Enterprise software users require more than just a beautiful UI. They want to view their apps on phones, tablets, surfaces, desktops and more. It is vital to a business’ success that this value be delivered to employees as fast as possible.
The industry is chock full of different technologies and frameworks that simplify the model for how we build UIs. Any number of technologies will make life easier for the interface developer, yet there is still much to be desired. To bridge the programmer to non-programmer gap, we wanted to create a way for anyone to easily design a powerful, modern application that stands the test of time. We reduce the responsibilities of the developer to a simple task: tell us what you want your UI to do — we’ll handle the rest. Dorothy didn’t know she needed to follow the yellow brick road, meet some friends, and kill a witch. She just wanted to get to Oz. Why should Dorothy have to know? We all probably could’ve been spared the details anyways.
Our mission is to change the way software is written. We created SAIL (Self-Assembling Interface Layer) in fulfillment of that vision.
var article = document.createElement(“article”);
var paragraph = document.createElement(“p”);
var text = document.createTextNode(“Lots of text”);
We’re simply trying to put some text in a paragraph, and put that paragraph inside of an article. Why worry about how to create the elements and how to stitch them together? Why not say what you mean? Try declarative:
Lots of text
Declarative code describes what you want to do, and not how you want to do it. This restricts the concern of the developer to what they want to happen. In other words, the developer just needs to describe the end result, not caring about how we get there. Why is this important? It’s much easier for developers to reason about a black box. As code becomes easier to reason about, the level of skill required to write the code approaches zero.
I Feel a Change Comin’
It’s pretty easy to understand the example I presented above without much knowledge. The real complexity comes when you want that UI to change in response to an event. The developer must be able to specify interactive behavior. In typical event-driven application, an event (typing, clicking, push notification, etc.) causes some imperative code to be called. The developers are then responsible for the propagation of those changes across the UI. Reactive programming allows the designer to declare the state change that a given event will trigger. That state is automatically propagated throughout the UI.
Modern MVC frameworks have done a lot of work to shoehorn imperative languages into declarative constructs. While these frameworks offer a well-defined set of rules for how one should develop, those rules are easily broken, undermining the power that the framework is supposed to provide. Restricting developers to the confines of a declarative and reactive world makes a framework much more accessible. We make it much easier to develop the right way, and much harder to develop the wrong way.
Make it Functional
Functional paradigms in our framework solidify the simplicity of our UI design experience. A few key principles:
- Functional programs have no mutable state. Simply put, what you see is what you get. There is no risk of side effects, and it makes it very easy for us to share and cache state. Immutability saves blood, sweat and tears down the road.
- Functional programs use first-class and higher-order functions instead of explicit control flow. No for or while loops. A long if/else statement can become a single assignment using a function.
- Functions are referentially transparent. No surprises. Every time you call a function with the same inputs, you should get the same result.
Our pure functions output UI elements. When a customer defines an element, there are no side effects. When you describe that element, the business logic can be collocated with its appearance. Most importantly, your interface appears and behaves exactly as you describe it no matter what. We create small, self-contained UI functions that act as building blocks for our users to work with to easily create complex UIs. Think Excel spreadsheets:
When you update a cell, everything in that sheet will automatically update based on the rules that you have defined for each UI element (cells and charts).
Appian’s UI Framework
SAIL is Appian’s patented reactive UI framework based upon our own functional expression language. Consider this expression:
display: lower(concat(first, ".", last)),
textField(label: "First", value: first, saveInto:first),
textField(label: "Last", value: last, saveInto: last),
textField(label: "Display", value: display, readOnly: true)
The designer wants two input text fields, and one read only. The designer declares that the display variable will be the concatenation of the first and last names, and that the value inside of the text field will be saved back into the first and last name when the user interacts.
When a developer is designing a UI in SAIL, they are describing the UI at any moment in time. Functional Reactive concepts guide our declarative control flow structures. There are no callbacks, no event handlers. Views are given the power to define what pieces of state they depend on and how. An event triggers an update of state, and each building block responds accordingly with deterministic output.
Appian follows similar patterns to those discussed above:
- Appian UIs are created from functions that describe the state of the UI at any point in time.
- Data propagation changes are automatic and implicit. There are no manual updates of the UI.
- Side effects can only be triggered by user interactions as part of a unidirectional data flow.
The SAIL Context (current state) and the designer-configured SAIL expression combine to create a model for the interface that is to be rendered. User interactions trigger reevaluations that are handed to the SAIL runtime. Updates propagate and are deterministically reflected on the interface exactly as the designer declared in their expression. Magic!
SAIL architecture closely resembles that of Elm, a popular language for developing front-end applications. These frameworks are the arbiters for all state changes triggered by the user. The view cannot directly update the model, the FRP runtime will handle the request. These are referred to as Managed Effects. In both SAIL and Elm, the developer simply has to describe to the runtime the set of rules for handling updates to values. The runtime handles the rest. Because all of these rules are referentially transparent, it gives great power to the framework to optimize — if we receive the same input, why re-evaluate? Just return a cached result. Even better: any and all side effects are managed through the framework, so they can be easily recorded and replayed.
Why use a UI Framework like this?
Our framework allows the designer to stitch together a robust interface using functions as the building blocks. It is our mission to make custom application development accessible with low amounts of code and SAIL was a giant leap towards that vision. Because we are confident that our functions are always going to behave in the same way in production, we can easily give developers a structured, graphical, design experience that lets them see what they are building in real time.
Business logic and functional relationships of components can be defined in one location. Our framework allows the designer to state his or her intent for a UI. Once we have captured that intent, we define how a given client should render the UI by implementing a client specific version of each building block (e.g. a drop-down). As UX trends and industry standards change, we can evolve these building blocks and give customers the latest and greatest user experience without touching functionality. The customer writes an application once and can expect it to appear and operate beautifully on all platforms throughout time.
Consider the simple example of our multiple dropdown component. Both of the components you see are sourced from the exact same UI definition. We were able to update the rendering of the component to a modern, more attractive, more compact and more accessible design without touching our customers work.
SAIL simplifies the development process so that it can be effective in the hands of non-programmers. FRP allows for extreme functional complexity with minimal development complexity. Businesses no longer need to hire expensive development teams for each custom software solution they require. Just about anyone can build robust applications in Appian simply by stating what you want to see and do, sans the typical concerns of many popular UI frameworks.