Lessons Learned from Migrating Our SaaS Backend: A Developer’s Story

Discover the challenges and solutions encountered during a critical middleware migration in a SaaS product backend, providing insights into resilient technical choices.

30 juin 2024

Published

Hugo Mufraggi

Author

4 min read
Lessons Learned from Migrating Our SaaS Backend: A Developer’s Story

A Developer’s Story

For two years, I have been sharing my discoveries, best practices, and tips for QA in software engineering. Based on the content I’ve read on Medium, everything has been going well.

Today, I’ll share my latest failure and a technical choice error for the Invyo SaaS.

Context

I work at Invyo, a French startup specializing in data-driven tools for the investment sector. In 2023, Invyo raised funds to accelerate its growth by creating a SaaS product that consolidates these services.

Technical Stack

We built the technical stack's backend and some data components in Golang. For the front end, we used React and TypeScript. For deployment, we used Qovery, and everything is deployed on AWS. If you’re interested in discovering more about the architecture, let me know, and I’ll explain why we made these choices in a future article.

In my introduction, I mentioned a poor technical choice.

But what was it?

At the beginning of every project, we needed to choose the right framework or library to build the backend.

In retrospect, it wasn’t entirely a bad choice but rather an unlucky experience.

I won’t name the Golang package we used because my goal isn’t to badmouth anyone. It is an open-source project and one of the top 5 backend packages. I greatly respect and admire the open-source maintainers, and I hope to become a maintainer myself in the future.

For six months, we built a monolith with this package. For the rest of the article, I’ll refer to it as “BACKEND_PACKAGE.” We shipped many endpoints, and the developer experience was pretty good. Everything was going well.

Until the Day

We created an endpoint to upload files, a very common feature, and it’s not the first time we’ve implemented such an endpoint. I tested it thoroughly, and everything worked fine. However, when I shared my branch with the frontend developer, she told me, “Your endpoint doesn’t work.”

After an hour of debugging, we discovered the problem. We had dereferenced a pointer within the middleware system of the framework. Unfortunately, there was no way to fix it. The development team is currently working on version 3 (V3) and, as I understand it, they have refactored the middleware system for V3. Unfortunately, the team hasn’t provided a clear release date for V3.

After Mourning

We had to make a quick decision to avoid blocking our development, so I migrated the HTTP package. I don’t know if it was the best solution, but the purpose of this article is to provide feedback from our experience.

Here are a few metrics:

  • We have 50+ endpoints to migrate.
  • Our global coverage is over 80%.
  • We develop with clean architecture patterns and some elements of hexagonal architecture.
  • We heavily use dependency injection and composition patterns, which provide huge modularity and design decoupling for each part of the code.

Feedback

HTTP Package

I hesitated between two packages: the Golang http/package and Echo. Given that version 1.22.0 of the http/package was released a month ago with significant improvements, I didn’t want to risk redoing a migration in two months. I chose Echo as our HTTP framework.

Difficulty

I was pleasantly surprised by the ease of the migration. The biggest challenges were:

  • Understanding how the middleware system of Echo works.
  • Ensuring our tests worked with minimal changes.

In reality, these were not major difficulties. For example, inside the handler function, we only had to change how we parsed the URL, got the query parameters, and retrieved data from the request's body. For the tests, we only needed to change one or two lines.

In Action

We spent four days on the migration. I worked for one day to bootstrap it, and then my co-worker Marina took over. The migration went smoothly, with 95–98% of the codebase remaining unchanged.

Conclusion

Today, we are back to where we were before the migration. We have resumed code production, and everything is deployed in pre-production and working well. Our architectural choices at the beginning of the SaaS development saved us. If you’re interested in software architecture, I plan to open-source a CLI tool to generate your codebase using best practices like dependency injection and composition patterns.

You can follow me on Medium or LinkedIn.

Feedback

Software Engineering