The Pragmatic Programmer by Andrew Hunt provides practical suggestions on all aspects of software development.
Guideline 1 – Write Understandable Code
Code is read more times than it is written so spend time writing clean code with clear variable names. Add comments when it is necessary to explain why the code is written that way and the decisions behind the implementation.
Each software module should be responsible for a single aspect of the system. When software modules are written to act independently, the system can provide more combined functionality as a whole. A module should not delve into another module’s implementation (Law of Demeter). Ask for what you need directly instead of digging through the module hierarchy.
Guideline 2 – Refactor Early
Refactor early to prevent existing code dictating future code. Refactoring is a process that must be undertaken slowly, deliberately and carefully. Always take short deliberate steps and have good test coverage before you begin.
Refactor when there is:
- Nonorthogonal design
- Outdated knowledge
- Improve performance
Every piece of knowledge in a system should have a single authoritative representation (DRY principle). Developers will often duplicate code in the short term to ship faster, at the expense of duplicating effort to update that code in the future.
Guideline 3 – Expect Errors
Everyone writes bugs. Do not trust or expect yourself to write perfect software and do not blame third-party libraries for your mistakes.
When you find a bug, try not to panic and concentrate on fixing the problem. The best way to start fixing a bug is to make it reproducible. This will also tell you when it is fixed. If you feel stuck, explain the problem to someone else as the act of explaining often reveals the solution.
Try to fail early at the site of the problem. Errors should not leave the system in an inconsistent state, for instance charging a credit card but not processing an order.
Guideline 4 – Test from the Start
Projects with automated tests have a better chance of success. Accessible test code is an invaluable example of code use, with crucial benefit of alerting you of regressions as you make changes to the system.
Build testing into the software from the beginning. Test each piece of the project independently with unit tests, then together with integration tests. When you design a module or even a single routine you should design both its contract and the code to test that contract.
Guideline 5 – Use Configuration Files
Put abstractions in code and details in configuration files. Configuration files allow an application to be customized without recompilation. This is extremely important in critical live systems which need to dynamically reload metadata while running to prevent downtime. Another use-case is distributing the same core app to different clients and enabling features based on their specific configuration.