This post is a tidied up version of a lightning talk I gave at Scale Summit yesterday after jonty successfully trolled me into getting up on stage.
A thing that people seemed to want to talk about at Scale Summit was “micro-services” (I have no idea what the hell they are in comparison to just normal services, but whatever) and writing service oriented architectures.
I’m here to make a request: can you not?
Services can absolutely be good things. There are a lot of cases where they are exactly what you want, but I’d argue that you shouldn’t write a service to do anything that your system is not already doing.
Instead what happens is that people starting out a project go “We’re going to need to scale. I’ve heard services are the way to scale. Lets write services!” and you end up with a service oriented architecture very early on and everyone suffers for it.
I’ve seen this at my last two companies. The first time the service oriented architecture was so bad that fortunately we had no choice but to fix it, but at my current place we still seem to be hell bent on pretending it’s a good idea so I’ve not much luck in doing so.
The problem is that when you start out on a project (whether a new product or a brand new company) you have no idea what you’re doing and you need to figure that out. This isn’t a problem, it’s entirely normal. You do some product development, write some code, and over time you start to figure it out.
Thing is, you need to change things a lot while you’re doing this, and services get in the way of that. A service boundary is one which is difficult to refactor across, and as a result if you discover you’ve cut your code-base across the wrong axis and that cut is a service you’re probably stuck with it. At the very least, fixing it becomes much harder than you want it to be and you’ll end up putting up with it for much longer than is optimal.
Similarly, it’s very hard to simultaneously make changes to both ends of a service because they’re deployed separately. The result is that you end up building up layers of backwards compatibility into the service, even when you’re in 100% control of every line of code involved in interacting with it, and the library (or libraries) you wrap around the service to talk to it tends to accumulate a lot of cruft to deal with various versions or the not-quite-right adaptations you’ve ended up making over time to cope with this inflexibility. This often makes the libraries for calling the services really awkward and unpleasant to work with.
All this is of course not even counting the extra code you had to write and extra operations overhead of having all these services.
Fortunately, it turns out that there’s an easy solution to all these problems: Don’t do it.
Your language has a perfectly good mechanism for calling code you’ve written: A function. It has a perfectly good way of grouping functions together: A module (or, if you insist, an object). You can just use those. Take the code you were going to write as a service and just call it directly. It’ll be fine. Trust me. Once the interface you’re calling has stabilised and you decide that you really want a service after all, you can just take that code and turn it into one. In the meantime, you can develop happily against it, change it if you need to, and generally have a much less stressful life than if you’d tried to build services from the get go.
Pingback: 4 – Write libraries, not services – Official Offeryour.com Blog
Pingback: 4 – Write libraries, not services – Exploding Ads
An interesting idea, but I think you may be missing the point where “micro”-services really shine: Large, semi-isolated development groups.
When every developer has their hands in every system, writing libraries is definitely the path of least resistance. But when we need to start scaling out and subdividing developer teams, library integration becomes a massive pain, since these libraries often have hidden dependencies (Needs to be running with a database, or LDAP, or in a certain network segment) that are sometimes incompatible with the work being done. Services allow this to all be hidden and abstracted away.
I think that’s the real scaling benefit of services. Not load-scaling, which most methodologies will provide with some effort, but orthogonal development-scaling.
Your argument of building libraries first is a good one, but it’s often difficult to figure out after the fact what people will actually want to consume. When building in a service-oriented architecture you often end up building many services below you that are composed to generate your service, and those are often just as useful to those that come later as your final product.
I’m not arguing that services are always the right approach, though they can be sometimes. I simply believe “Don’t do it” is a bit trite.
No, I understand why services are sometimes useful, I just think that almost everyone who is currently excited about building services and thinks they’re the hot new thing that will solve all their problems is not in that situation and would be better served by avoiding them. I also think that people who are in the situations where they’re useful are probably both large enough and deriving enough benefit from them that some guy’s blog on the internet saying they’re a bad idea is probably not going to have much effect one way or the other.
I see your point and it’s indeed an interesting one. I have to admit that, because of the title, it led me to think that the argument was that we should ‘not’ use microservices at all. Upon further reading I realized that wasn’t quite where you were getting at.
But I also think what you mentioned is very much applicable to languages. The ‘this will solve all problems’ thinking (AKA silver-bullet) is a dangerous one, and should never be adopted when thinking about not only microservices, but anything in general.
In short, I find very helpful to put a solution that someone else has found for their problem into our own context.