13

In our C# MVC application we have a lot of interfaces that map 1 to 1 with the objects that implement them. ie: basically, for each object created, an "extract interface" operation has been performed.

The interfaces are used by Moq to generate mock objects for our unit tests. But that's the one and only time the interfaces are re-used.

No concrete objects in our system implement multiple interfaces.

Can anyone tell me if this is going to cause problems down the road? And if so, what would they be?

I was thinking, re our app that there is a lot of duplication, for example in these 2 interfaces (Edit: in our SERVICES layer) the only thing that differs is the method name and the type of parameter they take, but semantically they do the same thing with the repositories they send messages to:

interface ICustomer
{
    void AddCustomer(Customer toAdd);
    void UpdateCustomer(Customer toUpdate);
    Customer GetById(int customerId);
}

interface IEmployee
{
    void AddEmployee(Employee toBeAdded);
    void UpdateEmployee(Employee toUpdate);
    Employee GetById(int employeeId);       
}

and that's where I think the reused abstraction principle would come in, ie to transform the code to something like:

public interface IEmployee: IAdd<Employee>, IUpdate<Employee>, IFinder<Employee>

This isn't about the repository pattern - this is about interfaces in any layer that look like they share semantically identical behaviours. Is it worth deriving common interfaces for these operations and making "sub-interfaces" inherit from them?

At least it would keep the signatures of the methods consistent. But what other benefits would this give me? (Liskov substitution Principle aside)

Right now, the names of the methods and the return types are all over the place.

I read Mark Seemann's blog about the Reused abstractions Principle but I didn't understand it, to be frank. Maybe I'm just stupid :) I also read Fowler's definition of Header Interfaces.

Ruben Bartelink
  • 59,778
  • 26
  • 187
  • 249
Scott
  • 924
  • 3
  • 8
  • 28
  • Sounds like you need a generic repository. – Sriram Sakthivel May 06 '15 at 13:37
  • I'll have to look up reused abstractions myself, but your suggestion looks like the Interface Segregation Principle, which is part of SOLID code. That can't be a bad thing :) – jmrah May 06 '15 at 13:38
  • These methods I mentioned are actually part of the service (business) layer. We're not using DDD. In our implementation, MVC controllers use "services" (objects named along the lines of EmployeeServices, CustomerServices), which implement interfaces like those above. They "use" repositories in another layer, implemented in Entity Framework, which have pretty similar interfaces. – Scott May 06 '15 at 14:38
  • 1
    FWIW, my blog isn't the appropriate source to learn about the RAP - Jason Gorman is the [original source of the principle](http://www.codemanship.co.uk/parlezuml/blog/?postid=934). – Mark Seemann May 06 '15 at 19:53
  • The nicer way to write code is "contract first". So you'd define the interface first, then implement it. Concrete class first with extract interface let's you Moq, but nothing else. Question, do you bind to concrete classes or interfaces in your services? – Brian White May 06 '15 at 20:24
  • 1
    Wait, that's a crazy looking interface. Interfaces should not reference concrete classes inside. ICustomer AddCustomer should take an ICustomer, not a Customer. And you want some properties in there too – Brian White May 06 '15 at 20:27
  • Brian, can you explain why interfaces should not reference concrete classes? We don't have an IEmployee or ICustomer interface on our objects because to be frank they are practically POCOs. But let's say they were to become fully fledged domain objects - what reason would I have for making them implement interfaces? Just because of the DIP? – Scott May 06 '15 at 20:59
  • Brian: "Question, do you bind to concrete classes or interfaces in your services" - our MVC controllers have references to IEmployeeService, ICustomerService etc, and the service impls the concrete objects take references to IEmployeeRepository in their constructor. These repositories use EF. All dependencies are injected with Unity IOC. – Scott May 06 '15 at 21:20

2 Answers2

14

Given this:

interface ICustomer{
    void AddCustomer(Customer toAdd);
    void UpdateCustomer(Customer toUpdate);
    Customer GetById(int customerId);
}

interface IEmployee
{
    void AddEmployee(Employee toBeAdded);
    void UpdateEmployee(Employee toUpdate);
    Employee GetById(int employeeId);       
}

I'd probably start by redesigning it like this:

interface IRepository<T>
{
    void Add(T toAdd);
    void Update(T toUpdate);
    T GetById(int id);
}

However, this may still very well be violating the Interface Segregation Principle, not to mention that since it also violates the Command-Query Responsibility Segregation pattern (not the architecture) it also can't be made neither co- nor contravariant.

Thus, my next step might be to split these up into Role Interfaces:

interface IAdder<T>
{
    void Add(T toAdd);
}

interface IUpdater<T>
{
    void Update(T toAdd);
}

interface IReader<T>
{
    T GetById(int id);
}

Furthermore, you might notice that IAdder<T> and IUpdater<T> are structurally identical (they are only semantically different), so why not make them one:

interface ICommand<T>
{
    void Execute(T item);
}

To stay consistent the, you could rename IReader<T> as well:

