8 ms·
>Shared libraries were created to provide behavior that was similar for all workers. However, this created a new bottleneck, where changes to the shared code co
by kkapelon 6y ago
>Shared libraries were created to provide behavior that was similar for all workers. However, this created a new bottleneck, where changes to the shared code could require a week of developer effort, mostly due to testing constraints.
That is a big red flag. Microservices that suffer from shared code changes are not really microservices, but a distributed monolith instead.
- MaxBarraclough 6y agoThat sounds like an overly broad generalisation. They might well all share the same basic framework code, of course. Why not share code for recurring concerns like auth?
- bauerd 6y agoIdea is that you have a service that authorizes transactions
- klohto 6y agoBecause if you share something (like auth for example), you should have microservice for that. The question is not about duplicate code, but about duplicate libraries that handle the same thing. Decoupling the auth process into separate microservice removes the bottleneck.
- alkonaut 6y agoEventually you'll have a service to format phone numbers in the format that the company needs to be standard across all services. If you don't want to do that, then you need a simple shared library for that. The problem is that there is no easy way to draw the line between "this is obviously a trivial library function we should just link into our code" and "this is something we can't share because it would create friction or break our isolation". Auth is obviously a "service" but phone number formatting as a service seems extreme.
- gridlockd 6y ago> Auth is obviously a "service" but phone number formatting as a service seems extreme. You clearly haven't finished drinking your Kool-Aid yet.
- curryst 6y agoOne of the lines is going to be acceptable performance. Your phone number formatting microservice is going to be orders of magnitude slower than a client library. The auth service will likely have to hit a DB anyways. Assuming the microservice call has roughly the same network latency as the DB call and the DB has 0 response time, it would double the total time to perform the auth. It only gets more favorable as DB response times go up. More generally, I think microservices make sense in scenarios where the time to process the request is longer than the network latency incurred by making it a microservice. Things that have to hit a DB are generally okay. Pure functional things that just compute on CPU and RAM are generally not, unless they're very computationally expensive like running a simulation or something like that.
- jmt_ 6y agoI'm reminded of the classic problem of static utility classes, where you have functions for say formatting phone numbers, or computing a commonly occurring simple mathematical function. It can be difficult to figure out how to better modularize the functionality provided by this class, the motivation typically being having a large static utility class often violates the principle of a class having a clear, single responsibility. Breaking up a large static class into other static classes that better encapsulate some functionality/concept can help but isn't always the best solution. So lets say we have shared code for doing something like phone formatting. My question for more experienced microservice practitioners is -- does it make sense to create a microservice for preprocessing data in general? Phone number-formating-as-a-service is excessive but creating a microservice for processing data where phone number formatting is just one aspect of this service makes sense to me. All other services can throw data at the data processing service and get data back in some sort of standard and expected way conforming to whatever business logic/processing rules required.
- dx034 6y agoReinventing all parts for every microservice sounds wasteful to me. Especially if they handle the same data and/or use the similar business logic.
- kminehart 6y agoA common practice is to introduce services that handle shared functionality. One common example is, instead of having a shared library that reads & verifies JWTs, use a gateway service that handles this before requests reach the upstream service. This means changes to your organization's JWT code will only require a redeployment of one service, the JWT Auth service.
- dx034 6y agoBut that also for input handling, formatting or simple business libraries? Sure you could implement that as services but that would probably result in up to a hundred service calls for one customer interaction. Maybe it looks clean from an architecture perspective but I can't imagine how that'll result in a good user experience.
- kkapelon 6y agoLet me clarify because I wasn't clear in the parent comment. Microservices using shared libraries -> ok Microservices "suffering" from shared libraries -> not ok.
- pjc50 6y agoThis is really a time-of-binding argument; the difference between a "library" and a "service" is that one is in-process and accessed over function calls, and the other is out-process and accessed over RPC. If you change code that other services are using, you can break those other services. No way round that.
- Autowired 6y agoWhile that is true, a microservices architecture can (and in my opinion should) rely on messaging and account for message schema evolution. Dependencies between services should be way less coupling than dependencies between an application and a library.
- caust1c 6y agoSchema evolution is just as big of a dependency hell as managing direct library dependencies. With a monolithic architecture, a lot of those concerns are contained within the context of a single repo, and can be tested much more easily than with many repos.
- marcosdumay 6y agoA library API can rely on versioning and account for schema evolution too. Even different versions can coexist if you decide that's important from the beginning (what is the same requirement as with services). The only real difference is that services have a slow serialized network interface that fails 4 or 5 orders of magnitude more often than libraries, but can migrate over memory domains.
- zzbzq 6y agoThere are circumstances where they are equivalent, but they're very different overall. Namely, if you use a service, you update it once and see the new behavior everywhere. If you use a shared library, you have to update and redeploy every service. Libraries are strictly inferior in that scenario. This sounded, to me, like it was Segment's problem. They were updating shared libraries all over the place all the time. I generally avoid creating shared libraries, they're a trap. They have a very narrow band of usefulness squeezed in between the more palatable solutions of creating new services or just copy & pasting code and allowing it to diverge for each different use-case.
- gridlockd 6y ago> Microservices that suffer from shared code changes are not really microservices, but a distributed monolith instead. In other words, if you can share a lot of code between services, a monolith is actually an appropriate architecture.
- barrkel 6y agoSharing code or reinventing the wheel repeatedly is inevitable once you have more than one concern by which you can divide services. For example: let's say you have lots of integrations, and you need to scale compute, and parse and generate common data sent to and from the integrations. You can either have a monolithic integration service which you scale out on load; or you can have integration-specific services that scale out on load and share your data parsing & generation library. Due to multiple concerns, there's no "best slice". FWIW, scaling out compute is a stronger argument to me for a service boundary than responsibility segregation. Scaling out requires distribution; scaling up complexity doesn't, though it can help for other reasons, like CI/CD. I prefer FaaS architectural patterns with the freedom to share libraries in different functions (images) to services, especially if long-running state is not needed.
- kkapelon 6y agoSorry for not being clear. Having a shared library is not a bad thing on its own. Making the library a bottleneck is the anti-pattern. If you wish to have a shared-library of microservices you should be prepared to have multiple versions of it running at the same time without any pressure to update everything at once. If your shared library is the bottleneck, it means that your microservices are tighly coupled (hence the distributed monolith)
- gitgud 6y agoA good architecture is orthogonal, meaning parts can scale independently... Shared code shackles everything together, like global variables...
- jmilloy 6y agoThat just sounds like the shared libraries needed to make breaking changes less often. If you're going to make changes to core code, it's going to take time to get everything up to date no matter how your code is organized. In other words, shared code needs to be treated just like a third-party library/service (both from the developers and users points of view).
- NewEntryHN 6y agoIf you have zero coupling, it means you have multiple products.