Author of Metawidget: http://metawidget.org Richard has posted 4 posts at DZone. View Full User Profile

Rant: Who Designs These UI Frameworks Anyway?

12.01.2010
| 7836 views |
  • submit to reddit

I've been working with a few different UI frameworks lately as part of building Metawidget, and I've noticed something...

Building Consensus

First let me state some things I hope we can all agree on:

  • Rule 18 of Effective Java: Prefer interfaces to abstract classes
  • Rule 16 of Effective Java: Favor composition over inheritance
  • The industry trend toward POJO-based development is a positive one

If you accept all these, then I have a shock for you: most UI frameworks ignore them. Oh sure, UI frameworks love defining interfaces for you the developer to have to pass them (MouseListener, SystemEventListener etc) but when it comes to adhering to these rules themselves, internally? Not so much.

Swing of Doom

Here's the challenge: how come hardly any UI frameworks define their widgets in terms of interfaces, as opposed to abstract base classes? Why isn't, say, Swing's JComponent an interface? By all means have a JComponentImpl as a convenience class, but don't force me to extend from it. Many programming languages use single-shot inheritance, so if you constrain my single-shot I'm screwed if I want to develop, say, some cross-platform UI functionality or a composite component without putting everything inside a JPanel.

It's Not Just Me, They're All Doing It!

Sure you could argue this is a corner-case, and that Swing predates much of the modern wisdom, but just look at this list:

Framework Base Interface?
SwingJComponentNO
AWTComponentNO
SWTWidgetNO
JSFUIComponentNO
WicketComponentNO
AndroidViewNO
JavaFXNodeNO
FlexUIComponentNO
GWTUIObjectNO
Spring MVCAbstractFormTagNO
ASP.NETControlNO
PivotComponentNO

Where are the lightweight, POJO-based, interface-based (or even, gasp, annotation-based) UI frameworks?

A Shining Example To Us All

A twist to the tale: I did manage to find one UI framework that implements its base widget using an interface. What is this enlightened, cutting-edge, modern framework you ask? Why plain ol' Java Server Pages of course! Its base Tag is an interface, with convenience class TagSupport. JSP, eh? Before its time or what :)

Published at DZone with permission of its author, Richard Kennard.

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Tags:

Comments

jocke eriksson replied on Wed, 2010/12/01 - 2:40am

I totally agree with you on this on. The cure is to use composition in your own classes and only expose necessary methods from that component in your interface, using method forwarding.

Karl Peterbauer replied on Wed, 2010/12/01 - 3:47am

I also have the impression that current UI frameworks rely on inheritance too heavily. But your Tag example is simply silly. JSP tags provide fairly limited functionality: They generate some markup during page rendering, nothing more. No big deal to define an interface here. They can be seen as the equivalent of Swing's ComponentUI or JSF's Renderer, but they cannot be compared to JComponent or UIComponent.

Haiku Ukiah replied on Wed, 2010/12/01 - 5:50am

Precise instructions and recipes you need no more.
Proficient you are.
But patterns and principles you follow bindly.
Expert you are not.

Purity a virtue is,
But when a dead line you have,
Pragmatic must you become.

And Remember you must,
From principles beauty is derived not,
But from beauty itself
Extracted are the principles.

Christian Ullenboom replied on Wed, 2010/12/01 - 6:34am

If there is just one implementation of an interface then some abstract class might be more appropriate. Otherwise interfaces just add complexity. An interessting comment comes from Elliotte Rusty Harold where he discusses the XOM-design: http://www.xom.nu/designprinciples.xhtml#d0e235.

Andrew McVeigh replied on Wed, 2010/12/01 - 7:26am

i agree, i think that all UI toolkits should come with an interface taxonomy.  the toolkit creators spend all their time ranting and raving about model-view-controller, or how it is decoupled in some fancy way...

if interfaces are not used, the protocols get confused over time.  for instance, have a look at the swing hierarchy for JButton and the hundreds of associated methods.  which methods are specific to button pressing?  which are specific to being a contained widget?  who could implement a replacement for that, or a good mock for that for specific situations?

but jsp tags have their own issues...  and they don't provide interfaces in some places where they are sorely needed -- intertag comms and interaction with the request.

Greg Brown replied on Wed, 2010/12/01 - 8:02am

