As a software developer I normally use general purpose languages to build software. I need the flexibility. But there’s a flip side to that coin. Great flexibility means more ways to bring the code into unmaintainable chaos.
So it comes to no surprise that a significant number of programming principles have been formulated to battle the code rot that seems to strike every software system sooner or later.
Here are the programming principles I try to keep in mind while designing code. I don’t always follow them but my goal is to know when and why I break them.
- Once and Only Once
Each and every declaration of behavior should appear once and only once.
- Don’t Repeat Yourself
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
- You Aren’t Gonna Need It
Always implement things when you actually need them, never when you just foresee that you need them.
- Law of Demeter
You have no business with other object’s objects.
// Asking for the customer's wallet is
// a LoD violation
// Better to Tell the customer
// to pay you
- Tell, Don’t Ask
It’s better to Tell an object to do something for you, than to ask for its internal state and perform the task yourself.
- Keep It Simple and Stupid
All design should be as simple as possible, but no simpler.
- Fail Fast
In case of unexpected errors, your system should fail straight away and in a clear manner.
It’s […] well known that the cost of failure increases with time. The sooner you discover the flaw, the easier it is to fix. In other words, if we are going to fail, there are good reasons to do it fast.
- Self-Documentation Principle
The designer of a model should strive to make all information about the module part of the module itself.
- Command-Query Separation Principle
Functions should not produce abstract side effects.
Of course, the S.O.L.I.D. principles:
- The Single Responsibility Principle
A class should have only one reason to change.
- The Open-Closed Principle
Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
- The Liskov Substitution Principle
Subtypes must be substitutable for their base types.
- The Interface Segregation Principle
Clients should not be forced to depend upon methods that they do not use. Interfaces belong to clients, not to hierarchies.
- The Dependency Inversion Principle
Abstractions should not depend upon details. Details should depend upon abstractions.
Principles regarding packaging and dependencies:
- The Release-Reuse Equivalency Principle
The granule of reuse is the granule of release.
- The Common Closure Principle
The classes in a package should be closed together against the same kind of changes. A change that affects a closed package affects all the classes in that package and no other packages.
- The Common Reuse Principle
The classes in a package are reused together. If you reuse one of the classes in a package, you reuse them all.
- The Acyclic Dependencies Principle
Allow no cycles in the package dependency graph.
- The Stable Dependencies Principle
Depend in the direction of stability.
- The Stable Abstractions Principle
A package should be as abstract as it is stable.