I'm done DDD for a couple of years now and still its challenging when it comes to designing Aggregates. Thats the fun part of DDD and it makes your head spin. I'm asking this question since I'm architect in a project and we're in the middle of designing the model. Its an iteration when model evolves parallel with GUI and requirement gathering together with customer.
Now to the problem. Our scenario is that we are facing some Aggregates that are growing into very large AR's. I think I'm good at finding Value objects and avoiding the anemic domain model trap. But I've never been in this situation.
One example is that our system should represent a mobile telecom antenna. The antenna is located on a green field. But the antenna can have a shelter with equipment. Antenna can have microwave links, it can have fiber lines in ground, it can have radio elements, it can have power supply. Face it. If Antenna is terminated... all these dependencies are removed as well. Since they are part of the installation (except for the green field :))
But You get the picture. The antenna model is complex... And large AR's are inflexible regarding to concurrency locks, performance, memory consumption.
After reading Vaughn Vernons very good paper on Effective AR design http://dddcommunity.org/library/vernon_2011/ I realize that We need to start chopping our big AR's up in pieces.
My Idea is to do like Vernon suggest to move out for example MicrowaveLinks to a separate AR (even if its not in reality).
The MicrowaveLink Entity, now AR, is reference Antenna by Id. In MicrowaveLink Entity class we have a value object property that is AntennaId.
Our Uses cases support this scenario. We rarely list antenna and links together. So loading MicrowaveLinks is possible through a MicrowaveLinkRepository.ListByAntenna(Guid antennaId)
1) Have you done this AR split before and how did you do it?
2) Did you manage to support this AR --> AR relationship intact through both domain constraints and DB (we use EF 5 as ORM)?
My optimal goal is to be able to skip a Antenna.Microwaves Collection on Antenna. So Antenna are not aware if Links. The Links are aware of what Antenna they are mounted on.
And At MicrowaveLink Entity I only want a AntennaId Property, with hopefully, a DB Constraints that make sure that Antenna exists.
I'm aware of that I can manually add FK constraints in Seed method in EF or in DB directly through T-SQL scripting. But can this relationship be supported in some way by EF5 Code First Fluent mapping?
By the sounds of it you have an Installation AR. When requiring an AR in another you should model the contained AR as a only the ID in the container or a VO if required.
You need to have hard edges around your ARs.
Back to the Order / OrderLine example :)
An OrderLine seems to 'require' a Product but you shouldn't ever give a Product instance tot eh OrderLine. Instead only model, say, the ProductName and ProductId as a VO in the OrderLine. Now you have a distinct edge to your Order AR.
Hope that helps somewhat.
Related
I have an ERD Diagram of an E-commerce with the following entities Product , Tag , ProductTag,Category and other entities of course.
I tried to convert it into class diagram as follows:
1- removed the id
2- converted the foreign key into object of the type i'm refering to(product_id converted into => product: Product)
my question is , is this good approach to follow on all my entities? does it like achieve the SOLID principle? I have a presentation in 2 days and I want to be very sure of what I have made , any comment or modification would be really enough .I also chose these tables because they represent one to many and many to many. thanks in advance.
Basically your approach is correct. It's just a couple of UML specifications you got wrong.
The label in the middle of the connectors is just the name of the connector. Unless you do some OCL wizardry this name is meaningless. There is a way to adorn it with a black triangle to show the reading direction. This sometimes helps business people to understand how classes are related to each other (see Fig. 11.27 on p. 202 of UML 2.5). But usually you would not use it.
The shared aggregation has no semantics (p. 110 of UML: Indicates that the Property has shared aggregation semantics. Precise semantics of shared aggregation varies by application area and modeler.). So leave the open diamond away. Composite (filled diamond) can be used to show responsibility (when I'm killed I will kill my composites first). Usually it adds too little to be really useful, it only heats up the futile composition-discussion.
The navigation-direction is incorrect. The AC in the middle sees both connected classes so it's shown without any arrow. If you have an additional (directed) association you place it as lone (extra) connector. In that case put role names towards any end. That makes navigation clearer than just a simple arrow. I for myself use arrows only on rough sketches on the drawing board.
P.S. Just noticing that you have operations in your classes that have the same name as the class and take one paramter being also the class. I would guess you intend to show a constructor here. In that case you would make it Classname():Classname and provide only the paramaters that are needed for the constructor. Else these opreations don't seem to make much sense. Similarly the CRUD operations seem to work on a list of 'itself' which is also probably not desired. You would have a collection class which handles the base class where these operation make sense. So to summarize: you would only add getter/setter operations for the (private) properties matching the columns from your table.
P.P.S.: As per Christophe's comment it's a good idea to adorn the class instantiation operation with a <<create>> stereotype which highlights its purpose. See p. 196 of UML 2.5:
This stereotype is part of the standard (see p. 677) and the table on p. 678 states:
Specifies that the designated feature creates an instance of the classifier to which the feature is attached.
On the modeling part of your question, there’s already a perfect answer. For the records, I’d nevertheless like to add a complementary answer on the SOLID part:
Single responsibility: your classes have more than one reason to change, because you may want to change Product for what it is (e.g. add more product-related attributes), but you may also want to change the class to add new getByXxx() operations to find products in the database based on other criteria, independently of what a product really is. SO it's not complying.
Open-closed principle: we cannot tell
Liskov substitution principle: in absence of inheritance, this is not relevant. Moreover, you couldn't tell without having precondition, postcondition and invariant constraints.
Interface segregation principe: is probably not compliant, because you impose an implicit interface that all inheriting class would have to provide, even if they don't need it (e.g. products not stored in a database). A first step in the right direction, would be to use an interface for the common database operations.
Dependency inversion: we cannot tell but probably it isn't , because update(), delete(),... probably depends on some database, so that you can't switch it to another database. With DIP, you'd inject the database in the class that use it, so that you could at any moment inject another database that offers the same interface.
You didn't ask, but your design seems to correspond to active records. If you want to go for a cleaner, more SOLID design, you should prefer factor out the database related code to either repositories or table data gateways.
I’m build a calendar/entry/statistics application using quite complex models with a large number of relationships between models.
In general I’m concerned of performance, and are considering different strategies and are looking for input before implementing the application.
I’m completely new to DBContextPooling so please excuse me for possible stupid questions. But has DBContextPooling anything to do with the use of multiple DBContext classes, or is the use related to improved performance regardless of a single or multiple DBContext?
I might end up implementing a larger number of DBsets, or should I avoid it? I’m considering to create multiple DBContext Classes for simplicity, but will this reduce memory use and improve performance? Would it be better/smarter to split the application into smaller projects?
Is there any performance difference in using IEnumerable vs ICollection? I’m avoiding the use of lists as much as possible. Or would it be even better to use IAsyncEnumerable?
Most of your performance pain points will come from a complex architecture that you have not simplified. Managing a monolithic application result in lots of unnecessary 'compensating' logic when one use case is treading on the toes of another and your relationships are so intertwined.
Optimisations such as whether to use Context Pooling or IEnumerable vs ICollection can come later. They should not affect the architecture of your solution.
If your project is as complex as you suggest, then I'd recommend you read up on Domain Driven Design and Microservices and break your application up into several projects (or groups of projects).
https://learn.microsoft.com/en-us/dotnet/architecture/microservices/microservice-ddd-cqrs-patterns/
Each project (or group of projects) will have its own DbContext to administer the entities within that project.
Further, each DbContext should start off by only exposing Aggregate Roots through the DbSets. This can mean more database activity than is strictly necessary for a particular use case but best to start with a clean architecture and squeeze that last ounce of performance (sometimes at the cost of architectural clarity), if and when needed.
For example if you want to add an attendee to an appointment, it can be appealing to attack the Attendee table directly. But, to keep things clean, and considering an attendee cannot exist without an appointment, then you should make appointment the aggregate root and only expose appointment as an entry point for the outside world to attack. That appointment can be retrieved from the database with its attendees. Then ask the appointment to add the attendees. Then save the appointment graph by calling SaveChanges on the DbContext.
In summary, your Appointment is responsible for the functionality within its graph. You should ask Appointment to add an Attendee to the list instead of adding an Attendee to the Appointment's list of attendees. A subtle shift in thinking that can reduce complexity of your solution an awful lot.
The art is deciding where those boundaries between microservices/contexts should lie. There can be pros and cons to two different architectures, with no clear winner
To your other questions:
DbContext Pooling is about maintaining a pool of ready-to-go instantiated DbContexts. It saves the overhead of repeated DbContext instantiation. Probably not worth it, unless you have an awful lot of separate requests coming in and your profiling shows that this is a pain point.
The number of DbSets required is alluded to above.
As for IEnumerable or ICollection or IList, it depends on what functionality you require. Here's a nice simple summary ... https://medium.com/developers-arena/ienumerable-vs-icollection-vs-ilist-vs-iqueryable-in-c-2101351453db
Would it be better/smarter to split the application into smaller
projects?
Yes, absolutely! Start with architectural clarity and then tweak for performance benefits where and when required. Don't start with performance as the goal (unless you're building a millisecond sensitive solution).
I work in cattle production and I am learning about database design with postgreSQL. Now I am working on an entity attribute relationship model for a database that allows to register the allocation of the pastures in which cattle graze. In the logic of this business an animal can be assigned to several grazing groups during its life. Each grazing group in turn has a duration and is composed of several pastures in which the animals graze according to a rotation calendar. In this way, at a specific time, animals graze in a pasture that is part of a grazing group.
I have a situation in which many grazing groups can be assigned to many animals as well as many pastures. Trying to model this problem I find a fan trap because there are two one-to-many relationships for a single table. According to this, I would like to ask you about how one can deal with this type of relationship in which one entity relates to two others in the form of many-to-many relationships.
I put a diagram on the problem.
model diagram
Thanks
Traditionally, using a link table (the ones you call assignment) between two tables has been the right way to do many-to-many relationships. Other choices include having an ARRAY of animal ids in grazing group, using JSONB fields etc. Those might prove to be problematic later, so I'd recommend going the old way.
If you want to keep track of history, you can add an active boolean field (to the link table probably) to indicate which assignment is current or have a start date and end date for each assignment. This also makes it possible to plan future assignments. To make things easier, make VIEWs showing only current assignment and further VIEWs to show JOINed tables.
Since there's no clear question in your post, I'd just say you are going the right way.
We often encounter class models, in UML modeling, that state a 1 x 1 or 1 x 1..* or 1..* x 1 or 1..* x 1..* association between given classes.
Take the example: Player 1..11 x 1 Team.
Wouldn't that impose a practical problem, in which it wouldn't be possible to determine what comes first: the team or a player?
In the example, a team would need a player, at least, to exist, while a player, to exist, needs the team.
Am I misinterpreting something?
Trying to implement it, you wouldn't be able to instantiate a Team, because you'd need at least one Player, and if you try to instantiate the Player, the Team would be missing.
How are 1 x 1 associations possible?
Thank you for your time!
When a model as a 1..11 relationship (Team - Player) there is no "what comes first". There need to be 11 Players and these can be connected to one Team. Only when the connections are all made you have a complying model. You can point out that players form a team by adding a composition. But usually from a programming aspect this does not add much semantics. You need to have the instances anyway in order to create the connections. So the Team will likely have an array of 11 Players and in order to work, none of them must be Null.
The same goes for 1..1 relations (plug/socket). Only when they are connected you have a complying model. From a modeling perspective a 1..1 is often used if you need a rucksack for one of the two classes. Then you bind another one with separate information. This can then be used together with other classes which are only interested in this contents and not the carrier itself.
You are correct. You must satisfy all the constraints somehow. Either create everything at once or relax your constraints. For example, a team can still exist as a team without any players, but a team must exist for a player to join it.
Your question "How are 1 x 1 associations possible?" refers to the issue of mandatory mutually inverse references, or, in DBMS jargon, cyclic foreign keys, which may indeed create an object/row creation or update problem in a data management app or its underlying database (DB).
There are two approaches how to deal with it: 1) Relax the mandatory reference constraint in at least one direction, 2) Allow intermediate app/DB states that do not have to satisfy the constraint.
1) While we know that in reality a team always includes more than zero players, we may choose not to implement this constraint for pragmatic reasons, such that we can more easily create a team data object (or DB row) without immediately assigning player objects/rows to it.
2) In our app, we may allow an intermediate state where a team has been created without any players assigned to it, and correspondingly in the underlying DB, we may instruct the transaction manager that the foreign key constraint is only checked when the entire transaction (consisting of first creating an empty team, then creating 11 players, such that each of them is assigned to the team and the team is assigned to them as their team) is completed. This can be achieved with the SQL clause DEFERRABLE INITIALLY DEFERRED, see the section Cyclic Foreign Keys of the post "Deferrable SQL Constraints in Depth".
It depends what kind of model it is. A UML model might be a model of the real world, e.g. a human hand has 1:1 relationship with a human arm. This 1:1-association models a biological fact (ignoring disabilities).
A UML model might also be a model of the functionality of an application. If the application enforces that every team has 11 players and every player has one team (e.g. they are all created at once by filling out a form with a "Save"-button), then the 1:11-association correctly models the functionality of the application.
A UML model might also be a technical model of classes in some programming language or tables in a database. In that case, the 1:1-associations are only possible if your programming language or database system allows creating the instances on both sides simultaneously, or at least in the same transaction.
Side note: When modeling teams and players, you might consider an association between Team and Person, with multiplicity 0..* and role name 'player' on the Team side.
I've been reading a lot about Entity Frameworks and now I want to implement it on my game. An Entity Framework is based on making the game entities simple containers of Components, where a Component contains a certain characteristic of an Entity (and all the variables/accessors which describe this characteristic).
The game logic is then modularized by creating Systems. Each System implements and runs a certain aspect of the game logic (eg. Collisions, Rendering, Animation). Each System has to be able to access every Entity which has some certain combination of Components (eg. RenderSystem has to get only Entities which have PositionComponent and AnimationComponent).
My question regards the best data structure for achieving such functionality.
My current idea is to create a Vector (with N cells, where N is the number of possible components) of List of Entity. So whenever I create (instantiate and add certain Components) an Entity, I would also reference this Entity from each List for each Component it contains. "Killing" an Entity would require removing each reference from each List. The problem would be querying which entities have to be processed by a certain System, because the search-key would be a combination of Components, and not a single Component, adding overhead to the operation (many searches and comparisons would have to be done).
Is my idea good? Is there any better data structure I can use? Note that everything in the game is supposed to be an Entity, summing up to thousands of Entites on a single Level (I could possibly use some space partitioning).
They are two ways of doing it,
The purely data oriented system would lead you not to have an Entity class but just components sharing an ID. In this case, a vector or a hashmap for every system wouldn't be a problem as the search in these data structure is fast. If you want several components per system per entity you can aggregate your components in one data structure adapted for each system.
The problem is that a pure data oriented system can be less usable than a more pragmatic approach where you keep all the features of the previously described system but you keep an entity class that holds reference to his components (or aggregated components structures) of every system. Processing an entity (deleting or inspecting it) becomes much easier as you still have a place where all the information about what the entity is, i.e. what it is made of and not what state it is in, can be found in one place instead of querying every system.
In your case, the best thing is to try... It's quite easy and fast to implement a rough engine in the two ways, and once you've played with the two you'll be able to decide which one suites you better.
This article is valuable as far as it suggests 4 iterations for the data structure, but no one is a good solution in my opinion. But I recommend to read it, because there is a detailed analysis of the problem, nice estimations in terms of memory and such other good material.