Skip to content

Instantly share code, notes, and snippets.

@ordnungswidrig
Created January 20, 2016 14:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ordnungswidrig/e0af8ecee4f97ae08aa8 to your computer and use it in GitHub Desktop.
Save ordnungswidrig/e0af8ecee4f97ae08aa8 to your computer and use it in GitHub Desktop.

Apex architecture on documents, forms and modality

Motivation

During the execution of workflows at certain points information must be presented to the user and information must be gathered from the user. The actualy input method depends on the device that is used by a user, ranging from a web application to filling out a paper form.

The attributes of different devices are collected in “modalities” which describes a group of devices sharing common properties.

The data that shall be collected varies in shape and size, ranging from a single decision (“checkbox”) over what is a typical form (“residential address”) to a dynamic collection of data (e.g. document with a list of structured individual data items, “allergy status”)

We looked into prio art and found no existing data format or protocol specification which would either satisfy our needs or could be extend to do so while still not causing an extraordinary amount of work to implement it.

Design

Separation of data model and ui model

Following the design of XFORMS the document specification separates the description of the underlying data model from the specification of the user interface. This gives clean semantic for a data processing component that needs to validate a document instance without the need to understand the user interface related declaration. Additionally this enables to user a different (generally simpler) set of validations in the user interface.

Data model

There are existing languages do describe and validate nested data structures, e.g. XML Schema, IDL or protobuf. Regardless of the actual language used a data model description must satisfy two properties: it must provide a way to determine if a data instance is valid according to the model and it must provide some means to “suggest” how to construct a valid instance. The latter is especially essential for the automatic creation of a user interface. These two properties loosely resemble existential and constructive proofs.

UI model

The description of the user interface must be as generic as possible and as concrete as necessary. Given the high level of abstraction while modeling a workflow and to keep the efforts low it’s feasable to create a ui language that is not bound to “physical” properties of a target device. This means that instead of specifying a screen layout with x and y coordinates in pixels, it’s preferrable to use “logical” units as “em”, which is the width of the lower case letter “m” and to declare the arrangement of interface controls by spatial relations (right of, below, a wide as). The android layout language can serve as a good example of this. Even with a “logical” layout description it’s unevitable to take a device’s physical attributes into accound, or, even on the same device the attributes change with it’s orientation. For these different Modalities the UI model needs to support the adjustment of individual properties of the interface, or, where necessary, defining alternate layouts.

Proposed implementation

Data Model

Types

Atomic Types
  • String (min, max, pattern, charset?)
  • Text (multiline String, max chars, charset?)
  • Integer (min, max)
  • Floating point (min, max, precision)
  • Boolean
  • Enum
Composed Types
  • Records (named fields of some type)
  • Lists (sequence of fields of some type, min count, max count)
Validation
  • Every type supports list of additional validation expressions
  • For composed types validation can inspect contents
  • Arbitrary validation declaration which triggers some custom validation function in the engine? E.g. validation “custom:ssn” would a registered validator function that was registered in the engine as “ssn”
Lookup Values

Some values in the datamodel must refer some other data. The user should not enter an “identifier” of that data but should be able to select from some options. If the set of options is not know when creating he data model, or when it’s dynamic the we need to support some callback declaration which the engine can use to provide a concrete set of options.

Constraints

  • XPath - implementations exist, tooling support but XML oriented, XSD uses this
  • clojure - generic and powerful, unclear how to restrict the power
  • custom - must be defined and implemented

UI Model

Allow annotation of data model elements with ui declaration

  • Keep declaration simple in the simple case.
digraph bigpicture {
  node[fontname="Helvetica Neue", shape=box];
  model[label="document model"];
  model->m1;m1[shape="ellipse", label="data type"];
  model->m2;m2[shape="ellipse", label="constraints"];
  model->m3;m3[shape="ellipse", label="multiple field validation"];
  model->m4;m4[shape="ellipse", label="field description"];
  model->m5;m5[shape="ellipse", label="basic types"];
  model->m6;m6[shape="ellipse", label="composed types"];
  m6->m7;m7[shape="ellipse", label="list types"];
  m6->m8;m8[shape="ellipse", label="record types"];
  
  ui[label="ui model"];
  ui->model[label="enriches"]; 
  ui->u1;u1[shape="ellipse", label="modality"];
  ui->u2;u2[shape="ellipse", label="layout"];
  ui->u3;u3[shape="ellipse", label="input time validation"];
}
{:id :allergy-status
 :type :record
 :fields [{:type :string :id :firstname :minlength 1 :maxlength 100 :ui/label "First name"}
          {:type :string :id :lastname :minlength 1 :maxlength 100 :ui/label "Last name"}
          {:type date :id :dob :mindate "1890-01-01" :maxdate "2050-01-01" :ui/label "Date of birth"}
          {:type :list :id :allergies :contains {:type :record :fields [{:id :first-occurence :type :date}
                                                                        {:id :allergen :type :string}
                                                                        {:id :tested :type :boolean}]}}]}
{:layout :linear
 :direction :page
 :contents [{:layout :linear
             :direction :line
             :contents [{:layout :field :ref :firstname :width "70%"}
                        {:layout :field :ref :lastname :width "30%"}]}
            {:layout :field
             :ref :dob}
            {:layout :field
             :ref :allergies
             :elements {:layout :linear :direction :page
                        :contents [{:layout :field :ref :allergen}
                                   {:layout :field :ref :first-occurence}
                                   {:layout :field :ref :tested :control :toggle}]}}]}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment