How to Start Using Microservices
hackernoon.com
hackernoon.com
Microservices add complexity, they don't remove it.
Monolithic architecture doesn't force tight coupling. Tight coupling doesn't depend on an architecture. Making a monolith crash-proof is easier than dealing with intermittently-functioning microservices.
Being able to change microservices without that affecting any other services is a design goal, not an architectural feature.
Microservices are not inherently more scalable than monoliths. They have to be designed that way. And monoliths can equally well be designed to be scalable (just add more instances!).
When to use microservices? When one part of your monolith can easily be broken out and run on its own server as a service, and that would improve some performance bottleneck that you need because you can see a point where it will matter in the near future. Otherwise "never".
1. Fewer merge conflicts, easier branching/merging strategy. If you have 200 people checking into a monolith then it is easy to start stomping all over each other.
2. Large changes(say upgrading to a new major version of a library for security reasons) can result in the code base being in a state of conflict hell, or just frozen, while work gets done. With microservices you can upgrade them one at a time.
3. The build/test/deploy pipeline for any given team is shorter. Large code bases take a long time to build and run through tests. If instead everyone has to have well defined interfaces to their microservices then it is possible to test the interface points of a given microservice that is being committed to.
4. Serious screw-ups in one part of the code don't impact code in other places. If someone starts leaking memory in one microservice, then one part of the system has degraded functionality. Worst case it is a critical microservice and your system goes down. Best case it isn't on the golden path for users and it isn't a major outage.
5. It makes you think about deployment and configuration up front. I have seen major systems (billions of dollars, systems you've used in the past) where only tribal knowledge of how to "get it running" existed. There was no formal deployment plan, and deployments could take days.
Microservices force organizations to solve deployment up front.
1) You're right that there aren't merge conflicts, but you swap out merge conflicts with interface changes. Meaning let's say programmer A is working on Microservice B that consumes from Microservice C and she changes the "what I expect from Microservice C" interface. Who changes Microservice C? In THEORY it could be whoever "owns" it, or Programmer A, but in practice sometimes it falls between the cracks.
2/4) We ended up actually writing our own Python packages that did end up being shared amongst some of the microservices. If you want to abide by DRY (not juts as dogma but you just don't want to implement the same thing twice), you do need some shared code. Maybe that "breaks" the microservice "model" and we didn't do it "right"? Maybe. But with what we did, we still did have "internal Python package" updates intended for one Microservice that effected another
This is all from my personal experience so it could be that we just didn't follow best practices or fell into some traps.
To change your RPC protocol in a distributed system, you may add optional fields to the request but you must not add required fields nor change the semantic meaning of any field. You can add new services and methods but you must not disable one that anyone calls.
Who knows exactly what their interfaces are going to be, across their entire project, on day 1, and gets that right every time?
Same problem exists for binary interfaces, or source code interfaces.
Or for a client system that talks to a cloud service.
Or for a cloud service that exposes APIs for other cloud services to call.
Technologies exist to version APIs. It is sad that JSON is the standard interchange format, since it is pretty miserable at this entire problem.
1. You just move your conflicts outside your git repo (or other VCS). The reason you get conflicts is because multiple people are changing the same bit of code. If that's happening over multiple repos/services, it still happens, but now it's harder to detect and deal with.
2. Again, if your change causes an interface change, then that's going to be easier to deal with in a monolith than in a microservice.
3. This is only true if you're not running integration tests across multiple microservices. Which you need to be.
4. This is plain untrue. If one of your microservices is crashing all the time, then the other services that depend on it are also fubar'd. The only different is that you only detect this at run-time.
5. This is a management problem, not an architecture problem. And the fact that several successful monolith deployments have scaled to the point where I'd have used them without needing formal deployment plans is a positive point for monoliths, surely?
Integration tests cover this.
> 2. Again, if your change causes an interface change, then that's going to be easier to deal with in a monolith than in a microservice.
This point was more about upgrading dependencies. A lot of code bases never upgrade dependencies because it is too much work. (I've seen some really old versions of OpenSSL in code repos...).
In a monolith the task is "we have to freeze the entire code base and upgrade this library in hundreds of places".
In a microservice based system, the work is "farm out the work to a dozen teams and add upgrading the dependency to their sprint backlog."
That is a huge difference. The first time I saw this in action I was blown away by how incredibly different this was vs what I'd experienced before. It means keeping up to date with security changes, or just not letting dependencies get too stale, is no longer a huge burden on a code base.
> 3. This is only true if you're not running integration tests across multiple microservices. Which you need to be.
Yup, of course you need to be! But monoliths also need tests, and ideally the monolith is broken up into black box modules that don't know each other's insides and the code is tested accordingly. Microservices force that test approach, but ideally there is not much difference.
(Placing the entire system under test may be easier/harder, depending on business logic being tested)
Also I have experience where build/test pipelines can take hours. With microservices you can only run the integration tests that directly impact that microservice.
In theory with a monolith you can use tools that intelligently detect what code was changed and only run a subset of tests accordingly, but I've not seen those tools used, only discussed on HN.
> 4. This is plain untrue. If one of your microservices is crashing all the time, then the other services that depend on it are also fubar'd. The only different is that you only detect this at run-time.
It is an edge case benefit, but I'd argue it is still a benefit. Degraded performance in one use case is better than an entire service going down. There are differences between "Everything Xbox is down", "Xbox Live match making is down" and "You can't redeem gift cards".
(No comment on actual Xbox Live functionality or stability!)
> 5. This is a management problem, not an architecture problem. And the fact that several successful monolith deployments have scaled to the point where I'd have used them without needing formal deployment plans is a positive point for monoliths, surely?
Sure, but most things I mentioned can be solved by management! Better test strategies, giving enough time to planning to avoid brittle interfaces, etc etc.
To be clear, outside of running my own startup (which was mostly serverless), the backends I've seen or worked on have been part of large systems.
For a team of 5? Microservices are probably the wrong solution.
I'd say anything less than a team of 25. And even then, I'd want to do a sacrificial prototype as a monolith.
It might not meet the current definition of a micro service, but it makes sense when each bit of functionality is being developed/managed by different teams. Especially in a large company where there are many teams that cater only to other employees.
That is, Instead of forcing everyone to choose the same language and architecture and everything, let each team spin up an API for whatever it is they are providing. I believe this was the original reason for micro services, and somehow it morphed into breaking applications into separate systems even when there is no real reason to do so.
Another OK reason is when a particular service needs it's own change schedule.
I get the "multiple teams" argument, but I don't think it's an architectural feature. To get multiple teams working on separate-but-connected code, you need to define the interfaces between those separate chunks of code. That's enforced by microservices, sure, but there's nothing stopping you from defining an immutable interface in the monolith too.
If you're writing a monolith with loose coupling of features, then its not that much more work to break those features out into a service.
You might not be able to change the API of a service without affecting others but you should be able to deploy separately to meet the definition of a microservice.
there are good reasons to split things out into separate services, especially if they no longer fit on a commodity server, but this rarely applies to the stateless webapps and rest/grpc services that 95% of people work on.
The problem I see with some of the backlash against it is that the complaints are often circular and inconsistent. The hardest part is writing a decoupled codebase, not the fixture of running part of the code in a service wrapper. Proponent of monoliths will claim its easier to build a monolith and you can organize your code too, but this is a contradiction. Either you're doing the hard decoupling work properly or you're simplifying things by keeping them coupled. To say you can do both at the same time is disingenuous.
But that said, both styles have their pros and cons and they have their place.
that and junior developers reading about microservices and deciding that regexservice needs to be a thing.
But it's cool, so everyone wants to use it, so suddenly we get bullshit like TFA.
It's like Agile. Agile has some great ideas. But now when people say "agile" they mean Scrum. And Scrum is so badly implemented in most places, used as an excuse to do all the things that the Agile Manifesto tried to warn us about in the first place. We end up at shittily-organised micro-waterfalls and everything is crap, but somehow that's "Agile".
Same for microservices. There's some good ideas there, but most of the time it's implemented so badly, increasing complexity and reducing managability. We end up with thousands of lines of spaghetti YAML organising god-knows-how-many of instances of god-knows-what when all we needed was a simple webserver, file store and database. And somehow that's "better".
1. Write a monolith.
2. If the project fails or doesn't really need to scale in terms of code or hardware, you don't need microservices.
3. If the project succeeds, and the code size and team size starts to grow, start looking for parts of the monolith that make sense to encapsulate as their own services.
3a. Also look to see if some parts of the monolith need to scale more than others. This can also indicate part of the code to break out into its own microservice.
4. Now that you have identified potential microservices, very carefully think through the API for each microservice. APIs are very difficult to change after they are widely used, so its important to get it as close to right as possible the first time. API design does not lend itself to "agile" very well.
5. Now you are ready to create your "two pizza" teams and start implementing your microservices.
6. Don't bother thinking about Kubernetes too much before this point. Until you really need to scale, it just adds unnecessary complexity. (But when you need it, you really need it!)
6a. Same may or may not be true for Docker, it can potentially simplify deployments, but if what you have works and isn't creating significant toil, you can always introduce it later.
You can do a lot with module separation and a good dependency tree within a single repo before actually requiring microservices.
> Microtica is abstracting complex cloud setup and automation on AWS
Microservices aren't necessarily a bad idea but keep in mind that the company behind this article has an incentive to encourage developers to build complex systems.
> Microservices are an alternative to the monolith approach that gives developers the flexibility, scalability, and simplicity they need to build complex software applications.
Why can't folks just assess their own situations, review/learn about possible solutions, try stuff out and then eventually go with something?
There's going to be unpleasant problems no matter what you choose. There's no silver bullet. Projects fail for many different reasons, only one of them is because of wrong "technology platform choice."
Microservices are very complex, especially if you don't know the domain beforehand. Most of the time, the additional complexity brings more harm than the benefit.
> Microservices are completely disrupting the way we build applications nowadays. This is one of the hottest trends when it comes to software architecture. More and more developers are adopting it.
> Microservices are an alternative to the monolith approach that gives developers the flexibility, scalability, and simplicity they need to build complex software applications. Companies all over the world have recognized the advantages they get with microservices. Amazon, Netflix, eBay, Spotify, Uber, Groupon, and SoundCloud, are only some of them.
At the bottom of the challenges section, it mentions:
> Aside from all these disadvantages, it’s very important to state that the right kind of automation, tools, and developers who are rockstars in their areas every challenge can be solved.
It also does briefly mention why you'd want a monolith, but doesn't really give it much weight:
> Monolithic architecture is better when:
> * the application you’re developing is simple, and everything is in the same language and framework,
> * you want to test quickly and easily by simply launching the application, and
> * you don’t have too many new features that will trigger the release of the entire application.
So basically the way this comes off:
* Everyone is using microservices, and if you aren't, you should be.
* Only "simple" apps that aren't getting new features use monoliths (and who describes the app they are spending a significant effort on as "simple"?)
* If you find them too hard, you're not a "rockstar" and/or you don't have good tools.
It may not be the intent of the article to have this tone, but that's the way it comes across (and so many articles advocating for the trendy technology-of-the-day are written in this style).
This causes people to react strongly the opposite way to balance it out, and that knee-jerk reaction is naturally "don't!". I bet many of those reacting this way are people that have negative experience and know the downsides better than described here.
Of course every team should evaluate technology decisions on their merits, but cargo-cult programming, resume-driven development, and clueless managers that want to show they're working on the "new hotness" are all things that drive these decisions, and articles written like this strongly influence all those categories.
If you're anywhere near the point of "needing" microservices (if there is such a thing), there is no simple "try stuff out", fwiw. You're talking about potentially 10s of different teams needing to be involved even for some small effort.
1. Don't do microservices
2. Don't do microservices yet
3. Do some larger, more sensible, level of service integration
Might be the worst possible reasons to adopt Microservices. If your Account Management service runs in a different language then your Email service, then guess what? You now need to hire different developers to maintain each service.
Don't. Do do it for this reason, or any reason until your business demands them.
If you're breaking an app apart so one part can use redis, you have something seriously wrong in your engineering culture.
Consequently there are customers left in wind with a tiny problem on their monolith that could've been easily solved if the original architect would've split it in 3 or 4 parts, which I usually do at the time.
I love hypes and I love the culture HN is spreading in developers world. It means a lot of code needs me to fix it and as a freelancer I make sure to get the big money while posing as the God's gift to them clueless clients.
1. Don't do it
2. Don't do it yet