Diving into the world of DDD is something of a whirlwind for me. While I've done a lot of research I'm struggling to change my thought process.
So, I have a package and a products entity. A package cannot function without products; vice-versa. The problem comes in when I'm needing to get the products belonging to a package (Note: the package is customisable, this means the products belonging to the package could be different the next time round). It seems that this belongs on neither entity, furthermore applying this to the package or product entity would make them tightly coupled.
I must stress that I'm using the word association because I'm trying to figure this out on a domain level rather than infrastructure.
A little thinking has led me to the following thoughts:
Make Packages an Aggregate root & the products to be a sibling of the
Package entity. However I believe that both of the Package & Products
are entities due to them been uniquely identified.
Create a domain service that would take the package ID & map to the
infrastructure layer to find the associated products. However, this
seems rather long winded for a single look up.
It would be great if someone could turn me sane again! Thanks in advance!
Ubiquitious Language
DDD is all about language - the key here is to listen to your domain experts talk about products and packages - how do they think about them? And about the processes involved in working with them?
When they create a package, do they really think to themselves "I must define products with this package", or do they think "I'll setup a package, and then link a few products to it" - if the latter, although it may on first blush feel like a package can't exist without products, notice the subtle implication in the timing - that the package can exist without products, because they expect to link products to it as a second step.
Given that, you might model the link as a completely independent aggregate with a single entity as the root, e.g. PackageProduct (or better yet, some term your domain experts use to define the assocation) and simply create new instances of this aggregate when a product is linked to a package. This entity would have a PackageId and a ProductId on it.
However, if there are business rules, e.g. a Package can only have one product of a given type, or at most 5 products, then make the PackageProduct entity an entity within the Package aggregate, which has Package as the aggregate root. The PackageProduct would have a reference to the Package and a property of the ProductId. See below for some terminology clarification.
Entities vs Aggregates
Based on your question, it seems there might be some confusion about terminology. In DDD, we have:
Entities:
Have an identity that outlasts any given property
Has a mutable state
Generally, modelling business processes is all about working out how to mutate the state of entities
Aggregate
A group of entities over which invariants must be enforced
invariants are business rules that MUST hold at all times
A single entity is always nominated as the 'aggregate root'
Other entities can only refer to the aggregate by the root
When modelling a business process in order to mutate state, the aggregate is the boundary within which the states of all entities must be consistent with the invariants.
Outside the aggregate boundary, other entities may get updated asynchronously - aiming for eventual consistency
Domain Service
A service that contains business logic that doesn't belong in a single entity
It is generally not just a wrapper around a piece of infrastructure
See https://lostechies.com/jimmybogard/2008/05/21/entities-value-objects-aggregates-and-roots/ for more info.
Read vs Write Operations
The problem comes in when I'm needing to get the products belonging to a package
This sounds a lot like it might be in order to support a UI or a report? In which case - don't stress about the entity model. The entity model is there to ensure the business rules hold while users are trying to modify the state of the system. When doing a read operation, there is no need to modify the state, so you can bypass the model. Define a query that projects your data store onto a DTO and tailor the the projection to suite the needs of the UI or report.
The problem comes in when I'm needing to get the products belonging to a package (Note: the package is customisable, this means the products belonging to the package could be different the next time round).
This sounds like a query. It often helps to separate the modelling of commands (things that can alter your domain model) and queries.
Related
Let's say I have a group of database tables (customer, product, category, customer_products, product_categories, customer_categories) and classes corresponding to each of them (basic entity classes for the basic entity tables, and classes like CustomerProductLinker for the foreign key tables). The "linker" classes have methods like addXToY, removeXFromY, getXsOfY, and getYsOfX.
The problem comes from the additional business requirements that 1) adding a Customer to a Product should add that Customer to each of the Product's Categories, and 2) adding a Product to a Category should add each of that Product's Customers to the Category. With the current class system, that creates a dependency cycle between CustomerProductLinker and ProductCategoryLinker.
I do not know how to solve this. Combining all the "linkers" into one big "SuperLinker" class seems very wrong. And keeping the linker object instantiation inside only the methods that need them rather than passing the linkers in via constructor injection seems worse (though it would technically solve the cycle).
I doubt this system of linker classes is the best way to handle this kind of setup, but I'm not experienced enough to know what could be done instead. Unfortunately I can't use an ORM, because the tables are not all stored on the same server. So... What else can be done?
I need help with something I can’t get my head wrapped around regarding the Repository and Service/Use-case pattern (part of DDD design) I want to implement in my next (Laravel PHP) project.
All seems clear. Just one part of DDD that is confusing is the data structures from repositories. People seem to choose data structures the Repository should return (arrays or entities) but it all has disadvantages. One of which is performance looking at my experiences in the past. And one is which you don’t have interfaces for simple data structures (array or simple object attributes).
I’ll start with explaining the experience I have with a previous project. This project had flaws but some good strengths I learned from and like to see in my new project but with solving some design mistakes.
Previous experience
In the past I’ve build a website that was API Centric using the Kohana framework and Doctrine 2 ORM (data mapper pattern). The flow looked like this:
Website controller → API client (HMVC calls) → API controller → Custom Repository → Doctrine 2 ORM native Repository/Entity-manager
My custom Repository returned plain arrays using Doctrine2 DQL. Doctrine2 recommends array result data for read only operations. And yes, it made my site nice and light. The API controller just converted the array data to JSON. Simple as that.
In the past my company created projects relying fully on loaded Doctrine2 entities and it’s something we regretted due to performance.
My REST API supported queries like
/api/users?include_latest_adverts=2&include_location=true
on the users resource. The API controller passed include_location to the repository which directly included the location relation. The controller read latest_adverts=2 and called the adverts repository to get the latest 2 adverts of each user. Arrays were returned.
For example first user array:
[
name
avatar
adverts [
advert 1 [
name
price
]
advert 2 [
….
]
]
]
This proved to be very successful. My whole website was using the API. It would be very easy to to add a new client because the API was perfectly in production already using oauth. The whole website runs on it.
But this design had flaws too. My controller still contained A LOT of logic for validation, mailing, params or filters like has_adverts=true to get users with adverts only. It would mean that if I created a new port, like a total new CLI interface, I would have to duplicate alot of these controllers due to all the validation etc. But no duplication if I would create a new client. So at least one problem was solved :-)
My admin panels were completely coupled to the doctrine2 repository/entity-manager to speed up development (sort of). Why? Because my API had fat controllers with special functionality for the website only (special validation, mailing for registering etc). I would have to redo work or refactor a lot. So decided to use the Entities directly to still have some sort clear way of writing code instead of rewriting all my API controllers and move them to Services (for site & admin) for instance. Time was an issue in fixing my design mistakes.
For my next project I want all code to go through my own custom repositories and services. One flow for good separation.
New project (using DDD ideas) and dilemma with data structures
While I like the idea of being API centric, I don’t want my next project to be API centric in core because I think the same functionality should be available without the HTTP protocol in between. I want to design the core using DDD ideas.
But I liked the idea using a layer that just talked as a API and returns simple arrays. The perfect base for any new port, including my own frontend. My idea is to consider my Service classes as the API interface (return the array data), do the validation etc. I could have Services specially for the website (registering) and plain services used by the Admin or background processes. In some admin cases a Service would not be required anyway for simple CRUD editing, I could just use Repositories directly. Controllers would be very thin. With this creating a real REST API would just be a matter to create new controllers using the same Services my frontend controller classes do.
For internal logic like business rules it would be useful to have Entities (clear interfaces) instead of arrays from repositories. This way I could benefit from defining some methods that did some logic based on attributes. BUT If I would be using Doctrine2 and my repositories would always return Entities my application would suffer a big performance hit!!
One data structure ensures performance but no clear interfaces, the other ensures clear interfaces but bad performance when using a Data Pattern pattern like Doctrine 2 (now or in the future). Also I could end up with two data types which would be confusing.
I was thinking something similar to this flow:
Controller (thin) → UserService (incl. validation) → UserRepository (just storage) → Eloquent ORM
Why Eloquent instead of Doctrine2? Because I want to stick a bit to what’s common within the Laravel framework and community. So I could benefit from third party modules, for example to generate admin interfaces or similar based on models (bypassing my DDD rules). Other than using third party modules, I would design my core stuff so switching should always be easy and not affect data structure choices or performance.
Eloquent is an activerecord pattern. So I would be tempted to convert this data to POPO’s like Doctrine2 entities are. But nope... as said above, with doctrine2 real models would make the system very fat. So I fall back to simple arrays again. Knowing this would work for both and any other implementation in the future.
But it feels bad always rely on arrays. Especially when creating internal business rules. A developer would have to guess values on arrays, have no autocompletion in his IDE, could not have special methods like in Entity classes. But making two ways of dealing with data feels bad too. Or I am just too perfectionist ;) I want ONE clear data structure for all!
Building interfaces and POPO’s would mean a lot of duplicate work. I would need to convert an Eloquent model (just a table mapper, not entity) to an entity object implementing this interface. All is extra work. And eventually my last layer would be just like a API, thus converting it to arrays again. Which is extra work too. Arrays seem the deal again.
It seemed so easy reading up into DDD and Hexagonal. It seems so logic! But in reality I struggle with this one simple issue trying to stick to OOP principles. I want to use arrays because it’s the only way to be 100% sure I am not depended on any model choice and querying choice from my ORM regarding performance etc and don't have duplicate work in converting to arrays for views or an API. But there's no clear contract on how a user array could look. I want to speed up my project using these patterns, not slow them down :-) So not an option to have many converters.
Now I read a lot of topics. One makes POPO’s & interfaces that conform proper entities like Doctrine2 could return, but with all the extra work for Eloquent. Switching to Doctrine2 should be fairly easy, but would impact performance so bad or one would need to convert Doctrine2 array data to these own entity interfaces. Others choose to return simple arrays.
One convinces people to use Doctrine2 instead of Eloquent, but they leave out the fact that Doctrine2 is heavy and you really need to use array results for read only operations.
We design repositories to be changeable right? Not because it’s “nice” by design only. So how could we rely on full Entities if it has such big impact on performance or duplicate work? Even when using Doctrine2 only (coupled) this same issue would arise due to its performance!
All ORM implementations would be able to return arrays, thus no duplicate work there. Good performance. But we miss clear contracts. And we don’t have interfaces for arrays or class attributes (as a workaround)... Ugh ;)
Do I just miss a missing block in our programming languages? Interfaces on simple data structures??
Is it wise to make all arrays and have advanced business logic talk to these arrays? Thus no classes with clear interfaces. Any precalculated data (normally would be returned by an Entity method) would be within an array key defined the Service class. if not wise, what’s the alternative considering all of the above?
I would really appreciate if someone with great experience in this “domain” considering performance, different ORM implementations, etc could tell me how he/she has dealt with this?
Thanks in advance!
I think what you are dealing with is something similiar I'm struggling with. The solution I'm thinking works best is:
Entities/Repositories
Use and pass around Entities always when performing Write operations (Creating things, Updating things, Deleting things, and complex combinations thereof).
Sometimes you may use Entities when doing Read operations (when you anticipate the Read might need to be used for a Write soon after...ie. ->findById is soon followed by ->save).
Anytime you are working with an Entity (whether it be Write or Read), the Repositories need to be the place to go. You should be able to tell new developers that they can only persist to the database through Entities and the Repository.
The Entities will have properties that represent some Domain Object (many times they represent a database table with the fields of a table, but not always). They will also contain the domain logic/rules with them (ie. validation, calculations) so they are not anemic. You may additionally have some domain services if your Entities need help interacting with other Entities (need to trigger other events), or you just need an additional place to handle some extra domain logic (perform Repository calls to check for some unique conditions).
Your Repositories will solely be for working with Entities. The Repositories could accept Entities and do some persistence work with them. Or they could accept just some parameters, and do some reading/fetching into full Entities.
Some Repositories will know how to save some Domain Objects that are more complex than others. Perhaps an Entity that has a property which contains a list of other Entities that need to be saved along side the main entity (you can dive deeper into learning about Aggregate roots if you want).
The interfaces to Repositories rest in your Domain layer, but not the actual implementations of those Repositories. That way you can have an Eloquent version or whatever.
Other Queries (Table Data Gateway)
These queries won't work with Entities. They'll just be accepting parameters and returning things like Arrays or POPO's (Plain Old PHP Objects).
Many times you will need to perform Reads that do not return nicely into a single Entity. These Reads are typically more for reporting (not for CRUD-like operations, like Reading a user into an edit form that is eventually submitted and saved). For example, you might have a report that is 200 rows of JOINed data. If you used the Repositiory and tried to return large deep objects (with all the relationships populated, or even lazy-loaded) then you are going to have performance issues. Instead, use the Table Data Gatway pattern. You are just displaying data and not really needing OOP power here. The outputted data could however contain ID's, which through the UI could be used to initiate calls to Repository persistence methods.
As you are developing your app, when you come across the need for a new Read/Report query, create a new method in some class somewhere in your Table Data Gatway folder. You may find you have already created a similar query, so see how you can consolidate the other query. Use some parameters if necessary to make the gateway method's queries more flexible in particular ways (ie. columns to select, sort order, pagination, etc.). Don't make your queries too flexible though, this is where query builders/ORMs go wrong! You need to constrain your queries to a certain extent to where if you need to replace them (perhaps a different database engine) then you can easily perceive what the allowed variations are and aren't. It's up to you to find the right balance between flexibility (so you have more DRY code) and constraints (so you can optimize/replace queries later).
You can create services in your Domain to handle receiving parameters, then passing them to the Table Data Gateway, and then receiving back arrays to do some more mutating on. This will keep your Domain logic in the domain (and out of the infrastructure/persistence layer of the Repository & Table Data Gateway).
Again, just like the Repository, use interfaces in your domain services so that the implementation details stay out of your Domain layer, and resides in the actual Table Data Gateway folder.
I'm in the process of designing a system that stores entities and their relations over time.
Each entity has properties, each property should be versioned, so when a property of the entity changes, a new history state gets added. The complexity comes with the fact that I also need to version the relations between the separate entites. For example: when entity A moves from parent X to parent Y, the relation of both entities also gets a new history state.
I'm looking for advice on how to design this on a lower level - are there any design patterns available for this sort of thing, or any other best practices/proven methods?
I'm building this in PHP with a PostgreSQL database, optionally using Doctrine as the ORM/DBAL.
I would recommend looking into the table_log extension (https://github.com/psoo/table_log) for this. It does require compiling but it has the advantage of allowing you to restore tables to a previous state, audit changes, etc.
One important detail here is that the history changes are stored in other tables, not your main tables, so you think of it as current data plus external audit trails. If you need to merge them for a query, you could create a view.
I'm learning my ways with Symfony2 while building a small eshop for a family-run wine importer. Slowly I'm gaining understanding of the Symfony2 concept but while moving on to building a shopping cart, I'm not quite sure what would be the correct (at least according to the Sf2 standards) way to implement this.
What I'm looking for is a simple Basket storing BasketItems and their amount in sessions and later use this data in the checkout. Now before I go and glue this somehow together, I'd like to hear an advice on how this should be done and separated correctly.
So far, I've created the two as entities and now I'm not sure if I should put the logic directly in the Entity classes or Repositories or where preferably?
I hope this is not a too wide question. I'm well aware of the fact that a truly robust shopping cart implementation is no small job.
On a sidenote, are there already some proven and working shopping baskets for Symfony2 around?
The general rule when creating Entities and Repositories is that an Entity class should contain the logic needed to operate on a single Entity, and Repository classes contain the logic needed to operate on groups of Entities.
A simple example:
If you wanted to convert the price of an item from dollars to euros, you would have BasketItem::convertCurrencyTo($currencyType). This is code that operates on a single Entity.
If you wanted to find all BasketItems whose price is between $10 and $20, you would use BasketItemRepository::findByPriceRange($min, $max). This is code that operates on a group of Entities.
IMO, things can get a little confusing when dealing with Entities that have a one-to-many or many-to-many relationship. I would imagine that one Basket has many BasketItems, and one User has one Basket. Therefore, I think it's reasonable to assume that in order to fetch the BasketItems a User is interested in, you could do something like this:
$user->getBasket()->getBasketItems().
Note that there is no Repository being used in this example because it's a very basic query. If you needed to do something more specific, like find the BasketItems a User is interested in that happen to be on sale, you could use something like BasketItemRepository::findWhereOnSaleForBasket($BasketId). There's nothing stopping you from adding a similar method directly to the User or Basket classes, but I feel that because your query's main 'target' is a BasketItem, it belongs in that Entity's Repository class.
You mention that implementing a shopping cart is no small task, and you're right. But the questions you're asking aren't really limited to Symfony2 (in this case it's more about Doctrine 2), so I think it might be helpful if you check out other open source shopping carts and study what they're doing. I think the only impact Symfony2 would really have is forcing you to decide how to split up your code within bundles.
Hope this helps!
There is an ecommerce bundle available called Vespolina which also provides a cart.
I have recently been looking at the Repository Pattern as a way of brushing all the details of persistence under the carpet where the client code is concerned. While reading around it appears that a Repository is/can be [usually?] responsible for aggregates rather than just straight-forward classes.
This make sense to me as you could have a class defining Posts and another defining Comments. This makes an ideal candidate for an aggregate since the two are very closely related. However, how would I represent a Users class and its relationship with his or her Posts?
Would it make sense to aggregate Users with the Posts/Comments aggregate, or keep Users by itself and simply have an association via a good old fashioned reference?
I have tried looking for the answer myself using Google, but a lot of the examples I find are just stand-alone. ie, Posts/Comment or maybe Order and OrderLine etc. I can't find anything that shows how other related classes fit together.
I am not applying this to anything specific, though PHP or Java/C# would probably be the area I would look to using these ideas. In any case I am just exploring and trying to get my head around some of these ideas and concepts before I run off and create a monster. :)
Thank you for your time.
The Repository Pattern is fairly loosely defined and does not necessarily have any relationship to the Aggregate Pattern. However, if you subscribe to the DDD way of doing things, then yes, repositories are unique to aggregates.
So let's have a look at this from the DDD point of view. DDD says that objects within an aggregate can have a reference to another aggregate root, but objects within an aggregate can only be accessed via the root. The rule of thumb for determining aggregates is what should be deleted when deleting the root. However, DDD discourages the use of relationships more than most methodologies saying that just because a relationship exists in a domain, it does not need to exist in your model of the domain, so just keep that in mind.
In your case, when you delete a post I assume that you would also delete the comments, but not the user who created the post or users who commented on it. Therefore, you are correct in defining the post/comment aggregate, but it would not make sense to group users into that aggregate.
Users, being its own aggregate, can contain a relationship to all of their posts, because Post is the aggregate root. You could also implement this a method on the PostRepository to get all of the posts by a given user. Hope that helps!