5 ms·
You could also have a "monolith" in a single or multiple compatible languages (C, Rust, C++, etc) and have different features/modules separated in different lib
by conradk 9y ago
You could also have a "monolith" in a single or multiple compatible languages (C, Rust, C++, etc) and have different features/modules separated in different libraries. These libraries could then act as the "microservices".
Developers could be tasked with working on these libraries that would have 0% overhead (since they are just a piece of code that can be used in another library), instead of creating REST/SOAP/RPC APIs that come with the HTTP/SOAP/RPC overhead.
This means you can start small, with a public REST/SOAP/RPC API. Less infrastructure, less server config, etc. And if at some point you need more scalability, you can always do an actual microservice (ie a separate REST/SOAP/RPC API) with the library code the day you absolutely need it for horizontal scalability or whatever.
I have seen this pattern used in the Rust world a lot. Projects expose both a library and a binary. And the binary is built on top of the library. This means you have 0 overhead if you want to use the binary's features, since you can simply include the library and get going.
Also, I think that having the tools to support deprecation is big advantage when working with a monolith. I think Rust has built-in support for compile-time deprecation notices. PHP, for instance, doesn't have that particular feature yet, as far as I know. Symfony tries its best by adding deprecation notices when you call a deprecated method/function. But you have to call it to realize it's deprecated.
I'm not here to promote Rust or hurt PHP, I actually love both. The statements above apply to a lot of other languages as well. I just took the examples of Rust and PHP because these are the ones I've worked with the most.
@xxs's comment is spot on as well.
- partycoder 9y agoIf you divide your project so self-contained components with scoped set of responsibilities that are not coupled to the rest, that's fine as well. I've used that pattern with great success. Microservices are a way of achieving this, but as you describe it, is not the only way. Discipline is another way. Now, as you have more people involved, or release deadlines get tighter, chances that tech debt gets introduced increase. Unless you go back and repay the tech debt, situation would worsen. In that sense, microservices are some sort of cap on the impact of tech debt from rushed deadlines and lack of discipline.
- potatoyogurt 9y agoJust saying that you're using microservices doesn't guarantee that you'll be avoiding or capping tech debt. I've seen some hopelessly entangled "microservices" that are so full of assumptions about how other parts operate that they're essentially unusable anywhere except for one or two places. You need that discipline whether you are separating components by service boundaries or just by organization of code within a monolith. I agree that microservices tend to make it harder to accrue tech debt past a certain point, though. Although they can also dramatically complexify the process of figuring out what is going on in an app if log files are spread around a ton of places (which is mainly a tooling problem).
- partycoder 9y agoThat's what log aggregators are for.
- potatoyogurt 9y agoYes, that's why I said it's a tooling problem. But not everyone has log aggregators set up (or set up in a sane/totally adequate way), and even with log aggregators, it takes a little more care to make sure you're exposing the right information and exposing it in a way where it's easy to trace the important stuff that's happening chronologically. I'm not saying that it's an unsolvable, or even unusually difficult problem, I'm just saying that it's very possible to do wrong. If an organization can fill a monolith with tech debt, they can probably find a way to do the same with microservices.
- imhoguy 9y agoThis is true but for meaningful aggregation is not easy. You need to provide correlation identifiers to identify log entries which are part of user request invocation. This complicates the protocol between distributed services if they are in different business domains with APIs using unrelated resource identifiers. Usually correlation ID is dispatched over e.g. HTTP header or separate API parameter. With monolith the issue also occurs but loggers usually take care of this with thread local variables or some other contextual storage.
- spdionis 9y agoHaving to call the method to get a deprecation notice is theoretically a non-problem, if you have a proper test-suite. Any interpreted language will have this problem anyway. Not to take away anything from your comment, just nitpicking.
- conradk 9y agoNot every interpreted language has this problem. I'm thinking that there probably is a way to get compile time deprecation notices in Typescript. If there isn't, this will probably be possible in the coming years. Typescript is somewhat compiled, but the same applies to Dart, which is both interpreted in a VM and/or compilable to Javascript. Maybe Hack (the Facebook version of PHP) could have that too (it is both interpreted and statically checked).