Frau Aydin, die Disponentin bei Brandt Haustechnik, will, dass die Rechnung aus dem Auftragsbuch auch auf der Webseite der Firma erscheint, später auch in einer App für die Monteure. Die Frage an Sie lautet: Wo steht, wie eine Rechnung berechnet wird? Die Antwort aus der Inventur (Lektion M1.3) war unbequem: in der Klasse HauptForm, einem Fenster. Solange das so ist, kann kein anderes Programm die Preise berechnen, ohne ein Fenster mitzuziehen.

Diese Lektion löst die Preisregeln aus dem Formular, in einer Bibliothek ohne Windows-Bezug und mit Tests. Sie ist die erste Naht der Reihenfolge aus Lektion M1.4 (N1), und alles Weitere in diesem Kurs baut darauf auf: Die Web-API, die Blazor-Seiten und die Datenbankzugriffe rufen später diese Bibliothek. Vorausgesetzt ist Modul 2: Das Auftragsbuch läuft als net10.0-windows, und die Charakterisierungstests aus Lektion M2.1 sind Ihr Sicherheitsnetz. Zur Architektur dahinter siehe K4, Modul 4.3 (Ports and Adapters) und 4.10 (Code-Architektur); hier geht es nur um den ersten, kleinen Schnitt.

Fachlogik im Formular erkennen

„Fachlogik“ ist das, was ein Fachbereich als Regel formulieren würde: Mindestens eine Stunde wird berechnet, Wartungsaufträge kosten keine Anfahrt, ein Auftrag muss erledigt sein, bevor man ihn abrechnet. Regeln dieser Art sind im Auftragsbuch an vier Merkmalen zu erkennen:

Merkmal Beispiel im Auftragsbuch Folge
Es rechnet oder entscheidet mit Werten Arbeit, Anfahrt, Netto, Brutto; die Prüfung des Status vor dem Druck Gehört in die Bibliothek
Es kennt Technik der Oberfläche DataRow, MessageBox, ConfigurationManager Bleibt im Formular oder wird als Parameter hereingereicht
Andere rufen es auf Rechnungsdruck und Exporte rufen HauptForm.Netto(...) Das Formular ist zur Bibliothek geworden
Regel und Meldung stehen im selben Satz Der Test auf „noch nicht erledigt“ und der Text der Meldung Regel herauslösen, Text dem Formular lassen

Das dritte Merkmal finden Sie mit einer Suche, die nur liest:

PowerShell
Select-String -Path .\Brandt.Auftragsbuch\*.cs -Pattern 'HauptForm\.(Arbeit|Anfahrt|MaterialMitAufschlag|Netto|Brutto)\(' |
    ForEach-Object { '{0}: {1}' -f $_.Filename, $_.Line.Trim() }
Exporte.cs: decimal netto = HauptForm.Netto(auftrag);
Exporte.cs: decimal brutto = HauptForm.Brutto(auftrag);
Rechnungsdruck.cs: Position(g, normal, rechts, ref y, x, zeile, "Arbeit", HauptForm.Arbeit(_auftrag));
Rechnungsdruck.cs: Position(g, normal, rechts, ref y, x, zeile, "Anfahrt", HauptForm.Anfahrt(_auftrag));
Rechnungsdruck.cs: Position(g, normal, rechts, ref y, x, zeile, "Material", HauptForm.MaterialMitAufschlag(_auftrag));
Rechnungsdruck.cs: Position(g, normal, rechts, ref y, x, zeile, "Netto", HauptForm.Netto(_auftrag));
Rechnungsdruck.cs: Position(g, normal, rechts, ref y, x, zeile, "Brutto", HauptForm.Brutto(_auftrag));

Sieben Aufrufer in zwei Dateien, und beide Dateien haben mit dem Fenster nichts zu tun. Das ist der Beleg: Die Regeln sind längst gemeinsamer Besitz des Programms, sie wohnen nur an der falschen Adresse. Und sie hängen an einer Zeile aus der Datenbank (DataRow) und an Einstellungen, also an Technik, die eine Bibliothek nicht kennen soll.

Die Regeln selbst haben Sie aus Lektion M1.2 vor sich:

  • Arbeit ist das Größere aus Stunden und einer Stunde, mal Stundensatz.
  • Anfahrt ist null bei Wartungsaufträgen, sonst die Anfahrtspauschale.
  • MaterialMitAufschlag ist das Material mal 1,15, auf zwei Stellen gerundet.
  • Netto ist die Summe der drei; Brutto ist Netto mal (1 plus Mehrwertsteuersatz), auf zwei Stellen gerundet.