This post is a part of How To Ship Maintainable Product series
Every solution is based on an idea. Every idea is based on observation. In order to build maintainable software, we should build solutions from observations. Usually, that implies an upfront domain knowledge requirement.
Business thinks in money dimension. Fulfilling the business goals is the ultimate objective. Creating a solution is a
cost required to meet the goal. This bias can have an impact on requirements transfer from business to software engineers. We can then build software nobody needs nor uses.
That is why we - developers - should demand proper requirements
There are several techniques to get requirements in written form, sometimes even discover them with product owner etc.
Just to name few:
- Sequence diagram - is one way of gathering the requirements. It may look little bit naïve, but it helps to understand the processes taking place is the system.
- Event Storming - recently introduced by Alberto Bartolini DDD-way of requirements gathering, usually in workshop form.
Be prepared for a change
As system designers, we should prepare the solution to new business changes by making it easily adjustable. We already know that any part of our software may be affected in the future. If the proposed business value has to pivot - we should pivot our code too. Throw away unnecessary pieces, tweak some others and maybe add a few new.
Agile Manifesto says: Responding to change over following a plan. This is the natural way of adapting to an evolving ecosystem.
Design should be as simple as possible, but not simpler. Every single unit existing in our codebase must absolutely necessary to fulfil the business goals. Optional classes/modules/components are just garbage and introduce unnecessary confusion. We only waste energy by wondering what are they here for.
Organize the solution structure is commonly understood and used standards. Use best practices form language of your choice. Instead of re-inventing the wheel, just use what is already there. It will help you during maintenance - if you ever reach that point :)
Divide a big problem into small problems that are easier to tackle. They are also easier to understand and test.
Modular solution allows replacing bits and pieces in separation
Best designs do not change too often. They are easy to extend and tweak. The key is to divide the solution into modules of the correct granularity.
KISS - keep it simple, stupid!
You design (and not only design) should be super simple. Interfaces should serve almost as documentation. Based on the overall view you should have a feeling of how the pieces are connected together and how the system works. The best validation of your design is when somebody else looks at it and start asking questions. Too many questions can mean that the design is cumbersome to understand. Even worse if it’s you who as yourself those questions :)
Apply SOLID principles to make fine-grained modules. Try to use Design Patterns - but not force yourself (or others) to use all of them everywhere. Use then when they fit.
Big Design up front
Do not over engineer. BDUF is your enemy - after you design is ready it may be too late. Business could have changed already several times. Make something that works from the beginning and extend it incrementally. It is easier to adjust a simple solution, with little code, than a large codebase.
That is the bare minimum what you need to know about requirements gathering and creating a simple design.