Cabin

Creating simple apps for Linux

by Stuart Langridge and Alan Pope

We need to ensure a thriving app ecosystem to bring Linux to the masses. Our dream of an open desktop, accessible to all can only be achieved by enabling everyone to develop for Linux.

The GNOME desktop needs applications. Other platforms have more of them; for almost anything a person may want to do, there is, as the saying goes, an app for that. More importantly, there is more than one app for that, and our person has a choice; they can try one and another until they find the thing they need. To make apps you need developers. And to make developers you need a way to connect the desire to make a thing with the ability to make it. That’s what Cabin is for, and where it gets its name: a simple building, for doing simple building of apps. To turn an idea into reality.

So what is it?

Some words on the philosophy behind Cabin are important to set the scene; technical implementation details are less important than the mindset, the intention that it is built to serve. Cabin’s goal is to help a beginner programmer build simple apps for GNOME and get them to users. All the parts of that description are chosen for a reason.

Simple apps

Cabin is for making simple apps; it is not GNOME Builder, nor is it trying to be. It’s been suggested that the best programming language would be “accurate, consistent, broad in scope, simple and fruitful” (Graham Nelson), and there are languages that already meet those criteria (choose your own favourite, if you like). Cabin intentionally sacrifices some of its breadth of scope and some of its fruitfulness exactly so that it can double-up on being simple; if you want something comprehensive then you need a Builder. If what you want is something simple, then a Cabin will be fine.

Cabin is explicitly not for apps about controlling or understanding the computer itself rather than things in the world that real people care about (people, places, the weather, photographs, bills, and the like). There are no provided features, nor should there be extensions, for creating an app to manipulate the Wi-Fi stack.

A beginner programmer

Programming is a skill. Over the years there have been countless attempts to abstract programming away, all of which overlook or wilfully ignore that it is a skill. Cabin is not a tool which encourages you to snap together jigsaw pieces to build a program, nor something which conceals that all apps are code underneath.

Building apps involves writing code; anything trying to hide this or leave it out will join a pile of other shipwrecks who foundered on this very principle, and Cabin is explicitly not attempting to allow building apps without writing code. Instead, it guides the beginner programmer into learning what lies beneath their app, without requiring them to understand that before starting.

Cabin apps are written in something like a very rigorous and simplified English, and are partially built by choosing existing widgets and features from a collection of pre-provided items, but they are compiled into Python and Gtk. This is not hidden: it is an explicit goal of Cabin that the new Cabin programmer will learn to dig under the covers, to see how their simple app is actually made using Gtk and Python, and to graduate away from Cabin into full-blown app development once they hit Cabin’s limitations. It’s a stepping stone to GNOME Builder and Gtk.

Get them to users

Publishing is just as important as writing. There are ways to distribute GNOME apps already, but these are implementation details; the writer of a Cabin app needs to be able to publish and advertise it as easily as they can conceive of and write it.

An app development environment’s responsibilities do not end when the code’s in Github; they’ve hardly even started, then. Creating the AppStream data for an app, making an icon and a banner and a description and a strapline for display in software stores, handling versioning, pushing the app to repositories, and allowing users to feed back about this app they’re engaged with are critical parts of modern software development, and Cabin handles that as part of the development process with just as much importance as it does writing the code to begin with.

An app creator is also a community creator, and building and maintaining that community is just as important as building and maintaining the app that the community is centred on; our tools should help with both.

How does it do it?

The Cabin interface is in three parts: the code, the app, and the Library.

The code and the app are interchangeable; one a textual description, one a running window. During development, the app is embedded in the Cabin window, and operates exactly as though it were a separate window; making changes to the app changes the code accordingly, and making changes to the code changes the app.

There is no separate compile step, no separate requirement to manually push a “Run” button; changes are instantaneous and immediately effective. This is to help establish the direct link between code and running artifact in the mind of the new programmer; that a change here effects a change there. It allows for experimentation, and encourages that programmer to feel that they can play, that they can make a small change and immediately see what that means.

Bret Victor talks about this immediacy of effect as how “creators need an immediate connection to what they're making” to properly understand it, to feel comfortable with it. This also helps the programmer to learn the environment; its limitations, what happens and where and when.

How the code itself works will be described shortly.

The Library is where all the widgets live. Widgets, self-contained visual items, are provided by Cabin itself or by extensions. Each has lines of code associated with it which are how to create it and use it, and most have some sort of visual display: a line of text, or an image, or an Entry, or a Range, or anything else. Each also has documentation associated with it; Cabin is designed to encourage programmers and extension writers to describe what they’re doing in detail, to help others to understand the code that’s written or the extension they provide, and so each widget and extension is required to come with examples of how to use it and documentation on what to write.

Widgets can be dragged from the Library into the app, and this updates the code to include a creation statement for the widget: My weight is a typeable number, or similar.

Widgets in the app can be dragged around to change the layout. Cabin uses a simple(-ish) layout algorithm: widgets are stacked from top to bottom vertically in source-code order, unless code alters this. The layout algorithm can be altered with statements describing that one thing is to the left of another, or right, or above, or below, like My weight is to the right of my height or The clock is above the location. The layout algorithm then solves for the simplest layout that meets these criteria.

The things defined in the Library are as much as possible, real objects that actual people care about: photos and appointments and friends. Not integers and doubles and pointers. Text is something of a crossover here; strings are not something that people care about, but words are.

