Analyzing Architecture Quality Evolution

Aug. 25, 2019

Tags: Code quality , Architecture smells , Refactoring , Case study , Maintainability , Software architecture quality , Java , Evolution , DesigniteJava

Code smells occur at all granularities. We may categorize smells based on their scope and impact. Specifically, smells arising within a local scope, typically within a method, could be referred to as implementation smells (such as empty catch block or magic number). Smells that involve properties of a class and the scope of impact comprises a set of classes then they are referred to as design smells (such as god class and multifaceted abstraction). Smells arising at the highest granularity, where we observe the properties of components (packages/namespaces) and their influence on the whole system, are referred to as architecture smells (such as god component and dense structure).

The architecture of a software system represents the critical design decisions that span multiple components and have a system-level impact. Therefore, architecture smells affect a set of components and given its relatively wider scope require considerable effort to refactor. Though the risk and effort to refactor increases with the increase in the granularity of smells, their benefits also increase significantly. In this context, it is relevant to understand the evolution of architecture quality. The evolution may reveal interesting insights about architecture quality of the software project.

This article provides a summary of architecture smells with examples and presents a case study of analyzing the evolution of architecture quality using DesigniteJava and an open-source utility program. You may use the open-source utility to carry out a similar analysis for your Java project.

Architecture smells

Software engineering literature has documented numerous architecture smells; a detailed list can be found here. Let us understand some of the architecture smells that we can detect in a software system.

  • Ambiguous Interface: This smell arises when a component offers only a single, general entry-point into the component.
  • Cyclic Dependency: This smell arises when two or more architecture components depend on each other directly or indirectly.
  • Dense Structure: This smell arises when components have excessive and dense dependencies without any particular structure.
  • Feature Concentration: This smell occurs when a component realizes more than one architectural concern/feature.
  • God Component: This smell occurs when a component is excessively large either in the terms of LOC or number of classes.
  • Scattered Functionality: This smell arises when multiple components are responsible for realizing the same high-level concern.
  • Unstable Dependency: This smell arises when a component depends on other components that are less stable than itself.

Let us take an open-source project to analyze and see some examples of architecture smells. We analyzed the latest version of Jenkins using DesigniteJava Enterprise. The analyzed Jenkins version contains 203 thousand LOC.

We found many instances of god component architecture smell. A large component is difficult to understand and thus harder to maintain. Many such instances reduce the maintainability of the project. One of the instances reported in package hudson.model; this package contains 646 classes and total 56,710 LOC.

The tool also reports an instance of cyclic dependency smell. This instance contains a long chain of dependencies forming a long tangle. The involved components are hudson.init, hudson.util, hudson,, hudson.model, jenkins.model,, hudson.model.queue,, hudson.tasks, hudson.model.listeners,, hudson.diagnosis, jenkins.util, jenkins.model.lazy, hudson.widgets, hudson.scm,, jenkins, hudson.slaves, jenkins.slaves, hudson.node_monitors, hudson.console, It is important to realize that unit cycles (two components depend on each other) are relatively easier to find by a human eye. However, cycles of length 3 or more are subtly hidden in your code and you need tool support to help you reveal such instances.

A feature concentration architecture smell occurs when a component is realizing more than one architectural concern/feature. In other words, the component is not cohesive. Akin to LCOM (Lack of Cohesion of Methods) that applies to classes, DesigniteJava computes LCC (Lack of Component Cohesion) to measure the component cohesion. Package suffers from this smell where computed LCC is 0.7. Independent sets of related classes within this component are: [PathRemoverTest, FileLockerRule, PathRemover, PathChecker], [FileBoolean], [LinesStream], [CompositeIOException], [RetryStrategy], [PausingGCRetryStrategy], [OnMaster].

Scattered functionality indicates that two or more namespaces are realizing the same architectural concern (kind of opposite to the feature concentration smell). DesigniteJava checks access to external namespaces that occur together from a method. If such accesses happen many times in a component, it leads to a scattered functionality architecture smell in the accessed components. One of the 18 examples in the analyzed code shows that hudson.model and jenkins.model are accessed together frequently and are realizing similar functionality.

