Whilst we may muse about engineering, architectural or craft metaphors for software development, there is no denying that, in essence, programming is writing. It is a form of communication that has two distinct audiences: us and the machine. Although there are times when it might not feel this way, the machine is easily pleased, demanding little more than well-formed code. We, however, are a little more complex and discerning: we demand that our communication communicate.

As a discipline of composition much of what can be said for writing natural language is directly applicable to code. There is no virtue in long-windedness and, by way of balance, there is also no virtue in code that is unreadably terse. As ever the appeal is for well-written code. Code that is simple and clear, brief and direct.

— Kevlin Henney in “Minimalism: Omit Needless Code

While reading the article quoted above, I was reminded of the first big leap I made professionally. Engaging the part of my brain that deals with composing and editing English prose enabled me to move from being an entry-level developer to a “Senior Software Engineer”.

The circumstance for my “aha” moment was the transition between two very different projects. I had just returned to the home office after being offsite for 14 months. My offsite assignment had been a testing job, during which I had written scripts for doing some test script prep and data analysis, and to maintain my sanity. I came back and started working on a .NET web service that served as an integration point between a legacy Visual C++ app, some legacy C++ code extracted from the app, and a perl/CGI/Oracle web application.

I was working on a team with a couple of Senior Engineers. My first task was to write a component that would handle the compression needs of the application. I wrote a class that abstracted zip files, and let you list a zip file’s contents, extract one or all of the files in the zip, add files to the zip, etc. Essentially, I wrote a subset of #ziplib. It was really sweet, and had 0 (that’s right, zero) unit tests.

Unfortunately, all the application needed was two functions: Zip and Unzip. It needed to add a single file to a zip at one end, and pull it out on the other end. Added to that, my code was generally sloppy. The code review was a bit painful.

During the project, there were many more code reviews. This was the first project that I was on that had code reviews, and I really hadn’t gotten the hang of it at that point.

When we were close to finished, one of the engineers asked me to review a paper he had written that gave guidance about exception handling. I like reviewing and marking up documents — I’m one of those people who thinks that bad grammar and bad spelling detract from the value of written things — so I had no problem printing out a copy and taking a red pen to it.

During the document review, something clicked for me. I realized that during code reviews, I needed to engage the same part of my brain that I used when reviewing prose. Code, like prose, tells a story. There is some reason that you’ve written the thing. You’re starting in one place, and going to another. You’re building arguments that you can fall back on later. You’re using the results of other works to build up something significant, at least in the current context. I was now able to use that part of my self that wanted to be a writer, and my professional growth took off.

At a brown-bag lunch at work the other day, someone asked about the process of learning design. After thinking about it for a while, I’ve come up with a short answer: experience. This response is based on a couple of things and leads to a couple different courses of action.

One of them is my own experience. As I’ve progressed through my career, I’ve built up a body of experiential knowledge. Some designs age well, some don’t. I’ve designed things that have stood up to abuse, but more often I’ve designed something that I’ve later wanted to redo in order to alleviate some problem or other. Having worked on many projects, I have an easier time seeing where pitfalls lie and avoiding them, in addition to being able to make simple, flexible designs. I don’t think a good designer can be made without significant experience in the field.

Another facet of this “experience” argument is the aspect of knowledge acquisition. The seed of this idea was planted when I read The Knowledge Deficit, by E.D. Hirsch, Jr. In this book, Hirsch blames illiteracy in the USA on the approach taken by educators. According to Hirsch, the wrong approach is to teach the ability to read and the ability to analyze what you’re reading, and the right approach is to expose the students to a wide breadth of knowledge. I have found this point to be applicable to software engineering in a couple of ways. The first is that my own design skills have been markedly improved by reading things like the GoF’s Design Patterns book. When David Anderson visited SEP, I noticed that he made lots of references to books and articles he had read. Some of his comments made it sound like he reads a book or two per month. Finally, in the last few years, I’ve enjoyed reading historical texts (either old/original speeches texts, or, sometimes, non-fiction history books from the library). Reading these books has colored my perspective (for the better, I think) on current events in a way that other learning methods could not. Being exposed to a breadth of knowledge broadens my perspective and helps me understand how things got to be the way they are, in addition to allowing me to glean insight from other people’s experience.

In summary, good design skills are something that comes by practical experience and by knowledge. Read books and blogs about the things you are trying to do. Try new tools and techniques. Grow.