17

I'm making an application using DDD principles. After thinking everything through as much as I can I'm down to start making my Bounded Contexts. I haven't set the final structure yet, but as of now my application will consist of the following bounded contexts:

  1. Employee managment
  2. Purchasing
  3. Archive
  4. Reporting

I want this to be as pluggable as possible, so I can for example develop and maintain them seperately. Probably they will expose either WCF or Web API to interact with them.

I will use Udi Dahans implementation of a simple CQRS pattern. I'd prefer not to go all the way with event sourcing, message busses and so on because this wil not be a highly collaborative app (less than 1000 users, and they are not likely to edit the same small dataset), and this would add a lot of unneeded complexity.

So to the questions:

The employee and department entities are common for all BC, how to model that?

Department is a part of the organizational structure, so in the employee managment BC the employees work in a department, they can manage an department and they have a history of departments they've worked on.

In the purchasing BC goods are purchased from a department, and delivered to a department. Suplliers have different contracts with different departments.

In archive some information will be archived and tied to a department, and so on.

The same pretty much applies to Employees.

How to persist the data from the bounded contexts?

They can be mapped to the same database or each have their own.

Some thoughts I've made so far

How to model
Should I make one more BC called "Company" or "Organization" and manage departments there?

Acoording to Udi Dahans article referenced above, I should make a department entity and a employee entity for each BC with just the fields and behavior I need for that BC. This sounds reasonable but then I'm thinking of how to actually use this and I can't figure that out. I need to access the departments managed somwhere else, but how exactly do i do this and not mix my BC's?

How to use?
Let's say that I get my list of departments from somwhere by querying. In the UI i get a list of departments that I want to make a purchase too. This is the first purchase for this department so the Purchasing BC does not know about this department yet... So the Department Object in Purchasing BC will be filled with data maintained from anoher BC - so how do I persist this? I would need to add some information like delivery address, and invoice address if that doesn't exist?

In the "register department UI" should I then call "RegisterDepartment" service on all BC and then make shure that these are in sync with all changes made through the UI (MVC controller)?

The same with employees. I want to know which employee made a purchase or put something in the archive. So somehow I would need an employee-object in these BC's too but manage them from a different BC.

Persisting
Some of the challanges above could be solved by mapping the different employee-objects to the same table in a database. Purchasing BC and Archive BC cannot register new employees, but append information to those who are there and tie them to other objects in the same database. Then the database would make shure that all the BC's still live in the same world...

I need advice so I don't end up making something that will be very hard to maintain later on.

Jon
  • 15,110
  • 28
  • 92
  • 132
