4 ms·
Microservices vs. monoliths is a false dichotomy in the present day. If you put microservices in a monorepo with a good build tool (like NX), put the common au
by basicallybones 4y ago
Microservices vs. monoliths is a false dichotomy in the present day.
If you put microservices in a monorepo with a good build tool (like NX), put the common auth/logging/types/dtos/etc. functions in reusable libs, and version/release all the apps together, you get the best of both worlds.
At a small scale, you can deploy your whole containerized stack on two big HA instances (monolithic infrastructure, so much easier). You can leverage common libraries without versioning hell/cross-repo coordination. If you have mediocre developers on the team and very aggressive development timelines, the monorepo structure helps enforce modular organization. If you are a good developer, your workflow gets very, very fast, and you can manage a lot of complexity.
Add: additionally, if you have ever-changing requirements and some are obviously bolt-on one-offs that aren't going anywhere, you can limit damage to the code quality by splitting those features into a separate microservices (making it much easier to safely deprecate/remove them in the future).
- twblalock 4y agoA monorepo of microservices is the best pattern, but only if you have a dedicated team that keeps the monorepo buildable, builds tooling for it, and enforces best practices and the right culture. If you don’t do that, you will end up with a huge mess — I’ve seen it happen. For companies that can’t dedicate the resources to do a monorepo properly, a repo per team is the best approach. The true value of microservices is decoupling teams so they can move independently without blocking each other. Also, needing to release the services together, or in a certain order, is a very bad and unscalable pattern. Teams need to be able to move independently. This requires a commitment to avoiding breaking API changes no matter what kind of repo structure you use — and for the love of God, never let more than one service access a database table! A table should only ever have one service that accesses it, and API boundaries need to be enforced as the only way other services get to the data. Do those things and you will be better off no matter what repo structure you use.
- basicallybones 4y agoThese are very good points. A few responses: - The monorepo tooling I prefer at startup scale (NX) does have a learning curve, but it has been pretty easy to maintain using automation (good linting, good build/test pipeline, etc.). For me, learning and leveraging the right monorepo tooling is way easier than having to enforce consistency across large numbers of repos with a small team or watch a low-tooling monolith decay into tightly-coupled spaghetti. I am also in a particular situation where the need for eventual scale is obvious, will come very quickly (clients are big), and the thought of having to rush a scale-inexperienced team (management and devs!) through a monolith-to-microservice migration on a tightly coupled codebase while meeting SLAs is so unpleasant that it makes me a bit sick to my stomach to think about it. - The monorepo framework/tooling matters a lot. For instance, NX is small-scale friendly and largely can be overseen by senior Typescript devs. Bazel, on the other hand, requires a hefty context switch and has a very steep learning curve. - You are right that releasing all services together does not scale past a certain point. My point is that microservice monorepos let you pivot quickly between all-together (monolithic) releases and individual app releases as appropriate for your scale. With good caching and parallel blue/green deployments, adding new services to an all-at-once build/deploy pipeline just uses a bit more compute for the pipeline without meaningfully impacting the pipeline run times. - Having to release services serially in a certain order obviously indicates something is seriously wrong under the hood. - You are very right about monorepo tooling/best practices, but I would extend that to any project that eventually will need to scale. Someone has to take ownership and enforce good practices. Spaghetti code can be harder to prevent in a feature-heavy monolith and certainly is harder to deal with for me if it is in many different repos (i.e., several monoliths). - You can have more than one monorepo for teams that are very different or have specific needs (i.e., different languages, mobile apps, etc.). - I wish I were in a situation where my team could commit to avoiding breaking API changes, but it just is not so because of aggressive development timelines. (I am sure this will change in the future as we scale.) All-together versioning/releasing helps deal with (planned, intentional) breaking API changes very efficiently, because (as long as you can tolerate a failed API call once in a while as a blue/green deployment switches traffic) you're basically performing the deployment as if it is a monolith. Add: 1000% agree about db access. That is very easy to enforce at the architecture/team level.
- simplotek 4y ago> If you put microservices in a monorepo (...) What exactly do you gain with this approach, other than pinning versions of all microservices? Any competent team working on services does not suffer from "versioning hell" because APIs are stable and tracked with integration tests and smoke tests, and you version the API and not the code.
- TakkemTan 4y agoIt vastly reduces the complexity of things like dependencies, testing, CI/CD, versioning. Dependencies can be relative paths. Relative path dependencies will break the build on your machine, so you don't get devs pushing broken stuff. CI/CD servers don't get plugged up with billions of repos building because one changed. CI/CD servers don't need to wait for other builds to finish and push artifacts to do their job. Testers don't need to say "I used version 10.2 of x and 11.5 of y", they can have a single version number for the whole stack. All these things are possible with microservices in different repos. But they require a lot more time to set up and require regular maintianance. If your company isn't large enough to need that, then it makes no sense to move away from a monorepo. Arguably no company is big enough, Google has all it's code in a single 80 terabyte monorepo. But I can understand why that wouldn't scale well either...
- simplotek 4y ago> It vastly reduces the complexity of things like dependencies, testing, CI/CD, versioning. Did it, though? The only conceivable advantage is version pinning. I makes absolutely no difference in terms of test coverage whether you use a monorepo or not. Dependencies-wise, the only thing that a monorepo saves is releasing individual components, which ultimately is not an advantage but a drawback and a liability. So exactly what's the upside, if any?
- cobalt 4y agowhat is the upside of separating them?
- mirekrusin 4y agoExactly. Now it just needs catchy name so vocal juniors have one word to refer to it - they currently know only 2 words for architecture - bad monolith and good micro services.
- boxed 4y agoIsn't that just a monolith with super slow function calls?