Saturday, June 20, 2015

A web developer's unrest

Being a long time Dojo Toolkit zealot, I was eager to see what would become of its upcoming 2.0 release. I can't say I'm disappointed, not at this point at least, but I do experience some unrest. This is not only because of the general direction Dojo is headed (TypeScript), but also because of the obvious difficulty the team has in deciding on a UI component solution. To my knowledge it is generally agreed that the current widget facility in Dojo (Dijit) is no longer deemed viable.

I expect that the core Dojo contributors have already made some sort of overview of their options, but I have not. For my own insight I'll attempt to sketch out the current developments in UI techniques, clearly with the ultimate goal to be able to decide upon a long-term strategy myself. Since this will all become very TL;DR I will divide the post into topics. I also promise to make a chart at the end of the series, to show all considerations at a glance. Today I'll start with code reuse, comparing Dijit with some newer techniques now available.

Part 1: code reuse


Dijit is an object-oriented widget library that builds on the core technique of Dojo's class-based approach to code reuse through modularity: the "declare" mechanism. The "declare" function takes as its main parameter a list of classes that are mixed together to form a new class. Inheritance is ordered from left-to-right: each class can call this.inherited(arguments) in any method in order to execute its counterpart in the preceding class. This way a chain of inheritance is formed that is able to reach all the way back up to the first class in the list. This manner of ordering stems from a solution to the problem that arises with multiple inheritance. It is called C3 linearization, and is found in some serious object-oriented languages. Not for the faint of heart, and definitely not something you would expect to find in a web tool.

As far-fetched as C3 linearization may sound, it is not the reason Dijit is on the way out, on the contrary. The initial replacement of Dijit was to be Delite, a project backed by IBM. It takes the same approach to code reuse, but differs from Dijit on other points, as I will discuss later in this series.

A solution for mixing classes together was also discussed for the next version of Javascript, ECMAScript 6. The proposal has been revised many times on this point, and still remains a topic of debate, but as it now stands the inheritance model will follow that of firmly established object-oriented dinosaurs, such as Java and C#. Although ECMAScript 6 doesn't embrace the Dojo solution, Dojo's approach to object-oriented Javascript did play a role behind the scenes. In addition, the solutions Dojo proposed for reusable components didn't stop with multiple inheritance, and the exploration for new patterns continues to this day. I won't go into detail about those here, because that was not the intended topic. However, it is likely that they will persist in Dojo 2.0.

So how do other tools solve the problem of re-usable code? Some more recent players of major import are Polymer and React.js. To start with Polymer, it's a project aimed at enriching markup, and does so by encapsulating it, together with Javascript and CSS, into a single component. Because the focus is on markup, one would expect the possibility for extension to be limited. However, there is some room for code reuse through mixins, which, instead of mixing together classes, does so with instances. This means there's no chain of inheritance, but it's arguable if that was necessary in the first place. Polymer proposes to simply reuse what behavior is in another piece of code, as if it were a container of functionality, and that's a valid way to make use of Javascript's inherent features.

Although Polymer (or rather, web components) doesn't support Dojo's multiple inheritance model, it's very much related to Dijit, and one could argue that it has it's origins in it. The goal of Dijit was also to create a landscape of encapsulated, albeit interdependent, widgets. Although Dijit requires almost half of the stuff in the Dojo tool chain, it does rather well at separating concerns. And although Polymer is presented as the future of the web (because, hey, it's web components) it also needs to download quite a bit of code to get started.

React.js is a radical departure from Dijit, but also from Polymer. It is more concerned with updating the user interface efficiently than with component encapsulation. Perhaps it would be possible to make use of React's fast UI rendering without using its component engine, but it would be quite an undertaking. React's engine is build around an in-memory representation of the document tree: instead of updating the actual document tree that the browser renders, all manipulation is done on the "virtual DOM".

Every time a change occurs due to some outside event, the virtual DOM is reloaded. A batch of changes are compared to the previous snapshot, and the differences are then rendered to the UI. This diffing is what makes React so efficient, but there is some critique on the component side of React. Because the components need to interact with the virtual DOM, all native parts of the component need to be "virtualized", including its markup and styling. Although these are mere technical limitations that at some point will be overcome, the question remains if it is a good idea to work with an in-memory copy of the document tree, and to basically overwrite the default behavior of the browser software, at all times.

As to the re-usability problem, React has chosen to completely abandon the idea of multiple inheritance and mixins, in favor of "higher-order components".  put development of multiple inheritance and mixins on hold, since it's not a part of upcoming ECMAScript standards. When googling for React and mixins, I came across an interesting alternative to mixins, proposed by React developer Sebastian Markbåge: higher-order components. All this means is that a container of reusable code is bound to a component. This can be achieved by simply wrapping the component in a function, and calling the function with the container as its argument. The container will remain in the scope of the function, and so accessible to the component. One could argue that this is very much like mixins, with the important difference that the technique is available in plain vanilla Javascript, and doesn't require any boilerplate code for mixins, let alone C3 linearization. If the concept will hold for more complex cases remains to be seen.

This concludes the first part of my attempt to find my bearings in UI development in the year 2015.

Update 06/22/2015: the assumption that React would move away entirely from mixins seems to be incorrect. The resource I used was authored by a React contributor, and not (yet) part of official documentation. Source: https://medium.com/@dan_abramov/mixins-are-dead-long-live-higher-order-components-94a0d2f9e750

No comments:

Post a Comment