Symptomps of bad code. It slows you down!
When you modify bad code, you break something else.
- Rigidity (Hard to extend)
You need to modify tons of other code to come back to your consistency.
It was a lot more complicated than I thought.
Code that has dependencies that sneaks out in many directions that you cannot make an isolated changed without chaning everything else around it.
- Fragility (Unpredictable breaks)
Tendency of the code to break in many places eventhough you only changed it in one place.
Some function set a flag and other function use that flag ..etc.
- Non-reusablity
Desirable parts of the code are coupled to undersirable parts of the code.
The main problem is bad dependencies/coupled systems.
HL Module
/ \
ML Module ML Module
/ \ / \
LW LW LW LW
module M ---> module N (function F)
M calls N.F
- Flow control from M to N
- If N changes, M has to change
- M knows about N (M imports N)
- Source code dependecy from M to N
- High level modules know about low level modules.
- High level policy polluted with low level detail.
- A change to the detail affects high level policy.
- Rigid because of coupling towards detail.
- Fragile because making a change at LW breaks HL.
- Can't reuse HL because it's tightly coupled to LW.
- A change in LW will recompile everything up the tree.
module M ---> interface I.F <--- module N.F
M calls I.F
N derives I.F
Polymorphism inverts dependecy arrows. Compile time dependency points against the flow of control instead of with the flow of control.
You will gain control over your dependency structure in the Dependency Tree.
Avoid writing rigid, fragile, non-reusable modules.
A class should only have one, and only one, reason to change.
Responsibility doesn't mean function or what it does, it means change, it has one reason to change.
Don't mix concerns in your classes.
A module should be open for extension but closed for modification.
You should be able to change the behaviour of the module without changing it.
A module that makes ploymorphic calls can be written and compiled at some point of time. However, 2 years later, a new module can extend it and implement these functions.
Adding a feature should be writing new code and not changing any old code.
Derived classes must be usable through the base class interface, without the need for the user to know the difference.
Square/Rectangle example.
Clients should not be forced to depend on interfaces they do not use.
High-level modules should not depend on low-level modules; instead, both should depend on abstractions.
Abstractions shouldn’t depend on details. Details should depend on abstractions.