To refactor or to rebuild: That is the question. (Sorry, Hamlet fans.)
That’s the question you’re probably asking yourself if you are trying to decide how to migrate your existing application to run inside containers. Do you want to refactor your app—meaning you modify it to work with containers—or rebuild it entirely?
This article offers things to keep in mind in order to answer the refactor-vs.-rebuild question. It aims to help you design the best approach for getting your old app up and running on new, containerized infrastructure.
Defining the Terms: Refactoring and Rebuilding
Before jumping into the details of the decision, we should make clear what refactoring and rebuilding mean.
When you refactor, you make significant modifications to your application, but you don’t rewrite all of the code. Refactoring could involve breaking monolithic code into modules that can be run as microservices, for example. As another example, it could involve excising the built-in storage service so that the application instead uses an externally hosted scale-out system. Or maybe you could optimize your compute code to take better advantage of multiple CPUs.
Refactoring is basically like remodeling your house by updating the appliances, putting on fresh paint, and maybe redoing some bathrooms, but you’re not replacing everything from the ground up.
The benefit of refactoring is that it takes less effort. It’s much easier to make modifications to an existing codebase than to rewrite all of the code.
In contrast, when you rebuild your app, you rewrite it entirely. It’s like knocking down your house, foundation and all, and starting entirely from scratch.
The upside to rebuilding is that you can redesign the app to work in exactly the way you want. That can be useful if the app was originally written a decade or two ago, long before anyone expected to deploy it on the cloud (let alone using containers). When you rebuild, you can totally reconfigure the way your app handles compute, networking, storage and everything else.
The downside to rebuilding is that it demands a huge amount of effort. It takes longer and requires a much greater investment of your team’s time—due not only to the need to write the new code itself, but also all of the testing, staging, building and management learning curves that come with a brand-new codebase.
Refactor vs. Rebuild: What to Consider
Now that we understand the differences between the two options, let’s discuss when you are best served by refactoring, and when it’s worth your while to do a complete rebuild.
You should probably refactor if the following are true:
- Your app is already distributed. If you are working with an app that was designed from the outset to run as a set of disparate services (which may be the case if your app was originally written during the SOA craze of the 2000s, for example, or in the early days of the cloud), there is probably no need to rebuild it. Just tweak it so that each of the services can run inside separate containers, and voilà, you have an app that is ready to be containerized.
- Your app can run efficiently inside a single container. Keep in mind, too, that part of the beauty of Docker is that you can use it to compose an app of multiple microservices, but you don’t have to. It’s flexible. If your app can run efficiently in a single container (which is likely the case if it has no data or public-facing network layer, for example, and instead just does compute), then there is no need to rebuild. (This is why, for instance, web servers like Apache HTTP and NGINX are obvious candidates for containerization. Their main task is just to do compute, so there is no need to rebuild them to run as multiple microservices.) Just optimize the app with some refactoring, and deploy it inside containers.
- Your time is limited. There’s no shame in recognizing practical constraints on what you can do. Even if (from a technical perspective) your app would ideally be rebuilt, you may not have time to spend on a rebuild before you need to move to containers. Containers are a flexible form of infrastructure, and although in a perfect world all apps would be designed with containers in mind, you can still get a lot of mileage out of Docker containers using an app that was not built for them originally. So, if you need to make the migration quickly, consider just refactoring, and holding off on a rebuild until you have more time to spend on it.
Rebuilds make sense when:
- Your app is totally monolithic. Some legacy apps are more monolithic than others. A truly monolithic app is one that was not written to be modular at all (in other words, the programmers missed the object-oriented programming train) and it offers no feasible way of running as a set of distributed services. In this case, rebuilding is your only way to run the app efficiently inside containers.
- Your app has major feature or security shortcomings. Even if your app is not totally monolithic, it could be outdated because it lacks important features or has security vulnerabilities. If you’re going to address those issues, you’ll end up writing a lot of new code anyway. With a little extra effort, you can just rewrite the entire app. In this case, that extra effort is worth it, because you’ll get a brand-new app that has all the modern features you need, and one that was designed from the start with microservices and containers in mind.
- Your app was written for an environment Docker doesn’t support. You can now run Docker on both Linux and Windows, but there are still places where Docker doesn’t run, like mainframes. (And in case you are running a server app on macOS for some reason, you’ll be sad to learn that Docker does not and probably never will run natively on Macs.) Plus, Docker only supports Windows 10 and Windows Server 2016, and it’s still subject to some limitations on Windows, so Docker may or may not work well for you if you run Windows on your servers. If your app works only on an operating system that is not supported by Docker, then you’ll have to rebuild it for a Docker-friendly environment if you want to containerize it.
There are issues to weigh beyond these, of course. But this is a good list of considerations to start with when trying to figure out whether refactoring or rebuilding your app will lead to the best trade-off between effort invested and results gained.
About the Author
Chris Tozzi has worked as a journalist and Linux systems administrator. He has particular interests in open source, agile infrastructure and networking. He is Senior Editor of content and a DevOps Analyst at Fixate IO.
We’re hiring! Check out the careers page for open positions in Amsterdam, London and San Francisco.
As usual, if you want to stay in the loop follow us on twitter @wercker or hop on our public slack channel. If it’s your first time using Wercker, be sure to tweet out your #greenbuilds, and we’ll send you some swag!