I always find it amusing how good microservices design looks almost identical to individual small monoliths, and how the microservices of today are often larger than monoliths of 10 years ago in terms of code size and resources needed.
Most people doing microservices today have a distributed monolith. Large states moving from service to service with versioning as a huge problem, prone to cascading failures, vague boundaries, vague understanding of which service should handle a cascading failure. Moreover like you mentioned, you really cannot spin up an instance independently which was the whole point of building a standalone service. Lastly testing is a nightmare.
Thank you for this video! I think this is the first time I've seen someone explicitly show an example between the logical view and the physical view where the database logically is "split", but physically is the SAME database, with the logical split happening at the schema level. Lots of people miss this when developing microservices. Almost every SOA/microservice system I've seen in the last 15 years (except for one) all have the same development view, logical view and physical view. Separate visual studio solution per microservice and separate database. It does NOT have to be like this. A lot of people this same physical vs. logical view mistake when using CQRS. A separate write store and read store does not mean you have to use two separate databases. You can achieve logical separation using schema, relational db views, and other patterns like state changes only happen view commands, and reads only happen via a db's LINQ provider or a repository layer.
You're hitting the nail on the head with this one. Mixing up logical boundaries with physical boundaries is one of the most common and expensive mistakes I see happening. To make matters worse, lots of companies also base their entire team structure on this wrong split making it very hard to recover from this mistake
Man, always when I watch one of your videos and then see a list of your other videos I am like "Yeah, that's the exact set of next questions that I have". Great content for serious backend devs ;)
Having every tiny little feature live in its own repo also makes it nearly impossible to statically reason about how business processes actually function and to think about what existing systems can be used to implement new processes.
"Microservices are not an architecture, they are a deployment strategy." - Uncle Bob. A lot of what is considered architecture today is actually implementation patterns and infrastructure creeping into architecture. Architecture is not the tools and materials used to build something.
Often developers choose to bulld microservices for one characteristic specifically. Then they disregard the rest. Not actually understanding boundaries.
Another example of that is code itself. It may be tempting to split code for different microservices into physically different repos, but then you create hurdles for sharing code between them.
Hi Derek, I am a complete beginner/new commer to DDD and your channel is a gold mine =) So thank you for putting all that effort in sharing your knowledge. One technical concept that i can't wrap my head around regarding to separating domains is regarding entities that are cross domains by nature, like Users for example. A user is referenced in every single domaine, and every domain needs to access user informations (like username and whatnot). Let me give a concrete example: 1/ Let us say that we have an ordering, sales, purchases and inventory domains, each with its own transactions. We want to be able to display the username of the user that performed the transaction when displaying the lists of transactions. 2/ We also want to be able to have some audit data recorded per entity, ie the user that created and last updated the entity, and when displaying the list of the said entity, we also whant to display the username of the related user for the entire list. I know i asked a lot already but i will be forever grateful if you could give a small example user EF =) Thank you in advance.
As an example, I usually have a 'user' that tied to every command/query/event. Every request from the outside API (eg http API) gets generally translated to a message that also contains some identification of the user the initiated it. It's not the entire "user" just some identification of them and possibly roles/permissions etc. (Think identify/claims)
@@CodeOpinion So, each domain defines its 'user' within its database ? or are we "allowed" from a DDD perspective to let all domains cross boundary with the one and only domain that owns the user (a sort of controlled coupling) ?
@@CodeOpinion Ok, if i am getting you right, There will bo no foreign key constraint between, let's say the Order table and a "User" table in the Sales DB, the Order will only hold a simple flat ID and the username. When deleting the user or altering it, Domain Events will allow to keep everything in sync. Is that right ? Thank you.
It's true logical and physical boundaries are not the same, but it's not as if separating different services onto different physical structures is a thoughtless choice. If you have two services sharing the same physical database, if that database goes down, both services go down. Any sharing of physical resources increases coupling between services.
My guess is smaller teams creating bigger systems would be better served in making this distinction to reduce physical/deployment complexity where it's just not needed.
Sorry but i don;t get it.A phisycal boundry is a application web or worked, which is a deployment unit (has behind it a container/process and an repo) whereas a logical boundry is a subsystem,could be made of some physical apps.Is this correct?Thank you!
on 07:50, I'm a bit confused. What do you mean by having a local data cache on other boundary could mean wrong logical boundary? What if the local cache is needed to display the data? Or here's a scenario. Let's say, I have a service that sending message to other user. Now, part of the process of sending the message, I would need to perform validation whether the user exists or not. My Question is, what should be done here? Should this message service perform RPC calls to identity service to validate the existence of the user, or should the message service holds the local cache of the list of available users mirroring the identity service?
It depends why you want or need the data as a local cache. If it's for display purposes (eg, product name), sure, but if it's for data that's required for business logic, that's when I'd start digging into why that data is owned in another boundary.
Great video, I have question on 2 logical boundary on one database. By allowing one logical boundary access the data of another through the database would this introduce coupling as the first logical boundary would need to what data to query for, for example Or have I misunderstood?
No, you wouldn't be allowing a logical boundary to access the data of another logical boundary. What I was intending to describe is that the schema/data can live on the same physical database instance.
@@CodeOpinion you literally said that the benefit would be that the collocated service could just access the data it would otherwise have had to retrieve from the other service via rpc (your first of several straw men).
Clearly, I didn't articulate that well. What I was attempting to say is if you needed data in another logical boundary for business logic purpose, it's likely that you have boundaries wrong, and that feature is in the wrong logical boundary. Even if it was in a different physical boundary, it could reach out to the db directly, if it's in the correct logical boundary.
I think I perfectly agree with the spirit of this video especially for traditional infrastructures. I still have some doubts about cloud scaling options. Maybe this is not really related to video, this can be considered off topic, but I try to ask. The point is that - from the perspective of concurrency in a 12 factors app as well as in an event driven architecture like keda on k8s - you end up scaling pods based on some queue mechanism. I consider that a physical boundary because it triggers the number of physical nodes in a cluster. But in modern languages (f#, golang, even c# and scala somehow) you have an async task model that is different from, say, old classical java spring boot jms (which in turn works well with some activemq or rabbitmq, hence with keda). That modern async model is really a logical boundary: indeed tasks or goroutines are not in 1:1 correspondence with low level os processes (how can they be correctly intercepted by kubernetes scaling metrics? I don't think they easily can). In conclusion I'm afraid that it's very difficult for an app that is not designed as the expected microservices cloud native app to scale well on the kubernetes cluster. The cause of logical boundaries becoming also physical boundaries could be the "dockerization pattern", this cloud native approach to the cloud infrastructure where we no longer have single virtual machines, but only containerized, ephemeral, immutable pod processes, for which the physical and logical boundaries intrinsically fade into one another
Yes, the "dockerization" I think contributed to it. But I was also pointed out from Udi Dahan on Twitter, that his goes back farther to the "Web Services" days of SOAP. Which I agree with as well when I think back to it (yes, I'm old).
@@CodeOpinion I'm afraid I'm also old... because I remember those years. But if I open a book I bought at that prehistoric time - rational unified process - it reads like the architectural model has more views (4+1) among which there is the *logical* view that is distinct from the *implementation* view and from the *deploy* view... Somehow similar to the concepts you've expressed here... Correct? I was trying to say that instead docker and kubernetes (to some extent) tightened/overlapped together those old different views in the "cloudy" concept of pod/container/deployment. Also the concept itself of devop can be imagined as a fusion of dev (=logical view?) and ops (=physical view? =the old deploy and implementation views of the years of rational unified process?). But I surrender here and I stop. Because I absolutely don't want to confirm that we are old and/or we are saying old things!))
Hi Derek, Is event-driven architecture t a way that medicare or services communicate with each other in an async way? And then, event sourcing, event notification, cqrs, event carried state transfer are just a patterns in event driven arch that we can implement. Please reply back!
The tutorial is useful. I have a scenario that i want to build a API to get the list of all orders of the current user. Each order will include the following info: -Product name, product category: collected from product service -Shipping info from shipping service -Payment info from payment service ... If i understand you correctly composing the related info should be handled at UI or some kind of API composer service? There's also an use case where we need to validate stock availability from inventory service to make sure there's any order is created and failed after that due to stock unavailability issue. Could you share idea how to solve that kind of problem?
Stock availability in a warehouse doesn't really work like that but if you are just using an example of requiring a guarantee on the qty, check out this video on the reservation pattern: ru-vid.com/video/%D0%B2%D0%B8%D0%B4%D0%B5%D0%BE-PZm0RQGcs38.html
Nice presentation on the differences but the question I have is what should I do when my logical boundary is required by multiple physical boundaries? Can I then say my logical boundary = physical boundary to determine the capacity to serve multiple physical systems?
When this design is met.I mean on bounded context doesn't map to a single app,but to many apps services which may be sharing the same database or multiple databases?
Bounded context owns it's data and schema. Don't share it directly, provide ways for other boundaries to retrieve that data if required (for good reasons) via a defined API or messages.
Noob question .. can two logical boundaries share a db ? Say if communication across autonomous components is via ids and detailed information about the ids is in a db, can the db be shared ?
@@CodeOpinion thanks for response. So each autonomous component could share a physical db instance but will have their own schema ? If so, just hypothesising could it lead to data redundancy ? Or is it like more contextual ? And In such scenarios we may pass more than an id ?
I'll be putting something out sooner or later. I wouldn't call it about "microservices" rather having a well defined logical boundaries and loose coupling between them.
Great video once again, thank you. The use of schemas as an isolation strategy over a shared database doesn't seem to be that popular, at least from my minimal research into the topic in the .NET ecosystem. Is that an accurate assessment?
Entire video is an attempt to rationalise tight coupling of the implementation of logical entities. Fail. Solution complexity should only be reduced to get it as close to problem space complexity as possible and no further. You’re basically adhering to the KISS principle here: Keep It Stupidly Simple. Additionally your introduction of rpc as the only alternative to event-based as a means of state change is the first appendage in the strawman you built to justify your desire for micro-tight-coupling to save you from the reality of the complexity required to solve the problem space of loose coupling and independently evolvable solutions. Calling into question the very fabric of event-based state management is an even more laughable part of your wickerman. Presented as simply an annoying complication to this implementation mechanism it would in fact render the who concept a non-starter. If I could pinpoint your root problem it would be that you present a set of issues that could simply be removed from the equation without requiring the tight physical coupling solution as a reason to do so. It is painful to watch you guys try to recreate the lessons we learned in the mid-2000’s due to tool vender and consultancy disinformation campaigns of the 20teens and go in the wrong directions (ie running back toward bad decisions we were moving away from before hand). This is why the IT industry is so cyclical: every time we make progress towards simplicity that actually solves problems across the breadth of the value-stream it cuts tool vendors and cookie-cutter consultants out of the reward chain and they respond with a campaign to embrace and redirect the effort into a corrupted form they can profit from and then sit back and watch reactionary developers run back towards the old ways thinking they are running to awards new ones with new understandings of “how they are ok if we do it this way or that” (new jargon to justify old bad ideas). Once you live long enough to see the cycles it becomes extremely disheartening to watch.
I'm at a loss for a response. I'll take the blame and say that I clearly did not explain my intention very well. I say this because you wrote "the first appendage in the strawman you built to justify your desire for micro-tight-coupling". The entire video is exactly about not tightly coupling between logical boundaries by forcing them to be physical boundaries as well. Anyways, thanks for the comment.
@@CodeOpinion but you ARE tightly coupling! Just in the physical space rather than the logical. That may solve the problem you see in one space but it causes a whole bunch of others across the entire value stream. A) I hope you are not trying to achieve DEcoupling rather than loose coupling. B) you can’t solve coupling in one space by moving it to another. That’s just playing the shell game and moving issues around solves nothing.
@@thescourgeofathousan I have no idea how this video is inferring that I'm talking about tight coupling. My intent in this video is to call out that logical boundaries aren't physical boundaries. They can be the same but they don't have to be. I'm not advocating anything more than explaining they aren't the same thing. That's it. My intent (as in most of my videos) is to define logical boundaries that that defined by functional cohesion (business capabilities) with data ownership. These logical boundaries are loosely coupled and interact by messaging to remove temporal coupling. How you define that on a physical aspect and deployment is another thing entirely. I appreciate the comment but I think we're on two different worlds.
@@thescourgeofathousan I never said couple. UI composition is a good example of that. Components from logical boundaries can be composed in the same UI. That's a deployment and composition concern. If you disagree, so be it, I'm clearly not going to change your mind :)