marp | theme | _class | paginate | backgroundColor | math |
---|---|---|---|---|---|
true |
gaia |
lead |
true |
katex |
HS Fulda WS 2021/22
Jörn Auerbach [email protected]
Orga, vim, VCS
z.B. via YouTube Playlist Ready2Code Terminal/Shell Lektion
Vorlesung | Übung | |
---|---|---|
10/21 | Orga, vim, VCS | Lerntagebuch, vimtutor |
10/28 | Git Grundlagen | GitLab, SSH-Key, Repository |
11/04 | Workflows mit Git | Merge, Pull Request |
11/11 | Git Sonstiges | Gruppeneinteilung, Projekt-Diskussion |
11/18 | Shell Scripting | bash |
Vorlesung | Übung | |
---|---|---|
11/25 | Agile Entwicklung | GitHub Team Repository |
12/02 | Scrum | Projekt Board |
12/09 | DevOps | GitHub Action (Linter) |
12/16 | Reguläre Ausdrücke | grep, sed, awk |
01/13 | Debugging & Testing | Test Driven Development |
Vorlesung | Übung | |
---|---|---|
01/20 | Clean Code | Refactoring |
01/27 | Rückfragen Projekt | Rückfragen Projekt |
02/03 | Open Source / Puffer (optional) | Projektpräsentationen |
02/10 | Open Source / Puffer (optional) | Projektpräsentationen |
02/17 | Preisverleihung | Projektpräsentationen |
- IDE und Debugger
- Versionskontrollsystem (Git)
- Kommandozeile
- Software-Entwicklungszyklus
- Dokumentation
- Team- und Projektarbeit
- 20% Lerntagebuch
- 80% Teamprojekt
Die Details auf den folgenden Folien nehmen viel vorweg, was wir uns erst im Laufe des Semesters erarbeiten. Es dient zunächst nur dazu, die Anforderungen klar zu machen.
- Was waren die wesentlichen Inhalte? (stichpunktartig)
- Was kann ich für das Teamprojekt anwenden? (2-3 Sätze)
- Einen Begriff/Ein Thema in eigenen Worten erklären (2-3 Sätze)
- Optional: Was möchte ich den Dozierenden mitteilen?
- Verbesserungsvorschläge, Gefühle, Kritik, Lob (0-2 Sätze)
- Markdown-Datei (z.B.
README.md
) - über die Konsole bearbeiten (z.B. vim, nano)
- Sprache entweder Deutsch oder Englisch
- verfügbar machen auf https://gitlab.cs.hs-fulda.de
- fdai0178 & fdai0209 mit Rolle Developer hinzufügen
Ein Beispiel Lerntagebuch: https://gitlab.cs.hs-fulda.de/fdai0178/lerntagebuch-beispiel
- jeder Eintrag startet mit 100% (~2 Punkte)
- Abzüge:
- -100% Abgabe (push) erst nach der nächsten Vorlesung
- -50% Formatierung mit Markdown mangelhaft
- -33.3% pro fehlender Antwort zu 1-3
- -20% Rechtschreibung/Grammatik ungenügend
- pro Eintrag minimal 0 Punkte (keine Negativpunkte)
- selbstorganisiert zusammenfinden (Forum, Campus,...)
- 4-5 Studierende pro Team (keine Ausnahmen!)
- Anmelden des Teams über Moodle bis 17.11.2021
- Konsolenanwendung in Java oder C
- z.B. Spiel, Quiz, Story, Animation,...
- fehlende Programmier-Erfahrung wirkt sich nicht negativ aus! Wählt Programm und Umfang anhand Eurer Kenntnisse. Wendet an, was Ihr in anderen Modulen lernt, z.B. in Programmierung 1.
- je Team ein Repository auf https://github.com
- User jo3rn und franzibmnn hinzufügen
- zur Weihnachtspause wird es eine kleine "Feature-Anfrage" geben, die Ihr in das Projekt einbauen müsst
- 1x Product Owner & 1x Scrum Master (programmieren nicht!)
- 2x/3x Developer
- GitHub:
- Product & Sprint Backlog (Product Owner)
- Issues (Product Owner, Developer)
- Pull Requests (Developer)
- zwei Sprints durchführen (Scrum Master)
- Planning, Daily, Review, Retrospective
- am Ende des Semesters während der SU-/Übungszeit
- Termine buchbar nach der Weihnachtspause
- in 10 Minuten z.B.:
- Programm / Code vorstellen
- Organisation und Arbeitsweise erläutern
- Erkenntnisse und Gelerntes zusammenfassen
- danach 5 Minuten Rückfragen
- gesamter (ausführbarer) Code auf GitHub
- Sprint-Ziel
- Screenshot(s) Product & Sprint Backlogs (Product Owner)
- Beginn des ersten Sprints
- Beginn des zweiten Sprints
- Ende des zweiten Sprints
- Ergebnisprotokoll Retrospective (Scrum Master)
- springt nach der Anmeldung nicht mehr aus banalem Grund ab
- unterstützt euch gegenseitig
- eine nicht selbst erstellte Abgabe führt zu Nichtbestehen!
- kleine Code-Schnipsel, einzelne Algorithmen etc. sind unter Angabe der Quelle (z.B. stackoverflow-Link) erlaubt
ab ... Punkten | Note |
---|---|
0 | 5 |
50 | 4 |
55 | 3.7 |
60 | 3.3 |
65 | 3 |
.. | .. |
90 | 1.3 |
95 | 1 |
Punkte | Challenge (abzuschließen bis 26.01.2022) |
---|---|
2 | ein Programmier-Meme/Comic/etc. in der Übung präsentieren und erklären, warum das lustig ist (darf noch nicht gezeigt worden sein, max. 4 pro Übung) |
2 | einen sinnvollen Pull Request zu einem Open Source Projekt erstellen (Mail mit Link zum PR an mich) |
1 | einen (auch sinnlosen) Pull Request zu diesem Veranstaltungs-Repository erstellen (+1 Punkt: falls gemergt) |
Ab hier geht's los.
Wikipedia Versionsverwaltung (zentral)
Linux kernel (dezentral)
nutzt Git als VCS
- Protokollieren
- was wurde wann von wem und wie geändert?
- Absichern
- einen protokollierten Stand wiederherstellen
- Kollaborieren
- dezentrale Datenhaltung
- gleichzeitig bearbeiten und später zusammenführen
Download oder vorinstalliert git --version
Eigene Informationen festlegen:
git config --global user.name "Vorname Nachname"
git config --global user.email [email protected]
Befehle um ein Lerntagebuch-Repository anzulegen:
mkdir Lerntagebuch && cd Lerntagebuch
git init
echo "# Woche 1" >> lerntagebuch.md
vim links.md
(vim direkt mit:wq
wieder verlassen)
Was zeigt git status
an?
Was befindet sich im versteckten Verzeichnis .git
?
Untersuche nach jedem Befehl, wie sich die Ausgabe von git status
verändert und was im .git
-Verzeichnis passiert:
git add lerntagebuch.md
git commit -m "Create lerntagebuch.md"
git add links.md
git commit -m "Create empty file for links"
Was gibt git log
am Ende aus?
Was soll das Ganze?
- Pro Git Buch: https://git-scm.com/book/en/v2 (Englisch) https://git-scm.com/book/de/v2 (Deutsch) Für Woche 1: Kapitel 1 "Erste Schritte"
- https://git-scm.com/docs Git Dokumentation
- https://itoshkov.github.io/git-tutorial.html "Teach Yourself Git Without Learning a Single Git Command"
Wir kennen ls
, cd
, mkdir
, etc.
Mit vim
bearbeiten wir Dateien im Terminal über die Tastatur.
Download oder vorinstalliert vim --version
Dokumentation oder man vi
vim öffnen: vim
Dateiname
Standardmodus beim Start von vim
Cursor bewegen:
h/l links/rechts
j/k runter/hoch
b/w vorheriger/folgender Wortanfang
e Wortende
0/$ Zeilenanfang/-ende
gg/G Dateianfang/-ende
rudimentäres Bearbeiten:
u letzte Änderung rückgängig
r Zeichen ersetzen
x Zeichen löschen
yy Zeile kopieren
dd Zeile ausschneiden/löschen
p nach dem Cursor einfügen
P vor dem Cursor einfügen
Zahlen-Präfix für mehrfache Ausführung:
5j 5 Zeilen nach unten
4x 4 Zeichen löschen
3p 3 Mal einfügen
zum Schreiben von Text
von Normal Mode in Insert Mode wechseln:
i an der Stelle des Cursors
I am Zeilenanfang
a eine Stelle nach dem Cursor
A am Zeilenende
o neue Zeile unter dem Cursor
O neue Zeile über dem Cursor
Mit Esc
zurück in Normal Mode
Kommandos im Normal Mode mit :
einleiten, Enter
zum Bestätigen
:w speichern
:q beenden
:q! beenden und Änderungen verwerfen
:wq speichern und beenden
Suchen:
:/Wort Vorwärtssuche nach Wort
:?Wort Rückwärtssuche nach Wort
n nächster Treffer (während Suche)
Vom Normal Mode mit R
in Replace Mode: Text wird Zeichen für Zeichen ersetzt
Mit Esc
zurück in Normal Mode
vimtutor
in der Shell eingeben ~30-minütiges Tutorial zusammen mit vim installiert- https://www.openvim.com interaktives Tutorial
- https://vim-adventures.com spielerisch die Grundbefehle entdecken (nur erste Level kostenfrei)
- https://www.vimgolf.com (fortgeschrittene) vim Challenges
Git Grundlagen
Woher weiß Git, welche Dateien in einen Zwischenstand gehören?
+--------------+ +-----------------+ +------------+
| Working Tree | | Staging / Index | | .git |
+--------------+ +-----------------+ +------------+
alle Dateien im für die nächste in der Daten-
aktuellen Verzeichnis: Version vorgemerkt: bank gesichert
- modified - modified
- unmodified - tracked / staged
- untracked
git add git commit
---------------> ---------------->
Ausgabe | Befehl | beteiligte Bereiche |
---|---|---|
Untracked files |
Working Tree | |
add |
Working Tree -> Staging | |
Changes to be commited |
Staging | |
commit |
Staging -> Repository | |
nothing to commit |
Repository |
- inhaltlich zusammengehörende Änderungen
- über einen Hash-Wert identifizierbar
- commit message:
git commit -m "kurze, aussagekräftige Beschreibung"
bei Bedarf weitere Zeilen mit Details - add und commit in einem:
commit -a
git log listet alle Commits.
Viele Optionen, um die Ausgabe anzupassen, z.B. --oneline
:
Organisationen/Teams sollten sich auf ein Commit Message Schema einigen, z.B. Conventional Commits.
HEAD
zeigt auf den Punkt, an dem man sich gerade im Repository befindet:
- Branch (meistens)
- Commit (wenn man es herausfordert)
Speicherort: .git/HEAD
git diff zeigt welche Änderungen genau vorgenommen wurden.
git diff
: Änderungen zwischen Staging Area und Working Tree (allerdings nicht für neu hinzugefügte Dateien)
git diff --staged
: Änderungen zwischen Staging Area und Repository
git diff
oldCommit newCommit
: Änderungen zwischen zwei Commits
Es gibt viele GUI Clients oder IDE-Integrationen für häufig auftretende Git-Arbeitsabläufe (add, commit, diff view, remote,...), z.B.:
gitk
in der Git Bash eingeben- Git Integration von VS Code
Aber: die Grundkonzepte sollten auch ohne GUI verinnerlicht werden. Außerdem sind schicke Oberflächen wesentlich anfälliger für Veränderungen als Konsolenbefehle.
Situation: viele bearbeitete Dateien im Working Tree sollen in mehrere Commits aufgeteilt werden
Mit git add -i
die zu committenden Dateien fein justieren:
[u]pdate
: Datei stagen[r]evert
: Datei unstagen[p]atch
: einzelne Bereiche (hunks) einer Datei stagen
Die .gitignore
-Datei spezifiziert Dateien und Verzeichnisse, die Git ignorieren soll.
.DS_Store
/build/
server_log.txt
*.zip
.gitignore
-Templates gibt's im Netz, z.B. für C oder Java
- ein Tag referenziert einen Commit
- zum Markieren von Release-Versionen, "Lesezeichen" o.ä.
- erstellen mit
git tag
Tagname
, z.B.git tag v1.0.0
git tag -a
(annotated Tag) sichert zusätzliche Metadaten
- alle auflisten mit
git tag
- löschen mit
git tag -d
Tagname
git revert
oldCommit
hebt die Änderungen aus oldCommit auf, indem ein gegensätzlicher Commit hinzugefügt wird (ungefährlich)
git commit --amend
ergänzt den letzten Commit (verändert Hash/Historie)
git reset
oldCommit
setzt das Repository auf den Stand von oldCommit zurück (mit --hard
potentiell gefährlich: Verlust von Änderungen ohne Commit!)
git rebase -i
oldCommit
ermöglicht verschiedene Operationen auf alle Commits nach oldCommit
(Löschen, Tauschen,...)
git config --list
listet die aktuelle Konfiguration auf, z.B. die gesetzte Identität (user.name
und user.email
)
Auswahl an weiteren Konfigurationsmöglichkeiten:
- Standard-Editor ändern (wer vim nicht mag)
- Aliase vergeben, z.B. für kürzere Kommandos
- Farbschema ändern
- Login auf https://gitlab.cs.hs-fulda.de/ mit fdNummer
- SSH-Key erstellen und hinzufügen
- neues Projekt
Lerntagebuch
anlegen- fdai0178 & fdai0209 mit Rolle Developer hinzufügen
Das zuvor erstellte lokale Repository verknüpfen wir nun mit dem remote Repository, um es für die Dozierenden verfügbar zu machen.
Im Verzeichnis eures lokalen Repos:
git remote add origin [email protected]:fdNummer/lerntagebuch.git
(fdNummer
und Projektnamen entsprechend anpassen)- mit
git remote -v
prüfen, ob dieorigin
gesetzt wurde - mit
git push -u origin --all
das Lerntagebuch zu GitLab laden
git fetch
liest alle Änderungen vonorigin
git pull
bringt alle Änderungen vonorigin
ins lokale Repositorygit push
sendet alle Änderungen zuorigin
"origin" als Referenzname der remote
-URL ist nur eine Konvention. Es können auch weitere (anders benannte) remote
s hinzugefügt werden.
- https://ndpsoftware.com/git-cheatsheet.html Schema möglicher Aktionen zwischen den Git-Bereichen
- Pro Git Buch: https://git-scm.com/book/en/v2 (Englisch) https://git-scm.com/book/de/v2 (Deutsch) Für Woche 2: Kapitel 2 "Git Grundlagen"
- https://tom.preston-werner.com/2009/05/19/the-git-parable.html The Git Parable (Git mit einer Geschichte erklärt)
Branching & Workflows mit Git
❌ | ✅ | |
---|---|---|
Leerzeichen nach Symbol | #Überschrift 1.Erstens -Stichwort |
# Überschrift 1. Erstens - Stichwort |
Backticks ` für Code |
git init |
`git init` |
Einrückungen haben eine Bedeutung. Nur gezielt einsetzen!
Achtet auf die korrekte Darstellung von Umlauten/Sonderzeichen!
weitere Doku: https://www.markdownguide.org/basic-syntax/
- Eintrag für Woche 1 + 2 nicht vergessen!
- "2-3 Sätze" bedeutet: weniger als 2-3 Sätze gibt Abzug! (mehr ist immer möglich)
- Einträge aktiv selbst schreiben, nicht von irgendwo kopieren
- beginnend mit nächster SU (11.11.2021) müssen die Einträge immer vor der SU commitet und zu GitLab gepusht sein
- d.h. für Woche 3 bis 11.11.2021 11:40 Uhr usw.
Ein Beispiel Lerntagebuch: https://gitlab.cs.hs-fulda.de/fdai0178/lerntagebuch-beispiel
-
Git push wird dafür verwendet um die veränderten Dateien die sich im Staging befinden auf git hochzuladen.
-
Öffnen über Git durch ... vim Name.md
-
Der Befehl git diff zeigt [...] Änderungen zwischen dem Repository und dem Working Tree. Folglich wird das, was sich in dem Arbeitsverzeichnis befindet, mit dem, was sich in der Staging-Area befindet, verglichen.
-
md: Wechselt den Location, jenachdem was für Ordner/File man eingibt. Mit md .. geht man auf 1 Location zurück
git clone
repository
kopiert ein (remote) repository
in ein neues Verzeichnis.
fetch
, pull
und push
stehen im geklonten Repository direkt zur Verfügung.
Beispiel:
git clone [email protected]:fdai0178/lerntagebuch-beispiel.git
Branch | HEAD | Tag | |
---|---|---|---|
"zeigt" auf einen Commit | x | x | x |
wandert mit neuem Commit weiter | (x) | x | |
kann mehrere geben | x | x |
- man commitet immer auf maximal einem Branch
(bislang
main
bzw.master
) - Branch an der aktuellen Stelle erzeugen:
git branch
branchName
- auf anderen Branch wechseln:
git checkout
branchName
- Release / verschiedene Varianten
- Long Term Support
- Premium-Version
- A/B-Test
- Designs
- parallel Arbeiten ohne andere zu beeinträchtigen
- (un)fertiges Feature
- Bugfix
Situation: mehrere Varianten sollen zu einem Stand zusammengeführt werden
git merge
branchName
holt die Commits aus branchName
in den aktuellen Branch.
reibungsloser Merge durch "vorspulen"
A --- B (* main -> B)
\
C --- D (feature -> D)
git merge feature
A --- B --- C --- D (* main -> D) (feature -> D)
A --- B -- D -- F (* main -> F)
\
C ----- E (feature -> E)
git merge feature
erzeugt neuen Commit G
A --- B -- D -- F - G (* main -> G)
\ /
C ----- E - (feature -> E)
G
hat zwei Vorgänger und vereinheitlicht die Änderungen der Commits C
, D
, E
und F
.
Situation: eine Datei wurde auf mehreren Branches an der gleichen Stelle verändert
# README.md
<<<<<< HEAD/main
main will das hier schreiben
======
feature will lieber das hier schreiben
>>>>>> feature
git merge --abort
bricht Merge ab
Für jeden <<< === >>>
-Block muss entschieden werden, wie er zusammengeführt werden kann.
# README.md
main will das hier schreiben
feature fügt das hier an
Um den Merge abzuschließen wird die Datei nach dem Editieren wie gewohnt versioniert.
git add README.md
git commit -m "Merge feature into main"
Nicht mehr benötigte Branches sollten gelöscht werden.
git branch -d
branchName
: wenn Branch gemergt istgit branch -D
branchName
: wenn Branch noch nicht gemergt ist
A --- B -- D -- F (main -> F)
\
C1 ----- E1 (* feature -> E1)
git rebase main
A --- B -- D -- F (main -> F)
\
C2 ----- E2 (* feature -> E2)
- setzt den aktuellen Branch hinten dran
- verändert die Commits des aktuellen Branchs
(im Beispiel:
C1
&E1
wird zuC2
&E2
) - wenn Merge Konflikte entstehen:
Konfliktdatei
öffnen, Konflikt lösen, Trennzeichen entfernengit add
Konfliktdatei
git rebase --continue
- ...oder
git rebase --abort
Ich möchte diesen Branch in diesen anderen Branch mergen.
Vor dem Merge können sich andere Developer die Änderungen anschauen und Feedback geben.
PR wird akzeptiert | PR wird nicht akzeptiert |
---|---|
Branch wird gemergt | TODOs sind entstanden |
Workflow: Trunk Based Development (1/2)
main
ist "trunk", in den direkt committet (z.B. D
, F
) oder kurzlebige feature
-Branches gemergt werden.
(release1.0 -> B) ---------- (release1.1 -> K)
/ / /
A --- B -- D -- F - G -- H -- I -- J -- K -- L (* main -> L)
\ / \ /
B1 -- B2 -- G1 --- G2 --- G3 -- G4
(feature1 -> B2) (feature2 -> G4)
Releases sind Tags auf dem trunk-Branch (release1.0
) oder abgespaltete release
-Branches (release1.1
) mit Hotfixes (K
).
Workflow: Trunk Based Development (2/2)
- Developer:
pull
en mehrmals täglich vom trunkpush
en möglichst täglich in den trunk
- es kann zu (fast) jeder Zeit releast werden
- "never break the build"
- Commits vor dem
push
testen / reviewen / pair-programmieren - falls dennoch kaputt:
revert
/reset
(möglichst automatisiert)
- Commits vor dem
Workflow: Feature-Branch (1/2)
A --- B --------- C ------------------------ D (* main -> D)
|\ / \ /
| B1 --- B2 (cc-payment -> B2) C1 (bugfix -> C1)
\
BA --- BB --- BC --- BD --- BE --- BF (coupon-code -> BF)
- alle Änderungen werden auf einem dedizierten Branch entwickelt
- auf
main
wird nicht direkt committet, nur gemergt main
hat immer funktionierenden Code (so die Hoffnung)- wird in Verbindung mit Pull Requests auch GitHub Flow genannt
Workflow: Feature-Branch (2/2)
feature
Branches:
- fördern Reviews und Kollaboration durch Pull Requests
- isolieren Experimente, die auch mal schief gehen oder frühzeitig beendet werden können
- lassen erkennen, woran gerade gearbeitet wird
Workflow: GitFlow (1/2)
master
: Release-Historydevelop
:feature
s für nächstes Releasefeature
: work in progressrelease
: letzte Vorkehrungen vor Releasehotfix
: Behebung kritischer Fehler in bereits releaster Version
Workflow: GitFlow (2/2)
- relativ komplexe Branch-Struktur
- explizite Regeln führen zu Sicherheit, aber auch Limitationen
- mehrere langlebige Branches müssen aktuell gehalten werden
develop
undfeature
entsprechen im Grunde dem Feature-Branch Workflow- gut geeignet, wenn nur selten releast wird oder mehrere Releases parallel existieren
- (Remote) Repository auf das alle Zugriff haben, z.B. auf GitHub
- alle
push
en regelmäßig, um ihre lokalen Commits allen zur Verfügung zu stellen (und als Backup) - alle
pull
en regelmäßig, um die Änderungen der anderen zu prüfen und in ihre Arbeit zu integrieren
Jeder Workflow hat Vor- und Nachteile.
Wichtig ist, dass sich die Developer in eurem Team auf einen Prozess einigen, mit dem sie sich wohl fühlen.
Ihr könnt auch einen der vorgestellten Workflows modifizieren oder einen anderen Weg gehen. Das solltet ihr in der Präsentation aber begründen können.
Tipp: einen simplen Workflow ausprobieren und nur bei Bedarf zu einem komplexeren wechseln.
-
Pro Git Buch: https://git-scm.com/book/en/v2 (Englisch) https://git-scm.com/book/de/v2 (Deutsch) Für Woche 3: Kapitel 3 "Git Branching" & Kapitel 5.1, 5.2
-
https://learngitbranching.js.org interaktives Git Tutorial mit Visualisierungen
-
https://xosh.org/explain-git-in-simple-words/ "How to explain git in simple words?"
Git Sonstiges
-
Es können pro 'merge' immer nur zwei Branches zusammengeführt werden.
-
HEAD = ist der "Branch" auf dem man sich gerade befindet
-
Falls Fehler aufgetreten sind, kann man mit dem Interactive Staging Commits umstagen und korrigieren.
git stash
lagert Dateien aus Index und getrackte Dateien aus Working Tree in einen "Stash" aus.
Stash zurück holen mit
stash pop
: löscht diesen Stashstash apply
: belässt den Stash instash list
git blame
file
zeigt die Commits an, durch die der aktuelle Zustand vonfile
entstanden ist.
$ git blame README.md
16497eb4 (alice 2015-01-11 13:43:02 -0800 1) # How to authenticate via SSH
16497eb4 (alice 2015-01-11 13:43:02 -0800 2)
aab42501 (bob 2015-01-12 00:08:51 +0100 3) ## Prerequisites
59b51cde (alice 2015-01-11 15:09:44 -0800 4) 1. You need an SSH key pair.
git log -p --follow
file
zeigt alle Commits, die das File verändert haben.
git show
commit
zeigt die Änderungen, die durchcommit
entstanden sind.git rm
file
löschtfile
und staged die Löschung.git mv
oldFile
newFile
verschiebt / benennt um und staged die Änderung.
git cherry-pick
commit
hängt commit
an den aktuellen Branch an.
Working Tree muss clean sein.
Auch hier können Konflikte entstehen:
git add
->git cherry-pick --continue
- oder
git cherry-pick --abort
Mit git rebase -i
parentCommit
kann man die Commits editieren, die auf parentCommit
folgen. Die gängigsten Aktionen:
pick
: Commit unverändert lassen
reword
: Commit Message ändern
edit
: Änderungen zum Commit hinzufügen
squash
: mehrere Commits zu einem Commit verschmelzen
drop
: Commit entfernen
Beispiel: git rebase -i HEAD~3
für die letzten 3 Commits.
A --- B -- C -- D -- E -- F -- G -- H (* main -> H)
\ /
D1 - D2 (feature -> D2)
HEAD -> main
HEAD^ -> G HEAD^^ -> F HEAD^^^ -> E
HEAD~ -> G HEAD^^^2 -> D2
HEAD~1 -> G HEAD~2 -> F HEAD~3 -> E HEAD~4 -> D
git bisect start
: Suchprozess startengit bisect good
commit
: einencommit
ohne die unerwünschte Änderung angebengit bisect bad
commit
: einencommit
mit der unerwünschten Änderung angeben- mit
git bisect good
odergit bisect bad
angeben, ob der aktuelle Stand "good" oder "bad" ist - nach ein paar Durchläufen ist der Übeltäter-
commit
entlarvt
Projekt Ideen: BSD games
- Installation z.B. über Linux (oder WSL):
sudo apt install bsdgames
- Aufruf über
hangman
,morse
,wtf
,tetris-bsd
,snake
,wump
etc.
-
Pro Git Buch: https://git-scm.com/book/en/v2 (Englisch) https://git-scm.com/book/de/v2 (Deutsch) Für Woche 4: Kapitel 7.3 & 7.10
-
https://ohshitgit.com/ Gits "Oh, shit!"-Momente entschärfen
-
http://www-cs-students.stanford.edu/~blynn/gitmagic/ (umfangreiche) Erläuterung von Git als wäre es ein Computer-Spiel
Shell Scripting
(entfällt krankheitsbedingt)
Agile Entwicklung
-
git diff
: Änderungen zwischen Repository und Working Tree
- Kommunikation: kaum, nur in Silos
- Plan: zu detailliert, nicht realistisch, unflexibel
- Fristen: zu starr, nicht einhaltbar, strategisch/politisch festgesetzt
- Software: erst nach langer Zeit einsatzbereit
Agilität ist eine Reihe von Werten und Prinzipien, die als Agile Manifesto und 12 Principles zusammengefasst sind.
Laut der Verfasser verbessern diese Werte den Softwareentwicklungsprozess und die Kundenzufriedenheit.
- eine spezifische Methodologie
- ein Rahmenwerk
- ein Prozess
mehr Wert beimessen | weniger Wert beimessen |
---|---|
individuals and interactions | processes and tools |
working software | comprehensive documentation |
customer collaboration | contract negotiation |
responding to change | following a plan |
Das Agile Manifesto zielt nicht darauf ab, die Elemente der rechten Spalte abzuschaffen. In Entscheidungsprozessen sollen aber die Elemente der linken Spalte vorrangig einbezogen werden.
- Prozesse/Tools nach dem Team ausrichten
- auch mal unkonventionelle Dinge ausprobieren
- Fehlerkultur entwickeln
- Autonomität und Eigenverantwortung ermöglichen
- Prozessgläubigkeit und Beharren auf bestimmte Vorgehensweise
- bei jedem PR müssen alle eine E-Mail bekommen
- "Schick mir das als Excel-Formular"
- Meeting planen, wenn man auch schnell aushelfen kann
- alle müssen zwischen 9 und 16 Uhr im Büro sein
- Passierschein A38
- Beharren auf Hierarchien
- ungeeignete Metriken für Beurteilung des Outputs
- jedes Inkrement (besser: jeder Commit) produziert funktionierende Software
- Qualität über Quantität
- gerade so viel dokumentieren, dass alle wissen, was zu tun ist
Vorteile:
- Kundenfeedback jederzeit möglich
- fehlerhafte Änderungen können sofort erkannt werden
- temporäre Dinge ausführlich dokumentieren
- alles im Vorfeld ins kleinste Detail ausplanen
As a ... I want ... so that ... (was soll erreicht werden?)
(nicht ernst gemeinte User Story)
- gegenseitiges Vertrauen schaffen
- direkte und regelmäßige Kommunikation
- Erfahrung, Wissen und Feedback des Kunden nutzen, um:
- Aufgaben zu priorisieren
- neue Aufgaben zu erstellen
- Aufgaben zu verwerfen
- alle Anforderungen im Voraus genau festlegen
- Aufwandsschätzungen auf falschen Annahmen
- auf langfristig geplanten Aufgaben beharren
- Kommunikation mit Kunden nur
- über Projektmanager*innen
- alle paar Wochen in mehrstündigen Meetings
Auch ohne "Kunden" könnt ihr Feedback zu Eurem Programm einholen, z.B. indem Ihr es unbeteiligte Personen testen lasst:
- versteht der User Zweck und Bedienung des Programms
- treten unbedachte Grenzfälle/Fehler auf
- hat der User Verbesserungsvorschläge / Wünsche
- User "laut denken" lassen für sonstige Anmerkungen
- Mindset:
- die Zukunft ist nicht vorhersehbar
- Veränderungen verbessern das Projekt
- Priorisierung regelmäßig auf den Prüfstand stellen
- Nutzen der zu entwickelnden Software regelmäßig validieren
- komplexe Aufgaben in kleinere Pakete herunterbrechen, um flexibel zu bleiben
- annehmen, dass die Anforderungen zu Beginn vollständig sind
- annehmen, dass sich die Anforderungen nachträglich nicht ändern
- sich nur nach dem Plan richten:
The project manager’s thinking, as represented by the project plan, constrains the creativity and intelligence of everyone else on the project to that of the plan, rather than engaging everyone’s intelligence to best solve the problems.
Ken Schwaber (2011)
- grobe Planung für gesamten Projektzeitraum
- detaillierte Planung nur für nahe Zukunft (2 Wochen)
- simpel & funktionierend > ausgefeilt & halbfertig
- regelmäßiger Austausch
When "Agile" ideas are applied poorly, they often lead to more interference with developers, less time to do the work, higher pressure, and demands to "go faster".
Ron Jeffries (2018)
However, the values and principles of the Manifesto for Agile Software Development still offer the best way I know to build software.
Ron Jeffries (2018)
http://www.extremeprogramming.org/
Scrum
-
User Story: (…) eine art "Geschichte des Benutzers" wobei der Benutzer verschiedene Rollen einnehmen kann (der Benutzer kan auch der Product Owner(Scrum) sein.)
eine (mögliche) praktische Ausprägung von Agilität
Ziel: komplexe Aufgaben in einer sich verändernden Umgebung lösen
Methode: einfach und offen gehaltene Rahmenbedingungen einer iterativen Arbeitsweise mit inkrementellen Ergebnissen
Scrum was invented to function in hostile environments, it's a really interesting contract between hard-pushing execs and devs needing time to think. Alistair Cockburn (2021)
Management | Entwickelnde |
---|---|
möchte Richtung vorgeben, langfristig planen und fordert Ergebnisse | benötigen Freiheit und Zeit zum Denken, Untersuchen, Erforschen... |
- Product Owner
- Scrum Master
- Developer
- überschaubar (<= 10 Personen) und interdisziplinär
- selbstorganisiert ohne Hierarchien
- respektiert und unterstützt sich
- offen und anpassungsfähig
- kommunikativ
- brennt für das Produkt (will das Beste rausholen)
- macht verständlich, was das Produkt leisten soll (Product Goal)
- pflegt und priorisiert den langfristigen Plan (Product Backlog)
- urteilt, ob ein Arbeitsergebnis abgeschlossen ist
- verantwortlich für die Einführung von Scrum
- vermittelt die Scrum-Werte und macht sie verständlich
- unterstützt bei der Umsetzung der Scrum-Events
- löst Blockaden und beseitigt Hindernisse des Teams
- darf coachen, aber keine Anweisungen erteilen
- erstellen einen kurzfristigen Plan (Sprint Backlog)
- legen fest, was "fertig" bedeutet (Definition of Done)
- ziehen sich gegenseitig zur Verantwortung
- arbeiten i.d.R. nicht an mehreren Dingen gleichzeitig
- Sprint
- Sprint Planning
- Daily Scrum
- Sprint Review
- Sprint Retrospective
- sorgen für regelmäßige Transparenz
- minimieren Notwendigkeit für sonstige Meetings
- enthält
- das Produkt-Ziel (zukünftiger Zustand des Produkts)
- beschreibende Einträge, wie das Produkt-Ziel erreicht wird
- Einträge sind danach geordnet, was das Produkt am meisten verbessert
- durch "Backlog Refinements" werden einzelne Einträge kontinuierlich präzisiert, angepasst, zerlegt und besser verstanden
- Verantwortung: Product Owner
- Spalte im GitHub Project Board
- User Stories beschreiben den gewünschten Zustand der Software
- zur Präsentation sollten noch User Stories offen sein (= mehr planen als implementiert werden kann)
- PO & Devs leiten anhand der User Stories konkrete Aufgaben ab (dokumentiert z.B. als Issues)
- ein Zeitraum mit fester Länge (i.d.R. 2-4 Wochen), in dem die anderen Scrum Events stattfinden
- Team verpflichtet sich auf ein konkretes Ziel
- am Ende entsteht mind. eine Produktverbesserung ("Increment")
- konkreter Schritt in Richtung Produkt-Ziel
- fertig, nutzbar und wertvoll
- befolgt die "Definition of Done"
- formale Beschreibung aller erforderlichen Qualitätsmerkmale, z.B. Styleguide eingehalten, alle Tests bestanden, Dokumentation vorhanden, von Fachleuten begutachtet
- DoD wird vom Scrum Team oder der Organisation festgelegt
Timebox: max. 8h (4-Wochen-Sprint) Teilnehmende: Scrum Team + wer sonst Input liefern kann
-
das Sprint-Ziel gemeinsam erarbeiten
- Wofür machen wir den Sprint?
-
Einträge aus dem Product Backlog auswählen und verfeinern
- Was erreichen wir in diesem Sprint?
-
die Entwickler*innen zerlegen die Einträge in kleine Aufgaben
- Wie erledigen wir die Arbeit in diesem Sprint?
- enthält
- das Sprint-Ziel
- die ausgewählten Einträge des Product Backlogs
- weitere abgeleitete Aufgaben
- sollte während des Sprints nur im Ausnahmefall verändert werden
- wird nach jedem Sprint gelöscht/zurückgesetzt
Timebox: max. 15min Teilnehmende: alle, die an etwas im Sprint Backlog arbeiten
- findet wenn möglich täglich zur selben Zeit am selben Ort statt
- den Fortschritt hin zum Sprint-Ziel eruieren
- Gibt es Hindernisse oder offene Entscheidungen?
- einen umsetzbaren Plan für den kommenden Arbeitstag erstellen
- ggf. das Sprint Backlog anpassen
Timebox: max. 4h (4-Wochen-Sprint) Teilnehmende: Scrum Team + wichtige Stakeholder
- das Ergebnis des Sprints vorstellen
- Fortschritt in Richtung Produkt-Ziel evaluieren
- Entscheidungen für das weitere Vorgehen treffen
- Haben sich äußere Umstände geändert?
- Sind Anpassungen nötig?
- Was ist als Nächstes zu tun?
- Wie sollte das Product Backlog angepasst werden?
Timebox: max. 3h (4-Wochen-Sprint) Teilnehmende: Scrum Team
- Wie kann die Qualität und Effektivität des Teams in Bezug auf Individuen, Interaktionen, Prozesse und Werkzeuge verbessert werden?
- Was lief im letzten Sprint gut?
- Gab es Probleme und wie könnte man sie lösen / wurden sie gelöst?
- umsetzbare Erkenntnisse können ins Sprint Backlog des nächsten Sprints übernommen werden
- Organisation & Durchführung durch Scrum Master
- ein Beispiel wie eine Retro ablaufen kann
- jede Retro durch mind. eine kurze Übung oder ein Spiel anreichern (Anregungen online, z.B. hier und hier)
- kurzes Protokoll umfasst:
- angesprochene Probleme / Erfolge
- durchgeführte Übung(en) (Ablauf & Ergebnis)
- abgeleitete Änderungen / Aufgaben
Das sich wiederholende Schema des Sprints ist darauf ausgerichtet Veränderungen zu bewirken.
Transparenz ermöglicht Überprüfung ermöglicht Anpassung.
https://scrumguides.org/index.html Scrum Guide online lesen oder herunterladen
https://www.scrum.org/open-assessments kurze Tests zum Scrum-Verständnis
DevOps
- formuliert und verfeinert User Stories, Aufgaben & Vision
- gibt Akzeptanzkritieren vor und überprüft deren Einhaltung
- entwickelt eine passende Methode der Priorisierung
- analysiert Markt und Stand der Technik
- prüft das Produkt selbst
- holt Feedback ein (z.B. User Tests)
- Kommunikationskanal zu Stakeholdern (z.B. Auerbach)
- bereitet Product Pitch vor und kann ihn jederzeit abfeuern
-
[Im] Product Backlog (...) definiert der Product Owner seine Ziele und Wünsche für das Projekt (...). Diese werden dann von dem Scrum Master (...) in das Sprint Backlog (...) übertragen.
-
Der Developer erstellt einen Plan für das Projekt und entscheidet auch mit wann ein Meilenstein als erledigt gilt.
-
Am Ende eines Projekts ist es hilfreich nocheinmal über das Product Backlog drüber zu gehen, um nachzuschauen ob alles umgesetzt wurde, was gewünscht war.
10+ Deploys Per Day: Dev and Ops Cooperation at Flickr (Erste Erwähnung von "Dev Ops")
Gute Zusammenarbeit zwischen Development und Operations durch
- automatisierte Infrastruktur (möglichst wenig manuelle Prozesse)
- gemeinsame Versionskontrolle
- Build in einem Schritt
- Deploy/Release in einem Schritt
- Feature Flags
- Vertrauen zwischen Development und Operations
- keine Stereotypen unterstellen
- keine Angst vor Veränderungen
- Expertise öffentlich machen
- Probleme und Fehler ohne Schuldzuweisung gemeinsam angehen
- gemeinsame, sichtbare Metriken
- Messaging Tools (Slack, MS Teams,...)
Zeitpunkt: z.B. bei Merge auf Haupt-Branch
- den Build-Prozess soweit wie möglich automatisieren
- statische Code-Analyse
- Kompilieren
- deploybare Artefakte erzeugen
- den Build soweit wie möglich automatisch testen lassen
- Tests müssen geschrieben werden
- Tests müssen auf einem CI-Server ausgeführt werden
= Verfall schnell bemerken und früh stoppen
- Wiederholung: Transparenz ermöglicht Überprüfung ermöglicht Anpassung. Transparenz erfordert Mut und Offenheit.
- "grüner Build"
- als Teil der Definition of Done
- signalisiert "brauchbaren" Stand für das Sprint Review
- CI-Ergebnisse als Input für Daily und Retrospektive: Gibt es Prozessprobleme oder Blockaden?
Airbus engineers in Germany (...) were using (...) computer-aided design software-version 4. Engineers in Toulouse (...) were using a newer version of the software (...) Those errors are going to cost Airbus billions.
- ersichtlich, ob sich Änderungen nahtlos in Bestehendes integrieren
- Releases erfordern keinen großen Aufwand
- sofortige Warnung wenn der Build fehlschlägt
- Signal an alle, dass sie dem Build nicht vertrauen können
- Entwickler*innen können sich drum kümmern, wenn das Wissen um die Änderung noch "frisch" ist
- weniger Bugs in der Produktiv-Version
- QA-Team wird weniger mit "kleinen" Fehlern aufgehalten
den Auslieferungs-Prozess soweit wie möglich automatisieren ("mit Klick auf einen Button"):
- Weiterentwicklungen in eine Testumgebung bringen
- Releases in eine Produktivumgebung bringen
- User sieht nur fertig entwickelte Features
- häufigere Auslieferung
- höhere Kundenzufriedenheit
- schnelleres Feedback
- kleinere Releasepakete
- bessere Fehlereingrenzung
- geringere Komplexität
- alle Beteiligten können (theoretisch) die Software selbst zum Laufen bringen
...passiert wenn Continuous Delivery ohne manuelles Zutun abläuft.
Unveröffentlichte Features sind im Release...
- bereits (teil-)integriert (siehe z.B. PokeMiners)
- "aus der Ferne" an-/ausschaltbar, z.B. via Feature Flags
- vom Team festgelegte & automatisiert überprüfbare Regeln
- bei Regelverstoß: Hinweis oder automatische Korrektur
- in IDEs integriert oder als CI-Schritt ausgeführt
qualitative Schwachstellen, Bugs, unnötig komplizierte Konstrukte,...
Beispiele:
- ungenutzte Variablen
- nicht erreichbarer Code
- Duplikate
- Schleifen mit nur einer Iteration
scanf()
ohne Feldbreite- Go To Statement Considered Harmful
Vorgaben an die Syntax von Code
Beispiele:
- einheitliche Einrückung
- Namenskonventionen
- Reihenfolge von Importen, Schlüsselwörtern
- Zeilenlänge
- Klammerung von Blöcken
- dokumentiert, z.B. via Javadoc oder Doxygen
- Zu überprüfenden Regeln werden in einer Konfigurationsdatei (z.B.
.xml
oder.json
) festgelegt. - Ein Programm (Linter) sucht die Dateien nach Regelbrüchen ab.
Warum Code Style Check automatisieren:
Computer | Mensch | |
---|---|---|
Fehler schnell erkennen | x | |
verlässlich alle Fehler erkennen | x | |
hat eine Meinung | x |
Idee: Ein Event auf GitHub löst eine automatisierte Aktion aus, z.B.:
- Push/Merge auf
main
Branch -> neue Release-Version erstellen - ein Issue wird erstellt -> formale Kriterien überprüfen
- ein Pull Request wird eröffnet -> Code kompilieren und testen
Was wann passieren soll wird in einer YAML-Datei formuliert, welche im Repo im Verzeichnis .github/workflows
liegt.
- Verantwortung: Developer
- GitHub Super-Linter einrichten
- clang-format für C (Beispiel-Regeln)
- checkstyle für Java (Beispiel-Regeln)
- Regeln dürfen angepasst, aber nicht komplett deaktiviert werden
- Linter soll mind. vor Merge auf Haupt-Branch laufen besser noch: bei jedem Commit
Videos zur Einrichtung aus letztem Jahr: 1 & 2 (nicht ganz up to date)
https://www.oreilly.com/library/view/the-phoenix-project/9781457191350/ Buch: The Phoenix Project (Gene Kim, Kevin Behr, George Spafford)
https://www.atlassian.com/devops DevOps Übersicht (Firma Atlassian bietet DevOps-Tools an)
https://docs.github.com/en/actions GitHub Actions Dokumentation
Reguläre Ausdrücke
Konsole:
git add *.txt
.gitignore:
*.class
[abc].txt
/root/**/leaf/
An expression that describes a set of strings Oxford Handbook of Computational Linguistic
patterns used to match character combinations in strings MDN Web Docs
Eine formalere Definition findet sich in: "Representation of events in nerve nets and finite automata" (S.C. Kleene) und dessen Nachfolgern
Beispiel-Muster: eine 1
gefolgt von einer weiteren Zahl
Regex | Treffer | kein Treffer |
---|---|---|
1[0-9] |
123456789 | 987654321 |
grep (global regular expression print)
grep
prints lines that contain a match for one or more patterns.
Beispiele:
grep Jörn names.txt
sucht nach Jörn innames.txt
grep 1[0-9] nums.txt
sucht nach10
,11
, ...,19
innums.txt
echo 123456 | grep '1\|2'
sucht nach1
oder2
in123456
grep unterstützt verschiedene RegEx Syntaxen
-G
: default - "basic regular expression" (BRE)
-E
: "extended regular expression" (ERE)
-P
: "Perl-compatible regular expression" (PCRE)
Übersicht der Unterschiede zwischen diesen (und weiteren): https://www.regular-expressions.info/refflavors.html
- ein
a
- die Buchstabenreihenfolge
ber
Regex | Treffer | kein Treffer |
---|---|---|
a |
Rhabarberbarbara | Erdbeeremil |
ber |
Rhabarberbarbara | Erdbeeremil |
Diese Sonderzeichen können eine besondere Bedeutung in einer RegEx-Syntax haben. Sie müssen ggf. escaped werden (z.B. mit \
):
\ Backslash * Stern
^ Dach + Plus
$ Dollar () runde Klammern
. Punkt [] eckige Klammern
| Pipe {} geschweifte Klammern
grep Befehl | Treffer | kein Treffer |
---|---|---|
grep '1$' |
1$ + 1$ = 2$ | |
grep '1$ +' |
1$ + 1$ = 2$ | |
grep -E '1$ +' |
1$ + 1$ = 2$ | |
grep -E '1\$ +' |
1$ + 1$ | 1$+1$=2$ |
grep -E '1\$ \+' |
1$ + 1$ = 2$ | |
grep '1\$' |
1$ + 1$ = 2$ | |
grep '2$$' |
1$ + 1$ = 2$ | 1$ + 1$ = 2$$ |
- ein
a
oder einR
- Großbuchstaben zwischen
I
undZ
- kein (
^
) Kleinbuchstabe zwischena
undg
oderi
undz
sowie kein Großbuchstabe zwischenA
undZ
Regex | Treffer | kein Treffer |
---|---|---|
[aR] |
Rhabarberbarbara | Erdbeeremil |
[I-Z] |
Rhabarberbarbara | Erdbeeremil |
[^a-gi-zA-Z] |
Rhabarberbarbara | Erdbeeremil |
\d
Ziffer\w
Buchstabe oder Underscore\s
Whitespace Zeichen.
egal was
Regex | Treffer | kein Treffer |
---|---|---|
\d |
Rha6ar6er6ar6ara | Erdbeeremil |
\s |
Rhabarberbarbaras Bar | Erdbeeremileck |
. |
Erdbeeremil |
? 0 oder 1 Mal + ein oder mehrmals
* 0 der mehrmals {n} n-mal
Regex | Treffer | kein Treffer |
---|---|---|
arb? |
Rhabarberbarbara | Erdbeeremil |
rbe* |
Rhabarberbarbara | Erdbeeremil |
ba+ |
Rhabarberbarbara | Erdbeeremil |
(bar){2} |
Rhabarberbarbara | Erdbeeremil |
|
logisches Oder
Regex | Treffer | kein Treffer |
---|---|---|
ba|ber |
Rhabarberbarbara | Erdbeeremil |
r(a|b) |
Rhabarberbarbara | Erdbeeremil |
^
Beginn der Zeichenkette$
Ende der Zeichenkette\b
nach einem Wort (zwischen\w
und nicht-\w
)
Regex | Treffer | kein Treffer |
---|---|---|
^r |
rhabarberbarbara | erdbeeremil |
a$ |
Rhabarberbarbara | Erdbeeremil |
s\b |
Rhabarberbarbaras Bars | Erdbeeremil |
-
bb|[^b]{2}
bzw.grep 'bb\|[^b]\{2\}'
Welches Zitat versteckt sich hinter diesem regulären Ausdruck? Tipp: Es hat etwas mit Shakespeare zu tun. -
Sucht auf angio.net/pi nach eurem Geburtsdatum in
$\pi$ (Pi)- dort könnt ihr auch verschiedene Dateien mit x Stellen von $\pi$ herunterladen und auf der Konsole mit
grep
testen
- dort könnt ihr auch verschiedene Dateien mit x Stellen von $\pi$ herunterladen und auf der Konsole mit
/pattern
: nachpattern
suchen (vorwärts)?pattern
: nachpattern
suchen (rückwärts)n
: zum nächsten Ergebnis springenN
: zum nächsten Ergebnis in umgekehrter Richtung springen:%s/old/new/g
: alles, auf dasold
zutrifft mitnew
ersetzen:%s/old/new/gc
: wie oben, aber Ersetzen muss bestätigt werden (c
onfirm)
git grep
pattern
sucht in den Dateien im Arbeitsverzeichnis nachpattern
.- ähnlich wie
grep -r --color=always
pattern
.
- ignoriert das
.git
-Verzeichnis und hat tlw. andere Optionen - auch
git grep
pattern
HEAD~6
usw. möglich
- ähnlich wie
git log -i --grep="add"
filtert das Commit-Log nachadd
(mit-i
case-insensitive)git log -G
pattern
listet die Commits, in denen sich die Vorkommen vonpattern
geändert haben
sed & awk sind Programme, die
- Daten einlesen
- Daten (zeilenweise) filtern und/oder manipulieren
- Daten (ggf. neu formatiert) ausgeben
RegEx mit sed und awk: /
pattern
/
sed 's/0\+\([1-9]\)/\1/' nums.txt
- entfernt alle Nullen am Anfang einer Zahlenfolge (
s
ubstitute) - Klammern
(...)
bilden eine "capturing group", die mit\1
wiederverwendbar ist
awk '/[ab]/ {print $1}' names.txt
- gibt das erste Wort aller Einträge aus, die ein
a
oderb
enthalten
Das FreeBSD Spiel hangman speist sich aus der Datei /usr/share/dict/words
, welche sich natürlich auch filtern lässt, z.B.:
- Anzahl Buchstaben gesamt, z.B. 7:
-
grep '^.\{7\}$'
file
odergrep '^.......$'
file
-
sed -n '/^.\{7\}$/p'
file
-
awk 'length($0)==7'
file
-
- Position erratener Buchstaben, z.B.
t
an dritter Stelle:grep
???
sed
???
awk
???
- nicht vorkommende Buchstaben, z.B. kein
b
und keinm
:grep
???
sed
???
awk
???
Ein Easter Egg ist ein verstecktes Ereignis in Software, Film, Musik,...
Beispiele:
about:mozilla
in der Adressbar des Firefox Browsers- Der Igel im Bild des Eintrags zu Easter Eggs auf Wikipedia
- Die Skala des IMDb Ratings von This is Spinal Tap
:help 42
in vim- "do a barrel roll" oder "askew" in der Google Suche
-
https://regexone.com/ interaktive Übungen zu Regulären Ausdrücken
-
https://regex101.com/ Test-Tool für verschiedene RegEx-Engines
Testing & Debugging
- deckt nicht erwünschtes Verhalten auf
- dokumentiert erwünschtes Verhalten (Spezifikation)
- schafft Vertrauen für Änderungen am Code
- beeinflusst Softwaredesign ("testability")
- Unit = kleine, für sich stehende Komponente im Code
- Funktion(en), Method(en)
- Klasse(n), Datei(en), Modul(e)
- Unit Tests sind schnell, häufig und automatisiert ausführbar
in Bezug auf Agile Development:
- Autor*in des Codes und der zugehörigen Tests identisch
- Teil von Continuous Integration und Definition of Done
zu testende Einheit (Unit):
int add(int a, int b) {
return a + b;
}
Tests:
void main() {
printf("%s\n", add(2, 3) == 5 ? "ok" : "Fehler!");
printf("%s\n", add(-2, 3) == 1 ? "ok" : "Fehler!");
}
- gültige und ungültige Eingaben von Äquivalenzklassen
- z.B. Wertebereiche, leere Elemente, Datentypen,
null
- z.B. Wertebereiche, leere Elemente, Datentypen,
- Grenzfälle
- größte/kleinste/längste/... Eingaben
- z.B.
add(INT_MAX, 1)
- Zustandsdiagramme, endliche Automaten, Business-Logik
- z.B. je nach Kontostand Zahlung erlauben oder verweigern
- Integration: das Zusammenspiel mehrerer Units/Komponenten
- System: Usability, Sicherheit, Lasttest, Interaktion mit Hardware
- Akzeptanz: Spezifikationen (User Stories) werden erfüllt
Was passiert, wenn...
- das Backend nicht erreichbar ist oder ein Sensor ausfällt?
- externe Services ihre Schnittstelle ändern?
- das Gerät in den Energiesparmodus wechselt oder der Stromkreis unterbrochen wird?
- die Software über einen langen Zeitraum läuft?
- User körperlich beeinträchtigt sind?
- sich rechtliche Rahmenbedingungen ändern?
- Hilfsfunktionen, um Annahmen zu überprüfen (assert)
- Verhalten anderer Programmteile nachahmen (mock)
- mehrere Tests gruppieren und getrennt ausführen
- Suites: gemeinsame Funktion
- Fixtures: gemeinsame Daten
- Tests unterbrechungsfrei durchführen
- anpassbares, anschauliches und exportierbares Logging
Beispiele: JUnit/Mockito (Java) und GoogleTest (C)
...am Anfang war der Test...
Red | Was soll der Code tun? Passenden Test entwerfen und ausführen -> Test sollte fehlschlagen |
Green | Code schreiben, bis der zugehörige Test das gewünschte Verhalten bestätigt |
Refactor | den Code vereinfachen, optimieren, etc. und nach jeder Veränderung den Test erneut ausführen |
-> diesen Ablauf für jede weitere Anforderung wiederholen
int isPalindrome(char str[]) {
// TODO: implementation
return 0;
}
TEST(PalindromeTestSuite, EmptyString) {
char str[] = "";
int actual = isPalindrome(str);
ASSERT_EQ(actual, 1);
}
// TODO: more tests
printf("Bis hierhin gekommen.");
The most effective debugging tool is still careful thought, coupled with judiciously placed print statements.
Brian Kernighan (Unix for Beginners, 1978)
FILE *fp;
fp = fopen("/tmp/logs.txt", "a");
fprintf(fp, "2022-01-13 11:32:09,458 - basket - ERROR - couldn't add item");
fclose(fp);
- Wichtigkeitsgrade, z.B. debug, info, warn, error (SysLog Severity)
- Zeitstempel
- farbliche Hervorhebungen
- viele Libraries und Cloud-Services verfügbar
- ein Programm unter kontrollierten Bedingungen ausführen
- Ziel: Fehlverhalten ergründen
- für C z.B. GDB
- pausiert das Programm an einer Stelle, um den aktuellen Zustand zu inspizieren (oder zu ändern)
- lässt sich dynamisch an/ausschalten oder loggen
- Variablen: Werte ändern, zur Deklaration springen
- Ausdrücke auswerten
- Ausdrücke/Variablen beobachten
- Speicher inspizieren
-
Kapitel "Testgetriebene Entwicklung" in "Agile Entwicklungspraktiken mit Scrum" https://hds.hebis.de/hlbfu/Record/HEB261342312 (HLB)
-
https://www.jetbrains.com/help/clion/debugging-code.html https://www.jetbrains.com/help/idea/debugging-code.html Debugging Informationen zu CLion und IntelliJ IDEA
Clean Code
- nicht lesbar
- Überraschungsmomente und Verständnisprobleme
- nicht wartbar
- Änderungen erfordern Anpassungen an vielen Stellen
- nicht testbar
- alles hängt mit allem zusammen
- keine Zeit
- "Das Feature brauch ich bis Freitag!"
- "Der Code ist durcheinander, aber da kann ich mich jetzt nicht drum kümmern."
- nicht in die Architektur passende Änderungen
- veraltete Praktiken oder Sprachen
- nicht länger gepflegte Libraries / Frameworks
"Leave the campground cleaner than you found it."
Die folgenden Beispiele sind Anregungen. Ausnahmen bestätigen die Regel.
Variablen, Methoden, Klassen, Pakete, Parameter,...
- eindeutig beschreibend
- unterscheidbar
- aussprechbar
- suchbar
Beispiel: Fortschritt des Downloads in Prozent
downloadProgressInPercent
vs. goal
, progress
, dpip
, d
, 50
...
Moderne IDEs helfen mit Rename-Funktion.
- selbsterklärender Code benötigt keine Kommentare
- keine Wiederholungen
- kein Palaver
- auskommentierten Code nicht einchecken
- sinnvolle Kommentare:
- warnen vor Nicht-Offensichtlichem
- erklären die Absicht
- verdeutlichen Unklarheiten
- Anzahl gering halten
- wenn möglich nicht in place verändern (keine "output arguments")
- Rückgabewerte oder Memberfunktionen nutzen
- nicht als Flag benutzen:
getPrice(boolean discount)
- separate Funktionen erstellen:
getPrice()
getPriceWithDiscount()
- separate Funktionen erstellen:
- semantischer Zusammenhang durch räumliche Nähe
- Hierarchie durch Einrückung
- Lesbarkeit durch horizontale Grenzen
- Verständlichkeit durch Stringenz/Konventionen
double price = 50 * 1.19;
besser so:
double VAT_GERMANY = 0.19;
double netValue = 50;
double price = netValue * (1 + VAT_GERMANY);
return PI * r * r * h / 3.0;
besser so:
double baseArea = PI * radius * radius;
return baseArea * height / 3.0;
// nicht kryptisch
while (a > b && !(c || d) || a != f) { ... }
// sondern erklärend
while (has2GPlusStatus()) { ... }
Negation und doppelte Verneinung vermeiden:
if (!notVaccinated) { ... }
// besser so:
if (vaccinated) { ... }
RPS choice = STONE;
if (opponent == STONE) {
choice = PAPER;
} else if (opponent == PAPER) {
choice = SCISSORS;
}
return choice;
// besser: keine koppelnde Laufvariable "choice"
if (opponent == STONE) {
return PAPER;
if (opponent == PAPER) {
return SCISSORS;
}
return STONE;
Für Funktionen, Module, Klassen,... gilt: "only one reason to change" (nicht immer trivial festzustellen)
Kann ich...
- Teile der Funktion auslagern?
- Informationen mit Parametern übergeben?
- unerwartete Seiteneffekte verhindern?
git log --format=format: --name-only | egrep -v '^$' | sort | uniq -c | sort -rg | head -10
-> zeige Dateien, die in den meisten Commits auftauchen
Hat der Code in diesen Dateien evtl. mehr als "one reason to change"?
Code, der sich wiederholt, lässt sich schwieriger und fehleranfälliger verändern und warten.
kann subtiler auftreten als simples Copy-Paste:
if (choice == 1) {
difficulty += 2;
} else if (choice == 2) {
difficulty += 4;
}
// besser so:
difficulty += choice * 2;
for (int i = 0; i < sizeof(items) / sizeof(items[0]); i++) {
printf("%llu items\n", sizeof(items) / sizeof(items[0]));
if (i >= sizeof(items) / sizeof(items[0]) / 2) {
// ...
}
}
// besser: Ausdruck zur Bestimmung der Länge als lokale Variable
size_t length = sizeof(items) / sizeof(items[0];
for (int i = 0; i < length); i++) {
printf("%llu items\n", length);
if (i >= length / 2) {
// ...
}
}
- fehlerhafte / veraltete Dokumentation
- keine Infrastruktur (z.B. VCS, Backups)
- keine Coding/Style Standards
- // TODO all over the place
- keine (grünen) Tests
- ignorieren von Warnings/Errors
- allgemein: "Quick/Cheap Fixes" (siehe Abbildung)
- träge: eine Änderung erfordert viele Folgeänderungen
- anfällig: eine Änderung verursacht Fehler an anderen Stellen
- unbeweglich: Teile des Codes können nicht in anderen Projekten wiederverwendet werden
Refactoring bedeutet bestehenden Code so zu verändern, dass mind. eine Eigenschaft verbessert wird:
- Lesbarkeit / Verständlichkeit
- Wartbarkeit
- Fähigkeit für Erweiterungen / Veränderungen
- Effizienz / Performance
Durch Refactoring verändert man den Code, aber nicht das beobachtbare Verhalten des Programms.
- vorhandene Tests bleiben grün
- den Zustand vor dem Refactoring sichern (und ggf. zurückrollen)
- Wie groß ist die Auswirkung der Optimierung an dieser Stelle? (siehe Amdahlsches Gesetz)
- Wird die Optimierung bald obsolet?
- Ist der Aufwand der Optimierung höher als der Ertrag?
Every new line of code you willingly bring into the world is code that has to be debugged, code that has to be read and understood, code that has to be supported. Jeff Atwood
- in einem Schritt ausführbar:
- Builds, z.B. mit Build Systemen
- Tests, z.B. mit Testing Frameworks
- eigene Entwicklungsumgebung portierbar, z.B. mit Dotfiles
-
Buch: "Clean Code" (Beispiele in Java) https://hds.hebis.de/hlbfu/Record/HEB366074660 (HLB)
-
Sammlung von Refactoring Praktiken und Design Patterns https://refactoring.guru/
-
GitHub Action, die auf Clean Code Vorschläge prüft https://github.com/marketplace/better-code-hub
Wiederholung / Projekt
Free and Open Source Software