How simple is too simple?

This question came up at the recent Expo-C conference, when presenter Michael Stal talked about designing services to be “as simple as possible but no simpler”. Kent Beck advises us to do “the simplest thing that could possibly work”, but this is often mistaken for “the first thing I could possibly think of” or even “the only thing I know” (also known as the Golden Hammer antipattern).

We picked up the topic as an open space session later that day. I took the position that you should only ever focus on the specific case in hand, and then only generalize if you meet another similar case. Erik Meijer, the reknowned language guru and thoroughly nice guy, took the opposing stance that you should abstract the general solution and then implement it locally. He pointed out that this was an approach with centuries of mathematical tradition behind it and is a fundamental tenet of modern functional programming1. This developed into a good-natured but heated stand-off. I just couldn’t see the value of building a fancy general solution on the client’s money, when there was lots more important work to do and limited time. He couldn’t understand why you wouldn’t take the effort to make something as flexible as possible for the end user, especially if you were designing something like a programmers’ toolset or language. On the scale of specific to general – or concrete to abstract – we were at opposite ends, with a seemingly intractable chasm between us. He was simply wrong, and so, of course, was I.

If you are working on an agile project, you can confidently take the “simplistic” approach of only solving for today, safe in the knowledge that you can easily change the code tomorrow, or next week, as you learn more. If you are designing something that involves publishing an API – of which designing a programming language can be considered an extreme example – then your decisions can have a far-reaching impact2.

This led us to the notion of a Change Event Horizon, which is the amount of time before you can undo the effect of a decision. For a programming language the change event horizon is huge. It can take years to repair a bogus language decision, and involve complex processes such as deprecation. For an internally-deployed enterprise app you are only as far away as your next release date.

So now we had a working definition of “too simple”. It can be defined as any decision that doesn’t consider the scale of the change event horizon. As an agile developer, one of my objectives is to create as small a change event horizon as I can, through the medium of continuous integration, automated testing and regular user feedback. Erik doesn’t have that luxury – he has to predict what his users will want, and use much blunter instruments such as beta programmes and focus groups. Add to that the myriad unpredictable things people do once you release a language – who would have predicted that Ruby would become the DSL host language of choice, or that VB would ever become cool3 – and you can quickly see that Erik lives in a far more complex world than me. No wonder then that he looks to the general, abstract case whenever he encounters a new situation. And I can rest easy knowing that my tiny change event horizon means I can change the world with the next release.

NLP talks about “in time” vs “through time“. Being in time means living in the moment, and not worrying about the future. Being through time means seeing the wider context, and carefully considering the implications of any action. Of course most people are a healthy mix of both of these. I am notoriously in time, which might explain why the immediacy of feedback on an agile project appeals to me – I simply don’t have the attention span for anything longer!

1. Erik is also the father of Haskell

2. Thanks are due to Niclas Nilsson for taking the role of translator/peacemaker for us to reach that realisation.

3. Take a look at some of the up-coming language features in VB9 if you don’t believe me.


  1. Pascal Bleser · ·

    Well put. Like Erik, I don’t agree either with Kent Beck’s statement in the scope of developing a framework that’s being used by a wide number of projects and teams (definitely a case of API publishing).

    Also, more generally, and IMHO, “the simplest thing that could possibly work” does not mean that you shouldn’t put certain abstractions into place right from the start.
    It does not discard using interfaces (almost) everywhere (*), for the sake of putting mechanisms in place, upfront, to facilitate refactoring, alternative implementations, and of course easy unit testing (at the very least to be able to easily implement a stub implementation without having to hack with cumbersome mock frameworks)
    (*) except for Domain objects, where it’s to be considered bad practice as of overengineering (see Evan’s “Domain Driven Design”, amongst others)

    Neither does it discard “design by contract” (well, a light form that applies to Java, i.e. well-defining the contracts of and by interfaces) or “single concern” patterns. Take those seriously, right from the start, even for a simple solution, even for “the simplest thing that could possibly work” because it will make refactoring and/or providing alternative implementations of an interface a lot easier, even in the short run.

    Not sure that statement by Kent was such a good idea… a lot of less (experienced|skilled) developers take that literaly (as they do with a lot of ideas from XP).

    But it’s definitely an interesting topic to discuss ;)

    just my 2c

  2. I’ll just do only, first, simplest thing I know that works……

    TW Dan has written a very thoughtful post about the concept of simplicity in agile development: Kent Beck advises us to do “the simplest thing that could possibly work”, but this is often mistaken for “the first thing I could……

  3. […] » How simple is too simple? […]

  4. Bruce Eckel · ·

    “It does not discard using interfaces (almost) everywhere (*)”
    Using interfaces everywhere is exactly the kind of “maybe we’ll need this” thinking that DTSTTCPW is intended to eliminate.

    1. That’s an interesting observation. Before I got into mocking using jmock, I was also very wary of interfaces everywhere. Especially the dreaded Impl antipattern – the 1-1 mapping of CheeseService to CheeseServiceImpl. I’ve found that using TDD with mocks helps me “discover” services and dependencies that I mock using interfaces, so that I can defer worrying about the implementations until later. Tim Mackinnon – one of the originators of mock objects – describes these interfaces as “flex points”. The interfaces that come out of mock-based TDD seem to appear just where I need multiple implementations down the line. Still not sure how, but I trust the mocking pixies and it seems to work.

  5. Hi Dan,

    Thanks for writing this interesting and thought provoking article. To hopefully put a face to a name, we met at ACCU this year. Syd introduced us. I previously worked with Syd before he joined Thoughtworks. I was at ACCU with Mauro Talevi and sat with him and joe Walnes in the Gumption Traps session.

    Simon Baker.

  6. […] » How simple is too simple? […]

<span>%d</span> bloggers like this: