Refactoring for Architecture Smells: An Introduction

“Cities grow, cities evolve, cities have parts that simply die while other parts flourish; each city has to be renewed in order to meet the needs of its populace…
Software-intensive systems are like that.”

– Grady Booch

“Code smells” or “bad smells” [1] are considered structures or code fragments that indicate deeper problems in code and suggest the possibility of refactoring. Refactoring [1] is the technique to eliminate smells and is defined as behavior-preserving program transformations.

In general, smells and their corresponding refactorings are applied at various granularity levels of abstraction. Smells could be categorized as implementation smells [1], design smells [2], and architecture smells [3]. How do we decide whether a smell is an implementation, design, or architecture smell? It is based on the characteristics, scope, and the impact of the smell. Implementation smells have limited scope (typically confined to a class (or file)) and have a limited local impact. On the other hand, architecture smells span to multiple components, have a system level impact. Because smells differ in their scope, impact, and effort required for refactoring, it is pragmatic to classify the smells into implementation, design, and architecture smells. Similar to smells, refactoring techniques applied to refactor these smells can also be classified as implementation refactoring [1], design refactoring [2], and architecture refactoring [3].

In this article, we focus on architecture smells and architecture refactoring. We can borrow and extrapolate the definition of code and design smell to define architecture smells. Architecture smells are architecture decisions or structures that “negatively impact system quality” [4]. On the similar lines, architecture refactoring can be considered as semantic-preserving architectural transformations for addressing architecture smells [5].

Let us consider an example of architecture smell from an industrial project. In this case, one of the architectural components of the application is a Data Access Layer (DAL). The architectural decision made earlier with respect to DAL in the software is that all the accesses to the database (Oracle) must be made only through the DAL. The project roadmap had plans to support other databases such as MySQL and MS SQL as well in the upcoming releases. However, developers introduced numerous SQL queries that directly accessed the database skipping the DAL either due to negligence or due to lack of appropriate knowledge transfer of the architectural decision. This “skipped layer” smell affects the flexibility of the architecture (in supporting new databases) and hence negatively affects system quality. The project team had to later refactor the SQL queries and route the calls through the DAL when they needed to support MySQL and MS SQL databases in the later releases. The name of the smell, that occurred in this case, is “skipped layer” smell which required an architecture refactoring to enforce the original architecture decision of directing the data access calls through DAL layer (see Figure 1).

skipped layer
Figure 1. Refactoring for “skipped layer” smell

Another very commonly known architecture smell is “Cyclic dependencies between packages”. For instance, consider extensive cyclic dependencies between packages in the java.lang package (Figure 2); the figure is generated from “Structure 101 for Java (version 4.1)”. The packages involved in the cycle have to be used, reused, tested, and deployed together. For this reason, this smell negatively affects maintainability, reusability, testability, reliability, and deployability of the software.

cyclic dependency
Figure 2. Cyclic dependencies between packages in java.lang package

There are many options for refactoring such cyclic dependencies:

  • Break one of the dependencies (by removing unused classes or part of the classes responsible for the dependency to the other package)
  • Change the dependency direction (by moving classes or part of the classes)
  • Extract another package from one of the packages to a new package in such a way that the cyclic dependency breaks.

refactoring cyclic dependency
Figure 3. Refactoring by breaking cyclic dependencies between packages

Apart from the discussed examples of architecture smells, there are many commonly known architecture smells such as “complex package” and “back layer call”.

There are many important reasons for performing architecture refactoring. Let us examine one of the very prominent reasons here. When architecture debt [6] accumulates, the clear impact of the debt is felt in the form of reduced productivity and reduced agility – i.e., the team is unable to keep up with increasing customer needs and the number of features delivered by the team reduces over time. Most often, the problem is due to lack of refactoring as part of the development process that manifests as architecture and design decay. The system becomes brittle – adding one feature requires touching many components and those changes have ripple effects and results in breaking other components. Performing architecture and design refactoring helps repay debt, enables agility, and gets the project on track.

In summary, architecture smells are architecture decisions or structures that negatively impact software qualities. Architecture refactoring is semantic-preserving architectural transformations for addressing architecture smells. Performing architecture refactoring enables agility and helps keep architecture debt under control.

References:

  1. Martin Fowler, “Refactoring: Improving the Design of Existing Code”, Addison-Wesley, 1999.
  2. Girish Suryanarayana, Ganesh Samarthyam, and Tushar Sharma, “Refactoring for Software Design Smells: Managing Technical Debt”, Morgan Kaufmann/Elsevier, 2014.
  3. Michael Stal, “Software Architecture Refactoring”, Tutorial in the International Conference on Object Oriented Programming, Systems, Languages and Applications (OOPSLA), 2007.
  4. Joshua Garcia, Daniel Popescu, George Edwards, and Nenad Medvidovic, “Identifying Architectural Bad Smells”, European Conference on Software Maintenance and Reengineering (CSMR ’09), 2009.
  5. Michael Stal, “Architecture Refactoring”. Available online at: http://stal.blogspot.com/2007/01/architecture-refactoring.html [last accessed on 8-Nov-2015]
  6. Ipek Ozkaya, “Strategic Management of Architectural Technical Debt”, SEI Agile Research Forum, 2012. Available online at: http://www.sei.cmu.edu/library/abstracts/webinars/Strategic-Management-of-Architectural-Technical-Debt.cfm [Last accessed: 9-Nov-2015]