From spaghetti to lasagna

leboncoin tech
leboncoin tech Blog
4 min readJan 24, 2018

by Gabriel de Laboulaye (Backend Lead Developer)

Preparing the plate

leboncoin’s code was inherited from its Swedish sister, Blocket, when the website was launched in France, in 2006. Most of it was written more than 10 years ago, including the core functionalities: ad creation, store creation, payments, alerting …

Needless to say, most of the standards used in 2006 are now somewhere between obsolete and outdated. This includes the architecture -a big monolith, the APIs — hand-crafted JSON endpoints, the programming language -most of the backend is written is C, we have our very own templating language, even the search engine was made in-house.

Bon appétit!

Pouring spaghetti

The site’s success has been terrific; leboncoin has earned a good reliability and solid performance reputation, and it quickly became one of the most successful French websites. The obvious drawback of this success story was that some important parts of the code started to be considered “untouchable”: the best illustration would be the ad creation backend endpoint.

Over the years, ad categorization appeared, then we created multiple ways of paying ad options, then Classified Ads became associated with accounts, then we adapted the ad creation endpoint so that an ad could be created from our back-office, etc.

Several years later, the ad insertion stack looks like this: 7k lines of PHP calling 2k lines of C, calling 1k lines of SQL. On the database side, it looks even worse: Classified Ads are highly intertwined with accounts, payments, locations, etc.

What about some sauce ?

As if the spaghetti plate weren’t complicated enough with these three “layers”, we once decided that we needed to expose a unified API, no matter how it looked like underneath, as long as our clients could see one leboncoin backend from their perspective. This resulted in several different APIs written in different languages(!), with no restriction to their interactions with each other or even how to call each others’ databases.
The whole thing was starting to be a bit indigestible.

Bringing back some organization

Over a year ago, we decided it was time to change. While the organization still allowed for projects to be delivered with a reasonable velocity, we realized how bad the situation was when we had to draw our current architecture to a new employee. Not only was there no way to draw everything on a 2-dimensional board, we also didn’t have enough colors to represent our technical heterogeneity.

The team then decided to operate a radical rework of the architecture based on several principles:

  • Go microservices managing their own database
  • REST APIs exposed and unified from the client perspective
  • Aggregation and composition handled by a backend-for-frontend layer
  • Forbid synchronous calls between microservices in favor of event-based communication

From recipe to meal

Two approaches emerged: top-down (writing new APIs on microservices, then cutting the branches beneath until the SQL part could be isolated) and bottom-up (splitting the database first, then writing the new APIs above this). Depending on the use-case , (can the data be isolated? do we have a lot of endpoints and/or callers?), we tried both.

In particular, the accounts team started by isolating the SQL tables, while the Classified Ads team deprecated the former ad creation APIs. During this whole refactoring, the monitoring turned out to be really helpful; it’s probably the best way to know how your clients consume your APIs, and how much.

One year later, where do we stand ?

Of course, this split is extremely time-consuming and postponing all projects to finish it would be a death sentence for us. But some important parts of the code have already been separated, starting with professional accounts and payments. In the meantime, the frontend migration to ReactJS enforced our systematic development of RESTful APIs.

From time to time, our principles were forced to face reality, which drove us to allow some exceptions. We adopted the rule that “no rule is absolute”. And the virtuous circle started: now that some parts are split and the legacy codebase is getting slimmer, it’s easier to split other parts.

Now that we’ve almost finished the process, we’ll still probably focus on not letting this happen anymore: architecture workshops are still organized frequently, and we try not to rely on our current principles, even if they seem perfect for us right now. With that in mind, the future should be bright!

--

--