Hacker News new | past | comments | ask | show | jobs | submit login

You contradict yourself here. Interfaces are useful for the same reason having private data is a good idea: separating the contract from the implementation. Interfaces are a description of what the consumer of the interface needs, not a description of some commonality between implementations. Interfaces can be useful even if you have no implementations.



Do you want to pay me several years income to write a book on this subject, including the cost of editors, publishers, and other things I'm not even aware of (I've never written a book). This is a very complex subject but I stand by it as a general rule even though there are some exceptions. In general if there is only one implementation just use it.


Not several years' income, but I might pay you up to $50 for it if it's good.

> In general if there is only one implementation just use it.

This is good advice for people who don't understand what interfaces are for -- which seems to be most people. If you make the mistake of believing that interfaces are for describing the commonalities between similar implementations, then demanding an IFoo for every Foo is indeed a waste. Generally if I see literally the same word twice, but one has an "I" in front of it, it's a flag that the interface might not need to exist. I think this is the advice you're giving here. But you've missed the other important point: interfaces are not "about" their implementations, they're "about" their consumers. The point of an interface is for the consumer to define exactly what it needs to do its job. That's why interfaces can be useful even if there are 0 implementations: it's still a clear definition of what some service or function requires. Assuming that service isn't private/internal, it's a hook that a consumer of your module can implement if they choose.

I'd say the frequency of the following patterns is correlated with different levels of code quality -- sometimes causally, sometimes spuriously.

    1. StringWarbler : IStringWarbler  (worst)
    2. StringWarbler                   (fine)
    3. StringWarbler : IWarbler        (maybe worse or better, but a bit smelly)
    4. StringWarbler : ITextProcessor  (good)
Yes, #2 is fine if all you need to do is warble strings and there's really only one thing that means. That's common and it's fine. #3 is suspect because it looks like it was abstracted along the wrong line. It looks like there were a lot of different "ThingWarblers" and someone tried to define what was similar about them, without really focusing on the consumers of these services. Whereas with #4, it looks like someone identified a need to process text in various ways, and one way to do that is to warble them. It sounds like the interface was created to describe a need, not an implementation. When you do it this way, you start to see classes that implement two or three interfaces as well.

When I see #2 everywhere, I don't think "these classes need to be implementing more interfaces!". Instead I think "the services relying on these classes are probably not doing a good job specifying exactly what they need to do their job, and are therefore brittle against changes in how those needs are fulfilled." Whether that's a problem depends on the exact situation. I feel like your advice is "prefer #2 over #3", which I generally agree with. But the better advice is "ask for what you need to do your job, in the most general form you can", which #2 (in excess) violates.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: