Recently, I was responding to a question on the TDD list and found myself writing this:
Although there's only one use of the interface, you could think of it as a way of keeping a clean distinction between the naming of different domains (user and persistence). It makes managing package dependencies easier too.
which is what I've been meaning to say for ages. The reason we're keen on discovering interfaces in our code is that we think they're a good way of expressing concepts in a domain.
If I'm writing a ring tones store (the video store folded last year) and I need to look up, say, the customers that were active last month, I'll ask a SalesLedger object. So, what type is SalesLedger? If it's a class then my marketing module will have a dependency on whatever persistence framework I use. If my SalesLedger class is clean and delegates to some further persistence type then I've only deferred the problem. I'm importing, directly or indirectly, the persistence packages into my domain code. If I do the same with a few other frameworks (printing, display, network, etc.) then I'll have tied down my domain module with third party dependencies. The module dependency chain looks like this:
There are two problems with this, one obvious and one subtle. The obvious point is that I've raised the risk of inflexible code. One day I'll have to rip out a messy chain of dependencies to get to some code I want to change. Now, because I'm another World's Greatest Software Developer, I'll be careful not to embed the dependency too deeply and keep my packages clean and layered, but that's intellectual overhead I could do without. When SalesLedger is an interface, I have a clear distinctions between the domains of marketing and persistence, and I cannot let the abstractions leak through. If I do this for all my external dependencies, I can package up my domain code and use it in all sorts of ways I haven't thought of yet. The top-level Application then becomes a matchmaker, introducing all the modules to each other and helping them get started.
The more subtle issue is that SalesLedger, the interface I use in the body of my code, is in a different domain from the HibernateLedger, a class that implements it (and maybe some other interfaces). The code that uses a SalesLedger is concerned with marketing and payments, the code that uses a HibernateLedger is concerned with setting up connections. There may only be one implementation of an interface, but the two types are addressing different things.
Is this breaking YAGNI? I don't think so (although there are others that do). I'm not adding features I haven't identified a need for yet. Part of the deal with YAGNI is that I make the code as expressive of my current intentions as I can, and I think I'm expressing the needs of the domain code needs more clearly by limiting its dependency to an interface that defines just the services it needs from other parts of the system.
n.b. Gulliver image taken from news.bbc.co.uk