I was at Scale Summit yesterday and jonty successfully trolled me into giving a lightning talk. For once I managed to do this without the crippling nervousness I usually get from public speaking (turns out the secret is being slightly drunk), so I actually managed to be reasonably coherent and people seemed to enjoy it. Woo.
Anyway, this post is a tidied up version of the talk I gave:
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.