interface IQuery<T>
{
    T GetById(int id);
}

Essentially, you can reduce everything to these two interfaces, but for some people this may be too abstract, and carry too little semantic information.

However, I don't think it's possible to provide a better answer, because the premise is flawed. The initial question is how the interface should be designed, but the client is nowhere in sight. As APPP ch. 11 teaches us, "clients [...] own the abstract interfaces" - in other words, the client defines the interface, based on what it needs. Interfaces shouldn't be extracted from concrete classes.

For further study materials on this subject, here are a couple of my Pluralsight courses:

General Grievance
  • 4,555
  • 31
  • 31
  • 45
Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • Hi Mark, believe it or not I've watched your Pluralsight course! That was what made me look for the RAP in the first place, our interfaces "smelled". I looked at your blog but couldn't understand why the extra effort was required. I need to justify the rework to the team. – Scott May 06 '15 at 20:56
  • 3
    The RAP is mostly a description of a desirable quality of a code base. The lack of reused abstractions is often a *symptom* that a code base violates the [LSP](http://en.wikipedia.org/wiki/Liskov_substitution_principle). That's not *necessarily* bad. The SOLID principles exist to address certain problems with code (maintainability, mostly). If you don't have those problems, there's no reason to attempt to apply the 'solution'. – Mark Seemann May 07 '15 at 05:27
10

All of that can be united using the Repository pattern ...

public interface IRepository<TEntity> where TEntity : IEntity
{
    T FindById(string Id);
    T Create(T t);
    bool Update(T t);
    bool Delete(T t);
}

public interface IEntity
{
    string Id { get; set; }
} 

EDIT

No concrete objects in our system implement multiple interfaces.

Can anyone tell me if this is going to cause problems down the road? And if so, what would they be?

Yes, it will cause problems if it hasn't started to do so already.

You'll end up with a bunch of interfaces which adds nothing to your solution, drains a large proportion of your time in maintaining and creating them. As your code base increases in size, you'll find that not everything is as cohesive as you once thought

Remember that interfaces are just a tool, a tool to implement a level of abstraction. Whereas abstraction is a concept, a pattern, a prototype that a number of separate entities share.

You've summed this,

This isn't about the repository pattern - this is about interfaces in any layer that look like they share semantically identical behaviours. Is it worth deriving common interfaces for these operations and making "sub-interfaces" inherit from them?

This isn't about interfaces, this is about abstractions, the Repository pattern demonstrates how you can abstract away behaviour that is tailored to a particular object.

The example I've given above doesn't have any methods named AddEmployee or UpdateEmployee... such methods are just shallow interfaces, not abstractions.

The concept of the Repository pattern is apparent in that it defines a set of behaviours which is implemented by a number of different classes, each tailored for a particular entity.

Considering that a Repository is implemented for each entity (UserRepository, BlogRepository, etc.) and considering that each repository must support a core set of functionality (basic CRUD operations), we can take that core set of functionality and define it in an interface, and then implement that very interface in each Repository.

Now we can take what we've learned from the Repository pattern, and apply it to other parts of our application, whereby we define a core set of behaviours that is shared by a number of objects in a new interface, and then deriving from that interface.

public interface IVehicleOperator<TVehicle> where TVehicle : IVehicle
{
    void Accelerate();
    void Brake();
}

In doing so we no longer have 1:1 mappings, but instead an actual abstraction.

While we're on the topic, it may be worth reviewing the decorator pattern as well.

Aydin
  • 15,016
  • 4
  • 32
  • 42
  • @Scott Let me know if that answers your question – Aydin May 06 '15 at 17:45
  • Excellent answer, but I can't see why the second example is a repository pattern. It just looks like a nice interface using generics. – Brian White May 06 '15 at 20:21
  • You're right it's not, what I wanted to demonstrate was that we can take ideas and concepts from existing design patterns and use them elsewhere too, that they don't have to be confined to specific cases, when you look at `IVehicleOperator` and `IRepository`, all that's actually different is the names, the rest of the code is the abstraction... – Aydin May 06 '15 at 20:30
  • Aydin, thanks for your help, but I thought re your 2nd example the repository pattern was to abstract away the concept of a data store? An SO reply says "It allows all of your code to use objects without having to know how the objects are persisted" ( http://stackoverflow.com/questions/11985736/repository-pattern-step-by-step-explanation) - how is your IVehicleOperator anything to do with persistence? I'm confused I'm afraid. – Scott May 06 '15 at 21:02
  • That's 100% right, that is the ultimate purpose of the repository pattern, to abstract away the data layer. I was attempting to point out something completely different. A repository is implemented for each entity, and each repository could derive from IRepository, so instead of having an interface for each repository (1:1), we have 1 interface (IRepository) which is then implemented by many. It's that concept that we can carry over to any part of your application – Aydin May 06 '15 at 21:25
  • @Scott, So even though the second example has nothing to do with the repository pattern, it still has as much to do with abstraction and how one might implement it in their application – Aydin May 06 '15 at 21:45