Java Forum / General / January 2006
Design for Extension
Martin Ankerl - 17 Jan 2006 09:11 GMT Hi! I have recently read about Design for Extension [1], which says that all your methods should be either
* abstract, * final, or * have an empty implementation
This forces you to design the classes for extension, i.e. provide hooks for each extension you need. I used to be an opponent of final methods, because you never know in advance when you have to extend something. But from the viewpoint described in [1] this makes a lot of sense. What are the opinions on this topic? I could not find anything with Google. I am curious if anyone here has use this approach for a project and can share his experience?
[1] http://checkstyle.sourceforge.net/config_design.html#DesignForExtension
 Signature Martin Ankerl | http://martinus.geekisp.com/
Thomas Weidenfeller - 17 Jan 2006 10:50 GMT Martin Ankerl wrote:
> Hi! I have recently read about Design for Extension [1], which says > that all your methods should be either [quoted text clipped - 8 lines] > But from the viewpoint described in [1] this makes a lot of sense. What > are the opinions on this topic? It is religion. If you are in need of another faith, then consider XP. One of the fundamentals of XP is
*You ain't gonna need it*
Which e.g. means, you do not explicitly design your stuff to be expendable, unless the extension is needed right at the moment. The XP arguments for doing so also make sense.
/Thomas
 Signature The comp.lang.java.gui FAQ: ftp://ftp.cs.uu.nl/pub/NEWS.ANSWERS/computer-lang/java/gui/faq http://www.uni-giessen.de/faq/archiv/computer-lang.java.gui.faq/
