14

I've been delving into more "organized" programming recently and I've been learning that I should be programming to an interface, not an implementation. With that in mind, would it be better to "sketch" out a project in interfaces before writing the implementation for it where possible?

And if this is the case, in the case of using 3rd party libraries (ie Lidgren), should I be wrapping those in interfaces as well and resolve them through IOC containers, or is it OK to expose them to the interfaces?

gnat
  • 21,442
  • 29
  • 112
  • 288
Dan
  • 654
  • 1
  • 7
  • 18
  • In my personal experience - it's good to design the architecture first - the responsibility of each class. You don't have to write it down, just think about it or sketch it on a paper. Then it's about personal preference but I recommend to write doc comments first for every method you start to implement. Writing docs really makes you to think about the functionality before you start writing code. – Sulthan Dec 06 '13 at 10:41
  • Yes, and program to the interfaces (or abstract classes for that matter) before you implement them. It helps getting the message flow from client to server and vice versa "right" before being bogged down (and invested in) implementations. Very good slide show on the matter: [How to Design a Good API & Why it Matters](http://www.infoq.com/presentations/effective-api-design) – Marjan Venema Dec 06 '13 at 11:08

5 Answers5

13

Yes, you should code against interfaces rather than known implementations, and yes, you should construct interfaces first rather than having them emerge from your own code.

The reasons for both recommendations are largely the same: computer programming is largely about human factors. Many find this surprising, but consider: there are a near-infinite number of different ways to solve the same computing problem that work equally well. Nearly all of them are completely impossible to make sense of for anyone who didn't write them (or in fact to the author a short time later).

It follows that good software engineering is largely about how to achieve the desired effect (correct computation with reasonable efficiency) in a way that allows the source code to be worked with later on. Interfaces and APIs are a crucial part of that discipline: they allow you to think about a problem at one level of description at a time. This is far easier than thinking about business consistency rules and about linked list implementations at the same time, and therefore imposing such a separation of concerns forcibly is better than allowing the client programmer to use your code any way he likes.

This is hard to believe for many cowboy programmers, who are convinced that they understand everything they write, are much better than average thinkers, and can handle all the complexity that gives "lesser" programmers trouble. Not being aware of one's own cognitive limits is an extremely common phenomenon - this is why best practices in code organization are so hugely important (and so often ignored).

To repeat, interfaces and API barriers are largely good, even when you only cooperate with yourself. As for external libraries, if they bring a well-thought-out API with them, I see no problem in using it as it is as long as you don't anticipate having to swap out that library for another one. Otherwise, a wrapper or anti-corruption layer can be a very good idea.

Kilian Foth
  • 107,706
  • 45
  • 295
  • 310
  • I like your point about SE being largely about achieving the desired effect in a way that allows the source code to be worked with later. I wish I had been able to phrase it that well at my last job, where I was always fighting for clean code! – MetaFight Dec 06 '13 at 10:06
  • Is there a naming convention for APIs that are just interfaces that I will end up using all over the place? Like, if I am doing a command pattern, do I call it "commandables"? – Snoop Apr 14 '16 at 13:38
  • @StevieV There are various, e.g. `IBlah` implemented by `Blah`, or `Blah` implemented by `BlahImpl`. I dislike both, and tend to use `Blah` implemented by `OralBlah`, `WrittenBlah` or `ASLBlah`. But as usual, it's more important to conform to your existing code base and expectations than to any general standard. – Kilian Foth Apr 14 '16 at 14:21
8

Unfortunately, you'll find this often boils down to personal preference.

What you've described so far, though, seems good. In fact, if you wanted to (and I recommend it) you could use the following approach:

  1. Write your application skeleton as Interfaces, abstract classes (stubbed), and classes (also stubbed)
  2. Write your tests against those interfaces and stubs (they will fail for now)
  3. Write your implementations (your tests will start passing as you finish your implementation)

You're focusing on trying to write more "organized" code. Following TDD will help you with this.

Some extra points:

  • IoC containers are convenient. Use them and DI as much as you can.
  • Do wrap 3rd party libraries. This will loosen the coupling between your code (code you control) and 3rd party code (code you don't control)
MetaFight
  • 11,549
  • 3
  • 44
  • 75
  • 1
    This was what I had originally thought but I was told it would violate the YAGNI principle. The problem that I find with a lot of my projects that never get finished is that they rapidly become un-maintainable with the amount of blob code I've written, because I don't organize it properly or plan out my plan of attack. – Dan Dec 06 '13 at 09:58
  • which part would violate YAGNI? – MetaFight Dec 06 '13 at 09:58
  • Wrapping 3rd party libraries. – Dan Dec 06 '13 at 09:59
  • 2
    I guess it boils down to: What are the odds of the 3rd party library changing? If there is a 0% chance of this, then sure YAGNI. But, that's rarely the case. Also, wrapping your 3rd party libs *may* make your other code more easy to unit test (if, for example, you couldn't mock out the 3rd party library) – MetaFight Dec 06 '13 at 10:01
  • 1
    @DanPantry: Wrapping third party libraries isn't a YAGNI violation, but a much needed protection against "third party library infestation of your own code". It is not just about being able to swap out a library, but as MetaFight also says a defense against changes in newer versions of the library which would otherwise require changes throughout your own code. By wrapping the library (and especially its specific types: classes, enums, structs etc), you insulate your own code and have a single point to change when the library changes (for whatever reason). – Marjan Venema Dec 06 '13 at 11:13
  • +1 Writing against interfaces or abstract classes is a good way to get the organisation right. For API's this is especially important as an API is the part that "gets out" to your clients. Did you see [How to Design a Good API & Why it Matters](http://www.infoq.com/presentations/effective-api-design)? You are very much in line with it :-) – Marjan Venema Dec 06 '13 at 11:15
  • Nope, I haven't watched that yet, but I'll give it a go later on tonight. Thanks :) – MetaFight Dec 06 '13 at 17:27
  • I don't think it's a very good idea to write failing tests - plural - for your app before implementing it. TDD suggests working one (small) test at a time because a) it's demotivating to be 'red' for a long time and b) it helps you prioritise. By growing your API one feature at a time, you naturally end up doing the important/fundamental/easy ones first. – Benjamin Hodgson Dec 07 '13 at 00:00
  • What you describe is typically what I would do. I just assumed that kind of approach was a product of Agile and its "Vertical Slicing" rather than a product of TDD. You're right, though. In the absence of Agile, doing TDD one test at a time would make sense. – MetaFight Dec 07 '13 at 00:11
