Simplicity vs Expressiveness: Leverage Cloud Development Environments to Solve this Low Code Dilemma

Andreas Eberhart
6 min readJan 16, 2024

--

Low Code development platforms allow citizen developers to quickly develop custom applications. These platforms abstract from the nitty-gritty details of traditional development approaches and provide a framework for modeling the domain and application logic in a quick and concise manner.

“Hiding the nitty-gritty details” inevitably involves the platform making a compromise between forcing citizen developers to adhere to predefined — and thereby easy to use — standards and the complete freedom of writing things from scratch.

In this paper, we first show how this tension between simplicity and expressiveness manifests itself in low code platforms. Then, we show how a hybrid approach based on Cloud Development Environments (CDE) can solve this dilemma.

Simplicity vs. Expressiveness in Low Code Editors

The GrapesJS editor exposes several options for a screen element (seen on the right)

Consider this screenshot of the GrapesJS UI editor. It hides the underlying HTML code, but it does expose around 100 options even for a simple text element. The target audience for GrapesJS are web designers, so it certainly makes sense to show all of these options. However, a normal citizen developer would probably be overwhelmed by the sheer number of options and by terminology like flex layout and text decorations.

In the Dashjoin Low Code platform, we try to limit the options. The text editor looks like this:

Dashjoin editor for a text widet

This is certainly easier to use, but it raises the question: “what if I really want this text to be italic green?”

Another place where the dilemma surfaces is the widget library. The following screenshot shows the available elements of the Bubble platform:

Visual elements for building App with Bubble.io (partial list)

We can see a mix of very generic widgets (text, icon, button, table) and very specific ones (facebook like, shoprocket buy button). Obviously, it is impossible to build a widget for every use case. Therefore, low code platforms typically allow some sort of plugin mechanism. Bubble, for instance, provides some HTML and JavaScript hooks for this purpose:

Bubble editor for custom elements

Obviously, this is not ideal. You are forced into the world of regular coding (which is understandable), but you’re left without the proper tools (editor, debugger, etc.) and with severe limitations (i.e. you cannot use the NPM library of your choice).

Cloud Development Environments

The previous section showed that Low Code platforms must provide a way for developers to express requirements that are outside the simplicity provided by the platform defaults.

We believe that Cloud Development Environments (CDE) are the solution. CDE leverage cloud packaging and deployment methods to provision coding workspaces right in the browser. The advantage is that new team members can get started immediately, without having to go through an elaborate setup procedure. Furthermore, sentences like “it works on my machine…” can no longer serve as an excuse since everybody has a standardized environment. It either works or it doesn’t.

Companies like Gitpod offer CDEaaS solutions, and CDE features like Codespaces are being added to existing solutions like Github. Dashjoin Studio is the first Low Code CDE available.

Let’s step through an example to see how this works: Assume you’re building a life science application that is based on data about molecules. The data includes SMILES strings describing the molecule structure, and you would like to use a 3rd party library to visualize the molecules. Obviously, the core platform does not provide a widget for this very specialized purpose. So we need to build it.

The first step is to provision the CDE:

docker run -p 3000:3000 -p 8080:8080 -p 8081:8081 -e DJ_ADMIN_PASS=djdjdj dashjoin/studio

Next, we open http://localhost:8081/ and login using admin and djdjdj (the password provided on the docker command line). This opens VS Code in your browser. From the menu, open a new terminal in the “Dashjoin Platform UI” folder and type:

yarn add smiles-drawer
yarn dev

Yarn is a JavaScript package manager that will retrieve the latest version of the library and all other required components. The command “yarn dev” starts the development webserver.

Now we add the widget code Smiles.tsx in src/widgets:

import { Icon } from "@mui/material"
import { Widget } from "../model/widget"
import { expression, title } from "../api/Const"
import { useEffect, useRef } from "react"
import { Loading } from "ra-ui-materialui"
import { PrintError } from "../components/PrintError"
import { useExpression } from "../hooks/useExpression"
const SmilesDrawer = require('smiles-drawer')

export const Smiles = ({ widget }: { widget: Widget }) => {

const imgRef = useRef<HTMLImageElement>(null);
const drawer = new SmilesDrawer.SmiDrawer();

let { data, isLoading, error } = useExpression(widget.expression)
useEffect(() => {
drawer.draw(data ? data : 'C', imgRef.current, 'light');
});

if (isLoading) return <Loading />
if (error) return <PrintError error={error}></PrintError>

return (
<div>
<img ref={imgRef} width={300}></img>
</div>
);
}

export const config = {
id: 'smiles',
title: 'Smiles',
description: 'Renders a SMILES string as a 3D molecule',
version: 1,
icon: <Icon>science</Icon>,
controls: {
type: 'autoform',
schema: {
properties: {
title: title,
expression: expression
}
}
}
}

This code contains two blocks. The first block is the actual widget. It gets the parameter “widget”, which is a JSON structure, to configure the widget. The rest of the code is taken from the library’s documentation. The key point is the line where the result of widget.expression is passed as the parameter to the draw function (the call drawer.draw(…)). This parameter contains a JSONata expression to compute the SMILES string passed to the widget.

The second part defines what the widget edit dialog looks like. It contains an icon, some description, and a list of controls. In this case, we allow for editing the widget title (this is a property shared by all widgets) and the expression to compute the SMILES string. You could add other properties. For instance, the width of the generated image is fixed at 300 pixels. This could be replaced with a widget parameter.

Now edit the file CustomWidgets.tsx in src and add the following lines:

import { config } from "./widgets/Smiles";
import { Smiles } from "./widgets/Smiles";

export const customWidgets = [
{
widget: Smiles,
config: config
}
]
Dashjoin Cloud Development Environment including VS Code, Git, and custom plugins

As soon as these changes are made, they become available on http://localhost:3000. Specifically, the new SMILES widget can be added to a page using the regular layout editor:

The new SMILES widget in the widget library
The widget is configured with the SMILE string constant for Glucose (“OC[C@@H](O1)[C@@H](O)[C@H](O)[C@@H](O)[C@H](O)1”)

Please note that the platform can access external REST services and databases. Rather than providing a constant string, we can retrieve the SMILES string via a more complex expression such as $openJson(url).smiles or $read(“life-science-db”, “molecule-table”, “Glucose”).

Obviously, adding a new widget requires ReactJS know-how and is not something a typical citizen developer would do. Therefore, we provide the option of packaging these changes for re-use. Once a ReactJS developer implemented the widget, it looks like just another widget for the citizen developer.

Summary

We have shown how Cloud Development Environments can benefit Low Code platforms in cases where a citizen developer needs to escape from the platform defaults in order to implement a certain requirement. Leveraging CDEs has the advantage that familiar tools such as VS Code, git, yarn etc. are available and that developers are free to use any 3rd party ReactJS library available on NPM.

--

--

Andreas Eberhart

Entrepreneur, Geek, Techie, Programmer, Dad & Husband, Biker & Baller