Source Allies Logo

Sharing Our Passion for Technology

& Continuous Learning

<   Back to Blog

The Danger of Carrier Objects

In the everyday world, it's usually a good thing to have what you need ahead of time, even if there's a possibility of never using it: I'm going to school, better pack my books; I'm taking a flight this afternoon, better bring some earplugs; I'm going to a meeting, better bring a notebook, and coffee... and my phone. If I don't end up using these things for the task at hand, no problem.

Unfortunately, this "eager preparedness" principle has found its way into software architecture everywhere. Developers start carrying around cobbled-together bits of information in an attempt to save later calls to expensive services or to make it easier to format output for consumer processes (like the UI or a document). Or because they are lazy. At the same time, the disparate bits of information lose their original purpose, which is to be a neat encapsulation of business information (e.g., the models). For example, consider the following two plain old classes. Employees are... employees. But every employee also has demographics, which is information such as ethnicity, age, gender, location, maybe some payroll information, and so forth. Together, these would form employment information for a particular employee.

public class Employee { /* ... */ }

public class Demographics { /* ... */ }

Some teams would combine these classes into a tuple/composite class at a service or data layer, calling it EmployeeDemographics probably. This is an acceptable solution, and quite easy to code early on in a project's life cycle. But suppose EmployeeDemographics wasn't coded, because there was no need early in the project for it. Now it's month 10 into a 12 month project and the system owners are asking for a screen where employees are listed by name along with a summary of demographics. To do that, you need Employee objects (which contain a name property) and the associated Demographics object for each Employee.

The developer who gets this task says to himself, "I ain't touchin' the data layer! Beaded handbags for me!" If you've ever seen the Harry Potter films you know that Hermione Granger, one of the protagonists, has a magic beaded handbag with no size limit. It can hold anything and everything. This poor developer resolves himself to use a magic handbag to cobble together the information he needs.

In the screen's view, he creates an innocent container class with properties for the employee and its demographics.

     public class EmployeeData {
    public Employee Employee { get; set; }
    public Demographics Demographics { get; set; }
}

Ah, but now the system owners want a little more. They want to see licensing information for truck drivers...

    public class EmployeeData {
    public Employee Employee { get; set; }
    public Demographics Demographics { get; set; }
    public bool IsTruckDriver { get; set; }
    public List Licenses { get; set; }
}

And after your impressive demonstration of the updated feature, the system owners-- all excited from the possibilities-- ask for way to see certifications for shipping accountants...

    public class EmployeeData {
    public Employee Employee { get; set; }
    public Demographics Demographics { get; set; }

    public bool IsTruckDriver { get; set; }
    public List Licenses { get; set; }

    public bool IsShippingAccountant { get; set; }
    public List ShippingAccountantCertifications { get; set; }
}

Once again your technical Paul Rowess woos the system owners and now they want a way to see hazardous materials clearances for freight workers...

    public class EmployeeData {
    public Employee Employee { get; set; }
    public Demographics Demographics { get; set; }

    public bool IsTruckDriver { get; set; }
    public List Licenses { get; set; }

    public bool IsShippingAccountant { get; set; }
    public List ShippingAccountantCertifications { get; set; }

    public bool IsFreightEmployee { get; set; }
    public List MaterialsClearances { get; set; }
}

I think you get the idea. All of this data is accumulated ahead of rendering time and stored in a carrier object-- EmployeeData-- to make it easier for the view (but not much else) to get at data during the rendering phase. But in reality, that's not true. Consider that the rendering complexity for the view will grow proportionally with the growth of the carrier object. If your project tests views, the size and number of tests will explode, too.

If the project uses MVC or some similar architecture, then there's bound to be a controller behind the view. If that's the case, then why use a carrier object? Isn't the controller intended to provide for the many needs of the view?

I need to step back here. I've written this article because I abuse carrier objects to no end. Probably because I use view models for my home projects, and I try to shoehorn the concept into my work projects which do not use view models. But after a lot of frustration dealing with a multi-month old design that I wrote to use carrier objects, I got sick of the increasing rigidity and complexity the carrier objects (and code) were taking on in order to meet new and ever-changing requirements. So, I begged my team to let me rewrite a certain feature because its was becoming a titanic boat anchor for productivity, progress, and quality on the project. When I got the clearance to do so, I hit Ctrl-A + Delete on all the feature's files and started over. I banned myself from using carrier objects and forced my view to always ask the controller for every piece of information separately. To go along with our story, as each row of a table was being bound to an Employee's name property, I'd make separate calls to the controller to load demographic data, licensing data, certification data, and materials handling data.

What happened? My view code was still huge, but it was neatly divided into isolated pieces where each unit of work was nothing more than reading the ID from the employee object and making a controller call. Complexity? Gone. Rigidity? Gone. Carrier object? Gone. And the best part? I actually enjoyed writing the tests for the view and its controller.

I'm not saying that carrying around encapsulated data is a bad thing. But it's like anything else in software development-- it can be abused.