💾 Archived View for johnhame.link › posts › 2012-11-09-code-is-poetry.gmi captured on 2024-05-10 at 10:43:45. Gemini links have been rewritten to link to archived content

View Raw

More Information

⬅️ Previous capture (2023-09-08)

-=-=-=-=-=-=-

Code is Poetry

2012-11-09

I once read a much better article than this one by Matt Ward[1] that attempts to show the similarity between code and poetry. Matt shows how the flow and syntax of good code, that abstract minimalism and lowest common denominator approach, is actually very similar to that of a poem.

I agree with everything Matt says, but I felt the article was a little lacking in showing how the coder can be a poet in order to achieve greatness and self-fulfillment (that's what poetry and coding are partly about, in my opinion). To this end, I've compiled some advice I've learned by myself or from others over the years in the hope that it will help someone out there on these vast pipes we call the Internets.

1: a much better article than this one by Matt Ward

Fail Early, fail often

In the UK, we often suffer from a certain cultural ailment: we're afraid to fail. Those involved in the startup scene will testify to this: in the US a failed company is almost a badge of honor - a mark of cutting one's teeth and removing that "green" status. In the UK however, if your first startup isn't reasonably successful, good luck getting investment on a second business. This is the sign of the "if you fail, you're a failure" psyche which plagues all entrepreneurs. Stop being daft. Failing is the best way of learning. Look at any top person in any industry, and I guarantee they'll have failed at something in their life, took it on the chin, and learned about it.

The trick to failing, is to fail early and often. The quicker you fail, the easier it is to fix. If it's unfixable, then you're in a far better-off state now than you would have been 6 months later, with more investment (emotional, chronological and fiscal) in your strategy than before. And for goodness' sake, learn from your mistakes!

Make a test

Make a test, check against common sense. Check again! Write code that shouldn't pass (to test the test). Make it pass!

Make your tests as fast and as complete as possible. The faster they are, the more likely you and others are to run them, the more likely you and others are to make them even more complete.

For large projects, Automate your testing with a continuous integration server connected to your version control system. This forces the testing to happen, and helps keep bad code out of your version control.

Make it modular. Break it, see what happens! What can you learn from your application by doing this?

No code is perfect, but a perfect coder makes perfect code...

Before we can define "perfect code", we should really first define why code should be perfect in the first place.

Code should be as close to perfect as possible because how well you build something defines you as a person. If you are happy to build something that is "good enough", or "not bad", then you are not fulfilling your full potential, you are devaluing yourself, and you are selling your ideals to time and money.

For me, the number one reason why code should be perfect is because I, the coder want to be perfect, and to show others that I strive for perfection, because I care passionately about what I do.

But of course this isn't the only reason: perfect code leads to better understanding for 3rd parties, and helps clearly define the end goal of the code ("of pen and purpose", as Matt puts it).

Which leads me nicely to the final reason I have for striving for perfection.

Often the purpose will change: the business will change and so the goal-posts will move. For a developer, this is often a very tricky manoeuvre to handle cleanly. The more perfect the code is before this point, the better the outcome is afterwards.

Now that we've defined the "why", we should define the "how". For me, the following list serves as a definition of good code:

- Does is perform the task?

- Does it perform well?

- Does it break gracefully?

- Is it easy to read?

- Is it easy to extend?

- Is it simple and well formatted?

- Does it pass a lint test?

And for the project as a whole:

- Is it DRY[1]?

- Are the particularly useful bits abstracted and made into self-containing blocks which could be reused elsewhere or in another project?

- Is the scope safe and sensible?

- Are the tests covering all the business logic of the project?

- Are the design, business logic, and event handling logic separated from each other (using a pattern such as [MVC][2])?

I believe that if you follow that list religiously, and you'll be on your way to being a true software artisan.

1: DRY

2: MVC

Make it self documenting, then document it anyway

My definition of self documenting code is that it reads as close to a sentence as possible, but that its purpose is also instantly recognisable to someone who isn't working on your project at all.

A good example of self documenting code is the syntax that Should.JS[1] allows you to use sentences to build your test assertions:

1: Should.JS

describe("Creation " + data.collection, function () {

    it("shouldn't fail", function () {
        data._response.statusCode.should.equal(200);
    });

    it("Should Respond with valid JSON", function () {
        data._response.should.be.json;
    });

    it("Should have a createdAt column", function () {
        var _json = JSON.parse(data._body);

        _json.should.have.property('createdAt');
        _json.should.have.property('updatedAt');
        _json.createdAt.should.be.equal(_json.updatedAt);
    });

    it("Should have every column we defined", function () {
        var _json = JSON.parse(data._body);

        for (var documentKey in data._document) {
            for (var keyJson in _json) {
                if (keyJson == documentKey) {
                    _json[keyJson].should.be.equal(data._document[documentKey]);
                }
            }
        }
    });
});

Super easy to read, right? `it` lets you define what the closure is for, which is used both to help you understand what the object of the test is, but also in the output of the test to show you what passed or failed. See how the `should` object has objects like `be` which allow us to make a sentence? When you think about it, all they do is daisy chain the object, so in terms of functionality they are useless, but they help to make a line of code so much more readable for someone who has no idea what the code is for.

But how could we make this code even better? By adding in a comment to explain not what we are doing, but why we are doing it. Why is it important for us to test if `data_response.statusCode` should equal 200? Why are we checking to see if `data._document[documentKey]=` is equal to `_json[keyJson]=`? That is still not very obvious at all.

Follow documenting standards

I'm a big fan of the DocBlock syntax. Throughout all of my PHP code, I make sure that every file, function and class I write, has a DocBlock. Here's an example of a DocBlock I wrote for a method:

/**
 * receiveData
 *
 * This method accepts an array
 * of data that is then used within the run
 * function.
 *
 * The data should look like this:
 * <code>
 *  $data = [
 *      'research' => \Entity\Research::findOne('rur'),
 *      'foo'      => 'bar',
 *      'toast'    => [1,2,3,4,5]
 *  ];
 * </code>
 *
 * @param Array $data Array of values to be used by the run method.
 *
 * @return Bool
 */

Can you tell how to use it? I hope so! The best part of using documenting standards like DocBlock is that you can then use tools which run through the code and generate documentation in all sorts of formats, which makes it super easy for newcomers to figure out how to work on your application.

Don't be a developer, be a software poet.

Very few developers can truly check off this list (I'd be lying if I said I could); those that do truly are close to perfect.

As someone wise once said (I'm paraphrasing):

The pursuit of happiness is not found at the destination, but on the path itself.

For me, perfection comes from the meticulous pruning and cleaning of my code in an attempt to make myself perfect. While I'll never achieve that, the perfection lies in the fact that I still try.