Simple rules that allow for good design, taken from Kent Beck's 4 rules of Simple Design:
All tests run with no failures
Code contains no duplication
Expresses the intent of the programmer
Minimises the number of classes and methods
Design Rule One: All Tests Run
If a system can't be verified as working properly, any planning or how well the code is written is essentially nullified and shouldn't go live.
Making systems testable means they are more likely to be small and simple, as well as de coupled and cohesive.
Design Rules Two to Four: Refactoring
Tests encourage a developer to continuously look back on the code they've written and make it easier to read, and verify any refactoring changes will not break our code.
Refactoring includes increasing cohesion, decreasing coupling, separate and modulising concerns and making code easier to read.
The final three rules of simple design is also applied here: Eliminate duplication, ensure expressiveness and minimise classes and methods.
Duplication, including direct copying of lines, as well as code that does the same thing, adds unnecessary complexity and additional work.
To remove higher level duplication, the template method is often used. This is where a parent class implements a vague method, and each child class that uses that method fills in the details.
To allow for easy maintainablility, code should be easy to read and express the intent of the author. Otherwise, there is a high risk for code breaking as developers unfamiliar with the code implement it, as well as high maintenance cost.
Ways to express yourself include: choosing good names for your methods and classes, keeping functions and classes small, using standard vocabulary and patterns, and well written tests.
To avoid complexity and maintainability, keep the number of classes and methods low.