Motivation: change is inevitable, even the most perfect code is subject to imperfect requirements (the real world is messy). A good design
- requires little time to make the most expected changes
- requires little time to validate changes
This would allow you to move faster and break fewer things.
Here’s a quick procedure
Look at the requirements, and find the weakest or most likely to change. Deduce from that what is most likely to change in your code. Make a ranked list of most likely changes
- For each change, answer the following questions:
- how many separate locations in the codebase need to be updated to make this change? Fewer is better
- what tests do you need to run to be sure ALL affected code (direct or indirect) is working as intended, no regressions? Fewer is again better
- As time goes on, you’ll see whether you were right about the changes you expected the most. Keep the list up to date as changes do actually happen, and keep re-evaluating your design to see if it is keeping up or needs some changes
A lot of good design advice falls out of these principles:
- “don’t repeat yourself” means factoring so fewer code locations need to be updated for each change.
- isolation, abstraction, and focus on decoupling via code contracts are all means of controlling side effects of a code change. Limiting the scope of side effects limits the number of code paths which must be tested after a change
- testing automates validation of important code paths, allowing you to spend less time validating code that changes often, or otherwise would be costly to manually test