1

I overheard the below and was asked to confirm this statement:

"SOLID/TDD encourages one implementation for one interface, this is not real world and goes against the point of interfaces doesn't it?"

I initially agreed as all online examples of TDD and DI all follow typical IRepository/MyRepository examples where there is only one implementation. After further thought I didn't agree.

What I'm trying to do is provide proof that it doesn't and also an example of where there can be multiple implementations of one interface and show how it works in terms of DI.

I was hoping people could help me with this.

UPDATE: Whilst I understand the concepts of DI and Unit Testing what I'm trying to show is how we can have multiple classes in production implementing one interface.

UPDATE2: Having thought of a simple example, here is a possible implementation of multiple implementations however it still doesn't really answer what I want. What if you had a constructor that had a single dependency on ILogger or IDataProvider or ISomething:

public interface ILogger
{
  void Write(string data);
}

public class FileLogger : ILogger
{
  void Write(string data)
  {
    //
  }
}

public class DBLogger : ILogger
{
  void Write(string data)
  {
    //
  }
}

public class EventViewerLogger : ILogger
{
  void Write(string data)
  {
    //
  }
}

public class Calculator
{
    private IEnumberable<ILogger> loggers;

    public Calculator(IEnumberable<ILogger> loggers)
    {
        this.loggers = loggers;
    }

    public int Add(int a, int b)
    {
      var result = a + b;

      foreach(var logger in loggers)
      {
        logger.Write("Result was " + logger);
      }
    }
}
Jon
  • 38,814
  • 81
  • 233
  • 382
  • Related: http://stackoverflow.com/questions/5411648/how-to-deal-with-interface-overuse-in-tdd . With unit-testing in isolation, you will quite often end up with an interface which is implemented by a test-double and precisely *one* production class. – SSJ_GZ Aug 27 '12 at 17:09
  • to me this is not a question at all, we create interfaces expecting that there could be multiple implementations...this is what makes your application more flexible...I really don't understand why you wan't to prove it...bottom line is even if you are in TDD/SOLID...purpose of using an interface is to specify a contract and that can be implemented by multiple classes...instead trying to prove this...ask the person who asked you to prove it to brush up his/her OOP skills... – NiK Aug 27 '12 at 20:12

6 Answers6

4

No, you can have as many implementations as you want. TDD tests implementations, not interfaces. DI injects implementations, not interfaces. You use interfaces so that you can have mulitple implementations.

Jim Barrows
  • 3,634
  • 1
  • 25
  • 36
3

When testing, you usually create a mock for the interfaces to isolate the unit under test.

Although you didn't write the mock yourself, the mock still counts as an implementation of the interface to me.


I don't know what you want to get here. It depends on your problem if you have many implementation of the same interface or not. At the end - it doesn't matter. The advantages of the interface is not because you can have multiple implementation at the same time in production. We have many interfaces in out project, and probably most of them have only one implementation. It's still worth having it, because:

  • The calling code doesn't care how many implementations you have -> it enhances decoupling
  • You have a single implementation today, you may have another one in the future. (I know, it is a weak argument, considering YAGNI).
  • Testing has its mock implementation
  • changing the implementation is like creating another one. You have multiple implementation, but not at the same time. => it enhances maintainability.

In short: you don't need many implementations in production to excuse the use of interfaces.

Stefan Steinegger
  • 63,782
  • 15
  • 129
  • 193
  • True but its not in production. I would like to demo multiple implementations of one interface in production with DI – Jon Aug 27 '12 at 17:49
  • Do not bloat your code with unnecessary interfaces. See http://stackoverflow.com/questions/90851/is-creating-interfacesfor-almost-every-class-justified-or-are-interfaces-overus. In particular From http://martinfowler.com/bliki/InterfaceImplementationPair.html Using interfaces when you aren't going to have multiple implementations is extra effort to keep everything in sync.Furthermore it hides the cases where you actually do provide multiple implementations. – Michael Freidgeim Jun 18 '13 at 12:54
  • @Michael: I partially agree. Writing more code than necessary is always a bad thing. "Necessary" always depends on the size and complexity of the project. In the large and fast changing project I'm working on we saved a lot of time because of interfaces which weren't an obvious benefit when we wrote it. In the last years I started to use interfaces even more. Interfaces shouldn't bloat anything. They should be small, making things clearer and decoupling parts of the software from each other. – Stefan Steinegger Jun 19 '13 at 08:54
