2

The question title is not good, but I couldn't think of a way to word it better.

I am used to develop using POCO classes in my projects, that is, domain objects contain absolutely no logic, only data.

I am wondering which is the best approach when dealing with class relationships - to put a collection inside the class or to request it later.

For example, consider we have an e-commerce application, that has Orders, and Items inside those Orders. So we could have (pseudo-code)

class Order
{
     int id;
     List<OrderItem> Items;
}

class OrderItem
{
     Product product;
     int quantity;
}

And then use it (1)

var o = LoadOrder(id);
foreach (var i in o.Items) {

...or we could do:

class Order
{
    int id;
}

And use it this way: (2)

var odr = LoadOrder(id);
var itms = LoadItemsOfOrder(odr);
foreach (var i in itms) { 
    .....

The first way is more compact and more "OOP-ish", but the second way gives more control on how and when items are requested, e.g. what if now I need to request only the items that have quantity > 3 ? And what if I don't use the Items collection at all (e.g. to display only a list of orders) - I will be doing unnecessary queries to the database.

In my older, big projects I've gone with a hybrid approach - the domain classes are of the first flavor but there are various "load" methods, like "LoadOrder" and "LoadOrderWithItems" or "FillOrderObject".

Now I am working on a small, toy project, no customers and crazy deadlines and got time to think on these issues.

I tried searching the web but it is very hard to find a POCO answer not related to Entity Framework. (I am not working in .net this time, but would like to apply these concepts.)

Question: is there a method which is clearly better than the other, or both are valid and "it depends" on my project, if I am aiming for performance or for code clarity and maintainability?.

2
  • Which ORM are you using?
    – Euphoric
    Commented May 3, 2014 at 6:17
  • @Euphoric None :) I am starting with in-memory arrays to test if the concept works, and then going implement a real database later. That's my point too: which way is the better independently of ORM? I saw POCO being promoted as "persistence-ignorant objects", something that should not depend on any specific ORM... Is that wrong? Do I need to settle on an ORM before coding my models? Commented May 3, 2014 at 10:47

3 Answers 3

2

It's never okay to satisfy hypothetical performance goblins at the expense of fewer lines of code or an API that more clearly expresses the relationship between entities.

So, the first example is preferred. Any decent ORM should be able to lazy-load the collection, and some of the more advanced ones will even let define a property on an entity with a custom loading function, also lazy-loaded. That takes care of both of your use cases without breaking encapsulation of the Order class and exposing its inner data structure.

1
  • 1
    Fair point. I am really inching towards the first approach now. Commented May 3, 2014 at 16:39
2

From the TDD point of view I would prefer pocos with collections over having specialalized LoadSubItems methods because it is much easier to create a testOrder with one orderitem than to mock a databaseLoadMethod to implement a test for a order processing service.

1
  • Good point. Seeing things from a TDD point of view is a nice way to think about these kind of problems. Commented May 3, 2014 at 15:04
0

I am used to develop using POCO classes in my projects, that is, domain objects contain absolutely no logic, only data.

First off, your objects should not be only data. Behavior is central to you domain, and thus your domain objects should contain behavior logic. If anything they should contain all your behavior logic.

Domain objects that are just data would be what Martin Fowler calls an anemic domain model

POCO simply means you don't create your objects in your domain model with dependencies to external libs or frameworks. You don't make your classes all children of FunkyORMLibrary7 or something. The objects should be plain old objects that can be run without any external modules being loaded, this reduces dependency and also makes them easy to test in isolation. But that doesn't mean no logic in them, quite the opposite.

I am wondering which is the best approach when dealing with class relationships - to put a collection inside the class or to request it later.

You should be restricting who has responsibility to send messages to Order Item objects based on responsibilities. Who is responsible for ensuring the integrity of the who order including all the items in an order. In both your examples you are pulling order items out of the Order that contains them and operating on the items independently. That, in most cases, is a bad idea.

Think of a real world example. If you worked in a company would you let anyone in the company alter the information on an order document? I would imagine not, you would end up with a situation where the janitor just turned an order for 5 iPhones into an order for 50 million iPhones.

Some where you will need domain logic that controls what is or isn't valid actions to take on an order item. Only the object that contains this logic should be allowed operated on order items.

It makes far more sense that Order Items are accessed only through the Order object that contains them, since this is probably where all that logic will be held. In this case neither of your examples works. The for loop that is in both examples should be in the Order object, not outside of it and nothing should be able to iterate over the order items other than the order object itself.

Unless you have a very very good reason for accessing an individual order item outside of the order that contains it the rest of your system shouldn't be able to access the order item outside of the order that contains it. That is the key notion of the principle of encapsulation in OO and of an aggregation root in DDD.

Again from Martin Fowler DDD Aggregate

A DDD aggregate is a cluster of domain objects that can be treated as a single unit. An example may be an order and its line-items, these will be separate objects, but it's useful to treat the order (together with its line items) as a single aggregate ... Any references from outside the aggregate should only go to the aggregate root. The root can thus ensure the integrity of the aggregate as a whole.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.