8

I know the purpose of it and everything. I see myself as a solo developer for a couple more years.

I always see answers that it is contract. Yes I get it.

But here's something on my mind:

If a class did not provide what an Interface wants, it'll throw an error.

Well, if a class really needs that method, it'll throw an error still if there's something that calls it and it's not there right?

What's the difference?

I can just actually implement it and go along with the "norms" but that will leave me hanging with the question "why". I don't like blindly following something without understanding it.

EDIT:

I tried searching for answers about this question many times before and what I always find is something like "So when someone else...". Haven't tried working with someone else before and I am not sure if that really is the reason on why use an Interface.

I mean, because I do everything my own so I do know what something in my code needs right? And again, even if I forget to implement a method, I will still see an error that says a method is not defined.

EDIT 2:

The Dependency Injection is a very good answer. Implementing Interfaces on those helps in case you need to swap out dependency implementations. You are somehow confident that what you need is provided.

It is a little more clear to me now that it is a Contract between components (maybe between developers too)

14
  • 10
    What relevance does being a solo developer bear on your question? (i.e. are you expecting to have a different answer based upon that fact)
    – Matthew
    Commented Apr 3, 2017 at 13:19
  • 1
    You're already dealing with interfaces if you use anything as fundamental as JDBC or mysqli in your code, for instance. They're everywhere. Commented Apr 3, 2017 at 13:54
  • 2
    if you practice Java, get Spring and try to write two services that work with each other and then write the unit tests that test each of them independantely, you will understand.
    – Walfrat
    Commented Apr 3, 2017 at 14:11
  • 7
    @jen Always remember: "Someone else" could also be you in a couple of months. There really is little to no difference between working without multiple persons at the same time or the same person over a long time (in fact one could argue that future you is a different person, but let's not get that philosophical right now) Commented Apr 3, 2017 at 16:16
  • 1
    Your question tells me you don't write any unit tests for your code.
    – Bryan B
    Commented Apr 3, 2017 at 21:20

9 Answers 9

13

I always see answers that it is contract. Yes I get it.

I can just actually implement it and go along with the "norms" but that will leave me hanging with the question "why".

If you're asking why, you maybe don't really get it.

Using interfaces is a decoupling technique. They allow some portion of your code to be ignorant of the implementation details of another portion of your code. This allows you to change those implementation details secure in the knowledge that the other parts of your code are not impacted.

That reduces the cognitive load when making the changes. That reduces the testing effort necessary to make sure that things work properly after the changes. And they make things a lot easier when you need multiple implementations to coexist at the same time.

But sometimes you don't need those benefits, so interfaces are just overhead then. The best way to really learn this sort of impact is to write code. Write some with interfaces. Write some without. See how the design shifts with each. See how changes to the program impact it differently depending on the design.

18
  • 4
    @jen - By making your function take in a concrete instance, you're coupled to that instance. If your function takes in only an interface, it's coupled only to the signature of the interface's functions, not the implementation of a class' functions. Consider constructors. Constructors are never part of an interface, because often a function needs some functionality, but shouldn't know how to build the object that provides that functionality (standard Dependency Injection).
    – Telastyn
    Commented Apr 3, 2017 at 14:09
  • 1
    @jen If I can save something to file or to database, I might have FileRepository, DatabaseRepository and IRepository. Without IRepository, anything that wants to save will have to pick whether it wants to use a file or a database. It's coupled to that decision. With IRepository, it doesn't need to know how it's saved, just that it will be saved. And in case that sounds like a contrived situation, if you want to unit test that code you'll certainly want to be able to use a fake repository that doesn't save to disk at all! Commented Apr 3, 2017 at 15:17
  • 1
    @BenAaronson Why not just have a DataRepository with all methods doing SQL work and being marked virtual, and for testing purposes, have a FakeDataRepository that inherits from DataRepository and overrides the methods? You don't need Interfaces explicitly to get the decoupling behavior you're after, or am I missing something?
    – GHP
    Commented Apr 3, 2017 at 19:11
  • 1
    @FrankHileman - That is the entire point? The interface is strongly coupled to its consumer and to its implementer, but the consumer and implementer are not as tightly coupled to each other.
    – Telastyn
    Commented Apr 4, 2017 at 0:40
  • 1
    A fake class for each contract I have? Seriously? Services, Repositories and any other kind of abstraction? And when any of them changes what... Would you maintain your farm of fake components? Before such approach make sure your project manager understand that the project is going to last twice than he/she thinks and all the tests are going to be just fakes
    – Laiv
    Commented Apr 4, 2017 at 4:51
7

If you don't feel you need an interface then you probably don't. Just use the class directly. Keep it simple. If an interface is implemented by only one class, then it is probably a useless interface.

Interfaces are useful in some particular circumstances, like

  • allowing multiple compatible implementations of some service
  • allowing you to mock a component for testing purposes
  • defining contracts between subsystems

But if you don't have those requirements, then you don't need interfaces.

Contracts (when taking interfaces) are not contracts between developers, they are contracts between components. The number of developers are irrelevant, the question is if the system is complex enough that such a decoupling provides value.

6
  • 2
    +1, I guess that is exactly what the OP missed to understand so far - he has the believe of interfaces being primarily a contract between developers (where "primarily" is plain false).
    – Doc Brown
    Commented Apr 3, 2017 at 16:38
  • Good answer, except an interface is not a contract. Commented Apr 3, 2017 at 23:52
  • @FrankHileman: nitty, nitty. Interfaces typically are used to define a part of a contract, they may not incorporate the full contract. In many programs, they are the only explicitly coded part of the contract.
    – Doc Brown
    Commented Apr 4, 2017 at 6:29
  • @DocBrown Sorry for being nitty, but contracts are valuable, and very rarely used, so I would prefer the term "contract" to keep its true meaning. Interfaces, on the other hand, tend to be abused more than anything else. Commented Apr 4, 2017 at 17:27
  • @FrankHileman: An interface is a form of contract, although by no means the only form.
    – JacquesB
    Commented Apr 5, 2017 at 7:28
2

If, when you write unit tests, you use a mocking framework that created mocks based on the class, I don't believe you need an interface for a very well defined class.

Abstraction should come from refactoring

  • when two classes will have common implementation details, you might want to move those bits in an abstract class, to respect the DRY principle.
  • when two classes have the same behavior with different implementations, you'd use an interface to define the behavior and inject each implementation as needed

Bottom line, I agree with you that premature optimization and abstraction leads to over-engineering (YAGNI principle).

As to the 'solo' argument, in 2 years you'll be a different person and you will thank your-current-self if you've kept the code base maintainable. Or you might be sorry for taking some decisions.

6
  • Those bullets is already helpful as it is. I guess it's time for me to use Interfaces
    – jen
    Commented Apr 4, 2017 at 3:02
  • "when two classes have the same behavior with different implementations" of course, base classes can often serve the same purpose of interfaces in this situation, if you favor composition over inheritance. Commented Apr 5, 2017 at 19:16
  • @FrankHileman I try to favor composition over inheritance; when inheriting, I only do it from abstract classes. However, I don't understand you comment. How can a base class be of use when the contract is the same (same behavior), but the implementation is different. E.g. if the behavior is Eat(), class X has one way of eating and class Y has a different way. How can a base class help here? Commented Apr 6, 2017 at 11:10
  • @aepureI don't understand your question. A base class and an interface are abstractly identical and perform the same purpose in the situation you describe. Two classes both inherit from the same base class, or two classes both inherit from the same interface. The reason to prefer an interface is to work around a flaw in the programming language design: the inability to inherit from multiple base classes. Commented Apr 7, 2017 at 17:23
  • @FrankHileman: We might think of different languages. I have experience in C# and Java, where interfaces contain only a contract, whereas abstract classes can also contain implementation. Two classes than inherit from the same abstract class have at least some common implementation. Two classes that implement an interface only share the contract (e.g. for a Storage interface, the FileStorage and MySqlStorage classes have totally different dependencies and implementations, and share nothing in common except the method signatures) Commented Apr 9, 2017 at 17:00
0

Answering this specific point:

I mean, because I do everything my own so I do know what something in my code needs right?

Just because you wrote something does not mean that you will always remember what it needs, especially a few years down the line on large code-bases.

You'll likely find it easier to navigate than someone who didn't write it, but that doesn't mean you'll remember every aspect of it either.

0

Interfaces are contracts, and 90% of the time they are contracts with other people/technologies. But they can also be contracts with yourself: your future self.

Say you want to port an application to a new platform that requires you to change where you get your data, but still support the old platform. Oops, now you have to write two different versions of your data retrieval code, and all the code that uses it. Or, just use an interface and load a different class to retrieve data from a different source.

This is actually a real-world scenario that happened to me: I had an existing WPF app that used a local database and ran on tablets (with no data connection) for technicians in the field. I needed to port it to UWP/iOS/Android so it would run on phones and connected tablets. But I couldn't just abandon the old version and demand the company purchase 100s of new phones/tablets in one shot. Since I had abstracted the data access layer through an interface, I simply wrote new data-access classes that contacted a service rather than a local database, and used DI to load the appropriate class for the environment.

4
  • 1
    Interfaces are not contracts. They do not specify anything other than signatures, which the compiler checks. Commented Apr 3, 2017 at 23:53
  • 1
    Could you have written it as an abstract base class for the data access first, with a new derived class that talked to the services instead of the local database? Seems like that would have been a nearly identical solution to the problem?
    – GHP
    Commented Apr 4, 2017 at 13:26
  • You did not explain how only an interface could be used, instead of a base class. Commented Apr 6, 2017 at 6:06
  • 1
    @Graham If I had implemented in as an ABC the temptation would have been to implement local database access in the base class, or put some code in the base class. And in this case, whatever code I had put in the base class, I'd have to split/move later.
    – HiredMind
    Commented May 1, 2017 at 21:40
0

As far as I'm concerned school does a very poor job teaching about such things. The problem is they only meaningfully come into play as systems get larger.

Lets take a real-world case to show the value of abstract:

I have a program here that among other things digests some "paper" (they're printed to disk) reports and turns them into on screen checkoff lists. There are currently (knowing my boss, I would be very surprised if the list doesn't grow at some point) half a dozen different parsers for different possible report structures and some of those structures can actually have multiple reports.

Should I write a separate checkoff routine for each report type? Of course not! Yet there is no standard "report", the only field that is common to every report type is quantity.

Thus I have an abstract type that represents a report and implements a bunch of behavior common to all the reports. I then have a class for each report type that knows how to parse it's report and yield the values in response to strings containing the names of the desired fields.

There is likewise a label printer that takes the same named strings and outputs a label to stick on the item.

Both the screen checkoff and the label printer work entirely off the abstract report type (of course it was initialized as some descendant type in response to information read from a configuration file) and almost never need to be updated when new reports are added to the system.

In my current primary language, C#, interfaces are for when you need to define behavior that is separate from the class using it. I have yet to find a reason to write one but consider a standard system one: IDisposable. Basically any class that controls a limited resource needs to implement this to ensure proper cleanup.

-1

One of the strongest implications of decoupling (which is the main purpose of interfaces) is not only that you can more easily change your code without (or with less) side effects (which is already huge).

(This is not an exhaustive description of the benefits of interfaces!)

Also you can write your code more flexible, resulting in less code (less IF-statements, etc.). This is especially true if you handle lots of objects of different classes, maybe even in a container/array.

Imagine the following scenario: Your program has classes for Cat, Dog, Car, Train, Wind. You want to have an array or a list of the objects of these classes sorted by their movement speed. Now these classes COULD derive from the same base class(es), because they all have a "speed" property. The base class could be "MoveableObject". But they could also have something else in common, for example the ability to create a log string (Method: CreateLogString()). As all of these classes would have this ability, you would need to create a virtual method "CreateLogString" in the hbase class "MoveableObject". On the other hand, this forces all moveable objects to implement CreateLogString and vice versa.

To declare "abilities" for classes (like the ability to create a log string, or the ability to have speed), you could implement 2 interfaces: ILogstringAble, IHasSpeed (or however you wanna call them).

Now if you implement a method that takes an object an logs it's current value, you can code that method to receive an argument of type ILogstringAble. You don't need to overload this method for all these classes.

void PrintLogs(ILogstringAble obj) {
    string s = obj.CreateLogString();
    ...do something...
    print(s);
}

If you have an array of IHasSpeed objects, you could sort that array using the speed property of IHasSpeed. This task would be not that easy if you don't abstract the ability of having speed by using that interface.

In short: With interfaces you can move up one abstraction layer and "categorize" objects based on their common behaviour, even if they are instances of different classes.

3
  • 1
    Strongly typed interfaces do not decouple anything. The caller is coupled to the interface, and the implementing class is coupled to the interface, the same way it would be if you used an abstract base class. Commented Apr 4, 2017 at 0:05
  • that's the point. the caller is only coupled to the interface, not to the implementation. in fact, a caller can use many different implementations without even knowing it. yes, you can achieve the same behaviour with an abstract base class. but as languages like java or C# don't support multiple inheritance, we need to work with interfaces if we want this behaviour. this is why C++ doesn't support interfaces -> cause it supports multiple inheritance. thus, (bastract) base classes are the C++ equivalent to interfaces in java/C# Commented Apr 6, 2017 at 16:02
  • To get a true decoupling, you could use one of several methods, including delegates. But decoupling is not an advantage inherently. It makes code harder to debug and read. Strong coupling is preferable, unless you need weaker coupling for some reason. Commented Apr 7, 2017 at 17:29
-1

I find that working with abstraction and interfaces in the design and architecture phases helps me think more about what I am trying to accomplish rather than how. The result is a design that is relatively language- and platform-agnostic and that can be easily extended to similar problems I'll see in the future.

2
  • 1
    Wouldn't you have the same level of mental abstraction with an abstract base class that defines your what?
    – GHP
    Commented Apr 4, 2017 at 13:21
  • @Graham Yes you would, and all of your comments are showing good critical thinking skills! Commented Apr 5, 2017 at 19:17
-3

An interface in languages such as C#, is not a contract. It is simply a collection of method, property, and event signatures. To be a contract, each such member would need a specification (i.e. preconditions, post-conditions), as well as invariants for the abstraction as a whole. Since C# and other .net languages lack formal ways to specify contracts (except unfinished tools provided by Microsoft), we can only create informal contracts in such a language.

In .net or Java, the only reason to use an interface is because you are forced to, due to some tool requirements, or you are forced to because you need multiple inheritance, and there is no other way to do it. Unnecessary interfaces simply clutter code and cause additional human error.

If you feel the need to add superfluous interfaces due to pressure from colleagues, consider the following:

  • Many object oriented programming languages have no concept of an interface, because they support multiple inheritance using classes. Potential problems with multiple inheritance were solved in programming languages long before Java and .net were designed. The concept of an interface, which is abstractly identical to an empty class, can be viewed as a workaround for a flaw in a programming language: no good support for multiple inheritance.
  • Some people claim that interfaces provide "decoupling". Code using an interface is strongly coupled to that interface, and a class implementing an interface is also strongly coupled to that interface. Therefore, an interface is no more "decoupling" than a base class in the same situation.
  • Interfaces are not contracts (see above).
  • The excessive use of interfaces may promote inheritance over composition, when composition is preferable. A class can implement many different interfaces, but can only inherit from one base class. This can lead to bloated classes. An alternative design, using base classes instead of interfaces, and promoting composition, would have that same class contain instances of other classes, each of which inherits from a different base class.
  • When creating a reusable library for others, by providing an interface instead of a base class, you enable users of your library to implement that interface by any class, avoiding inheritance restrictions. This can be necessary and a good thing. On the other hand, by providing only base classes instead of interfaces, you can promote composition over inheritance.
5
  • How would you define all the interfaces of the JEE. Aren't they specifications (JSR) and hence contracts?
    – Laiv
    Commented Apr 4, 2017 at 17:53
  • @Laiv A specification can either be formal or informal. A formal specification that is also machine readable is useful for automated proof checking. There is no built-in proof checking in Java compilers (most of them), so the specifications can only be checked or enforced by humans. There may be some specifications for the interfaces provided by documentation. Commented Apr 5, 2017 at 18:43
  • Just because an interface isn't formal specification doesn't mean it's not useful and not a contract. It's a method signature contract that the compiler can enforce. Coupling to an interface is looser than two classes being coupled together. The wikipedia article states "Low coupling refers to a relationship in which one module interacts with another module through a simple and stable interface" (emphasis mine). Interface inheritance is different from class inheritance and interface inheritance goes hand in hand with composition.
    – Samuel
    Commented Jul 26, 2017 at 23:24
  • @Samuel The compiler can enforce the signature, but that is not a contract in a software engineering sense. There is little semantics there. If you had an employment contract containing no conditions, only a signature, would you consider it a contract? Probably not. So the same idea applies to the word contract in other contexts. Commented Jul 27, 2017 at 0:57
  • @Samuel The point is that interfaces exist only to support the restriction on multiple inheritance in a language. In a language without such a restriction, there are no interfaces. So interfaces are no different from abstract base classes in another language. Commented Jul 27, 2017 at 1:00

Not the answer you're looking for? Browse other questions tagged or ask your own question.