It seems that “Building microservices” finally made it to general availability. Actually, I’ve been following the book quite a while now, signed up (and bought the ebook version) pretty early during its early-access phase, and, finally, am pretty pleased with what the result looks like…
Code not first
With “microservices” apparently being one of the recent buzzwords in software development and quite a few tools, frameworks, technologies seem to support this, one is tempted to look for a book giving you a quick hands-on on how to build a system on top of microservices. Instead, the book possibly does the only right thing at this point in time by providing an insightful, pragmatic view on microservices, a view that goes beyond mere technical or architectural aspects and very heavily focusses on “less technical” aspects such as organization and team structure, development process, roles of team members and stake holders in there and so on. This can be seen pretty easily already by the end of chapter 1, in a paragraph entitled “no silver bullet”:
Before we finish, I should call out that microservices are no free lunch or silver bullet, and make for a bad choice as a golden hammer. They have all the associated complexities of distributed systems, and while we have learned a lot about how to manage distributed systems well (which we’ll discuss throughout the book) it is still hard.
Every company, organization, and system is different. A number of factors will play into whether or not microservices are right for you, and how aggressive you can be in adopting them.
Especially that part of “every system/company/customer is different” is a re-occurring topic in the book, which can’t be emphasized enough in my opinion. In many ways I have quite a history of experience in dealing with “golden hammer” approaches (which so far and still is my most favorite architectural antipattern for several reasons beyond the scope of this article), and even just this first chapter makes the book pretty much worth reading. All in all, throughout the book Sam Newman does a great job of providing a good guideline for architects and software designers on how to implement micro-servic’ish approaches in their software – if to do so at all. This includes, too, critical things such as testing, monitoring and security, each on a conceptual level so you should not expect code snippets to be copied from the book, but it will (at least for my taste) provide you with enough general insight to know where to look for technologies, frameworks, implementations of “things” if you want to make it work out for you.
Another good thing, for this, is the very last concluding chapter (“Bringing it all together”); in many situations I would recommend reading this first, directly after or maybe even before reading through chapter 1 to get a quick idea of what the book is all about, and to get an idea where to go more into details. Again, this includes a final thought on when explicitely not to use microservices as an architectural approach.
My first piece of advice would be that the less well you understand a domain, the harder it will be for you to find proper bounded contexts for your services. As we discussed previously, getting service boundaries wrong can result in having to make lots of changes in service-to-service collaboration—an expensive operation.
Greenfield development is also quite challenging. It isn’t just that the domain is also likely to be new; it’s that it is much easier to chunk up something you have than something you don’t! So again, consider starting monolithic first and break things out when you’re stable.
Good concluding thoughts in a book I do heavily recommend to anyone who is into software architecture or software design and who is, eventually, in charge of operating and updating (semi-)monolithic systems to both keep them running and make them meet new requirements…
Monoliths and dimensions
A few personal reflections on the whole subject: We have decided to go a microservic’ish approach a while ago, indeed after seeing that maintaining a large and complex monolithic applications is a tough and extremely risky job (especially assuming disputable test coverage because the system itself doesn’t really support automated tests).
So, what did we learn so far: There is no free lunch about it indeed. Not that this comes as a surprise, but it really is important to point this out. Moving from a monolith to a microservices-based environment, as with possibly all technical or architectural changes, is tempting because it’s easy to see the benefits and same as easy to ignore the problems that immediately will come.
Talking, especially, about our move from larger Java EE / Spring modules to a bunch of services: Of course, it is easier to maintain and deploy particular services. Components turn out to be smaller (and so easier to understand/debug/maintain). It’s easier to communicate interface contracts because you can eliminate a whole load of technical stuff from these and focus on what’s essential (compare working with a browser-based swagger API reference to working with CORBA or Java RMI IDLs and you will get a pretty good idea of what I mean), at least if you go down a RESTish route. It’s indeed much easier to replace a particular service with a new implementation (given the API is robust enough and people actually do care about API compatibility). And it’s, again assuming these services are somehow “RESTish”, easier to test these things – comparing testing a RESTful service implemented in a dropwizard application to testing a set of EJBs (that, in production, run inside an application server) in an IDE, I have a pretty clear idea what my favorite is.
Downsides, however: First and foremost problem is that, obviously, you don’t generally reduce complexity. It’s just that you push it to another level in this way or the other. If you do what I consider to be a “half-baked” microservice environment (services that still depend upon each other more or less strong), you suddenly end up with something you never really needed to care much about while your application was a large EAR file deployed to an application server: Availability of the services – suddenly you need to make sure either all of the services you depend upon are really available all the time, or you need to make sure your “consumer” has a robust way of dealing with temporary outages of required services. Same goes for service discovery: While essentially you relied upon your application server to @Inject the “right” EJBs to your service, now you need to handle a more or less complex environment with different servers running on different hosts or VMs. It works, of course, but it’s not trivial and it’s a level of complexity you possibly didn’t have to deal with before. Same goes for transport and, eventually, (un-)marshalling of data on the wire – there’s a difference in between working with an all-Java application and a set of common base entity classes, interfaces and the like and working with a RESTful environment in wich all communication between services, if so, happens based upon JSON and HTTP. There’s a penalty of course for (de-)serialization here, but there also are more profound issues (such as, in example, dealing with Files or other internal resources that can’t be easily serialized for obvious reasons).
All these things make microservice architectures indeed complex. So, I guess one of the developer colleagues of mine surely is right: If you can’t get a monolith to work, you aren’t likely to get a microservices application to work either. Yet, I think microservices are a good thing for your toolbox if indeed you repeatedly learnt to know how hitting the wall of your monolith feels like, and it also is a good approach if your application is in for some more general architectural refactoring: Oliver quite a while ago did a pretty good talk on software architecture during a JUG Saxony session, and the “sliced” architecture approach indeed seems the sane way to go here – the idea to not build a bunch of heavily interdepending microservices but actually of more or less loosely coupled applications solving certain business use cases (user management, order management, document control, …) from bottom (persistence) to top (user interface). From my point of view, coming from a monolith and moving to a more “maintainable” architecture, so far this seems to be the smartest way to get you going… and yet, of course, it’s also a learning curve. But it doesn’t get boring. ;)