August 6, 2012

...Learn TDD with Codemanship

Back To Basics #10 - Grow Complex Software Using The Simplest Parts

This is the final of ten posts aiming to set out basic principles for software developers in a way that avoids pandering to trends and marketing hype, so that developers and aspiring developers can hopefully gain some useful insights that might last their careers. Well, maybe.

One thing I learned years ago is that when life is simpler, I tend to get more done. Other people make themselves busy, filling up their diaries, filling out forms, taking on more and more responsibilities and generally cluttering up their days.

Like a lot of software developers, I'm inherently lazy. So when I need to get something done, my first thought is usually "what's the least I can do to achieve this?" (My second thought, of course, is "what time does the pub open?")

Somehow, though, I do manage to get things done. And, after examining why someone as lazy as me manages to achieve anything, I've realised that it's because I'm an ideal combination of lazy and focused. I tend to know exactly what it is I'm setting out to achieve, and I have a knack for finding the lowest energy route to getting there.

When life gets more complicated, we not only open ourselves up to a lot of unnecessary effort, but we also end up in a situation where there are a lot more things that can go wrong.

I measure the complexity of my life in terms of keys. In my twenties, I had lots of keys, house keys, car keys, keys for the garage, keys for the windows, spare keys for the office if I had to let myself in out of hours, and so on. And lots of spare keys in case I lost any of those keys.

Today, after recently selling my old VW, I have a key. Just the one. I am living a one-key life. (And not a wonkey life. Well, not in my opinion, at least.)

Although I'm lazy, I actually have to work quite hard to keep my life simple. But it's worth it. By keeping things simple and uncluttered, it leaves much potential to actually do things. In particular, it leaves time to sieze opportunities and deal with problems that suddenly come up.

Keeping things simple reduces the risk of disasters, and increases my capacity to adapt to changing circumstances. I've got time to learn and adapt. Busy people don't.

And waddayaknow? It turns out that much of the joy and fulfilment that life has to offer comes through learning and adapting, not through doggedly sticking to plans.

Software is similar. When we make our programs more complicated than they need to be, we increase the risk of the program being wrong - simply because there's more that can go wrong.

And the more complex a program is, the harder it is to understand, and therefore the harder it can be to change without breaking it. Teams who overcomplicate their software can often be so busy fixing bugs and wrestling to get their heads around the code that they have little time for adding new features and adapting the software to changing circumstances.

When we write code, we need to be lazy and focused. We need to work hard at writing the simplest code possible that will satisfy the customer's requirements.

And hard work it is. Simplicity doesn't come easy. We need to be constantly vigilant to unnecessary complexity, always asking ourselves "what's the least we can do here?"

And we need to be continually reshaping and "cleaning" the code to maintain that simplicity. Uncluttered code will no more stay magically uncluttered as it grows than an uncluttered house will magically stay uncluttered with no tidying.

But doesn't software necessarily get complicated? Is it possible to write a "simple" Computer-Aided Design program, or a "simple" Digital Audio Workstation, or a "simple" Nuclear Missile Defence System?

While we must strive for the simplest software, many problems are just darn complicated. There's no avoiding it.

Cities are also necessarily very complicated. But my house isn't. I don't need to understand how a city works to deal with living in my house. I just need to know how my house works and how it interacts with the parts of the city it's connected to (through the street, through the sewers, through the fibre-optic cable that brings the Interweb and TV and telephone, etc.)

Cities are inescapably complex - beyond the capability of any person to completely grasp - but living and working in a big city is something millions do every day quite happily. We can build fantastically complicated cities out of amazingly simple parts.

The overall design of a city emerges through the interactions of all the different parts. We cannot hope to plan how a city grows in detail at the level of the entire city. It simply won't fit inside our heads.

But we can apply some simple organising principles to the parts - houses, streets, communities, roads, waterways, power supplies and all the rest - and in particular to how the parts interact, so that what emerges is a working city.

And we can gently influence the overall shape by applying external constraints (e.g., you can't build here, but build affordbale houses over there and we'll give you a generous tax break.)

When it comes to organising software in the large, a great deal of the action needs to happen in the small. We can allow complicated software to grow by wiring together lots of very simple pieces, and applying a few basic organising principles to how those individual pieces are designed and how they interact with each other.

We can focus on getting it right at that atomic level of functions, modules and their interactions, working to maintain the ultimate simplicity.

And then we can constrain the overall design by applying the customer's tests from the outside. So, regardless of what internal design emerges, as a whole it must do what the customer requires it to do, while remaining simple enough in its component parts to accomodate change.

Posted 5 years, 7 months ago on August 6, 2012