Most developers are familiar with the term refactoring, but refactoring is not constrained to just code. It is applicable to software architecture as well. Architectural refactoring is improving the design of an existing software application. Architectural refactoring changes the structure of the code but not the functionality.
The problem is that, over time, software architecture erodes as it evolves (see our blog post on architectural erosion). The original design may be lost or was never intended to address new requirements. Architectural refactoring, like redesigning a city, needs to be done in pieces and be part of a controlled, iterative development process. This refactoring deals with resolving architectural smells like breaking dependency cycles, splitting subsystems, and enforcing strict layering.
The goal is to improve a set of quality attributes such as performance, scalability, extensibility, testability, and robustness. As it is more involved than code refactoring, architectural refactoring is more than just a technical task – it’s about justifying your design, creating a case, and presenting your ideas in a well-thought-out plan to your business.
Architectural Refactoring vs Code Refactoring
Architectural refactoring typically involves code refactoring as well, which leads to confusion between the two. As Martin Fowler says, code refactoring restructures code to make it more maintainable without changing its observable behavior. For code refactoring, you focus on software entities like packages, classes and methods.
Code refactoring is a bottoms-up activity that preserves structure. Architectural refactoring is a top-down activity that improves structure. It pertains to components, connectors, subsystems, and interfaces. Architectural refactoring is a deliberate process to remove architectural smells while not changing the scope or functionality of the code. When you refactor the architecture, you can revisit architectural decisions, now with more domain knowledge, and seek better alternatives.
How to Perform Architectural Refactoring
“Architecture is the stuff that’s hard to change” – Martin Fowler
Architectural refactoring should be part of an iterative development process. The goal is for incremental improvements in each development cycle or sprint. Here are steps on how to perform this refactoring:
- Understand and visualize the current architecture. A Dependency Structure Matrix (DSM) is a great way to visualize the current architecture (watch our How to Read a Dependency Structure Matrix video). This quickly gives you an understanding of the components in your software system and how they are connected to each other. With this knowledge, you might find that your systems or components are too tightly coupled or too dependent on each other.
- Determine what architectural changes are needed. For example, if you have a monolithic application, maybe splitting it into multiple units or services is the answer (microservices).
- Develop a high-level refactoring plan. Create a worklist of items that need to be fixed. If you are using a tool like Lattix Architect, you can set up rules to make sure future builds do not break your intended architecture (watch our How to Specify Architectural Rules video).
- Monitor the architecture as you refactor. This refactoring should be done incrementally. The architecture needs to be monitored to make sure it is trending towards a clean state and new architectural violations are not being introduced.
Architectural refactoring is more than a technical task. It is about creating a proper case and selling your ideas. Always remember to identify the business value associated with the refactoring effort to justify the cost. This can be increased performance, reduced downtime, faster delivery and time to market, and improved quality. Finally, software architecture should be continuously monitored because as the software evolves the architecture decays. The longer the architecture is left unchecked the more expensive the architectural refactoring. A solution like Lattix Architect, which is designed for refactoring, can simplify the process