These are principles that I have picked up along the way which have been reinforced by experience. These principles, which can be found in many programming books, I have found to be generally valid and useful. I’ll add to this list as I remember them.
Verify As You Go
Devise ways of testing the theory design and implementation of your project as you work. Create ways of walking through the design, build unit tests as you code, keep the application in a runnable state as you work so that it can be tested.
Design Components In One Scale
Design systems, data structures, classes and other components to work at a particular scale. Components should interact with other components at different scales but should not perform actions at those scales. For example, a class that is design to hold data should not also attempt to perform UI operations or database reads and writes. This rule creates a simple tiered structure that can be managed and understood as the application develops. A good design should consider the thousands of angles and interactions within the program. Designing components at their appropriate scales allows you to narrow the problem down to those angles and interactions working at one scale at a time.
Refactor in Bursts
Be aware of the impact of your design choices as you code. Refactor when it becomes consistenly clear that the design can be significantly improved. Refactor when the team has clarity about what design fix is needed, not when the project plan calls for refactoring. Make the decision to refactor first, then plan the time to do it. As the cost of refactoring builds with the amount of code, devise ways of testing the new design (Verify As You Go) before you refactor.
Learn As You Go
The best time to learn design skills or new technologies is when you are working on a project. Research as you work.
Don’t Copy, Steal
When you copy, without modification, design or code from another application or from a book such as a book on design patterns you are not taking ownership. The copy remains in your application as someone else’s idea, some one else’s code. It makes for an incongruity in the application design where we shift from one paradigm to another. It also may be an area of your own application that you don’t understand. Rather than copy, steal. Take ownership of the stolen ideas, make them your own, understand them, incorporate them into your code. When you bring in an outside library, don’t recode it, but do understand how to use it and devise your own way of use that is unique for your application, take ownership of its use. Try not to “wrap” outside libraries, the insulating buffer isolates you too much from the library’s intent and may not provide you the interchangeability you strive for unless very well designed. Rather learn the library and understand its use, if you need a wrapper, learn the intent of similar libraries and build an interface that really is interchangeable.
Create Reuse on the Third Implementation
The first implementation of a function is unique to its particular context. The second implementation is an experiment in reuse. The third implementation creates the library. It is good to strive to create reusable components in your code, but don’t force it. Just because a reusable library can be written does not mean it is useful. A reusable library not reused is waste of effort.
Evolve the Design
Create a high level vision for the project. Understand what it must be to accomplish its basic goals. Understand what it has the potential to be if well designed. Understand what is important and what are the details. Evolve this vision as you work. Refactor in Bursts. Jettison unnecessary baggage. Remain true to the vision. If the vision divides, create another project with a different vision. Do this as you work, not in a preplanned “design” phase.
Create Diagrams that Communicate
The purpose of diagrams and documentation is to communicate. Don’t clutter them by attempting to convey every detail of every system, class, operation, table column, variable, relationship, enumeration, or etc. Use economy and focus to highlight the details that present the broader picture while removing details that don’t. Instead of one giant diagram that represents everything, create smaller digestable diagrams that represent the system from different view points: how the user sees the application, the high-level table structure, how the application is to be deployed on servers, etc. Customize these views by being selective with details. For the complete detailed picture rely on the source code and installation scripts (try not to have many manual build/installation steps). Use automated tools to generate documenation directly from the code.