Journeys around the refactoring of application and system architectures are dangerous. Every experienced developer probably has a horror story around an effort to evolve an application that has gone wrong. Because of this, any consideration around the refactoring effort of an application or system needs to start with a frank evaluation as to whether or not that application has hit the end of its lifecycle and should be retired. You should only consider a refactor if you are convinced that the return on investment for that refactor is higher than the return on a rewrite or replace. Even then, it should not be an automatic decision.
First, let us define a refactor. The multiple ways in which this word is used can lead to confusion. The first approach is best described by Martin Fowler, who defined it as “A change made to the internal structure of software to make it easier to understand and cheaper to modify without changing its observable behavior.” That is not the appropriate definition in this case. Instead, refactor in this case refers to a process that evolves the software through multiple iterations, with each iteration getting closer to the end state.
One of the common misconceptions of an application refactor is that the refactor will successfully reduce problematic areas. However, studies have shown that refactoring has a significantly high chance of introducing new problem areas into the code (Cedrim et al., 2017). This risk increases if there is other work going on within the application, thus an application that requires continuing feature or defect resolution work will be more likely to have a higher number of defects caused by the refactoring process (Ferriera et al., 2018). Thus, the analysis regarding refactoring an application has to contain both an evaluation of the refactor work and the integration work for the new functionality that may span both refactored and refactored work. Unanticipated consequences when changing or refactoring applications is so common that many estimation processes try to consider them. Unfortunately, however, these processes only try to allow for the time necessary to understand and remediate these consequences rather than trying to determine where these efforts will occur.
Analyzing an application for replacement
Understanding the replacement cost of an application is generally easier than analyzing the refactor cost because there tends to be a deeper understanding of the development process as it pertains to new software as opposed to altering software; it is much easier to predict side effects in a system as you build it from scratch. This approach also allows for “correction of error” where previous design decisions may no longer be appropriate. These “errors” could be the result of changes in technology, changes in business, or simply changes in the way that you apply software design patterns to the business need; it is not a judgement that the previous approach was wrong, just that it is not currently the most appropriate approach.
Understanding the cost of replacing an application then becomes a combination of new software development cost plus some level of opportunity cost. Using opportunity cost is appropriate because the developers that are working on the replacement application are no longer able to work on the current, to be replaced, version of the application. Obviously, when considering an application for replacement, the size and breadth of scope of the application is an important driver. This is because the more use cases that a system has to satisfy; the more expensive it will be to replace that system. Lastly, the implementation approach will matter as well. An organization that can support two applications running in parallel and phasing processing from one to the other will have less of an expense than will an organization that turns the old system off while turning on the new system. That you can phase the processing like that typically means that you can support reverting back to the previous version, before the last phasing-in part. The hard switch over makes it less likely that you can simply “turn the old system back on.”
Analyzing the Analysis
A rough understanding of the two approaches, and the costs and benefits of each approach, will generally lead to a clear “winner” where one approach is demonstrably superior to another. In those other cases, you should give the advantage to that approach that demonstrates a closer adherence to modern architectural design – which would most likely be the replacement application. This becomes the decision maker because of its impact to scalability, reliability, security, and cost, all of which define a modern cloud-based architecture. This circles back to my earlier point on how the return on investment for a refactor must be higher than the return on investment for a rewrite\replace, as there is always a larger error when understanding the effort of a refactor as compared to green-field development. You need to consider this fact when you perform your evaluation of the ROI of refactoring your application. Otherwise, you will mistakenly refactor when you should have replaced, and that will lead to another horror story. Our job is already scary enough without adding to the horror…
Cedrim, D., Gheyi, R., Fonseca, B., Garcia, A., Sousa, L., Ribeiro, M., Mongiovi, M., de Mello, R., Chanvez, A. Understanding the Impact of Refactoring on Smells: A Longitudinal Study of 23 Software Projects, Proceedings of 2017 11th Joint Meeting of the European Software Engineering Conference and the ACM SIGSOFT Symposium on the Foundations of Software Engineering, Paderborn, Germany, September 4–8, 2017 (ESEC/FSE’17), 11 pages. https://doi.org/10.1145/3106237.3106259
Ferreira, I., Fernandes, E., Cedrim, D., Uchoa, A., Bibiano, A., Garcia, A., Correia, J., Santos, F., Nunes, G., Barbosa, C., Fonseca, B., de Mello, R., Poster: The Buggy side of code refactoring: Understanding the relationship between refactoring and bugs. 40th International Conference of Software Engineering (ICSE), Posters Track. Gotherburg, Sweden. https://doi.org/10.1145/3183440.3195030