The code

Cabin’s programming language is akin to a very restricted form of English. It is strongly influenced by Inform 7, a game programming language, and by principles of literate programming where code should as much as possible also be documentation, and by the idea that it not contain seemingly arbitrary sequences of punctuation which inexplicably cause a program to fail to the bafflement of the new programmer.

An example will serve to illustrate the principles. Full details of exactly how the code will work aren’t complete yet, and the challenge is as always in the full detail, but a programmer reading this should be able to generalise in a basic way.

"Calculator" by Stuart Langridge.
"This is a tiny calculator."

First number is a typeable number with default 0 and label "Equation:".
Second number is a typeable number with default 0.
Operator is a choice between "+", "-", "×", and "÷".
The operator is to the right of the first number.
Second number is to the right of the operator.

The result is a label with prefix "Result:".
If the operator is "+" then the result is first number + second number
otherwise if the operator is "-" then the result is first number - second number
otherwise if the operator is "×" then the result is first number * second number
otherwise if the operator is "÷" then the result is first number / second number.

The language is intentionally verbose; abbreviating an expression, or reducing the amount of typing required, is never a consideration.

The first parts of the code, called the preamble, define the program name, author, and description. These are mandatory. As above, a guiding principle of Cabin is that publishing is as important as coding, and an app to be published needs metadata; a name, an author, a short description, enough to populate AppStream data. If an app is missing these, it is just as incomplete as if it were missing a vital feature, and so they are required.

A programmer would probably recognise “first number” and “second number” as variable names; note that they are words, with spaces in. There’s nothing stopping a user using underscores_to_divide_words or studlyCapsNames but Cabin, being a simpler language, does not need the disambiguative qualities of single-word variable names.

Cabin takes a maximalist approach to error messages: each should describe the problem, what it thinks causes the problem, and possible ways to resolve it. It is not possible to entirely encompass all possible failures this way -- authors are extremely creative at coming up with programs that the compiler does not understand -- but any error message where the programmer does not understand how to fix the problem is by definition a bug in Cabin and will need to be fixed.

Statements in the code end with a period (full stop, “.”) character. They do not have to begin with a capital letter, but it looks tidier. Cabin code aims to be readable, not just in the sense that a programmer can decipher its meaning, but that it can be read out -- a Cabin program should pass the “telephone test” where you can unambiguously read out the code over the telephone to someone who is typing it in, without needing to resort to military phonetic alphabets or getting confused about what was said.

To maintain the direct link between code and app, the names of widgets are lightly highlighted with an underline; mousing over a widget name will highlight that name in the code panel and the widget itself in the app.

Extensions to Cabin’s language are included by name and author and URL at the top of the code. An extension is a self-contained package which defines new items and new grammar lines to use them. They are not intended to be written by Cabin’s target audience of developers looking to build simple apps; they are intended to be written by seasoned developers who wish to allow new features into Cabin itself.

There is a great deal of complexity and detail involved in creating an extension setup, most of which isn’t yet worked out, but the core principle is there: that extensions are decentralised, that they augment the Cabin grammar, that their authorship is specified and included in the developed app. This helps Cabin developers stay in touch with their supporters and antecedents; it underlines that every app is built by a community of people, even if there is only one developer.

Beyond your laptop

Making an app that works is only the first step. A built app isn’t real until other people can use it, and then do so. This requires the app to be published, and for a community to grow around it. That community may be small, maybe even microscopically so, but that doesn’t matter; what’s important is that the tools we build should provide just as much assistance with community as they do with compilation.

Publishing

Publishing an app is done straight from the Cabin UI. As mentioned above, an app in development requires metadata as much as it requires code, in order to populate AppStream and show up in software stores. Cabin will help manage this process; no Cabin app will be published without an icon or with an empty description. Publishing is likely to involve generating a flatpak and pushing it to a repository -- exactly how this works still remains to be defined (and will be, as part of the next phase of development). The key point is that this is a critical part of the development process; it’s not something that happens after the development process.

Community

Helping users of the app form a community, if they want to, is also part of Cabin’s remit. There is flow between developer and users, between users and developer, between different users. A Cabin app shows an icon which flips the app over to reveal its source code; this is deliberately designed to encourage users to in some small way become developers, by seeing code that they can read which powers the app they’re using and awakening them to the idea that they could do the same.

Perhaps an app should be pushed to source control, and Cabin should assist with that process; integrating links to issues in the Help menu, providing ways to contact the developer (see Evan Miller on why an Email the Developer link better fosters a relationship between developer and users), showing software store ratings and helping the developer stay in touch with them. Again, a reasonable chunk of the next stage of development involves deciding on and designing how this could and should work.

Here beginneth the lesson

That’s Cabin. A tool to help someone who thinks of an app idea turn it into an actual app, for their GNOME desktop. A way to build apps which themselves convince others to build apps. It’s not for making a word processor. It’s for making yourself a tiny little application to calculate how high the handlebars should be on your new road bike, or to show you when sunset is at the beach, or to track your incoming parcels. It’s for turning ideas into things and having fun doing it, and then letting other people join you in the fun and in the building, whether they’re doing it for the first time or the thousandth.

A cabin is where you go to get away from stress. The cabin is a respite from the terminals on either end of the flight where noise bombards you as soon as you walk through the gate.