Ootoovak

How to Write the Code You Want

Procrastination

The creator of Perl, Larry Wall, is known for coining the “Three Virtues” of programming. They include laziness, impatience, and hubris. So taking the hubris recommendation to heart, I propose we add another programming virtue to the list: procrastination. Just like optimising early, as a developer you should strive to put off any implementation details for as long as possible. Doing so will not only improve your code’s structure but, even more importantly, it’s communication.

Communication And Messages

Communication

When we first learn how to program we are given this brand new ability, a whole other language to communicate with. We can finally talk to the fancy silicon box we are all so familiar with and get it to do exactly the things we want! In all this heady excitement of learning how to make a machine understand us we forget who we should really be trying to communicate with when we program, people, both ourselves and others. The best way to write for people is to write the code that we want to have, the kind that expresses your thoughts clearly to any human reader.

Messages

Using messages to communicate between things is a common practice in programming. Object Oriented Programming allows us to communicate the same way we do with external things, within our own application, between encapsulated objects. This gives the writer of object oriented programming language some great freedoms.

The way you can think about messages is that you are not asking an object to do something you are telling it to do something, trusting that it will perform the task you assigned and you don’t have to know or care about how right away. The nice thing about the fractal nature of programming is that you can use this same mental model when working with external applications as well, passing messages around and trusting other code to know what the message means and what do with it.

The nice thing about not caring how the messages are processed is that you can affectively just assume that they exist and deal with the implementation later. This allows you to write your messages in a way that reads like a sentence making your methods affectively paragraphs that clearly describe your intent.

Pictures And Code

The following examples should be quite familiar to web developers, the code is written in a style that plainly describe what they are doing by the messages they send. After writing the code we want to have then we can then take a look at setting up the implementation code that we initially we put off, encapsulated away from the main flow of your application.

The Passing Of Messages

Before we get into code I want to give the grand overview of messages being passed around in the programming world. You can see whether it is objects calling external dependancies, other objects, or calling itself if is all pretty much the same.

AJAX

Between your JS application and your server.

Controller

Between your controller and your model.

Model

Between your model and itself.

Persistence

Between your ORM and your database.

Writing A Story

These are examples of code written in the style I talked about above:

1
2
3
4
5
6
7
8
9
10
11
12
Procrastinator.prototype = {
start: function() {
var gifs = findMeGifs();
saveGifs(gifs);
},
findMeGifs: function() {
animal = findMeSomeAnimalGifs();
tv = findMeSomeTVShowGifs();
movie = findMeSomeMovieGifs();
return { animal: animal, tv: tv, movie: movie };
}
}

Javascript main app flow example.

1
2
3
4
5
6
7
8
9
10
class ProcrastinatorController < ApplicationController
def save_gifs
mosaic = GifMosaic.new(gif_hash)
mosaic.stitch_together
mosaic.add_caption("All the LOLs - #{today}")
mosaic.save
end
end

Ruby main app flow example.

Once again you can see I just wrote the methods I wanted, each method almost reads like a user story. I didn’t worry about any of the implementation details. When test driving this code I can just stub and mock out the calls to external dependancies (like other objects or even other applications).

Implementation

Below are some of the implementation details for the code above, written after I knew exactly what my program actually needed and it is all nicely encapsulated.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
var Procrastinator = function Procrastinator(persistence, tumblr) {
this.persistence = persistence;
this.tumblr = tumblr;
};
Procrastinator.prototype = {
saveGifs: function(data) {
var gif_data = process_data(data);
persistence.save(gif_data)
},
findMeSomeAnimalGifs: function() {
tumblr.gifWithTags(["kittens", "bunnies"]);
},
findMeSomeTVShowGifs: function() {
tumblr.gifWithTags(["game of thrones"]);
},
findMeSomeMovieGifs: function() {
tumblr.gifWithTags(["thor"]);
}
};
var ProcrastinatorPersistence = function ProcrastinatorPersistence() {};
ProcrastinatorPersistence.prototype = {
save: function(data) {
var ajaxCall = $.ajax({
type: 'POST',
url: "/gif_mosaics",
data: data
});
return ajaxCall;
}
};

Javascript implementation example.

Notice even here I am still deferring some implementation and writing messages to the external implementation I want. In the constructor I assume the user is passing in an object that interfaces with Tumblr’s API and knows how to search for gifs based on tags.

I do the same thing with the persistence object but have included the example implementation for that. Right now it uses a jQuery Ajax call but it can easily be changed to use another library or even local storage if we wanted.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
class ProcrastinatorController < ApplicationController
private
def gif_hash
params
end
def today
Date.today
end
end
class GifMosaic
CAPTION_COLOUR = "#fff"
CAPTION_OUTLINE_COLOUR = "#333"
def initialize(gif_hash)
@gifs = gif_hash.fetch(:animal, [])
@gifs += gif_hash.fetch(:tv, [])
@gifs += gif_hash.fetch(:movie, [])
end
def stitch_together
self.mosaic = ImageProcessor.stitch_images(gifs, cols: 9)
end
def add_caption(text, style_options = {})
style_options = default_style_options.merge(options)
ImageProcessor.add_caption(mosaic, text, style: style_options)
end
def save
GifMosaicPersistance.save(self)
end
private
attr_accessor :mosaic
attr_reader :gifs
def default_style_options
{ colour: CAPTION_COLOUR, outline_colour: CAPTION_OUTLINE_COLOUR }
end
end

Ruby implementation example.

Once again I am procrastinating on the implementation. This time I am calling an ImageProcessor class that might be a 3rd party library, or more likely a wrapper to a 3rd party library. I don’t care, I just wrote the messages I wanted to be able to call.

A piece of advice is to write the internals of your implementation methods like you would a story. Introduce your work by putting down what you know, then write the body of the method which is the work and finally return your conclusion.

One More Time: Write The Messages You Want

So, if we code in a fire and forget series of messages like above it frees us to write the code you want. You can just start writing code that tells the reader exactly what you want to happen, it is effectively self documenting. This helps so much when you go back to re-read your code (and you will) and as a great side affect you put off implementation until you absolutely have to write it and it ends up in a container with a name that says exactly what it does. Also, when you want to improve or change your implementation you can feel much freer to do so knowing that you are operating on only a small isolated part of your code that doesn’t affect the larger design of the application.

Conclusion

When you program be sure to communicate with your reader, the person. That might be your coworkers, an open source community, or most likely your future self. Know that ultimately people are your audience, you are your audience, so write code with people in mind. Write code you would want to read yourself.

Inspiration