-1

I am a C# programmer. Both at my last job and my current one, it is very common to create interfaces for most classes we write. E.g. when we have a class named Spork, we will add an interface ISpork that contains the public methods of Spork.These interfaces are used for dependency injection (e.g. via StructureMap) and for creating mocks in unit tests (e.g. with Rhino Mocks or Moq).

Some weeks ago I attended a talk by a Javs developer. We somehow got to talking about interfaces, and he seemed really surprised that anyone would have lots and lots of one-one-relations between classes and interfaces.

Now my questions: Have I been doing it wrong all the years? Or is this a Java vs C# thing? If it is, how are mocking and dependency injection handled in Java?

P.S.: I am mainly interested in the DI and mocking aspects and the related need (or not?) for lots of interfaces that have only one implementing class. I think the situation re. classes that are neither going to be mocked nor injected is quite similar. But I was surprised that something that seemed like a no-brainer to me as a C# developer was completely unheard of for that Java guy.

Jan
  • 241
  • 1
  • 6
  • This sounds like a C habit carried over – Thorbjørn Ravn Andersen Jul 13 '19 at 07:53
  • 2
    This is a somewhat broad, opinion-based question, which unfortunately doesn't work well for Stack Overflow's format. See [this](https://stackoverflow.com/questions/2659366) related question, though. One thing to note is that some mock libraries actually do pretty decently with non-final classes (I use Mockito, and it does a pretty good job). But imo, it really depends on the class and its expected use cases. – yshavit Jul 13 '19 at 08:09
  • 2
    First show some respect to the man: it's _Robert_ C. Martin :) It is just a naming _convention_. Prepend an _I_ so that when reading the code it is clear that the type is an interface. You have `IPrinter` which is implemented by `FilePrinter` and a `ConsolePrinter`. `IPrinter`outputs `IPrintable` which is implemented `TextMessage` and `FormattedMessage`. This is a one-to-many relation which is quite common (e.g. `IDisposable`) and more often since implementations are specializations with a single responsibility. In Java you often see `Printer` for the abstraction and `FilePrinterImpl`. – BionicCode Jul 13 '19 at 08:30
  • 1
    Since we are using dependency injection everywhere, the business code is only written in abstractions. Code maybe is more readable without the prefix, since the implementations doesn't matter. Both naming conventions make sense. Without dependency injection the prefix based is more readable and with dependency injection the prefix feels redundant. In the end it's taste. If you _know_ what you are doing and _why_ you are doing it the way you are doing it, it has a value. – BionicCode Jul 13 '19 at 08:30
  • #BionicCode: thx – Jan Jul 13 '19 at 08:34
  • BTW What is the difference (in c#) between an abstract class and an interface? You can "inherit" from many interfaces but only from a single (abstract) class. – Sir Rufo Jul 13 '19 at 08:34
  • @Sir Rufo: interfaces can also not contain any logic (until recently, at least) – Jan Jul 13 '19 at 08:37
  • @Jan An **abstract** class - I mean totally abstract - should also not contain any logic, because otherwise it is not pure abstract. I know you can add logic and now you can add logic to interfaces too. The main reason for all of it: C# designers were lazy and do not want to implement multiple class inheritence. Nowadays they try to heal it – Sir Rufo Jul 13 '19 at 08:39
  • @BionicCode hit on an important difference in the naming conventions. Java tends towards interface names without an I- prefix, and then class names that are ImplementationDescription+TheInterfaceName. For instance, the List interface has implementations LinkedList and ArrayList. If there's not a reasonable description, "Default" or "Simple" often stand in: SimpleEntry implements Map.Entry, DefaultCellEditor implements CellEditor, etc. – yshavit Jul 13 '19 at 08:41
  • No matter what the opinion is: this is not a Java vs C# thing. It has nothing to do with the language. Since we don't reflect on it, we got used to what we see in the tutorials and just copy it. Because we don't reflect, books like those of Uncle Bob are successful and can be an eye opener (either you agree or disagree, but you now reflected). Microsoft decided to go the prefix way. I personally like it more because documentation of an API reads much better. – BionicCode Jul 13 '19 at 08:43
  • @yshavit The wohle naming thing is only convention - and one of the most hardest task in programming ;o) – Sir Rufo Jul 13 '19 at 08:43
  • @Sir Rufo: The way abstract classes are most commonly used is as a means to share some logic, but not all. In my experience at least. If you do not want to share any logic, you should probably use an interface. But that is a separate topic - I suggest to open another question for that. – Jan Jul 13 '19 at 08:44
  • @yshavit There are only **two** hard things in Computer Science: **cache invalidation** and **naming things** and **off-by-one-error** ;o) – Sir Rufo Jul 13 '19 at 08:46
  • @SirRufo I agree it's a convention only -- but part of learning a language is learning its idioms. IList would look "weird" (or superfluous, or pick-your-adjective) to most Java developers. They'd look at you funny and ask if you came from a C# shop. :-) Anyway, with that, I'm going to reflect back on my first comment about this not being an appropriate question for Stack Overlow, take this extended discussion as evidence of that, and take my leave of this discussion. ;-) – yshavit Jul 13 '19 at 08:47
  • @yshavit It does not matter who is laughing - who is right? => both and none. It totally depends on the context. – Sir Rufo Jul 13 '19 at 08:49
  • Very opinion based topic. – BionicCode Jul 13 '19 at 08:52
  • 1
    DI has been the cause of many bad habits in software development in recent years, `interface` use being one of them leading to the `1:1 ratio` of which you speak. The DI community is obsessed with _abstractions_ (so they can mock their unit tests leading to questionable valie) but has yet to grasp the more useful feature that of **de-coupling** - by that I mean putting your contracts or `interface`s in one assembly and the implemention in another. You should `minimize` what assemblies have a direct reference to the actual `implementation`. –  Jul 13 '19 at 08:59
  • ...the fact that nearly every DI framework encourages 1:1 interfaces; that the app reference both contract and implementation; that the app explicity initialise the DI-framework with explicit concrete types, makes for a overly complex _factory pattern_ of questionable improvement –  Jul 13 '19 at 09:01
  • Creating a `1:1 interface` is not useful either as it `reduces re-usability`. Developers using DI should really take a look at the vast interface patterns Microsoft has created for everything COM-related. e.g. _do I really need to include my serialisation method in my 1:1 interface or can I just implement `multiple interfaces` and use the existing `IPersistStream` interface?_ Creating 1:1 interfaces is kinda like creating tables in SQL and not using table normalisation. My summary is - `If you are learning about or wanting to design interfaces, stay clear of DI examples` –  Jul 13 '19 at 09:03
  • For more information on de-coupling, abstrations and interfaces check out the wonderful static code analysis tool _[nDepend](https://www.ndepend.com/)_ –  Jul 13 '19 at 09:09
  • @SirRufo _"C# designers were lazy and do not want to implement multiple class inheritance."_ Nice one. Who needs multiple inheritance? Does any modern language support it? Isn't it composition over inheritance (for a good reason)? Multiple inheritance is not allowed for some good reasons. An abstract class without (virtual) implementation is de facto an interface. Abstract classes with method implementations are the result of generalization. Nothing wrong with it. I don't think this is about C# vs Java. And the logic of "I love A - but B can do something A can't do so B is bad" is stubborn ;) – BionicCode Jul 14 '19 at 00:36
  • @BionicCode FYI https://blog.cleancoder.com/uncle-bob/2015/01/08/InterfaceConsideredHarmful.html – Sir Rufo Jul 14 '19 at 04:52

2 Answers2

1

DI can be made with classes only without interfaces. You register the type, you inject the type. That's all. The difference comes when talking about mocks in unit tests. In c# you can mock only virtual or abstract (that are also virtual) members. Hence if you want your code to be testable you need to mark all public members with virtual keywords or use an interface instead of real class in your implementation. In Java all methods are virtual by default so they don't have this mess with one-to-one interfaces because they can mock everything.

Artur
  • 4,595
  • 25
  • 38
  • _"In Java all methods are virtual by default "_ I read the Java language designers regret this decision. It allows every method to be overridden if not declared final. The most time you _don't_ want your methods do be overridden, so you need to to add final everywhere. Default behavior should meet the default requirements. Liskov also doesn't want all methods to be virtual or at least wants us to use them with caution. – BionicCode Jul 14 '19 at 00:08
  • Declaring all public methods `virtual` only to mock the type sounds very weird to me. Never saw any test doing this. This is too much. Then why don't make everything `protected` or even `public`? And what is the point of using dependency injection with concrete classes? Every pattern comes with an overhead. The price for extensibility and test-ability or re-usability. – BionicCode Jul 14 '19 at 00:15
  • Good code design needs dependencies to point to abstractions. I don't get the point what is wrong with interfaces (one to one or what ever). Why is `virtual`_better_ than interfaces. `virtual` has nothing to do with dependencies. DI is all about dependencies (**dependency** _injection_ and not method _overriding_). Interfaces are all about dependencies. Mocking is about dependencies. DI and interfaces go hand in hand. So do mocking and interfaces. `virtual` is about inheritance and has nothing to do with dependencies. Maybe you will get fired one day for this kind of class design ;) – BionicCode Jul 14 '19 at 00:21
  • @BionicCode, I absolutely agree with your first comment. And that's why I love C# and not Java ;) – Artur Jul 14 '19 at 06:08
  • @BionicCode, Regarding making everything `virtual` - is about a technical requirement to make mocking possible, not about "proper design" or something else. AFAIK all or almost all mocking frameworks use [interceptors](https://github.com/castleproject/Windsor/blob/master/docs/interceptors.md) to mock the behavior. Making everything public or protected won't make it possible to intercept method call. On the other hand, interface methods are virtual by definition, and that's why they been chosen to make code testable. – Artur Jul 14 '19 at 06:16
  • @BionicCode, don't mix DI and mock. They are different concepts with different purpose. Mocking **is NOT about dependencies**. It's about **faking behavior for tests**. And **DI is about object creation and lifetime management**! Using DI you don't think how to instantiate your dependency and where you take its dependency and can you dispose it already or not. DI is about helping you implement IoC without going all the way from your main method to desired class and passing your new dependency. Maybe you will get fired one day for not understanding basics of what you are paid for ;) – Artur Jul 14 '19 at 06:27
  • I know mocking quite well. It _is_ about dependencies. You are faking a dependency. When my class that I need to test depends on a resource hungry `IService` implementation I create a mock and pass it to the constructor instead of the real dependency: e.g. `new Mock()` and **not** `new Mock`. I repeat: when you are mocking concrete classes and need to declare their method `virtual` than you obviously have a bad design. It doesn't matter if your mocking framework allows this. It's not how it is done. The `virtual` aspect shows this. `virtual` is a bout inheritance. – BionicCode Jul 14 '19 at 07:21
  • _"interface methods are virtual by definition, and that's why they been chosen to make code testable."_. Which `language`? This is true only for a special language. Other language define an interface members as a public members (which makes sense). The mocking framework can creates a fake object that implements this interface. It implements fake methods that do nothing but to return the required value. This is how the behavior is replaced or mocked. Again. `virtual` methods are only needed when mocking concrete classes and this is a bad idea => forced to misuse `virtual`. – BionicCode Jul 14 '19 at 07:28
  • @BionicCode we are talking about C#, remember? https://stackoverflow.com/questions/3621410/why-are-c-sharp-interface-methods-not-declared-abstract-or-virtual/3621600 – Artur Jul 14 '19 at 08:01
0

Dependency injection is used to contain and separate concerns. You want to do something new in your code, you add a dependency interface that does that. You can then test your code without even bothering with the implementation of that interface until later on.

Your question, though, is about one on one relationship between interface and implementation. From my standpoint, that's irrelevant, since you care about the implementation only in the context of the interface you have already declared, not where it is used. You can have a class inheriting multiple injectable interfaces, for example, which is usually a sign that it has too many responsibilities, but it can be done. You can have multiple classes that inherit the same interface and then used based on DI configuration. There are even cases where the DI container handles stuff that I usually relegate to factories, mainly give you the implementation for an interface based on some parameters.

Either way, what does it matter? If (reducing to the absurd) there is one developer per class, then they will only write their code and their tests and define the interfaces of the dependencies needed, letting others implement them.

Siderite Zackwehdex
  • 6,293
  • 3
  • 30
  • 46
  • _"Dependency injection is used to contain and `separate concerns [(SoC)]`"_ - it doesn't actually. All it does is **free** a _client_ class from `knowing the nature` of a `dependent` class/interface/object particularly _how it is instantiated; its lifetime_; or _ownership_. One does not need DI to achieve SoC. [Aspect-orientated programming](https://en.wikipedia.org/wiki/Aspect-oriented_programming), a realisation of SoC is oftent confused with DI because whilst both "inject", only AOP can do so without requiring the code to be modified. I think you might be confusing the two. –  Jul 13 '19 at 11:04
  • I didn't mean it as a definition, but as an actual use case. I use DI in my projects in order to achieve separation of concerns (mainly my own concerns about the quality of code from different people). ;-) I don't need DI, but I use it anyway for this exact purpose. – Siderite Zackwehdex Jul 13 '19 at 11:07
  • 1
    Np. _"You can have a class `inheriting multiple interfaces`, for example, which is usually a sign that it has `too many responsibilities`"_ - well we can't be too quick to judge whether a class is violating the SRP because for all we know we might be using **composition**. e.g. I might have `class Car : IVehicle, ISteerable, IBrakeable { ... }`. It's polymorphic, avoids monolithic `interface`s and depending on the situation, allows for a _[kind of **multi-class inheritence in C#**](https://stackoverflow.com/a/178368/585968)_. Again, DI and its religion has a lot to answer for sadly –  Jul 13 '19 at 11:24
  • 1
    I agree. I was vague. Added "injectable" to clarify the context of dependency injection. And I am not an evangelist. I just find DI is nice. – Siderite Zackwehdex Jul 13 '19 at 11:28
  • Not a problem good sir. Wasn't suggesting you were. :) I wrote my own DI system actually but I made it smart so that type registration is 100% automatic and still allowed for switching implementation (like for tests). I think if more did that I would be a happy chappy –  Jul 13 '19 at 11:36