Transifex has been around for more than ten years, providing a great localization experience for a lot of customers, which means that a lot of people have worked on its technical side. There is technical debt and new trends…all the hype is just part of our everyday lives. DX (Developer Experience) is important for maintaining and growing a healthy product.
Over the last couple of years, we’ve been thinking of modernising our front-end architecture, but we’ve always hit roadblocks, impediments, bad timing, or other priorities due to our capacity.
But when things are difficult, what can you do? Well…You prepare.
Here is our journey on how we prepared and what helped us create a Vision for our front-end architecture, as well as a smart plan to tackle it.
The Current State of Front-end at Transifex
For simplicity’s sake, I’m going to reduce the scope of our architecture. Our core application is a Django monolith and in the client, we use Marionette for our views and Less for our custom CSS framework.
The UI consists of multiple Marionette applications with routing depending on the case.
If we need to create a new feature, what we do is:
- A back-end engineer creates the Django endpoint views.
- A front-end engineer creates our UI logic in a new Marionette application and some HTML files with Underscore templates.
- We localise content from a Django view as parameters we pass to Marionette or with Django template tags inside the HTML templates.
- We test our code through a Grunt task.
And then we are done and ready to push to production.
Why We Needed Something Different
Some might say that the current process is just about right. But the devil is in the details.
Client-side Code Tightly Coupled with Django
Currently, we use Django Compressor and the static asset management flow that Django provides to manage our client-side code. This is great for small-sized projects, but in our case, it doesn’t scale anymore. It has become a bit cumbersome for us to install new tools, do optimization based on data, and all the shiny things a different approach might provide. Also, this creates another layer of dependency. To upgrade a package that manages the static assets it needs to be available for our current Django version, which might be related to our Python version. This is where we run into an impediment…
Another thing that has proven to be stressful is the deployment process. To fix a simple typo issue in production, we need to redeploy the whole monolith, which means CI and backend tests that are not in the scope of a JS code change. We wanted the ability to move faster.
Happy people create great products. So, we need to provide the best experience for our engineers. This doesn’t come easy for a few reasons.
Django on the fly file compilation is slow. You need to wait for a bit when you refresh a page. The difference between the compressed version of the app and the development one is huge. And serving the app compressed might be ok for our back-end engineers, but when we are in development mode, it’s not viable.
ES* features cannot be used. Because file compilation is slow, using Babel in Django is a road paved with surprises for us, and creating a new flow with external tools was really difficult to maintain without having a clean slate.
Our client-side views retrieve a lot of content from Django templates and back-end endpoints. We need one unified way of requesting data for our client-side code without the need for Django views. We have our new shiny APIv3 in the works and we are proud of it. Why not use this as a single point of truth? In the long run, this could help us use the bare minimum of Django or migrate to another framework more easily.
Overall we are very happy with the framework and what their team has done over the years. There are no serious issues, apart from some improvements that I’m sure the Marionette team will figure out eventually at their pace. There are, however, some side effects.
Limited reading resources. Unfortunately, there are not many resources out there for Marionette, like there are for other frameworks, which are needed in case someone wants to contribute to our code. Back-end engineers can copy-paste code from another file, but they cannot be sure about the result. We are a small team, so any kind of help is important.
Talent acquisition. The framework you use is not why someone will stay on your team but it is going to help you acquire people. There are cases in which people have turned down offers because we are using an “old” framework. I’m not saying I agree with this approach but it’s a fact and our people are our most valuable asset.
How We Knew It Was Time
For many years, our stack worked. It is a well-tested environment and there are no weird surprises. Some might say it’s “boring”, but it is a good kind of “boring”, the one that works!
We are productive and we have a mentality of building things for our users and investing more in UX (User Experience), instead of worrying about the next trend that comes up. If you read the “why” section again you are not going to find something about an “x” framework that is better than Marionette. It’s all about things that are keeping us back or difficulties with our current setup.
We Gathered Pain Points
It is usual for any new engineer that joins a company to want to rewrite everything from scratch. Before jumping into anything we had to remove any bias, better understand our issues, and then write them down. Are these reasons enough to justify the investment? Can we do something within a smaller scope that will provide a solution? If yes, we can revisit this after a while, and if not we can continue to the next step.
We Created a Vision and Strategy
One thing we did wrong in the past was that, instead of doing calculated planned steps, we did individual efforts to fix the current setup, which usually ended up as stale pull requests due to large changes.
So what we needed to do was to focus on a Vision and a way to tackle it, which would be our Strategy. A big and difficult part for us was the migration process. How could we have a plan for a migration to the new state without going crazy? We didn’t get fixated on technologies or small details but rather focused on how a new architecture can help us solve the issues we have. This is what unlocked everything for us and gave us the boost we wanted. We were a step closer to our initial goal.
We Seized the Opportunity
Our fairly new infrastructure was one of the things that would help us move fast. Being able to build our new services in a few hours empowered us not to care about infrastructure restrictions. Do you want a new service? Create some files and you get it up and running in a few hours. Your POC (proof of concept) is live in production.
Reasoning, a Vision and an Opportunity. Once we had these things, we knew we were ready.
Our team is small and it is a long way for the whole project to come to life. We are still at the beginning of this journey but we feel really excited. It is an opportunity to make our product better and to provide the best experience for our engineers and our users.
We know that big changes can be stressful and make teams lose their focus and motivation. When we started this initiative, there was no manual on “how to migrate a ten-year-old monolith without losing your mind” and it was scary. One of our goals is to share our experience, our Vision, our process, and our technical challenges through these posts so that other teams can be inspired. Hopefully, these posts can help them with their decision making along the way. Buckle up!