DEVWorld 2026

Michiel van der Ros - How to prevent a rewrite

23:54 · 07 May 2026 – 08 May 2026 · YouTube

About this talk

This talk covers the evolution of a web development codebase at TomTom over seven years. The speaker, Michiel van der Ros, discusses transitioning from old technologies, including a legacy CMS, to modern frameworks like Next.js and Storyblok as a headless CMS. He emphasizes the importance of maintaining a cohesive monorepo and the challenges of managing multiple libraries, including legacy components alongside newer ones. The speaker introduces the metaphor of the Strangler Fig to illustrate gradual transitions in codebases, addressing the significance of strategy in handling legacy dependencies while ensuring progress without complete rewrites. He encourages teams to adopt coexistence as a viable migration strategy while continuously finding ways to modernize and streamline their systems.

Full transcript

Good morning everyone. Hear me? Yes, great. Thanks for showing up early today. I'd like to start today lightly by telling you a story, a very old story. Thousands of years ago on the island of Crete, there was the King Minos who was reigning over the island of Crete. He had a big palace and under the palace was a labyrinth and in the labyrinth was a mythical creature.

It was actually a Minotaur. It was half man and half bull. And the evil King Minos requested cities in the surroundings to send every 9 years 14 young men and women to be offered to the Minotaur who lived in the labyrinth. They had to sail to Crete and these young people never came back. One year when it was time to send the 14 young people to Crete

again, a young hero joined them. Not as an offering but as a hunter. His name was Theseus. Theseus sailed to Crete and there he met the daughter of King Minos. Her name was Ariadne, which some Dutch people might know as a sewing machine, but anyway. Ariadne gave him a thread so he could, while exploring the labyrinth and finding the Minotaur, he could find his way back and

he did get to the center of the labyrinth, slay the Minotaur, found his way back with the thread and sailed back home to Athens unifying Athens and its surroundings under a new reign. In the harbor of Athens, he was welcomed as a hero. They preserved the ship as a monument, but as with all monuments over time, they need to be cleaned, restored, parts of the planks of

the ship started to rot and after many years all the planks of the ship have been replaced with new planks. Which led Greek philosophers, at least they're good in philosophy as we all to ask the question, is this still the same ship or are we looking at the new ship built out of new planks? This puzzled uh philosophers for uh centuries actually because later even um another

philosopher asked the question what if we had kept all the old planks and built another ship from that? Then we have two ships, which one is the original? Which could lead to indeed a second ship being in the harbor. I'll get to the relevance of this metaphor of replacing the planks, you might already get it a bit. But first to introduce myself, I'm Michiel van der Ros.

I work at TomTom as a staff engineer on the web team. Um maybe not all of you had like a little TomTom box in the car back in the days, but in the 2000s uh TomTom was the first Dutch unicorn. Uh worldwide we sold more than 100 million devices and uh even though mobile phones and in-dash navigation uh have have made the device obsolete uh we're still

around and we might be in your pocket without you knowing it. Um the original Apple Maps was running on TomTom, Uber runs on TomTom technology and a lot of car makers clients because there's only a few map makers in the world and we try to uh put ourselves out there as uh privacy aware alternative for some other big map makers you may know. >> [sighs] >> Um

and of course uh having live traffic data historical traffic data, we can advise governments um around big events uh or around parts of their uh city network that are slowing down traffic uh on a daily basis. We still do consumer stuff though like our um uh we have an app, there's a free app nowadays. You can actually connect it to a little device called the Tom. You

put it on your dashboard and it gives you like a sound and a and a color when there's a sudden traffic jam for example, uh road works um um, of course speed traps. And our motorcycle devices and truck devices, um, you still see them everywhere. Every time I get on a bus, there's still a TomTom, which is, uh, you know, makes me proud. Um, I, however, do

not work on the navigation and location technology directly. We use it a bit on the website, but literally what you see on www.tomtom.com, that's what I'm, uh, talking about today. So, it's, uh, a website that runs on multiple apps. But, let's talk about the code base. I work on a code base that started more than 7 years ago. Um, roughly 10 years ago, um, I was brought

in as a freelancer and I brought, uh, I helped to bring the web development back internal instead of with an external agency. I was working on the B2B website. Uh, someone else was working on the consumer website and we realized we had a lot of, uh, components in common, so we started to combine them. But, a little bit of, uh, facts first. Uh, I looked up our

