Large Refactors -
The Agile way, Or The Highway
The reason for change
Are you working on a living, breathing application with plenty of daily active users, legacy code and an almost deprecated UI framework that is slowing you down? If the answer is yes — this one’s for you.
We usually don’t have the privilege (time) to start our project from scratch and re-choose our tech stack whenever we want. That could be a bummer, but when you think about it, it’s a good sign. It means you’ve invested your time and energy on the most important thing — the USER, and not on keeping your stack up to date.
At some point though, the price of keeping that technical debt becomes too high. As your application becomes more complex, with more co-dependencies and more developers in a growing team, 3 things happen:
- Velocity starts dropping
- Application performance decreases
- Hiring becomes harder
Our tech debt due to be paid was an AngularJS SPA.
Augury lets its users be on top of their machines’ health. Our app is a dashboard displaying machine lists, deep dives into a single machine and its history, and also data heavy pages for analysts and more tech savvy users.
After about 6 years of our app doing a great job, we felt it needed a massive overhaul. We conducted some research and several POCs, which brought us to decide on a move to ReactJS.
Before we talk about how we planned to do the rewrite, let’s talk about Buy-In
Get that buy-in!
In Augury most developers work in Product Squads — small autonomous multidisciplinary teams with clear product objectives. On top of that, each developer is part of a tech guild (in my case — the frontend guild), which is where we work on cross-squad alignment, cultivating knowledge and innovation, and kicking off wide initiatives that do not come directly from a product need.
Getting cross company buy-in is a must before kicking off heavy initiatives at the guild level. Here’s why you should get it:
- Eliminate friction
Big tech moves vs. developing features, appears to be a zero-sum-game. The buy-in you’ll get by communicating the reasons behind it and the expected benefits of such a move, will lower or even eliminate the natural friction between the development and product/design - Extra time in squad tasks
With that buy-in, you’ll be able to dedicate part of the squad delivery time to the tech move, e.g. add 20% time for refactoring in the squad task time estimations - Guild/Discipline time
If you don’t have it already, getting some percentage of time for work in the guild is key to the success of a big refactor. Such a move needs to be based on foundations that can’t be planned or built in the squad domain. This can only be done with buy-in from management, as it is not a local change within the squad, it is a company wide decision.
So, how can we get that super important buy-in?
Communication communication communication!
We communicated our reasons and our work plan from the beginning. It is very hard to say no when you are presented with the reasons (if possible backed up with some numbers).
Explain to your managers what happens when a framework is deprecated, or how hard it will soon become to find amazing developers if your tech stack is out-dated.
Explain to your product how fast you’ll be able to deliver once the refactor is done, and how fast and reactive the app will be with the new framework and a fresh architecture.
Conveying the ROI (Return On Investment) of the move in all its stages will create that buy-in.
Get the others as excited about the future as you are.
Planning the move
We are working on a live product. The change has to be agile and continuous for several reasons:
- We can’t just stop everything and rewrite the app
We must continue delivering value to our customers and stay ahead of the competition - Working in small deployable chunks allows us to see value at early stages
We can also use those mid-way wins for the rest of the team, and help maintain that super important buy-in!
In our case introducing TypeScript to our codebase was one of those stages. After a short setup and introduction period done within the guild time, we started to see it’s value as it eliminated bugs, helped new developers understand the models and just write better code - There is almost always a dependency between the plan stages.
By working in small iterations we can implement the knowledge accumulated at each step on the future steps, or even change the high level plan if needed.
Breaking down big initiatives into smaller milestones
Each stage is different, some are more straightforward, while others need research and some trial & error. Let’s go over two different stages with different needs:
Example 1: Move to TypeScript
After deciding that we need this step, we assigned it to a small (2–3 people) task force within the Frontend Guild. This small team took a number of guild days to bootstrap TypeScript to our project, and start implementing it on different use-cases in our code (e.g. tsx files, ts files, old angularjs controllers, etc.). As well as encountering and solving the problems you get when you start using a new technology on a complex production product.
Next stage was teaching the rest of the team what the task force learnt (by face to face sessions and code review), and encouraging them to use it (code review and a fun grade board for whoever uses TS the most!)
Once everybody in the guild got familiar with TS (a matter of weeks), it became the only way to write code. All new components/files are written in TS, and if a dev touches old code, they’re encouraged to migrate it to TS. We even talk about it in our Design Reviews, and encourage it as a necessary stage when planning a task in the Product Squad.
Last stage is data — we try to measure our progress in numbers and not just gut feeling. The small initiative team is in charge of getting those numbers out and continuing to push the initiative even after it has moved from the Guild realm to the Squad realm.
Example 2: Use State Management in the app
This initiative differs from the TS move in one way — we were not sure which state management we should use. After some research we’ve decided on two final candidates: Redux vs. MobX.
(That is where we are right now. I promise to write another blog post on which one won and how smooth the transition was.)
The next stage is to decide on the decision criteria, conduct POCs in our actual code base, and with that new knowledge and experience — decide on the winning state management.
The rest would be the same as in the TS initiative.
When is the refactor done?
This kind of change takes time, and sometimes it’s hard to put a finger on when it is really done. When looking at a piece of legacy code, one should ask oneself…
Does this code affect our users?
Is it ever re-visited by developers?
Is it here to stay?
If all those answers are “no”, putting effort into migrating might not be worth it. We know that we’ll probably live with some legacy code for a long time. Such code should be minimal and encapsulated and affect the app as little as possible.
Let’s wrap it up
Are you heading toward a big refactor? Try to use these steps and I promise you the transition will be smoother with a higher chance of working out:
- Communicate your plans and get buy-in from the team
- Get guild/discipline time to work on the foundations of the refactor and do the bulk of the change in squad time
- Break your initiative into smaller chunks and be agile