Comments

Why I don’t like IEntity interfaces

One comment that keeps popping up in regards to my YouTube video about repositories (Repository Pattern, Done Right) is why I don’t like IEntity interfaces. So, let’s see.

The case for IEntity is to apply a constraint in the repository interfaces.

public interface IRepository<T> where T : IEntity 

I need to write another post about why you should avoid generic repositories. But for now, let’s just ignore it and focus on IEntity.

So, what’s the value of this constraint here? Does this force a developer from accidentally creating a repository for an integer?

public class IntRepository : IRepository<int>

Probably not! Those familiar with domain-driven design (DDD) argue that repositories are should be created for aggregate roots. So, this will stop a developer from creating a repository for an entity that is not an aggregate root, or a value object. So, perhaps it’s more accurate to call this interface IAggregateRoot (which is even worse than IEntity, as you’ll find out shortly).

With either IEntity or IAggregateRoot, a junior developer can bypass this “constraint” in just a second:

public class Money : IEntity
{
}

So, these marker interfaces don’t really stop anyone from creating a repository for the wrong type!

With these interfaces, every time you want to create a class, you need to write some additional code (noise) to mark it as an entity or aggregate. What is the value of this? I’ve never seen it! Hopefully, you can drop a comment and enlighten me.

What is an interface really?

An interface is a contract. When you declare an interface and implement it, all those implementations follow that contract. This gives you two benefits: extensibility and testability.

Think of the classic polymorphism example you read in your first object-oriented book.

IEnumerable<IShape> shapes = GetShapes();
foreach (var shape in shapes)
    shape.Draw(); 

Here, the type of the actual objects in our enumerable doesn’t really matter. We can “extend” this design, and define new shapes that implement this contract (IShape). At a minimum, they all will have a Draw method.

Another benefit of these contracts is that they help us mock dependencies of objects during unit testing. For example, we can unit test a controller or a service by providing a mock or fake repository. This way, we don’t need a database up and running to test the controller / service.

The case for IEntity

Look at this IEntity declaration. This is what I call a hollow interface.

public interface IEntity // or IAggregateRoot
{
}

What is the point of this interface? It’s an empty contract. What’s that supposed to mean “conceptually”? A contract that doesn’t enforce anything?! Really? Again, back to the first example, if you think by using these interfaces you prevent an inexperienced developer creating the wrong repository, you’re just fooling yourself.

Wait, I have a better solution!

Ok, Mosh, how about this interface?

public interface IEntity // or IAggregateRoot
{
    int Id { get; set; }
}

Not a hollow interface anymore! At least it enforces that every entity or aggregate root should have an Id, and that Id should be integer.

Wait… what if one of our entities needs a Guid as an Id?

Ok, what about IEntity<T>?

Here is another form of IEntity:

public interface IEntity<T> // or IAggregateRoot<T>
{
    T Id { get; set; }
}

This interface is even worse. Why? Look at how we use it:

public class Student : IEntity<int>

Read the code in plain English: class Student which is an entity of integer. What?! Entity of integer? (*my head spinning*).

Nonetheless, what value do you get from an interface like that? That every entity or aggregate root follows a contract? Would you be working with those IEntity or IAggregateRoot instances without caring what object is actually under the interface at runtime (like the polymorphism example I showed earlier)? Most likely not! You work with concrete types, like Student, Course, etc.

So, one more time, what’s the point of creating these contracts? To the best of my knowledge, nothing but extra noise in your code.

Unfortunately, interfaces are one of the least understood constructs of object-oriented programming languages. If you want to learn more about interfaces, check out my C# course: Classes, Interfaces and Object-0riented programming.

Tags: , , ,
Comments

Repositories or Command / Query Objects?

This is a follow up post to my YouTube video Repository Pattern, Done Right. If you haven’t seen this video, it’s best to watch it first, before continuing reading.

There have been many interesting questions in the discussion area and I’ve replied to most (if not all) of them. One that has come up a few times is:

Should we favour command/query objects over repositories?

A few have referred me to Jimmy Bogard’s post. So, in this post, I’ll be comparing these two approaches and pros / cons of each.

Before I get started, I need to emphasise: neither the repository pattern, nor command / query objects, are silver-bullets. Just because these architectural patterns exist, doesn’t mean you should use them in every single application. If your queries are simple enough (one or two lines), don’t worry about creating an abstraction over them. There is nothing wrong with writing them in your controllers (assuming a web application).

