Every time you come to a fork in the road a principle can help you.
- If traffic gets confusing, slow down,
- If you take the last pasta sauce from the pantry, put it on the shopping list
- The more you learn the more you earn
Principles work as guiding lights but you should not see them as absolute laws.
If there is a good justifiable reason to not apply the principle then don’t.
These can be applied not only to software development. You can use them in everyday life as well.
DRY – Don’t Repeat Yourself
Unfortunately as a parent I cannot avoid to repeat myself. But in programming I really try to stick to this principle.
It is the most basic but yet often the hardest to implement.
It is Tip #15 from the pragmatic programmer
Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
A violation of the DRY principle often comes from copy-pasting code instead of generalizing.
You can of course cut yourself some slack by applying the rule of three from TDD: when you repeated a block of code three times look for a more generic approach.
KISS – Keep it simple, stupid
This principle was coined by Clarence Johnson who was an aeronautical engineer.
Simplicity should be a design goal: do you need a class when a function is sufficient (compare Pythons unittest with pytest)
YAGNI(Y) – You ain’t gonna need it (yet)
This is a fun one! From junior dev to principal engineer: everyone can become the victim of over-engineering or scope creep
While with KISS the solution shall be as simple as possible, YAGNI asks the question if a solution is needed at all.
The urge to implement a color chooser widget when the customer just wants a green button.
POLS – Principle of Least Surprise
When you come into a room and hit the light switch you would expect…
…that the light turns on, when it was off before and the other way around.
You would be very surprised if instead of the light the dishwasher starts doing its thing.
Software should behave the same way and not surprise you!
For example when you close a program you would expect that the programs warns you of any unsaved changes with a dialogue.
When it just discards your changes you would be not amused aka pissed.
Software specific principles
SOC – Separation of concerns
Concerns are things a piece of software shall to do besides the mere customer feature:
- Putting log output to the console or a file (Logging)
- Granting access to specific features only to a distinct group of users (Authorization)
- Remembering the last choices of a user (Persistence)
This lead to the development of Aspect oriented programming. In Python lots of the above mentioned concerns can be implemented with decorators
IOSP – Integration Operation Segregation Principle
This principle sound a bit complicated but it can be summed up like this
Functions shall either only contain logic or they shall only call other functions.
A function which contains logic is the “Operation” and the function which calls the other functions is the “Integration”.
And these two shall be segregated 🙂
A simple example could be a main function as the integration function delegating all the work to three other operation functions:
def main(): content = read_file("input.txt") result = calculate(content) write_results("output.json", result)
SLA – Single Level of Abstraction
In Clean Code Martin calls it “One Level of Abstraction per Function”
The example from above is already a good example of the SLA principle as well because the main function sticks to it.
Object Oriented Software specific principles
FCOI – Favor Composition over Inheritance
tl;dr; avoid subclassing, use instances of other classes
Code reuse is a goal in software engineering. And one way to achieve reuse is to use abstractions.
To achieve abstraction schools teach us to extract base classes aka inheritance.
So when beginners learn about object oriented programming suddenly everything becomes a inheritance hierarchy.
But instead of looking for the greatest common divisor you should look for the lowest common denominator!
Construct your classes by using small interfaces or aggregate them by using instances of other classes.