cfs
  • 1,304
  • 12
  • 30
  • the link to Udi Dahan text should be (http://udidahan.com/2011/10/02/why-you-should-be-using-cqrs-almost-everywhere/) – Thang Hoang Dec 25 '15 at 09:10

2 Answers2

13

It seems that most of your doubts circle around: "How are single real-life objects shared by different Bounded Contexts?"

The thing is, though the entities are the same, they are treated differently by every BC. In Employee Management BC, the whole weight is centred on Employee and Department entities - you should be able to add them, modify, assign to each other, keep history and take care of all business logic regarding management. You could implement some policies of keeping employees personal data, maintaining proper official structure or maintaining certain responsibilities.

On the other hand, the department entity in the Purchase context would mean only, for example, invoice address and maybe person from the department responsible, and the centre of interest would be constructing the order. All data that is not directly connected to the procedure of making the purchase should be given to a different context. If, for example, the domain requires that every order has to be connected to the department and the invoice details are missing, purchase context should not try to fill them by itself. Instead, a notification to Employee Management could be made to fill the missing parts.

Note that it may very well happen in the same application or even the same window. But you must ensure it will happen through Employee Management context, i.e by invoking context public API.

As a side note, I do not know your domain, but you may want to reconsider your context boundaries, for example by separating deliveries from purchase.

Moving on to usage and following your example, if you want to make a purchase, I would consider following path:

  • Read necessary department data (let's wait till later with "how"), you may want to check if every data are present at this point
  • Read goods that can be purchased, depending on your domain it might be worth to introduce another BC, such as Suppliers. These all above are the "Query" part of CQRS
  • Construct order or any other necessary purchase context entity, perform validation or any other logic
  • Commit changes, persist purchase context entities (the "Command" part)
  • Create and publish some domain events (for example to notify Archive or Reports)

Last but not least, you should not be concerned with global persistence in the domain layer. Every BC should be connected to some Data Access or Infrastructure layer supplying necessary objects and taking care of such details as from where to take them.

Especially, entities do not necessarily need to mirror database layout, and the question whether to store in one or multiple databases should be only a performance issue. For example, some entities will refer to the same object (for example employee Name), but can take other details from totally different tables or db (i.e. purchase history or elements sent to archive). You may use something like NHibernate to make this easily manageable.

jnm2
  • 7,960
  • 5
  • 61
  • 99
Jeremy
  • 154
  • 1
  • 3
  • Thanks for the thorough input. I agree with all you say. However I've been reading different advice as how to implement the BC and most seem to say that I should take care of persistence in each BC, but I might have misunderstood this. Regarding the events, would you expose this as normal C# events or start introducing something like a message bus (I'd hope to stay away from that though)? And would you make one persistance implementation for all BC's or one for each? I'm using EF Code First, so it should not be so different from NHibernate. – cfs Nov 23 '12 at 18:28
  • Yes, each BC should maintain persistence control of it's own entities, but it is more of infrastructure than BC problem. It would be perfectly viable, though uncommon, to use filesystem or external webApi as storage, and it should not change the way your context works. My suggestion would be to start with separate implementation for each. Consider implementing them through interfaces to no be stick to early implementations. As for events, I with success used Event Broker, example of simple implementation is [here](http://devtalk.net/dotnet/event-brokers/) – Jeremy Nov 23 '12 at 20:24
  • Great answer. I've read through the Event Broker example, and I think that will do for me. Maybe I rather sooner than later will have to learn a message bus framework like NServiceBus, Mass Transit or so, but I'll use this for a start since it is quite clean and simple. – cfs Nov 24 '12 at 13:08
5

I'm answering an old question here, but I have another example of the issue faced in the OPs question.

I have a situation where I am working on an application used within a manufacturing company. This company has departments for Sales, Operations, Production, Accounts, Tech Support. Within all of these departments there is a concept of Customer. So I had a hard time working out how I have a Customer entity in these departments (which I have mapped out as my Bound Contexts).

It was when thinking about this over and over that something clicked, and then I remembered a comment I read in a blog post from Jimmy Bogard, where he talked about a domain model he had worked on which took weeks of work to arrive at because the more they worked on the problem, the more they understood the domain and were able to arrive at an elegant design.

My moment of clarity was when I stopped thinking about persistence and stopped thinking about customers in these BCs.

What I realised was the Sales BC needs to know about Customers, but they need very specific information like who is the MD, a list of contacts, a list of offices, who the decision makers are, who is the finance contact etc.

Now, the Ops BC is responsible for raising an order in the system, and they need a concept of customer. However, they don't need to know who the MD is, or a list of contacts, and who cares about what offices that customer has? Ops just need to know the customer name, and in our case a 4 character customer code. When I think that through, I don't even need to persist this information as an Entity, it could just be a Value Object in my Ops BC. But how do I get this information into my Ops BC? Well, that's really simple. The BC defines an interface through which my application can interact with the Ops BC. My application has no idea what goes on inside that Ops BC, but it does know that there is an Order Aggregatr root, and that has a method to RaiseNewOrder which takes in an argument of type CustomerValueObject. The CustomerValueObject consists of a 4 letter code and a Customer Name. So, in my App UI I can use the Sales (let's call it Customer Management) BC to to get a list of customers to present a drop down list. Then, when I handle the transactional part of the operation, i.e. the user posting the new order information I use the Ops BC and pass in the customerVO as an argument.

So, my Ops BC and Sales BC are separate, and self contained, they have the concepts internally which they need to ensure the integrity of the domain, and I am able to access the data I need in my UI so that the operator can pick a customer to then perform an action in the Ops BC.

