645 lines
25 KiB
Markdown
645 lines
25 KiB
Markdown
# Implementing for Maintainability
|
|
## Motivation and Introduction
|
|
|
|
- Unit und Integration Testing ist ein bekannter Ansatz um Qualität sicherzustellen
|
|
- Gut-getestete Anwendungen:
|
|
- 1 line of code = 1-3 lines of test code
|
|
- kann auf bis zu 1:10 hochgehen
|
|
- Produkt- und Testcode werden parallel geschrieben
|
|
- guten Code schreiben ist schwer
|
|
|
|
## Black-/White-Box Testing
|
|

|
|
### Black-Box-Testing
|
|
> Nur das Interface ist bekannt, nicht der Inhalt
|
|
|
|
- Methode vom Software-Testing, das die Funktion analysiert, ohne den Mechanismus zu kennen
|
|
- Normalerweise rund um die Spezifikationen und Anforderungen
|
|
- _Was soll die Anwendung tun, nicht wie tut sie es_
|
|
|
|
### White-Box-Testing
|
|
> Das Interface und alle Mechanismen sind bekannt
|
|
- Testmethodik, die verifiziert, wie die Anwendung arbeitet
|
|
- Tests sind am Sourcecode ausgerichtet, nicht an den Anforderungen
|
|
|
|
### Pros / Cons
|
|
- [White-Box-Testing](01_ImplementingForMaintainability.md#white-box-testing) ist systematischer und anspruchsvoller
|
|
- Analyse des Codes kann zu Fehlerentdeckungen führen, die zuvor übersehen wurden
|
|
- Testergebnisse sind oft spröde
|
|
- Sind sehr verknüpft mit der Implementierung des Codes
|
|
- Solche Tests produzieren viele false-positives und sind nicht gut für die Metrik der Resistenz gegen Refactoring
|
|
- Können häufig nicht rückgeschlossen werden zu einem Verhalten, dass wichtig ist für eine Business-Person
|
|
- Starkes Zeichen, dass die Tests nicht viel Wert hinzufügen
|
|
- [Black-Box-Testing](01_ImplementingForMaintainability.md#black-box-testing) hat gegensätzliche Vor-/Nachteile
|
|
|
|
> Black-/White-Box-Testing sind Konzepte, die auf verschiedene Test-Typen angewendet werden können
|
|
|
|
|
|
## Testing Quadrants Matrix
|
|

|
|
|
|
### Quadrant 1: Technologie-fokussierte Tests, die das Development leiten
|
|
- Developer Tests:
|
|
- Unit tests
|
|
- Verifizieren Funktionalität eines kleinen Subsets des Systems
|
|
- Unit Tests sind die essenzielle Basis einer guten Test-Suite
|
|
- Verglichen mit anderen, sind sie einfach zu erstellen und warten
|
|
- Viele Unit-Tests :)
|
|
- Component-/Integration Tests:
|
|
- Verifizieren Verhalten eines größeren Teils
|
|
|
|
- Tests sind nicht für den Kunden
|
|
|
|
|
|
|
|
## Goals of Testing during Implementation
|
|
### Aktiviere nachhaltiges Wachstum des Software-Projekts
|
|
- 
|
|
- Nachhaltigkeit ist wichtig
|
|
- Projektwachstum ist am Anfang einfach
|
|
- Das Wachstum zu halten ist schwer
|
|
- Tests können das nachhaltige Wachstum fördern
|
|
- Aber: erfordern initialen, teilweise signifikanten Einsatz
|
|
- Schlechte Tests bringen nichts
|
|
- verlangsamen am Anfang schlechten Code
|
|
- langfristig trotzdem ungünstig
|
|
- Test Code ist Teil der Codebase
|
|
- Teil, der ein spezifisches Problem behandelt - Anwendungsrichtigkeit sicherstellen
|
|
- Kosten eines Tests
|
|
- Wert
|
|
- anstehende Kosten
|
|
- _Refactoring des Tests, wenn der Code refactored wird_
|
|
- _Test bei jeder Codeänderung ausführen_
|
|
- _Mit Fehlalarmen durch den Test umgehen_
|
|
- _Zeit für das Verstehen des Tests, wenn man den zu testenden Code verstehen möchte_
|
|
|
|
### General Testing Strategy
|
|
#### Testing Automation Pyramid
|
|

|
|
- Software Tests in 3 Kategorien aufteilen
|
|
- **UI-Tests**
|
|
- Testen die Anwendung durch Interaktion mit der UI
|
|
- sehr high-level
|
|
- **Service Tests**
|
|
- [Black-Box](#black-box-testing) testen von größeren Softwareteilen
|
|
- _bspw. Komponenten, Services_
|
|
- **Unit Tests**
|
|
- werden während Entwicklung von Developern geschrieben
|
|
- Gibt Idee, wie viele Tests pro Kategorie in der Test-Suite sein sollten
|
|
|
|
#### Testing Ice Cream Cone
|
|

|
|
- Style einer Test-Suite, die häufig in der Industrie verwendet wird
|
|
- hohe Anzahl manueller, high-level Tests
|
|
- end-to-end Tests (auch an UI), die automatisch ausgeführt werden können
|
|
- nur wenige integration/unit tests
|
|
- Tests Suite mit dieser Strategie ist nicht gut wartbar
|
|
- manuelle Tests sind teuer und langwierig
|
|
- automatisierte high-level Tests gehen häufig kaputt, sobald Änderungen in der Anwendung auftreten
|
|
|
|
|
|
|
|
### Test Driven Development (TDD)
|
|

|
|
1. Tests schreiben
|
|
- **Design**
|
|
- Akzeptanzkriterien für den nächsten Arbeitsschritt festlegen
|
|
- Anregung [lose gekoppelte Komponenten](ImplementingForMaintainability.md#loose-coupling) zu entwerfen
|
|
- einfache Testbarkeit, dann verbinden
|
|
- Ausführbare Beschreibung von dem was der Code tut
|
|
- **Implementierung**
|
|
- Vervollständigen einer regressiven Test-Suite
|
|
2. Tests ausführen
|
|
- **Implementierung**
|
|
- Error erkennen, während der Kontext noch frisch ist
|
|
- **Design**
|
|
- Bewusstmachung, wann die Implementierung vollständig ist
|
|
|
|
> Golden Rule of TDD: schreibe niemals neue Funktionalitäten ohne einen fehlschlagenden Test
|
|
|
|
#### Vorteile des TDD
|
|
- signifikante Reduktion der Defekt-Rate
|
|
- auf Kosten eines moderaten Anstiegs im initialen Development-Prozesses
|
|
- Empirische Untersuchungen haben das noch nicht bestätigt
|
|
- TDD hat aber zu Qualitätssteigerung des Codes geführt
|
|
|
|
#### Häufige Fehler beim TDD
|
|
- Individuelle Fehler
|
|
- _Vergessen die Tests regelmäßig auszuführen_
|
|
- _Zu viele Tests auf einmal schreiben_
|
|
- _Zu große/grobe Tests schreiben_
|
|
- _zu triviale Tests schreiben, die eh funktionieren_
|
|
- Team-Fehler
|
|
- _Nur partieller Einsatz_
|
|
- _Schlechte Wartung der Test-Suite_
|
|
- _Verlassene Test-Suite (nie ausgeführt)_
|
|
|
|
## Unit-Testing vs. Integration Testing
|
|
| Unit | Integration |
|
|
|-------------------------------|----------------------|
|
|
| kleiner Teil eines Verhaltens | größere Portion Code |
|
|
|
|

|
|
|
|
### 4 Typen von Produktions-Code
|
|

|
|
|
|
#### Dimensionen
|
|
##### Komplexität und Domain-Signifikanz
|
|
- Code Komplexität
|
|
- Definiert durch Nummer der Branching-Punkte im Code
|
|
- _if-statements, Polymorphismus_
|
|
- Domain-Signifikanz
|
|
- Wie signifikant ist der Code für die problematische Domain
|
|
- normalerweise Verbindung Domain-Layer-Code zu End-User-Ziele
|
|
- Hohe Domain-Signifikanz
|
|
- _Bsp. für niedrige Relevanz: Utility Code_
|
|
|
|
##### Nummer der Kollaborateure
|
|
- Kollaborateur = Abhängigkeit, die veränderlich /& außerhalb des Prozesses ist
|
|
- veränderlich
|
|
- nicht nur read-only
|
|
- außerhalb des Prozesses
|
|
- häufig geteilt
|
|
- hindert Tests an unabhängiger Ausführung
|
|
- Code mit vielen Kollaborateuren ist schwer zu testen
|
|
|
|
|
|
#### Typen
|
|
##### Domain model & algorithms
|
|
- **Domain Code, wenige Kollaborateure**
|
|
- komplexer Code häufig Teil des Domain-Models
|
|
- wenige Kollaborateure → Testbarkeit
|
|
- sollte NIEMALS Abhängigkeiten außerhalb des Prozesses haben
|
|
##### Controllers
|
|
- **Wenig Domain Code, viele Kollaborateure**
|
|
- Koordination der Ausführung von Use-Cases für Domain-Klassen und externen Anwendungen
|
|
- Keine komplexe / Business-kritische Arbeit selbst/allein machen
|
|
- wenig Komplexität, wenig Domain-Signifikanz
|
|
- Viele Abhängigkeiten außerhalb des Projekts
|
|
##### Overcomplicated Code
|
|
- **Viel Domain Code, viele Kollaborateure**
|
|
- ist aber auch komplex und wichtig
|
|
##### Trivialer Code
|
|
- **wenig Domain-Code, wenig Kollaborateure**
|
|
|
|
#### Separierung von Controllers & DomainModel, Algorithmen
|
|

|
|
- Separiert komplexen Code von Code, der Orchestrierung macht
|
|
- Domain Code hat tiefe Implementierung in Business Logik
|
|
- Controller haben breite Orchestrierung aber enge Komplexität
|
|
- Erhöht Wartbarkeit und Testbarkeit
|
|
|
|
#### Wie testet man die 4 Typen?
|
|

|
|
- trivialer Code muss nicht getestet werden
|
|
|
|
|
|
## Unit Testing
|
|
- Beim Unit Testing gehts nicht nur um den technischen Aspekt
|
|
- möglichst wenig Zeit Input
|
|
- möglichst viel Benefits
|
|
|
|
### Gute Test-Suite
|
|
1. integriert in [SDLC](00_Introduction.md#software-development-lifecycle-sdlc)
|
|
- Tests bringen nur was, wenn man sie ständig benutzt
|
|
- am besten alle automatisiert bei jeder Änderung
|
|
2. testet nur die wichtigsten Teile der Code-Base
|
|
- Business-Logik
|
|
- Systemkritische Teile
|
|
- auch Abhängigkeiten nach außen
|
|
- Rest nur indirekt / wenig testen
|
|
3. gibt maximalen Wert mit minimalem Wartungsaufwand
|
|
- Auch automatisierte Tests müssen ggf. nach Änderungen angepasst werden
|
|
- Nur Tests behalten, die wirklich sinnvoll sind
|
|
|
|
### Was ist ein Unit-Test
|
|
> 1. Verifiziert einen kleinen Teil des Codes (unit)
|
|
>
|
|
> 2. macht es schnell
|
|
>
|
|
> 3. macht es isoliert
|
|
|
|
#### London School Interpretation
|
|
- Isolation bedeutet, dass jede Klasse ihren eigenen Test bekommt
|
|
- Auch wenn sie von gleicher Klasse erben
|
|
|
|
##### Testing Doubles
|
|

|
|
- Objekt, dass gleiches Verhalten und Aussehen, wie Gegenstück hat
|
|
- Vereinfachte Version, die Komplexität verringert
|
|
|
|
##### Vorteile London School Interpretation
|
|
- Wenn ein Test fehlschlägt, ist klar, was kaputt ist
|
|
- Gibt Fähigkeit den Objektgraphen aufzusplitten
|
|
- Jede Klasse hat ihre eigenen Abhängigkeiten / Vererbungen
|
|
- Schwer zu testen ohne [Testing Doubles](#testing-doubles)
|
|
- Es müssen nicht die Abhängigkeiten von Abhängigkeiten beachtet werden
|
|
- haben ja eigene Tests
|
|
- Projektweite Guideline:
|
|
- Nur eine Klasse auf einmal
|
|
- 
|
|
|
|
|
|
#### Classic School Interpretation
|
|
- Isolation bedeutet, dass jeder Test in Isolation läuft
|
|
- Mehrere Klassen auf einmal ist okay
|
|
- Solange sie alle auf ihrem eigenen Speicher laufen
|
|
- kein geteilter Zustand
|
|
- Verhindert Kommunikation /Beeinflussung zwischen Tests
|
|
- Scheiß auf Reihenfolge oder Ergebnis von anderen Tests
|
|
##### Geteilte, private, Out-Of-Process Abhängigkeiten
|
|
- Geteilte Abhängigkeiten
|
|
- Können sich gegenseitig beeinflussen
|
|
- Müssen ersetzt werden
|
|
- _bspw. geteilte DB → neue/bearbeitete Daten können Tests beeinflussen_
|
|
- Private Abhängigkeiten → :)
|
|
- Out-Of-Process Abhängigkeiten
|
|
- Meistens ähnlich wie geteilte Abh.
|
|
- _DB = geteilt und out-of-process_
|
|
- _read-only-DB ist fine_
|
|
- also: kommt drauf an ob gut oder nicht
|
|

|
|
|
|
#### Beispiel Classic School
|
|

|
|
- _Enough inventory → purchase geht durch, inventory amount geht runter_
|
|
- _not enough product → kein purchase, keine änderungen_
|
|
|
|
- Typische AAA-Sequenz
|
|
- arrange, act, assert
|
|
- alle Abhängigkeiten und System vorbereiten
|
|
- Verhalten ausführen, das verifiziert werden soll
|
|
- Erwartete Ergebnisse überprüfen
|
|
|
|
- Outcome:
|
|
- `Customer` und `Store` werden verifiziert, nicht nur `Store`
|
|
- Jeder Bug in `Store` lässt die Tests fehlschlagen
|
|
- auch wenn `Customer` komplett richtig ist
|
|
|
|
#### Beispiel London School
|
|

|
|
|
|
- Gleiche Tests, aber Store wird mit test-doubles ersetzt
|
|
- "fake dependency" = "Mock"
|
|
|
|
- AAA Sequenz {id="aaa-sequenz"}
|
|
- Arrange:
|
|
- Store nicht modifizieren, stattdessen festlegen, wie er auf `hasEnoughInventory()` reagieren soll
|
|
- Act
|
|
- Assert
|
|
- Interaktion zwischen `Store` und `Customer` wird genauer untersucht
|
|
|
|
#### Vergleich Classic / London
|
|
| | Isolation of | A unit is | Uses test doubles for |
|
|
|----------------|--------------|-----------------------------|--------------------------------|
|
|
| London School | Units | A class | All but immutable dependencies |
|
|
| Classic School | Unit tests | A class or a set of classes | shared dependencies |
|
|
|
|

|
|
|
|
### Unit Tests - Good Practices
|
|
#### Good Practices - Structuring
|
|

|
|
- Offensichtliche Struktur ist wichtig
|
|
- Code wird häufiger gelesen als geschrieben
|
|
- AAA-Pattern splittet Tests in 3 Teile
|
|
- Alternative: Give-When-Then Pattern
|
|
- Einziger Unterschied: besser lesbar für nicht-Programmierer
|
|
|
|
##### Zu vermeidende Dinge
|
|
- Manchmal benutzt ein Test **mehrere AAA Steps**
|
|
- bspw: 
|
|
- ist kein Unit-Test mehr, sondern ein [Integration-Test](#unit-testing-vs-integration-testing)
|
|
- **if-statements**
|
|
- wird schwerer lesbar
|
|
- sollte eine simple Sequenz ohne branches sein
|
|
|
|
##### Größe der [AAA](#aaa-sequenz) Sections
|
|
- **arrange**
|
|
- meistens am größten
|
|
- falls deutlich größer als act und assert zusammen
|
|
- extrahieren in neue Methode oder separate [Factory-Klasse](DesignPatterns.md#factory-method-virtual-constructor)
|
|
- **act**
|
|
- sollte nicht mehr als eine Zeile sein
|
|
- **assert**
|
|
- kann mehrere Asserts beinhalten
|
|
- eine unit kann ja auch mehrere Dinge verändern, die überprüft werden müssen
|
|
- zu viele asserts implizieren schlechten Production-Code
|
|
- _fehlende Abstraktion bspw._
|
|
- **teardown-Phase** (_alles wieder auf den alten Stand bringen_)
|
|
- die meisten unit-Tests brauchen keine
|
|
- ist meistens durch ein anderes Modell gelöst
|
|
- bspw. Mocks oder so
|
|
|
|
#### Good Practices - Naming Tests
|
|
- aussagekräftige Namen
|
|
- häufig aber schlecht:
|
|
- [MethodeDieGetestetWird]_[Szenario]_[ErwartetesErgebnis]
|
|
- Name in plain Englisch besser lesbar
|
|
- Beispiel
|
|
- _Sum_TwoNumbers_ReturnsSum()_ :(
|
|
- _Sum_of_two_numbers()_ :)
|
|
|
|
**Guideline**
|
|
- Keiner starken Benennungspolicy folgen
|
|
- Benenne die Tests als würdest du es einem nicht-Programmierer-Deppen erklären, der aber die Anwendung kennt
|
|
- Separiere Wörter, sodass sie lesbar sind
|
|
- bspw. durch `-`, `_`, `testTest`
|
|
|
|
#### Good Practices - Parameterized Tests
|
|
**Motivation:**
|
|
- Ein Test ist meistens nicht genug um eine Verhaltens-Unit zu beschreiben
|
|
- hat div. Komponenten
|
|
- Beispiel:
|
|
- Online-Store mit Lieferfunktion
|
|
- constraint: frühstes Lieferdatum ist übermorgen
|
|
- ```
|
|
public void Delivery_with_a_past_date_is_invalid()
|
|
public void Delivery_for_today_is_invalid()
|
|
public void Delivery_for_tomorrow_is_invalid()
|
|
public void The_soonest_delivery_date_is_two_days_from_now()
|
|
```
|
|
- das viel zu viel
|
|
- wenn man das mal auf größere Probleme anwendet wirds nicht besser
|
|
|
|
**Parametrisierte Tests:** {id="parametrized-tests"}
|
|
- gruppieren Tests
|
|
- meiste xUnit Frameworks haben Funktion dafür
|
|
- Beispiel in .NET:
|
|
- 
|
|
- Also:
|
|
- weniger Test-Code
|
|
- Aber:
|
|
- schwerer herauszufinden, welche Fakten die Methode repräsentiert
|
|
- je mehr Parameter, desto schwieriger
|
|
|
|
|
|
## Integration Testing
|
|
- Verifiziert größeren Teil des Systems (mehrere Units)
|
|
- aus dem [Controllers-Quadranten](#4-typen-von-produktions-code)
|
|
- braucht evtl. länger als ein Unit-Test
|
|
- ist evtl. abhängig von anderen Tests (keine Isolation)
|
|
|
|
- Balance zwischen Unit- und Integration-Tests ist wichtig
|
|
- direktes Arbeiten mit out-of-process-Abhängigkeiten macht Integration Tests langsam
|
|
- sind teuer zu warten
|
|
- dafür besserer Schutz gegen Zurückentwicklungen
|
|
- Integration-Tests für den längsten Happy-Path mit den meisten Abhängigkeiten
|
|
- Eck-Szenarien des Business-Szenarios mit Unit-Tests
|
|
|
|
- Out-of-Process Abhängigkeiten
|
|
- **Managed** (_Abhängigkeiten über die wir volle Kontrolle haben_)
|
|
- nur Zugriff über die Applikation
|
|
- Interaktionen sind für die externe Welt nicht sichtbar
|
|
- **nicht mocken**
|
|
- wir wollen, dass die tests fehlschlagen, wenn wir was an der DB ändern bspw.
|
|
- **Unmanaged** (_Abhängigkeiten über die wir keine Kontrolle haben_)
|
|
- **mocken**
|
|
- wir wollen volle Kontrolle über die Tests
|
|
|
|
### Integration Testing - Example
|
|
**Customer Management System**
|
|

|
|
- alle User sind in einer DB
|
|
- Änderungen werden an angeschlossene Anwendungen über Message-Bus geschickt
|
|
- Business-Rules
|
|
- Falls Email zur Company-Domain gehört → Employer Status, sonst Customer
|
|
- System muss Anzahl der Employer tracken (auch beim Wechseln)
|
|
- Wenn Mail wechselt müssen externe Systeme über MessageBus benachrichtigt werden
|
|
|
|

|
|
|
|
- **Domain model, Algorithms**
|
|
- Company
|
|
- Attribute: `DomainName` `NumberOfEpmoyees`
|
|
- Methoden: `ChangeNumberOfEmployees(...)` `IsEmailCorporate(...)`
|
|
- CompanyFactory
|
|
- Erstellt `Company`-Objekte anhand von DB-Feldern
|
|
- User
|
|
- Attribute: `UserId` `Email` `UserType` `EmailChangedEvents[]`
|
|
- Methoden: `ChangeEmail(...)`
|
|
- UserFactory
|
|
- Erstellt `User`-Objekte anhand von DB-Feldern
|
|
- **Controllers**
|
|
- UserController
|
|
- Delegiert die Ausführung von Email-Änderungen
|
|
- Logik ist gekapselt in den Domain-Klassen
|
|
- Managed Kommunikation mit out-of-process-Abhängigkeiten
|
|
- hier: DB und messageBus
|
|
|
|
- **Integration Test für den längsten Happy-Path**
|
|
- geht durch alle Abhängigkeiten
|
|
- _hier: corporate → non-corporate Mail_
|
|
- davor: out-of-process-Abhängigkeiten Kategorisieren
|
|
- was direkt testen, was mocken?
|
|
- _hier: DB ist managed → direkt testen_
|
|
- _hier: messageBus ist unmanaged → mocken_
|
|
- _[OCP](DesignPrinciples.md#o-open-closed-principle-ocp) anwenden durch ein Interface_
|
|
- 
|
|
- **Edge-cases mit Unit-Tests**
|
|
|
|

|
|
|
|
### Integration Testing - Good Practices
|
|
- Immer einen festen Platz für das [Domain-Model](#domain-model-algorithms) in der Code-Base haben
|
|
- unit-tests dafür, integration-tests für Controller
|
|
- Abgrenzung kann unterschiedlich vorgenommen werden
|
|
- package, namespace, assembly, ...
|
|
- Möglichst wenig Layer in der Anwendung
|
|
- Abstraktionen und Generalisierungen → mehr Layer
|
|
- wird schwer den Code nachzuvollziehen
|
|
- 
|
|
- 
|
|
- Dopplungen im [AAA](#aaa-sequenz)-Schema
|
|
- teilweise verlockend
|
|
- 
|
|
- Falls einer nicht funktioniert geht der andere nicht
|
|
- Ausnahme:
|
|
- out-of-process-Abhängigkeit, die nur schwer in den gewünschten Zustand kommt
|
|
|
|
## Test Coverage
|
|
> Test-Abdeckung wird häufig genutzt, um die Qualität einer Test-Suite zu beurteilen
|
|
|
|
> Niedrige Coverage zeigt, dass die Test-Suite nicht ausreichend ist.
|
|
>
|
|
> Hohe Coverage bedeutet nicht, dass die Test-Suite gut ist
|
|
|
|
### Code Coverage
|
|
- Anteil der Code-Zeilen, die durch die Tests ausgeführt werden
|
|
- Beispiel:
|
|
- 
|
|
- 80% Coverage
|
|
- 
|
|
- 100% Coverage
|
|
- nicht besser als der Test oben, der True outcome wird ja trotzdem nicht überprüft
|
|
|
|
### Branch Coverage
|
|
- Anteil der Code-Branches die durch die Tests ausgeführt werden
|
|
- Beispiel:
|
|
- 
|
|
- 1 / 2 Branches gecovered → 50% Coverage
|
|
- **Gibt meist wertvollere Ergebnisse als Code-Coverage**
|
|
|
|
### Probleme mit Coverage-Metriken
|
|
- Keine Garantie, dass der Test alle möglichen Ausgänge überprüft
|
|
- um die Garantie zu haben:
|
|
- Alle Codepfäde müssen getestet werden
|
|
- Asserts müssen da sein
|
|
- 
|
|
- führt zwar alles aus, überprüft aber nicht ob es richtig ist, weil nix asseert
|
|
- ein System kann teilweise mehrere Outcomes haben
|
|
- Alle müssen getestet werden
|
|
- Keine Coverage-Metrik kann Code in externen Libraries abbilden
|
|
- Externe Bibliotheken
|
|
- 
|
|
- Test-Coverage ist bei 100%
|
|
- Es sind aber trotzdem nicht alle möglichen Outcomes abgedeckt
|
|
- bspw. wenn die Zahl zu groß ist, keine da ist, ...
|
|
- **Coverage-Metriken sind nur Indikatoren, nix tatsächlich final festlegendes**
|
|
|
|
## Rubber Duck Debugging
|
|
> Wenn verzweifelt → Den Fehler einer Gummiente erklären
|
|
|
|
- Wenn man versucht jemandem das Problem zu erklären ist man gezwingen
|
|
- Das Problem von einer anderen Perspektive anzusehen
|
|
- Dadurch ein tieferes Verständnis vom Problem zu bekommen
|
|
- einfacher eine Lösung zu finden
|
|
|
|

|
|
|
|
|
|
## Pair Programming
|
|
- Zu zweit auf einer Maschine Code schreiben
|
|
- gleichzeitig auch Arbeit planen und diskutieren
|
|
- Idee dahinter:
|
|
- zwei Gehirne und vier Augen sind besser als ein Gehirn und 2 Augen
|
|
- Teams haben ausprobiert und festgestellt
|
|
- geht schneller, da man fokussierter bleibt
|
|
- höhere Code-Qualität
|
|
|
|
### Pairing Styles
|
|
#### Pairing Style: Driver and Navigator
|
|
- **Fahrer**
|
|
- Person an der Tastatur
|
|
- ist fokussiert das nächste kleine Ziel zu erreichen
|
|
- ignoriert größere Probleme
|
|
- sollte die ganze Zeit mitreden, was er tut
|
|
- **Navigator** (_hoffentlich ohne link rechts Schwäche_)
|
|
- ist in der überwachenden Position, während der Fahrer tippt
|
|
- Reviewed den Code durchgängig
|
|
- direktes Feedback
|
|
- Hat auch größere Probleme, Bugs im Kopf
|
|
- Notizen für mögliche nächste Schritte
|
|
- **Möglicher Arbeitsablauf:**
|
|
- 
|
|
|
|
#### Pairing Style - PingPong
|
|
- Perfekt für einen TDD-Task
|
|
- **Ping**
|
|
- Dev A schreibt einen fehlschlagenden Test
|
|
- **Pong**
|
|
- Dev B schreibt Implementierung damit er klappt
|
|
- **Ping**
|
|
- Dev B schreibt den nächsten Test
|
|
- Bei jedem Pong kann man auch nochmal refactoren
|
|
|
|
#### Pairing Style - Strong-Style Pairing
|
|
- Super für Wissenstransfer
|
|
- Regel: "Jede Idee, die von deinem Kopf in den Computer soll, muss durch die Hände von jemand anderem gehen"
|
|
- **Navigator**
|
|
- erfahrene Person
|
|
- **Fahrer**
|
|
- Person die was lernen will/soll
|
|
- sollte dem Navigator voll vertrauen
|
|
- Warum?-Fragen und Challenges nach dem Implementieren besprechen
|
|
|
|
#### Pairing Style - Research and Explore
|
|
- Überlegen und herausfinden ist häufig notwendig
|
|
- bspw. bei neuen Technologien etc.
|
|
- Wie kann man das im Pair-Modus angehen
|
|
- Liste mit Fragen für eine mögliche Situation machen
|
|
- Aufsplitten für einzelne Zeitslots
|
|
- entweder Fragen aufteilen oder gleichzeitig Antworten auf gleiche suchen
|
|
- Zusammenkommen und diskutieren/teilen was man gefunden hat
|
|
|
|
#### Pairing Style - Documentation
|
|
- Je nach Situation und Präferenz
|
|
- Dokumentation zusammen machen
|
|
- Einer schreibt, anderer macht Anmerkungen
|
|
|
|
### Benefits / Challenges
|
|
|
|
| Vorteile | Herausforderungen |
|
|
|--------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------------------|
|
|
| Wissensaustausch | Kann anstrengend sein |
|
|
| Reflektion: hat mans wirklich (richtig) verstanden? | Verschiedene Skill Levels: Können zu falschen Erwartungen und Frustration führen |
|
|
| Fokus behalten: Zusammen arbeitet man strukturierter, keine "schnellen" side-quests | Power-Dynamics: Chef-Mitarbeiter → kann das ganze schwierig machen |
|
|
| Code Review on-the-go: | Pairing erfordert Verletzlichkeit: ist schwer zu sagen, dass man etwas nicht weiß/kann - aber notwendig |
|
|
| Zwei Denk-Modi kombiniert: verschiedene Perspektiven haben | Chef überzeugen, dass es gut ist |
|
|
| Gemeinsames Code-Ownership: Höhere Chance, dass jemand sich traut Änderungen vorzuschlagen | |
|
|
| Schnelles Onboarding |  |
|
|
|  |  |
|
|
|
|
|
|
## Static Code Analysis
|
|
- Code analysieren, ohne ihn auszuführen
|
|
- Tools inspizieren das Programm für ...
|
|
- alle möglichen Verhalten
|
|
- suchen Coding-Fehler, Back-Doors, ...
|
|
- generieren Metriken für den Code die helfen die Qualität zu analysieren
|
|
- Kann Qualität verbessern
|
|
|
|
### Beispiele für die Identifikation von Bekannten Problemen und Bad Practices
|
|
- **Generische Beispiele**
|
|
- Größe
|
|
- Kann verschieden gemessen werden
|
|
- _Code-Zeilen, Klassen, Dateien, Funktionen, ..._
|
|
- Kommentare
|
|
- zeigen häufig, dass der Code zu komplex ist
|
|
- Duplikate
|
|
- _Dont repeat yourself!_
|
|
- **Sicherheitsrelevante Issues**
|
|
- OWASP Top Ten
|
|
- Sammlung von kritischen Risiken für Anwendungssicherheit
|
|
- SAST Tools
|
|
- finden bekannte Risiken
|
|
|
|
### Simple Metrik für Komplexität: McCabe Metrik
|
|

|
|
- Cyclomatische Komplexität
|
|
- Behandelt Programmstuktur als Graphen
|
|
- Wird folgendermaßen kalkuliert:
|
|
- $$C = E-N + 2P$$
|
|
- E = Nummer der Ecken
|
|
- N = Nummer der Nodes
|
|
- P = Nummer der verbundenen Komponenten (für eine OO Funktion ist P = 1)
|
|
- Beispiel:
|
|
- $$C = 9-8+ (2*1) = 3$$
|
|
- 
|
|
|
|
|
|
## Übung Test Cases, Dependencies and more
|
|

|
|

|
|
|
|
3. :
|
|
- BriefSystem - Controller
|
|
- BriefErstellung - Domain
|
|
- Empfaenger - trivialer Code
|
|
- EmpfaengerInterface - Domain Model
|
|
- EmpfaengerCsvLeser - trivialer Code
|
|
- Brief - trivialer Code
|
|
|
|
|
|
4. : alle
|
|
5. :
|
|
- wurdeEmpfängerHinzugefügt
|
|
- Empfänger über Interface hinzufügen
|
|
- Brief erstellen und schauen ob Empfänger hinzufügbar ist
|
|
- EmpfängerListe kann sonst nicht abgefragt werden
|
|
|
|
6. :
|
|
|
|
|
|
|