first commit is roughly 7, uh, 7 years old. We have 35, 35,000 commits since then. There's four active developers in our team working on it and we did zero rewrites. So, um, I I would like to split this part up in three, uh, parts. I'd like to talk about what we were building, what we're maintaining, and third, uh, what we're renewing. So, our mono repo started about

7 years ago, uh, when the B2B, the work on the B2B side and the consumer side were merged into one, um, uh, one repository. The whole idea of mono repo was still pretty new back and also to give you a bit of an idea for the web developers amongst you, uh, React Hooks was still in beta, but we were kind of betting on that, uh, becoming the

new standard and lucky enough, like I think literally a few weeks before we went live, it was it came out of beta. So, that's about the timeframe we're talking about. Like I said, monorepos were also not something that everyone was adapting yet. So, we had uh three main elements in our monorepo. the B2B website, the consumer website, and drumkit library to unify our components, which was written

in JSX and and SAS. Then uh the maintenance over the years. we jumped on, like like I said, like on on React hooks like really early on. And we tried to always uh look for uh good alternatives, things that we could use. Um so, of course, originally the project started in NPM, but we quickly moved to Yarn because it was a lot faster, and pretty quickly after

that to PNPM because uh especially with a growing monorepo, it's it was like orders of magnitude faster for installing uh stuff. Managing a monorepo is um it it takes some work doing uh like aligning and linking libraries, and Lerna was a tool that's really good for that. It's still around, but in our case, uh actually, I think less than a year ago, we realized that PNPM workspaces

can do all the heavy lifting uh connecting those projects. We had a lot of unit tests in in uh in Jasmine that got replaced by Vitest. Uh we had uh Jenkins to deploy things in a very complicated project from the uh backend people. Nowadays, we manage our own Kubernetes cluster, um organized by uh by the platform engineering team. So, we use Kubernetes. At some point, we introduced

even like TypeScript, Tailwind, uh and other new technologies, and they're all in the same monorepo. Complicated ship, but maybe not. I just want to illustrate like the things that were um that were happening because very often you see that companies at some point decide like oh we're going to make a new website and they start from scratch. And we never did that and it was a conscious

choice. A big shift came in 2022 when we wanted to move away from our old content management system Tridion. We had it for I think 15 years or something so you can imagine that no one dares to delete anything and it becomes like a huge blob of information. And um yeah last year I gave a talk about how to do this kind of migration and to summarize

it basically don't try to convert all the data that you have. Think of what you need for new website pick that and don't be afraid to pull the plug in the end on your old CMS. Um we landed on Storyblok as as our headless CMS and started migrating first like one of our smaller apps because by now we have like roughly 10 web apps in our mono

repo. Four of them are the main parts of the TomTom website. Um we decided to go for Next.js until that point we had our own custom written server-side rendering in React. There was not really a framework that was doing this and actually looking back our solution was uh very simple and fast compared to Next.js that's why we're also doing some some projects in Astro nowadays. But anyway

in 2022 it was a big wave we started introducing type script Tailwind which means that we had like a library with our old components in JSX and the new components in more strictly typed and in Tailwind. Then another shock it was actually an external factor but they decided to rebrand TomTom. We had the same logo for many years. And um um maybe you remember I I just

mentioned our library it's called drumkits it's of course like a little wink to our old logo, the TomToms, part of it the drum kit. and there for those who who remembers going on holidays with their parents perhaps, the little TomTom box that was sold all over the world. Uh but in the new identity we're also focused on like self-driving cars, even though that was just around the

shift, so it has the old logo. Um but this is the logo you also see in our office next to Central Station, but we're like in about 20 cities Also, this rebranding did not cause a full rewrite. We were able to just modify our design system, uh modify the colors, the logos, um and everywhere across the company people working to update everything. And we were able to

just do that by switching some SVGs and some styles in our in our library, both in the old and the new one. Coming back to the migration to the new CMS, to Storyblok, uh we were like a pretty early enterprise customer, so we have a good relationship with them. Um and a colleague are also on MVP program. uh the first thing we did was migrate the newsroom,

later the B2B side, because it is, looking at it, relatively static. It's not, you know, we call it a web application, but in fact it's mostly just rendering pages with a lot of product information that need to be easy to find and index and also be indexed by LLMs nowadays. And the last thing was the consumer side, because that's really complicated. We have all these devices with

