We frequently get asked about our opinion, and direction Uno Platform will take, about declarative code vs markup. In good product (and OSS project) management the question we need to ask ourselves is not *could* we build something, but also *should* we build something.
One of our core team members and architects on Uno Team – David Oliver – discusses the kinds of concerns we take into consideration when deciding on our future approach. While we haven’t made any decisions, the blog post will give you a general idea of items involved when making the decision to add declarative code approach in addition to markup approach Uno currently uses. This blog originally appeared at David’s personal blog.
There’s a good-spirited but earnest debate currently about the ‘right way’ to write a UI-driven application. In many domains where specialized markup languages for authoring visual layouts have long been the dominant paradigm, newer frameworks are appearing which eschew markup completely, opting to declare UI purely in code.
About the Uno Platform
For those new to Uno Platform – it allows for creation of pixel-perfect, single-source C# and XAML apps which run natively on Windows, iOS, Android, macOS, Linux and Web via WebAssembly. Uno Platform is free and Open Source (Apache 2.0) and available on GitHub.
Both the ‘markup’ approach and the ‘code’ approach have vocal proponents. Personally I don’t have a horse in the race – yet – but I do have thoughts on the benefits and limitations of each approach, and I wanted to get them down, mainly for my own benefit.
Let’s give some concrete examples first, in case it’s not clear what I’m talking about.
Examples of markup-based UI: HTML/CSS, Xaml (UWP+Uno Platform/WPF/Xamarin.Forms), Android’s xml layout format
Examples of code-based UI: Flutter, React, SwiftUI, Comet (.NET)
Now we can talk about the relative merits of each approach.
Benefits of markup
Markup is structured
Retained-mode GUIs are typically implemented as a recursively-defined tree of objects, and UI markup formats are well-suited to defining a hierarchy of objects.
Consider the following UI layout, first in Xaml and then in C#:
With such a simple layout, they’re not so different. Nonetheless I believe if I were to see them cold, in the middle of a file, it’d be almost immediately obvious for me what the first is describing, whereas it’d take me a few seconds to pin down the meaning of the second. The first has to be a hierarchical object declaration. The second could be anything – that’s the beauty of code! – but by that token it takes a moment longer to narrow down the vast possibility space of what it could be saying to what it is saying.
Markup is a domain-specific language
This point is really a generalization of the first: markup is a domain-specific language for UI declaration, with all the advantages (and drawbacks) that entails. The parser can do a lot of clever stuff that might not be appropriate in a general-purpose language, like context-sensitive implicit conversions, specialized syntax, implicitly understanding nested content, etc.
Inherent separation of concerns
Markup pushes you to keep your UI separate from other layers of your app because it can only do UI. I don’t find this point particularly compelling: we’re reliant on discipline and good dev culture to maintain separation of concerns in all the other layers of the app, so I don’t think artificially forcing that separation solely for UI makes much difference. But I guess it’s a minor point in markup’s favour.
Markup is tooling-friendly?
I include this one because it seems to’ve been an important argument historically for why markup is superior. The argument is that markup, with its inherent structure and reduced expressivity, would be more amenable to tooling support where you drag and drop UI elements into a WYSIWYG editor. The dream seems to’ve been that designers would author the bulk of an app in such a tool, a developer would come along and tweak the resulting markup output, and app development times would be slashed.
I don’t think that’s necessarily technically inaccurate – such tools do exist, like Blend and Xaml Designer. It just doesn’t seem to be particularly relevant. The dream never really panned out. WYSIWYG tools are great for static documents, but in an interactive application there are key aspects that in practice must be manually handled by an experienced front-end dev, like responsive layouts and virtualized lists to name a couple off the top of my head. And a tool and a human ‘collaborating’ on the same raw markup is not a pleasant experience for either, making it difficult to do further tool-aided edits after the markup has been hand-tweaked.
The trend in practice seems to be for designers to use designer-focused tools like Figma and Zeplin, and then to focus on improving the capabilities of such tools to export feedstock for front-end devs, like first-draft markup layouts, colour and text style resources, etc.
Meanwhile on the dev side, the increasing power of ‘hot reload’ capabilities in most modern UI frameworks is making build-time design tools increasingly redundant.
Just as the constrained structure of markup is beneficial for editing tools, it also potentially lends itself to pre-parsed intermediate formats which may offer particular performance benefits. UWP’s Xaml, for instance, supports the Xaml Binary Format (.xbf) which loads faster at runtime.
It’s probably more than that: I suspect the curtailed expressiveness of markup helps to steer UI authors away from performance-killing anti-patterns. It’s easy to shoot yourself in the foot, when it comes to UI and performance, and markup by no means makes it impossible; but the exposed API surface tries to guide authors towards the happy path. Virtualized ListViews in Xaml languages are a good example.
Benefits of code
Let’s turn to the advantages of declaring UI in code.
Code is Turing-complete
I don’t mean, like, you literally couldn’t implement a Turing machine in markup somehow. (Maybe you could, feel free to tell me how.) But what I mean is that code is capable of expressing arbitrary logical constructs, that’s basically code’s whole job, whereas markup struggles to do so.
Proponents of code show examples of UI snippets that are neatly expressed as code, but verbose and unwieldy in markup, often involving conditionally setting a property, or transforming a value. Proponents of markup usually concede that there are some things markup just can’t (or shouldn’t do); no one I’ve seen is really maintaining the position that a rich interactive application can be built only in markup. The pro-markup position is that the mechanisms for calling into code from markup, or vice versa, are adequate. The anti-markup position is that they aren’t worth the bother.
I would note that the interconnectivity between code and markup varies widely from one markup language to another. Xaml leans heavily into said interconnectivity, with the whole notion of ‘code-behind’ as well as mechanisms like value converters, template selectors, behaviours, etc.
I’m not sure where I stand on this one. Some of the ‘verbosity’ of markup seems more apparent than actual, but whenever I use, say, a value converter, it does feel like a lot of boilerplate. (You know that ‘boilerplate feel’… ugh.) There are innovations that try to address this, like UWP Xaml’s function binding feature, but they don’t yet go far enough.
Code is reusable
Code reuse is one of the major themes in the development of modern high-level programming languages, and one of the obsessions of the craft of software development. Code is reusable at the level of a one-line method, a million-line assembly, or absolutely anywhere in between.
Reuse is a problem for markup. Some languages, like HTML, have practically no ‘reuse story’ for functionality. I think this is why code-only UI frameworks gained ground earlier in web development with respect to other settings.
Xaml has a much better reuse story, with affordances like UserControls and control templates. But the boundaries of reuse are relatively fixed and inflexible; and passing information into or out of a ‘block’ of reuse can be tedious, at times arcane. It’s a painful choice at times whether to refactor a Xaml app for greater reuse, or accept the markup duplication in exchange for a more sane architecture. Code wins this round.
Better IDE support
IDE features, be it an open-source or closed-source IDE, are driven by customer demand, and customer demand is proportional to the volume of customers.
As we noted, you can have code with no markup, but you can’t have markup with no code. It follows, then, that code will always have better IDE support than markup, because the set of all users of a given markup language will always be a subset of the users of the associated coding language.
The IDE support for markup is not necessarily bad – Visual Studio for Windows actually has pretty nice support for Xaml. But Visual Studio’s C# support is amazing. And if we look at other popular IDEs, Visual Studio Code to take one example has good C# support but minimal understanding of Xaml. This will hopefully improve in the future, but it seems likely that IDE support for specialized markup is always going to lag behind support for the associated coding language.
You don’t have to learn a new language
Given a programming task, many developers, not unreasonably, prefer to complete it using a language they already know and are familiar with, rather than one they never touched before. Many, moreover, are not full-time front-end developers, but still want to be able to throw together a GUI-driven application when the need arises.
Some developers judge specialized markup languages to be an unnecessary cognitive burden, and would rather write UI in the general-purpose coding languages they already know.
I am well-steeped in Xaml after years working on the Uno Platform, but I know how this feels. Specialized syntaxes serve to demarcate and perimeterize areas of expertise. I know when I see a YAML file, it’s as if I’m seeing a battered wooden board with a skull-and-crossbones and “THIS IS DEVOPS TERRITORY” scrawled on it.
This is a valid shortcoming, then. The negative of being an ‘extra’ syntax to learn is something that markup has to outweigh with other positives, if it’s to be worthwhile.
Good tooling can go some way to alleviate the cognitive burden of a new language, by catching errors and guiding you toward the happy path. This couples into the area of IDE support already mentioned. The issue specifically of error-checking is trickier for Xaml than for a static-typed language like C#, since on Windows the bulk of the Xaml parsing takes place at runtime. It’s further compounded in UWP and WinUI by the .NET/WinRT boundary, which can lead to frustratingly opaque errors.
I wanted to point a couple of other UI approaches that don’t match the ‘markup’ definition here but aren’t code either, but perhaps another time.
Before I started writing this post, I didn’t have a strong opinion on whether markup or code was the ‘right answer.’ Having written it, I’m more convinced that there is no right answer. Each approach has inherent strengths and weaknesses. A specialized UI markup syntax is essentially a domain-specific language, which can be a powerful tool, but brings an additional knowledge burden and has to avoid the risk of being a second-class citizen in the tooling ecosystem.
I wrote this post mainly with an ‘app developer hat’ on. To wear a ‘framework designer hat’ for a second: it’s obvious that many individual developers have a strong ‘gut level’ preference for one model or the other. Is it possible for a single framework to please them both? But that’s perhaps a fitting subject for a separate post.
David Oliver, Architect, Uno Platform