Alexander von Zitzewitz
5
Regeln für eine bessere Architektur
(5
rules for a better software architecture)
Your most frightening enemy: the Dragon
of Complexity
Erosion of Architecture - Dragon
Fire
Architecture erosion is quite a known
problem
- System knowledge and skills are not evenly distributed
- coupling and complexity grows faster than system size. When you realize it, it is often too late.
- Unwanted dependencies are created without being noticed.
- Management usually doesn't care about internal quality (black box)
- Time pressure is always a good excuse to sacrifice structure
Typical symptoms of an eroded architecture
are a high degree of coupling and a lot of cyclic dependencies
- Changes become increasingly difficult
- Testing and code comprehension also become increasingly difficult
- Deployment problems of all kind
Resistance to Change vs. time:
exponential ascent
do architecture management: higher cost
in the beginning, big rewards over time
Architecture Management - Fighting
the Dragon
Goal 1: Keep a simple and maintainable
software structure
- use an architecture meta model
- define a mapping from your code to the architecture (naming conventions help)
- make sure the architecture is always matched by the code
- avoid cyclic dependencies
- controls and minimize overall coupling
Goal 2: Keep complexity under control
- avoid monster Java files
- avoid overly long or complex methods (cyclomatic complexity check)
- avoid monster packages
Benefits: Dramatic reduction of overall
project cost
- improved testability
- improved code readability
- improved modularity
- code can be extended and maintained much easier
A Proven Architecture Meta Model
1. Step: Cut horizontally into Layers
User interfaces
Business logic
Data Access
2. Step: Cut vertically into vertical
slices by functional aspects
Contracts
Customer
User
Common
3. Step: Defines the rules of engagement
Matrix layer x slices: which block =
subsystems depend on which others?
Mapping of Your Code to the Meta
Model
Each package is mapped to exactly one
subsystem
If packages contain types of several
subsystems, virtual refactorings are helpful
A good naming convention for packages
can make your life very simple
- e. g. com.hello2morrow.project.verticalslice.layer...
Subsystems
should have interfaces
Work incrementally
- start with your layering
- then add the vertical slices (if applicable)
- define subsystem interfaces
- fine tune the rules of engagement on the subsystem level
How to measure coupling
ACD = Average Component Dependency
Average number of direct and indirect
dependencies
rACD = ACD / number of elements (-->
it's always between 0 and 1)
NCCD is even more useful (normalized
components coupling dependency; comparison to balanced binary tree)
use Dependency Inversion to reduce coupling
the bigger the system, the smaller the
rACD should be
e. g. 500 elements, rACD < 7% might
be good
NCCD < 6 might be good (independent
from system's size!)
How to keep the coupling low?
Dependency Inversion Principle (Robert
C. Martin)
- build on abstractions, not on implementations
- best pattern for a flexible architecture with low coupling
- have a look at dependency injection frameworks (e. g. Spring)
Golden Rules for a successful project
Rule 1: Define
a cycle free logical architecture down to the level of subsystems and a
strict and consistent package naming convention
Rule 2: Do
not allow cyclic dependencies between different packages
Rule 3:
Keep the coupling low (NCCD < 6)
Rule 4: Limit
the size of Java files (700 LOC is a reasonable value)
Rule 5: Limit
the cyclomatic complexity of methods (e. g. 15)
Rule 6: Limit
the size of a package (e. g. < 50 types)
Update:
Removed German umlaut from URL