I can only speak for Pivot, but the Component class is abstract because there is a LOT of functionality in it. The purpose of a framework is to save the developer time. It is unlikely that any framework user is going to want to invest the time in re-implementing all of this functionality.

> Rule 18 of Effective Java: Prefer interfaces to abstract classes
Perhaps thanks to this advice, interfaces are overused. Not everything needs to be divided into a Foo and a FooImpl. This just introduces unnecessary complexity and impairs readability.

> Rule 16 of Effective Java: Favor composition over inheritance
The "component" and "container" constructs facilitate composition in most, if not all, of these frameworks.

G

Laird Nelson replied on Wed, 2010/12/01 - 8:24am

Goodness; the Component class and its children are abstract--not interfaces--so that when they add a new method to it 40 million Swing applications around the world don't suddenly stop working.

arjan tijms replied on Wed, 2010/12/01 - 8:33am

I agree with Laird that there are also advantages to having the Component bases as abstract classes.

Nevertheless, this was one of the few surprises for me in JSF. I think the framework is very well designed, but when I browsed through the source code of UIComponent and the almost mandatory UIComponentBase, I was surprised that a lot of functionality that you would expect to be in the framework itself that calls my components, was actually embedded in those base classes.

Andrew McVeigh replied on Wed, 2010/12/01 - 8:41am in response to: Laird Nelson

Goodness; the Component class and its children are abstract--not interfaces--so that when they add a new method to it 40 million Swing applications around the world don't suddenly stop working.

That's a simplistic analysis.  of course they are backed into a corner now and have no choice.  If they'd started with role interfaces (container, button, component), we'd be in a much better position now.

 

Ronald Miura replied on Wed, 2010/12/01 - 8:43am

