Characteristics of "Great Software Design"TM

This post is not about design-design, but the internal design of a software system. Such a design has several general characteristics, and Code Complete 2 has a list of these. First, a related quote by R. Buckminster Fuller:

“When I am working on a problem I never think about beauty. I think only how to solve the problem. But when I have finished, if the solution is not beautiful, I know it is wrong.”

Great Software Design would have all these characteristics, but that’s almost never possible. Some of them contradict each other, so often we have to make tradeoffs. Anyway, here’s the list:

  • Minimal complexity – if your design doesn’t let you safely ignore most other parts of the program when you’re immersed in one specific part, the design isn’t doing its job. This is also known as avoiding complexity.
  • Ease if maintenance – design the system to be self-explanatory. Wheter it’s yourself or a maintainance programmer that’s going to sit down and fix a bug in a couple of months time it’ll be worth it.
  • Loose coupling – Loose coupling means designing so that you hold connections among different parts of a program to a minimum. This means; encapsulation, and information hiding [read] and good abstractions in class interfaces. This also makes the stuff easier to test, which is a Good Thing.
  • Extensibility – You can change a piece of the system without affecting other pieces.
  • Reusability – Designing the system so that you can use pieces of it in other systems.
  • High fan-in – This refers to having a high number of classes that use a given class. This is good, the opposite on the other hand …
  • Low-to-medium fan-out – Refers to how many classes a given class use. If a class have a high fan-out (Code Complete says this is more than 7 classes, I don’t want to be that specific) this is often an indication of that the class may be overly complex. And complexity is bad, remember?
  • Portability – How easy would it be to move the system to another environment?
  • Leanness – I guess this could be compared to KISS. Voiltaire said that a book is finished not when nothing more can be added but when nothing more can be taken away. Extra code will have to be developed, reviewed, tested, and considered when the other code is modified.
  • Stratification – designing “in layers”. Can you view “one layer” of the code without thinking about the underlying layer? An example giving in Code Complete is if you’re writing a modern system that has to use a lot of older, poorly designed code – you would want to write a layer of the new system that is responsible for interfacing with the old code.
  • Standard techniques – this means using design patterns whenever it is appropiate to do so. This way, if you say to another coder “Here I use the Factory pattern” he will instantly know what you’re talking about if he knows the pattern. You do not want to be one of those “valued employees” who only write code that the “valued employee” can understand.

And, whatever you do: DO NOT CONSIDER SPEED! NEVER OPTIMIZE WHILE DESIGNING! (yes, those really needed to be capitalized). If I have one more PHP coder tell me that the MVC solution probably won’t be speedy, I will have to slashdot him physically in public. You don’t want to start off by trading any of the characteristics above for speed.

You design the system with design in mind, and if it turns out to be slow then you optimize. You will know what the bottleneck is, and you will make a sensible and thought-through trade-off. Then you will have your good design, and your speed. You will, rule the entire planet. Hah, kidding, the last part I just made up.

Well, what are you waiting for? Run out in a flowery meadow with your pen and paper and design something beautiful!

  1. I definitely take note with your proclamation not to consider speed. I see where you are getting at – certainly when some argue that one of the tools of abstraction (polymorphism for example) which has an associated runtime cost should not be used, despite an utter lack of profiled evidence, I’m with you. But when you’re designing a system that you well know must scale in particular directions, i.e., you expect it to be handling millions of X a second, then whatever algorithm or data structure you use to handle X needs to be built with speed in mind. This is more of the Big ‘Oh sort of ‘speed’ rather than pure clock cycles. For many applications, such as embedded, games, scalable aps or libraries, performance should actually be on your mind from day one. It’s just that many people believe performance comes from forgoing abstraction and maintainability, when real performance comes from an analysis of the available algorithms, domain specific design patterns, etc…

  2. “If I have one more PHP coder tell me that the MVC solution probably won’t be speedy, I will have to slashdot him physically in public.”

    mind to elaborate more on this ?

  3. I just started learning basic programming after years working on the business side of web development / web marketing. This is an outstanding set of lessons for a newbie hacker and articulated in a way that it is easy to understand, yet fundamentally valuable. Thanks for posting!

Leave a Reply