Everything is Divide and Conquer
An interesting way to think about software design.
Julius Caesar was reputed to say “Divide et Impera” or “Divide and Conquer”. He used this strategy to divide and conquer the Gauls, simplifying his war with them into a series of smaller conflicts, each more easily winnable on its own. This strategy of breaking down a larger problem into smaller, easier problems is really the only useful strategy I know of for addressing code complexity. This core strategy of divide and conquer actually takes on dozens if not hundreds of names in computer software. Here are just a few examples. At the large scale:
- The Internet itself divides and conquers the problem of routing information for the whole planet through a hierarchy of addressable sub-networks
- Enterprises divide and conquer problems of service quality and high availability by distributing data and service requests to network operations centers located in different geographical regions
- Enterprises divide and conquer large scale systems by using networks to organize servers into clusters and server farms
- Individual servers divide and conquer the problem of concurrent code execution by dividing code into processes
- Virtual machines divide and conquer the problem of varying run-time environments by dividing code description (byte code) from code implementation (machine code)
- Enterprise “tiers” divide and conquer large projects by organizing groups of related modules into independent service layers
- Modules divide and conquer the problem of organizing and configuring related sets of features
At the small scale:
- Packages divide and conquer code complexity and security issues by organizing related classes and resources
- Interfaces divide and conquer code binding issues by decoupling the intention to make a method call from the exact method to be executed
- Dependency injection and locator registries divide and conquer code binding location issues by decoupling the desire for an implementation from the source of the implementation
- Design patterns divide and conquer code complexity by decoupling the features of a design into smaller, simpler, more flexible classes
- Objects themselves divide and conquer through encapsulation by separating internal implementation from external use, yielding increased flexibility to change the implementation at a later date without affecting clients
I’m sure you can think of many, many more examples.
In our work as software designers, it’s quite reasonable to expect that any approach we might take to modeling a real world process is going to involve dividing it up into pieces. But the process that you use to analyze your problem and break it down will determine the quality of your model. And the quality of your model is the quality of your code.
You can easily find some dividing lines using a haphazard, even unconscious approach to analysis, whether it be experience, group consensus or gut instinct. But what separates the excellent, flexible, functional, testable and reusable from the ordinary is this:
The ability to find the clearest dividing lines that break a problem down fully.
The more detailed and precise your understanding of the concepts involved in the process you are trying to model, the more likely it is that you will identify ways to divide those concepts up cleanly. It takes time and practice to get really good at this, but you will find if you do practice mindfully that you get better and better at it.