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
| 7813 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

Christian Schli... replied on Thu, 2010/12/02 - 8:43am

Interfaces are good if they are small and easy to implement so that you can expect multiple implementations. However, UI components are the counter example: Their interface is big, complex and there is only one reasonable implementation. The latter is true even if you would compose their interface from many smaller subinterfaces. As a result, there's simply no point using an interface here. On the other hand side, using a class has many advantages that you can leverage on. You can provide an implementation, you can mark methods or the entire class as final, thereby forcing the user to favor composition instead of inheritance and so on. I think that's enough to justify why all the examples you've listed are using classes instead of interfaces for their base component type.

Andrew McVeigh replied on Thu, 2010/12/02 - 9:19am in response to: Christian Schlichtherle

Their interface is big, complex and there is only one reasonable implementation.

Why? Adding new components, and building on them, is a key part of using and extending a UI library.  If to make those new components you have to inherit from something like JComponent, then you are automatically limiting new widgets.

The latter is true even if you would compose their interface from many smaller subinterfaces

The point of the smaller subinterfaces is to limit what the underlying framework needs to know about the component.  So, if it just wants (IFocusable, IAccessible) you don't have to provide a monolith to it.

Ronald Miura replied on Thu, 2010/12/02 - 12:09pm

Tim Boudreau posted on his blog some time ago what he called the Capability Pattern, used extensively in Netbeans.

This is one way to keep the core small, and add capabilities as the software evolves, without breaking things.

That said, I think those capabilities fit better for 'add-on' features (IFocusable, IAcessible), not the core, structural characteristics that base classes are there for (the Component/Composition structure, standard lifecycle).

Eric Giese replied on Fri, 2010/12/03 - 4:25am

I'd like to add that none of the solutions is really worthwhile: abstract classes are too limited, interfaces create as correctly pointed out too much redundancy. The only proper OO-solution to this scenario is (mixin) multiple inheritance, which allows a more flexible composition.

But as pointed out, "modern" languages force us to choose one of two evils: Either code redundancy with interfaces (evil) or limited design flexibility with abstract classes. Why again was multiple inheritance removed? To create better code?

Andrew McVeigh replied on Fri, 2010/12/03 - 4:35am in response to: Eric Giese

But as pointed out, "modern" languages force us to choose one of two evils: Either code redundancy with interfaces (evil) or limited design flexibility with abstract classes. Why again was multiple inheritance removed? To create better code?

;-)

IMHO the issue is the coupling that inheritance creates between a sub and super class.  If a framework is coupled to the superclass, then no implementation can work with the framework unless it carries the baggage of that superclass even if it is not wanted in all situations.  This is still true with multiple inheritance, although perhaps to a lesser extent as you could make the superclasses fine-grained rather than a one-size fits all approach which single-inheritance forces.

In that sense, I am going to experiment with Scala traits and other mixin systems.  They solve some, but not all of these issues.

I think the patterns that Ronald pointed out are relevant in this regard: the capability pattern (netbeans) and the extension object pattern (eclipse).  It would be very interesting, I think, to design a language and type system specifically oriented towards evolvable "capabilities".

Jose Maria Arranz replied on Fri, 2010/12/03 - 5:16am

Inheritance is fine and good when you have source-level control of the base class, this is not the case of a public API, end users has no control of the code of the base class they are inheriting and almost nobody changes the source code of the tool being used.

Another downside of classes being public is for toolkit developers, when you expose a class you have a problem in the future to evolve this class because you are exposing TOO much. For instance end users are going to create objects with new sentences providing the necessary context information in constructor, if you need more context information in a future you have a problem because construction is also a public API.

For instance I remember when the developers of a famous UI toolkit proposed to end users to systematically change constructors adding a new context parameter. This context parameter (for instance the parent component to be inserted, the object representing the "web page" going to contain this component or similar) would be very useful to set up the component on construction phase, and end users said NO (some like "is your problem"). If the class is not exposed you don't have this problem you don't need to ask to end users or break end user's code. 