If you do, however, have fat queries that have bloated your controllers, you might want to consider one of these patterns to achieve “better separation of concerns”.

Repository vs Command / Query object

In a repository, we often have many methods, all related to a specific entity:

GetUpcomingGigs()
GetGigsIAmAttending()
GetMyGigs()
GetPopularGigs()

When you promote one of these methods to a class, you’ll end up with what we call a query object.


public class GetPopularGigsQuery
{
     private GigsContext _context;

     public GetPopularGigsQuery(GigsContext context) 
     {
          _context = context;
     }

     public IEnumerable<Gig> Execute() 
     {
          return _context.Gigs
                      .Where(...)
                      .Include(...)
                      .Include(...)
                      .Include(...)
                      .OrderByDescending(...)
                      .Take(10)
                      .ToList();
     }
}

So, what you see in the Execute() method here, used to be one of the methods of a class like GigsRepository. Now, we’ve promoted that to a class. Have we gained anything here? Absolutely not!

With this approach, if you have a repository with 5 methods, you’ll end up with 5 new classes in your application. Now, take into account how many repository classes you have and eventually how many command / query classes you’ll end up with. You’ll end up with an explosion of classes that don’t provide any additional value than a simple method.

When Command / Query objects provide value

When you want to execute some operation before and / or after the execution of the command / query. Sometimes, in large enterprise applications, you may want to check that the current user has permission to execute a given query (or command), and additionally you may want to log that somewhere.

Without using command / query classes, your repository methods would end up with a lot of duplicate logic:

public IEnumerable<Gig> GetPopularGigs()
{
     // authorisation logic 

     // logging logic 
     
     return _context.Gigs.......
}

public IEnumerable<Gig> GetUpcomingGigs()
{
     // authorisation logic 

     // logging logic 
     
     return _context.Gigs.......
}

At this point, by promoting a method to a class, you’ll have at least a couple of options in front of you to implement the same behaviour in a more elegant way. You can use the template or strategy pattern.

With the template pattern, you would define a base class for your commands or queries like this:

public abstract class Query 
{
      public void Execute()
      {
           // authorisation logic 

           // logging logic
 
           DoExecute();
      }

      abstract void DoExecute();
}

So, you write the authorization and logging logic only once, in the base Query or Command class. Then, when implementing an actual command or query, you override the DoExecute method:

public abstract class GetPopularGigsQuery : Query 
{
      public override DoExecute()
      {
           return _context.Gigs....
      }
}

With the strategy pattern, instead of using inheritance, you’d use composition to achieve the same thing. If you need more understanding of inheritance vs composition, check out my C# course: Classes, Interfaces and Object-oriented programming.

What about ASP.NET MVC action filters?

Mosh, aren’t action filters exactly for that? To execute some custom logic (e.g. like authorisation or logging) before each action? True! Then, why bother using the command / query pattern?

Good question! First, you don’t have to use the pattern, if you prefer to use ASP.NET MVC action filters. But what if, in the future, you decide to use a different web presentation framework that doesn’t have the concept of MVC filters? Tools and frameworks come and go. What is popular now, is not going to be popular in a few years time. There was a time we thought ASP.NET WebForms was so cool. Now, it’s almost a dead technology!

If you want to protect your application architecture from change of external tools and framework, you need to decouple it from them by creating your own abstractions. Command / query pattern is one of the ways to create such abstraction. If you switch over to a different presentation framework, you can take all your existing code and re-use it without modifying a single line, and more importantly, without breaking things along the way!

What if…

What if you’re not too concerned about decoupling your application architecture from external tools / libraries? What if you think this is overkill? That’s a perfectly valid argument. Then, don’t use these patterns. As I always say to my students: “Keep it simple”. Use MVC filters to achieve the same result, and if they won’t help you in the future, then you’d spend time solving that new problem, not now.

What if you don’t have such requirements like authorisation and logging before each query? Then, command / query objects don’t give you any additional value. You’ll just waste your time and energy writing more and more code.

What if you don’t have complex queries in the first place? Don’t bother with the repository pattern either!

Every pattern is designed to solve a specific problem. Don’t solve a problem that does not exist!

Till my next post, all the best my friends!

 

 

Tags: , , , ,