different configurations, uh comparison tables, and translations in more than 10 languages. over time we had another library next to our old library. So, DrumKit is still alive. We still use JSX, even though everything we've written in the past few years is in in We still need to support SAS for some old components. And what we also had to do um during the migration to the new CMS

is write adapters because uh some components were expecting the old data format. And there's never really good incentive to get rid of those kind of adapters if everything is working just uh just fine. And now that slowly gets to the core of um what we're doing. So, we kind of didn't see what was there all along. We didn't present a rewrite, but we kind of did one.

It just became a bit of a strange ship. It's a matter of philosophy. Is it a new one? Is it the old one? Or is it a kind of a hybrid? Because we did not visibly do a full rewrite. Um we did all kinds of transitions. Some we were able to complete and some we didn't complete like uh leaving those adapters there and not fully refactoring the

old components. So, it became more additive like adding extra new planks on the outside where the earth things were were rotting, which is not a bad thing but you need to be aware uh if it's what you want because there's something else going on. Yeah, like I mentioned Storyblok, we really love it, but some components still uh still have like a little layer in between that converts

uh some some text formats for example. But what I want to uh tell you is that there's a bill that nobody gets. There's three issues with that. The The bill doesn't land on anyone's table, but there are two mental models. Um when we onboard new colleagues or interns, we uh they kind of need to understand why we have uh two libraries of components and that they should

not write them in the old style but in the new style. So, there is some mental overload that you cannot really measure, but it will cost time over time. There's a bit of decision fatigue because uh there can be little utilities like um that uh strip things in a URL or manipulate data in other ways that were already there in the old library. Do you rewrite them

also in TypeScript or you don't? You keep running into these things and it is a bit tiring, I have to realize in all honesty while I was preparing this talk. And there's no real forcing function to finally get rid of your old library because there's always some other work that needs to be prioritized. So analyzing what we were actually doing, whether we were doing a rewrite or

not, I realized that um uh we also have a lot of transitions, replace blanks that are fully replaced. For example, the infrastructural stuff. I think we're running on like a a top-notch Kubernetes infrastructure using Argo CD integrated uh with Grafana and um and with Sentry and and all these things. Um we we try to really keep an eye on on uh security patches and we can release

much more frequently. There used to be like a 2-week cadence like many years ago and now we can release multiple times a day. and there's a lot of uh invisible transitions that the user cannot see like uh swapping out vendors uh for example for forms and and uh and webinars. and also all kinds of um uh all kinds of of tracking or logging. It's all stuff that

the end user doesn't really see. So we ended up on a pattern called uh on a kind of a coexistence pattern and we're kind of okay with it. We had like a pretty stable team for for years already. Um but coexistence has become our default. And investigating this, I found out there's a lot of articles around about a pattern called strangler fig. And I first thought that

it was two computer scientists that came up uh with like an award-winning white paper. There was Mr. Strangler and Mrs. Fig. Uh it's not really true. A strangler fig is actually a a fig that strangles. You might know it from these temples in in Cambodia. But as you can imagine, there were not all temples and humans around and these these kinds of plants or trees have existed

for a long time. So they start in the leaves of a host tree and they drop their seed like on a little line and then when they hit the ground and they can grow roots, it slowly gets thicker and thicker and over time you end up with really cool looking structures like this. And what actually happens in nature is that at some point the root gets so

thick they take energy. The leaves get so thick that there's no oxygen anymore. So the host tree is deprived of of water and air. And it will slowly die. And I found really interesting pictures where there's like the stems of these trees and they cut them through for woodworking and there's like a hollow middle of where the host tree used to be. when the strangling really works,

this is what's left. You get like a a hollow tree and the original host is gone. But what we kind of realized is that we were putting the host tree on a kind of life support. It had these adapter patterns that we were never replacing. So it was kind of staying alive even though maybe subconsciously we were thinking like, well, you know, in two years DrumKit will

be gone. Base drum is our new library. Everything is strictly typed, running well on a centralized Tailwind configuration. Doesn't happen automatically. So it's an uncomfortable truth. So what you need to realize is having a strategy of how to strangle. So there's three things I want to tell you about that. Or three strategies that you can use. It's at different levels. So one thing you could for example

have as a team rule is if you need to touch a file for a new feature, you have to convert it to the new system. But, did that a few times when the forms needed to be improved or connected to a new vendor. We were like, "Okay, we don't like the old forms anyway. They got really complicated. Lots of exceptions and stuff added, which is a good

