Software is designed and implemented to solve problems. While some problems are more complex than others, every problem requires certain breaking down and simplification. This is called divide and conquer. Latin version is “divide et impera” and this has been one of the most successful politics strategy among our short history of politics. Although the history of software is even shorter and not comparable to politics, the necessity of divide and conquer strategy is vital. A software engineer or architect needs to divide a problem into smaller pieces to understand it better and to come up a comprehensive solution. In this post, you will be reading about the ways to break down a big problem into more manageable pieces and we will be discussing which way is better.
Functional Decomposition
Functional decomposition is the traditional way to break-down a complex problem into smaller pieces. Most of the time, it is the most evident and obvious solution to a given problem. To achieve functional decomposition, object oriented programming (or sometimes other paradigms as well) influences the problem solver to construct the smaller pieces. I would like to concentrate on the mental model of the programmer in decomposing the problem and let’s consider an object oriented programming language is used. Object oriented programming will allow the programmer to make abstractions of the bigger problem into smaller functional pieces. Functional decomposition is the first solution which comes to mind when designing software. I think this is because people who are coding using OOP languages are inclined to design their systems with functional decomposition because of the way OOP is taught to them. Also almost always there is an obvious break-down of the problem using this decomposition method.
Is that right thing to do?
Absolutely not, from the software architecture point of view. Functional decomposition leads the complex problem to be broken down to smaller functional problems which are isolated from each other in the wrong way. Solutions to small functional problems force coder to implement incorrect encapsulation which prevents reuse between different sub-solutions and make solution to small problem also over complicated. Joe Armstrong criticize Object Oriented Programming “The problem with object-oriented languages is they’ve got all this implicit environment that they carry around with them. You wanted a banana but what you got was a gorilla holding the banana and the entire jungle.”
Object Oriented Programming is a powerful tool, but relying only on it when decomposing software is not the right approach.
Volatility Based Decomposition
I heard this type of decomposition at a conference from Juval Löwy. Decomposing by volatility means that system should be designed via separate modules with different volatility levels. Those modules should be isolated from each other and changing one of them should not affect the other modules. It is in a way close to composition design pattern. Breaking down a big problem into smaller pieces is not that easy when the solution is not as evident as in functional decomposition.
Rules:
– Identify change areas and isolate similar change areas from others.
– Do not use functional change as a change area.
– Integrate features onto the architecture (features are not implementation)
– Do not resonate with change
Where does object oriented paradigm stand in this decomposition as a tool? Volatility based decomposition takes advantage of powerful encapsulation mechanisms. Interfaces and classes should be designed to isolate the implemented change area/module from other modules. Features emerge on top of the different volatility levels. Functions or features are most of the time at the highest volatility level and changing features should not break the architecture.
Credits
This blog post was inspired by Juval Löwy at Zen of Architecture session presented in Software Design and Development Conference 2019, London.