TheFork ❤️ Microservices

Francesco Lerro
TheFork Engineering Blog
5 min readDec 4, 2023

A dive into patterns and practices

Microservices promote a modular approach, where various components of an application operate as independent services.

The adoption of that architectural paradigm actually helped TheFork to build more scalable, resilient, and highly maintainable systems. The migration process from monolith to microservices allowed the organization to evolve towards cross-functional teams with clearer boundaries and responsibilities.

In this article, we will explore several patterns and practices that we actually adopt at TheFork to harness the full potential of the microservice architecture.

The front door (API Gateway)

Imagine a reception of a busy hotel where numerous clients check in and out. The reception acts as a central point of contact for guests, streamlining the check-in process and directing guests to their respective rooms, while ensuring a smooth and consistent experience.

Accessing backend services via the API Gateway

Similarly, an API Gateway serves as a unified entry point for clients in a microservices ecosystem. It centralizes authentication, authorization, and SSL termination, enhancing the overall security of your system. It also enables the distribution of incoming requests across multiple instances of a service enabling load balancing.

Elastic harmony (Autoscaling)

Imagine you’ve just completed your shopping at a busy grocery store and you’re waiting in a single long line to check out. Suddenly a store employee with a microphone announces the opening of several new registers and you can walk out of the store way faster. You just experienced autoscaling!

Autoscaling dynamically adjusts the number of microservice instances based on the current traffic, ensuring that you only pay for the resources you need.

Autoscaling the Review service according to the incoming traffic

Together with load balancing, the autoscaling pattern will create a harmonious symphony of efficient resource utilization and responsiveness. The microservices can gracefully adapt to sudden spikes in traffic, keeping your applications performant and cost-effective.

Tailored Experiences (Backend For Frontend)

Imagine a personal shopper, perfectly knowing customer needs and picking the best items from the store for each customer. Similarly, in the Backend For Frontend pattern (BFF) the API endpoints and data payloads are tailored to suit the specific needs of individual front-end clients.

Different clients accessing tailored APIs

This allows you to optimize client experience, by serving the right data to your clients efficiently. The overall user experience will also be enhanced, by minimizing the back-and-forth between clients and backend services. On the other hand, more effort will be required in terms of maintenance and evolution.

The implementation of BFF at TheFork played a crucial role in optimizing the developer experience for our mobile software engineers and enhancing the speed of our mobile apps.

Asynchronous facts (Event-Driven Architecture)

Do you like podcasts? Content producers can record episodes discussing different topics, subscribers are notified when a new episode is published and can consume the content at their own pace.

Similarly, in Event-Driven Architecture, services communicate through events, enabling the software components to operate independently. A service publishes an event when something significant happens, and other services subscribe to the events they are interested in.

Inventory and Billing services consuming the “Table reserved” event

This asynchronous communication style promotes flexibility and scalability. Services are loosely connected at runtime and can be scaled independently. Even if a service goes down temporarily, events can be stored and processed later, enhancing overall system resiliency.

Event-driven architecture adoption significantly improved the team independence at TheFork, the organisation experienced accelerated iteration, delivering more value to both diners and restaurant owners.

Incremental transformation (Strangler pattern)

Picture this: your are growing a new plant to replace an ancient tree with tangled roots. The Strangler Pattern is the axe that enables you to gradually replace the old with the new without taking the whole tree down at once.

This pattern involves gradually replacing parts of a monolithic system with microservices. Over time, you “strangle” the monolith by migrating specific functionalities and features.

Gradual transition from monolith to microservices

The risk of migration failure is mitigated, due to the incremental transformation of the system. In addition, only critical or outdated parts of the monolith can be migrated and new features can be rapidly introduced, without waiting for the migration process to finish.

The implementation of this pattern enabled us, at TheFork, to accelerate innovation, while eliminating concerns about disrupting existing functionalities for end users.

Illuminate the path (Distributed tracing)

Distributed Tracing is like a detective for microservices, helping you trace and monitor requests across the entire architecture.

Microservices are all about breaking down applications into smaller, more manageable components. With this approach, tracking and debugging issues can be daunting. This is where Distributed Tracing comes in. It provides visibility into the journey of a request, allowing you to identify bottlenecks, troubleshoot issues, and optimize performance.

Ability to correlate services behaviour across the entire system is essential for maintaining a healthy microservices ecosystem, ensuring that you can effectively identify and resolve issues as they arise. Without it, you’re navigating in the dark. With it, you have full visibility and control over your microservices architecture. Modern monitoring tool providers already include this feature in their offerings.

Distributed tracing has proven invaluable for us at TheFork to build real-time service maps, providing an enhanced overview of the actual system behaviour. Prior to its adoption, our practice involved extracting static dependency diagrams from source code configurations. However, getting a comprehensive understanding all the side effects associated with asynchronous interactions via events was a time-consuming challenge.

Conclusion

Microservices, with their modular, decentralised approach, have transformed the way we design and build applications.

Embracing microservices also comes with its fair share of challenges. Managing a distributed system composed of numerous services and ensuring the reliability of interconnected components can be daunting. Understanding and implementing these patterns, helped us at TheFork to unleash the full potential of microservices while ensuring applications are scalable, flexible, and resilient.

Further reading

--

--