What I realised was a Customer to the sales team is not the same thing as a Customer to the Ops team. To the Ops guys, a customer is just something they tag an order with. They don't have any interest in the inner workings of that company, or any of the information about it. As long as I have a common ID for customers throughout the BCs I have a way of pulling that data back id I need to for presentation. For example, I can use the Ops BC to pull back a list of orders for customer XXXX. I don't need to go in via the Customer Aggregate to do that.

Now, throw in this wrinkle. The Sales guys will need at some point to know about orders a customer has placed, so do I need to start replicating information in my Sales BC? This is where I got stuck, but then I realised I am talking about the sales guys, they are users of the UI, and in the UI I can pull back a list of orders for a given customer.

I am still fairly new to DDD but what I am realising is DDD is all about the conversations with the domain experts, and when you have those conversations properly you realise that an Entity that you think exists across BCs... doesn't.

I think we as developers through experience are set up to denormalise data, and think about database structures, and how we will persist these Customer objects back to a table... and so we see the entity as one glob of stuff, but the domain experts do not see these entities in this way.

The comment which sealed the deal for me was from the rather cantankerous Ops Director when I asked a question like "so what would the accounts department need to see from this order" and his response, minus the swearing was "I don't care what they want, I just want what I want". And I think that's how you need to look at the BCs.

I hope this waffle helps someone anyway.

PaulAdvancedUk
  • 153
  • 2
  • 10
  • 1
    This is about the same path I went down after a while. It's so easy to mix in thoughts about persitance and in my example even som application logic. DDD is only a part of a solution to my initial goal of creating a loosely coupled and easily maintainable application, not "the" solution i realised. One question I had though and didn't get was the sentence: " The BC defines an interface through which my application can interact with the Ops BC...". Which BC and what type of interface are you talking about here? – cfs Feb 04 '16 at 13:33
  • Ah sorry, that wasn't too clear was it. I shouldn't have used the term Interface maybe, but what I mean is I provide a means for an application to interact with my BC, and I control that means by providing certain methods for the application to use. The BC I was talking about is the Operations BC, which is responsible for creating and scheduling orders. It needs some customer detail, but actually only needs the name and 4 letter code, not the myriad of information which goes along with the customer in the sales BC. As you say DDD isn't THE solution, but I find it brilliant to really help you – PaulAdvancedUk Feb 04 '16 at 22:14
  • analyse the domain you are working in. The more I force myself to forget about the database, and just focus on the domain language, I realise that an Entity I thought needed to be shared, doesn't. One big issue I had was dealing with how you combine information from multiple BCs into a common Application UI. It was then I realised that the BCs and Aggregates are for transactional scenarios, where you are modifying an entity. When you are pulling back data to be displayed, you don't need to hydrate the aggregates, you can use for want of a better word ViewModels. There is a great talk by – PaulAdvancedUk Feb 04 '16 at 22:17
  • Udi Dehan where looks at the Amazon product page, and shows you that the information on that page doesn't come from 1 BC. product name and description comes from product catalog, inventory comes from the Inventory BC, price comes from the price BC, reviews come from the Product Review BC and it goes on. You just hook up "widgets" in your UI to pull in the bits of info you need. – PaulAdvancedUk Feb 04 '16 at 22:18
  • In this example the ops BC needs the subset of the information that sales BC has. What if it or another BC needed to keep some info that doesn't necessarily have to exist in sales BC. Imagine BC A needs to know name and telephone number of a customer and BC B needs to know name and tax number of a customer. How can it be modeled? – aycanadal Nov 07 '17 at 13:57
  • Well in that case you would have a "Customer" Aggregate of some sort in each BC. The Customer Aggregate in BC A would hold the name and telephone number. The Customer Aggregate in BC B would hold the Tax Number. Both aggregates would have a CustomerID, which is what "links" the 2 sets of data. They aren't linked across Boundary Contexts though, but if you have a CustomerID, you can operate with BC A and BC B. – PaulAdvancedUk Nov 09 '17 at 13:25
  • This all relies on you being certain that the info you have mentioned belongs in those BCs. If they belong elsewhere, but you need to know them in these BCs then you can use Domain Events to synchronise across BCs within the Domain. – PaulAdvancedUk Nov 09 '17 at 13:25