This patterns is based on the Second Principle in SevenPrinciplesOfSoftwareDevelopment
. -- DavidHooker
Also known as the Keep It Simple, Stupid
, or KissPrinciple
If you have a choice between a simple solution and a complex one, then opting for complexity would be stupid.
This notion is discussed at http://www.artima.com/intv/simplest.html
in an article entitled "The Simplest Thing that Could Possibly Work".
See also OccamsRazor
Needless complexity gets in the way of actual work. No one will use new feature or gimmicks if they are too difficult or confusing. Hide complexity so that users of the system don't have to deal with it.
Adding features to software is easy, and tempting. The TechnologySolution
may look like a panacea. Don't fall into this trap. Remember: Removing features is very hard, once they've been added.
Keep It Simple
We have difficulty understanding systems as they become more complex.
Complexity leads to more errors and greater maintenance effort. We want systems to be more understandable, more maintainable, more flexible, and less error-prone.
Software design is not a haphazard process. There are many factors to consider in any design effort. All design should be as simple as possible, but no simpler. This facilitates having a more easily understood, and easily maintained system. This is not to say that features, even internal features, should be discarded in the name of simplicity. Indeed, the more elegant designs are usually the more simple ones. Simple also does not mean "quick and dirty." In fact, it often takes a lot of thought and work over multiple iterations to simplify.
Software that is more maintainable, understandable, and less error-prone.
A simple look at simplicity:
- under-simplified: i.e. complex; this is the problem topic.
- over-simplified: bad because it fails to solve part of the problem, or introduces new problems of its own.
- basic simplicity: simple avoidance of unnecessary complexity; this is the easy kind. This kind of software looks more or less like you would expect it to.
- insightful simplicity: the best kind but hardest and least formulaic, this kind of simplicity is actively surprising in how much it accomplishes with how little. This kind of software is worthy of study, precisely because it is simpler than you expected.
- "The success of UNIX lies not so much in new inventions but rather in the full exploitation of a carefully selected set of fertile ideas." -- D. M. Ritchie and K. Thompson, "The UNIX Time-Sharing System," Communications of the ACM, vol 17, no. 7, July 1974, 365-375.
- UNIX is very simple, but it takes a genius to understand the simplicity. -- Dennis Ritchie (This paraphrases the first quote.)
- Some will complain that the most powerful kinds of simplicity cannot be fully described nor taught nor reduced to rules, but that's the point: creative genius in any area is very worthwhile, sometimes precisely because it transcends simple stimulus-response patterns.
- This is perhaps most widely appreciated in mathematics, where an elegantly simple theorem is widely considered beautiful and worth its weight in gold, but well known to be generally far more difficult than a complex theorem on the same topic, and much more likely to be generated by deep insight than by methodical plodding. (There are plenty of exceptions to this; that's just the loose idea.)
It seems to me that simplicity is a force, or a property, but not a pattern. We need patterns that tell us how to make something simple. Few people argue against simplicity, but it is hard to make a system simple, and just saying "keep it simple" doesn't necessarily help.
pattern can't be created to encompass KeepItSimple
, however MartinFowler
may be a good collection of patterns that describe this.
The quest for simplicity is often misguided. Simplicity does not live in a vacuum. And making code simple is often synonymous with making it brittle, hard to generalize, or inefficient.
Chrys Nehaniv and I were once talking about John Stalling's grad algebra course at CalBerkeley
. And Chrys said "When I took that course, I often had no idea what John was doing. But now that I understand what the theorems mean [note: this was after Chrys finished up his PhD], I also know that John gave the best possible proofs in a lot of cases."
John's lectures illustrate the right focus. Likewise, we should design so that the more another person understands the design, the more they praise it. Or should we?
Lately I've been wondering a lot about dynamic run-times and RunTimeTypeInformation
and marvelling at how much of the stuff I do simply assumes that RTTI will be there for me.
Anyway, Patterns of Software
has a very nice essay,
Habitability and Piecemeal Growth
, which shows a better goal than elegance, simplicity, or the one I stated above.
Habitability. I like this goal. I like the book, I like the essays, I like the way RichardGabriel
has of stating what I already knew but didn't realize.
Keep It Straightforward, Simpleton. Simplicity without straightforwardness is not simplicity.
Just because one approach is shorter or has fewer words than another does not mean it is 'simpler'. To be 'simple', it must be understandably simple, within the conceptual reach of other who might see it. That is, the solution must be 'straightforward' and require less analytic skill to understand.
A programming 'trick' is usually not simple, nor straightforward, nor understandable. Each language is permitted a few popular idioms, but no more than a few.
- Hmm? But you're an APL/J fan/appreciator, which has a very large number of popular idioms.
Here is a simple trick for printing a comma separated list (like a,b,c)...
[:each | aStream print: each; nextPut: $,].
aStream skip: -1
The programmer avoided conditional logic and used the simplest iterator. But there is something strongly unsatisfying about printing an extra comma and then erasing it. -- WardCunningham
Perhaps because it is probably the wrong approach for an empty list. -- VickiKerr
Perhaps because it is the wrong approach period.
aStream print: aList head.
(aList tail) do:
[:each | aStream print: each; nextPut: $,].
(head and tail are from haskell, sorry)
Is it just me, or is that approach wrong too? It looks like you have the print: and nextPut: messages in the wrong order. -- DanielBrockman
It's not just you, they're both wrong. The correct approach is...
aList do: [:each | aStream print: each] separatedBy: [aStream nextPutAll: ', '].
See rant on SimplicityIsOverRated
. See also DoSimpleThings