4

Rather than slavishly just programming to interfaces, why not look into Test Driven Development/Design (TDD)?

Many people think of TDD as a testing practice, but actually it's a design approach where you let tests expose how your code will be used via tests (initially via unit tests, but can also be via integration tests).

Programming to interfaces is an important weapon in your toolset, but like most things, it's not always the appropriate solution/technique/practice, as it's not always needed. You should program to interfaces where you need to.

Using TDD will force you to explore where such interfaces are important and where it, frankly, doesn't matter. And at the end of it you should have a pretty good set of unit tests across your code base.

As for using 3rd party libraries I would highly recommend wrapping them in your own abstractions where appropriate; and not let clients of your API "know" about them.

Good Luck!

[edit: saw megaflight's answer - completely agree]

rupjones
  • 1,102
  • 9
  • 7
  • 2
    TDD implicitly has you think in terms of interface rather than implmenetation, although it may not be a formal "interface" declaration. – DougM Dec 06 '13 at 16:36
  • 1
    This is a great answer. +1 for suggesting TDD, which I think is the solution to the OP's _real_ problem of where to start when working on a new project, and I'd +1 again if I could for "Using TDD will force you to explore where such interfaces are important and where it, frankly, doesn't matter." – Benjamin Hodgson Dec 07 '13 at 00:10
2

I think it is overkill. If the user of your API does not need to be forced to implement/use something a certain way then I would leave it out. Interfaces are contracts, if I don't need it then why give me one?

I think people overuse interfaces. You are adding a layer of complexity that is not needed in most cases.

Kyle Johnson
  • 459
  • 1
  • 4
  • 10
  • I think, people **under**-use interfaces. If you want to create reusable pieces, the interface is not only a "nice to have" addition, but the main thing to take care of. Besides the actual implementation of course. – JensG Dec 06 '13 at 18:39
1

Programming against a contract is almost always a good idea. That contract need not be an interface, it can be fulfilled by a class instead. In my opinion, interfaces have become somewhat overused along with DI due to unit testing concerns and mocking frameworks.

I personally prefer to only bring in interfaces when I very likely could have or do have more than 1 implementation of a contract. Interfaces are great for repositories where I wish to abstract away data access, but probably less so for my standard business logic which is likely to be relatively inflexible.

Now not having an interface can cause problems with unit testing, especially for purists. But I'm interested in mocking the external dependencies of my programs, not its internal dependencies. I want my tests to perform validation of the code, not echo the code structure.

Peter Smith
  • 2,587
  • 19
  • 21