Another downside is the benefit of inheritance for the benefit of the toolkit, for instance, if the class of a component is not exposed you can create the appropriated internal implementation based on the parameters provided in some kind of factory method, if your class is public you are forced to provide several types of behaviour coupled in the same class plagued of "ifs" instead of some kind of inheritance used internally,  more elegant solution.

In the case of ItsNat, the interface ItsNatComponent for new components is an interface because provided methods are very simple to implement, furthermore, most of them could do nothing (or throw an exception) because most of them are not called by the framework.

Regarding to adding new APIs, I agree that in public classes you can add a new public method (to be called by the framework) and provided a default implementation (for instance "do nothing"), this is not possible in interfaces, if you add a new method you break the user code when he/she recompiles. But there is another option: put these new methods in a new "conceptual" interface related with the new feature, if the user component needs this new feature the developer can implement this new interface and the framework can ask the user componet with a simple instanceof before calling the new methods. The benefit of this kid of approach is it can help to divide the API by "features", if you look at the API of JComponent you see tons of methods that could be better classified by using interfaces.

I must recognize that web environment is usually a simpler place than desktop (for instance Swing), I agree with Greg Brown (desktop guy) and Jonathan Locke (desktop guy and web guy) desktop is pixel based and more complex and Component base classes do many things. However I think that composition can also work , you can extend the "configurable" behavior of a component with extensions the same like Swing allows pluggable renderers to replace the default behavior, you are not going to see classes derived from Swing's  JTable because JTable provides as pluggable extensions all your need, the same could be done for JComponent like an interface, you could create a prototype object (the default implementation) calling a factory method and extend it with "plug-ins". 

Anyway I must recognize that when I have complete control of source code of classes I prefer inheritance instead of composition (plugins explained before), of course when inheritance is the best option (when the question "I am X" is yes, inheritance is the path, different to "is part of me" a.k.a. composition), but this is not the case (in my opinion) in public APIs.

Ah, finally, coupling is not ever bad, when you inherit is because there is a strong "conceptual" coupling between classes. Like in marriage coupling is "sometimes" needed :)

 

Fadzlan Bin Yahya replied on Fri, 2010/12/03 - 11:12am

Yes you have one chance of inheritance, but in an MVC environment, if you are inheriting or implementing interfaces from the UI Toolkit framework, it does not make sense that you *want* to inherit from another set classes.

That would mean, even if those frameworks are using interfaces, if you try to inherit from another tree of class not related to UI implementation, then you have broken MVC anyway. That would simply mean the class that you design may have more than one responsibilities (ie. view and business logic).

Andrew McVeigh replied on Fri, 2010/12/03 - 11:25am in response to: Fadzlan Bin Yahya

That would simply mean the class that you design may have more than one responsibilities (ie. view and business logic).

Views of Widgets in a rich UI toolkit necessarily have far more than 1 responsibility, which is why they get so large.  They will typically handle graphical rendering, tabbing, accessibility, containment of other widgets, being contained by containers, focus handling, keyboard mapping & shortcuts, event management and many other concerns.

And this is before any business logic in the app at all.  This logic typically all sits in event listeners.

Essentially this entire discussion has been about how to manage these complex capabilities in a sensible way, whilst supporting the creation of new widgets and evolution of the underlying toolkit itself.

James Jamesson replied on Sun, 2010/12/05 - 4:50am

As far as I know JSF uses an abstract class for the base component namely UIComponent. Tag is a final class not an interface unless there is another JSF out there that I dont know of. Using an interface as a base for a UI component hierarchy is a ridiculuous idea. There must be a component set and hierarchy (cells, components, containers, etc) based on some abstract skeleton available to the programmer. Composite UI components are developed by the programmer to accomodate a certain UI design type they must have, i.e. forms. Please do not mix the apples(UI frameworks) with oranges(Others). UI frameworks are not designed to accomodate your test environment.

Andrew McVeigh replied on Sun, 2010/12/05 - 6:59am in response to: James Jamesson

