I'm new to Domain Driven Desing and completely stucked with modelling problem. Here is a screenshot of design level event storming of simple feature with only one invariant:
Let's assume that eventual consistency is not allowed for certificate's condition and it is absolutely crucial to fulfill this condition immediately to process an order. In this case to check my certificate invariant I need an access to:
season of the order
supplier's country
season from which certificates are checked for specific country
supplier's certificates and if they are accepted and up to date
Initially I tried to split my application into multiple bounded contexts and for me those informations belong to different bounded contexts. Should I then have all these necassary data (list above) in one aggregate in order to ensure consistency and have its quite large or maybe there is any other solution? Maybe my whole reasoning is wrong and it doesn't make much sense? Maybe the bounded contexts boundaries are wrong due to necesity to reach for data to other contexts (not being autonomous)? Maybe domain service could be a solution? I would be really grateful for any help because I'm quite confused with those ddd topics :/
before answering your question I suggest you keep in mind the next statements:
Consolidate your business invariants(rules) inside Aggregate.
Design small and autonomous aggregates, if it is possible.
Reference other Aggregates by using their id.
Update other Aggregates using eventual consistency.
now let me share my opinion and give you advice (I've used C# syntax in below code snippets)
I recommend to you use 2 BC - Order and Supplier, and each of those is a good candidate for the individual aggregate. Certificate is not an aggregate and we have access to it via Supplier aggregate.
Preface: We have 2 services, - Order application service which injects repository interfaces to retrieve specific data. Also, we have an Order domain service where we're working with our aggregates.
Now if you want to check the certificate invariant, to do the next steps -
We should arrange all required data in the order application service by pulling data from repositories
Now it's time to validate
(supplier's certificates and if they are accepted and up to date) certificate invariant.
Let's switch to the Order domain service to decide about order processing where we have the next method public void AddOrder(Order newOrder, Supplier supplier).
But let's start with adding the concrete business rule class like that
public class SupplierCertificatesAreValidRule{
public SupplierCertificatesAreValidRule(IList<Certificate> supplierCertificates){
...
}
public bool IsValid() {...}
}
Get from the Supplier entity collection of its certificates.
Let's define the season of the order
Then get the supplier's country
Fetch the season from which certificates are checked for specific country
Add the Add method in the Order entity itself, where at beginning of this method we should call our business rule like that :
public static Order Add(Order newOrder, Supplier supplier){
CheckRule(new SupplierCertificatesAreValidRule(supplier.Certificates));
return new Order();
}
If the rule does not meet, then we should throw some business rule validation exception and explain the reason there.
If our rule is met, then it means that we can process our order
Related
I'm thinking about a REST API design. There are several tables in my database. For example Customer and Order.
Of course - each Order has its Customer (and every customer can have many Orders).
I've decided to provide such an interface
/api/v1/Customers/ -- get list of Customers, add new Customer
/api/v1/Customers/:id: -- get Customer with id=:id:
/api/v1/Orders/ -- get list of Orders, add new Order
/api/v1/Orders/:id: -- get Order with id=:id:
It works flawlessly. But my frontend has to display a list of orders with customer names. With this interface, I will have to make a single call to /api/v1/Orders/ and then another call to /api/v1/Customer/:id: for each record from the previous call. Or perform two calls to /api/v1/Orders/ and /api/v1/Customers/ and combine them on the frontend side.
It looks like overkill, this kind of operation should be done at the database level. But how can/should I provide an appropriate interface?
/api/v1/OrdersWithCustomers
/api/v1/OrdersWithCustomers/:id:
Seems weir. Is it a right way to go
There's no rule that says you cannot "extend" the data being returned from a REST API call. So instead of returning "just" the Order entity (as stored in the backend), you could of course return an OrderResponseDTO which includes all (revelant) fields of the Order entity - plus some from the Customer entity that might are relevant in your use case.
The data model for your REST API does not have to be an exact 1:1 match to your underlying database schema - it does give you the freedom to leave out some fields, or add some additional information that the consumers of your API will find helpful.
Great question, and any API design will tend to hit pragmatic reality at some point like this.
One option is to include a larger object graph for each resource (ie include the customer linked to each order) but use filter query parameters to allow users to specify what properties they require or don't require.
Personally I think that request parameters on a restful GET are fine for either search semantics when retrieving a list of resources, or filtering what is presented for each resource as in this case
Another option for your use case might be to look into a GraphQL approach.
How would you do it on the web?
You've got a web site, and that website serves documents about Customers, and documents about Orders. But your clients aren't happy, because its too much boring, mistake-prone work to aggregate information in the two kinds of documents.
Can we please have a document, they ask, with the boring work already done?
And so you generate a bunch of these new reports, and stick them on your web server, and create links to make it easier to navigate between related documents. TA-DA.
A "REST-API" is a facade that makes your information look and act like a web site. The fact that you are generating your representations from a database is an implementation details, deliberately hidden behind the "uniform interface".
From Microsoft's API design guidance(https://learn.microsoft.com/en-us/azure/architecture/best-practices/api-design#more-information):
In more complex systems, it can be tempting to provide URIs that enable a client to navigate through several levels of relationships, such as /customers/1/orders/99/products. However, this level of complexity can be difficult to maintain and is inflexible if the relationships between resources change in the future. Instead, try to keep URIs relatively simple. Once an application has a reference to a resource, it should be possible to use this reference to find items related to that resource. The preceding query can be replaced with the URI /customers/1/orders to find all the orders for customer 1, and then /orders/99/products to find the products in this order.
Avoid requiring resource URIs more complex than collection/item/collection.
From Microsoft's example, let's say I want to find all the products of customer 1. Then I would need to first query /customers/1/orders to find all the orders then query individual orders by /orders/{id}/products which falls into N+1 problem. Also, If I want to create a new order, should I POST to /customers/1/order or /orders with customer_id?
//2 endpoints
/customers/1/orders
/orders/{id}/products //for n orders
Or I could build all APIs with 1 depth and search for all the products by /products/?customer_id=1
//3 endpoints
/customers
/orders
/products
To sum up,
which would be better approach? nested vs 1depth but more endpoint
If nested is better, with microsoft's example, if I want to create a new order for customer 1, should i POST to /customers/1/orders or /orders with customer_id in body or support both?
Both approaches are okay from a REST API design perspective. You should design it according to your use case and to increase the developer experience:
If it's more intuitive to create an order in a customer context, choose a nested approach.
If it's more intuitive to create an order and send the customer id as an attribute of the order object, choose the other approach.
You can even serve both approaches, as the API is just an interface to communicate with your service (just like a GUI, but for m2m purposes).
I have two bounded contexts which lead into two micro services
PersonalManagement
DocumentStorage
I keep the entity model simple here.
PersonalManagement:
Entity/Table Person:
#id - int
tenantId - int
name - string
...
DocumentStorage
Entity/Table Document:
#id - int
tenantId - int
personId - int
dateIssued - string
...
You need to know that before the application is started - a company (tenant) is choosen to define the company context.
I want to store a new document by using REST/JSON.
This is a POST to /tenants/1/persons/5/documents
with the body
{
"dateIssued" : "2018-06-11"
}
On the backend side - I validate the input body.
One validation might be "if the person specified exists and really belongs to given tenant".
Since this info is stored in the PersonalManagement-MicroService, I need to provide an operation like this:
"Does exists (personId=5,tenantId=1)"
in PersonalManagement to ensure consistence since caller might be evil.
Or in general:
What is best practise to check "ownership" of entities cross database in micro services
It might also be an option that if a new person is created (tenantId,personId) this information is stored additionally(!) in DocumentStorage but wanna avoid this redundancy.
I'm not going to extend this answer into whether your bounded contexts and service endpoints are well defined since your question seems to be simplifying the issue to keep a well defined scope, but regarding your specific question:
What is best practise to check "ownership" of entities cross database in micro services
Microservice architectures use strive for a "share nothing" principle. And that usually extends from code base to data base. So you're right to assume you're checking for this constraint "cross-DB" in your scenario.
You have a few options on this particular case, each with their set of drawbacks:
1) Your proposed "Does exists (personId=5,tenantId=1)" call from the DocumentContext to the PersonContext is not wrong on itself, but you will generate a straight dependency between these two microservices, so you must ask yourself whether it seems ok for you not to accept new documents if the PersonManagement microservice is offline.
In specific situations, such dependencies might be acceptable but the more of these you have, the less your microservice architecture will behave as one and more like a "distributed monolith" which on itself it pretty much an anti-pattern.
2) The other main option you have is that you should recognize that the DocumentContext is a very much interested in some information/behavior relating to People so it should be ok with modelling the Person Entity inside its boundaries.
That means, you can have the DocumentContext subscribe for changes in the PersonContext to be aware of which People currently exist and what their characteristics are and thus being able to keep a local copy of such information.
That way, your validation will be kept entirely inside the DocumentContext which will have its operation unhindered by eventual issues with the PersonContext and you will find out your modelling of the document related entities will be much cleaner than before.
But in the end, you will also discover that a "share nothing" principle usually will cost you in what seems to be redundancy, but it's actually independence of contexts.
just for the tenancy check , this can be done using the JWT token (token which can store tenancy information and other metadata).
Let me provide another example of the same scenario which can't be solved with JWT.
Assume one Customer wants to create a Order and our system wants to check whether the customer exist or not while creating the order.
As Order and Customer service are separate, and we want minimal dependencies between them, there are multiple sol. to above problems:
create Order in "validating state" and on OrderCreated event check for customer validity and update customer state to "Valid"
another one before creating order check for the customer (which is not the right way as it creates dependency, untill and unless very critical do not do it)
last way is the let the order be created , somebody who will final check the order for delivery will verify customer will remove
Lets assume I have an object that I expose as a REST resource in my application. This object has many fields and contains many other objects including associated collections. Something like this, but think MUCH bigger:
Customer
List<Order> orders
List<Address> shippingAddresses;
// other fields for name, etc.
Order
List<Product> products
// fields for total, tax, shipping, etc.
Product
// fields for name, UPC, description, etc.
I expose the customer in my api as /customer/{id}
Some of my clients will want all of the details for every product in each order. If I follow HATEOAS I could supply a link to get the product details. That would lead to n+1 calls to the service to populate the products within the orders for the customer. On the other hand, if I always populate it then many clients receive a bunch of information they don't need and I do a ton of database lookups that aren't needful.
How do I allow for a customer representation of my resource based on the needs of the client?
I see a few options.
Use Jackson's JsonView annotation to specify in advance what is used. The caller asks for a view appropriate to them. i.e. /customer/{id}?view=withProducts. This would require me to specify all available views at compile time and would not be all that flexible.
Allow the caller to ask for certain fields to be populated in the request, i.e. /customer/{id}?fields=orders,firstName,lastName. This would require me to have some handler that could parse the fields parameter and probably use reflection to populate stuff. Sounds super messy to me. The what do you do about sub-resources. Could I do fields=orders.products.upc and join into the collection that way? Sounds like I'm trying to write hibernate on top of REST or something.
Follow HATEOAS and require the client to make a million HTTP calls in order to populate what they need. This would work great for those that don't want to populate the item most of the time, but gets expensive for someone that is attempting to show a summary of order details or something like that.
Have separate resources for each view...
Other?
I would do something like this:
/customers/{id}/orders/?include=entities
Which is a kind of a more specific variation of your option 1.
You would also have the following options:
Specific order from a specific customer without list of products:
/customers/{id}/orders/{id}
Just the orders of a customer without products:
/customers/{id}/orders/
I tend to avoid singular resources, because most of the time or eventually someone always wants a list of things.
Option 2 (client specifies fields) is a filtering approach, and acts more like a query interface than a GETable resource. Your filter could be more expressive if you accept a partial template in a POST request that your service will populate. But that's complicated.
I'm willing to bet all you need is 2 simple representations of any complex entity. That should handle 99.9% of the cases in your domain. Given that, make a few more URIs, one for each "view" of things.
To handle the 0.1% case (for example, when you need the Products collection fully populated), provide query interfaces for the nested entities that allow you to filter. You can even provide hypermedia links to retrieve these collections as part of the simplified representations above.
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
When designing resource hierarchies, when should one use sub-resources?
I used to believe that when a resource could not exist without another, it should be represented as its sub-resource. I recently ran across this counter-example:
An employee is uniquely identifiable across all companies.
An employee's access control and life-cycle depend on the company.
I modeled this as: /companies/{companyName}/employee/{employeeId}
Notice, I don't need to look up the company in order to locate the employee, so should I? If I do, I'm paying a price to look up information I don't need. If I don't, this URL mistakenly returns HTTP 200:
/companies/{nonExistingName}/employee/{existingId}
How should I represent the fact that a resource to belongs to another?
How should I represent the fact that a resource cannot be identified without another?
What relationships are sub-resources meant and not meant to model?
A year later, I ended with the following compromise (for database rows that contain a unique identifier):
Assign all resources a canonical URI at the root (e.g. /companies/{id} and /employees/{id}).
If a resource cannot exist without another, it should be represented as its sub-resource; however, treat the operation as a search engine query. Meaning, instead of carrying out the operation immediately, simply return HTTP 307 ("Temporary redirect") pointing at the canonical URI. This will cause clients to repeat the operation against the canonical URI.
Your specification document should only expose root resources that match your conceptual model (not dependent on implementation details). Implementation details might change (your rows might no longer be unique identifiable) but your conceptual model will remain intact. In the above example, you'd tell clients about /companies but not /employees.
This approach has the following benefits:
It eliminates the need to do unnecessary database look-ups.
It reduces the number of sanity-checks to one per request. At most, I have to check whether an employee belongs to a company, but I no longer have to do two validation checks for /companies/{companyId}/employees/{employeeId}/computers/{computerId}.
It has a mixed impact on database scalability. On the one hand you are reducing lock contention by locking less tables, for a shorter period of time. But on the other hand, you are increasing the possibility of deadlocks because each root resource must use a different locking order. I have no idea whether this is a net gain or loss but I take comfort in the fact that database deadlocks cannot be prevented anyway and the resulting locking rules are simpler to understand and implement. When in doubt, opt for simplicity.
Our conceptual model remains intact. By ensuring that the specification document only exposes our conceptual model, we are free to drop URIs containing implementation details in the future without breaking existing clients. Remember, nothing prevents you from exposing implementation details in intermediate URIs so long as your specification declares their structure as undefined.
This is problematic because it's no longer obvious that a user belongs
to a particular company.
Sometimes this may highlight a problem with your domain model. Why does a user belong to a company? If I change companies, am I whole new person? What if I work for two companies? Am I two different people?
If the answer is yes, then why not take some company-unique identifier to access a user?
e.g. username:
company/foo/user/bar
(where bar is my username that is unique within that specific company namespace)
If the answer is no, then why am I not a user (person) by myself, and the company/users collection merely points to me: <link rel="user" uri="/user/1" /> (note: employee seems to be more appropriate)
Now outside of your specific example, I think that resource-subresource relationships are more appropriate when it comes to use rather than ownership (and that's why you're struggling with the redundancy of identifying a company for a user that implicitly identifies a company).
What I mean by this is that users is actually a sub-resource of a company resource, because the use is to define the relationship between a company and its employees - another way of saying that is: you have to define a company before you can start hiring employees. Likewise, a user (person) has to be defined (born) before you can recruit them.
Your rule to decide if a resource should be modeled as sub resource is valid. Your problem does not arise from a wrong conceptual model but you let leak your database model into your REST model.
From a conceptual view an employee if it can only exist within a company relationship is modeled as a composition. The employee could be thus only identified via the company. Now databases come into play and all employee rows get a unique identifier.
My advice is don't let the database model leak in your conceptional model because you're exposing infrastructure concerns to your API. For example what happens when you decide to switch to a document oriented database like MongoDB where you could model your employees as part of the company document and no longer has this artificial unique id? Would you want to change your API?
To answer your extra questions
How should I represent the fact that a resource to belongs to another?
Composition via sub resources, other associations via URL links.
How should I represent the fact that a resource cannot be identified without another?
Use both id values in your resource URL and make sure not to let your database leak into your API by checking if the "combination" exists.
What relationships are sub-resources meant and not meant to model?
Sub resources are well suited for compositions but more generally spoken to model that a resource cannot exist without the parent resource and always belongs to one parent resource. Your rule when a resource could not exist without another, it should be represented as its sub-resource is a good guidance for this decision.
if a subresource is uniquely identifiable without its owning entity, it is no subresource and should have its own namespace (i.e. /users/{user} rather than /companies/{*}/users/{user}).
Most importantly: never ever ever everer uses your entity's database primary key as the resource identifier. that's the most common mistake where implementation details leak to the outside world. you should always have a natural business key (like username or company-number, rather than user-id or company-id). the uniqueness of such a key can be enforced by a unique constraint, if you wish, but the primary key of an entity should never ever everer leave the persistence-layer of your application, or at least it should never be an argument to any service method. If you go by this rule, you shouldn't have any trouble distinguishing between compositions (/companies/{company}/users/{user}) and associations (/users/{user}), because if your subresource doesn't have a natural business key, that identifies it in a global context, you can be very certain it really is a depending subresource (or you must first create a business key to make it globally identifiable).
This is one way you can resolve this situation:
/companies/{companyName}/employee/{employeeId} -> returns data about an employee, should also include the person's data
/person/{peopleId} -> returns data about the person
Talking about employee makes no sense without also talking about the company, but talking about the person does make sense even without a company and even if he's hired by multiple companies. A person's existence is independent of whether he's hired by any companies, but an employment's existence does depend on the company.
The issue seems to be when there is no specific company but an employee technically belongs to some company or organization otherwise they could be called bums or politicians. Being an employee implies a company/organization relationship somewhere but not a specific one. Also employees can work for more than one company/organization. When the specific company context is required then your original works /companies/{companyName}/users/{id}
Lets say you want to know the EmployerContribution for your ira/rsp/pension you'd use:
/companies/enron/users/fred/EmployerContribution
You get the specific amount contributed by enron (or $0).
What if you want the EmployerContributions from any or all companies fred works(ed) for? You don't need a concrete company for it to make sense. /companies/any/employee/fred/EmployerContribution
Where "any" is obviously an abstraction or placeholder when the employee's company doesn't matter but being an employee does. You need to intercept the 'company" handler to prevent a db lookup (although not sure why company wouldn't be cached? how many can there be?)
You can even change the abstraction to represent something like all companies for which Fred was employed over the last 10 years.
/companies/last10years/employee/fred/EmployerContribution