DEV Community

Discussion on: Avoid anemic domain models by empowering your objects

Collapse
 
dubyabrian profile image
W. Brian Gourlie

Your article illustrates a problem that is hard to model nicely in classic OO, requiring a bunch of nuanced code to overcome these shortcomings. I'd argue that inter-mixing data and "process" is a consequence of these shortcomings.

Since you're using C#, I'll illustrate how this problem would be more appropriately modeled in F#. We'll start by modeling a type that encodes the activity date:

type ActivityDate = 
    | ArbitraryDate of DateTime
    | Today
Enter fullscreen mode Exit fullscreen mode

Here we've declared a sum type (aka discriminated union) that encodes all the information necessary to determine if the activity date is EITHER an arbitrary date, OR a value that indicates that the user is filtering on today's activity. Now we'll define the actual domain model:

type ActivityFilter = { activityDate : ActivityDate; /* Hiding the other properties */ }
Enter fullscreen mode Exit fullscreen mode

As you can see, we require one fewer properties than the C# example in order to convey the same amount of information.

Take a moment to consider how much code was required in the C# examples to determine the actual date we need to filter on. Here's how that would look in F#:

let getFilterDate activityDate = 
    match activityDate with
    | ArbitraryDate date -> date
    | Today -> DateTime.Now.Date
Enter fullscreen mode Exit fullscreen mode

In a grand total of 8 lines of code, we've modeled the same problem in a much cleaner, more straightforward way. Debating where the methods that operate on our domain models should live is largely an exercise in bike shedding. Instead, we should be asking if the languages and paradigms we use are anemic.