Rant: Who Designs These UI Frameworks Anyway?
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? |
|---|---|---|
| Swing | JComponent | NO |
| AWT | Component | NO |
| SWT | Widget | NO |
| JSF | UIComponent | NO |
| Wicket | Component | NO |
| Android | View | NO |
| JavaFX | Node | NO |
| Flex | UIComponent | NO |
| GWT | UIObject | NO |
| Spring MVC | AbstractFormTag | NO |
| ASP.NET | Control | NO |
| Pivot | Component | NO |
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 :)
(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)





Comments
Christian Schli... replied on Thu, 2010/12/02 - 8:43am
Andrew McVeigh replied on Thu, 2010/12/02 - 9:19am
in response to:
Christian Schlichtherle
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 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
;-)
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
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
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
Andrew McVeigh replied on Sun, 2010/12/05 - 6:59am
in response to:
James Jamesson
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.
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
@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:
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