This interview was done for our Microservices for Startups ebook. Be sure to check it out for practical advice on microservices. Thanks to Julien for his time and input!
For context, how big is your engineering team? Are you using microservices and can you give a general overview of how you’re using them?
We have a team of 49 people in engineering.
We have tried to split our service as much as possible in different pieces and use different technology for that. For example our core search API is written in C++ for performance but only focuses on the core search tasks. We have a lot of different services around the search API to make the service work. A few examples include:
- Push logs from search machines to our analytics infrastructure (developed in Go)
- Probes to check the status of our service (developed in Java)
- Monitoring infrastructure that collect status of our probes (developed in Scala)
- Monitoring dashboard (developed in Rails)
- Log processing - analytics (developed in Go)
- Click tracking service (developed in Go)
- Product dashboard (developed in Rails)
Did you start with a monolith and later adopt microservices or did you start directly with microservices? Why?
We started with a microservices approach. The main goal was to be able to use different technologies to build our service, for two big reasons:
1) We want to use the best tool for each service. Our search API is highly optimized at the lowest level and C++ is the perfect language for that. That said using C++ for everything is a waste of productivity, especially to build a dashboard!
2) We want the best talents and using only one technology would limit our options. This is why we have different languages in the company. Go is less perfect than C++ when you want to optimize everything at the millisecond level but is the perfect language when performance is still key (e.g., processing of logs where we process several terabytes of logs per day -- using Ruby or Python would be a waste of CPU).
How did you approach the topic of microservices as a team/engineering organization?
Microservices should not come at the cost of a visible impact on performance for the end user.
We have a culture of using microservices. Several customers consider our search API as a microservice itself even if the product is actually composed of dozens of microservices. We do not really care about the size of the service and whether it is "micro" or not. We think it is important to investigate the different ways to split the service we develop into several pieces. If there is a way to split and that the performance impact is acceptable, then we do the split. Otherwise, we do not accept the split because of performance reasons.
To say it differently, microservices should not come at the cost of a visible impact on performance for the end user. We have a big focus on performance and we never consider something that can result in degraded performance from a user point of view.
The engineering team has grown a lot in the previous years and we have naturally organized the teams around the different services we have.
Have you broken a monolithic application into smaller microservices? If so, can you take us through that process?
We have not broken a monolithic application into smaller microservices, but we have already replaced a lot of microservices. A good example is our log-processing that was replaced twice in four years.
The V1 was developed quickly in Rails for the launch of our product in September 2013 and it was only a few hundred lines of code. We knew it would not scale but it was enough for the first few months of the service.
We introduced the V2 in April 2014 with a multi-threaded Java version to scale with the service.
In 2017, we introduced the V3 developed in Go using Google Cloud Pub/Sub, mainly for scaling reasons but also to prepare for future evolution of this service where we will have new microservices connected to it that were non-existent before.
How do you determine service boundaries and what lessons have you learned around sizing services?
We define the boundaries of a service by defining its input and output.
Sometimes a service is a network API but it can also be a process consuming files and producing records in a database. This is the case of our log-processing service.
In practice, the discussion on boundaries is done through a specification document shared to all engineers to collect feedback and make sure we have the best design. We sometimes have discussions on over-engineering to make sure we do not introduce complexity for something that has a low probability of happening. Staying pragmatic and not inventing problems is key for engineering teams.
How have microservices impacted your development process? Your ops and deployment processes?
In terms of development process the main challenge is to ensure we have enough people on the team that know each service. We are SOC2 compliant and have a change policy that requires us to have a minimum of three people for each change: one engineer that writes the PR, one engineer that reviews it, and a third engineer that deploys in production.
To solve this challenge, it is important to control the number of new programming languages introduced in the stack relative to the size of the team.
The second challenge is in term of deployment is that having more services means that the operation become more complex.
We have solved this by defining the SLA for each service and redefining our on-call strategy. We initially had only one on-call team and we then moved to three different on-call teams: one for our main API, one for our website/dashboard, and a third team for all other services.
How have microservices impacted the way you approach testing?
Each team is writing their own tests and while the level of testing is pretty good, it is never perfect. The challenge is to have a unified level of testing across all services. We have tried a few things to improve the homogeneity. Every quarter we organize an offsite with all the engineering team and we share best practices between the teams in order to replicate things that worked well. Testing and quality is one of those topics.
How have microservices impacted security and controlling access to data?
Overall it simplified our security audit and tests, especially regarding compliance. Each service is easy to analyze compared to a big monolithic system. That said, the challenge is to be sure we do not forget any service. We have seen several times that having a lot of services can easily lead to often forgetting one when discussing access to data. This issue can be solved by sharing the knowledge across the team and documenting the different services in production.
Thanks again to Julien for his time and input! This interview was done for our Microservices for Startups ebook. Be sure to check it out for practical advice on microservices.