Ok...so I've gotten way behind. The 4-day immersion class finished today and I'm just getting to day two. Also, the days have blurred together a bit, so I'll try to get it all straight. If you haven't read my earlier blogs, DDD Immersion is a training class on Eric Evan's book Domain Driven Design.
Before I get started on the topics covered in the training, I'd like to mention a couple of interesting things that I've noticed. First of all, although DDD is not really a methodology, and therefore not an Agile methodology, I believe that almost all of its core principles are founded on the same principles. Not only is evidence of that found in its teachings, but also in the make-up of its students. It was quite interesting to see the mix of people that attended this class. Every one of us thought alike...well, perhaps not thought alike, but we all shared the same principles and that made our thoughts compatible. It seemed that most everyone in the class (if not everyone) was either already working in an agile environment or were striving to make their environment agile.
Anyhow, back to the class. The three main topics that we discussed on day two (or at least the three that are still paramount in my mind and notes) were: Aggregates, Entities, and Value Objects. At first I was having a really hard time understanding Aggregates, however, after a little more study I think I am starting to understand them...and their value. I'll come back to aggregates in a minute. First, lets talk about entities and value objects.
Just about any class in a project that is not a UI specific class or a service (meaning a class that exists only to perform some sort of operation and has no identity or data of its own) is either an entity or a value object. The difference between an entity and a value object is that an entity is individually identifiable (meaning it has something like and ID or a set of fields that, when combined, create a unique identifier). Entities also track state. Value objects, on the contrary, do not have an identity of their own nor do they track state. In addition, there is a cost that comes with tracking identity and state, so wherever possible we want to avoid creating more entity classes and instead create value objects.
Value objects can be freely and promiscuously shared across objects. This is because value objects are also, by definition immutable. Imagine a string which is also a value object an immutable. You don't hesitate to pass around a string from one object to another. If you say person2.FirstName = person1.FirstName and then you change person1.FirstName, you know that won't affect person2 because FirstName is a string, and is therefore immutable so each object has its own copy. But, immutability for our own objects, doesn't just happen, we have to actually put thought and effort into making our value objects immutable. For example, instead of instantiating a value object and then setting its properties, you would set create it all at once with a constructor (otherwise, every time you change a property you'd have to actually be creating a whole new object in memory. Also, once created, if you want to modify the object, you will actually need to create a whole new copy. This sounds like extra work, but it's actually quite liberating when you understand the benefits.
So, lets look at an example. An example (which is in the DDD book) of these two types of objects is Cargo, Itinerary, and Legs (not human legs, legs of an itinerary). These objects (I should stop using the term classes, since we want to be able to speak about these things in a way the business user also understands) are used within a shipping company model. Consider this scenario...a piece of cargo needs to be shipped from Hong Kong (HKG) to Dallas, Texas (DAL). In order for that to happen it will also have to make a stop at a port city such as Long Beach (LGB).
So you can imagine, a piece of cargo has an itinerary and that itinerary is made up of two legs: HKG to LGB and LGB to DAL. So, I've just described three objects (Cargo, Itinerary and Leg). Which of these has to be an entity and which ones can we make into value objects? Clearly cargo will need to be an entity because it has identity. One piece of cargo is different from another piece of cargo, even if everything about it (other than the ID) is the same. That's because we need to track the delivery of each piece of cargo separately and make sure they arrive at their respective destinations.
So, can we make Itinerary and Leg both value objects? That really should be our goal. We want as many of our objects as possible to be value objects. If a leg is just a starting point and an ending point, such as "HKG" and "LGB", then it can definitely be a value object. This is because the leg containing "HKG" and "LGB", can be used anywhere without consequence. We can feel free to share a leg with other objects because no matter where it is used it means the same thing and it has no identity or state. So we'll make Leg a value object.
Now, how about Itinerary? If itinerary is just going to contain a list of legs then it can certainly also be a value object. We could have a further discussion here about other things that could go into itinerary or legs such as tracking which legs have been completed, but it actually makes sense to move these tracking items up to the cargo object so that we can continue to leave itinerary and leg as value objects. And it actually makes sense for them to be on cargo anyhow.
Ok, phew! One more topic. Aggregates. An aggregate is essentially a grouping of objects. The definition Eric gave was "a clump of data that is completely internally consistent." In this case, Cargo, Itinerary, and Leg all belong within the same aggregate because they are so closely related and it is important that the data always remains consistent across these three elements. There is a rule regarding aggregates which is what gives aggregates all their power and benefits. This rule states that anything outside of the aggregate must access anything inside the aggregate via the "Aggregate Root". What is the aggregate root? It is the primary entity class at the top of the aggregate that is responsible for tracking the state of the whole aggregate (or something like that :) ). Like I said, this was an area that I struggled with for a bit in the training so I think I may have a few things a little unclear, but I believe, nonetheless that I have it clear enough that I could implement it. In our example, he Cargo object is the aggregate root. If I want to know anything about the cargo's itinerary, I have to ask the cargo object, I can't ask the itinerary object itself.
So here is where the power of aggregates comes in. Think about any project of significant size and complexity that you have worked on. Now consider all the inter-dependencies of all the objects in that project. Now think of that one really bad project you worked on where everything was just a big tangled mess (most of us have had that...um...opportunity). Aggregates help prevent this mess. By forcing everything outside of an aggregate to access anything inside the aggregate via the aggregate root, you significantly limit the number of inter-dependencies between classes. This is very helpful in keeping the state maintainable and bug free.
So there is a recap of Entities, Value Objects, and Aggregates. There is much more that could be learned than could be laid out in one blog post (or even ten blog posts). If you are intrigued and would like to learn more about it, read the book Domain Driven Design, by Eric Evans, or go to the DDD immersion training which you can find at http://www.domainlanguage.com/.
Sorry for the long posts. These are not concepts that can be explained briefly, nor completely in a blog post. But I have found them very valuable and I am excited to start teaching them to our team and our business users.
In my next post DDD Immersion - Day Three we'll learn about Context Mapping.
No comments:
Post a Comment