Taken from the presentation of Alexander von Zitzewitz.
- Apply a consistent packing naming convention.
- No cycles in your logical architecture, no cycles in your layers.
- No cyclic dependencies between different packages.
- Keep coupling low.
- Limit lines of code per file, 700 lines should be the maximum value.
- Limit cyclomatic complexity of methods, e.g. 15, at least less than 25.
- Limit the size of packages, e.g. less than 50 types.
Notes on the above
Slice technical stuff horizontally, business stuff vertically. An easy pattern for example is <id>.<project>.<module>.<implementation>, e.g. de.xroot.travel.reservation.dao.hibernate.
Coupling can be measured with ACD (Sum of dependent files for each file). In this case less than 7% for 500 files is good, for 1,000 files it would be better to keep below 4%. Alternative use NCCD, then a factor less than 6 is acceptable.
Coupling can be reduced by using Dependency Inversion, i.e. program against interfaces, and Dependency Injection. Re-use will increase coupling, but that is very good, so a reduction to 1 – a file depends only on itself – is not desirable.
Cylces are evil per definition ;-). All cycles can be broken by using interfaces and eased by abstraction.
Out of the wild
Most projects that adhere to the above rules will be better than 80% of the existing projects. That doesn’t mean that those are not cool or not a success story. Spring does adhere to those rules, and it is thus easy to read. Hibernate on the other hand is … well, it is cool and pretty useful. Just don’t try to understand it.