Appearance
Best practices
This page discusses some best practice we use here at Aire Logic to build forms that are easy to maintain and to encourage consistency across your form authoring team.
TLDR
In summary - here at Aire Logic we:
- Use Pascal Case naming for form controls - for instance naming controls with names such as
FamilyName
orDueDate
- Use kebab-case naming for building blocks - for instance
personal-details
andnext-of-kin
- Identify reusable building blocks up-front - for instance by prefixing the name with the word generic - e.g.
generic-next-of-kin
. - Favour small building blocks - with 10 or less controls to allow flexibility of form layout composition and maximise the likelihood of re-use.
- Use short kebab case names for forms - for instance
asthma-review
- Favour intermediate calculations - Typically done within the same building block to avoid significant cross-building block coupling and also to reduce calculation complexity and fragility to change. For instance if you had a form that calculated a wellbeing score on a variety of measures such as GAD-7, PHQ-9 and The Warwick-Edinburgh Mental Wellbeing Scale - WEMWBS then it is best to break these into individual building blocks with scores in each that are then summed or otherwise combined to create an overall score.
Naming Conventions
When you have multiple form authors working on developing your library it is worth defining some naming conventions up-front. By having some naming conventions in place it will make it easier for your form authors and maintainers to understand what has already been developed, to be able to create a common data dictionary (e.g. the names of building blocks and controls are used on the reporting APIs in much the same way a Database Table and Column Name is used in SQL queries) and to reduce duplication.
Below we describe some of the strategies we typically adopt, however there is no reason you could not define your own conventions - the goal is to create consistency.
Control and Section Naming Conventions
When deciding on a naming convention for controls it is worth bearing in mind the following:
Constraints
- A control name must be unique within a building block. For instance if you had a building block that captured a structured address you could not have multiple
AddressLine
controls - you would need to find an alternative approach such as usingAddressLine1
,AddressLine2
etc. - Control names cannot contain spaces - for instance you cannot have a control called
Address Line
- Must start with a letter - Control names cannot start with a number - for instance you cannot use
1-Item
but you can haveItem-1
. - Permitted characters in the name are letters, digits, hyphens, underscores, and full stops [periods]
Naming considerations
- Use meaningful names - for instance the default names the designer applies are similar to
control-1
andsection-3
. It is better to rename them to something meaningful such asGivenName
(control) andPersonalDetails
(section) to make it easier for downstream consumers to understand what the data represents. For instance the data/value of the control might be used in a calculation elsewhere on the form or be queried via the data and reporting APIs - Choose names that reflect the data, not the question - for instance if there is a question asking about customer satisfaction use a name such as
SatisfactionRating
rather thanHowSatisfiedAreYou
. This means the control describes the data rather than the context of the data capture and is therefore more meaningful when consumed by downstream systems. - XPath is case sensitive so when referring to controls in xpath you must use the same casing as you have defined in the control/section
Possible naming conventions
You might wish to consider the following naming conventions (many of these will be familiar to coders or JSON/XML designers).
- camelCase - or more specifically lower camel case where the control name starts with a lowercase letter and each word in the name has a capital - for instance
familyName
- PascalCase where the control starts with an uppercase letter and each word in the name has a capital - for instance
FamilyName
- snake_case where the control starts with a lowercase letter and each word in the name is separated by an
_
[underscore] - for instancefamily_name
. Note: you could equally choose to start each word with a capital letter - e.g.Family_Name
. - kebab-case where the control starts with a lowercase letter and each word in the name is separated by a
-
[hyphen] - for instancefamily-name
. Note: you could equally choose to start each word with a capital letter - e.g.Family-Name
however this is relatively uncommon in the wider technology industry.
Here at Aire Logic we favour the Pascal Case notation, however any of the above is fine - consistency is key.
Repeats - approaches for naming repeated items
If you use a repeat to capture naturally repeating information such as medications or team members you might want to alter the defaults that the building-block designer will create (the designer just adds an ...-iteration
postfix to the name you give the repeat/grid). You can override this default behaviour and provide a more meaningful name.
Building Block Naming Convention
When naming building blocks you can adopt any of the naming conventions as above, however any uppercase characters will be converted to lowercase.
Constraints
- Must start with a letter.
- Cannot contain spaces.
- Can contain letters, digits, hyphens, underscores.
- Avoid lengthy names
Note - the application name is not used by the runtime environment at all so can be called anything. Sometimes it is useful to use a common application name to readily spot building blocks related to a given use-case - for instance wellbeing
.
Planning for re-use
Create a convention whereby you strongly indicate that you would expect a building block to be re-used in a wide variety of forms. For instance include the word generic as part of the name.
For example - here at Aire Logic we tend to favour kebab-case names for building blocks such as personal-details
and prefix building blocks with the word generic where we expect a building block to be re-usable - for example generic-patient-details
.
Form Naming Convention
Again similar naming convention rationale and options apply. The only thing to bear in mind is that form names will tend to be reflected in the URL - for instance https://demo.forms4health.com/SinglePassDemo/gad-7/1 the gad-7
part of the URL is the form name. As such we would recommend short / succinct form names and here at Aire Logic we prefer to use a kebab-case naming convention for forms.
Note: the form title can be different to the form name. The form title is (typically) displayed at the top of the form and should be human friendly, whereas as discussed above the form name is the unique name for the form and needs to be URL friendly.
Building Block Scope and Reuse
When designing a new form, or translating a form from an offline equivalent then it is useful to try to identify the building blocks within your form before you start.
A building block normally has one or more of these characteristics
- Appears in multiple existing forms - If you are analysing a whole suite of forms you might notice there are some common questions or set of questions that seem to be asked on all forms. For instance personal details, or Alcohol Consumption.
- Contains a set of related questions / information - For instance patient name, address and contact details.
- Something you might want to trend - For instance Body Mass Index or BMI. You might wish to trend BMI over time irrespective which form the BMI building block appeared in.
Other considerations
- Data capture you would want to split onto a separate page - Within forms4health it is not possible to split questions / fields of a building block across multiple pages, so consider how you want the layout to be before defining your building blocks.
- Err on the side of small building blocks - To give you the most flexibility in re-organising the layout of a form we would recommend creating small building blocks with no more than around 10 or so controls. This can still allow you to create long pages (containing multiple building blocks) if you so wished, but would equally allow you to capture data across multiple pages / steps as an alternative layout. If you built the form as effectively one huge building block changing layouts would not be possible.
- Consider reducing the amount of questions presented to users in one go - There has been a fair amount of user research that suggests less is best. For instance see some guidance from the UK’s Government Digital Service (GDS). Clearly you need to consider your audience though - as a clinician filling a form on a daily basis will not have the same behaviour and needs as a patient who rarely uses the service.
In reality working out the boundaries of building blocks is more art than science that you will learn through experience, however the considerations above should allow you to discover good practice for your organisation in an accelerated time frame.
Scores and Calculations
If your form contains some complex logic we would recommend trying to break it down as much as possible to minimise downstream complexity, make it easier to test and less fragile when you make changes. This is a similar strategy that an advanced user of Excel or Google Sheets would likely employ. Just like Excel and G Sheets your intermediate calculations can be hidden from end users and only be represented in the actual data.
To explain further it is easiest to consider an example scenario.
Example scenario
You are developing an overall wellbeing assessment that calculates a score based on a variety of measures such as GAD-7, PHQ-9 and The Warwick-Edinburgh Mental Wellbeing Scale - WEMWBS. Looking at the building block guidance above you have already identified that you will probably need to have at least three building blocks to capture that data (generic-gad-7
, generic-phq-9
and generic-wemwbs
) as well as a final building that summarises the overall score - let’s call it wellbeing-summary
. If we imagine the overall score as being a simple sum of all the individual wellbeing measures we have two distinct ways we could approach the solution:
Put all the calculation logic in the summary
In this case the summary score would need to consider the answers to nearly all the questions (controls) in each of the three building blocks. Combined with the need to employ the Cross Building Block Notation you will have a formula that looks like something like:
instance('generic-gad-7')/$q1 + instance('generic-gad-7')/$q2 + ...
instance('generic-phq-9')/$q1 + instance('generic-phq-9')/$q2 + ...
instance('generic-webmwbs')/$q1 + instance('generic-webmwbs')/$q2 + ...
Which is clearly a bit of a long and error prone XPath. Furthermore such an approach makes it hard to test / spot issues and also would be fragile to any changes in each of the building blocks.
Furthermore - in this case - GAD-7, PHQ-9 etc. are internationally recognised assessment scoring mechanisms and therefore justify the generic-...
prefix. You would not want to recalculate the individual scores just because the building blocks were used in a different form.
Far better to use the approach below.
Calculate subtotals within each building block
In this strategy the majority of calculations are performed within the building block with minimal cross-building block logic. In our example this would mean there would be a field (often hidden to the user) that would calculate the individual building block scores such as:
Gad7Score = $q1 + $q2 ... + $q7
And the overall score calculated in the wellbeing-summary
building block would be simplified to:
instance('generic-gad-7')/$Gad7Score +
instance('generic-phq-9')/$Phq9Score +
instance('generic-webmwbs')/$WebmwbsScore
Whilst the above seems obvious with well established scoring mechanisms such as PHQ-9, the same principles would apply for any locally created algorithms. Equally breaking apart complex logic within a building block allows some intermediary values to be checked / tested and reduces the complexity of the individual formula.