Should we rewrite our app from scratch ?

AntoineJ
YounitedTech
Published in
7 min readAug 31, 2021

When creating software over several years, this question has necessarily arisen: do we have to rewrite our old application ? This may seem like a good idea when the pain points are numerous. This offers more good prospects and hope to start again on good bases. Let’s see that all this is not so simple.

Why can we consider rewriting?

The reasons may be business or technical related :

Business related

  • The application no longer corresponds to the need, some features have become useless while others lack and call into question the existing
  • Major business change, the new required features do not fit in the box at all

Technical related

  • When quality has not been an important topic, the codebase can — after years and many past developers — be a real mess
  • Sometimes there is so much technical debt that a point of no return has been reached. Technical debt would cost a fortune to be redeemed
  • The application was written in old / obsolete / unmaintained technology (language or framework) : it can be difficult to maintain it and to recruit developers

And also human related ?

Make no mistake, the point is not to say that a rewrite should be guided by the desire of developers to get rid of legacy at all costs. But there can be positive consequences to start greenfield :

  • This can increase the motivation of developers
  • Usually when developers are working on a clean, quality codebase, velocity is more important

How to rewrite?

Here is the classic flow that we often see:

  1. We acknowledge a lot of problems with our old system. Many pain points ; the new features are more and more expensive to develop ; it is difficult to make the product evolve
  2. Technical and business team agree to have a budget to rewrite
  3. Costing, architecture, analysis and let’s go for several months/years of development
  4. Sometimes the budget continues to make difficult choices such as chosen functional regressions (and that can be the battle with business teams)
  5. New and old products have to evolve together: features must be implemented twice
  6. The new legacy system finally contains many more functionalities than what had been analyzed initially
  7. At the end of planning, the project is late
  8. A decision is made to either stop the new product or increase the budget

This is a huge mistake.

I suggest that this flow is better to follow:

  1. Isolate a small feature or a business context with the best return on investment
  2. Develop at the target architecture/framework and new code standards (with a vision of what will be the next functionality / business context and anticipate it in the code to continue the migration quickly and easily).
  3. Test it and set up automatic non-regression tools
  4. Plug the new product to the new legacy system
  5. Learn, take feedback and KPIs, fix what is needed and monitor
  6. Kill the legacy : means here new unreachable code (remove or archive code, infrastructure, etc)
  7. Come back to the first step and iterate until all the pain points are resolved. It is important that each iteration be short, around a few months maximum to limit the divergence as much as possible.

Note that the subject is not finished when everything is migrated. The migration project ends when the pain points have disappeared. It is perfectly acceptable to keep some parts of the legacy codebase. If it is easy and inexpensive to maintain it, we keep it.

Example

At Younited, even if we prefer to evolve our applications by iteration, we also sometimes rewrite from scratch. Our architecture is based on a microservice approach and each team oversees a scope of applications.

2 years ago, our team were faced with this dilemma. We had the ownership of the credit decision system orchestration (technically a REST API). We had big structuring topics in our backlog:

  • Redeem various technical debt
  • Change framework: .NET 4.7 to .NET Core
  • For business purposes, we must add what has been called the eligibility matrix: a way to finely manage a prospect’s decision and all the commercial offers we have for him. What must be connected to the heart of our orchestration system which was no longer sufficient for the functionalities to come
  • New upcoming business features will require interface contract changes with our callers

Clearly the question of starting from scratch arose. Especially since developers who had detailed knowledge of the existing could work on these subjects. And that’s what we decided.

We followed the iterative approach.

With a little more detail, here is what we achieved:

  1. We started by analyzing the existing situation, interviewed the business experts and our callers to be sure to know all the existing use cases, possible future needs and avoid technical or business regressions. We defined a business context to migrate and associated features.
  2. With all this, we have defined an architecture, interface contracts, data structures considering all the needs but developing only for the first chosen business context (YAGNI). In our case, we have divided into countries (FR, ES, IT, etc) and what we call “execution modes”
  3. As the features were delivered our callers were able to connect to the new API (ie: new REST routes). The old system continued to work but it was necessary to migrate to the new one to benefit from the new functionalities
  4. The new features were first connected with a “shadow” mode: an http call added in the caller API to our new API in fire & forget so the result is not read but only stored and has no impact in the existing system. This allowed us with a small tool that we had developed for the occasion to automatically compare the data generated by the old and the new system and to find a lot of bugs (or missing features)
  5. Once everything has been tested, fixed and validated, we applied the new system to the chosen perimeter and move forward at the desired pace
  6. This system is central in our information system, we took about 18 months to complete the migration

Overall it went well. Our greatest difficulties were:

  • To fit these migrations into the roadmaps of several teams and to coordinate the dependencies
  • Limit the migration times of an iteration as much as possible: we had to manage urgent business requests and sometimes had to carry out developments on the old and the new system.

We could have been better on these points.

Why shouldn’t you rewrite everything at once?

  • There is no reason for the developers to do better than the entire current version, especially when they are new to the project
  • Mistakes made in the past can be made again
  • When the application is too big, it is difficult to process all this information for a developer or even a team of developers. A big problem must be split into smaller problems
  • Code in production works, has value, lots of bugfixes, tweaks for specific cases
  • Some of this knowledge is lost when the code is not explicit and tested (and let’s be honest, we all have a few areas in our n years codebases with untested or non-explicit code)
  • If there are two products to maintain, the development is carried out twice or worse the 2 applications can diverge
  • It is very expensive for a company to build and maintain two products for the same use

How to avoid rewriting as much as possible?

It is not possible to avoid major impacts during business pivots, but we can try to anticipate them as much as possible by discussing with the business teams and questioning the vision.

Apart from that, the central point is to think about quality:

  • Do clean code
  • Carry out refactoring regularly
  • Write decoupled code to easily plug and unplug features
  • Redeem technical debt as things progress
  • Have an ADR to keep track of past choices, in particular the chosen technical debt

Conclusion

Rewriting an entire application from scratch is a bad practice.

It is not at all guaranteed that one will do better than the current application.

Rather than a complete rewrite, it’s far better to do incremental shifts.

Thanks for reading ♥

Source

--

--