iamfractal@hotmail.com - 17 Jan 2006 12:10 GMT Object-orientation is based on variance-encapsulation (see GoF), so to practice object-orientation you must know:
A) What quality of a system is varying, and B) How to encapsulate that quality.
Varying necessarily means, "Varying with time," so unless you're planning to design a system that's moving into the past, then there is some aspect of the future that you'll find yourself contending with.
People sometimes use the phrase, "Don't design for the future," as though desiging-for-the-future carries a cost and not-designing-for-the-future is free: this is an inaccuracy.
To practice variance-encapsulation you must of course practice encapsulation; and to practice encapsulation you must identify your system's natural fracture-lines and carve it up appropriately: those carved pieces must then be encapsulated from one-another.
This is inevitable, whether you're designing for the here-and-now or the ever-after; this is a cost even for not-designing-for-the-future. (And make no mistake, there is a great harvest of benefits to be reaped from this approach: increased comprehensibility and maintainability to name but two.)
The question is: what informs these natural fracture-lines? What makes encapsulating AB from C more, "Natural," than encapsulating A from BC?
The answer splits the discipline of obect-orientation in three, giving rise to immediate, tactical, and strategic object-orientation.
If you're really lucky, your requirements will tell you, "We need a C, but we also need a D and an E which should be swappable with C from AB's point of view," and your iteration plan will say, "We need C, D, and E delivered in the first iteration."
Then the solution is clear: you need to employ immediate object-orientation: you are being told exactly what is varying and what to encapsulate and when to deliver them altogether. Put C, D, and E behind the same interface and have AB program to this interface.
This is an XPer's (and most people's) delight. This is a sure sign that your product is being driven by solid requirements. This project will probably deliver a product that somebody (maybe the customer but certainly Product Management).
If you're a little less lucky, your requirements will say, "We need a C, but we also need a D and an E which should be swappable with C from AB's point of view," and your iteration plan will say, "We need C, in the first iteration, and D and E in the second and fifth iteration."
Then the solution is clear: you need tactical object-orientation. You're being told exactly what is varying and what to encapsulate and that they'll be delivered at different times.
Only the shortest of the short-sightest would look at the requirements for the first iteration in isolation, and decide not to encapsulate C from AB. So here we are designing for the future, but there are degrees of future, and this future seems pretty certain.
Of course no future is completely certain, and in the second iteration, the requirements may change, and the D and E parts may be dropped, meaning that the fracture-line you've chosen to cut between AB and C could have been a waste of time; but even if those requirements hadn't been dropped, you might still have chosen to cut a fracture-line somewhere in the mass of ABC, just for comprehensibility/delivery/maintainability - and those benefits are still accrued from the AB/C split.
Finally, you may have no requirements beyond the end of your project, and thus don't know what might vary, and so don't know what to encapsulate. But there are always hints to be found in the nature of your product. (And this is where a product road-map is essential to object-orientationists.)
If you're designing an operating system, you probably won't hard-code it to a particular file system. You have no requirements on your desk taht say, "We'll have a new file system in three releases' time," but it's possible, so you may chose to encapsulate the file system from the kernel.
Similarly, you may be designing a car's engine-control system, and decide that, in future, an electric engine might come along after the current diesel engine, and so encapsulate those parts common to both. In the end, of course, no electric engine may come along, and that encapsulation work might be completely wasted.
This is strategic engineering, and it is the most dangerous (uncertain) of the three. XPers seldom invest much effort in this; and I think they may be right.
I doubt that the best approach to product-development is either a rabid fear of the future or an all-comsuming addiction to it. The best (that is, most cost-effective) solutions tends to snake somewhere between the two.
Gotta love engineering ...
.ed
-- www.EdmundKirwan.com - Home of The Fractal Class Composition.
Chris Uppal - 17 Jan 2006 13:19 GMT > Object-orientation is based on variance-encapsulation (see GoF), so to > practice object-orientation you must know: > > A) What quality of a system is varying, and > B) How to encapsulate that quality. A sensible post, but I want to raise a couple of quibbles.
> Varying necessarily means, "Varying with time," so unless you're > planning to design a system that's moving into the past, then there is > some aspect of the future that you'll find yourself contending with. I don't think that's true. The variance can occur across several axes. For instance, we might want to have AB+C at one site, and AB+D at another. Or one product line might include AB+C while another includes AB+D. Such variances also supply your "natural fracture lines".
Secondly, and in a way generalising that point, while variance does suggest object boundaries, I think it's an exaggeration to claim that it's the source of OO. If that were true, then in my own (personal) software, written with no thought to the future ('cos I have no idea what it is) nor consideration of other possible variance (since it's only used by me, typically for only one purpose), I would have no idea where to put object boundaries. Indeed I could /only/ structure my applications as one big object. Obviously that's absurd. Variance is only one of the inputs to OO design, and managing variance over time is only one of the benefits of OO code.
I don't suggest that you really hold the views I'm disagreeing with above, but your words could certainly be taken that way.
(None of this has anything to do with the OP's question, of course ;-)
-- chris
iamfractal@hotmail.com - 17 Jan 2006 13:53 GMT All good points, Chris.
I should be more careful with my words.
(Late night last night, watching, "Vanilla Sky; don't know why the critics slammed that so hard.)
.ed
-- www.EdmundKirwan.com - Home of The Fractal Class Composition.
Martin Ankerl - 17 Jan 2006 12:57 GMT Actually I think "Design for Extension" can work very well with XP. The difference from the normal approach is, that whenever you need to extend a class, you cannot just make a subclass and override a method; you need to refactor the base class and add an extension hook somewhere first.
I think this might be a very good way of developing software. These are the advantages/dissadvantages I see with this approach:
+ No beeing able to forgett to call super() in a subclass + Whenever behaviour of the base class is modified, it is done at a place where it is designed to be extended.
- You have to be able to access and modify all the code you have to be able to add hooks which can be very problematic with libraries.
 Signature Martin Ankerl | http://martinus.geekisp.com/
Martin Ankerl - 17 Jan 2006 13:01 GMT Actually I think "Design for Extension" can work very well with XP. The difference from the normal approach is, that whenever you need to extend a class, you cannot just make a subclass and override a method; you need to refactor the base class and add an extension hook somewhere first.
I think this might be a very good way of developing software. These are the advantages/dissadvantages I see with this approach:
+ No beeing able to forgett to call super() in a subclass + Whenever behaviour of the base class is modified, it is done at a place where it is designed to be extended.
- You have to be able to access and modify all the code you have to be able to add hooks which can be very problematic with libraries.
 Signature Martin Ankerl | http://martinus.geekisp.com/
Chris Uppal - 17 Jan 2006 13:18 GMT Martin Ankerl wrote:
> Hi! I have recently read about Design for Extension [1], which says > that all your methods should be [...] I tend to be extremely sceptical of prescriptive design principles. Even more so of Names With Capital Letters.
If I ask someone why some aspect of a design is the way it is, or why something is coded in a specific way, then I expect to get an explanation in terms of the other aspects of the design (current, historical, or anticipated). That's to say, I want a reasonably concrete explanation. If the author tells me that it's because of <some Design Principle>, then s/he has told me nothing except that s/he quite probably doesn't understand his/her own design. (The -- important -- exception to this is s/he's using the name of the Design Principle just as a short-cut for something more concrete that s/he knows I'll be able to recognise from the name).
In this case, the discipline of making all methods either abstract or final may well be appropriate in some cases. But I wouldn't claim that it's appropriate in all, or even most, cases. And the decision whether to follow that discipline in some case should be based on the requirements of that case, not on the tenets of some Design Principle.
-- chris
Michael Redlich - 17 Jan 2006 17:47 GMT > Hi! I have recently read about Design for Extension [1], which says > that all your methods should be either [quoted text clipped - 13 lines] > [1] > http://checkstyle.sourceforge.net/config_design.html#DesignForExtension Hi Martin:
The "Design for Extension" section of the article is obviously trying to point out the importance of good object-oriented design.
As Chris and Ed had already mentioned, it is indeed difficult to predict common object behavior in an abstract class or interface. You obviously want to write software that is robust and easy to maintain. This is why design patterns are such a big help, but you also need to be careful because applying a design pattern in the wrong context can cause more harm than good.
It is important to understand some of the design principles at work, such as:
"Program to an interface, not an implementation."
For example:
Manager manager = new Manager();
is an example of programming to an implementation. You are basically stuck with the defined behavior of a manager object that *cannot* be changed at runtime. However:
Employee manager = new Manager();
is an example of programming to an interface (Employee being an interface), and allows the employee object (manager variable) to be changed at runtime by, say, with the Decorator design pattern.
Along with the GoF book, I would also recommend the Head First Design Patterns book. Check out http://www.wickedlysmart.com/. There are links to all of their books and source code from them.
Sincerely,
Mike.
--- ACGNJ Java users Group (http://www.javasig.org/)
Free MagazinesGet these publications absolutely FREE for up to 12 months. There are no hidden fees and no obligation. Simply choose a title, complete the application form and submit it. Read more ...
|
|
|