The mightiest rivers lose their force when split up into several streams.
Ovid
What Is Decomposition?
The academic definition of decomposition is “a method that allows us to replace the solution of a complex problem with the solutions of many interrelated but smaller problems”. In simple words, we divide a whole into parts to make it more convenient to interact (analyze, manage etc.) with each of the smaller parts.
Decomposition is widely used in computer science and project management, particularly in software development. In this article, we will look at cases of its use by testing professionals.
Decomposition is usually represented as a hierarchical tree, but for testing purposes it may simply mean that the system (or its individual components or functional parts) is seen as consisting of relatively independent subsystems, each of which is much easier to test than the whole system at once (we will refer to any application under test as the “system”).
Why Decompose?
In general, decomposition is used to:
- aid in the assessment of project feasibility, as well as the resources required to complete it
- determine the sequence of project tasks and their priorities
- delegate tasks to team members depending on their qualifications and other skills
Often decomposition also helps cope with procrastination: if the system is too complex, we understand WHAT to test, but we may not understand HOW to do it or WHERE to start.
When applied to software testing, decomposition is useful for:
- collecting information about the system when performing exploratory testing
- writing checklists or test scenarios (e.g., for regression testing)
- analyzing and testing requirements
- test planning (evaluation and prioritization of required resources)
- designing automated checks based on page object pattern
Decomposition in the testing process helps us achieve better quality and provides greater confidence.
Decomposition Criteria
As an example, we will use a typical site for ordering pizza and various additions to it. Our site is called “My Tasty Pizza” has a typical structure:
- a global navigation bar and buttons to sign up/sign in at the top
- a carousel of images linked to pages with information on new products and deals in the middle
- a footer section with contact information, links to mobile applications, and pages of the pizzeria in social networks at the bottom
Before we start decomposing our system, we need to decide what criteria we will use for that. Let’s review a few basic ones.
Decomposition by GUI Elements
When decomposing the system, we rely on the elements of its graphical user interface as a guide.
We look at the system through the eyes of its users, and thus can quickly provide coverage of the most important, visible functionality.
The disadvantage of this approach is that we don’t see “invisible” functionality, such as API functions that are not accessible through the GUI.
Decomposition by User Actions
The system is decomposed based on the actions users can perform on the website:
This approach is applicable to a vast majority of systems and can be used in addition to GUI-based approach to extend coverage.
Unfortunately, such versatility is also a disadvantage, because it may not always correctly reflect the relationships between the subsystems with some of them depending on each other, which makes it impossible to test them in isolation.
Decomposition by Business Process Stages
This is a more advanced approach that ensures maximum consistency with real use cases.
For example, when ordering a pizza, the user performs several consecutive steps and goes through a series of states: signing in (ordering scenario is also possible without signup), choosing a pizza from the menu, selecting toppings (an optional step), adding everything to the cart, and making a payment. Once the order is complete, the user can track the delivery on the website or in the mobile app. In addition, the order can be picked up at the selected restaurant, or the user can order catering services (a separate use case).
Since each individual scenario corresponds to a specific use case, it provides good traceability to requirements and ability to quickly test and deliver a minimal viable product (MVP).
On the other hand, effective decomposition using this approach requires well-designed and documented requirements and use cases.
Other Decomposition Approaches
There are other approaches to decomposition that depend on the system, qualifications of the tester, and the goals of testing.
For example, we can decompose based on data that our system takes as input, then stores and processes, and finally passes to output (“inputs/process/outputs” approach). This includes processing web forms, opening, saving, and printing files, exporting internal data for interoperability with other systems, etc.
A role-based/security decomposition is also possible when there are accounts with different access levels in the system. Unregistered users may have no access to certain parts of the system, registered users will have limited access, and administrators will have full set of permissions everywhere. Given that, each role will have its own specific scenarios for using the system.
Decomposition Best Practices
For more efficient decomposition, consider the following:
- Each act of decomposition forms a new level of depth (the original system is at level 0)
- All subsystems at the same level, which are children of the same parent system, should be decomposed by the same criteria. In other words, all those subsystems should answer the same question concerning their parent
- At each level, it is recommended to have no more than 7 subsystems. It is believed that a human brain is less efficient at comprehending a larger number of items than this
- The total number of levels should be 2 to 6, while 3 is optimal in most cases. The depth depends on the degree of understanding of the system by the decomposer. Lowest level subsystems are called “elementary”, and if decomposition is done to create a checklist, such subsystems represent ideas for tests
- Critically re-evaluate decomposed system time to time. Is everything covered? Maybe there are redundant or overlapping branches? Does the system have external relationships (integrations with other systems, external user groups, etc.)?
- Think ahead of any future changes in requirements if the system is going to be expanded since the changes will be represented by additional subsystems on existing levels
Recommended Reading
If you’re interested in learning more about this topic, I highly recommend “Righting Software” by Juval Löwy.