In software development the term refactoring has been established quite a while ago already in the context of code refactoring. However, there is also the refactoring of the design (i.e. changing the internal structures of subsystems, components, or services), database refactoring (i.e. changing the database structures), and architecture refactoring (i.e. changing structures of the system). In addition there are even organizational refactoring and process refactoring in projects, which don’t focus on the system developed, but rather on changes that will improve the project structure.
Like in architecture re-engineering projects, architecture refactoring activities have the goal to enhance the quality of the product by improving the architecture and design of the product. In that context increasing the habitability for the developers (developmental quality) is one of the qualities they both focus on.
Architecture refactoring changes the product through several design steps, each with a local focus, i.e. they do not change the external behavior and the semantics of the parts that are modified but only rectify the internal structure. The focus of refactoring lies on improving design and readability, and performing maintenance activities.
Indicators for Refactoring Activities
Refactoring is done when the design and/or code is too complicated, has bugs, or a “bad smell” (i.e. there are indicators that something is wrong), i.e. the system still works fine, but design and code may need improvement. Those are typically detected during code, design and architecture reviews.
Some typical “bad smells” requiring architecture refactoring are:
- Unclear roles and responsibilities of the design elements.
- Unnecessary centralization (e.g. singleton).
- A design that is too generic and tries to cover everything.
- Dependencies that are not necessary or cyclic dependencies.
- Asymmetry, i.e. there are different solutions for the same problem, or there is no symmetrical behavior (e.g. begin without end transaction).
- The “hammer and nail” syndrome, i.e. always the same solutions are used even if they don’t really match the problem.
- The architecture is not simple (i.e. it uses too many elements for the solution) or not expressive (i.e. the design is not easy to understand). E.g. proper naming of the design elements helps to better understand the architecture.
Other indicators for “bad smell” can be the metrics resulting from code quality management (CQM) activities. If e.g. a code complexity metric indicates that a certain part of the software has a high complexity, a refactoring of that part may be necessary.
A very neat method for detecting “bad smell” I’ve learned from Kevlin Henney: Using a tag cloud generator on the source code will show those words that are used more often in a more prominent way. So if e.g. Boolean, True and False are displayed very prominently, this is an indicator that a lot of flags are used in the code, which in turn indicates bad cohesion (e.g. a method performs two completely different types of logic based on a flag parameter, instead of providing two methods).
Refactoring in the Development Process
Since there is always change happening in product development that cannot be predicted (see also “Nothing is permanent except change”), it is important to plan ahead of time for change to be incorporated into the system. Thus the overall development process can be seen as a two-step approach: First the top-down design and implementation are performed as “green-field activities”, then the bottom-up clean-up activities are performed, i.e. the “brown-field gardening”. Refactoring is one of those gardening activities.
In the case of an iterative, incremental development process these two steps happen in each of the iterations continuously enhancing product quality and reducing risk by having feedback loops. This is especially important since the most critical decisions are done at the beginning while the most knowledge is gathered at the end. Therefore refactoring must be planned as last step for each of the iterations, in which architecture and code shall be adjusted based on the learning during the iteration. If architecture refactoring causes larger code changes, they may need to be planned and implemented during the next iteration. An evaluation of the impact is therefore crucial to architecture refactoring.
Also refactoring is the third step of the test driven development (TDD) approach, which I will discuss later. Independently of the development process, having a solid set of tests is essential for refactoring so that it is possible to verify that behavior and semantics of the refactored area of the system are not changed by the refactoring activity.
Relationship between architecture and code refactoring
Both types of refactoring focus on local changes. The major difference between architecture and code refactoring is that architecture refactoring focuses on the structures of the whole system and is much more abstract, while the scope of code refactoring is only the local piece of code and it can be performed in a very concrete and precise manner.
As long as there is no implementation yet, architecture refactoring is fairly easy and can be done without having to consider any implementation. However, if there is already an implementation of the architecture (or at least the affected part), architecture refactoring may cause code refactoring to be performed. Therefore evaluating the impact of the architecture refactoring on the existing implementation is critical and must be documented, e.g. explicitly specify the code refactoring steps that will be required due to the architecture refactoring.
It must also be kept in mind that several architecture refactoring steps may overlap, especially in the affected implementation. To avoid problems and confusion, it is therefore critical to first prioritize the refactoring steps (based on the requirements prioritization) and process them one by one in that prioritized order. It is critical to first address the strategic refactoring activities and only after that the tactical ones, as it is important that only after the architecture refactoring is done, the corresponding code refactoring steps may be performed. Having such a structured approach to address overlapping refactoring activities will significantly reduce the risk of breaking the system during refactoring.
References
- Interview with Michael Stal on architecture refactoring from OOPSLA 2007.
Wenn Sie diese Felder durch einen Klick aktivieren, werden Informationen an Facebook, Twitter, Flattr, Xing, t3n, LinkedIn, Pinterest oder Google eventuell ins Ausland übertragen und unter Umständen auch dort gespeichert. Näheres erfahren Sie durch einen Klick auf das i.
