The preceeding chapters have probably spawned many questions and hopefully a few good ideas. This chapter offers a discussion of some of the higher-level concepts, limitations, and possibilities surrounding this work, and suggests some directions for future research.
There are three main categories of current limitations:
Empowering novices to create the small-scale data-driven applications they envision for their needs is already a worthy goal. But once this becomes possible, the question arises: what are the boundaries of this approach? Could it possibly be used to prototype real-world applications like Facebook or Amazon? What about games like Fortnite or Minecraft? Or graphics editors like Photoshop or Illustrator?
Clearly, for any language that allows imperative programming as an escape hatch, the answer is yes, but that answer is of similar utility as the assertion that we can build these applications with any machine able to manipulate symbols on an infinite tape [1]. A more meaningful question would be whether Mavo could add enough value to substantially simplify the development of such applications. We explore several facets of this question below.
The first Mavo use case was a list of conference talks (Figure 10.1), and the dozens that followed in its first few years were of a similar scale and spirit: small-scale, mostly CRUD applications plus very lightweight computation for editing structured data in a high fidelity WYSIWYG interface, with few editors and any number of consumers (readers). For these use cases, Mavo was envisioned as an easier yet more flexible, more lightweight, and more portable alternative to CMSes, that still provided higher fideity editing interfaces than said CMSes.
Over the years, as its formula language (Formula2) and data I/O (Madata) developed, and with the introduction of data actions, Mavo has become capable of building applications that break out of this mold. It has been used to build games, color pickers, interactive graphics editors, code playgrounds, social feedback apps, chat applications, and more. Many such examples are described in the Case Studies chapter.
However, applications whose main complexity lies in their interactivity model rather than their data model are still largely out of scope. For example, a drawing applications, or a VR game. Applications requiring parts of such interactions can still be built, if these interactions are encapsulated in web components, but Mavo is likely not a good fit for applications where these types of interactions are central.
Because Mavo is implemented as a pure JavaScript library and all computation occurs on the client, serving a Mavo app to any number of users is as easy and scalable as serving static web pages. Scalability issues arise only around access to the data, which may be stored locally or outsourced to third-party storage providers such as Dropbox.
Mavo is therefore perfectly suited to so-called Personal Information Management (PIM) applications. These applications have a single author and reader, and the amount of data they manage is generally small. For the ultimate in scalability, the Mavo app web page can be stored (“installed”) on the user’s own machine and data stored locally in the user’s browser. While this old fashioned approach sacrifices the access-from-anywhere advantages of cloud-based services, it frees the user of any dependence on the network. Even when operating in the cloud, PIM-oriented Mavo applications scale extremely well because each user’s data is isolated. Each user’s Mavo simply loads or stores their own small data file, which is the bread-and-butter operation of the popular storage services. A peer-to-peer synchronization service for web storage would allow users to manage information on all their devices while still avoiding dependence on any cloud services.
Mavo is also well suited to “web publishing” applications where an author manages and publishes a moderate-size hierarchical data model and present it to audiences of any size through views enriched by computation of scalar and aggregate functions over those items. This large space spans personal homepages, blogs, portfolios, conference websites, photo albums, color pickers, calculators, and more. Since only the author edits, these applications scale like the PIM applications for editing, while on the consumption side any number of consumers are all simply loading the (static) Mavo application and data file, which again is highly scalable. Conversely, Mavo can be used to supercharge web forms that collect information from large numbers of individuals—such as surveys and contact forms—to adapt dynamically to inputs and perform validation computations.
Mavo was not originally designed to make social or big data apps that present every user with the results of complex queries combining data from many users. This social/computational space is important, but so is the large space of “small data” applications that Mavo can provide. Even on big-data applications, Mavo may in the future be a useful component for simplified UI design if powerful back-end servers are used to filter down and deliver only the small amount of data any given user needs in their UI at a given time.
Mavo is designed to work well with hiearchical data models, such as those that can be represented as JSON objects. This is a superset of tabular data models, as a table can be expresssed as an array of objects. However, a reasonable question is how could Mavo handle graphical schemas, which per [2] occur in 27% of the applications they studied — though only 22% of these cyclic (6% of the total dataset).
Mavo can already express graphical data models, but it requires a lot of manual effort (an example is described in Section 8.1.4). Authors need to designate a certain property of each object as (conceptually) a primary key, peform manual effort to ensure it is unique (e.g. via suitable formulas doing data validation), write custom Formula2 expressions to look up objects by this key and display them elsewhere, and author dynamic collections to facilitate data entry of foreign keys.
Inspired from the several decades of database system design, Mavo could introduce language primitives that make primary and foreign keys first-class citizens, which would greatly simplify this process.
These could include:
Authors could then either template the referenced data in a custom way, or when this power is not needed, Mavo could provide a default rendering that summarizes the object without requiring authors to write a new template for it (possibly by reusing the same template as in the defining collection, but adding a certain CSS class than can be used as a styling hook).
These kinds of implicit objects can be useful for more than foreign key references. For example, entering a URL in a property could expose an object with metadata about the website (e.g. title, description, image), or entering an address could expose an object containing metadata about the location (e.g. GPS coordinates).
More research is needed about the best mental model and syntax for expressing these concepts in a way novices can understand.
A big current limitation of both Mavo and Madata is the data model granularity.
Fetching data from the server is typically only done once: when the page is loaded.
The data powering a Mavo app is fetched as a whole (often from a JSON file)
and stored as a whole, even if the app only needs to read and edit a subset (via mv-path
).
Access Control is also expected to function at this level: a user can either read or edit the whole dataset, or no part of it.
These limitations are no issue for the use cases that drove Mavo’s design, such as personal information management applications, calculators, and web publishing applications, where the data is small and the editors are few and know each other. However, as authors who liked its novice-friendly syntax tried to push the boundaries of what was possible, these limitations started to become more restrictive.
Due to its distributed architecture, supporting data models with finer granularity is not a simple matter of programming, due to the number of moving parts involved. First, not all backends support finer granularity. The types of file-based backends that power the cloud storage of most Mavo applications (Dropbox, GitHub, Google Drive) typically only support reading and writing a single file.
It is important to tease apart the use cases that benefit from granularity, as solutions may vary depending on the need:
We now discuss some potential directions for future research in these areas.
Even for Mavo’s originally envisioned use cases involving small groups of editors acting in good faith, restricting edits of certain parts of the data to certain users can help prevent accidental data corruption, and hiding irrelevant elements can streamline the UI.
This is a lighter form of granular access control (henceforth referred to as Presentational Access Control (PAC)), as it does not actually require server-side enforcement, since none of the users involved is malicious.
PAC is largely already possible in Mavo, though not necessarily easy:
mv-if
can be used to hide elements based on formulas, and formulas can take include user information into account (e.g. username of current user).mv-mode="read"
can be used to prevent certain subtrees from being editable, and its value can be an expression that depends on user information.One conspicuous absence is the lack of a way to disable certain collection management operations
(e.g. conditionally disabling item deletions, while still allowing additions).
There are ways to hide the controls for these operations (e.g. the mv-item-bar
attribute, or simply CSS),
but this communicates a different user intent than disabling them
(e.g. we may be removing them because we have implemented these functionalities via different controls).
A primitive to disable the actual action would be higher level and thus more expressive and more future-proof.
It is important to note that there are no primary use cases for PAC, i.e. no use cases require it or benefit from it. There are only use cases for which it is an acceptable workaround, and use cases for which it is not. Furthermore, PAC workarounds need to be designed with care to avoid users assuming they are secure and building applications that contain security vulnerabilities.
PAC may suffice for small-scale collaborative use cases, but for the types of multi-user applications mentioned in the beginning of this section, server-side enforcement of access control is necessary.
There is a cornucopia of very common multiuser use cases that require this kind of granularity. Some examples include:
In cases like these, it is not enough to merely hide the UI elements that allow editing — permissions need to be enforced by the backend. This surfaces a tension that our approach creates: by not controlling the backend, but merely the choice of backend, Madata is also bound by the limitations and capabilities of these backends. Very few of the backends that Madata currently supports have the ability to enforce fine-grained access control. For example, there is no way to instruct GitHub to only allow writing certain parts of a JSON file to certain users, or even certain files.
However, back-end services with richer access models exist. For instance, DataHub [3] provides row-level access control, where each table row is “owned” by different users. Similarly, Firebase [4] is a popular commercial hierarchical database, where each node can have its own access control rules (and is already supported by Madata).
Even though Madata can be used with backends like these (and already supports some), it does not yet support reading or reflecting granular permissions in its objects. Similarly, Mavo can be used with such backends, but the author needs to take care of implementing suitable access control on the backend service and then reflecting it in the UI (via the same patterns as those used in PAC).
Even if we only consider backends that support granular access control, there are several pieces that need to fall into place for the Mavo ecosystem to properly support it:
These steps would already be a big improvement, as they would allow users to define elaborate access control rules in their backend service, and everything else would just work. However, typically the systems for defining these permissions require a higher level of expertise than the typical Mavo author possesses, and the syntaxes for defining these rules suffer from the same incompatibilities Madata was designed to normalize.
What if we could go further, and have the Mavo app become the source of truth for these permissions? Mavo could provide a novice-friendly syntax for authors to define granular access control rules in their Mavo templates, and Madata would define a backend-agnostic abstraction to describe them. Mavo would then be able to communicate these permissions to Madata, and the Madata backend would translate them to the appropriate backend-specific rules.
This brings us to the question: if novices could declaratively define access control rules in their Mavo template, and have then be translated to the appropriate backend-specific rules, what would that syntax look like?
There are two potential directions:
mv-can-edit="own"
)mv-can-edit="post.owner = $username"
).The first approach is has a lower threshold and is easier to translate to different backends, but also has a lower ceiling, and thus may not be expressive enough for all use cases. The second approach has a higher ceiling, but also a high threshold and imposes a higher burden on supporting additional backends, putting its generalizability at risk.
A layered approach could involve a hybrid of the two:
a declarative syntax at first, covering the most common use cases,
that can later expand to a formula-based approach for more complex rules,
where the initial keywords (e.g. everyone
, own
) are translated to suitable formula expressions.
Rather than restricting granular access control to the few backends that natively support it,
a different direction would be to allow a Mavo app to be backed by multiple backends,
by extending the mv-storage
attribute to apply to any property.
This would facilitate granular access control by partitioning.
For example, it would make it possible to create a blog where the posts are stored in Dropbox and can only be edited by the author, with upvotes stored in a service that allows public writes. Or, a designer portfolio where project metadata is stored on GitHub in a public repository, but billing details and client notes are stored in a private repository.
Sufficiently granular partitioning, if done well, could solve a very wide range of use cases. For example, the blog comments use case could be solved by storing each user’s comments in their own file space (e.g. a fork of the GitHub repository). This is not without its own set of challenges, which have been studied in the context of distributed systems, and are out of scope for this work.
It could be argued that this kind of partitioning is an eigensolution [5]: it does not only solve (many cases of) granular access control but also several other use cases, such as mashups. For example, a user could create a book reading log, where they store their ratings and notes in a personal Dropbox file, and display book metadata from a third-party API. Or a recipe manager, where the recipes are stored in a personal Google Drive file, and nutritional information is fetched from a third-party API. Mashups are already possible with Mavo, by using a separate Mavo app for each data source, and Formula2 expressions to join the data, but the authoring experience is suboptimal.
A creative solution (which can be combined with other ideas)
is for Madata to support storing data in backends
that are not storage services in the typical sense,
and take advantage of their more powerful access control mechanisms.
For example, one could imagine a Madata backend that stores its data in GitHub Issues, with each comment storing JSON for a collection item. Or as comments on a hidden Facebook post.
This gives Madata developers (and thus, Mavo authors) access to a storage mechanism that supports the commonly needed paradigm where any registered user can append, but the data owner (and admins) can edit or delete, without needing to configure any access control rules or set up complicated services.
Multi-user applications — especially realtime ones — require robust conflict resolution to scale, and larger datasets are slower to load and save. The typical solution to both is granular data reads and writes, where only the data that is needed is fetched or saved rather than the entire dataset. The less data that is transmitted over the wire, the faster data I/O will be, and (auto)saving granular changes frequently and pushing granular updates to the UI can reduce conflicts to a minimum that can be resolved via the UI.
For backends that support these capabilities, this becomes a matter of Madata (a) reading that they exist and interfacing with them, (b) exposing them to the application developer in a backend-agnostic way, and (c) Mavo handling such updates and propagating them to the displayed data.
Mavo already tracks edits in a granular way, so that it can communicate unsaved changes to the user, so it would be trivial to save these changes incrementally if Madata supported it. Similarly, applying partial updates can be relatively simple by recursively updating the data model in places where it has not been edited by the user.
However, this needs partial updates to be communicated by Madata as a hierarchical, ordered list of operations. This is because there is no way to know the identity of an object in a JSON file, as neither Mavo nor Madata enforce any kind of primary key. Approaches like JSON Patch [6] or some types of CRDTs [7] could be used for this purpose.
As with granular access control, this becomes a lot harder when the backend does not support these capabilities. For backends that do not support push updates and incremental writes, Madata could emulate them by polling the backend for changes, diffing changes with the fetched version of the data, then applying that diff to the displayed data. Similarly with saving, Madata could refetch the remote data, apply the user’s changes to it as a patch, and save that result. This would not help with performance since it still involves fetching and saving the entire dataset (in fact, it would make it worse due to the additional diffing/patch steps), but it would help with conflict minimization.
No discussion on the limits of Mavo would be complete without discussing the limits imposed by the platform itself. As a client-side extension, there are certain things Mavo simply cannot do, at least not without interfacing with a server-side component. The vast majority of these limitations are well-intentioned security protections, such as the same-origin policy [8] which prevents client-side code from reading HTTP responses from other origins [9], however it is unfortunate that there is currently no way for end-users to opt-out of these protections for certain trusted applications, which gives proprietary native platforms a competitive advantage.
Websites can opt-out of the same-origin policy for requesting sites by setting Access-Control-Allow-Origin
and other CORS [10] HTTP headers.
However, as with any opt-in mechanism, many neglect to do so.
Additionally, CORS does not disable all cross-origin protections.
For some, there is no opt-out mechanism, such as reading the contents of cross-origin iframes.
For example, it was mentioned in the Portfolio case study, while Mavo could generate thumbnails for uploaded images, it would not be able to do so for linked images. This also restricts the number of APIs that Madata can support, as many do not provide CORS headers.
Spreadsheets blur the line between data and computation, with formulas used ad hoc in cells, and columns being able to contain a mix of data and formulas. This design trades off maintainability for flexibility. Repeating a formula across a column is managed by essentially copying it to each cell, with the UI providing affordances to make this less painful, and there is no way to ensure all copies of the formula stay in sync. However, it also it allows creating one-off exceptions, which can be useful in a world of messy data.
Most data-focused no-code tools take a different approach for tables: columns are either data or formulas. This is decided upfront, and each cell automatically follows the same rule. This design makes the opposite tradeoff, sacrificing flexibility for maintainability.
An interesting pattern in some no-code tools is to allow formulas to be entered alongside rich text
(e.g. entering =
while writing kicks the editor into formula mode),
to interleave one-off computations with prose (Figure 10.2).
This is a very powerful pattern, and is currently not possible in Mavo. It remains an open question how to best support this pattern in Mavo, likely in an opt-in way.
Creating custom filters via dynamic collections and Formula2 expressions has been possible in Mavo almost from the start. An example of this can be seen in the CSS WG Disposition Of Comments application.
Thanks to work by Sanchez D. [11], sorting via an mv-sort
attribute (and corresponding Formula2 sort()
function)
and grouping via the Formula2 by
operator became possible as well.
There is no HTML syntax for grouping, making grouping in place tricky but possible:
(it would require sorting by the grouping expression and inserting content with its value before the first item that has a different value).
While this approach affords a high ceiling, it also imposes a high threshold. Writing the logic for one’s own filters is nontrivial, tedious, and error-prone, even for Mavo, and novices do not necessarily have the training to make good UI decisions in this area.
Higher-level primitives for data exploration such as those provided by Exhibit [12] could greatly simplify this process. Ideally these would automatically generate a suitable UI based on the shape of the data and the schema of the data model, with escape hatches to customize the UI if needed. Entirely custom widgets can still be used for more complex use cases, and even shared with others if abstractions (see Section 10.4) are added to the language.
Orthogonally, better view-update handling by Mavo could make it simpler to build custom data exploration UIs and still have editable data, not readonly copies.
There is a scarcity of abstraction and reuse mechanisms across most no-code or low-code tools. Extension points typically involve use of scripting languages, rather than ways for users to compose and reuse primitives of the language or tool they are already using. Part of this may be lack of demand; we know that novices and end-user programmers prefer cloning over abstractions [13], and it is something we have also observed in our user studies (Chapter 7).
However, to use the example of the most successful end-user programming environment, spreadsheets have evolved a whole continuum of users, from expert programmers to individuals who only use spreadsheets created by others and do not do any formula writing themselves [14]. Abstractions would allow such power users to share their creations with others, enriching not just their own experience, but that of the entire community.
Complex Mavo applications can become difficult to manage due to the limited abstraction and reuse mechanisms. Currently, Mavo can build some pretty complex interactive widgets, but there is no mechanism to reuse them and compose them into larger applications besides cloning, which restricts its ceiling, since there is only so much that can be done in a single HTML file. In terms of its abstraction gradient cognitive dimension [15], Mavo is closer to abstraction-hating than abstraction-tolerant.
In this section, we discuss some potential directions for future abstraction and reuse mechanisms in Mavo.
Last, for no-code abstraction mechanisms to be successful, it is not enough to simply implement such mechanisms. The tool also needs to teach users how they can benefit, e.g. by providing ways to convert existing duplicated structures to use an abstraction, or even automatically identify good candidates for abstraction. This is certainly easier for visual builders like Lifesheets rather than languages like Formula2 or Mavo HTML.
The extension point of plain HTML is custom elements, implemented via JavaScript. Therefore, a natural extension point for Mavo HTML would be to allow users to define their own custom elements, which encapsulate Mavo functionality. Ideally, this process would be able to create regular custom elements that can be used without Mavo.
Authors can already define computed properties whose values are Formula2 expressions. Functions are a natural next step, if viewed as parameterized computed properties.
Existing literature for adding custom functions to spreadsheets [16, 17] has explored ways to smoothly transition from the specific to the abstract, by allowing users to convert a regular cell formula to a parameterized function.
This approach could work well for Mavo too. Mavo already supports groups of properties (objects) some of which can be computed. Only two things are missing to turn such a group into a function: (a) A way to map input arguments to group properties, and (b) A way to select a specific property as the one containing the return value.
This could be opt-in (certain groups are marked as functions), or all groups could also be functions. The latter also opens up interesting interactions with Formula2’s scoping rules: If scope can vary function code, is that a feature or a bug?
Lifesheets (Chapter 9) has shown that Mavo concepts can reach a much wider audience when exposed visually. We believe this is a very small first step towards this goal. A higher fidelity visual interface could go a lot further in visualizing the data model, Formula2’s identifier resolution algorithm, introduce more direct manipulation interactions, and elimiate syntax even further.
Additionally, Lifesheets was very narrowly scoped to personal tracking, but it became clear that many of its ideas could be generalized to a more general no-code visual builder. Its affordances for editable properties, formulas, actions, or charts have no particular dependence to the personal tracking domain. It remains an open question where the boundary lies between a GUI that is too general to be helpful, and one that is too specific to cater to most use cases.
Anyone visiting a webpage could peek under the hood, see its inner workings, copy and repurpose the code, and ultimately learn from the experience. Editing this HTML code did not produce any errors, and rarely if ever produced non-local failures. Many of today’s software engineers got their humble beginnings by tinkering with HTML and CSS in this way. The so called tinkerability [18, 19] of the early Web served as a gentle introduction to programming for many of today’s software engineers.
Today, while View Source
still exists, it is of far more limited utility.
More often than not, the HTML that reaches the browser is the obsfucated result of a complex build process,
or a stub for a JavaScript framework to fill in.
We hope for Mavo to serve as a first step towards restoring some of this tinkerability of the early Web. Mavo applications are completely transparent: their UI, their logic, their storage location, and frequently their data, are all visible in the HTML. Tinkering with them does not require wading through dozens of JavaScript modules or understanding complex architectures, but merely looking at the HTML like it’s 1999.
But beyond learnability and tinkerability, there are other benefits to this approach, which hint at many possible future directions of research.
A big advantage of HTML-based approaches is that they are naturally interoperable, without requiring any plugin or integration to be written: the HTML itself is the integration point.
We saw an example of this in the e-shop case study (Chapter 8), where Mavo could interface with PayPal, a payment provider, without neither Mavo nor PayPal needing to know about each other, simply because they both spoke the same language: HTML.
Another example is Web Components: any web component can be integrated with Mavo simply by using it in the Mavo HTML. An extreme example of that is this Mavo - AFame demo (Figure 10.3), where a 3D scene is created using the A-Frame web component library by Mozilla, and Mavo is used to parameterize it.
Last, as we saw in the SVG Path Builder case study (Section 8.2.1) this interoperability extends to other markup languages that can be embedded in HTML, such as SVG or MathML.
A declarative language that describes the application at a high level rather than the low-level steps to achieve its various interactions, can automate many things that are currently laborious and require expert knowledge.
An important example is accessibility. In the State of HTML 2023 survey [20], web developers cited lack of knoweldge and low organizational priority as some of their core pain points with making their web applications accessible to people with disabilities. The more that is known about the application, the more of accessibility can be automated, rather than depending on the individual author’s knowledge and effort. Mavo already adds several ARIA [21] annotations to the author’s HTML, but there is a lot more that can be done in this area.
Declarative languages are better positioned for longevity. The very first page on the Web, created by Tim Berners-Lee in 1991, is still viewable and usable today. In contrast, most JavaScript-heavy applications from only a few years ago are already broken. One reason is that declarative languages can be standardized and used by a variety of competing but interoperating tools. Another is their fault tolerance; the HTML of this first website is now considered invalid. In fact, approximately half of its source is highlighted as an error or warning by the W3C Validator. And yet; every modern browser can render it flawlessly. This should be contrasted with the behavior of most imperative languages, where a single syntax error can break the entire application.
In recent years, LLMs are increasingly used to automate the authoring of code. This does not make approaches such as Mavo obsolete — quite the contrary. Humans still need to verify the generated code, and to do so, they need to understand it. The more readable and transparent the generated code, the more it facilitates this human verification step. We predict that code readability will become a top priority for future syntaxes, while efficiency of authoring will be less of a concern. We think that declarative languages like Mavo are excellent candidates for this trend. Our Lifesheets study (Section 7.6) has already touched on this, by making Mavo code more readable and editable by novices who would not have been able to author it. A lot more can be explored in this direction.