Tabris.js: Declarative UI in 100 lines of functional programming
Besides software development, I also love football (soccer), photography, and my recently born daughter.
But enough about that, let’s talk about building a declarative UI for Tabris.js!
Moreover, Tabris.js also offers some unique advantages to developers, like a cloud build service and developer apps for iOS and Android. This means you can develop iOS apps without owning a Mac or installing Xcode (but need an iPhone / iPad). Likewise, you can develop Android apps without downloading Android studio and the Android SDKs (but need an Android phone / tablet).
That said, as an evolving technology, there is still a lot to improve on. The beauty of it is that it’s open source so anyone can fork the code base, hack on it, and even become a contributor.
As I was building my first app with the platform I couldn’t help notice how the API is laser focused in its precision and ability to “control” the UI. However, I felt like I would be happy to trade some of this precision for more expressiveness and a more declarative code style that I was used to from web app development. That sent me on a journey of exploration – seeking to find a way to enjoy the advantages Tabris.js has to offer, while writing less (and cleaner) code.
The journey begins
I took the bookstore example from the Tabris.js repository, and I will show my thought process on a small snippet that is used to render the “Book details” section:
The things I wanted to improve:
- Avoid writing
appendTofor each of the elements (5 times)
- Avoid writing
tabris.createfor every element I create (6 times)
- Avoid saving references to items
var coverView = tabris.create(...)
- Extract layout data from the content
- Understand what the code does with a glance
- It doesn’t have a “detached” part of the application like external HTML / template files.
- It has really great tooling with a good IDE (like WebStorm or Visual Studio Code), and can even be joined with TypeScript. Compare that to a
- Event handlers like the
.on(“tap”, SOME_FUNCTION )blend in perfectly in the JS world.
I was on my way to find a better paradigm for Tabris.js – one that would fix the inconveniences, but still keep all the benefits over HTML and other template engines.
Functional programming to the rescue
I was reading an interesting post by André Staltz (functional programming expert). Something that really caught my eye was this well phrased explanation of what I was trying to accomplish:
“You want to choose the library/framework with the most ergonomic paradigm. That means a good signal-to-noise ratio: each line of code contributes to delivering features, each line of code is “semantic” and reads like a specification. In short, the closer the code is to a description of “what I want the program to do”, the better. But the more manual wiring there is, the more “noise” is added to your code, and the more verbose it gets.”
The article also explains how hyperscript-helpers can be used as a cleaner alternative to JSX with Cycle.js.
Inspired by this notion, I decided to apply this behaviour to the Tabris.js bookstore example. After a bit of tinkering using functional programming concepts, I wrote a small template engine that could render this:
* I also added ES6 into the mix to get arrow functions and other syntactic goodies.
All the styling, layout data and config were moved to an external object:
* Notice the use of the advanced layouts in Tabris.js using
A quick check shows everything that needed improvement was indeed improved:
AppendTo‘s were replaced with a semantic structure of arrays passed to components.
tabris.create(“TextView”)commands were replaced with a leaner
Text( content )
- There is no longer a need to save reference to elements.
- The layout data is extracted to an external source and referenced directly.
- It is easy to understand what the code does with a quick glance.
Will it scale?
Applications tend to grow in features and thus in the codebase demands, and we need to be sure this approach can scale well in the long term – I checked whether components, mixins and other paradigms I knew from web app development would blend in well.
It seems creating components is a natural behaviour with this technique. Using the
BookDetails function as a component in another template was very easy. Just pass it the book to render and it’s good to go:
It can also be moved to an external file and then required when needed.
Adding mixins for animations also turned out to be very clean and simple:
Also tooling is very powerful with this approach – the IDE can easily show the parameters and defaults for component / mixin:
In this experiment, all this goodness was added as external layer on top of Tabris.js that is just 100 lines of (lightweight) code in functional style in this file.
We are working to include a declarative UI, reusable component structure, animation mixins and much more into Tabris.js right now. In the meantime you can play around with my code and hack / comment on it on Tabris.js experiment playground on GitHub.
Please note that Tabris.js is not a framework that tries to do everything – it focuses on the core abilities to use native mobile platform UI widgets in a Cordova app, and offer a great cloud build service.
Hence, it doesn’t enforce any specific pattern, so that it can be easily combined with other libraries / frameworks or used as a powerful and lightweight standalone.
Who knows, do that and you could spark the “angular-native” project the community has been craving for 🙂
Go ahead — get started by signing up at Tabris.js and doing the getting started examples — you will be creating your shiny new app in no time! Comment here and tell us what you would like us to add to the new template engine (or just fork the project and add it yourself).