04 Requirements Engineering: Von Tests zu Spezifikationen
December 2025 (7097 Words, 40 Minutes)
1. Einleitung: Ihre Tests sind grün, aber was bauen Sie eigentlich?
Wo Sie bisher stehen:
In Kapitel 03 (Testtheorie und Coverage) haben Sie etwas Unangenehmes entdeckt: Als Sie versucht haben, die Testabdeckung für find_intersection() zu verbessern, sind Sie immer wieder auf Fragen gestoßen wie:
- “Was soll passieren, wenn der Strahl vertikal ist?”
- “Ist das Zurückgeben von
Nonefür Segmente hinter der Kamera korrektes Verhalten, oder ein Bug?” - “Wer hat entschieden, dass parallele Linien
t=0verwenden sollen?”
Sie haben erkannt, dass Abdeckungslücken Anforderungslücken offenbaren. Sie können keine guten Tests schreiben, wenn Sie nicht wissen, was die Software tun soll.
Die unbequeme Wahrheit:
In diesem Kurs haben Sie bisher Tests gegen implizite Anforderungen geschrieben - Docstrings, Type Hints, Code-Kommentare und Ihre eigenen Annahmen. Aber echte Softwareprojekte brauchen explizite Anforderungen, auf die sich alle einigen.
Die heutige Frage: Wie erfassen, dokumentieren und validieren wir systematisch, was wir bauen - bevor wir die Tests schreiben?
2. Lernziele
Am Ende dieser Vorlesung werden Sie:
- Verstehen, was Anforderungen sind und warum sie für Softwarequalität wichtig sind
- Funktionale und nicht-funktionale Anforderungen unterscheiden mit konkreten Beispielen
- Stakeholder identifizieren und ihre unterschiedlichen Perspektiven verstehen
- Qualitätskriterien anwenden auf Anforderungen (testbar, messbar, eindeutig)
- Moderne Werkzeuge nutzen für Anforderungen: User Stories, GitHub Issues, Akzeptanzkriterien
- Anforderungen mit Tests verknüpfen für Nachverfolgbarkeit
Fortsetzung in Teil 2:
- Anforderungen im Entwicklungsworkflow
- Anforderungen durch Stakeholder-Interviews ermitteln
- Unterscheidung Bug vs Change Request
- POC-getriebene Anforderungsermittlung
- Vorschau auf Agile-Methodik
Was Sie noch NICHT lernen:
- Formale Spezifikationssprachen (Z, VDM)
- Modellbasierte Anforderungen (SysML, UML Use Cases im Detail)
- Regulatorische Anforderungen (sicherheitskritische Systeme)
- Vollständige Agile-Methodik (Vorlesung 9)
3. Anforderungen auf Code-Ebene: Wo Kapitel 03 aufgehört hat
Bevor wir auf Geschäftsanforderungen eingehen, beginnen wir dort, wo wir aufgehört haben - auf Code-Ebene.
3.1 Implizite Anforderungen im Code
In Kapitel 03 (Testtheorie und Coverage) haben Sie diese impliziten Anforderungen in find_intersection() entdeckt:
def find_intersection(
x_road: NDArray[np.float64], # Implizit: erwartet numpy Array von Floats
y_road: NDArray[np.float64], # Implizit: muss gleiche Länge wie x_road haben
angle_degrees: float, # Implizit: wahrscheinlich 0-360, aber nicht erzwungen
camera_x: float = 0,
camera_y: float = 1.5,
) -> tuple[float | None, float | None, float | None]:
"""
Find the intersection point between the camera ray and the road profile.
Returns:
tuple of (x, y, distance) or (None, None, None) if no intersection
"""
Was fehlt?
- Was passiert, wenn
x_roadundy_roadunterschiedliche Längen haben? - Was ist der gültige Bereich für
angle_degrees? (0-360? -180 bis 180? Jeder Float?) - Was wenn
x_roadleer ist? - Was wenn
x_road-Werte nicht sortiert sind?
3.2 Design by Contract: Anforderungen explizit machen
Design by Contract (DbC) ist eine Programmiermethodik, bei der Sie explizit angeben:
- Vorbedingungen: Was muss VOR dem Funktionsaufruf wahr sein
- Nachbedingungen: Was wird NACH der Funktionsrückgabe wahr sein
- Invarianten: Was bleibt während der Ausführung wahr
Beispiel: Explizite Anforderungen für find_intersection() (der Kommentar-Ansatz)
def find_intersection(
x_road: NDArray[np.float64],
y_road: NDArray[np.float64],
angle_degrees: float,
camera_x: float = 0,
camera_y: float = 1.5,
) -> tuple[float | None, float | None, float | None]:
"""
Find the intersection point between the camera ray and the road profile.
Preconditions (Requirements on input):
- len(x_road) == len(y_road) >= 2
- x_road values are monotonically increasing (sorted left to right)
- angle_degrees is in range [0, 360) degrees
- camera_y > max(y_road) (camera is above the road)
Postconditions (Guarantees on output):
- If intersection exists: returns (x, y, dist) where:
- x is in range [min(x_road), max(x_road)]
- y is the interpolated road height at x
- dist > 0 is the Euclidean distance from camera to intersection
- If no intersection: returns (None, None, None)
Special cases:
- Vertical ray (angle = 90 or 270): returns (None, None, None)
- All road segments behind camera: returns (None, None, None)
- Ray parallel to road segment: uses segment start point
"""
Das ist Requirements Engineering auf Funktionsebene.
Jede Vor- und Nachbedingung ist eine testbare Anforderung. Jeder Spezialfall ist eine Äquivalenzklasse, die Sie in Kapitel 03 (Grundlagen des Testens) gelernt haben.
3.3 Das Problem mit Kommentaren: Sie lügen
Wichtiger Hinweis: Der oben gezeigte Docstring-Ansatz ist nicht, wie wir Design by Contract in modernem Code haben wollen. Wir zeigen es, weil:
- Sie werden diesem Muster in realen Codebasen begegnen, besonders in älteren
- Viele Lehrbücher und Tutorials lehren noch diesen Ansatz
- Das Verstehen seiner Probleme hilft Ihnen, bessere Alternativen zu schätzen
Übernimm dieses Muster nicht für neuen Code. Es gibt bessere Wege, wie wir gleich sehen werden.
Der Docstring-Ansatz oben sieht professionell aus, hat aber ernsthafte Probleme:
Problem 1: Kommentare machen Code schwerer lesbar
Jede Funktion beginnt jetzt mit 20+ Zeilen Dokumentation, bevor Sie echten Code sehen. In einer großen Codebasis wird das überwältigend - Sie schwimmen in Kommentaren, nur um zu verstehen, was der Code tut.
Problem 2: Kommentare veralten
Nichts zwingt den Docstring, mit dem Code synchron zu bleiben. Wenn Sie refaktorisieren oder Features hinzufügen, aktualisieren Sie immer den Docstring? Seien Sie ehrlich. Die meisten Entwickler tun es nicht - und jetzt ist Ihr “Vertrag” eine Lüge.
Problem 3: Kommentare verhindern keine Bugs
Der Docstring sagt len(x_road) == len(y_road), aber was passiert, wenn jemand Arrays unterschiedlicher Länge übergibt? Der Code wird irgendwo mit einem verwirrenden Fehler abstürzen, nicht an dem Punkt, wo der Vertrag verletzt wurde.
3.4 Besserer Ansatz: Das Typsystem Anforderungen durchsetzen lassen
Anstatt Anforderungen in Kommentaren zu dokumentieren, können wir sie durch bessere Datenrepräsentation durchsetzen.
Beispiel: Durchsetzen, dass x_road und y_road gleiche Länge haben
Die aktuelle Signatur erlaubt diesen Bug:
# BUG: Arrays haben unterschiedliche Längen - aber das Typsystem erlaubt es!
find_intersection(
x_road=np.array([0, 10, 20]),
y_road=np.array([0, 5]) # Oops, ein Element fehlt
)
Besseres Design: Verwende ein einzelnes Array von (x, y) Tupeln
import numpy as np
from numpy.typing import NDArray
# Straßenprofil ist ein Nx2 Array, wobei jede Zeile (x, y) ist
# x und y sind inhärent verknüpft - unmöglich, nicht übereinstimmende Längen zu haben!
RoadProfile = NDArray[np.float64] # Shape: (N, 2)
def find_intersection(
road: RoadProfile, # Shape (N, 2) - jede Zeile ist (x, y)
angle_degrees: float,
camera_x: float = 0,
camera_y: float = 1.5,
) -> tuple[float | None, float | None, float | None]:
# Zugriff auf Punkte als road[i, 0] für x und road[i, 1] für y
# Oder entpacken: x, y = road[i]
...
# Verwendung:
road = np.array([
[0.0, 0.0], # Punkt 1: x=0, y=0
[10.0, 5.0], # Punkt 2: x=10, y=5
[20.0, 10.0], # Punkt 3: x=20, y=10
])
Jetzt ist die Anforderung “x und y müssen gleiche Länge haben” unmöglich zu verletzen - jede Zeile enthält beide Koordinaten zusammen.
Beispiel: Gültige Winkelbereiche durchsetzen
Die aktuelle Signatur erlaubt diesen Bug:
# BUG: Was bedeutet angle=500 überhaupt? Ist es 500° oder 140° (500 mod 360)?
find_intersection(x_road, y_road, angle_degrees=500)
Besseres Design: Erstelle eine Angle-Klasse
from dataclasses import dataclass
import math
@dataclass
class Angle:
"""An angle in degrees, normalized to [0, 360)."""
_degrees: float
def __init__(self, degrees: float):
# Normalize to [0, 360) on construction
self._degrees = degrees % 360
@property
def degrees(self) -> float:
return self._degrees
@property
def radians(self) -> float:
return math.radians(self._degrees)
def is_vertical(self) -> bool:
"""Returns True if angle is approximately 90° or 270°."""
return abs(math.cos(self.radians)) < 1e-10
# Jetzt erzwingt die Funktionssignatur gültige Winkel:
def find_intersection(
road: RoadProfile,
angle: Angle, # Immer normalisiert, hat is_vertical() Methode
camera_x: float = 0,
camera_y: float = 1.5,
) -> tuple[float | None, float | None, float | None]:
if angle.is_vertical():
return None, None, None
...
Was hat sich geändert?
Angle(500)wird automatisch zuAngle(140)- die Klasse erzwingt Normalisierung- Die
is_vertical()Methode kapselt die Magic Number1e-10 - Die Anforderung ist jetzt Teil des Typs, nicht ein Kommentar, der ignoriert werden kann
3.5 Laufzeitprüfungen mit Asserts (Selten die richtige Wahl)
Einige Entwickler verwenden assert-Anweisungen, um Anforderungen zur Laufzeit zu prüfen. Sie werden das in manchen Codebasen sehen, also lassen Sie es uns verstehen - aber das ist selten der richtige Ansatz für Produktionscode:
def find_intersection(
x_road: NDArray[np.float64],
y_road: NDArray[np.float64],
angle_degrees: float,
...
) -> tuple[float | None, float | None, float | None]:
# Laufzeit-Anforderungsprüfungen
assert len(x_road) == len(y_road), "x_road and y_road must have same length"
assert len(x_road) >= 2, "Road must have at least 2 points"
assert 0 <= angle_degrees < 360, f"Angle must be in [0, 360), got {angle_degrees}"
# ... eigentliche Implementierung
Vorteile:
- Scheitert schnell mit klarer Fehlermeldung
- Dokumentiert Anforderungen in ausführbarer Form
- Fängt Bugs während der Entwicklung
Nachteile (und diese sind ernst):
- Performance-Overhead: Prüfungen laufen bei jedem Funktionsaufruf
- Kann deaktiviert werden:
python -Oentfernt alle Asserts - Ihr Produktionscode läuft möglicherweise ohne diese Prüfungen! - Crasht in Produktion: Ein
AssertionErrorin Produktion ist oft schlimmer als elegante Behandlung - Ihre Anwendung stirbt einfach - Kein Ersatz für richtige Fehlerbehandlung: Asserts sind für “das sollte nie passieren”-Fälle gedacht, nicht für Eingabevalidierung
- Falsches Sicherheitsgefühl: Entwickler denken “Ich habe Asserts hinzugefügt, ich bin sicher” - aber sie könnten deaktiviert sein
Fazit: Asserts haben einen sehr engen Anwendungsfall - interne Invarianten während Entwicklung und Tests prüfen. Sie sind kein Mechanismus zur Durchsetzung von Anforderungen. Verlassen Sie sich nicht auf sie für Produktionscode. Wenn Sie Eingaben validieren müssen, verwenden Sie richtige Validierung mit sinnvoller Fehlerbehandlung (werfen Sie
ValueErrormit hilfreicher Nachricht, geben Sie ein Fehlerergebnis zurück, etc.).
3.6 Tests als ausführbare Anforderungen
Hier ist eine Schlüsselerkenntnis, die Anforderungen mit Tests verbindet:
Tests können als ausführbare Dokumentation von Anforderungen dienen.
Anstatt:
- Kommentare (können veralten)
- Asserts (können deaktiviert werden, crashen in Produktion)
- Bessere Typen (gut, aber auf strukturelle Einschränkungen beschränkt)
Können wir Tests schreiben, die jede Anforderung explizit verifizieren:
import numpy as np
import pytest
from road_profile_viewer.geometry import find_intersection, Angle
class TestFindIntersectionRequirements:
"""Tests documenting the requirements for find_intersection()."""
def test_req_vertical_ray_returns_none(self):
"""REQ-GEOM-001: Vertical rays shall return None."""
road = np.array([[0, 0], [10, 5]])
result = find_intersection(road, Angle(90), camera_x=5, camera_y=10)
assert result == (None, None, None)
def test_req_intersection_distance_positive(self):
"""REQ-GEOM-002: When intersection exists, distance shall be > 0."""
road = np.array([[0, 0], [10, 5], [20, 10]])
x, y, dist = find_intersection(road, Angle(45), camera_x=0, camera_y=15)
assert dist is not None
assert dist > 0
def test_req_intersection_on_road(self):
"""REQ-GEOM-003: Intersection point shall lie on the road profile."""
road = np.array([[0, 0], [10, 5], [20, 10]])
x, y, dist = find_intersection(road, Angle(45), camera_x=0, camera_y=15)
assert x is not None
assert 0 <= x <= 20 # Within road x-range
Beachte:
- Jeder Test hat eine Anforderungs-ID (REQ-GEOM-001, etc.) - wir lernen in Abschnitt 6, dass gute Anforderungen eindeutige Kennungen haben sollten, und hier sehen Sie warum: es ermöglicht uns, Tests direkt mit Anforderungen zu verknüpfen
- Der Testname beschreibt die Anforderung
- Der Test ist die ausführbare Dokumentation
- Tests können nicht “aus dem Sync geraten” - wenn sich der Code ändert und eine Anforderung bricht, schlägt der Test fehl
Wir werden das weiter in Abschnitt 8: Anforderungen mit Tests verknüpfen erkunden, wo wir sehen werden, wie man:
- Ein systematisches Benennungsschema für Anforderungen definiert
- pytest-Marker verwendet, um Tests mit Anforderungs-IDs zu taggen
- Nachverfolgbarkeitsberichte generiert, die zeigen, welche Anforderungen getestet sind
Aber zuerst, lass uns herauszoomen und verstehen, was Anforderungen auf Geschäftsebene sind.
3.7 Die Brücke: Von Code-Anforderungen zu Geschäftsanforderungen
Beachte, was passiert ist: Wir begannen mit Code-Abdeckungslücken und endeten mit besseren Datentypen und Tests, die Anforderungen verifizieren.
Der gleiche Prozess passiert auf jeder Ebene:
Code-Abdeckungslücke → Funktionsanforderung → Modulanforderung → Systemanforderung → Geschäftsbedarf
Jetzt lass uns herauszoomen und Anforderungen von oben nach unten betrachten.
4. Was sind Anforderungen?
4.1 Definition
Anforderung: Eine Bedingung oder Fähigkeit, die ein Benutzer benötigt, um ein Problem zu lösen oder ein Ziel zu erreichen. — IEEE Standard 610.12
Praktischer ausgedrückt:
Eine Anforderung beschreibt was das System tun soll (oder wie gut es es tun soll), ohne zu spezifizieren wie es implementiert werden soll.
4.2 Funktionale vs Nicht-Funktionale Anforderungen
| Typ | Definition | Beispiel (Road Profile Viewer) |
|---|---|---|
| Funktional | Was das System tut - spezifische Verhaltensweisen und Funktionen | "Das System soll den Schnittpunkt anzeigen, wenn der Benutzer auf das Straßenprofil klickt" |
| Nicht-Funktional | Wie gut das System es tut - Qualitätsattribute | "Die Schnittpunktberechnung soll in weniger als 100ms abgeschlossen sein" |
Kategorien nicht-funktionaler Anforderungen:
- Performance: Geschwindigkeit, Durchsatz, Ressourcennutzung
- Sicherheit: Authentifizierung, Autorisierung, Datenschutz
- Benutzerfreundlichkeit: Lernaufwand, Effizienz der Nutzung
- Zuverlässigkeit: Verfügbarkeit, Fehlertoleranz, Wiederherstellung
- Skalierbarkeit: Umgang mit Wachstum bei Benutzern/Daten
- Wartbarkeit: Einfachheit von Änderungen und Debugging
4.3 Beispiel: Road Profile Viewer Anforderungen
Funktionale Anforderungen:
- FR-1: Das System soll Straßenprofildaten aus CSV-Dateien laden
- FR-2: Das System soll das Straßenprofil als 2D-Liniendiagramm anzeigen
- FR-3: Das System soll den Kamerastrahl basierend auf vom Benutzer angegebenem Winkel berechnen und anzeigen
- FR-4: Das System soll den Schnittpunkt zwischen Strahl und Straße berechnen und hervorheben
- FR-5: Das System soll die Entfernung von Kamera zum Schnittpunkt anzeigen
Nicht-Funktionale Anforderungen:
- NFR-1: Das System soll ein 10.000-Punkte-Straßenprofil in unter 2 Sekunden laden
- NFR-2: Die UI soll innerhalb von 100ms nach Benutzereingabe aktualisieren
- NFR-3: Das System soll auf Python 3.10 oder später laufen
- NFR-4: Die Codebasis soll >80% Testabdeckung aufrechterhalten
4.4 Anforderungs-IDs: Namenskonventionen und ihre Bedeutung
Sie haben vielleicht bemerkt, dass wir hier IDs wie FR-1 und NFR-1 verwenden, aber früher in Abschnitt 3.6 haben wir REQ-GEOM-001 verwendet. Lassen Sie uns das klären.
Warum brauchen Anforderungen IDs?
- Nachverfolgbarkeit: Anforderungen mit Tests, Code und Dokumentation verknüpfen
- Kommunikation: “Lass uns FR-4 besprechen” ist klarer als “dieses Schnittpunkt-Ding”
- Änderungsverfolgung: Wenn sich FR-4 ändert, wissen Sie, welche Tests zu aktualisieren sind
- Abdeckungsanalyse: Welche Anforderungen haben Tests? Welche nicht?
Gängige ID-Benennungsschemata:
| Schema | Beispiel | Wann verwenden |
|---|---|---|
| Typbasiert | FR-1, NFR-2 |
Einfache Projekte, unterscheidet funktional vs nicht-funktional |
| Domänenbasiert | REQ-GEOM-001, REQ-UI-005 |
Größere Projekte mit mehreren Modulen/Komponenten |
| Hierarchisch | REQ-1.2.3 |
Anforderungen, die in Unteranforderungen zerlegt werden |
| Feature-basiert | LOAD-001, CALC-002 |
Organisation nach benutzerorientierten Features |
Beide Schemata beziehen sich auf das gleiche Konzept - es sind nur verschiedene Konventionen. FR-4 und REQ-GEOM-001 identifizieren beide eine spezifische Anforderung, die getestet werden kann.
Impliziert die Nummer Priorität oder Reihenfolge?
Nein! Die Nummer ist nur ein Identifikator, kein Prioritätsranking.
FR-1ist nicht unbedingt wichtiger alsFR-5- Nummern werden typischerweise in der Reihenfolge vergeben, in der Anforderungen geschrieben/entdeckt wurden
- Priorität wird separat verfolgt (wir sehen das in Abschnitt 7 bei User Stories)
Wenn Sie Priorität angeben müssen, fügen Sie sie explizit hinzu:
FR-4 [Priorität: Hoch]: Das System soll den Schnittpunkt berechnen...
FR-5 [Priorität: Niedrig]: Das System soll Ergebnisse nach PDF exportieren...
Oder verwenden Sie ein separates Prioritätsfeld in Ihrem Tracking-System.
4.5 Wo Anforderungen speichern: Formate und Werkzeuge
Anforderungen müssen irgendwo leben. Hier sind die Optionen, von informell bis formal:
Informell (für alles Ernsthafte vermeiden):
- E-Mails, Chat-Nachrichten, Haftnotizen
- Problem: Geht verloren, keine Versionskontrolle, keine Nachverfolgbarkeit
Semi-formal (gut für die meisten Projekte):
- Markdown-Dateien in Ihrem Repository (z.B.
docs/requirements.md)- Versionskontrolliert mit Code
- Einfach zu lesen und bearbeiten
- Kann mit Tests und Code verknüpft werden
- GitHub/GitLab Issues
- In Ihren Entwicklungsworkflow eingebaut
- Verknüpfungen zu PRs und Commits
- Labels zur Kategorisierung (FR, NFR, Priorität)
- Templates für konsistentes Format
- Projektmanagement-Tools (Jira, Linear, Notion, Trello)
- Reichhaltige Tracking-Features
- Integration mit Entwicklungswerkzeugen
- Benutzerdefinierte Felder für Priorität, Status, etc.
Formal (regulierte Branchen, große Projekte):
- IEEE 830 / ISO/IEC/IEEE 29148 Format-Dokumente
- Standardisierte Struktur für Anforderungsspezifikation
- IEEE 830 war der klassische Standard (jetzt durch 29148 ersetzt)
- Erforderlich für manche Verträge/Zertifizierungen
- Hoher Overhead für kleine Projekte
- Requirements Management Tools (IBM DOORS, Jama, Polarion)
- Vollständige Nachverfolgbarkeitsmatrizen
- Änderungsauswirkungsanalyse
- Audit-Trails
- Teuer, komplex
Was sollten Sie verwenden?
Für diesen Kurs und die meisten Softwareprojekte:
- Beginne mit GitHub Issues - ein Issue pro Anforderung oder User Story
- Verwende Labels zur Kategorisierung:
requirement,FR,NFR,priority:high, etc. - Verknüpfen Sie Issues mit PRs - wenn Sie eine Anforderung implementieren, referenzieren Sie das Issue
- Verknüpfe Issues mit Tests - erwähne die Anforderungs-ID in Test-Docstrings
Beispiel GitHub Issue für FR-4:
Title: FR-4: Calculate and highlight intersection point
## Description
The system shall calculate and highlight the intersection point
between the camera ray and the road profile.
## Acceptance Criteria
- [ ] Intersection point is calculated correctly
- [ ] Point is visually highlighted on the chart
- [ ] Coordinates are displayed to the user
## Priority
High - Core functionality
## Related
- Implements: REQ-GEOM-001, REQ-GEOM-002, REQ-GEOM-003
- Tests: test_geometry.py::TestFindIntersectionRequirements
Wir werden diesen Workflow detaillierter in Abschnitt 8: Anforderungen mit Tests verknüpfen erkunden.
5. Stakeholder: Wer kümmert sich um Ihre Software?
5.1 Was ist ein Stakeholder?
Stakeholder: Jede Person oder Organisation, die ein Interesse an dem System hat oder davon betroffen ist.
Verschiedene Stakeholder haben unterschiedliche - manchmal widersprüchliche - Anforderungen.
5.2 Arten von Stakeholdern
graph TD
System[Software System] --- Users
System --- Customers
System --- Dev[Developers]
System --- Ops[Operations]
System --- Business
System --- Reg[Regulators]
Users --> EndUser[End Users]
Users --> Admin[Administrators]
Customers --> Buyer[Purchaser]
Customers --> Sponsor[Project Sponsor]
Dev --> Architect[Architect]
Dev --> Programmer[Programmer]
Dev --> Tester[QA/Tester]
Business --> PM[Product Manager]
Business --> Marketing
Business --> Support
Wichtig: Dieses Diagramm ist nicht vollständig. Die Stakeholder-Rollen für Ihr Projekt hängen vollständig von der Domäne, dem Umfang und dem regulatorischen Umfeld ab.
Stakeholder-Komplexität variiert dramatisch nach Projekttyp:
| Projekttyp | Typische Stakeholder | Warum? |
|---|---|---|
| Medizinprodukte-Software | Endbenutzer, Patienten, Ärzte, Krankenhaus-IT, Klinische Forscher, FDA/Regulierungsbehörden, Qualitätssicherung, Risikomanagement, Cybersicherheitsbeauftragte, Datenschutzbeauftragte, Versicherungen, Rechts-/Compliance | Leben auf dem Spiel → starke Regulierung (FDA, IEC 62304), Audit-Anforderungen, Haftungsbedenken |
| Kurzes Videospiel (Indie) | Spieler, Entwickler, Publisher (falls vorhanden), Plattform (Steam, etc.) | Unterhaltungsfokus, minimale Regulierung, kleinerer Umfang |
| Banking-Anwendung | Kunden, Bankmitarbeiter, Regulierer (BaFin, EZB), Sicherheitsbeauftragte, Betrugserkennung, Compliance-Beauftragte, Prüfer | Finanzregulierung, Sicherheitsanforderungen, Audit-Trails verpflichtend |
Ihre erste Aufgabe in jedem Projekt: Identifizieren Sie wer ein Interesse an Ihrem System hat. Einen Stakeholder zu übersehen bedeutet, seine Anforderungen zu übersehen - was Sie schmerzhaft spät entdecken werden.
5.3 Stakeholder-Matrix: Road Profile Viewer
| Stakeholder | Rolle | Hauptanliegen | Beispielanforderung |
|---|---|---|---|
| Straßeningenieur | Endbenutzer | Genauigkeit, Benutzerfreundlichkeit | "Schnittpunktgenauigkeit innerhalb 0,1m" |
| Laborleiter | Kunde | Kosten, Schulungszeit | "In unter 1 Stunde erlernbar" |
| IT-Administrator | Betrieb | Installation, Wartung | "Einzeldatei-Deployment" |
| Entwickler | Intern | Codequalität, Testbarkeit | "Modulare Architektur für Tests" |
| Sicherheitsbeauftragter | Regulierer | Zuverlässigkeit, Audit-Trail | "Alle Berechnungen protokolliert" |
Schlüsselerkenntnis: Das gleiche Feature sieht für verschiedene Stakeholder unterschiedlich aus. Die “Schnittpunktberechnung” ist:
- Für den Ingenieur: Ein Messwerkzeug
- Für den Manager: Eine Kosten-/Zeitersparnis
- Für den Entwickler: Ein Algorithmus zur Implementierung
- Für QA: Ein zu verifizierendes Verhalten
6. Was macht eine gute Anforderung aus?
Nicht alle Anforderungen sind gleich. Eine schlechte Anforderung führt zu:
- Missverständnissen zwischen Stakeholdern
- Features, die Benutzerbedürfnisse nicht erfüllen
- Tests, die Korrektheit nicht wirklich validieren
- Streitigkeiten darüber, ob die Software “fertig” ist
6.1 Die INVEST-Kriterien (für User Stories)
| Buchstabe | Kriterium | Beschreibung | Schlechtes Beispiel | Gutes Beispiel |
|---|---|---|---|---|
| I | Independent | Kann implementiert werden, ohne von anderen Stories abzuhängen | "Nach Login zeige Dashboard" | "Zeige Dashboard für authentifizierte Benutzer" |
| N | Negotiable | Details können diskutiert werden, nicht in Stein gemeißelt | "Verwende Blau #0000FF für Buttons" | "Buttons sollten visuell hervorstechen" |
| V | Valuable | Liefert Wert für Stakeholder | "Refaktoriere Datenbankschicht" | "Lade Profile 50% schneller" |
| E | Estimable | Team kann Aufwand schätzen | "Mache das System besser" | "Füge PDF-Export hinzu" |
| S | Small | Kann in einem Sprint abgeschlossen werden | "Implementiere alle Berichte" | "Generiere Einzelprofil-Bericht" |
| T | Testable | Klare Kriterien für "fertig" | "System sollte schnell sein" | "Antwortzeit < 200ms" |
6.2 Die Testbarkeits-Verbindung
Erinnern Sie sich an Kapitel 03 (Grundlagen des Testens)-7? Das “Testable”-Kriterium ist, wo Requirements Engineering auf Testing trifft:
Nicht testbare Anforderung:
“Das System sollte benutzerfreundlich sein”
Wie schreiben Sie einen Test dafür? Was assertet der Test? “Benutzerfreundlich” bedeutet für verschiedene Personen verschiedene Dinge.
Testbare Anforderung:
“Das System soll ein Straßenprofil laden und einen Schnittpunkt in unter 2 Sekunden berechnen”
Jetzt können Sie einen Test schreiben:
def test_load_and_calculate_performance():
"""
Performance test: Core workflow completes within time limit.
Requirement: NFR-PERF-001
"""
start_time = time.time()
app.load_profile("sample_road.csv")
app.set_camera_angle(45.0)
result = app.calculate_intersection()
elapsed = time.time() - start_time
assert elapsed < 2.0, f"Workflow took {elapsed:.2f}s, exceeds 2 second limit"
assert result is not None, "Calculation should return a result"
Die Schlüsselerkenntnis: Wenn Sie keinen Test dafür schreiben können, ist es keine gute Anforderung. Vage Anforderungen wie “benutzerfreundlich” müssen in spezifische, messbare Kriterien verfeinert werden, bevor sie nützlich sind.
6.3 Anforderungen und die Test-Pyramide
6.3.1 Welche Art von Test haben wir gerade geschrieben?
Schau zurück auf den Test, den wir oben geschrieben haben:
def test_load_and_calculate_performance():
app.load_profile("sample_road.csv")
app.set_camera_angle(45.0)
result = app.calculate_intersection()
assert elapsed < 2.0
Das ist KEIN Unit-Test! Er testet mehrere Komponenten, die zusammenarbeiten:
- Datei laden (
load_profile) - Zustandsverwaltung (
set_camera_angle) - Berechnung (
calculate_intersection) - Timing über alle Operationen
Erinnern Sie sich an die Test-Pyramide aus Kapitel 03 (Grundlagen des Testens)?
/ \
/ E2E \ ← Wenige, langsam, teuer
/-------\
/ Module \ ← Einige, mittlere Geschwindigkeit ◄── Unser Test ist HIER
/-----------\
/ Unit \ ← Viele, schnell, günstig
/---------------\
Unser Performance-Test ist ein Modul-Test (oder Integrationstest) - er testet Komponenten, die zusammenarbeiten. Das wirft eine Frage auf: Wenn Stakeholder-Anforderungen auf Modul/E2E-Ebene getestet werden, wofür sind dann all diese Unit-Tests?
6.3.2 Warum höherstufige Tests für Stakeholder-Anforderungen?
Die Stakeholder-Anforderung war:
“Das System soll ein Straßenprofil laden und einen Schnittpunkt in unter 2 Sekunden berechnen”
Das ist fundamental eine Systemebenen-Anforderung - sie erstreckt sich über mehrere Komponenten. Sie können das nicht mit einem Unit-Test von find_intersection() allein testen, weil:
- Es Datei-I/O-Zeit einschließt
- Es den vollständigen Workflow einschließt
- Der Stakeholder kümmert sich nicht um
find_intersection()- er kümmert sich um die gesamte Erfahrung
Das ist warum die Test-Pyramide existiert:
- Stakeholder-Anforderungen → Getestet auf Modul/E2E-Ebene
- Aber wir brauchen viel mehr Unit-Tests… wofür?
6.3.3 Die Implementierungslücke: Woher abgeleitete Anforderungen kommen
Bei der Implementierung von FR-CALC-001: "Schnittpunkt berechnen und Ergebnis anzeigen" treffen Entwickler Entscheidungen:
- Datenrepräsentation:
NDArray[(N,2)]oder separatex_road,y_roadverwenden? - Algorithmuswahl: Ray-Casting? Interpolation?
- Edge-Case-Behandlung: Was ist mit vertikalen Strahlen? Kamera unter der Straße?
- API-Design:
Angle-Klasse oder rohe Floats verwenden?
Den Kunden kümmert es nicht, welchen Ansatz Sie wählen - beide können FR-CALC-001 erfüllen.
Aber hier ist der Haken: Diese Entscheidungen hängen oft implizit von Anforderungen ab - besonders nicht-funktionalen. Betrachte:
- Performance (NFR-PERF-001: “< 100ms Antwortzeit”): Ray-Casting mit Early Exit ist schneller als alle Segmente zu prüfen. Diese NFR beeinflusst die Algorithmuswahl.
- Speicher (NFR-MEM-001: “< 50MB Speichernutzung”): Straße als
NDArray[(N,2)]zu speichern ist kompakter als separate Arrays mit Metadaten-Objekten. - Wartbarkeit (NFR-MAINT-001: “Zyklomatische Komplexität < 10 pro Funktion”): Eine
Angle-Klasse mit dedizierteris_vertical()-Methode hält die Komplexität niedrig, auch wenn etwas langsamer.
Die expliziten Anforderungen des Kunden (“Schnittpunkt berechnen”) diktieren diese Entscheidungen nicht, aber ihre impliziten Anforderungen (schnell, speichereffizient, wartbar) tun es.
6.3.3.1 Design Decision Documents (DDDs)
Wenn Sie signifikante Implementierungsentscheidungen treffen, sollten Sie sie dokumentieren. Ein Design Decision Document (oder Architectural Decision Record, ADR) erfasst:
- Kontext: Welches Problem lösen wir?
- Entscheidung: Was haben wir gewählt und warum?
- Konsequenzen: Was sind die Trade-offs?
- Betrachtete Alternativen: Was haben wir sonst evaluiert?
Warum Entscheidungen dokumentieren?
- Ihr zukünftiges Ich wird vergessen, warum Sie Ray-Casting statt Interpolation gewählt haben
- Neue Teammitglieder brauchen Kontext, nicht nur Code
- Anforderungs-Nachverfolgbarkeit: Verknüpft Entscheidungen mit den NFRs, die sie getrieben haben
- Änderungsauswirkung: Wenn NFR-PERF-001 von “< 100ms” zu “< 10ms” wechselt, wissen Sie, welche Entscheidungen zu überprüfen sind
Wo DDDs speichern:
Option 1: GitHub Issues (empfohlen für diskussionsintensive Entscheidungen)
- Eingebaute Kommentare für Teamdiskussion
- Verknüpfung zu PRs, die die Entscheidung implementieren
- Labels zur Kategorisierung (
decision,architecture,algorithm) - Durchsuchbar und in Ihren Workflow integriert
Beispiel GitHub Issue:
Title: DDD-001: Ray-casting algorithm for intersection calculation
## Context
FR-CALC-001 requires calculating intersection between camera ray and road profile.
NFR-PERF-001 requires < 100ms response time.
## Decision
Use ray-casting with early exit when intersection found.
## Rationale
- Benchmarked at 15ms for 10,000-point profiles (meets NFR-PERF-001)
- Early exit optimization reduces average case to O(n/2)
- Well-documented algorithm, easy to test
## Alternatives Considered
- **Interpolation search**: Faster for sorted data but complex edge cases
- **Binary search on segments**: Requires preprocessing, adds complexity
## Consequences
- Vertical rays (90°, 270°) require special handling → REQ-GEOM-001
- Performance degrades linearly with profile size
## Related
- Implements: FR-CALC-001, constrained by NFR-PERF-001
- Derived requirements: REQ-GEOM-001, REQ-GEOM-002
Option 2: Markdown-Dateien im Repository (empfohlen für stabile, genehmigte Entscheidungen)
- Versionskontrolliert neben dem Code
- Review und Diskussion passiert auf dem PR
- Üblicher Ort:
docs/decisions/oderdocs/adr/ - Template: MADR (Markdown Architectural Decision Records)
Praktischer Workflow:
- Öffne ein GitHub Issue, um die Entscheidung mit dem Team zu diskutieren
- Wenn Konsens erreicht ist, erstelle eine Markdown-Datei, um sie zu dokumentieren
- Referenziere das Issue in der Markdown-Datei für die Diskussionshistorie
- Verknüpfe das Entscheidungsdokument vom relevanten Code (Docstrings, Kommentare)
Aber sobald Sie entscheiden, erstellen Sie neue Anforderungen, die Ihr Code erfüllen muss. Diese werden abgeleitete Anforderungen genannt.
6.3.4 Abgeleitete Anforderungen: Die offizielle Definition
Der Begriff “abgeleitete Anforderung” ist in der Industrie standardisiert:
Abgeleitete Anforderung (ISO/IEC/IEEE 29148:2018): “Eine Anforderung, die aus der Sammlung und Organisation von Anforderungen in eine bestimmte Systemhierarchie abgeleitet oder gefolgert wird.”
Der Standard verwendet Eltern/Kind-Terminologie:
- Elternanforderung: Was der Stakeholder angefragt hat
- Abgeleitete (Kind-)Anforderung: Was unsere Implementierung erfüllen muss, um die Elternanforderung zu erfüllen
NASAs Systems Engineering Handbook bietet eine praktische Definition:
“Abgeleitete Anforderungen entstehen aus Einschränkungen, Berücksichtigung von Themen, die impliziert aber nicht explizit in der High-Level-Richtung angegeben sind, oder Faktoren, die durch die gewählte Architektur und das Design eingeführt werden.”
NASA verwendet auch den Begriff selbst-abgeleitete Anforderungen für Anforderungen, die rein aus Designentscheidungen entstehen - genau das, was wir hier diskutieren.
6.3.5 Vollständiges durchgearbeitetes Beispiel: Vom Stakeholder zum Unit-Test
Lass uns die vollständige Kette verfolgen:
Elternanforderung (Stakeholder):
FR-CALC-001: Benutzer soll Schnittpunkt auf Straßenprofil-Diagramm angezeigt sehen
Modul-Test (Testet die Stakeholder-Anforderung):
def test_fr_calc_001_intersection_displayed():
"""
Acceptance test for FR-CALC-001.
Tests the full workflow from user perspective.
"""
app = RoadProfileViewer()
app.load_profile("test_road.csv")
app.set_camera_angle(45.0)
result = app.calculate_and_display()
assert result.intersection_point is not None
assert result.chart_shows_marker == True
Implementierungsentscheidung:
“Wir implementieren
find_intersection()mit Ray-Casting und numpy Arrays. Vertikale Strahlen sind undefiniert und sollen None zurückgeben.”
Abgeleitete Anforderungen (aus dieser Entscheidung):
REQ-GEOM-001: find_intersection() soll (None, None, None) für vertikale Strahlen (90°, 270°) zurückgeben
REQ-GEOM-002: Wenn Schnittpunkt existiert, soll zurückgegebene Entfernung > 0 sein
REQ-GEOM-003: Zurückgegebener Schnittpunkt soll innerhalb des Straßen-x-Bereichs liegen
REQ-GEOM-004: Funktion soll Straßenprofil als NDArray mit Shape (N, 2) akzeptieren
Unit-Tests (Testen die abgeleiteten Anforderungen):
class TestFindIntersectionDerivedRequirements:
"""Unit tests for derived requirements of find_intersection()."""
def test_req_geom_001_vertical_ray(self):
"""REQ-GEOM-001: Vertical rays return None."""
road = np.array([[0, 0], [10, 5]])
result = find_intersection(road, Angle(90), camera_x=5, camera_y=10)
assert result == (None, None, None)
def test_req_geom_002_positive_distance(self):
"""REQ-GEOM-002: Distance is positive when intersection exists."""
road = np.array([[0, 0], [10, 5], [20, 10]])
x, y, dist = find_intersection(road, Angle(45), camera_x=0, camera_y=15)
assert dist is not None and dist > 0
def test_req_geom_003_on_road(self):
"""REQ-GEOM-003: Intersection lies within road bounds."""
road = np.array([[0, 0], [10, 5], [20, 10]])
x, y, dist = find_intersection(road, Angle(45), camera_x=0, camera_y=15)
assert 0 <= x <= 20
Die Nachverfolgungskette:
FR-CALC-001 (Stakeholder)
│
├──► test_fr_calc_001_intersection_displayed() [Modul-Test]
│
└──► find_intersection() [Implementierung]
│
├──► REQ-GEOM-001 ──► test_req_geom_001_vertical_ray() [Unit-Test]
├──► REQ-GEOM-002 ──► test_req_geom_002_positive_distance() [Unit-Test]
└──► REQ-GEOM-003 ──► test_req_geom_003_on_road() [Unit-Test]
6.3.6 Wo abgeleitete Anforderungen dokumentieren?
| Anforderungstyp | Zielgruppe | Wo dokumentieren |
|---|---|---|
| Stakeholder-Anforderungen | Alle | GitHub Issues, User Stories |
| Abgeleitete Anforderungen | Entwickler | Code (Docstrings), Test-Docstrings, interne Docs |
Für diesen Kurs, der pragmatische Ansatz:
- Stakeholder-Anforderungen → GitHub Issues mit FR-/NFR- IDs
- Abgeleitete Anforderungen → Im Code dokumentieren:
- Funktions-Docstrings (Vor- und Nachbedingungen)
- Test-Klassen/Methoden-Docstrings
- Interne REQ-* Kommentare in Tests
Warum NICHT abgeleitete Anforderungen in GitHub Issues?
- Zu low-level für Stakeholder (sie kümmern sich nicht um
Angle(90)) - Ändert sich mit Implementierung (wenn Sie refaktorisieren, ändern sich abgeleitete Anforderungen)
- Überfüllt den Issue-Tracker
6.3.7 Die Test-Pyramide ergibt jetzt Sinn
| Test-Ebene | Was sie testet | Anforderungstyp | Ausführungshäufigkeit |
|---|---|---|---|
| E2E | Vollständige Benutzer-Workflows | Stakeholder (FR-*) | Vor Release |
| Modul | Komponenten-Integration | Stakeholder (FR-*, NFR-*) | Bei PR-Merge |
| Unit | Implementierungskorrektheit | Abgeleitet (REQ-*) | Jeder Commit |
Die Erkenntnis:
- Wir haben wenige Modul/E2E-Tests, weil es relativ wenige Stakeholder-Anforderungen gibt
- Wir haben viele Unit-Tests, weil jede Implementierung viele abgeleitete Anforderungen erzeugt
- Die Pyramidenform entsteht natürlich aus dieser Struktur!
Unit-Tests testen nicht direkt Stakeholder-Anforderungen - sie testen, dass unsere Implementierung dieser Anforderungen korrekt ist. Die Modul/E2E-Tests verifizieren die eigentliche Anforderung.
6.3.8 “Verwaiste” Anforderungen vermeiden
NASAs Software Engineering Handbook warnt vor verwaisten Anforderungen - Code oder Tests, die nicht zu einer Elternanforderung zurückverfolgt werden können.
Anzeichen von Waisen:
- Unit-Tests ohne klaren Zweck (“test_thing_works”)
- Code, der “irgendwann nützlich sein könnte”
- Features, die niemand angefragt hat
Prävention: Jede abgeleitete Anforderung sollte zu einer Stakeholder-Anforderung zurückführen. Wenn Sie nicht erklären können, wie test_vertical_ray_returns_none() hilft, ein Stakeholder-Bedürfnis zu erfüllen, hinterfragen Sie, ob Sie es brauchen.
Bidirektionale Nachverfolgbarkeit bedeutet, Sie können verfolgen:
- Vorwärts: Stakeholder-Anforderung → abgeleitete Anforderungen → Unit-Tests
- Rückwärts: Unit-Test → abgeleitete Anforderung → Stakeholder-Anforderung
Wenn eine Richtung bricht, haben Sie ein Problem.
7. Werkzeuge zur Anforderungsdokumentation
7.1 Das Spektrum der Formalität
Informell Formal
| |
v v
E-Mails → Haftnotizen → User Stories → Use Cases → IEEE 830 → Formale Specs (Z)
(IEEE 830 und sein Nachfolger ISO/IEC/IEEE 29148 definieren standardisierte Formate für Anforderungsspezifikationen - siehe Abschnitt 4.5 für Details)
Die meiste moderne Softwareentwicklung verwendet semi-formale Ansätze: strukturiert genug, um klar zu sein, flexibel genug, um sich zu ändern.
7.2 User Stories
Format:
Als ein [Rolle], möchte ich [Feature], damit [Nutzen].
Beispiel:
Als ein Straßeningenieur möchte ich den Schnittpunkt im Diagramm hervorgehoben sehen, damit ich meine Messungen schnell verifizieren kann.
Warum dieses Format funktioniert:
- Wer: Identifiziert den Stakeholder
- Was: Beschreibt das Bedürfnis (nicht die Lösung)
- Warum: Erklärt den Wert (hilft bei Priorisierung)
7.3 Akzeptanzkriterien: Given-When-Then
Jede User Story braucht Akzeptanzkriterien - spezifische Bedingungen, die erfüllt sein müssen, damit die Story “fertig” ist.
Format (Gherkin-Syntax):
Given [initial context]
When [action occurs]
Then [expected outcome]
Beispiel:
Feature: Intersection Calculation
Scenario: Normal intersection with road
Given a road profile is loaded with points [(0,0), (10,5), (20,10)]
And the camera is at position (0, 15)
When I set the viewing angle to 45 degrees
Then the system should display an intersection point
And the intersection should be between x=0 and x=20
And the distance should be greater than 0
Scenario: Vertical ray (edge case)
Given a road profile is loaded
And the camera is at position (5, 15)
When I set the viewing angle to 90 degrees
Then the system should display "No intersection"
Das ist direkt testbar! Tools wie pytest-bdd können diese als automatisierte Tests ausführen.
7.4 GitHub Issues als Anforderungen
Moderne Entwicklung verwendet oft GitHub Issues, um Anforderungen zu verfolgen:
## User Story
As a road engineer, I want to export my results to PDF so that I can include them in reports.
## Acceptance Criteria
- [ ] Export button visible on main screen
- [ ] PDF includes road profile chart
- [ ] PDF includes intersection coordinates
- [ ] PDF includes calculation parameters
- [ ] File name defaults to "road_profile_YYYY-MM-DD.pdf"
## Technical Notes
- Use `reportlab` library for PDF generation
- Follow existing chart styling
## Links
- Related to #42 (Export feature epic)
- Blocks #45 (Reporting milestone)
Warum GitHub Issues für Anforderungen hervorragend sind
Erinnern Sie sich an die INVEST-Kriterien aus Abschnitt 6? Begriffe wie “Independent”, “Small” und “Valuable” sind inhärent subjektiv. Was ein Entwickler als “klein genug” betrachtet, könnte einem anderen zu groß erscheinen. Was der Product Owner als “wertvoll” betrachtet, stimmt möglicherweise nicht mit Engineering-Prioritäten überein.
Hier glänzen GitHub Issues - sie sind für kollaborative Diskussion gebaut:
- Kommentare: Teammitglieder können debattieren, ob eine Anforderung wirklich “Independent” ist oder versteckte Abhängigkeiten hat
- Reaktionen: Schnelles Feedback (👍 👎 🤔) zu vorgeschlagenen Akzeptanzkriterien
- @mentions: Spezifische Expertise einbeziehen (“@security-team - erfüllt das NFR-SEC-001?”)
- Threads: Separate Diskussionen für verschiedene Aspekte derselben Anforderung
- Historie: Vollständiger Audit-Trail, wie sich die Anforderung durch Diskussion entwickelt hat
Beispieldiskussion zu einem Issue:
@project-manager: Ich denke, das ist klein genug für eine Woche.
@dev-alice: Eigentlich sind allein die PDF-Generierung 3 Tage. Können wir in “einfacher Export” und “gestylter Export” aufteilen?
@dev-bob: Einverstanden. Außerdem, ist das Datumsformat im Dateinamen testbar? Welche Zeitzone?
@project-manager: Gute Punkte. Akzeptanzkriterien aktualisiert, um UTC anzugeben und das Feature aufzuteilen.
Diese kollaborative Verfeinerung ist genau das, was Sie brauchen für subjektive Kriterien - die Anforderung verbessert sich durch Teamdiskussion, und das Gespräch wird für zukünftige Referenz bewahrt.
Zusätzliche Vorteile:
- Mit Code verknüpft (PRs referenzieren Issues)
- In Versionskontrolle verfolgt
- Für alle Teammitglieder sichtbar
- Fortschritt automatisch verfolgt
- Labels zur Kategorisierung (FR, NFR, Priorität, Meilenstein)
- Meilensteine für Release-Planung
8. Anforderungen mit Tests verknüpfen: Nachverfolgbarkeit
8.1 Was ist Nachverfolgbarkeit?
Nachverfolgbarkeit: Die Fähigkeit, Anforderungen → Tests → Code in beide Richtungen zu verknüpfen.
Warum es wichtig ist:
- Vorwärts: Hat jede Anforderung einen Test?
- Rückwärts: Verifiziert jeder Test eine Anforderung?
- Auswirkungsanalyse: Wenn sich eine Anforderung ändert, welche Tests/Code sind betroffen?
8.2 Nachverfolgbarkeit mit pytest implementieren
Marker verwenden, um Tests mit Anforderungen zu verknüpfen:
import pytest
# Define custom markers for requirements
pytestmark = pytest.mark.requirements
@pytest.mark.requirement("FR-4")
def test_intersection_found_for_normal_case():
"""
Requirement FR-4: The system shall calculate and highlight
the intersection point between ray and road.
"""
result = find_intersection(x_road, y_road, angle=45.0, camera_x=0, camera_y=10)
assert result[0] is not None, "Should find intersection"
@pytest.mark.requirement("FR-4")
@pytest.mark.requirement("NFR-2")
def test_intersection_performance():
"""
Requirements:
- FR-4: Calculate intersection
- NFR-2: Complete within 100ms
"""
import time
start = time.time()
result = find_intersection(x_road, y_road, angle=45.0, camera_x=0, camera_y=10)
elapsed = (time.time() - start) * 1000
assert result[0] is not None
assert elapsed < 100, f"Took {elapsed}ms, exceeds 100ms requirement"
8.3 Anforderungsabdeckung vs Code-Abdeckung
Code-Abdeckung (Kapitel 03 (TDD und CI)-7): Haben wir den gesamten Code ausgeführt?
Anforderungsabdeckung: Haben wir alle Anforderungen getestet?
| Metrik | Was sie misst | Einschränkung |
|---|---|---|
| Code-Abdeckung | % der Code-Zeilen/Branches, die von Tests ausgeführt werden | 100% Abdeckung ≠ alle Anforderungen getestet |
| Anforderungsabdeckung | % der Anforderungen mit mindestens einem Test | 100% Abdeckung ≠ Anforderungen korrekt |
Sie brauchen beides:
- Hohe Code-Abdeckung stellt sicher, dass Ihre Tests die Implementierung üben
- Hohe Anforderungsabdeckung stellt sicher, dass Ihre Tests die Spezifikation verifizieren
9. Zusammenfassung
| Konzept | Kernpunkt | Verbindung zu Testing |
|---|---|---|
| Anforderungen | Was das System tun soll (oder wie gut) | Tests verifizieren, dass Anforderungen erfüllt sind |
| Funktional vs Nicht-Funktional | Was es tut vs wie gut es es tut | Verschiedene Testtypen für jeden |
| Stakeholder | Verschiedene Perspektiven, verschiedene Anforderungen | Verschiedene Akzeptanzkriterien |
| INVEST-Kriterien | Gute Anforderungen sind testbar | Testbarkeit ermöglicht Testdesign |
| User Stories | Als ein [Rolle], möchte ich [Feature], damit [Nutzen] | Akzeptanzkriterien = Testfälle |
| Nachverfolgbarkeit | Anforderungen ↔ Tests ↔ Code | Anforderungsabdeckungs-Metrik |
Was wir behandelt haben:
- Anforderungen auf Code-Ebene (Design by Contract, Typsicherheit)
- Was Anforderungen sind (FR vs NFR)
- Wer sich darum kümmert (Stakeholder)
- Was sie gut macht (INVEST, Testbarkeit)
- Wie man sie dokumentiert (User Stories, GitHub Issues)
- Wie man sie mit Tests verknüpft (Nachverfolgbarkeit)
10. Was kommt als Nächstes: Teil 2
In Teil 2 werden wir behandeln:
- Anforderungen im Entwicklungsworkflow - Wasserfall vs iterative Ansätze
- Geschäftsperspektiven - Wie verschiedene Rollen Anforderungen sehen
- Ermittlungstechniken - Wie man Anforderungen durch Interviews entdeckt
- Bug vs Change Request - Eine kritische geschäftliche Unterscheidung
- POC-getriebene Anforderungen - Bauen um zu lernen, einschließlich Gen AI-Ansätze
- Vorschau auf Agile - Warum es als Antwort auf Anforderungsunsicherheit entstanden ist
Weiter zu Teil 2 → Requirements Engineering - Von Prozess zu Praxis