Abstract classes have many advantages.

  • They evolve better (you can't add methods to interfaces).
  • You can force consistent behavior by making some methods 'final'. This way you can 'hardwire' core behavior, such as controlling the lifecycle of the component. 'Code to interfaces, not implementation' is a beautiful advice, but not *always* practical.
  • Depending on the case, the code you write to extend them is more concise than to pass in an interface.

Anyway, one thing is to create and extend components, other is how you compose them to build your views, and another is how you handle events. Most toolkits use inheritance for component creation, composition for view building, and interfaces for event handling. So, you do use composition and interfaces most of the time.

One more thing, JSP tags are not components, they are macros.

Robert Lauer replied on Wed, 2010/12/01 - 8:58am

My biggest point of criticism is that no UI framework seems to be designed with testability in mind. Lack of interfaces is one issue, but the monolithic nature of components is a much bigger issue in my opinion. Add to that the very complex yo-yo interactions of UI components across deep class hierarchies. Just try to debug into a Swing application. SWT is worse in many respects, since you cannot even debug into the native part of a component.

Andrew McVeigh replied on Wed, 2010/12/01 - 9:21am in response to: Ronald Miura

Abstract classes have many advantages.

they have advantages for implementation, but if you couple directly to them instead of interfaces they will bite as your system gets larger.  my view is always use interfaces, as well as using abstract classes to ease the implementation effort.

  • They evolve better (you can't add methods to interfaces).
You can also subclass interfaces and add methods there - this gives v1.0 and v1.1 of the interfaces with compiler enforced substitutability.
  • You can force consistent behavior by making some methods 'final'. This way you can 'hardwire' core behavior, such as controlling the lifecycle of the component. 'Code to interfaces, not implementation' is a beautiful advice, but not *always* practical.
Coding to interfaces should be the starting position.  Break the rule when you need to, but don't start coupling directly to abstract classes, particularly if you are making a serious library.  Making things final and combining them with inheritance is guaranteed to bite you when you need to add something later, particularly if you don't own the final class.  Use final with composition, avoid it with inheritance.
  • Depending on the case, the code you write to extend them is more concise than to pass in an interface

Sure, it might be a bit more concise, but it's penny wise and pound foolish.  As your system grows, if you couple to classes rather than interfaces, then you will be:

1. unable to easily switch in alternative implementations -- you will always carry the implementation baggage

2. have trouble testing

3. preventing others switching in completely different implementations -- for the proof of this, look at the magic that alternative implementations of swing (swing on top of swt, ajax swing etc) must go through.

4. complicating the system for the next generation of people working on it.  expect questions like "which methods of this 1000 method class are actually used in this context"

abstract classes work well, but only when combined with interfaces to reduce coupling to a specific implementation class.  i.e. create an interface, couple to it, and provide an abstract class that eases implementation in common scenarios.  that's a win-win situation.

Ronald Miura replied on Wed, 2010/12/01 - 11:57am in response to: Andrew McVeigh

they have advantages for implementation, but if you couple directly to them instead of interfaces they will bite as your system gets larger. my view is always use interfaces, as well as using abstract classes to ease the implementation effort.

This is an issue for your application. The post is about designing a UI toolkit. A UI toolkit will eventually grow, but it's growth is mostly limited to its component library. The core abstraction itself (which is the point of the discussion) usually is fairly stable (in size and complexity), and will only bite you if poorly designed (oh, 'good' design != only use interfaces).

You can also subclass interfaces and add methods there - this gives v1.0 and v1.1 of the interfaces with compiler enforced substitutability.

... and creates versioning hell. You will soon have IComponent, IComponent_v2, IComponent_v3, IComponent_v4 (which is identical to v3, but must follow the product's version for consistency). No, thanks.

Coding to interfaces should be the starting position. Break the rule when you need to, but don't start coupling directly to abstract classes, particularly if you are making a serious library.

Don't start with anything. Think. Think in the situation at hand, and where you want to go from there.

Overusing interfaces will bite you too. The Service/ServiceImpl plague is an example. Interfaces work better if they are small, but having lots of small interfaces complicates the system. It's perfect for validators, converters, and listeners, but components don't just "render()", they have structure, they have a lifecycle, much more complex behaviors that are difficult to map to interfaces nicely.

Making things final and combining them with inheritance is guaranteed to bite you when you need to add something later, particularly if you don't own the final class. Use final with composition, avoid it with inheritance.

Making things final is a design decision, and have its pros and cons. If you own the class with final methods, it's easier to maintain it, because it guarantees that no user of the class have overridden methods that they shouldn't. Swing, for example, is extremely difficult to evolve, because it's extendable by default, and people have done many weird hacks by overriding its internal methods.

Sure, it might be a bit more concise, but it's penny wise and pound foolish. As your system grows, if you couple to classes rather than interfaces, then you will be:

1. unable to easily switch in alternative implementations -- you will always carry the implementation baggage

You assume that changing implementations is good, and should be an objective of every design. If the implementation works, you don't need to change implementations. Not the core, at least.

2. have trouble testing

You'll have trouble testing if you can't assume anything besides the name of the methods of some class. If a method is final, or it works, or it doesn't. No subclass will be able to mess it up.

3. preventing others switching in completely different implementations -- for the proof of this, look at the magic that alternative implementations of swing (swing on top of swt, ajax swing etc) must go through.

Swing on top of SWT or HTML+Javascript is not difficult because it uses classes instead of interfaces, it is difficult because Swing was not designed for that kind of thing. It assumes the existence of the AWT event thread. It assumes that you can draw everything in low-level calls such as drawLine() and fillRect(). It assumes that people can override every method of every class (because they do that).

Try picking some cross-platform toolkit, and you'll see that it constrains much of the programmer's freedom, for portability's sake.

4. complicating the system for the next generation of people working on it. expect questions like "which methods of this 1000 method class are actually used in this context"

What about "which of these 1000 interfaces (and which versions) are actually used in this context"? If the answer is "it's a rotten design, there shouldn't be that many interfaces", than the same can be said about the 1000 methods.

abstract classes work well, but only when combined with interfaces to reduce coupling to a specific implementation class. i.e. create an interface, couple to it, and provide an abstract class that eases implementation in common scenarios. that's a win-win situation.

If every time you implement that interface you extend the abstract class, there is no need for the interface. I agree that most of the time the 'combo' interface + default abstract class works well, but you simply can't say it is the golden rule of design.


That said, abstract classes are not better than interfaces, nor interfaces are better than abstract classes. One is better than the other in some situations, but the inverse will be true in others. Without context, there is no 'right' or 'better' way of designing things. In UI Toolkit design specifically, both are valuable, and which one you should use will depend on the context, and the design goals.

Erich Gamma gave an interview for Artima about design principles and patterns, in the context of the Eclipse project. He clearly favors interfaces, but is well aware of the benefits of abstract classes in the design of APIs, as can be seen in answers 2 and 3.

Andrew McVeigh replied on Wed, 2010/12/01 - 1:16pm in response to: Ronald Miura

This is an issue for your application. The post is about designing a UI toolkit. A UI toolkit will eventually grow, but it's growth is mostly limited to its component library.

I don't agree that this is the only dimension of growth for a UI toolkit.

All sorts of unusual uses come up for toolkits, and some of the work around swing is a case in point - people doing ajax implementations of it, people backing it onto SWT.  Anything of strategic importance will be used in ways that the original designer cannot anticipate.  Too much coupling to abstract classes, by fiat, will limit the ability to vary the implementations and even if you manage to work around this you will carry around too much implementation baggage.  I work around the limitations of Swing abstract classes every week.

And of course we shouldn't use interfaces everywhere, I'm not saying that.  But let's not couple ourselves to more than we need to.  If you depend only on 5 methods for a significant widget, and those methods describe the responsibilities of that widget, you'd be foolish to use an abstract class instead of an interface unless you were *absolutely* certain you knew all the usages.  The more significant a library, the greater the need for interfaces.

If a method is final, or it works, or it doesn't. No subclass will be able to mess it up.

The fact that you are restricted to that final method's implementation, and other classes expect to find that method there, will hold you back in advanced cases.

Try picking some cross-platform toolkit, and you'll see that it constrains much of the programmer's freedom, for portability's sake.

Being cross platform is an orthogonal concern to designing with interfaces.  You can easily use interfaces when building platform specific software also, and there is nothing stopping a cross platform framework from using abstract classes. 

If every time you implement that interface you extend the abstract class, there is no need for the interface.

We are talking about class A is directly coupled to abstract class B.  Even if you never intend to vary the implementation of B, you will want to test A without B or use a mock. My point is that the more important A & B are in their own right as abstractions, the more you should trend towards interfaces.

That said, abstract classes are not better than interfaces, nor interfaces are better than abstract classes

Of course not.  They each have their uses.  However, the fact remains that when you couple to an abstract class, you are coupled to an implementation and depending on how widely used the library is, this can be a hindrance.

 

Greg Brown replied on Wed, 2010/12/01 - 1:21pm in response to: Andrew McVeigh

That's a simplistic analysis. of course they are backed into a corner now and have no choice. If they'd started with role interfaces (container, button, component), we'd be in a much better position now.
No, we wouldn't. See my comment above - there is no way an application developer is *ever* going to want to implement the large number of methods required to support Component, JComponent, or whatever. In fact, they may not even be able to - abstract classes can take advantage of protected or package private methods. Interface implementations that live in a different package can't.

The bottom line is that the designers of these frameworks are applying OO design principles effectively. Inheritance, composition, and interface implementation are all useful tools, and a good developer knows how and when to best apply them.

Andrew McVeigh replied on Wed, 2010/12/01 - 1:45pm in response to: Greg Brown

here is no way an application developer is *ever* going to want to implement the large number of methods required to support Component, JComponent,...

a large part of the reason why these classes are so damned large and ornery is simply because they didn't use interfaces.  instead, abstract classes allow a lot of the infrastructural implementation (accessibility, tabbing etc etc) to live inside the widget classes and they get immensely complex.

IMHO using interfaces often tends to push you to a better design where infrastructural code (that often ends up in widget abstract classes) is in a common place, simplifying widget design and implementation.

Andrew McVeigh replied on Wed, 2010/12/01 - 1:58pm in response to: Ronald Miura

Erich Gamma gave an interview for Artima about design principles and patterns, in the context of the Eclipse project. He clearly favors interfaces, but is well aware of the benefits of abstract classes in the design of APIs, as can be seen in answers 2 and 3.

I take the point about abstract classes allowing default implementations and a level of evolution, however, this is a pretty weak form of extensibility (defaults) and it adds coupling.  in that respect, scala traits give the benefits of default implementations without losing the interface goodness (multiple interface implementations, ability to override).

we have perhaps been forced into a false dichotomy by the java constructs.

Greg Brown replied on Wed, 2010/12/01 - 2:30pm in response to: Andrew McVeigh

a large part of the reason why these classes are so damned large and ornery
Large? Yes - these are complex classes that form the core of major UI toolkits. Ornery - maybe not so much. The implementation of the Component class in Pivot is quite understandable.

abstract classes allow a lot of the infrastructural implementation (accessibility, tabbing etc etc) to live inside the widget classes and they get immensely complex.
What you are describing is simply one design approach, and it is not the only one. For example, in Pivot, the implementation of these behaviors is delegated to the skin - it is not hard-coded into the component itself.

Andrew McVeigh replied on Wed, 2010/12/01 - 3:12pm in response to: Greg Brown

Large? Yes - these are complex classes that form the core of major UI toolkits.

Sure.  Looking at Pivot's component class (2700 lines) I'd simply say that the forces are there to push more and more code into the abstract widget classes over time.  It's effectively the same as the Swing approach to widget inheritance, and we all know what happened there (JComponent = 5500 lines).

Am I saying Pivot is not designed well?  No, I'm not saying that, it seems very nice and understandable.  I had no problems understanding its internals.  I am though saying that I think that the design could benefit from some role interfaces and more composition. When we create inheritance forests and couple directly to these, we remove some potential for extension.  Does Pivot need this flexibility?  Perhaps not, only you and the Pivot team can decide this.

What you are describing is simply one design approach, and it is not the only one

Of course.  I know very well the pros and cons, and my preferences are derived from managing large teams working on corporate software.   I have become perhaps pathologically adverse to implementation inheritance, having (finally) finished a phd on component systems which disallows anything but composition and interface inheritance.

However, I'm not alone on prefering interfaces and composition to implementation inheritance. This is a constant theme of good designers from the GoF through to Josh Block in Effective Java. It tends to create more flexible systems as composition and delegation between two classes separated by an interface is easier to adjust than an inheritance hierarchy.

p.s. to bring this argument full circle, i'd simply point to the metawidget design as something that I like the look of: http://metawidget.sourceforge.net/media/wallchart/wallchart.png

they have interfaces where it counts, and use inheritance judiciously.  it's more of a compositional approach.

Chris Knoll replied on Wed, 2010/12/01 - 3:15pm

Andrew said:

"Of course not.  They each have their uses.  However, the fact remains that when you couple to an abstract class, you are coupled to an implementation and depending on how widely used the library is, this can be a hindrance."

 

This is actually not true.  An abstract class is, by definition, absent of implementation.  There is some implementation but only to the extent to give form to your abstraction.  What do you think is under the covers of a JWindow on a windows platform vs. the JWindow on the Unix one?  (Hint: on Windows, it would be some class that starts with Win32) Different implementations of a common abstract class allow you write your code on one platform and execute on the other. But do we expect developers to be given a series of interfaces and say 'Hey, implement these and you'll have a whole windowing toolkit'. I don't think that is a very reasonable statement.

Even with a published set of interfaces, those are making some rules about how the toolkit will be consumed and used in applications that implement it.  Isn't this restricting the growth of the framework? Aren't you 'binding' yourself to a particular toolkit by writing to their API such that if something new and improved comes along you will still have to rewrite to take advantage of the new apis?  But I digress...

I think if you look closer at the toolkit API (at least in the .net case) you'll find that things such as Component actually implement a wide range of interfaces that describe it's capabilities from a UI framework perspective.  It's not really an either-or choice. It's what makes sense for your specific situation.

 I think the whole premise for this rant is a bit ideological and perhaps even fanatical  to be taken seriously...

 

 

 

Andrew McVeigh replied on Wed, 2010/12/01 - 3:44pm in response to: Chris Knoll

This is actually not true.  An abstract class is, by definition, absent of implementation

Aargh...  As we all know, an abstract class can mix up implementations of methods with purely abstract methods.  Do you honestly think I don't know that?!

I think the whole premise for this rant is a bit ideological and perhaps even fanatical  to be taken seriously...

We are arguing about design choices that affect how people can evolve and use toolkits.  Case in point: I'm limited by some of the design decisions they took when making swing. 

And noone here is saying "use one way or the other" or "use one way to the complete exclusion of the other" - clearly each have preferences with pros and cons.

We are arguing a subtle and important point though - how do you design a complex (UI) library with widget hierarchies and complex callbacks and roles?  For my part, I simply say that a library is no different to normal software and the conventional rules apply: "prefer composition over inheritance" and "design to interfaces".  If that's considered ideological in these times, so be it.

Jonathan Locke replied on Wed, 2010/12/01 - 5:22pm

To be honest, this rant strikes me as very fundamentalist (extremist) in nature and not very flattering to the intelligence of the people behind these frameworks and Swing (I worked on both Wicket and Swing). Expecting to "build consensus" around an extreme idea like "everything should be an interface in Java" is self-centered at best and the sort of process-avoidant thinking that leads to a career of jumping from one extreme fad to another while avoiding the real learning that usually lies in the process of negotiating tricky gray areas (notice that Josh always says "prefer", and for good reason). There are some very good reasons that Wicket uses abstract classes in some places and interfaces in others, and unfortunately, unlike the sloganeering of a rant, the proof of this won't fit in the margins of this post.

However, I would like to invite anyone who wants to know all about what I think about abstract classes and interfaces and certain structural defects in the Java type system to read my book "Coding: On Software Design Process" (http://tiny.cc/db7cj). In particular, pay attention to Chapter 5, where I discuss both sides of this exact problem and outline ways that Java could be improved to make everyone more happy.

Here is a short excerpt from Chapter 5 discussing this very subject using a term i've coined (or rather borrowed from hardware), "micro-architecture", to whet your appetite:

"[...]

Thinking about micro-architecture reminds me of an interesting conversation I had many years ago when I was working on the Swing team at Sun Microsystems back in the early days of Java. Some peo- ple on the team were of the opinion that Component should be an interface and others that it was best as an abstract class. But really, neither sounded like a good choice. Abstract class is an unfortunate choice because it makes mock-object testing hard and limits Swing to one implementation of Component. But Component would be very awkward as a single interface as well, because it includes a large and growing collection of concepts. If component were an interface, every time you wanted to add a new feature to Component, you would break every piece of code that depended on that interface. While you can work around this by defining Component2, Component3 and so on, it seemed like there must be a better way.

The root problem, as I see it, is that Component and List (and many other Java classes) are not micro-architectural. The fact that they are molecules that are not composed of smaller atomic concepts limits reuse and causes interoperability problems. It would be more ideal if Component were an abstract class that implemented many narrow interfaces, one for each capability that the Component supports:

public abstract class Component implements Sizable, Locatable, Drawable,
Visible, Enabled, Parented, BackgroundColored, Focusable,
Named, Clickable, [...] { } [...] public interface Sizable { void setSize(Dimension dimension); } public interface Locatable { void setLocation(Point point); } public interface Drawable { void repaint(); } {

[...]"

Andrew McVeigh replied on Wed, 2010/12/01 - 5:47pm in response to: Jonathan Locke

strikes me as very fundamentalist (extremist) in nature and not very flattering to the intelligence of the people behind these frameworks and Swing

I apologise if that's the impression my posts gave.  I have strong views on the evolution of software and how frameworks should evolve, based on my own industrial experiences with large scale frameworks and my phd research.  I know that in the heat of battle many of these grand premises must give way to pragmatic engineering, working with the tools we have at hand.

The fact that they are molecules that are not composed of smaller atomic concepts limits reuse and causes interoperability problems. It would be more ideal if Component were an abstract class that implemented many narrow interfaces, one for each capability that the Component supports

I agree completely in theory, and I've certainly tried this as a guiding principle on a mid-sized project (100kloc).   I found it to get problematic as I'd pass around something like (Sizable, Locatable) and then deep in the heart of the framework I realised I needed Focusable also, and I then had to go back up the stack chain and add it to all parameters.  In the end I opted for more broad interfaces.  The entire system is described by about 30 interfaces, some quite large now.

For me, the answer to the dilemma comes down in part to the fact that our languages are very well oriented towards software creation, but not to evolution and extensibility.  Here is my effort on making a completely extensible system which avoids this problem: http://www.intrinsarc.com/backbone/research

 

 

 

 

Jonathan Locke replied on Wed, 2010/12/01 - 5:55pm in response to: Andrew McVeigh

Well, yes. But one of the tools we have at hand that is limiting our ability to solve this particular problem is Java itself. The quote I gave is out of context. To understand what I really mean and how granular interfaces could be used to solve this problem in a re-envisioned Java type system, you'd have to read the rest of the book (which is not large... it's 70 pages)... but the basic gist of it is that Java should provide much more convenient ways for combining types through public interfaces than it presently does. In the meantime, we have abstract classes and interfaces and you might be surprised at how little is lost in the use of abstract classes in Wicket. It's all a matter of where and when and how you use them, not whether. The choice of Component as an abstract base class in Wicket is, in my view, a reflection not of design that could be improved but of flaws in the underlying language. It's not yet possible to write Component the way I really want to write it. To do that, you'd have to change Java.

Jonathan Locke replied on Wed, 2010/12/01 - 6:09pm in response to: Robert Lauer

This also gets to my points in the book about fine-grained interface composition and "micro-architectural" designs. Micro-architectures are highly testable because they are well-reduced thinking. In the end, all problem solving in software (that has to do with complexity anyway) has to do with a single technique: divide and conquer. If you can't divide things down to a pretty atomic level, you can't test anything in a meaningful way. The exact issues you are talking about in monolithic components can, IMO, only be resolved by a fairly fundamental change to the Java type system (or in whatever language comes next... although I can't stand to look at Scala code because it is so notational (non-linguistic), it certainly better addresses the sorts of issues we're discussing than Java)

Andrew McVeigh replied on Wed, 2010/12/01 - 6:10pm in response to: Jonathan Locke

But one of the tools we have at hand that is limiting our ability to solve this particular problem is Java itself.

Yes, completely agree.  In many ways, the polarisation in this entire thread is caused by us needing to choose between two incomplete constructs.

To understand what I really mean and how granular interfaces could be used to solve this problem in a re-envisioned Java type system, you'd have to read the rest of the book (which is not large... it's 70 pages)

Sounds interesting and I'll get it and have a read.  I hadn't heard of it before.

 you might be surprised at how little is lost in the use of abstract classes in Wicket

I'm not against abstract classes per se, it's just that in a framework, following established OO practice (i.e. allocate responsibility with the object) tends to over time breed very large abstract base classes which cause problems because they will never allow sensible alternative implementations. It's not the way they start out, but the inheritance naturally pushes extra functionality into a fat base.

using interfaces is no panacea, but I've found it to force me into keeping much of the infrastructure out of the widgets.  so, in my own product, i started with very large classes, each of which used the logic in a large base class to handle undo/redo.  i moved this out into infrastructure, which mean that each widget no longer handled its own undo/redo, but it very much improved the overall architecture at the cost of losing some encapsulation.

 

 

Jose Maria Arranz replied on Thu, 2010/12/02 - 3:15am

 

Framework   Base                    Interface

------------------------------------------------

ItsNat          ItsNatComponent    YES

ItsNat          anything else          YES

 

Said this I absolutely love inheritance, ItsNat uses a lot of inheritance internally and inheritance is absolutely fine if you know how to deal with it. However in my opinion is a REALLY BAD idea to expose a public API based on classes to end developers, so ItsNat public API is 99% based on interfaces, many of them are "identificative" interfaces (to be used in instanceof sentences), in fact the current implementation could be rewritten preserving end user code.

 

Andrew Spencer replied on Thu, 2010/12/02 - 4:27am

It's been a pleasure reading this discussion.

I would like to add Vaadin to the list of UI frameworks, as an example of a framework that operates in terms of interfaces but provides an abstract class which virtually all components extend in practice.

I haven't the experience with framework design to know which approach least constrains framework evolution. But as a user of UI (or any other kind of) frameworks, I prefer them to define interfaces, since it is easier to mock interfaces for testing. (That goes against the principle that one shouldn't modify one's code to make it testable, but I don't really agree with that principle anyway.)

Roman Dawydkin replied on Thu, 2010/12/02 - 5:36am

In SWT, you almost always should not subclass widgets (some of them iformally marked as final), so there is no need for them to be interfaces, indeed because of "rule 16 - favor composition over inheritance".

E Micklei replied on Thu, 2010/12/02 - 5:43am

Although not really a UI framework in the sense that it provides a set of reusable widgets, the open-source renderSnake library is designed with interfaces and promotes composition of POJO based component implementations.

This HTML presentation library is relatively new but some of its concepts where taken from the popular Seaside framework. You define your component by implementing the Renderable interface that requires the class to implement just one render method that takes a HtmlCanvas object. The canvas object is used to "paint" HTML elements. The library also provides interfaces for user interaction such as FormHandler and FormValidator.

As for a widget collection, I strongly believe that every project should define their own on top because then their behavior (interaction) and appearance (structure and style) can be defined according to the actual needs. Only then their reusability will show benefits.

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.