I'm trying to learn DDD and I want to create a marketplace. I have Seller and Buyer entities in the Sales bounded context. Is this how I'm supposed to write code the DDD way? Will it be better to make Seller and Buyer one entity? And will it be confusing that Buyer has AcceptOffer() method, because Buyer can't accept the offer and the method is used when the Seller Accepts the offer from the buyer to notify the buyer that his offer has been accepted?
public class Seller
{
private readonly ICollection<Product> productsForSelling = new List<Product>();
private readonly IDictionary<Product, Offer> soldProductsAndOffers = new Dictionary<Product, Offer>();
private readonly ICollection<Offer> receivedOffers = new List<Offer>();
private readonly ICollection<Offer> declinedOffers = new List<Offer>();
public void SellProduct(Product product)
{
this.productsForSelling.Add(product);
}
public void RemoveProductForSale(Product product)
{
this.productsForSelling.Remove(product);
}
public void AcceptOffer(Offer offer)
{
this.ValidateProductForSaleExistence(offer.Product);
this.soldProductsAndOffers.Add(offer.Product, offer);
this.RemoveProductForSale(offer.Product);
offer.Product.Status = Status.Sold;
}
public void ReceiveOffer(Offer offer)
{
this.receivedOffers.Add(offer);
}
public void DeclineOffer(Offer offer)
{
this.ValidateProductForSaleExistence(offer.Product);
this.declinedOffers.Add(offer);
}
private void ValidateProductForSaleExistence(Product product)
{
var isProductForSale = this.productsForSelling.Contains(product);
if (isProductForSale == false)
throw new InvalidOperationException();
}
}
public class Buyer
{
private ICollection<Offer> pendingOffers = new List<Offer>();
private ICollection<Offer> acceptedOffers = new List<Offer>();
public void CreateOffer(Product product, Seller seller)
{
var offer = new Offer(this, product, seller);
seller.ReceiveOffer(offer);
}
public void AcceptOffer(Offer offer)
{
if (this.pendingOffers.Contains(offer) == false)
throw new InvalidOperationException();
this.pendingOffers.Remove(offer);
this.acceptedOffers.Add(offer);
}
}
You are on the right track.
However, Buyer and Seller should be separate entities but you can create a base Entity class for any common code(not the common feature).
There are certain important rules in DDD that can help while designing:
The entities should not be anemic(only getter/setter), every public method should have a single responsibility and name should explain that.
This is also followed in DDD that code should be self explanatory.
Also the every entity should have an Id that you can keep in Entity bas class.
If an operation spans more than one entity create a DomainService class for that. Like a function involving Buyer and Seller both should be in the service class.
If you go for Layered architecture make sure that the domain model should be in package(like a namespace/package in java) and should not refer any upper layers. Make a package diagram for showcasing.
Find out all the concepts(Problem space) before start designing(Solution space) like Buyer/Seller/Offer and all the events. It concepts can come up in discussion with domain experts so it will be called as Ubiquitous language.
You can refer to Event storming technique for this.
I have Seller and Buyer entities in the Sales bounded context. Is this how I'm supposed to write code the DDD way?
I would say yes, because for me Seller and 'Buyer' are both concepts of selling. Finally the answer can only give the domain experts. DDD is about listening to domain experts and model bounded contexts as the domain experts think about them.
A bounded context is a context in which a term has a specific meaning. Thus you can have the same term in different contexts, because it has different meanings. E.g. if you are designing an application for a flight company the term flight might be used in different contexts. A flight can be the route that a plane will take (origin to destination). A flight can also be the thing that a ticket represents for a passenger. Or the company might look at flights* from the maintenance perspective. In each case the you will have different properties and methods for a flight (that change for different reasons -> single responsibility).
Will it be better to make Seller and Buyer one entity?
No, since a Seller and a Buyer are individual concepts of the selling domain. In Java I would put them in the same package and make the Buyer.AcceptOffer method package scope or protected so that it is only visible to classes in the same package. You must decide how to do it with the language features of the language you use.
And will it be confusing that Buyer has AcceptOffer() method, because Buyer can't accept the offer and the method is used when the Seller Accepts the offer from the buyer to notify the buyer that his offer has been accepted?
The domain concept of accepting an offer should be placed in one entity, at least the public api (see the answer to your second question).
But when you listen to your own definition it gives you another hint:
the method is used when the Seller Accepts the offer from the buyer to notify the buyer that his offer has been accepted?
The key word is notify. The notify gives you the hint that there might be a domain event. Thus it is also possible that Seller and Buyer are the roots of different aggregates and that one aggregate informs the other using domain events.
Diving into domain events and possible implementation solutions goes far beyond your question. If you are not aware of domain events you should read a book about them first. Either Eric Evans DDD Book or Implementing domain-driven-design by Vaughn Vernon.
Related
Depending on the example that vaughn vernon gave in his book about Agile.He designed Product as an Aggregate and BackLogItem as an aggregate which references Product AR by Id.
Now we need to plan new BackLogItem inside BackLogApplicationService as following:
public class ProductBacklogItemService
{
//...
public void planProductBacklogItem(
String aTenantId, String aProductId,
String aSummary, String aCategory,
String aBacklogItemType, String aStoryPoints)
{
Product product =
productRepository.productOfId(
new TenantId(aTenantId),
new ProductId(aProductId));
BacklogItem plannedBacklogItem =
BacklogItem.planBacklogItem(
aSummary,
aCategory,
BacklogItemType.valueOf(aBacklogItemType),
StoryPoints.valueOf(aStoryPoints),
product);
backlogItemRepository.add(plannedBacklogItem);
//commit the changes
}
//...
}
And the factory method will be like :
public static BacklogItem planBacklogItem(String aSummary, String aCategory,BacklogItemType aType, StoryPoints aStoryPoints,Product product)
{
if(product.Suspended)
//here prevent planning this backlogitem
//...
backLogItem.ProductId=product.Id
return backLogItem;
}
Did I violate the consistency boundary of the BackLogItem Aggregate inside the Factory method because I am using some information about Product state to decide planning new backLogItem into that Product, if so how I can prevent planning new backLogItems into that product in case that product is suspended or inactive?
Which level of communication is allowed between Aggregates Roots in DDD?
The core guideline is this: any given transaction modifies at most one aggregate in your model.
So if your model includes a relationship between a Product and a BacklogItem, then you can modify a Product using a stale copy of data from a BacklogItem, or you can modify a BackLogItem using a stale copy of data from a Product.
To help make this clear in code, we use interfaces to pass messages from one aggregate to another. In a use case where we are going to modify a Product, we have a product interface that supports mutations, and a back log item interface that only supports queries. If we are going to update the back log item, then the item has the mutable interface and the product interface is read only.
In other words, we use appropriate role interfaces to ensure that no code author inadvertently violates the rule of modifying more than one aggregate in a transaction.
our answer it means the above code it does not violate DDD because I don't here update the product aggregate(because of ddd it's not allowed to update more than one aggregate per transaction
Right - when Evans described DDD in 2003, he was working in a coding style that didn't rely upon interfaces; to have an instance of a product meant to have all of the capabilities of the product available at once.
Role interfaces help to reduce the number of errors made possible by this flexibility. Simply not making mistakes is also an option.
I need some clarification on modelling a user for Identity and access domain. The user domain model has a contact information entity (entity because it is mutable), the customer can register with a phone number, but can choose to change it when needed.
The phone number once used by a customer can never be used by any other user. So the model I believe must allow querying the phonenumber table(since it is many to one with the customer, as the old numbers are deactivated and archived).
If creating a domainservice is ok, what should be the Repository as there is no aggregate identified.
With these cases I have a customer(user) aggregate, but to allow querying all the users to see if the phone number provided by the customer is already been used by anyone else, what should be the aggregate, or can I write a DomainService that just can query the database directly to the phonenumber table to check for the uniqueness, am I violating any DDD principle doing so, what are the cleaner alternatives.
An alternative would be to create an Aggregate that makes it explicit in which scope you intend the unique constraint to hold.
As a (contrived) example, a phone number might be unique across a country but not internationally. Thus :
// An Aggregate Root
public class Country {
// Store a lookup structure (userId, phoneNumber) here
public void addUser(userId, phoneNumber) {
// check phone uniqueness here
}
public void changeUserPhone(userId, phoneNumber) {
// check phone uniqueness here
}
}
Since you're using CQRS, phone numbers being in a separate Aggregate doesn't matter because on the Query side, Read Models will reassemble the User and their phoneNumber together.
This also plays well with the "don't create Aggregate Roots" approach since you have a starting point from where to create your User (User is probably an AR) and not just create it out of thin air.
You could have your repository check if the phone number exists, if it does then throw a rule exception else save the change. The key here is to inject an instance of the repository through the application layer and run rule inside the domain layer.
I'm looking for some advice on how much I should be concerned around avoiding the anemic domain model. We are just starting on DDD and are struggling with analysis paralysis regarding simple design decisions. The latest point we are sticking on is where certain business logic belongs, for example we have an Order object, which has properties like Status etc. Now say I have to perform a command like UndoLastStatus because someone made a mistake with an order, this is not as simple as just changing the Status as other information has to be logged and properties changed. Now in the real world this is a pure administration task. So the way I see it I have two options I can think of:
Option 1: Add the method to order so something like Order.UndoLastStatus(), whilst this kinda make sense, it doesn't really reflect the domain. Also Order is the primary object in the system and if everything involving the order is placed in the order class things could get out of hand.
Option 2: Create a Shop object, and with that have different services which represent differant roles. So I might have Shop.AdminService, Shop.DispatchService, and Shop.InventoryService. So in this case I would have Shop.AdminService.UndoLastStatus(Order).
Now the second option we have something which reflects the domain much more, and would allow developers to talk to business experts about similar roles that actually exists. But its also heading toward an anemic model. Which would be the better way to go in general?
Option 2 would lead to procedural code for sure.
Might be easier to develop, but much harder to maintain.
Now in the real world this is a pure administration task
"Administration" tasks should be private and invoked through public, fully "domain`ish" actions. Preferably - still written in easy to understand code that is driven from domain.
As I see it - problem is that UndoLastStatus makes little sense to domain expert.
More likely they are talking about making, canceling and filling orders.
Something along these lines might fit better:
class Order{
void CancelOrder(){
Status=Status.Canceled;
}
void FillOrder(){
if(Status==Status.Canceled)
throw Exception();
Status=Status.Filled;
}
static void Make(){
return new Order();
}
void Order(){
Status=Status.Pending;
}
}
I personally dislike usage of "statuses", they are automatically shared to everything that uses them - i see that as unnecessary coupling.
So I would have something like this:
class Order{
void CancelOrder(){
IsCanceled=true;
}
void FillOrder(){
if(IsCanceled) throw Exception();
IsFilled=true;
}
static Order Make(){
return new Order();
}
void Order(){
IsPending=true;
}
}
For changing related things when order state changes, best bet is to use so called domain events.
My code would look along these lines:
class Order{
void CancelOrder(){
IsCanceled=true;
Raise(new Canceled(this));
}
//usage of nested classes for events is my homemade convention
class Canceled:Event<Order>{
void Canceled(Order order):base(order){}
}
}
class Customer{
private void BeHappy(){
Console.WriteLine("hooraay!");
}
//nb: nested class can see privates of Customer
class OnOrderCanceled:IEventHandler<Order.Canceled>{
void Handle(Order.Canceled e){
//caveat: this approach needs order->customer association
var order=e.Source;
order.Customer.BeHappy();
}
}
}
If Order grows too huge, You might want to check out what bounded contexts are (as Eric Evans says - if he had a chance to wrote his book again, he would move bounded contexts to the very beginning).
In short - it's a form of decomposition driven by domain.
Idea is relatively simple - it is OK to have multiple Orders from different viewpoints aka contexts.
E.g. - Order from Shopping context, Order from Accounting context.
namespace Shopping{
class Order{
//association with shopping cart
//might be vital for shopping but completely irrelevant for accounting
ShoppingCart Cart;
}
}
namespace Accounting{
class Order{
//something specific only to accounting
}
}
But usually enough domain itself avoids complexity and is easily decomposable if You listen to it closely enough. E.g. You might hear from experts terms like OrderLifeCycle, OrderHistory, OrderDescription that You can leverage as anchors for decomposition.
NB: Keep in mind - I got zero understanding about Your domain.
It's quite likely that those verbs I'm using are completely strange to it.
I would be guided by the GRASP principles. Apply the Information Expert design principle, that is you should assign the responsibility to the class that naturally has the most information required to fulfill the change.
In this case, since changing the order status involves other entities, I would make each of these low-level domain objects support a method to apply the change with respect to itself. Then also use a domain service layer as you describe in option 2, that abstracts the whole operation, spanning multiple domain objects as needed.
Also see the Facade pattern.
I think having a method like UndoLastStatus on the Order class feels a bit wrong because the reasons for its existence are in a sense outside of the scope of an order. On the other hand, having a method which is responsible for changing the status of an order, Order.ChangeStatus, fits nicely as a domain model. The status of an order is a proper domain concept and changing that status should be done through the Order class, since it owns the data associated with an order status - it is the responsibility of the Order class to keep itself consistent and in a proper state.
Another way to think of it is that the Order object is what's persisted to the database and it is the 'last stop' for all changes applied to an Order. It is easier to reason about what a valid state for an order might be from the perspective of an Order rather than from the perspective of an external component. This is what DDD and OOP are all about, making it easier for humans to reason about code. Furthermore, access to private or protected members may be required to execute a state change, in which case having the method be on the order class is a better option. This is one of the reasons why anemic domain models are frowned upon - they shift the responsibility of keeping state consistent away from the owning class, thereby breaking encapsulation among other things.
One way to implement a more specific operation such as UndoLastStatus would be to create an OrderService which exposes the domain and is how external components operate upon the domain. Then you can create a simple command object like this:
class UndoLastStatusCommand {
public Guid OrderId { get; set; }
}
An the OrderService would have a method to process that command:
public void Process(UndoLastStatusCommand command) {
using (var unitOfWork = UowManager.Start()) {
var order = this.orderRepository.Get(command.OrderId);
if (order == null)
throw some exception
// operate on domain to undo last status
unitOfWork.Commit();
}
}
So now the domain model for Order exposes all of the data and behavior that correspond to an Order, but the OrderService, and the service layer in general, declare the different kind of operations that are performed on an order and expose the domain for utilization by external components, such as the presentation layer.
Also consider looking into the concept of domain events which considers anemic domain models and ways of improving them.
It sounds like you are not driving this domain from tests. Take a look at the work of Rob Vens, especially his work on exploratory modeling, time inversion and active-passive.
I'm reading about the idea of Bounded Contexts in DDD, and I'm starting to realize that I don't have a clear understanding of exactly what a Model looks like in practice. (I might not even know exactly what a Domain means, either.)
Let's look at the popular e-commerce example: A customer browses products, adds to their cart, places an order. The order fulfillment people ship out the orders.
Is there one big e-commerce Domain with multiple Bounded Contexts (Product Catalog Context, Shopping Cart Context, Order Context, Fulfillment Context)? Does each Bounded Context contain a bunch of Models (So that the Product Catalog Context contains models for the products, the product images, the product reviews)?
How far off am I?
At least You are on right track. Classic mistake is to see patterns only.
Domain means problems You are dealing with (support for e-commerce, healthcare, accounting, etc.). Domain model is solution of those problems represented in code that follows our mental model as close as possible.
Let's look at the popular e-commerce example: A customer browses products, adds to their cart, places an order. The order fulfillment people ship out the orders.
In Your example, I would start with something like this:
class Product { }
class Customer
{
Cart Cart;
void PlaceAnOrder()
{
order = new Order(Cart.Products);
Orders.Add(order);
Cart.Empty(); //if needed
}
Orders Orders;
Orders UnfulfilledOrders()
{
Orders.Where(order => !order.IsFilled);
}
}
class Cart
{
void AddProduct(product)
{
Products.Add(product);
}
void Empty()
{
Products.Clear();
}
}
class Order
{
bool IsFilled;
void Order(products)
{
Products = products;
IsFilled = false;
}
void Fill()
{
IsFilled = true;
//TODO: obviously - more stuff needed here
}
Money TotalPrice()
{
return Products.Sum(x => x.Price);
}
}
class System
{
void Main()
{
SimulateCustomerPlacingAnOrder();
SimulateFulfillmentPeople();
}
void SimulateCustomerPlacingAnOrder()
{
customer = new Customer();
customer.Cart.AddProduct(allProducts.First());
allCustomers.Add(customer);
}
void SimulateFulfillmentPeople()
{
foreach (var customer in allCustomers)
{
foreach (var order in customer.UnfulfilledOrders())
order.Fill();
}
}
}
At start - this seems like a huge overkill. With procedural code - the same can be achieved with few collections and few for loops. But the idea of domain driven design is to solve really complex problems.
Object oriented programming fits nicely - with it You can abstract away things that doesn't matter when You advance forward. Also - it's important to name things accordingly so You (and Your domain experts (people that understands problem)) would be able to understand code even after years. And not only code but to talk in one ubiquitous language too.
Note that I don't know e-commerce domain and what kind of problems You might be trying to solve, therefore - it's highly likely that I just wrote complete nonsense according to Your mental model. That is one reason why teaching domain modeling is so confusing and hard. Also - it demands great skill in abstract thinking which according to my understanding ain't main requirement to get CS degree.
You are kind a right about bounded contexts. But You should remember that they add need for translation between them. They add complexity and as usual - complex solution is appropriate for complex problems only (this is true for ddd itself too). So - You should avoid spamming them as long as meaning of your domain entities don't overlap. Second reason (less "natural") would be strong need for decomposition.
P.s. Read Evans book. Twice... Until it makes sense... :)
I think your view is accurate. Contexts deal with different aspects of the same real-world concept. In your case, you might have an order represented as some kind of shopping cart abstraction for the user and at the same time in some form that is compatible with the used ERP.
Instead of trying to shoehorn the concept of an order into a single model, DDD's contexts basically say it's OK to represent some concept using two completely different models (in different contexts), providing explicit mappings between these models as the need arises. This prevents models from aggregating the cruft that usually creeps in if one tries to use the same model within a multitude of contexts.
If you are ok with example in java, this might be useful: http://dddsample.sourceforge.net/
I’m currently in the process of developing a domain model for a new application and have reached the stage where I need to define relationships with classes of different types that may perform the same role, and am confused as to the best way to define the relationship.
For example:
public class Car
{
public IDriver driver { get; set;}
public IPassenger passenger { get; set; }
}
public class Person : IDriver, IPassenger
{
}
public class Pet : IPassenger
{
}
In this case I want to be able to define that a diver of a car can be any class that implements IDriver and any passenger must implement IPassenger. In the case of a passenger it could be with a person or a pet. The interfaces in essence are defining the roles of each class.
What I want to understand is if in peoples opinions this is a good approach, or if the same thing could be accomplished using a different mechanism.
Hard to say with the information posted in the question...
Start with behavior, an acceptance test or a scenario of use. (I don't want to make up a scenario from thin air.)
Roles are relationships between collaborating objects. e.g. Object B may be a dependency, listener or a policy/strategy of Object A.
So now you need to design from Object A's perspective i.e. Outside-in. e.g. What does Car expect from its driver ? Those behaviors would translate to members of the Driver Role.