22 ms·
I wonder why no one ever talks about architectures in the middle between those two - modular monoliths. The point in time where you're splitting your codebase
by KronisLV 5y ago
I wonder why no one ever talks about architectures in the middle between those two - modular monoliths.
The point in time where you're splitting your codebase up in modules (or maybe are a proponent of hexagonal architecture and have designed it that way from the beginning), leading to being able to put functionality behind feature flags. That way, you can still run it either as a single instance monolith, or a set of horizontally scaled instances with a few particular feature flags enabled (e.g. multiple web API instances) and maybe some others as vertically scaled monoliths (e.g. scheduled report instance).
I wrote more about that approach on my blog, as one of the first articles, "Moduliths: because we need to scale, but we also cannot afford microservices": https://blog.kronis.dev/articles/modulith-because-we-need-to-scale-but-we-also-cannot-afford-micro-services https://blog.kronis.dev/articles/modulith-because-we-need-to...
In my eyes, the good part is that you can work with one codebase and do refactoring easily across all of it, have better scalability than just a monolith without all of the ops complexity from the outset, while also not having to worry as much about shared code, or perhaps approach the issue gently, by being able to extract code packages at first.
The only serious negatives is that this approach is still more limited than microservices, for example, compilation times in static languages would suffer and depending on how big your project is, there will just be a bit of overhead everywhere, and not every framework supports that approach easily.
- daitangio 5y agoThank you for sharing, and I agree with you- In my humble opinion microservices are "hot" because in theory you can scale a lot with them if you are able to do cloud provisioning. Microservices needs DevOps+Orchestration Service. A good example of microservices architecture is how K8s is designed: I think it is an overkill for most average needs, so think twice before entering in microservice trip tunnel.
- KronisLV 5y agoWell in my eyes equating microservices with Kubernetes is a problem in of itself. I actually wrote about Docker Swarm as a simpler and more usable alternative to it (for smaller/simpler deployments), though some other folks also enjoy Hashicorp Nomad which is also nice (another article on my blog, won't link here not to be spammy myself). If you evaluate your circumstances and find that microservices could be good for you, then there are certainly options to do them more easily. In my eyes some of the ideas that have popped up, like 12 Factor Apps https://12factor.net/ https://12factor.net/ can be immensely useful for both microservices and even monoliths. So i guess it's all very situational and a lot of the effort is finding out what's suitable for your particular circumstances. For example, i made the page over at https://apturicovid.lv/#en https://apturicovid.lv/#en When the app was released and the page was getting hundreds of thousands of views due to all of the news coverage, scaling out to something like 8 instances was a really simple and adequate fix to not break under the load.
- dboreham 5y agoMicroservices solve pretty much one problem: you have a larger organization (> 10 devs, certainly > 100) and as a result the coordination overhead between those devs and their respective managers and stakeholders is significantly limiting overall forward progress. This will manifest in various concrete ways such as "microservices allow independent component release and deployment cycles" and "microservices allow fine grain scaling", and "microservices allow components written in different languages", but really it's all Conway.
- eropple 5y agoThis is a pretty critical point. The drum I tend to beat is that the positive read of microservices is that they make your code reflect your org chart. (If they don't do this, and that usually resolves into developers each owning a bunch of microservices that are related concepts but distinct and are context-switching all the live-long day, you've created the reverse of a big ball of mud: you've created a tar pit. Companies used to brag to me when they had 250 microservices with 100 developers, and I don't think any of those companies are going concerns.)
- chasd00 5y agoi always think of microservices as a product an organization offers to itself. If you don't have the team including managers and even marketing to run an internal product then you probably shouldn't be doing the microservice thing.
- andy_ppp 5y agoThis is one of the things I love about Elixir and OTP+The Beam that underpin it all. It's really great that you can just slowly (as is sensible) move your system over to message passing across many VMs (and machines) before you need to move to a more bespoke service oriented architecture. With Umbrella apps this can already be setup from the start and you can break off bits of your app into new distinct message-able components (micro services you could say) as you like while still being able to share code/modules as needed. The other thing I'd say is you can introspect how these "services" are running in realtime with IEX and it feels like magic being able to run functions in your application like some sort of realtime interactive debugger. One of the biggest issues I had with micro-services is figuring out what the hell is going wrong with them (in dev or prod) without the layers of extra work you need to add in terms of granular logging, service mesh and introspection etc.
- jeremyjh 5y agoCreating a lot of actors and messaging for the business logic of your application is considered an anti-pattern in Elixir, and a typical novice mistake. Applications in Elixir are structured using functions that are in modules that call other functions in other modules. Yes you can use OTP applications to isolate dependencies but none of this is done with the intent to more easily break up your app into a bunch of micro-services.
- ianbutler 5y agoRight but that's not really what they're saying, they're talking about Umbrella Apps, https://elixirschool.com/en/lessons/advanced/umbrella_projects https://elixirschool.com/en/lessons/advanced/umbrella_projec... Which is a distinct feature made for breaking up the logic of your applications into smaller, domain bounded libraries. Umbrella apps are for the most part like regular libraries, just internal to the project which let's you do neat things like share config and deployment across them. They don't require interacting with OTP functionality unless you make them that way and I think the OP was crossing some wires there.
- 5y ago
- dlisboa 5y agoHave you seen this done well more than a few times? Honest question because it’s something I think everyone agrees with as being a good idea but it never gets actually done. It’s definitely not an industry practice that big monoliths eventually get split up in modules and quality increases. It’s something you have to fight for and actively pursue. I’ve been on projects with very good developers, who were very bought into the idea of separating modules in the monolith, yet for one reason or another it never got done to an extent where you could see the quality improving. This leads me to believe this technique just isn’t practical for most teams, for reasons that are more psychological than technical. It’s just something about how people approach a single codebase that leads to that, it’s harder to think about contracts and communication when everything is in the same language. But if you force them to communicate over the wire to something in a different stack then all of a sudden the contracts become clear and boundaries well defined.
- KronisLV 5y agoIn my experience, i've seen the modular code approach more often than separate deployment approach, quite possibly because the latter is still a bit harder to do when compared to just having 1 instance (or people are just lazy and don't want to take the risk of breaking things that were working previously for future gains), but sooner or later the question of scalability does come up, at least in successful projects. Let me tell you, as someone who has delivered a critical code fix for business continuity after midnight a few times, slapping N instances of an app runtime in a data center somewhere is way easier than having to struggle with optimizations and introduce more complexity in the form of caches, or write out Hibernate queries as really long and hard to debug SQL because people previously didn't care enough about performance testing or simply didn't have a feasible way to simulate the loads that the system could run into, all while knowing that if your monolith also contains scheduled processes, none of your optimizations will even matter, because those badly optimized processes will eat up all of the resources and crash the app anyways. In short, the architecture that you choose will also help you mitigate certain risks. Which ones you should pay attention to, however, depends on the specifics of your system and any compliance requirements etc. Personally, as a developer, fault tolerance is up there among the things that impact the quality of my life the most, and it's pretty hard to do it well in a monolith. In my eyes the problem with contracts is also worthy of discussion, though my view is a bit different - there will always be people who will mess things up, regardless of whether you expect them to use modules someone else wrote and contribute to a codebase while following some set of standards or expectations, or whether you expect them to use some web API in a sane manner. I've seen systems that refuse to acknowledge that they've been given a 404 for a request numerous times (in a business process where the data cannot reappear) and just keep making the same request ad infinitum, whenever the scheduled process on their side needs to run. So, having a web API contract can make managing responsibility etc. easier, however if no one has their eye on the overall architecture and how things are supposed to fit together (and if you don't have instrumentation in place to actually tell you whether things do fit together in the way you expect), then you're in for a world of hurt. To that end, when people need to work with distributed systems of any sort, i urge them to consider introducing APM tools as well, such as Apache Skywalking: https://skywalking.apache.org/ https://skywalking.apache.org/ (sub-par interface, but simple to set up, supports a decent variety of technologies and can be self hosted on prem) Or, you know, at least have log shipping in place, like Graylog: https://www.graylog.org/ https://www.graylog.org/ (simpler to setup than Elastic Stack, pretty okay as far as the functionality goes, also can be self hosted on prem)
- Jenk 5y agoIME it's the drive for microservices that encourage the modular monolith. That is to say, the monolith is typically loosely modular (but still with many rule-breakages) until the push for microservices starts _then_ the big refactor to modularity begins.
- MrBuddyCasino 5y ago> hexagonal architecture Tried it twice, never pulled its weight. It introduces abstraction layers everywhere, as a premature optimisation, even though they might never be needed, and its a bad fit for more verbose and statically typed languages due to all the ceremony thats required. Anyone made similar experiences?
- Ialdaboth 5y agoI've mixed feelings about it. As advertised it can be somewhat useful for business rules-rich apps, yes, but most of the times the application side of the project will just grow exponentially faster than your core - especially if you don't keep an eye on commits, as some of your coworkers may choose the easy way out and push business logic on the application side instead of refactoring... It's a clean architecture from a business logic standpoint, indeed, but it doesn't do a lot to keep the outside of the hexagone well organized (beside the port/adapter pattern), and that side of the app can grow into a mess really fast if your team lack experience. Not as many abstraction layers than in a classic J2EE app, though. It's not that bad.
- mbrodersen 5y agoI use it all the time. It is my default architecture choice. It works great in my opinion. I wonder why you think there is a lot of ceremony needed? The core idea doesn’t require much. The Hexagonal Architecture idea can be implemented in many ways. I recommend Googling “Elm Architecture” to see an example. It isn’t described as being a Hexagonal Architecture but I will argue that it is one of the best ways to implement it I have seen. It has zero ceremony (a few functions define the whole architecture).
- Philip-J-Fry 5y agoSplitting code into modules has the same downsides as splitting it into microservices. You can still end up making the wrong splits and needing to back track on things you once thought were modular but no longer are. The logistics of microservices are rarely the hard part. It's the long term maintenance. Everyone who's ever maintained a "core" library knows the same pain, at some point you just end up making sacrifices just to get things to work.
- discreteevent 5y ago> Splitting code into modules has the same downsides as splitting it into microservices. Not to be pedantic, but it has some of the same downsides. Microservices have other major downsides in that they bring in all the fallacies of network computing. Even if you manage to stabilize these in the end they just waste so much time in development and debugging.
- matwood 5y agoI've argued for a long time that microservices should grow out of a monolith like an amoeba. The monolith grows until there is a clear section that can be carved off. Often the first section is security/auth, but from there it's going to be application specific. A modulith could be just another step in the carve up process. But, there is no right answer here. Application domain, team size, team experience, etc... all matter and mean a solution for one team may not work for another and vice versa.
- SergeAx 5y ago> from there it's going to be application specific It is actually sensible to keep all the business logic layer(s) in the monolith while it is possible. Easier to grasp the domain for new team members, easier to bound context.
- farias0 5y agoIn my experience with enterprise software one of the things that cause most trouble is premature modularization (sibling to the famous premature optimization). Just like I can't understand how people can come up with the right tests before the code in TDD, I can't understand how people can come up with the right microservices before they start developing the solution.
- hu3 5y ago> premature modularization I'm stealing that. I have seen soo many small projects crumble due to sheer unnecessary complexity introduced by modularization dogmas.
- jackcviers3 5y agoOn the TDD argument, you should know what a return for a function f should be when given an argument b. Ideally, you have a set of arguments B to which b belongs, and a set of results C to which the return belongs. Your tests codifies mapping examples from B to C so that you can discover an f that produces the mapping. Take another step and generate random valid inputs and you can have property-based testing. Add a sufficient type system, and a lot of your properties can be covered by the type system itself, and input generators can be derived from the types automatically. So your tests can be very strong evidence, but not proof, that your function under test works as expected. There's always a risk that you modeled the input or output incorrectly, especially if you are not the intended user of the function. But that's why you need user validation prior to final deployment to production. Likewise, with a microservice architecture, you have requirements that define a set of data C that must be available for an application that provides get/post/put/delete/events in a set B to your service over a transport protocol. You need to provide access to this data via the same transport protocol, transform the input protocol to a specified output protocol. You also have operational concerns, like logging that takes messages in a set C and stores them. And monitoring, and authorization, etc. These are present in every request/response cycle. So, you now split the application into request/response services across the routing boundary-> 1 route = 1 backing model. That service can call other apis as needed. And that's it. It's not hard. It's not even module-level split depolyment. It's function-level deployment in most serverless architectures that is recommended because it offers the most isolation, while combining services makes deployment easier, that's mostly a case of splitting deployment across several deployment templates that are all alike and can be managed as sets by deployment technologies like Cloudformation and Terraform [1]. You can also think of boundaries like this: services in any SOA are just like software modules in any program - they should obey open/closed and have strong cohesion [2] to belong in a singular deployment service. Then you measure and monitor. If two services always scale together, and mutually call each other, it's likely that they are actually one module and you won't effect cohesion by deploying them as a single service to replace the two existing ones. easing ops overhead. Not deploying and running as a monolith doesn't mean not putting the code to be run into the same scm/multiproject build as a monorepo for easy shared cross-service message schema refactoring, dependency management, and version ingredient. That comes with its own set of problems -- service projects within the repo that do not change or use new portions of the comm message message schema shouldn't redeploy with new shared artifact dependencies; basically everything should still deploy incrementally and independently, scaling it is hard (see Alphabet/Google's or Twitter's monorepo management practices, for example); but there seems to be an extra scale rank beyond Enterprise size that applies to, it's very unlikely you are in that category, and if you are you'll know it immediately. We like to market microservice architecture as an engineering concern. But it's really about ops costs in the end. Lambdas for services that aren't constantly active tend to cost less than containers/vps/compute instances. 1: http://serverless.com//blog/serverless-architecture-code-patterns http://serverless.com//blog/serverless-architecture-code-pat... 2: http://www.cs.sjsu.edu/faculty/pearce/modules/lectures/ood/metrics/lcom.htm http://www.cs.sjsu.edu/faculty/pearce/modules/lectures/ood/m...
- rp1 5y agoThere is a more serious downside that you don’t mention: splitting things into modules takes time and involves making decisions you likely don’t know the answer to. When starting a new product, the most important thing is to get something up and running as quickly as possible so that people can try it and give you feedback. Based on the feedback you receive, you may realize that you need to build something quite different than what you have. I’ve seen plenty of successful products with shoddy engineering, and I’ve seen plenty of well engineered products fail. Success of a product is not correlated with how well it’s engineered. Speed is often the most important factor.
- KronisLV 5y ago> There is a more serious downside that you don’t mention: splitting things into modules takes time and involves making decisions you likely don’t know the answer to. Partially agreed. Domain driven design can help with answering some of those questions, as can drilling down into what the actual requirements are, otherwise you're perhaps reaching for your code editor before even having an idea of what you're supposed to build. As for the inevitable changing requirements, most of the refactoring tools nowadays are also pretty reasonable, so adding an interface, or getting rid of an interface, creating a new package, or even in-lining a bunch of code isn't too hard. You just need to know how to use your tools and set aside time for managing technical debt, which, if not done, will cause more problems down the road in other ways. > Speed is often the most important factor. If you're an entrepreneur or even just a business person who cares just about shipping the feature, sure. If you're an engineer who expects their system to work correctly and do so for the years to come, and, more importantly, remain easy to modify, scale and reason about, then no, speed is not the most important factor. Some business frameworks like COBIT talk about the alignment between the tech and business, but in my experience their priorities will often be at odds. Thus, both sides will need to give up bits of what they're after and compromise. If you lean too heavily into the pace of development direction, you'll write unmaintainable garbage which may or may not be your problem if you dip and go work for another company, but it will definitely be someone else's problem. Thus, i think that software engineering could use a bit more of actual engineering it. Not necessarily 50 page requirement docs that don't conform to reality and that no one cares about or reads, but actually occasionally slowing down and thinking about the codebases that they're working on. Right now, i've been working on one of the codebases in a project on and off for about 4 years - it's not even a system component, but rather just some business software that's important to the clients. In my personal experience, focusing just on speed wouldn't have been sustainable past 1 year, since the codebase is now already hundreds of thousands of lines long. For a contrast, consider how your OS would work if it were developed just while focusing on the speed of development.
- cbetti 5y agoPatterns and automation supporting modularization hasn't received the attention that patterns and automation around services has over the past 10 years. In practice, modularization raises uncomfortable questions about ownership which means many critical modules become somewhat abandoned and easily turn into Frankensteins. Can you really change the spec of that module without impacting the unknown use cases it supports? Tooling is not in a position to help you answer that question without high discipline across the team, and we all know what happens if we raise the question on Slack: crickets. Because services offer clear ownership boundaries and effective tooling across SDLC, even though the overheads of maintenance are higher versus modules, the questions are easier and teams can move forward with their work with fewer stakeholders involved.
- muxator 5y agoIf a dev team cannot self-discipline itself in maintaining a module, is it wise to entrust it with the responsibility of a whole service? I'd rather work on better mentoring the single members.
- watwut 5y agoModules have higher requirements for self discipline the services. Precisely because the boundaries are so much easier to cross. And also because it is harder to guard module from changes made by other teams. Both technically and politically, the service is more likely to be done by a single team who understands it. Module is more likely to be modified by many people from multiple teams who are just guessing what it does.
- dathinab 5y agoI think anyone who speaks about monolith today assumes you do use modules appropriately. I mean for "starting with a monolith and splitting out when necessary" you kind need property structures code (i.e code which uses modules and isn't too tightly coupler between them). Through in my experience you should avoid modularizing code with the thought of maybe splitting it into parts later on. That's kinda defeats the point of starting with a monolith to some degree. Instead modularize it with the thought of making it easy to refactor and use domain logic as main criterium for deciding what goes where when possible ( instead of technical details).
- amw-zero 5y agoI agree with your position, I'm a big fan of the modular monolith approach. I took a look at your post. This is one thing that jumped out to me: > Because the people who design programming languages have decided that implementing logic to deal with distributed systems at the language construct level... isn't worth it I'm not sure if this is just a dead end or something really interesting. The only language I really know that [does this is Erlang](https://www.erlang.org/doc/reference_manual/distributed.html https://www.erlang.org/doc/reference_manual/distributed.html), though it's done at the VM / library level and not technically at the language level (meaning no special syntax for it). What goes into a language is tricky, because languages tend to hide many operational characteristics. Threads are a good example of that, not many languages have a ton of syntax related to threads. Often it's just a library. Or, even if there is syntax, it's only related to a subset of threading functionality (i.e. Java's `synchronized`). So there might not be much devotion of language to architectural concerns because that is changing so much over time. No one was talking about microservices in the 90s. Plus, the ideal case is a compiler that's smart enough to abstract that stuff from you.
- lostcolony 5y agoRecent languages do have syntax related to -concurrency- though. Languages pre multi-core probably provided a VM/library, as you say, for threading, and then said "generally you should minimize threads/concurrency" (which for mainstream languages were the same thing). Languages since then have embraced concurrency at the syntax level, even if not embracing threading. Node has event listeners and callbacks (and added async/await as a syntactical nicety), go has goroutines (with special syntax to indicate it), etc. It's interesting that while languages have sought to find ways to better express concurrency since it became necessary to really use the chips found in the underlying hardware, they largely haven't sought to provide ways to better express distribution, leaving that largely to the user (and which has necessitated the creation of abstracted orchestration layers like K8s). Erlang's fairly unique in having distribution being something that can be treated transparently at the language level. Mind you, that also has to do with its actor based concurrency mechanism; the reason sending a message to a remote process can be treated the same as sending a message to a local process is because the guarantees are the same (i.e., "you may or may not get a response back; if you expect one you should probably still have a timeout"). Other languages that started with stronger local guarantees can't add transparent remote calls, because those remote calls would have additional failure cases you'd need to account for (i.e., Java RMI is supposed to feel like calling a function, but it feels completely different than calling a local function. Golang channels are synchronous and blocking rather than asynchronous and non-blocking, etc. In each case you have a bunch of new failure conditions to think about and address; in Erlang you design with those in mind from the beginning)
- aquent 5y agoI agree. Started with a simple React for frontend and NestJS for backend. Now I am running microservices for distributing third-party widgets, my search engine, and the analytics. Works well and it actually simplifies things a lot, each service has its repository, pipeline and permissions, developers don't need to understand the whole application to code. You also don't have to start with Kubernetes to make microservices work, many tools can act as in-betweens. I am using app engine from gcloud, yes it's a lot of abstraction over kubernetes and it is overpriced, but I don't care. It works perfectly for these use cases and even if overpriced, it stays a low absolute value. The caveat is that you really need to start off with a "stateless mindset".
- AtNightWeCode 5y agoMost monoliths are modular based like any other large solutions. At least in the languages I work with. One code base is something I totally agree with. I would like this to include every dependency, at least the OSS once.
- ozim 5y agoBecause there is no newly invented architecture called "modular monolith" - monolith was always supposed to be MODULAR from the start. Micro services were not an answer to monolith being bad. Something somewhere went really wrong with people's understanding and there is bunch of totally wrong ideas. That is also maybe because a lot of people did not knew they were supposed to make modules in their code and loads of monoliths ended up being spaghetti code just like now lots of micro service architectures end up with everything depending on everything.
- addsidewalk 5y agoWhat’s a mono repo of micro services called? We sure spent a lot of time debating semantics for a supposedly economical culture. I tend to focus on stability, correctness, security as those have concrete human meaning. All the rest is jargon largely unhelpful to solving problems. Often helpful selling books, finding “consultant” work, and booking speaking fees though.
- ravenstine 5y ago> monolith was always supposed to be MODULAR from the start Well, that certainly is sensible, but I wasn't aware that someone had to invent the monolith and define how far it should go. Alas, my impression is that the term "monolith" doesn't really refer to a pattern or format someone is deliberately aiming for in most cases, but instead refers to one big execution of a lot of code that is doing far more than it should have the responsibility to handle or is reasonable for one repository to manage. I wish these sorts of battles would just go away, though, because it's not like micro services are actually bad, or even monoliths depending on the situation. They're just different sides of the same coin. A monolith results from not a lot of care for the future of the code and how it's going to be scaled or reused, and micro services are often written because of too much premature optimization. Most things should be a "modular monolith". In fact I think most things should start out as modular monoliths inside monorepos, and then anything that needs to be split out into its own separate library or microservice can be made so later on.
- lostcolony 5y ago
- amelius 5y ago> I wonder why no one ever talks about architectures in the middle between those two - modular monoliths. I'm sure that if you look at the source code of existing monoliths, you will find heavy use of modules.
- why-el 5y agoI call these macro-services. They work nicely, but only if you want long enough, in my experience.
- PaulHoule 5y agoWhat I think nobody talks about is: (1) the legitimate reason for breaking up services into multiple address spaces, and (2) that using different versions of the runtime, different build systems, and different tools for logging, ORM, etc. in different microservices is slavery, not freedom. (1) is that some parts of a system have radically different performance requirements than other parts of the system. For instance 98% of a web backend might be perfectly fine written in Ruby or PHP but 2% of it really wants everything in RAM with packed data structures and is better off done in Java, Go or Rust. (2) The run of the mill engineering manager seems to get absolutely ecstatic when they find microservices means they can run JDK 7 in one VM, run JDK 8 in another VM, run JDK 13 in another VM. Even more so when they realize they are 'free' to use a different build system in different areas of the code, when they are 'free' to use Log4J in one place, use Slf4J someplace etc, use Guava 13 here, Guava 17 there, etc. The rank and file person who has to actually do the work is going to be driven batty by all the important-but-not-fashionable things being different each and every time they do some 'simple' task such as compiling the software and deploying it. If you standardize all of the little things across a set of microservices you probably get better development velocity than with a monolith because developers can build (e.g. "make", "mvn install") smaller services more quickly. If on the other hand the devs need to learn a new way to do everything for each microservice, they are going to pay back everything they gained and then some with having to figure out different practices used in different areas. (Throw docker into the mix, where you might need to wrangle 2G of files to deploy 2k worth of changes in development 100 times to fix a ticket you can really wreck your productivity, yet people really account for "where does the time go" when they are building and rebuilding their software over and over and over and over again.)
- bborud 5y agoIn my experience, long build times mostly come from not caring about build times. Not from large codebases. A surprising number of developers don't think build times (including running all the tests) are important. They'll just go "ok, so now it takes N minutes to build" rather than thinking "hold on, this shouldn't take more than a few seconds - what's going on here?"
- kgeist 5y agoWe've been following this modular monolith approach as well (for 3 years now), bounded contexts and all, but our architectural end goal is still "mostly microservices". Maybe it's specific to PHP and the frameworks we use (what the modulith is written in) but the startup time of the monolith is just unacceptable for our processing rates (for every request the framework has to be reinitialized again, with all the 9000 services via DI and what not). Microservices tend to be much more lightweight (you don't even need DI frameworks), and monolith also encourages synchronous calls (calling a bounded context's API in memory is so simple) which has been detrimental to our performance and stability, because microservices, at least in our architecture, encourage event-based communication which is more scalable, and allows clean retries on failure etc. But again, your mileage may vary, maybe it's specific to our tools.
- CRConrad 5y ago> modulith Bravo!
- SquishyPanda23 5y agoIt's usually not obvious where to put the seams ahead of time so you can cut them when you need to split into microservices. Plus keeping the API boundaries clean costs time and resources, and it's tempting to violate them just to launch this one feature. This extra discipline doesn't have any payoff in the short term, and it has unknown payoff in the long term because you're not sure you drew the boundaries ahead of time anyway. So I think in practice what happens is you create a monolith and just eat the cost of untangling it when the team gets too big or whatever.
- mattgreenrocks 5y agoTo be fair, modular monoliths weren't talked about much before microservices. I'm thinking about the heyday of Rails, where there were bitter debates over whether you should even move critical business logic out of Rails. I got the impression that most devs didn't even care. (That was sort of the point where I saw that I was a bit of an odd duck as far as developers go if I cared about this stuff, and pivoted my career.) I really enjoy contexts where I can make modular monoliths, however. I'm thinking of mobile/desktop apps here, mostly. Software design is something of a lost art currently. This is partially due to the current zeitgeist believing that anything that automated tools cannot create/enforce can't be that important in the first place. Of course, there's a whole swath of concerns that cannot be addressed with static or dynamic analysis, or even different languages. Microservices is a response to the fact that a monolith without any real design moves quickly but can easily converge on spaghetti due to the fact that everything is within reach. It enables teams to create an island of code that talks to other islands only via narrowly defined channels. Additionally, they support larger dev teams naturally due to their isolationist take, and reinforce the belief that "more developers = always better" in the process. In other words, they mesh perfectly with the business context that a lot of software is being built in. Factor in the fact that $COOL_COMPANY uses them, and you have a winner.
- deleted 5y ago[deleted]
- bcrosby95 5y agoModular design is decades old though. Rails devs argue about it because it's against the rails way, and that makes things harder for them. But I've been modularizing my Java webapps since I graduated from college, 18 years ago. But also, microservices weren't pioneered by rails devs. They were pioneered by huge companies, and they definitely have a role to play there, as you point out.
- Aachen 5y ago> I wonder why no one ever talks about architectures in the middle between those two Because that's the default. It doesn't make intuitive sense to integrate every separate service you develop internally into one huge bulky thing, nor to split up every little feature into even more small services that need a ton of management mechanisms and glue to even be functional. Only after advocates for both extremes sprung up does it make sense to invent, as you did, a new word for the thing in the middle. It's just the sensible thing to do in most situations.
- rwoerz 5y agoI even wonder why the word "monolith" got such a bad connotation that it is now used synonymously to "big ball of mud". I mean, monoliths in the original sense (Washington Monument, that 2001 - A Space Odyssee moon thing, ...) are all but messy.
- skeeter2020 5y agoMaybe because breaking up a monolith has proved to be as hard as combining microservices, once you get past the obvious and trivial steps.
- lowbloodsugar 5y agoAgree. But start with modules immediately. SOLID applies to modules as well as classes. [And if we're talking about Rust, then substitute "crate" wherever I write "module"]. Basically be constantly refactoring your code into classes (or equiv.) and the classes into modules. It's super easy to join multiple modules into a single application: the linker, JVM, whatever does it automatically. It's insanely hard to break a monolithic application into modules.
- SergeAx 5y agoBecause alternative to modular (and layered) monolith is spaghetti code, and no one wants to do it ever.
- strzibny 5y agoI think most people do modularize monoliths. There are Phoenix contexts and Rails engines that provide a good starting point, for example. After working with Phoenix I am actually thinking of bringing the idea of contexts to Rails applications (to some extend): https://nts.strzibny.name/business-logic-in-rails-with-contexts/ https://nts.strzibny.name/business-logic-in-rails-with-conte...
- deleted 5y ago[deleted]
- phlakaton 5y agoThe problem with modular monoliths is the relative difficulty of managing dependencies in the code. It’s easy to hack the modular interfaces or expose internals, which can make it hard to maintain and painful to pull out into another service down the road. “But I would never hack an interface like that!” you say. Oh, you sweet summer child.
- kashif 5y agoMy thoughts on this from a while back - https://kashifrazzaqui.medium.com/will-the-real-micro-service-please-stand-up-16bef3ed72ec https://kashifrazzaqui.medium.com/will-the-real-micro-servic...