Effective Arche
How to write a model that reads like every other one. The language
(spec.md) says what is allowed; this says what is good. Most of it is
done for you: archec fmt --write writes the layout, and archec vet reports
the rest. Each section is one vet code — archec explain <code> prints it.
The shape of a project#
- One folder per project, the main file at its top (
main.arche), one file per part of the system:models/,spec/(requirements, functions),verification/(test plans, scenarios),app/(what the Arche app shows). - Structure in
.arche, behaviour in.py, translations apart. A model file says what the system is; its Python lives beside it (archec fmt --extract-code); the texts in a second language live intranslations/<lang>.arche(archec refactor translations --extract en). - Write the core first (components, ports, links, messages, requirements, test plans). The other sets — deployment, functional analysis, safety and security, the app — come when you need them.
long-form#
There is one way to write each thing. An older or longer form still reads, but
archec fmt writes the standard one: message, not msg; out tx: can, not
port tx: can out; unit m/s, not unit "m/s".
bad: msg GO: bool good: message GO: bool
bad: port tx "TX": can out good: out tx: can "TX"
same-line#
One item per line. ; separates items only inside a block written on one line:
bad: kind ecu; layer physical good: kind ecu
tags safety layer physical
tags safety
fine: widget title { type text; at [0, 0, 12, 1] }
property-order#
The properties of an element in one order, in every file, so the eye knows where
to look: what it is (description, text, objective), how it is classified
(kind, layer, tags, status, priority…), its type (provides, sends,
unit…), the rest, its traces (satisfies, verifies, derives…), and its
place on the canvas (at, size). archec fmt puts them in it.
property-group#
Three or more properties that go together are written as their group —
timing { latency 2ms; jitter 100us; bitrate 1Mbps } — which is the same as the
lines. The groups: timing, delivery, compute, physical, errors.
declaration-set#
The Arche app's declarations (pages, panels, widgets, stories, benchmarks, the
menu) live in app/*.arche, apart from the model, so a model file holds only
the system.
naming#
A name's case says what it is, as in Go:
| What | Case | Example |
|---|---|---|
| a definition, a system, a type, an interface | PascalCase |
BrakeEcu, Car, Speed |
| a part, a port, a function, a variable | snake_case |
brakes, can0, regulate, target_speed |
| a message, a constant, an enum literal | SCREAMING_CASE |
BRAKE_CMD, MAX_SPEED, AUTONOMOUS |
| a requirement, a test plan, a case | as its document writes it | REQ-BRK-001, TP-AEB, TC-AEB-01 |
An imported name keeps its Arche id with as: component flash_memory "FLASH" as c-1793752253957. Rename in the editor (F2): every use follows.
code-in-model#
A Python block of more than a few lines is behaviour, and reads better in the
.py file beside the model: archec fmt --extract-code --write moves it, and
the function stays bound to it.
arche-body#
A Python body that does only what the action language does (if, goto,
send, return, assignments, comparisons, wait, log, calls to the part's
functions) reads better as a ```arche body. archec then checks it, and
translates it to C, Rust and Go, not only to Python. The quick fix Convert to
arche body (or archec fix --only arche-body) writes it. A body with more
than that (a list, a library, a name the model does not declare) is left as
Python.
Small things#
- A label is what people read: write one on every declaration a reader meets
(
component BrakeEcu "Brake ECU"). - A guard in brackets:
Idle -> Run on GO [speed > 0]. - A trace where it starts:
satisfies REQ-1on the part,verifies REQ-1on the case —archec refactor move-tracesmoves the ones written apart. - Cases that differ only in their values: one
casestable. - A text that cannot be verified ("as fast as possible", "TBD") is pointed out
(
vague-word): say the number, or mark the requirementtbc.