2

SOLID doesn't promote 1-1 mapping between interfaces and classes.

Interface segregation is the closest to interfaces that we get. But it states that you should create as specific interfaces as possible. A IUserRepository could be breaken down to IUserStorage (CRUD) and IUserQueries (searching). UserRepository would probably implement both from start, while you break them up later on. The great thing with that is that you can create a cached implementation (decorator pattern) with a little effort or use different data sources for the writings and readings (CQRS).

If you follow SOLID properly you'll end up with small well defined classes with interfaces that will be easy to use and create different implementations for.

The problem is rather that everyone just thinks of the typical business logic when discussing SOLID. But we all run code in different frameworks which would benefit hugely if SOLID would have been applied.

I'm not very good at TDD, so I won't comment on it.

jgauffin
  • 99,844
  • 45
  • 235
  • 372
1

I agree with Stefan's points. Tests may not be in production, but they are the first consumers of your application.

On the argument that TDD/SOLID produces meaningless interfaces, I will make one caveat: SOLID encourages abstractions, not necessarily interfaces. If you're creating interfaces for everything, this may seem very heavy-handed to some developers. Interfaces should be extension points for consumers of your system. In some cases, abstract classes or non-sealed classes with virtual methods may be more appropriate if testing is your primary objective. Some developers see virtual methods on internal classes as a something that will never be used outside the scope of their application. There may be merit to that claim, but there's always a possibility of extending this to external consumers -- having it broken down into small pieces may make extending it and refactoring easier. There's also something to be said about not having to test an application by hand for several hours. It's a compromise your colleague should be willing to make.

There are few applications that I've developed where core services needed to have more implementation per instance, but I've developed applications that needed different implementations to satisfy hardware-specific implementations such as a webcam, Kinect. I might only need one at a time, but the ability to mix/match components is powerful.

Regarding multiple implementations at once, the strategy and plugin patterns are popular. Could be as extensive as modular application that composes it's interface entirely through plugins, or a tax-calculation that's configuration driven.

Logging, as per your example, is often a great example of mixed-implementations. I often use log4net to log everything to a file, errors to the event log, and crashes to an email appender.

bryanbcook
  • 16,210
  • 2
  • 40
  • 69
  • You've started that you agree with Stefan's points, but then explained that he is wrong, and there is no need to overuse interfaces , because you can use virtual methods for mocking. Your answer contradicts itself, I suggest you to remove the first sentence. – Michael Freidgeim Jun 18 '13 at 13:12
  • Read it again. I never said that Stefan was wrong. Stefan's position is that the interfaces aren't useless because they're used in the tests. My position is very similar, tests are the first consumers of your code. On top of Stefan's position, my point is SOLID encourages abstractions (not specifically C# interfaces) and abstractions are good. – bryanbcook Jun 18 '13 at 21:29
  • IMHO, Stefan's position is that interfaces should be used ALWAYS, even if it would be simpler to use virtual methods instead. – Michael Freidgeim Jun 18 '13 at 21:55
  • Where did Stefan say ALWAYS? – bryanbcook Jun 19 '13 at 14:30
0

So you're looking for an example of an interface that has multiple implementations, and used in a production environment?

JDBC - Oracle, MySql, any other database has their own implementation of the JDBC interfaces

JPA - see JPA Implementations - Which one is the best to use? for list of implementations of the interface(s)

or are you looking for something else?

Community
  • 1
  • 1
Dennis S.
  • 2,081
  • 14
  • 14
  • Just a simple demo really. Maybe ILogger with FileLogger, DBLogger, EventViewerLogger. However not sure how all 3 could be used in one app – Jon Aug 27 '12 at 17:55
  • @Jon just log everything into a file (works even when DB is not reachable), but log serious errors into the DB for easier analysis and log all errors into eventviewerlog since that would be the easiest option to have a monitoring solution monitor your system... – Yahia Sep 10 '12 at 17:23
0

Uncle Bob, the namer (not inventer) of the solid principles has a famous accounting system example You can find it in the principles, patterns and practices book. In this example he has a class that can generate reports based on a list of employees. An employee could be an hourly paid employee or for example an monthly paid employee. Nevertheless they are both employees and thus implements the same interface.

mathiasbn
  • 881
  • 11
  • 21