Dieser Post ist Teil der Serie über mein privates BeagleBone-Black-Projekt. Das Projekt nutzt StrictDoc für Anforderungsmanagement — kein Word-Dokument, kein Jira-Ticket, sondern Textdateien direkt im Repository. Was merkwürdig klingt, ist in der Praxis überraschend sinnvoll.
Was ist StrictDoc?
StrictDoc ist ein Open-Source-Tool für dokumentenbasiertes Anforderungsmanagement.
Anforderungen werden in .sdoc-Textdateien geschrieben,
die im selben Repository wie der Code leben — und damit auch im selben Git-Verlauf.
Warum kein klassisches ALM-Tool?
Jira, Azure DevOps, Polarion — all diese Tools haben denselben Nachteil: die Anforderungen leben getrennt vom Code. Eine Anforderung wird geändert, der Code angepasst, aber niemand verknüpft beides explizit. Nach einem Jahr weiß niemand mehr ob die Implementierung noch zur Anforderung passt.
StrictDoc zwingt zur Verknüpfung. Ein Code-Kommentar referenziert eine Anforderungs-ID, und StrictDoc kann prüfen ob jede Anforderung mindestens eine Implementierungs-Referenz hat.
StrictDoc ist kein DOORS-Ersatz für sicherheitskritische Systeme mit regulativen Anforderungen. Für ein privates Projekt ist es genau richtig. |
Dokumentenstruktur
StrictDoc-Dokumente sind .sdoc-Textdateien mit einer einfachen Syntax.
Basis-Struktur
[DOCUMENT]
TITLE: BeagleBone Black — GPIO Anforderungen
[SECTION]
TITLE: Funktionale Anforderungen
[REQUIREMENT]
UID: BBB-GPIO-001
STATUS: Active
TITLE: GPIO Pin lesen
STATEMENT: Das System MUSS den digitalen Zustand eines konfigurierten GPIO-Pins lesen können.
[REQUIREMENT]
UID: BBB-GPIO-002
STATUS: Active
TITLE: GPIO Pin setzen
STATEMENT: Das System MUSS einen konfigurierten GPIO-Pin auf HIGH oder LOW setzen können.
RELATIONS:
- TYPE: Refines
VALUE: BBB-GPIO-001Wichtige Felder:
UIDEindeutige ID — wird im Code referenziert. Nie ändern nach dem ersten Commit.
STATUSActive,Draft,ObsoleteSTATEMENTDie eigentliche Anforderung — mit SHALL/MUST/SHOULD wenn man EARS-Notation nutzt
RELATIONSVerknüpfung zu anderen Anforderungen (Refines, Implements, Verifies)
Hierarchie: System bis Software
Ich trenne Anforderungen in drei Ebenen:
docs/requirements/
system/
gpio.sdoc ← Systemanforderungen (was das System können muss)
software/
hal-gpio.sdoc ← Software-Anforderungen (wie der HAL es umsetzt)
api-gpio.sdoc ← API-Anforderungen (wie die REST API es exponiert)
tests/
gpio-tests.sdoc ← Testfälle (wie verifiziert wird)Anforderungen schreiben — GPIO-Beispiel
Systemebene (system/gpio.sdoc)
[DOCUMENT]
TITLE: System — GPIO
[REQUIREMENT]
UID: SYS-GPIO-001
TITLE: Digitaler Ausgang
STATEMENT: Das System MUSS mindestens 4 unabhängige digitale Ausgänge bereitstellen.
[REQUIREMENT]
UID: SYS-GPIO-002
TITLE: Digitaler Eingang
STATEMENT: Das System MUSS mindestens 4 unabhängige digitale Eingänge bereitstellen.Softwareebene (software/hal-gpio.sdoc)
[DOCUMENT]
TITLE: HAL — GPIO
[REQUIREMENT]
UID: SW-GPIO-001
TITLE: GPIO lesen über sysfs
STATEMENT: Der HAL MUSS GPIO-Zustände über das Linux sysfs-Interface lesen.
RELATIONS:
- TYPE: Implements
VALUE: SYS-GPIO-002
[REQUIREMENT]
UID: SW-GPIO-002
TITLE: GPIO schreiben über sysfs
STATEMENT: Der HAL MUSS GPIO-Zustände über das Linux sysfs-Interface schreiben.
RELATIONS:
- TYPE: Implements
VALUE: SYS-GPIO-001Traceability im Code
Die Implementierungs-Referenz sitzt direkt im Quellcode als Kommentar.
C-Treiber
/**
* gpio_read - Liest den Zustand eines GPIO-Pins via sysfs.
*
* @req SW-GPIO-001
*/
int gpio_read(int pin, int *value) {
char path[64];
snprintf(path, sizeof(path), "/sys/class/gpio/gpio%d/value", pin);
FILE *f = fopen(path, "r");
if (!f) return -ENODEV;
fscanf(f, "%d", value);
fclose(f);
return 0;
}Rust HAL
/// GPIO-Read via C-Treiber.
/// @req SW-GPIO-001
pub fn gpio_read(pin: u32) -> Result<u8, HalError> {
let mut value: i32 = 0;
let ret = unsafe { c_gpio_read(pin as i32, &mut value) };
if ret < 0 {
return Err(HalError::GPIOReadFailed(ret));
}
Ok(value as u8)
}Test
// TestGPIORead verifiziert SW-GPIO-001 und SYS-GPIO-002.
// @req SW-GPIO-001
// @req SYS-GPIO-002
func TestGPIORead(t *testing.T) {
h := hal.NewMockHAL()
h.SetGPIOValue(48, 1)
val, err := h.GPIORead(48)
assert.NoError(t, err)
assert.Equal(t, 1, val)
}Das |
StrictDoc HTML-Export
# Installation
pip install strictdoc
# HTML-Export aller Anforderungsdokumente
strictdoc export docs/requirements/ --output-dir out/requirementsDer HTML-Export zeigt:
Alle Anforderungen mit Status und Text
Traceability-Matrix: welche Anforderung hat welche Implementierung
Lücken: Anforderungen ohne Code-Referenz (rot markiert)
Abdeckungsgrad pro Dokument
Lückenanalyse
StrictDoc hebt Anforderungen ohne Implementierungs-Referenz hervor. Das ist der eigentliche Mehrwert: nicht nur dokumentieren was implementiert ist, sondern sehen was noch fehlt.
strictdoc check docs/requirements/
# [ERROR] SW-GPIO-003: no implementation reference foundCI-Integration
In der Drone-Pipeline:
steps:
- name: requirements-check
image: python:3.11-slim
commands:
- pip install strictdoc --quiet
- strictdoc export docs/requirements/
--output-dir out/requirements
--formats=html
- strictdoc check docs/requirements/Ein fehlgeschlagener StrictDoc-Check blockiert den Merge — genau wie ein fehlgeschlagener Unit-Test.
Fazit
Lohnt sich StrictDoc für ein privates Projekt?
Ja, wenn:
man lernen will wie Anforderungsmanagement in der Praxis aussieht
man sehen will wie Code und Anforderungen auseinanderlaufen (sie tun es immer)
man ein Portfolio-Projekt zeigen will das über "ich habe Code geschrieben" hinausgeht
Nein, wenn:
man schnell Ergebnisse will und Dokumentation als Overhead sieht
das Projekt nur wenige Wochen läuft
Für mich ist es die richtige Wahl. Ich arbeite beruflich in einem Umfeld wo Traceability eine regulatorische Anforderung ist — das hier ist mein Übungsfeld um zu verstehen was das wirklich bedeutet, jenseits der Prozessdokumente.
Nächster Post in der Serie: Drone CI mit Podman