We’ve been designing and building software for over ten years and for most of that time we’ve been using the excellent Symfony framework to do so. Symfony is a traditional monolithic PHP component set, loosely inspired by Java Spring, and we’ve found it to be well suited to the rapid development of the enterprise web applications and digital products that are our bread and butter.
The release of Symfony 4 last year, however, represented something of a gradual change in focus for the framework; away from its monolithic roots and towards a microservices approach, which is a methodology that’s been gaining popularity over the last few years.
To illustrate this shift, the new release was billed as being ‘‘micro by default’, with the Symfony Foundation talking up its new microkernel design, claiming it requires 70% less code to start up an application, compared to Symfony 3.
Amongst other advantages, this change means the overhead of running an individual application is much smaller, making Symfony more attractive for use in a microservice architecture.
A microservice design is based on the concept of splitting your large, traditional (monolithic) applications into several small, distinct applications. Each of these apps will handle a single area of business functionality, and co-operate with other components as though they are third-party applications.
Now, is this really a new thing, or is this just Service Oriented Architecture with a modern name? Well, we’re not going to have that debate here – Slashdot and Hacker News can handle that perfectly well, after all. What we will say though is that the microservices approach (or whatever you want to call it) is primarily beneficial for big organisations. This is because very large applications can be split off into several distinct services, with each managed by their own separate development team.
An additional benefit of a microservice architecture is to allow flexible scaling of the capacity of one specific component, rather than an entire application. This is a good fit in the world of elastic cloud computing, but in most situations, I would argue that this efficiency gain is drowned out by a big, glaring problem.
I’m of the opinion that unless you work for a company such as Google or Netflix, with many hundreds of software developers, you probably don’t need microservices. In fact, for most small or medium sized business, it may be actively inappropriate to take this design route.
There are exceptions that I will come to, but the big elephant in the room is the development and maintenance cost of this approach. We can broadly determine if microservices should be your starting point with a simple question:
‘Is a single component of your system, such as user management, big enough to require constant development by more than one developer, full time?’
If the answer is no, a microservices approach is probably a waste of time and money for you. Instead, if you’re lucky enough to reach that scale later, you can probably afford to slowly split off the components that require such a level of individual attention.
Monolithic applications are usually a much cheaper proposition as you do not need to deal with a whole raft of distributed systems problems. Monoliths using a framework such as Symfony afford many benefits by providing out-of-the-box integration features that are then easy to access from all areas of your application. You can mostly avoid having to deal with issues such as:
- Authentication and authorisation on a distributed system.
- Tracing complex issues on transactions through multiple separate systems.
- Distributed locking.
- Communication between services.
- Additional configuration management for multiple applications.
There are times where microservices are appropriate, but in my experience, these are situations where the scaling requirements or fault tolerance requirements outweigh the drawbacks of having to design and manage a distributed system. A good example here is a business such as Monzo Bank, who need to be able to both instantly scale to demand, and also be able to ensure that a fault in one area of the system does not impact another.
A good approach that we at Browser have repeated several times is to take a hybrid approach to systems design. This involves a central monolith surrounded by supporting microservices, but only where there is a good reason for them to be there. For example, we recently used this approach when integrating NLP processing into an application.
We have built several systems where the core business application is built as a monolith (usually in Symfony) with heavy data processing being handled by a separate pipeline of microservices. This allows us not only to handle massive data volumes without impacting core application performance, but we can take these components offline if required, without affecting the day-to-day operations of the platform.
A considered approach – ideally with a clear understanding of scale and future development requirements – is essential to make a decision on architecture. Do you want to be fast to market? Do you want to support millions of users? Do you need to handle vast streams of data?
Making the correct decision early on gives your product the highest chance of providing a return on your investment in the shortest timeframe, without precluding the options you want to explore in the future. It is often more cost-effective to plan to separate components into microservices later on, rather than in the initial MVP development.