Simple Rules to be a Better Programmer

What is a rule?

In programming, a rule is a piece of code that defines how to achieve some goal. In Ruby it is called a class or method.

JavaScript: When a programmer makes a typo (i.e. has a few) he is committing a style violation and is told to write an additional letter (not too many).

Programmers often seem to not understand why a particular set of rules exist. It is a habit to follow a set of rules when using a given language. You might not follow all of them, but at least try to. If not, you might find yourself trying to solve the same problems over and over again, or worse, putting together long chains of hack-like solutions.

A few months ago, I started writing a new pattern for a design pattern repository. I called the pattern jq-routes

.jq-routes defines how to route an HTTP GET request to a web page using a JSON object that will be returned. Every time a GET request is made to your repository, it returns an object of JSON data from the route. A route can be used by multiple repositories at once. I like jq-routes because it takes very little setup and you can write your own routes as you like. You can even use jq-routes to create extensions that can be added to any given pattern.


This is a simple example of how jq-routes looks like:

describe Rack::User do context 'get a user' do let(:user) { Rack::User.new } before { -> $user { request_json( user: user.email, user_ids: user.user_ids ) } } after { -> $user { ( incr_user_id? ) -> $request { ( incr_user_id? ) -> render( :form ) } } } context 'get a user with id 6' do let(:user) { Rack::User.new } before { -> $user { request_json( user: $user.id, user_ids: 6 ) } } after { -> $user { incr_user_id? -> $request { ( incr_user_id? ) -> render( :form ) } } } context 'show a user' do let(:user) { Rack::User.new } before { -> $user { request_json( user: $user.id, user_ids: 1 ) } } after { -> $user { incr_user_id? -> $request { ( incr_user_id? ) -> render( :form ) } } } context 'show all users' do let(:user) { Rack::User.new } before { -> $user { request_json( user: $user.id, user_ids: user_ids ) } } after { -> $user { incr_user_id? -> $request { ( incr_user_id? ) -> render( :form ) } } } context 'show a user with id 7' do let(:user) { Rack::User.new } before { -> $user { request_json( user: $user.id, user_ids: 7 ) } } after { -> $user { incr_user_id? -> $request { ( incr_user_id? ) -> render( :form ) } } } context 'render a form for a user' do let(:form) { Rack::Form.new } before { -> $form { form_for( :user ) } } after { -> $form { form_for( :user ) } } context 'render a form for all users' do let(:form) { Rack::Form.new } before { -> $form { form_for( :user ) } } after { -> $form { form_for( :user ) } } context 'render an individual form' do # A form builder as a middleware for an entire application. app.get('/users', action: :edit, middleware: [ Rack::Form.new ], fn(req, res) -> { if req.user.has_admin?(user) { let req_form = req.form_for(user.admin); let form = form_for(req_form); res.render(form); } }); end app.get('/users/new', action: :new, middleware: [ Rack::Form.new ], fn(req, res) -> { let req_form = req.form_for(req.user.new); let form = form_for(req_form); res.render(form); }); end

We've already seen the basic steps of composing actions with middleware. We have four actions (users, delete, show, and show a user with a specific id) which we pass through our handlers to generate action objects. The :post method that we also wrap on the edit action's path just passes the form to the template, which is important because the text field doesn't handle the form submission. This is where our form builder comes in handy. Our form builder creates a new form for us and enqueues it to the rails server for all to see.

What else could we do with a form builder?

Here are a few ideas:

Post a form if the user's admin?

Capture a user's data so that you can render custom views based on the data

Helper functions to render the form in a different template based on the data

I've discussed this idea more than once in the tutorial on forms and templates, so this is a perfect time to talk about it. One of the challenges with building form-driven applications is that you often need to do multiple things at the same time, like fetching a user's information from some internal service, rendering the form in a template, and doing some action logic with the data. Form builders allow you to create a single place to do all of this for you.

Let's say you have an application where users submit their ID, name, and email. To do this you would put the data into a form builder, select the fields that you want to show on the form, and then bind all of that to a single action:It's not hard to see the benefits here. You can save time by defining a small set of fields and saving those to the form builder, saving your code, and shipping the form back to the server in the standard template.

The badForm builders, like the application we looked at above, make some dangerous assumptions.They don't make testable. Form builders, like our template, should always throw an exception if an invalid value is entered, and you should always take the necessary action to reload the form if an invalid value is entered. Yet form builders aren't built to make your code testable.

They don't separate logic from presentation. A typical template in a form builder looks like this:It's like a spaghetti of template tags all tagged with <!DOCTYPE html> , and each tag contains JavaScript code. Each tag runs its code after the event handler and before the form submission. With the way form builders work, the "layout" of your form comes from a combination of tags and JavaScript, and code that you may never have even touched.

You must write boilerplate.

The format for a form builder is that you build a form element, then you build a submit handler. You must read this boilerplate before building your form.

 If you do, you're in trouble.

>