Best practices
Naming conventions
In general, all bricks shall be named using Title Case, with capital letters for all words and spaces between words.
Functions and Actions
Function Names
use Title Case, with capital letters for all words and spaces between words.
inputs
and outputs
are in lowercase, with spaces between words.
Data models
Model Names
use Title Case, with capital letters for all words and spaces between words.
properties
and relations
are in lowercase, with spaces between words.
UI components
Component Name
use Title Case, with capital letters for all words and spaces between words.
Properties
use Title Case, with capital letters for all words and spaces between words.
UI Components
UI Components have two main purposes:
- Allow the creation of reusable components
- Make it easier to layout elements
For example, using a UI Component to store the content of a form allows to easily align the different text fields and form elements. The 'form component' can then be dropped on a screen and resized in a coherent manner, without needing to control each form element individually.
Reusing UI Components: exposing children object properties
It is quite rare that we want to reuse a UI Component as is in multiple locations. In most cases, we want to parameterise in one or both of two ways:
We want to have different texts (or any other property) in the different instances of the UI Component
Customizing texts (or other properties)
When text or other properties of the UI Component's internal UI Elements must be set, use the following approach:
- Add a custom property in the Context of the UI Component (e.g. "Form Title")
- Map that property to the appropriate UI Component, using the f(x) of the relevant property.
Exposing internal events
Beyond properties, the UI Component's context can define Events.
Those events can be triggered from within the UI Component using Dispatch Event actions.
Within the parent Screen or UI Component, the application can respond to the events by configuring the f(x) on the UI Component's events.
Data
Upon creating a data model, it is recommended to also create a set of helper logic bricks to make it easier to manipulate that data. The standard programming terminology is:
- Constructors are used to construct objects from a model and the relevant parameters to should be set. We may typically have multiple constructors to accommodate different criteria.
- Getters are used to retrieve information from an object.
- Setters are used to modify information within an object.
Those can be created straight from the Data Model Editor.
Summary
Given the following business model:
It is good practice to create the following bricks:
- Constructor: a
Create Geolocation
action, taking "Longitude", "Latitude" and "Altitude" as inputs, and outputting a persisted "Geolocation" object. - Getter: a
Geolocation's Attributes
function, taking a "Geolocation" object as input, and outputting "Longitude", "Latitude" and "Altitude" - Setters: a
Set Geolocation's Attributes
action, taking a "Longitude", "Latitude", "Attribute" and "Geolocation" as input, and outputting a "Geolocation" object.
Even though you may need to create multiple specialised variants of those bricks, those three base bricks provide a very good starting point. The sections below dive into those elements in a bit more detail.
Constructors
Constructors are logic bricks that typically contain a Create Local Object brick, as well as a few Set Object Property bricks.
More specific names could be:
Create Geolocation from City Name
Create Temperature from °C
Here is a potential Constructor action for creating a Geolocation object from a Longitude and Latitude:
As the number of actions and parameters grows, you may also want to stack the bricks instead (with the drawback of having the Control Flow getting a bit in the way):
Getters
Getters allow retrieving information from the object. Those can be simple properties (like Latitude in our example above), or higher-level (and often higher-valued as well) information.
Examples:
Geolocation's Attributes
Geolocation's Latitude
Geolocation's Position
(might for instance provide only Longitude and Latitude, but not Altitude)Geolocation as String
(provides a location with the following format: 46.5172214°N, 6.5621934°E)Geolocation as Address
(provides a location with the following format: PSE D, 1015 Ecublens, Switzerland)Temperature as °F
(provides a temperature as Fahrenheit)
Here is a sample getter that retrieves a single property:
Many functions need to retrieve more than one property of an object. As such, it is often more convenient to define a single function that provides all attributes. It is important to note that there is no harm in leaving outputs unconnected within a function. Retrieving all properties at once:
Setters
Setters are used to modify the attributes of an object.
Examples:
Set Geolocation's Attributes
(when setting all attributes at once)Set Geolocation's Position
(when setting both the Latitude and Longitude)Set Geolocation from Address
Set Temperature from Fahrenheit
Here is a sample setter:
Pitfalls
Draw still isn't feature complete. This section therefore lists the main limitations and possible workarounds.
Refactoring
Refactoring typically occur on different levels:
- Reusing a part of a function in another function
- Updating data models
- Updating the UI
Data models
When refactoring a Data Model, the following approach is recommended:
Adding a property:
- Nothing to do here, but don't forget to update the Constructors, Getters and Setters accordingly.
Removing a property
- In the data model editor, rename the property to "my property OLD"
- Look for usage of the property using the Spec & Doc editor
- Update all locations accordingly
- Once all usages have been removed, delete the property. This will delete all instances of that property in the DB.
Changing a property's type, or refactoring a property into a separate business model is done by combining the approaches above, i.e. by adding the new version and removing the old usage.
UI updates
UI Components are the best way to encapsulate and reuse information.
Scrolling
Lists are scrollable by default. Screens however are not, as they are meant to support apps, which usually have scrolling in specific locations, and not globally for the whole app. If you need a scrollable pane, you must for the moment use UI Components. The simplest approach is the following:
- Screen contains 1 full screen UI Component, and nothing more
- Full screen UI Component contains any additional UI Component
Local vs Global objects
By default, the Create Local Object
brick doesn't persist the object on the Orchestrator.
Importantly as well, files (typically those coming from Take Camera Picture
) must be persisted explicitly.
When building constructors that don't include the Persist operation, we recommend making it explicit by putting 'Local' in the constructor's name: Create Local <<name of business model>>
.
Working with multiple browser tabs
It is often very convenient to open multiple tabs or windows to avoid having to switch from one editor to another.
Main logic
Since there is no main loop, we recommend putting general functions (e.g. registration of a listener, starting a Timer, ...) in the screen's On Load
function.
Export
We recommend exporting the different bricks (screens, UI components, functions, etc.) individually, in order to make the export granular.
Dependencies
At the moment, Draw supports importing projects into one another. This allows creating one project acting as a library of reusable bricks, which can then be reused across multiple other projects. Versions are not fully functional at the moment, so updates to the library project are immediately reflected in the importing projects as well.
Similarly, double-clicking on an imported function or UI Component will open that function or UI Component for edition in the other project.