" A primary cause of complexity is that software vendors uncritically adopt almost any feature that users want" - Niklaus Wirth
Software is inherently complex, and so is its development. Careless development may produce the desired product and win you the satisfied customer. But when the customer comes back with new requirements/features to be added, then it may put you in a lot of trouble.
How do we know that our software can put us in trouble and it may require redesign?
Before you start blaming stakeholders, look at the following 8 symptoms of troubling software, which may become hard to evolve and change:
- Object Instantiation to Concrete Classes
- Using Explicit Operations/Implementation
- Building Hardware or Software Specific solution
- Tight coupling
- Inability to alter classes conveniently
- Extending functionality by Sub-classing
- Dependence on object implementations
- Dependence on Algorithm
In the first part, we will examine the first 4 symptoms.
1. Objects Have Neen Instantiated to ‘Concrete Classes’ Explicitly
Specifying a concrete class name when you create an object commits you to a particular implementation instead of a particular 'interface'. 'Abstract Factory' and 'Factory Method' design patterns can help you to avoid such situations.
2. Using Explicit Operations/Implementations
When you specify a particular operation, you commit to one way of satisfying a request. By avoiding ‘hard-coded requests’, you make it easier to change the way a request gets satisfied both at compile-time and at run-time. Design patterns to use in such situations are: 'Chain of Responsibility' and 'Command'. Sample code is shown in above picture.
3. Building Hardware or Software Specific Solution
External OS Interfaces and APIs are different on different hardware and software platforms. Software that depends on a particular platform will be harder to port to other platforms. It may even be difficult to keep it up to date on its native platform. It's important therefore to design your system to limit its platform dependencies. Design patterns to get help from are: 'Abstract Factory' and 'Bridge'
A very common mistake that developers commit, for example, to explicitly use specific Database Client (MySql, Oracle etc.) rather than using Abstract Database Client.
4. Tight Coupling
Classes that are tightly coupled are hard to reuse in isolation; since they depend on each other. It leads to monolithic systems, where you can't change or remove a class without understanding and changing many other classes. The system becomes a dense mass that's hard to learn, port, and maintain. To decouple such systems, you may refer to: 'Abstract Factory', 'Bridge', 'Chain of Responsibility', 'Command', 'Facade', 'Mediator' and 'Observer'.