Posted on 11th September 2024
Writing sustainable code for apps - part 1: The 'View'
'Maybe the real UI framework was the HTML we made along the way'
In this series I'm going to discuss ways in which we can write applications to give them a greater chance of being long lasting, more easily maintained, and generally more sustainable.
Let's start by considering a typical web application (a website with dynamic functionality). In most cases a web app will contain a lot of components that are reused throughout the application.
For example, if we are building an app for collecting data from surveys we might create custom components for our surveys and form fields:
<Survey>
<Heading>Acme Pet Company</Heading>
<Description>A short questionnaire on your experience today</Description>
<CheckList Label="What type of pets do you have?" Type="TickAllThatApply">
<ListChoice Label="Dog(s)" />
<ListChoice Label="Cat(s)" />
<ListChoice Label="Reptile(s)" />
</CheckList>
<LargeTextField Label="How could we improve our service today?" />
<SubmitSurveyButton />
</Survey>
A component template code example and a visual representation of how this template might look
Here I'm using a generic XML format as content / view 'pseudocode', if you like. A basic templating language such as this is all you really need to define the visual structure of the views* in an app, which forms the skeleton of an application. In this post I discuss the benefits of separating and standardising the view language.
* I'm using the terms view and 'visual structure' here to refer to a commonly understood aspect of app user interfaces, however it would be more correct and accessibility friendly to think of these as the semantic structure of the UI. Despite a lot of overlap, these are not completely interchangeable concepts. There is a whole separate discussion to be had about this and for the sake of the argument I'm making here, I'll avoid getting into that now.
Why we need templates and custom components
Custom components allow you to modify a single template and have the changes reflected everywhere it is used, saving time and duplication. If we needed to update the logic / behaviour of one of our survey app's custom form fields (in order to make changes and improvements), we simply update one template and it changes everywhere it is used. Most UI frameworks are designed to make updating components like this easy.
To enable the content to be dynamic we also need our component templates to allow for data to be injected into specific areas. In the most basic example this might look something like:
Welcome to the survey app { UserName }
We may also allow the ability to access properties on objects e.g. { User.Name }
and perform basic evaluation: I got { 98 + 1 } problems
. Additionally we might want to control the flow and iterate over multiple objects. However I would argue this is a slippery slope towards coupling programming to the view and that there is plenty of value in simply allowing basic data binding on its own.
Why the separation of a component's view matters
There may come a time where you want to update or change large sections of the application, a library used by it or the entire framework. You may also want to reuse parts of the application in other applications. Carrying this out will inevitably be time consuming. But if your templates are written in something like plain XML or HTML and stored in separate files you may not have to change them at all. With this separation you will only need to edit these files to change the contents of views in the user interface.
In the world of component based UI frameworks this is not often the case: the content, layout, styling and behaviour are often defined together and somewhat heavily coupled. The design principle is that components should be encapsulated so they can be reused. This is true of web frameworks like React and mobile app frameworks like Flutter.
There are many advantages of a component based approach to non-trivial user interface development. However, changing parts of an application developed using a framework based on this approach can be painful if the view code is not well separated from everything else. Furthermore if you have to replace the whole UI framework that has been used in an application, you might have to rewrite the vast majority of the code including the views.
How can the view be separated
The easiest way to avoid this pain is not to use a framework in the first place. If our surveys were written in plain HTML using the form elements HTML provide, and we want to make changes to our code that controls data access, logic and behaviour, we can leave the view itself untouched. In this case we might not even have a UI framework to worry about updating or changing.
However obviously some apps need more advanced UI components than HTML can offer. It was after all never intended to define application user interfaces. Regardless, the better the separation between the template for the UI's content / structure and the data, behaviour and styling, the easier it is to make changes. One simple way to achieve this is to use HTML based templates in separate files with custom elements where required.
In the example of our survey app, there is a case to be made that the survey content should be stored in a database. This could then create the basis of a 'form builder' system. Certain users could even be offered a UI to create their own surveys. The survey's content could be made available to render in the front-end via an API, using something like JSON. However, there is a cost-benefit analysis to be done here: It could be worthwhile, but only if it is a regular requirement for a user (who is not able to edit the HTML directly) to change the survey content. In the long term it is also likely to make replacing parts of the system harder.
How this affects the longevity and maintainability of an application
I implore software developers and architects to consider that planning for significant change to the tech stack on which your project runs is more than just an academic exercise. The tech world moves so fast that it's an inevitability for any successful software. Whether or not you are in the same job in a few years time, there is a high probability someone will be required to replace a fundamental technology or platform used by a project in this timeframe, particularly in the front-end.
The point at which your project's dependencies are phased out often comes sooner than you think.
Similarly user requirements change rapidly. If we needed to change the wording in our surveys, duplicate them or even lift them from one project into another, this is much easier with separate templates. It opens up template editing to a much wider audience too.
These changes will always be impossible to fully predict and prepare for, but how we separate parts of a solution go a long way to determining how well we can respond to them.
The bare bones of an app would be interchangeable if more UI frameworks used plain HTML templates in separate files, with simple established conventions for things like; custom elements, data binding and referencing other components.
Simple templates in separate files
When it comes to app development, why not just use separate HTML templates with basic a data binding syntax and a simple structure of HTML files referencing one another?
e.g.:
surveys/
pets/
pet-survey.html
...
forms/
check-list.html
list-choice.html
large-text-field.html
submit-survey-button.html
...
How the file names and element identifiers / tags are linked is not completely resolved in this example. I'm heavily leaning towards an implicit convention-based approach - e.g. somehow the file names denote the element names. If you use a more explicit approach to map the files to the components, you end up with a dependency between the view and something else, which is exactly what I think we should be trying to avoid.
Whether your application runs locally or remotely, and whether you are delivering the views from the server or client side, wouldn't it be nice if the code defining the view was all in the same format?
It seems to me HTML is an incredibly useful templating language given its universal ability to be read by people easily and interpreted by most devices natively. I find it hard to believe it is not the defacto templating format for all applications. It is even suitable as a templating language for mediums other than screens, for example printable documents like PDFs.
This seems to be over complicated every time a new framework is created, and I can't understand why ("because interactive features and scaleability" seems like an argument lacking in substance to me). Surely the fewer sections of our applications we have to completely re-write for different devices and frameworks, the better?
A standardised templating language, like HTML, for apps on all platforms
I'm not arguing we should run all software (including mobile apps) in the browser. Native apps usually work better and offer more functionality on a mobile device than web apps. But in terms of the code defining the structure of a UI, it seems strange that in 2024 we're not all using the same templating format, whether it is HTML or something else.
That's why, despite being a programmer, and Flutter's so-called declarative UI definition appealing to me, I am also uneasy about how it relies on a custom programmatic syntax written alongside component behaviour. Given that is unique to this specific cross platform framework, rewriting Flutter applications in anything else will be a nightmare.
I've already had to rewrite a mobile app twice in its lifetime because cross-platform frameworks, which were once very well supported, have been rendered obsolete. I'm not convinced the design choices promoted in each new framework have made it worth the churn.
I believe to build more sustainable apps we must find a way of making every aspect of coding more universal. This is a tall order, but structure and content in particular seems something we have solved and that doesn't require constant reinvention. Ultimately, a plain XML / HTML format seems more than suitable for the majority of applications to me.
The fact that we don't value 'content' highly enough is a pervasive problem today on so many levels. As far as applications are concerned, separating the content from application behaviour goes some way to addressing this and elevating the importance of it.
Why would you not want to preserve the semantic reasoning, the information architecture, the structure and the diction stored the user interface and make it as reusable and accessible to all?
Though it might sound like it, I'm not specifically advocating something like 'MVC'. This is not about arguing over the principles of front-end architecture. What it is about is ensuring the basic structure and content of a user interface can be understood and reused as widely as possible.
Essentially, this has been an awful lot of long words for me proposing that we should put things in separate files, in a file format which is as universal as possible!
A summary of the current options that helps achieve this form of more sustainable 'view' code
I thought I'd end this post with the results of a short investigation I've done into current frameworks, initiatives and libraries that might help developers achieve the goal of view simplification and separation more easily:
There are many templating libraries available. Some noteable ones with varying degrees of complexity are Mustache, Handlebars, Pug and Nunjucks. One of these could be incorporated into a solution along the lines of what I have described. Also some popular frameworks do allow for a separation of the view file, including Angular and React, but this seems not to be common practice and requires explicitly referencing the separate files. In these frameworks logic can also be heavily implanted in, or bound to, the view templates. This weakens the separation I would hope to achieve.
There is one framework I've found that provides a close match to my desired approach: Marko. It ticks the boxes in that you can separate the component's view and logic and it uses a implicit convention for discovering custom components / elements. It is not as popular as React, but it is still worth considering alongside it for web apps. It also supports both client and server side rendering and is more lightweight than React making it quite compelling in my opinion. However, I'm not saying you should necessarily use it for your next project or that I will, as I don't really know enough about it.
Also I've come round to the view point that for a lot of things on the web, which largely rely on simple views with basic data binding, PHP (or something similar) isn't such a bad option. We rarely need to build things as complex as we think we do.
I haven't investigated many options for other platforms, such as mobile devices. As a cross-platform app developer in my day job I do have knowledge and experience of some of the frameworks on offer and understanding of how the landscape is evolving. So far I've not come across a solution that fits mobile apps as well as Marko seems to for the web. Ionic and NativeScript seem interesting, as does the temptation to avoid cross-platform frameworks altogether and develop native apps directly. But the decision of what to develop mobile apps with and indeed whether to develop an application for web, mobile or desktop platforms relies on a lot of factors.
In summary
There are countless options out there for front-end development which are all subject to change and inevitably as a developer you will have to choose some form of UI framework for the apps you develop. Or you may be stuck with an existing choice for one of your projects for a while. Alternatively you may be using no framework at all. Regardless of technology you are using, there will always be a way to structure your code that makes the views more portable. It's up to developers to make good choices here to improve the sustainability of their applications. But there is only so much they can control.
The designers and developers of app frameworks themselves must consider how their choices affect app longevity too. If they have the required humility, their choices could include consideration for apps that will last longer than, or transition away from, their own framework. Maybe then in future adopting a standard view language, whether that is HTML, Mustache or something else will become the norm.
My conviction is that we need simple view templates separated from other code in their own files, with a convention for the file structure that allows custom components to be referenced implicitly. That is one way I think we can write more sustainable code for apps.
Join me again at some point for the next thrilling installment (or diatribe!) in this series where I will cover another aspect of writing sustainable code.