At some point, every engineer I've ever worked with has said "Let's rebuild this product". One day, when evaluating a SaaS product, the feedback I gave my CEO was: "Instead of buying it, we should just build it from scratch. We’ll get more bang for our buck". Ultimately, we decided neither to buy it nor to build it. However, knowing what I know today, I wouldn't have been so fast to suggest to rebuilding that. The challenges one faces when building a new product versus when rebuilding an existing one are two completely different challenges. The best comparison is trying to build a brand new house, or rebuilding one while also living inside of it. Now, let me tell you a little bit about what we faced here.

A background story

Here at Codelitt, we are about to deliver one of our biggest projects to date. It is an application that has been around for many years. The customer wanted to improve the experience by redesigning and rebuilding the frontend completely. The first version of the application was made of a mix of React and BackboneJS in the front end and .NET in the backend.

The goal was simple:

  • Redesign the entire frontend with over 500 pages and thousands of functionalities.
  • Implement an architecture to last the next ten years.
  • Build it fast.
  • Deploy it incrementally so its users can start seeing the benefits of the new application with its new features.

I hope you were able to spot the irony in the word "simple" over there. When I first reviewed this project, I was surprised about its size, and I was expecting it to be a herculean effort. However, things turned out to be far more challenging than I thought. Rebuilding an existing application has way too many hidden challenges that nobody talks about when they are going through a sales cycle. My initial impression was that it was supposed to be easier to build a product from an existing one, but as one of my preferred blog posts of all times is titled: Reality has a surprising amount of detail.

As we started the rebuild, we started facing many challenges that nobody warned me about before.

Easter eggs

The first hidden challenge we found was the amount of easter eggs. When we think about building a new application, we organize the tasks in a way that allows us to achieve the desired behavior. When we are rebuilding one we need to replicate the current behavior. The problem is, what happens when there is no written definition of current behavior? What do you do when there's no source of truth for the current features?

Well, given the application exists, then the definition of current behavior is in the code. However the project and product managers are not close to the codebase. That means that the engineers are the ones who know what the current application does. What happened is that every other week, we would find a set of functionalities that nobody was aware even existed. Needless to say, it was impossible to get our original estimation right.

Making it right the second time

Since we are basing a new design on top of an existing one, it ends up being impossible to be unbiased. Quite a few times, we found ourselves asking if we were building it right the second time, but because the current backend worked in a specific way, we had our hands tied. Some functionalities were overly complex, and there was just nothing we could do that wouldn't make the cost of it prohibitive.

It is like wanting to change the places of the walls in your house without being able to remove the ceiling. More often than not, it's simply impossible.

Recreating functionalities go beyond the ticket definition

When we are creating a new feature in a product, we usually need to worry about two factors:

  • How the current code is set up
  • what we need to change. When rebuilding an application

When we are recreating a project wee need to add a third factor

  • Understand how the current application does it

With this third variable, we can get into all sorts of problems, but I'll focus on the three biggest ones:

  1. The code is written in a different programming language/framework
  2. The code readability is poor
  3. The functionality is overly complex

In my scenario, we've hit all these three. Due to the fact that the existing application was built over many years, the original team had to work with the technology constraints of their time. They had multiple technologies mixed - and not in a fun way. With that, it became expensive for our team to properly understand the application's current behavior, and be able to recreate that behavior in the new application. Here, we have a two-sided view of the situation:

a) Since we have an existing code, it makes it easier because we don't need to spend time thinking about which data flow to follow

b) Since we have an existing code, it makes it harder for us to rebuild the application the right way because we need to follow the current data flow

I ultimately believe that it is a mix of both, depending on the situation. A lack of freedom can be a good thing because it limits our options, and it can also be bad for the same reason. Having the team having reverse-engineer the code in a different framework is also problematic, because it takes lots of time.

But there is a bright side!

This was not our first time modernizing an application, and it won't be the last. Once we recognize these challenges, bringing new life to old user experiences can be done in a timely (and often in a budget) manner. Next I'll talk about how to successfuly avoid these traps and set your team for success when rebuilding a large application. Stay tuned!