The Dependency Structure Matrix or Design Structure Matrix (DSM) is a simple, compact, and visual representation of a system or project in the form of a square matrix. When talking about software, the DSM is a great way to visualize and manage dependencies between modules, which is critical to the management of software projects.
Frequently when discussing software dependencies you are thinking about directed graphs that looks something like this:
The DSM represents the same information as a graph, but in a more concise format.
The DSM row and column headers represent the boxes in the graph. The DSM non-empty cells represent the arrows in the graph. Why do you need two different ways to represent the same information? As you can see, the equivalent representation in terms of a graph quickly becomes cluttered and difficult to understand while the DSM scales easily and offers the ability to spot architectural patterns at a glance. Problematic dependencies, such as dependencies between modules, are also easy to identify (red triangles in the DSM above).
What are the benefits of the DSM?
The DSM is particularly good for analyzing large, complex systems. A number of partitioning algorithms can be used on the DSM for architectural discovery and management. For software, we typically recommend the component or reachability algorithms. They help identify layering and componentization within the software system even after architectural intent has eroded.
The results of the partitioning algorithms are displayed as square boxes, called virtual partitions, within the DSM. Here is an example of how the results of the component and reachability partitioners are displayed within the DSM:
Partitioning helps determine:
- Layering. The layered view of a partition group (called virtual partition), where the higher layer depends on the lower layer but not the other way around. This is a great way to visualize and maintain your current layering structure.
- Strongly (or cyclically) connected components. These are the subsystems that are interconnected so that there are dependency links that go from one of the subsystems to another. This is also an example of high cohesion. If these components were supposed to be loosely coupled (or modular), breaking the dependencies above the diagonal should be the goal.
- Independent components within a layer. These are subsystems within a layer that have no dependencies on each other.
Example using a DSM to analyze software architecture
For a real example, we are going to use the open source tool, Ant. Below is a partitioned DSM for apache.org’s Ant 1.5.1. This version of Ant is made up of 20 packages, which contain more than 400 classes.
Once you load Ant into the DSM, it is possible to partition Ant into three subsystems as seen above. These subsystems are layered in a particular order where the lower layers are independent of the higher layer. The first thing that you can observe is that the architecture is not completely consistent. In the cell with the red flag, the “x” (row 4, column 11) shows a feedback loop existing outside of the subsystem.
By keeping the infrastructure (ant) independent of tasks (ant.taskdefs), Ant designers had designed the layering to allow additional tasks to be developed by multiple developers simultaneously. The DSM above shows that they were only partially successful in that goal. The conditional tasks (taskdefs.condition, column 11), which is in the infrastructure component, is used by the tasks component. This creates a feedback loop or cyclic dependency between infrastructure and task components. One possible solution to this cyclic dependency is to move the conditional tasks into the tasks component.
The DSM also highlights how intertwined the types subsystem (row 9) is in the framework. This means that developers of newer types need to understand and deal with the entire ant infrastructure. If future improvements require parallel and easy development of new types, then it would be advisable to define a component architecture for types. These are some of the quick insights you can get by visualizing your architecture with a DSM.
System complexity results from dependencies that violate the intended architecture as you saw in the Ant example above. Bad dependencies prevent modularity. The lack of a well-defined and well-understood architecture makes software changes difficult. This leads to high software maintenance costs.
As another example, we have analyzed the Android kernel using Lattix Architect to illustrate how understanding software architecture and identifying dependencies can help any development organization manage the impact of change, improve productivity, simplify code maintenance, and reduce risk. You can view the results in this whitepaper. If you are interested in seeing how your software project looks in Lattix Architect, sign up for a free trial.