Something I see is prevalent in .NET (C#) projects is the abuse of DTOs (data transfer objects) and services.
DTOs (as per definition) just keep some data and the services keep all the logic, manipulating said DTOs. If a bit of logic doesn’t really feel like it belongs to some service, off we go to create some helper or extension to drop said logic in.
This way of doing things is much more procedural than object oriented, which would be the primary programming paradigm we’d like to use in C# projects, with some sprinkles of functional and, sure, procedural.
POCOs, DTOs and services
To start with, POCO means Plain Old Clr Object (being the original term POJO, referring to Java).
For a quick definition, I refer to Kevlin Henney’s tweet.
“Once more, with feeling: • POJO does not mean DTO. • POJO does not mean that a class has to be as dumb as rocks, with nothing more than getters and setters. • POJO means that a class is not tied to a particular framework, whether by inheritance or annotation.”
The definition of POCO is broad, and if we want to be completely clear on it, a service (as long as not dependent on anything framework specific) is also a POCO, but the category of classes I want to discuss here are normally smallish ones, that represent a simple concept.
Comparing with a DTO (that may also be a POCO itself), which by definition doesn’t really have logic, just groups data, a POCO doesn’t really have that restriction, having logic is welcome.
If we go back to the basics of OOP, data and behavior are meant to be grouped together, and by abusing DTOs and services we’re doing the exact opposite. This doesn’t mean we shouldn’t use DTOs and services, they have their place, just not everywhere 🙂.
A practical example
Let’s see an example. Imagine we want to represent a football (of the soccer kind 🙃) match score sheet with a class, named
The DTO version could be something like:
With class like this, the responsibility to set the team information correctly, initializing the goal information and updating everything is delegated to some service. As everything in the class is a property with getters and setters, any piece of code that gets a hand of an instance of the class can make some changes, possibly ignoring rules that apply to its behavior.
Instead, to make sure the score sheet concept’s logic is always applied, we can (should?) move it together with its related data.
Ignoring the fact that the logic could be better organized, the gist of it is that now the class contains the logic to interact with its data. The data can be accessed by external code, via its public getters, but it cannot be changed (private setters). All the changes go through the class logic, so if there is an incorrect interaction, the class will signal it, in this case through exceptions.
Instead of creating massive services that have all the logic, interact with DTOs that have no encapsulation, using POCOs to group data and behavior regarding specific concepts can make your code more cohesive, less error prone and easier to reason about.
Looking at the framework for examples
The framework itself is a great place to look for POCOs in the wild. There’s no shortage of examples, but let’s use a simple one, the
Uri class is a nice example of a pretty simple POCO, which if you’re using web applications (or at least making HTTP requests to APIs) you probably used it.
Instead of just using a
string, then having a bunch of functions somewhere to do URI related stuff, the
Uri class itself already exposes such functionality, besides storing the data related to a specific URI.
As a side note, the
Uri class is also great to use to fight primitive obsession, by avoiding passing around
The DDD connection
A thing I noticed is that as soon as I start talking about things like the
ScoreSheet class introduced above, some people immediately think “ah, you’re talking about DDD”.
I understand the reasoning, as much of the DDD literature shows implementation examples using object oriented languages, in which the recommended approach for implementing the domain concepts is through POCOs that represent the entities and value objects (would probably be different in other paradigms, namely functional).
So, sure, if you’re implementing something with DDD in an objected oriented language, you’re very likely using POCOs in the way I’m talking about, but you can also take advantage of this POCO approach even if you’re not doing DDD. A clear example is if you use the
Uri class previously discussed. The URI concept doesn’t need to be part of your domain to make sense to use it.
I’m certainly not the first one to write about this, having certainly learned a lot from other people that talked about it, but as it seems the prevalent practice is to abuse services and DTOs, I thought it wouldn’t harm to give it another push.
If you agree, “spread the word”! Friends don’t let friends DTO all the things! 😆
Thanks for stopping by, cyaz!