I’ve been railing on why you should be coding against interfaces, and a number of you have been asking me to write an article about it, so I did. It turned out to be pretty long, so rather than make it a blog post, I turned it into an article.
1/23/2012 1:24:11 AM #
It's disappointing that you did not even quote the SOLID principles here. This is IMHO the main use of interfaces nowadays. See blog.synopse.info/.../SOLID-design-principles
You should also at least mention the fact that Delphi's Interface implementation may be broken in case of circular reference. This is the main need of a "weak pointer reference" in the ARC implementation model of Interfaces - see blog.synopse.info/.../Avoiding-Garbage-Collector%3A-Delphi-and-Apple-on-the-same-side and all references about this issue in the forum - synopse.info/forum/viewtopic.php?pid=3198#p3198
1/23/2012 8:23:29 AM #
I quoted two of the five....
1/24/2012 2:05:32 AM #
Of course, some of the SOLID principles are redundant (if you break one, you'll probably break other four). But when talking about modern use of interfaces, I think this is one keyword worth mentioning in a "Why interface" speach.
1/23/2012 2:33:24 AM #
Lack of support of Delphi Interfaces for circular references, as Arnaud pointed, is a rather serious blow to their usability in Delphi.
What you can read about interface-based design in other frameworks just doesn't apply 1:1 in Delphi, most of the time it means you can't use them for internal collections, and it can trun using them for anything with any form of events or callbacks an exercice into making a Rud Goldberg contraption.
1/23/2012 2:40:31 AM #
Minor correction: it is Erich Gamma.
1/23/2012 8:22:56 AM #
1/23/2012 5:22:05 AM #
Sorry to say but your EncryptSomething example is complete rubbish in the context of talking about how coding against interfaces and clean code. Even if it was just to show how to use them. You might watch Misko Hevery's session about how to write clean and testable code especially where he talks about avoiding calling constructors at the wrong places.
In that example you created a piece of code that is completly untestable. Wherever you call that EncryptSomething you are bound to the implementations of TSuperDuperPowerfulEncryption and TWhoCaresHowSafe and you have no possibility to change that implementation.
And wasn't that the whole purpose of this coding against interfaces stuff?
1/23/2012 8:21:35 AM #
It was just for illustrative purposes, but you are right, it's not testable.
1/23/2012 10:35:41 AM #
Country bumpkin coder here. In looking at your article, you give an example of a "Leaky" abstraction in a database backend. I'm kinda reckoning interfaces as the layer between the greasy side and the shiny side.
I'm wondering about connection details and communication of those from the shiny side. If I have a client that can connect to 3 different database backends, then an important part of that definition are the connection details. These sit firmly in the "implementation" camp.
I might be able to decouple the two sides thru an .ini file, or a registry setting, but it seems like this would still be "a leak". Is this an example where you just have to accept that leak, or is there some other strategy that you can suggest.
Thanks for your thoughts on coding. I learn an awful lot from reading your posts!!
1/23/2012 10:40:55 AM #
You ask a good question -- it is a tough thing to do correctly. Ensuring that you don't have leaky abstractions is on small problem.
In the particular case of connections, I would say that the approach to take would be to feel free to have as much configuration go on in the implementing object as desired, and then pick and choose which implementation you want active at any moment.
1/23/2012 11:48:21 AM #
I find the entire XYZ programming scheme is better than ZYX programming scheme to be a fallacy at best. OOP with interfaces or without is not a silver bullet to all designs and styles of programming IMO. Thinking in absolutes changes great programmers into fussy good ones who tend to over complicate design. We often forget that good programming includes designing and writing code for those that follow us. Adding more layers into any set of code creates more performance barriers, more complex systems and requires greater skill to navigate. Take the JCL. It could have been a complete object based system, but it likely wouldn't be as succinct and easy to use as it is now in its almost entirely procedural form. I am not saying procedural is better what I am saying is that matching the style of coding to the job at hand is more important than some fixed design architecture.
1/23/2012 11:53:13 AM #
I have now read a number of these articles that are suppose to be showing me the answer to the "big why" question. While I understand all the stuff everybody explains all the time, I don't see a clear difference between abstract classes and interfaces. The only obvious difference is that with interfaces, multiple inheritance is supported. However, I have been coding in Delphi for over 10 years and been getting by without multiple object inheritance.
Is just that the cool kids use interfaces instead of abstract classes? What can an application based upon interfaces do that one based upon abstract classes can not?
1/23/2012 3:06:36 PM #
+1, My thoughts exactly.
1/23/2012 4:55:18 PM #
If you use a abstract classes then you are programming to an interface and that's an opinion supported by the Erich Gamma article that Nick linked to in his own article.
"It isn't always possible to define an interface in an abstract class, but in the light of evolution you should consider whether an abstract class is sufficient."
"writing against a type far up in the hierarchy is consistent with the programming to an interface principle"
Erich Gamma - www.artima.com/.../designprinciples.html
Personally I use both interfaces and abstract classes. Thinking about how I decide between the two I would say I usually choose an abstract class by default. I then move to an interface when I need to reuse the code in say a different application and the concrete dependencies won't allow that. Converting code that uses abstract classes to use interfaces is a pretty trivial task.
You do see some smart examples of interface usage but they're often so smart I wonder whether that was their first attempt or if it was only after several iterations of class based designs that they understood the problem well enough to extract such finely crafted interfaces.
Interfaces are useful but can make working with your code day to day a bit clunky (Ctrl+Click won't take you to the method implementation for example). Used at system boundaries and for genuine instances of reuse they can make sense, but so can abstract classes so my advice is to use them sparingly for the majority of projects.
1/23/2012 6:29:49 PM #
"my advice is to use them sparingly for the majority of projects"
I think I should clarify what I mean by the majority of projects. That is the majority of single purpose business applications with little code reuse or interaction with external systems apart from a database server.
As your application becomes more complex and you develop shared modules you should expect to make increased use of interfaces and/or abstract classes.
If you're writing a reusable framework rather than an application, interfaces are a very valid design choice.
1/23/2012 7:16:27 PM #
Really good comment, Lachlan -- thanks.
1/24/2012 2:00:50 AM #
IMHO Ctrl+Click won't take you to the method implementation in an abstract class either, since there is no implementation (it is abstract), but to the virtual; abstract; method declaration.
I see at least two benefits of interfaces in regard to abstract classes:
- More easy to be disposed on Client-Server - we are in a SOA world of programming;
- Abstract classes tends to create huge list of methods, and it is well known that ISP (Interface segregation principle) makes things cleaner (e.g. for mocking and testing).
I totally agree with you about the benefit of using abstract classes. Interfaces are no magic. For instance, our mORMot framework relies only on abstract classes for its Client-Server implementation - and it works nicely. But I'm adding interface support for easier SOA implementation - there is already services implemented within classes, but interfaces are better candidates here.
1/23/2012 6:01:26 PM #
In fact, Erich Gamma shows that sometimes (and maybe, a lot of times) abstract classes are better suited for your application than interfaces:
"When you have an abstract class, you can add a new method and provide a default implementation in it. All the clients will continue to work. As always there is a trade-off, an interface gives you freedom with regard to the base class, an abstract class gives you the freedom to add new methods later"
So... when you are building a new class and you really don't know the full scope yet (you know, changing requisites), abstract classes are the best choices, IMO.
1/23/2012 7:16:47 PM #
Good point, Alexandre --
1/25/2012 4:15:53 AM #
Delphi way of coding interfaces born to be COM "compliance": that's my view.
To be honest I cannot understand references counting and GUID in a pure Delphi application (or I missed something?).
1/28/2012 4:53:59 AM #
Search the web about SOLID principles, Dependency Injection, Factories and Stubing/mocking.
You'll discover a new way of programming, not mandatory for Delphi, of course - but worth considering in the 21th Century.
1/31/2012 2:55:48 PM #
You used create in your example!
To be honest, I liked the "what are interfaces" part more than "why use" part. I think you should spend more time on the "why" if the article title is "Why you should be using interfaces". Anyway, this and the Serg's post are bookmarked.
2/3/2012 11:42:33 PM #
An Interface Implementation Pattern for Consideration
An Interface Implementation Pattern for Consideration
The views I express here are entirely my own and not necessarily those of any other rational person or organization. However, I strongly recommend that you agree with pretty much everything I say because, well, I'm right. Most of the time. Except when I'm not, in which case, you shouldn't agree with me.
Powered by BlogEngine.NET 188.8.131.52
Theme by Mooglegiant and modified by Nick Hodges