Using an interface as a base for a UI component hierarchy is a ridiculuous idea

That's simply not true; a number of frameworks do this to very good effect.  I do it in my commercial product.  Is it more difficult than using abstract classes with different pros and cons?  Yes, clearly.  It also tends to push infrastructure away from the widgets themselves.  This can be a good thing as it minimizes the work needed to implement a new component and makes the responsibilities clear.  The disadvantage of interfaces is that abstract classes support better framework evolution, as default implementations of methods can be added.  However, each approach has its strengths.

 UI frameworks are not designed to accomodate your test environment.

We are talking about testing the widgets and supporting infrastructure, and allowing alternative implementations that don't carry the default implementation baggage.

James Jamesson replied on Sun, 2010/12/05 - 8:52am

O.o my bad, author is talking about JSP not JSF. JSP is not a UI framework, it is designed for creating web content dynamically. I would not compare JSP to Swing if I were you.

@Andrew, you may use it for your own project and use it the way you want it, but that would not make it a usable UI framework. It would be dull for me to elaborate on an interface based design before seeing its architecture and API use. However, I can clearly say this that it would only make probably more sense to use that just internally for your own commercial purposes whatever it would be. For a usable UI framework there must be a skeleton to flesh around, interface as its name implies is not a good fit for that job. You can break the encapsulation and abstraction of the entire UI hierarchy if you use an interface which may be used to introduce a component with no flesh and place in the hierarchy at all. Good luck with that.

Richard Kennard replied on Mon, 2010/12/06 - 6:50am

A huge thank you to all those who participated in this lively discussion! It has been very useful to me. I have tried to summarise the key themes of the discussion over on my blog:

http://kennardconsulting.blogspot.com/2010/12/rant-who-designs-these-ui-frameworks.html

First, I would like to apologise to any who were offended by the somewhat incendiary tone of my article. It was pitched as a 'rant' in order to encourage responses, but in no way am I suggesting the UI frameworks I listed are anything but successful - or that their creators are anything but intelligent, brilliant people.

But anyway, the themes:

  • Some UI frameworks (albeit a minority) *are* interface-based. Examples include ItsNat, Vaadin
  • Other frameworks have considered being interface-based (Swing), but on balance decided to use abstract classes. Neither is optimal: "when I was working on the Swing team at Sun Microsystems back in the early days of Java. Some people 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 base classes limit future use cases. This is dangerous because "anything of strategic importance will be used in ways that the original designer cannot anticipate"
  • The problem with a 'monolithic' interface is that it is cumbersome to evolve: "You will soon have IComponent, IComponent_v2, IComponent_v3"
  • The problem with 'granular' interfaces is that you often have to pass around many of them together: "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"
  • Java does not have a good way to bundle several 'fine-grained' interfaces together, but other languages may (Scala traits): "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."

Thanks again!

Richard.

Jose Maria Arranz replied on Mon, 2010/12/06 - 7:56am in response to: Richard Kennard

"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"

Pass IComponent and when you need Focusable ask for this interface with a simple instanceof, if returns false then throw an Exception with something like "Focusable interface" required, is not perfect but it works.

"Java does not have a good way to bundle several 'fine-grained' interfaces together, but other languages may (Scala traits)"

As far I know Scala traits is a sort of multiple (implementation) inheritance.

 

Milos Solujic replied on Mon, 2010/12/06 - 8:36am in response to: Ronald Miura

Can't agree more Ronald.

 

Neither interfacing nor composition is always good choice or bad one.

It is needed that engineer think how that peace of code she writing will be used and to do it proper way.

Dangerous it is just to follow some advice which is good for only 90% of the time, like those above about interface over class and composition over inheritance.

 

Milos

Liezel Jane Jandayan replied on Mon, 2011/09/19 - 1:19am

A computer's processing unit executes series of instructions that make it read, manipulate and then store data. Conditional instructions change the sequence of instructions as a function of the current state of the machine or its environment.-Any Lab Test Now

Comment viewing options

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