Adding this example here, in case anyone wants to provide feedback on how I can better specify these design concepts (or offer any other advice). The actual application gets more complicated (e.g. I did not specify how widgets are edited), but my idea is that it’s better to start with a high-level description and then refine it with more details and more concepts.
Also, it seems to me that while we start with user-facing concepts, it should be possible to also define implementation concepts as well (i.e. redefine from user of the application to user of the code). Does that make sense?
A high-level definition of a dashboard.
Description:
A configurable grid of charts widgets.
When editing the dashboard, the user can drag new widgets onto a grid of drop targets or drag existing widgets to different locations on the grid. The user can edit individual widgets to define the dataset and size for the widget. When displaying the dashboard, widget positions and other properties cannot be edited. When NOT in edit mode, widgets display tooltips. When in edit mode, the user can click on widgets to drag and edit.
concept Widget
purpose render data as a chart
principle
after fetch(d) a chart can be rendered
state
edit: Bool
data: one DataSet
numRows: one Integer
numCols: one Integer
cursorHover: Bool
showTooltip: Bool
action
fetch(d: DataSet)
assign d to data
resize(r: Integer, c: Integer)
if edit is True
assign r to numRows and c to numCols
display()
set edit to False
editMode()
set edit to True
showToolTip(e: edit, c: cursorHover)
if e and c
set showToolTip to True
---
concept Grid
purpose edit widget positions
principle
after add(w, d) can move(w, d, d2) and remove(w, d)
cannot add(w, d) or move(w, d, d2) if d in assigned
state
edit: Bool
assigned: Widget -> DropTarget
hidden: set DropTarget
action
add (w: Widget, d: DropTarget)
if edit is True
if w not in assigned and d not in assigned
and d not in hidden
associate d with w in assigned
// A widget is only associated with a single drop target
// but when rendered it may hide additional drop targets
move (w: Widget, d: set DropTarget, d2: set DropTarget)
if edit is True
if w in assigned and d2 not in assiged and d2 not in hidden
unassociate d with w in assigned
and associate d2 with w in assigned
remove (w: Widget, d: set DropTarget)
if edit is True
unassociate d with w in assigned
display()
edit is False
editMode()
edit is True
---
app widget-grid
include
Widget
Grid
sync Grid.add(w, d)
Widget.fetch(d)
sync Grid.display()
Widget.display()
// Implementation note:
// When Grid.move(w, d, d2), we should not lose widget data, numRows or numCols