Application Refactoring is the rewriting of one or more components of an application, typically to take advantage of public cloud services. This can also involve refactoring the traditional application into from a legacy 3-tier application design to granular, micro-services based applications. Often, new components – such as replacing older Oracle databases with modern AWS Aurora – are often part of refactoring applications for the cloud.
The refactoring process may also involve new languages and tools, utilize APIs to communication between services, and improving performance by moving from an interpreted to compiled language.
Application refactoring is useful for extending the life of an application, improving its performance, adding needed new functionality, strengthening security, or adding support for mobile platforms such as iOS and Android, which can expand an application’s reach through the app stores for those new platforms.
Often developers will take an application refactoring approach that increases the modularity of the code while making the code easier to read, update, and to maintain. As a side benefit of creating modular code, those code modules become available for use in other applications, either directly incorporated or as part of a cloud-native application that utilizes microservices and APIs to stitch together multiple modules.
Refactoring enables continuous improvement of business application logic, making the code easier to work with and to modify. This enables code to evolve over time and for organizations to incrementally implement features or technology that improves the code performance or maintainability.
Updated or new functionality can be added on a periodic basis rather than all at once, enabling continuous delivery and regression testing before releasing entirely new production code. Over time, a refactored application experiences bug fixes, is improved by user feedback, and is thoroughly tested against the rest of the enterprise application environment.
Organizations refactor applications to meet many objectives, including:
- Eliminating bad coding techniques such as ‘spaghetti’ code which can make modifications difficult.
- Improving performance or execution speed for program functions
- Improving consistency of application design, structure, user experience, or database across multiple applications
- Uncovering bugs that have plagued operations
- Improving code readability and ease of understanding what the app does
- To retire legacy databases in favor of newer or cloud-native database options
- Supporting new technology advances that did not exist when code was written or taking advantage of native cloud services
Refactoring utilizes the underlying business process logic for the purpose of repairing either the design model, database utilization, coding techniques, or logic errors that have become codified. Refactoring is the method of improving existing code by making it more readable, easy to understand, and simpler. This process aids in the addition of new features over time, as well as enhances the ability to locate and repair bugs or errors.
In this manner, refactoring can enable the repair of poor initial design, simplifying application replatforming without changing the way the application interacts with other applications, users, or databases.
Application refactoring can be performed in three broad areas:
- Source code refactoring, which changes an application’s structure while retaining its functionality or adding new features
- Database refactoring, which changes database schemas to improve design and performance,
- User interface refactoring, which changes UI to improve consistency across enterprise applications while retaining functionality
Possible roadblocks to refactoring success include:
Refactoring Time – The amount of time taken to redesign, recode, rearchitect and redeploy each application workload on the desired target cloud platform can be substantial
Unknown Application Dependencies – Undocumented dependencies between applications can be suddenly uncovered during refactoring. These dependencies can create substantial additional work or even cause a refactoring project to fail.
Learning Curve – There may be a steep learning curve at the beginning of a refactoring process which could lead to coding errors early in the project as teams come up to speed with new tools, languages, and platforms.
Unexpected Errors – Any substantial application change presents the opportunity for new errors to be introduced.
Scope Creep – Even the best laid plans for refactoring will ultimately run into a situation where projects exceed the original scope. This can lead to additional delays.
Priority Interruptions – As emergency occur or new projects are prioritized, staff charged with refactoring may be called upon to work on other higher-priority projects, introducing delays.
Additionally, there are cases when refactoring is not a viable solution to an application problem, and there are instances where refactoring should just be avoided, including:
- If the existing code is stable and performs well – or if it ain’t broke, don’t fix it.
- When a tight deadline is involved that might impact regression testing, lest bugs are introduced from the refactoring process
- If it would be less expensive to rewrite from scratch than to refactor
- If management support is lacking for refactoring projects, i.e. the project is deemed expensive or incurs too much risk
Although refactoring can improve performance, it may not be simple to repair underlying problems with the basic architecture, and since the application should still perform the designed functions there must be extensive testing to ensure nothing has broken in functionality.
Finally, since application refactoring involves working with old technology stacks as well as new, it may be difficult to find developers who wish to work on refactor projects.
Refactoring should be chosen when there is a need to improve the readability, functionality, or extensibility of existing code. It should also be considered when there is a need for replatforming applications, whether to work on new infrastructure, with new storage APIs, or similar change.
Refactoring assumes an understanding of how the code currently operates. Developers should review the code to understand its processes and methods before beginning any code modifications, including not only what the code does but how it works.
Do not think of refactoring as debugging. Refactoring’s main goal is not to repair bugs, but rather to repair design or implementation problems referred to as code smells, such as redundancy or code segments that are long and convoluted.
It is also important to remember that refactoring is not only about new features and functionality, but also to make code cleaner, easier to modify, more efficient, and better performing.
Refactoring should be practical and should help bring consistency to coding practices across the enterprise, for example by standardizing on variable naming conventions or utilizing reusable code segments or external APIs rather than re-writing the same functionality in every program that requires a particular function.
Development teams should recognize that refactoring is usually a continuous process and not a one-off response to a single program’s shortcomings. For this reason having a clear set of goals early in the process can help prevent project creep and keep the development and DevOps teams focused on improving the performance or portability without negatively impacting functionality.
Refactoring thus helps a problem that often permeates in-house developed applications, which is duplication of code or functions. Repetitive code – whether in a single application or between multiple enterprise applications – increases the application’s memory and storage footprint, often becoming resource hogs. Duplication can demand that a change in a function be echoed in many other applications, creating loads of extra work as the offending routines are located in each application and refined or corrected. Deduplication of code reduces complexity, simplifies testing, and smooths debugging and remediation of problems.