Übungsaufgaben zu Clean Code: Code Smells, Werte, Kopplung und Kohäsion
https://bildung.social/@oerinformatik/
https://oer-informatik.de/clean-code-uebungsaufgaben
Clean Code, Code Smell, Kopplung, Kohäsion, Code-Review, KI-Assistent, Übungsaufgaben, Prüfungsvorbereitung
tl/dr; (Bearbeitungszeit insgesamt 37 min, mehrere Aufgaben): Zwei Übungsaufgaben zum Einstieg in Clean Code: Du findest Code Smells in der Buchungssoftware eines Barcamps, ordnest Prinzipien und Werte zu, vergleichst zwei Entwürfe eines Onlineshops nach Kopplung und Kohäsion und entwickelst eine Checkliste für das Review von KI-generiertem Code [AI-Assisted]. (Zuletzt geändert am 09.11.2026)
Disclaimer: Teile des Textes stammen von einer KI. Inhalte sind nicht automatisch zuverlässig; überprüfe Fakten und zitiere vertrauenswürdige Quellen.
Diese Übungsaufgaben gehören zum Artikel Clean Code: Werte, Kopplung und Kohäsion, Code Smells, Prinzipien und Praktiken im Überblick.
Hinweise zur Bearbeitung: Bis zur Teil-1-Prüfung der IT-Berufe solltest Du die Basiskompetenz beherrschen, also Aufgabe 1.1. Als FIA musst Du zur Teil-2-Prüfung Aufgaben auf Kernkompetenz-Ebene lösen können, das ist Aufgabe 2.1. Die Codeausschnitte stehen in Java und Python; wähle die Sprache, die Du gerade lernst. Achte auf die Operatoren: „Nenne“ verlangt Begriffe ohne Erklärung, „Beurteile“ und „Begründe“ verlangen eine Aussage mit nachvollziehbarer Begründung am Code. Schreib Deine Lösung zuerst vollständig auf, bevor Du die Beispiellösung aufklappst.
Du möchtest eigene Aufgaben zum Üben von einem KI-Sprachmodell generieren lassen?
Kopiere den Text in ein KI-Sprachmodell Deiner Wahl und passe Kompetenzstufe, Anzahl, Bearbeitungszeit und Szenario bei Bedarf an. Wie die Aufgaben aufgebaut sind, beschreibt der Artikel Wie sind die Aufgaben aufgebaut?. Prüfe die Ergebnisse mit dem Lehrartikel: KI-Sprachmodelle machen Fehler.
Erstelle neue Übungsaufgaben zum Thema „Clean Code: Code Smells, Werte,
Kopplung und Kohäsion“.
Bauplan: Halte Dich an Aufbau, Kompetenzstufen, Operatoren,
Anforderungsbereiche, Punkte und Zeitschätzung, die im Artikel
https://oer-informatik.de/aufgaben-aufbau beschrieben sind.
Fachliche Grundlage:
- https://oer-informatik.de/clean-code
- https://oer-informatik.de/lesbarer-code
- https://oer-informatik.de/teststrategie
- Stilbeispiel: https://oer-informatik.de/clean-code-uebungsaufgaben
Die Aufgaben sollen Inhalte zu diesen Schlagwörtern abdecken:
- Clean Code
- Code Smell
- Kopplung
- Kohäsion
- Code-Review
- KI-Assistent
Kompetenzstufe: Basiskompetenz (alternativ: Kernkompetenz, Profilkompetenz, Expertise)
Anzahl: 1 Aufgabe mit Teilaufgaben
Bearbeitungszeit in Minuten ca.: <5 bis 30 min>
Szenario: eines der Szenarien aus dem Bauplan
Vorgehen:
1. Lies zuerst die verlinkten Artikel. Kannst Du keine Webseiten
abrufen, sag mir das, statt zu raten.
2. Steht bei einer Angabe noch ein Platzhalter in <…>, frag mich
zuerst danach. Richte Punkte und Zahl der Teilaufgaben nach der
Bearbeitungszeit (ca. 0,9 min je Punkt).
3. Gib je Aufgabe Titel mit Kompetenzstufe, Ausgangssituation und
Teilaufgaben mit Operator und Punktzahl aus, dazu die geschätzte
Bearbeitungszeit.
4. Gib die Beispiellösungen mit Punkteverteilung erst aus, wenn ich
danach frage.
Aufgabe 1.1: Code Smells in der Barcamp-Software (Basiskompetenz)
(ca. 17 min Bearbeitungszeit)
Am DBH-Berufskolleg entwickelt ein Team von Schüler*innen die Web-App für das Barcamp „Lernen.Digital.Leben 2027“. Mia Schröder, Auszubildende Fachinformatikerin Anwendungsentwicklung, soll vor der Einführung von Pair Programming einen Ausschnitt des Buchungsdienstes durchsehen. Teilnehmende buchen damit Plätze in Sessions mit begrenzter Platzzahl; in den Werkstatträumen von Gebäude C gilt aus Sicherheitsgründen eine niedrigere Obergrenze. Die Klasse funktioniert, die Tests sind grün.
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
class Raum {
String bezeichnung;
String gebaeude;
int plaetze;
Raum(String bezeichnung, String gebaeude, int plaetze) {
this.bezeichnung = bezeichnung;
this.gebaeude = gebaeude;
this.plaetze = plaetze;
}
}
class Buchungen {
Map<Integer, List<String>> l = new HashMap<>();
List<String> ausgang = new ArrayList<>();
// bucht
boolean b(int sid, String mail, Raum r) {
l.putIfAbsent(sid, new ArrayList<>());
int m = r.plaetze;
if (r.gebaeude.equals("C")) {
m = 20;
}
if (l.get(sid).size() < m) {
l.get(sid).add(mail);
ausgang.add("An: " + mail + "\nSession " + sid + " in " + r.bezeichnung + ": Platz gebucht");
return true;
}
ausgang.add("An: " + mail + "\nSession " + sid + " in " + r.bezeichnung + ": leider ausgebucht");
return false;
}
String raumtext(Raum r) {
return r.bezeichnung + " (Gebäude " + r.gebaeude + ", " + r.plaetze + " Plätze)";
}
}a) Nenne vier verschiedene Code Smells, die im Ausschnitt vorkommen, und gib jeweils die Stelle im Code an. (8 Punkte)
| Code Smell | Stelle im Code |
|---|---|
| Code Smell | Stelle im Code |
|---|---|
| rätselhafte Namen | Methode b, Parameter sid, r, Variable m, Attribut l |
| magische Zahl und versteckte Regel | 20 und "C" in b: Obergrenze für Werkstatträume ohne Namen und Erklärung |
| doppelter Code | Aufbau des Mailtextes in b steht zweimal fast gleich da (gebucht/ausgebucht) |
| Feature Envy | raumtext nutzt nur Daten von Raum und gehört in die Klasse Raum |
| nichtssagender Kommentar | // bucht bzw. # bucht wiederholt nur den (schlechten) Namen |
| Methode mit mehreren Aufgaben (Ansatz zur langen Methode) | b prüft Platzzahl, speichert die Buchung und erzeugt Nachrichten |
Je richtig benanntem Smell mit passender Stelle 2 Punkte (1 Punkt für den Smell, 1 Punkt für die Stelle), höchstens 8 Punkte. Andere stichhaltige Smells (z. B. öffentliche Attribute, Rückgabe nur als Wahrheitswert) zählen ebenfalls.
b) Ordne die folgenden Prinzipien der Ebene zu, auf der sie vorrangig wirken: Ausdruck, Methode, Klasse, Klassenbeziehung oder Entwurf. (6 Punkte)
| Prinzip | Ebene |
|---|---|
| sprechende Namen | |
| Single Level of Abstraction (SLA) | |
| Information Hiding | |
| Liskov Substitution Principle (LSP) | |
| Design before Implementation | |
| Fail fast |
| Prinzip | Ebene |
|---|---|
| sprechende Namen | Ausdruck |
| Single Level of Abstraction (SLA) | Methode |
| Information Hiding | Klasse |
| Liskov Substitution Principle (LSP) | Klassenbeziehung |
| Design before Implementation | Entwurf |
| Fail fast | Methode |
Je richtiger Zuordnung 1 Punkt.
c) Im Team fallen die folgenden Sätze. Ordne jedem Satz den Wert der Clean-Code-Developer-Initiative zu, um den es vorrangig geht (Wandelbarkeit, Korrektheit, Produktionseffizienz oder Reflexion). (4 Punkte)
Hannah Klein: „Wenn die Schulleitung die Obergrenze für Gebäude C ändert, will ich das an genau einer Stelle anpassen.“
Emre Aksoy: „Ich will sicher sein, dass niemand eine Session bucht, die schon voll ist.“
Mia Schröder: „Nach jedem Sprint nehmen wir uns eine Viertelstunde und besprechen, was uns aufgehalten hat.“
Dimitrios Papadopoulos: „Die Tests sollen bei jedem Hochladen ins Repository automatisch laufen, damit niemand sie von Hand starten muss.“
Wandelbarkeit: Änderungen an einer Regel sollen nur eine Stelle betreffen.
Korrektheit: Die Software soll die fachliche Regel sicher einhalten.
Reflexion: Das Team verbessert regelmäßig seine Arbeitsweise.
Produktionseffizienz: Automatisierung spart wiederholte Handarbeit.
Je richtiger Zuordnung 1 Punkt.
Aufgabe 2.1: Zwei Entwürfe für den Gutschein (Kernkompetenz)
(ca. 20 min Bearbeitungszeit)
Im IT-Team der CSB-Rad GmbH soll der Onlineshop Gutscheincodes verarbeiten. Für den Code KURIER10 gibt es 10 % Rabatt auf den Warenwert, kaufmännisch auf ganze Cent gerundet; alle Beträge werden in Cent gespeichert. Jannik Wolters hat einen KI-Assistenten um einen Vorschlag gebeten und Entwurf A erhalten. Du hast Entwurf B selbst geschrieben. Beide Entwürfe liefern für dieselbe Bestellung (Bügelschloss 62,18 € und Rahmenschloss 41,18 €, Code KURIER10) einen Rabatt von 1034 Cent.
Entwurf A (vom KI-Assistenten):
import java.util.ArrayList;
import java.util.List;
class Bestellung {
List<Object[]> positionen = new ArrayList<>(); // {artikelnr, nettopreisCent, menge}
String gutscheincode;
}
class Kasse {
int rabattCent(Bestellung bestellung) {
int warenwert = 0;
for (Object[] p : bestellung.positionen) {
warenwert += (int) p[1] * (int) p[2];
}
if ("KURIER10".equals(bestellung.gutscheincode)) {
return (warenwert * 10 + 50) / 100;
}
return 0;
}
String alsEuroText(int cent) {
return String.format("%d,%02d EUR", cent / 100, cent % 100);
}
String newsletterText(String email) {
return "An: " + email + "\nNeu im Shop: Lastenräder nach Maß";
}
}Entwurf B (Deine Fassung):
import java.util.List;
record Position(String artikelnr, int nettopreisCent, int menge) {}
class Gutschein {
private final String code;
private final int prozent;
Gutschein(String code, int prozent) {
this.code = code;
this.prozent = prozent;
}
int rabattCent(int warenwertCent) {
return (warenwertCent * prozent + 50) / 100; // kaufmännisch gerundet
}
}
class Bestellung {
private final List<Position> positionen;
private final Gutschein gutschein; // darf null sein
Bestellung(List<Position> positionen, Gutschein gutschein) {
this.positionen = List.copyOf(positionen);
this.gutschein = gutschein;
}
int warenwertCent() {
int summe = 0;
for (Position p : positionen) {
summe += p.nettopreisCent() * p.menge();
}
return summe;
}
int rabattCent() {
if (gutschein == null) {
return 0;
}
return gutschein.rabattCent(warenwertCent());
}
}a) Beurteile, welcher Entwurf loser gekoppelt ist. Begründe Deine Antwort an zwei konkreten Stellen im Code. (4 Punkte)
Entwurf B ist loser gekoppelt.
In Entwurf A kennt
Kasseden inneren Aufbau der Bestellung: Sie liest die öffentliche Listepositionenund weiß, dass Preis und Menge an Index 1 und 2 eines Arrays bzw. an Position 2 und 3 eines Tupels stehen. Ändert sich die Datenstruktur, mussKassemitgeändert werden. In Entwurf B sind die Positionen privat; nurBestellungselbst kennt sie.In Entwurf A liest
Kasseden Gutscheincode als Zeichenkette aus der Bestellung und vergleicht ihn selbst mit"KURIER10". In Entwurf B hängtBestellungnur von der OperationrabattCent(...)bzw.rabatt_cent(...)des Gutscheins ab und übergibt dabei einen einzelnen Wert (Datenkopplung).
Bewertung: Entscheidung mit Begründung 1 Punkt, je stichhaltige Stelle 1,5 Punkte.
b) Beurteile die Kohäsion der Klassen Kasse (Entwurf A) und Gutschein (Entwurf B). (4 Punkte)
Kasse hat eine geringe Kohäsion: Sie berechnet Rabatte, formatiert Geldbeträge und baut Newsletter-Texte. Die drei Methoden nutzen keine gemeinsamen Daten und hätten verschiedene Gründe, sich zu ändern (Rabattregeln, Darstellung von Beträgen, Marketing). Das ist zufällige Kohäsion, ein typisches Merkmal von Sammelklassen.
Gutschein hat eine hohe Kohäsion: Die Klasse hat genau eine Aufgabe (den Rabatt eines Gutscheins berechnen), und ihre Methode arbeitet mit ihrem eigenen Attribut prozent.
Bewertung: je Klasse 1 Punkt für die Einstufung und 1 Punkt für die Begründung.
c) Sophie Bertram plant für das Frühjahr einen zweiten Gutschein FRUEHLING5 mit 5 % Rabatt. Außerdem sollen Positionen künftig eine Bezeichnung enthalten. Beschreibe für beide Entwürfe, welche Stellen dafür geändert werden müssen, und ordne das Ergebnis einem Wert der Clean-Code-Developer-Initiative zu. (4 Punkte)
Entwurf A: Für den neuen Code muss die Methode
rabattCentbzw.rabatt_centder Kasse um eine weitere Abfrage mit neuer magischer Zahl erweitert werden. Für die Bezeichnung ändert sich das Array bzw. Tupel der Positionen; alle Stellen, die mit Indizes bzw. Entpacken darauf zugreifen (hier die Kasse, im ganzen Shop vermutlich weitere), müssen angepasst werden.Entwurf B: Der neue Gutschein ist nur ein weiteres Objekt
Gutschein("FRUEHLING5", 5); die Rabattberechnung bleibt unverändert (die Zuordnung Code → Gutschein liegt an einer Stelle außerhalb der gezeigten Klassen). Die Bezeichnung wird als neues Feld imrecordbzw. in derdataclassPositionergänzt;BestellungundGutscheinbleiben unberührt, nur die Stellen, die Positionen erzeugen, bekommen den neuen Wert.Der Vergleich betrifft den Wert Wandelbarkeit: Entwurf B lässt sich mit weniger und besser eingegrenzten Änderungen anpassen.
Bewertung: je Entwurf 1,5 Punkte, Wert 1 Punkt.
d) Jannik möchte KI-Vorschläge künftig vor der Übernahme gemeinsam prüfen. Erstelle eine Checkliste mit sechs Prüfpunkten für das Review von KI-generiertem Code. Formuliere jeden Prüfpunkt als Frage und nenne kurz, welches Problem er verhindern soll. Beziehe mindestens zwei Prüfpunkte auf Mängel, die Du in Entwurf A findest. (6 Punkte)
| Prüfpunkt | verhindert |
|---|---|
| Verstehen wir jede Zeile und können sie erklären? | Code, den niemand im Team warten kann |
| Gibt es Tests für die fachlichen Regeln und Randfälle (Rundung, leere Bestellung, unbekannter Code)? | scheinbar korrekten Code mit Fehlern in Sonderfällen |
| Greift der Code auf Interna anderer Klassen zu (öffentliche Listen, Array-Indizes)? | enge Kopplung (in Entwurf A: positionen mit Index 1 und 2) |
| Hat jede neue Klasse genau eine Aufgabe? | Sammelklassen mit geringer Kohäsion (in Entwurf A: Kasse mit Newsletter-Text) |
| Gibt es die Funktion schon im Projekt (z. B. eine Formatierung von Geldbeträgen)? | doppelten Code |
| Sind Zahlen und Codes benannt und an einer Stelle hinterlegt? | magische Zahlen und verstreute Regeln (in Entwurf A: "KURIER10", 10, 50) |
| Gibt es alle verwendeten Bibliotheken und Methoden wirklich, und ist ihre Lizenz geklärt? | erfundene oder unsichere Abhängigkeiten |
| Werden Eingaben geprüft und keine Zugangsdaten oder personenbezogenen Daten preisgegeben? | Sicherheits- und Datenschutzlücken |
Je sinnvollem Prüfpunkt mit passender Begründung 1 Punkt, höchstens 6 Punkte; fehlt der Bezug zu Entwurf A, höchstens 5 Punkte.
e) Entwurf A besteht den vorhandenen Test für den Gutscheincode. Erläutere an zwei Stellen aus Entwurf A, warum ein grüner Test allein nicht genügt, um einen KI-Vorschlag zu übernehmen. Beschreibe außerdem, wie das Team auch kleine KI-Vorschläge mit wenig Aufwand absichern kann. (4 Punkte)
Der Test prüft nur das Ergebnis 1034 Cent für eine Bestellung. Er sagt nichts darüber, dass
Kasseüber die öffentliche Liste und feste Indizes bzw. das Entpacken eines Tupels in die Bestellung greift. Die enge Kopplung fällt erst auf, wenn sich die Positionen ändern, und dann scheitern viele Stellen gleichzeitig.Die Methode
newsletterTextbzw.newsletter_texthat mit dem Rabatt nichts zu tun. Kein Test bemerkt, dass die Klasse dadurch zur Sammelklasse mit geringer Kohäsion wird; ebenso wenig die magische Zahl und der fest eingetragene Code"KURIER10".Weitere mögliche Punkte: Randfälle wie eine leere Bestellung oder ein unbekannter Code sind nicht getestet; der Code formatiert Geldbeträge vielleicht doppelt zu einer vorhandenen Methode.
Absichern mit wenig Aufwand: Jeden Vorschlag kurz nach der Checkliste aus d) durchsehen (bei wenigen Zeilen in Minuten erledigt), für neue Regeln eigene Tests ergänzen, den Vorschlag als eigenen Commit übernehmen und die statische Codeanalyse in der CI mitlaufen lassen.
Bewertung: je erläuterter Stelle 1 Punkt, Vorgehen zum Absichern 2 Punkte.
Links und weitere Informationen
Clean Code: Werte, Kopplung und Kohäsion, Code Smells, Prinzipien und Praktiken im Überblick
Lesbarer Code (nächster Artikel der Reihe)
Hinweis zur Nachnutzung als Open Educational Resource (OER)
Dieser Artikel und seine Texte, Bilder, Grafiken, Code und sonstiger Inhalt sind - sofern nicht anders angegeben - lizenziert unter CC BY 4.0. Nennung gemäß TULLU-Regel bitte wie folgt: “Übungsaufgaben zu Clean Code: Code Smells, Werte, Kopplung und Kohäsion” von oer-informatik.de (H. Stein), Lizenz: CC BY 4.0. Der Artikel wurde unter https://oer-informatik.de/clean-code-uebungsaufgaben veröffentlicht, die Quelltexte sind in weiterverarbeitbarer Form verfügbar im Repository unter https://gitlab.com/oer-informatik/design-prinzipien/clean-code. Erstellt mit KI-Assistenz; von mir umfassend redaktionell überarbeitet, geprüft und freigegeben. Stand: 09.11.2026.
[Kommentare zum Artikel lesen, schreiben] / [Artikel teilen] / [gitlab-Issue zum Artikel schreiben]
