Declarative vs Programmatic UI

Posted: 2015-09-15. Modified: 2016-01-25. Tags: GUI, Opinion, programming.

There are two common ways of going about defining a graphical user interface.

  1. Declarative UI.
    1. You adapt a markup language like HTML or XML, possibly in combination with a layout language like CSS, to define the identity and basic placement of widgets and controls.
    2. You traverse your declared UI using a real programming language like Javascript in order to add functionality and advanced UI features.
    3. This approach has been adopted by frameworks such as AngularJS, and QT+QML, and is the standard approach for Android UI development.
  2. Programmatic UI.
    1. You create and lay-out the elements of the UI directly in a programming language. While you may still achieve separation of concerns by delegating UI creation and layout to a dedicated "View" object, all actions necessary to construct the UI are programmatically guided instead of declaratively specified.
    2. All older UIs used this approach, and it is commonly used today to construct UIs for a vast variety of desktop frameworks and can also be used to manipulate the web DOM.
    3. Swing, SWT, GTK, QT, is an option for Android.

Is one approach better than the other? What are the upsides and downsides of each approach?

Declarative UIs are probably at a higher level of abstraction. At the cost of a potential learning curve and flexibility, you specify what UI you want and leave it to the computer to figure out what actions to take to achieve that UI. This is in some ways similar to an oft-mentioned divide between functional programming languages and imperative languages – in a functional language, you more often define what you want to be done without going in to the details of how to do it. For a trivial, and common, example, the list manipulation functions "map," "filter," and "reduce" describe what an operation to perform without going into details of how to use accumulator variables, index variables, or loop bounds.

Abstractions are leaky, however. If a declarative UI framework is not closely designed after what you, the programmer, want to do, then you may encounter significant "impedance mismatch" and/or learning curve in making it do what you need. For example, imagine performing an arbitrary action upon a click in Swing vs AngularJS. Swing is very programmatic – you can simply register a click handler and do whatever you want to any other item on your page. In AngularJS, however, while you technically can register a click handler to do this sort of thing, it is not considerd "good practice" and the standard approach is to ensure that the view is bound to an underlying data model using "directives". In order to accomplish an arbitrary action using directives, you may have to think outside the box of simply accomplishing the action by also considering AngularJS's databinding semantics as part of your problem. There is a significant learning-curve for learning AngularJS two-way binding properly, and it is not appropriate for all web applications.

AngularJS claims on its website that it is optimized for CRUD (Create, Read, Update, Delete) websites, and even has a disclaimer that it may not work well for sites with heavily-custom DOM manipulation needs. For example, I suspect Google Docs would be very difficult to implement in idiomatic AngularJS.

In conclusion, there is no abstraction that meets all needs. While AngularJS may be great for CRUD apps (once you take significant time to understand it), it is not good for DOM-manipulation-heavy apps which do not lend themselves well to simple databinding. Data-binding declarative user interface frameworks tend to have advantages for applications which are close to the intended purpose of the framework, but if you need full customization and/or performance, you may need to specifiy not only "what" the computer needs to do but also "how" the computer should do it by using a traditional procedural user interface API.