moment to rewrite our forms in the new system." So, that's something you can do. You can also, and we actually did that, introduce a bit of a right freeze. So, you never build new components in SAS and JSX anymore. They always build them in TypeScript and Tailwind. Or you can have a boundary cut. For example, pick one least complicated application, and that application is just really not

allowed to use components anymore and the from the old library, and then you actually can make a ticket to phase out the last few components that that app is using. So, you can change you can set some rules that it's just examples. You can implement all kinds of other rules like, you know, find the most important component or the one that hurts the most. And discuss that

in your team. But, you can do it So, you can do it at three levels basically. So, which strategy you pick? It depends a bit on the cost. Is there room in your budget and in your time to actually address these issues? And something has has been changing. We're like heavily adopting Cloud Code where originally it might cost a lot of time to update your component and

convert it and go over all your CSS rules and convert them into Tailwind. It can be quite some It can be quite some work. But, with Cloud Code, it can speed up a lot. Actually, you can tell it like, "Hey, we have two libraries." You put it in your project configuration like, "We have our old library. You cannot touch that anymore." We did that in our Cloud

MD. If you make something, you always have to do it in that style. If it touches on something over there, maybe convert it. So, something that was just not cost effective and there was no real pressure to get rid of might now be feasible. So, again convert it touch. If you set that rule in your AI instead of that it takes you an hour extra, it might

only take you 5 minutes extra. If you look at the repository, you could even implement a a thermometer like some kind of statistic like that you can see that your old library is getting used less and less or something I'm thinking of is like writing a scanner that scans the CMS for all the components that are in use and I think there's quite a few components that

we just don't even have any more because they were specifically for old campaigns for example. So, I think cleaning up your code base is much easier and more fun to do nowadays than it was in the past. You can also set enforced boundary. So, you could also use AI to set rules on for example your pull request reviews to check whether you are adding new imports from

your old library and if you're doing that, it can give you feedback and maybe even help you in not doing that and getting that out of there. So, that basically means that the discipline to strangle the host tree moves from just team discipline to your tooling. And that can make it much more cost effective and make you move forward. So, what I'd like you to take home

from this presentation and of course if you're interested in these topics, always feel free to connect with me or talk to me. Coexistence is an excellent migration strategy. We actually had a moment where our app was able to render the whole website from either the old CMS or the new CMS because of these adapter patterns. It would just detect whether whether components were coming in in the

new format or the old format. It runs through the adapter and it'll run just fine. I think we even had at some point some pages coming from the old and some from the new adapter because that was just decided at the route level in Next.js. So, it's a great migration strategy, but it's not an end strategy. And you got to be fair about that. You know, everyone

has these kind of problems, but it's good to take a step back at some point and see where you're The question is not really whether you do a rewrite, but whether you complete at the the transitions of the small rewrites that you're doing in your code And third, something that you might have considered too costly like to to really that you think like someone needs to focus

on this for 2 months to finally get rid of the old library, it might cost less much less time nowadays if you Identical AI to do your coding. Or help you with it. A long time ago I did a lot of agency work and projects were often stuck to a very strict deadline. So, at some point the project was done, the code was done, the website was

delivered, and that's it. You didn't touch it anymore. You moved on to the next project. In our case and in many many I guess many of you have the same issue. You can have code bases that live for many many years. The website is always on. Changes are subtle. Sometimes there are bigger banks, but the code base keeps moving. It's never finished. But inside that big code

base there are a lot of small transitions and those are meant to end. They are supposed to not move forever. So, every year we choose which blanks to keep, make tickets for it, improve the tooling. And coexistence can be by design, but when we set up Base Drum, we wanted it to be an independent React library. We didn't we really took care not to put any Next.js

imports in there because we use the same components in our old custom-made SSR and we could just use them in Next.js and now we're using them in Astro. It's not a problem. We can use them with feet. I even put like a few Svelte components in the Astro app. But also you still have to be careful not to mix too many technologies. But it just shows the

power of making your library meta-framework independent. I think it's an important thing to keep in mind. Try to prevent that framework lock-in just like you do with vendor lock-in. So in the end I promised that this talk was also to be about keeping your code base fun. And fun is not just because your code base is using the latest stack. It's also because it feels like your

work is getting somewhere. Thank you. >> [applause]

From event

DEVWorld 2026

07 May 2026 – 08 May 2026

All event videos
Back to Watch