QML anti-patterns

There's a pair of antipatterns I've ran into when dealing with QML (QtQuick & Qbs) that I keep seeing people make a lot; so I might as well make a blog post detailing what they are and why they're bad.

property alias

property alias is a pretty surefire way of getting further from “single source of truth” which translates into spaghetti QML where you have to dive through things chained to each other like plumbing to an amount that negatively affects readability.

Instead of:

Item {
	property alias text: label.text
	Label {
		id: label
	}
}

you should:

Item {
	id: root
	property string text

	Label {
		text: root.text
	}
}

Not only does this centralise all the state for an item and make it easier to locate, it also has the effect of encoding the property's type with the property declaration itself, making it easier for tooling (and humans!) to identify the type of the property. This is particularly important for public-facing APIs, where API documentation tools cannot evaluate the QML to determine the underlying type of the alias.

id overuse

id is extremely easy to abuse. In short, id has a very limited possibility space before it starts to become spaghetti: reading user input status from controls and referring to a view's root.

This mostly has to do with state management in general: “single source of truth” is the key; avoiding fragmenting your program's state throughout random items in a view mostly leads to more readable QML, and provides other benefits as well. For example, a chat application whose chat view has a single source of truth to the current navigational state can easily save/load where it was. If you're passing a full ChatModel* object to your messages view when you push() instead of an ID that allows the messages list view to obtain a ChatModel* itself; that isn't SSOT, as the ChatModel* has to come from somewhere in the state of the chat list view pushing the new messages list view, and it means that other views cannot push a new messages view view unless they replicate the code & state that the chat list view had; which is prone to bugs.

What does id have to do with this? id allows fragmenting your single source of truth by making it convenient to put stateful properties in scattered objects and refer to them from anywhere in a context/scope. Locating what does what when many child contexts are able to mutate a random object in a non-centralised manner is painful, to say the least.

Some QML frameworks provide facilities for making “single source of truth” and reducing id usage easier to perform; e.g. the Kirigami.PageRouter which can facilitate SSOT with the route API allowing centralising data into a singleton that stores navigational state, which applications should use as the only information needed to fetch other things like network resources. In Qbs land, file tags + the Project type serve this purpose; the Project type centralises various Products into a single source of truth for managing them, and file tags are the source of truth for input/output and composing of various Rules.