The last example of architecture smell belongs to dense structure. This smell occurs when all the components form a very dense dependency graph. Thus, at most only one instance can occur per analysis. DesigniteJava forms a dependency graph among all the packages and computes the average degree of the graph. For the analyzed version of Jenkins code, the tool reported an average degree = 9.02 that implies that each component is associated with more than 9 other components on an average which is quite large. It indicates that coupling among components is high and efforts must be dedicated to reducing it.

Component structure
Component dependency graph of the analyzed version of Jenkins

Analyzing the evolution of architecture quality

We develop a utility program in Python to analyze multiple versions of a Java project and detect architecture smells using DesigniteJava. This utility program uses the analysis reports generated by DesigniteJava and then produces evolution data (LOC and number of architecture smells in each version) and plots (architecture smell density, version-wise architecture smell distribution, and component dependency structure) to present evolution. This utility program is open-source and you may use it to observe the evolution of architecture quality of your Java projects.

Here is the result of analyzing 10 versions of Jenkins. The utility program summarizes each analyzed version including total LOC and number of architecture smells found.

Version Commit-hash Date LOC Total architecture smells
V1 8a0dc230f44e84e5a7f7920cf9a31f09a54999ac 05/11/06 29345 14
V2 c817a9dae8fbc406ee4d62ddfc10d57424ee8a2e 03/03/08 61742 34
V3 f4302f544d0fb0165cdd10da073d06678e66ebe3 03/04/09 89374 47
V4 7c3e2b1cf449c84865df159365f1a5224eab25e8 22/12/10 118664 79
V5 753d6253485b0bd0b328b89bc39927fc44b37611 25/12/11 127511 91
V6 5894e301abcb1fe434cee9b7385af3ace11d1cb6 22/05/13 144107 105
V7 149d078adb3a08755978095f895d692305150ba3 10/08/14 147747 96
V8 57473e82ce63db47bbaf53383629aa2bd14def26 03/02/16 155904 96
V9 adf01d08884bcebbb802543fb71c68073bb6c7cc 22/07/17 178189 115
V10 374ce3a0d8a65d8e5e74111f5da9488e9a46c2ca 16/08/19 203144 122

Comparing absolute values of detected architecture smell instances across versions is not a good idea because the size of the code is also changing. Therefore, we compute smell density. It is a normalized metric capturing number of smells per one thousand LOC. The utility program produces the plot as follows.

smell density
Smell density across all analyzed version

It shows that architecture quality was deteriorating till V6 and then started improving. It could be the result of conscious focus on architecture quality and refactoring.

We are also interested in fine-grain details. The utility program generates smell-wise summary too so that we can observe the contribution of individual architecture smells per version towards quality degradation. The generated summary is presented below.

Version Ambigious interface Cyclic dependency Dense structure God component Feature concentration Scattered functionality Unstable dependency
V1 0 1 0 1 8 0 4
V2 0 2 0 8 16 1 7
V3 0 2 0 9 23 4 9
V4 0 3 1 16 34 10 15
V5 0 3 1 16 39 13 19
V6 0 1 1 20 48 16 19
V7 0 1 1 19 49 9 17
V8 0 1 1 18 50 7 19
V9 0 1 1 18 53 19 23
V10 0 1 1 21 57 18 24

Graphically, we can observe the same information in the form of a stacked-bar plot. We can observe that feature concentration smell instances are the most frequently occurring architecture smell in Jenkins followed by unstable dependency.

smell distribution
Smell distribution across all analyzed version

Finally, we can see how the overall structure of the software getting complex in each analyzed version. The utility produces the component dependency graph for each analyzed version where dense structure smell is detected. In these plots, each component is represented by a graph node and size is proportional to their degree. These plots also show five components with the highest degree (number of dependencies to other packages).

component dependency graph
Component dependency graph (V4 - Dec 2010)
component dependency graph
Component dependency graph (V6 - May 2013)
component dependency graph
Component dependency graph (V8 - Feb 2016)
component dependency graph
Component dependency graph (V10 - Aug 2019)

Go ahead. If you have a Java project, you may use this open-source utility along with DesigniteJava Enterprise to understand quality characteristics of your software architecture.