<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="de">
	<id>https://mletkin.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ullrich</id>
	<title>MimiPedia - Benutzerbeiträge [de]</title>
	<link rel="self" type="application/atom+xml" href="https://mletkin.net/api.php?action=feedcontributions&amp;feedformat=atom&amp;user=Ullrich"/>
	<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Spezial:Beitr%C3%A4ge/Ullrich"/>
	<updated>2026-05-19T16:08:09Z</updated>
	<subtitle>Benutzerbeiträge</subtitle>
	<generator>MediaWiki 1.39.4</generator>
	<entry>
		<id>https://mletkin.net/index.php?title=Builder:Motivation&amp;diff=211</id>
		<title>Builder:Motivation</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Builder:Motivation&amp;diff=211"/>
		<updated>2025-02-26T07:28:17Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Fluent Interfaces */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Java]]&lt;br /&gt;
[[Kategorie:Builder]]&lt;br /&gt;
= Motivation =&lt;br /&gt;
&lt;br /&gt;
Ber Begriff &amp;quot;Builder&amp;quot; tritt wohl zum ersten Mal im &amp;quot;Design Patterns&amp;quot;-Buch der Gang of Four auf.&lt;br /&gt;
Die Absicht des Builder Pattern wird dort definiert durch:&lt;br /&gt;
:Separate the construction of a complex object from its representation&amp;lt;br&amp;gt;&lt;br /&gt;
:so that the same construction process can create different representations&lt;br /&gt;
&lt;br /&gt;
Es geht dort also um die Trennung von Konstruktion und Repräsentation. Ein wesentlicher Aspekt&lt;br /&gt;
dabei ist die Anforderung &#039;&#039;verschiedene&#039;&#039; Repräsentationen aus dem Ergebnis des selben&lt;br /&gt;
Konstruktionsprozesses zu erzeugen. Als Beispiel führt das Buch die Konstruktion eines Textes an,&lt;br /&gt;
der dann in unterschiedliehen Formaten ausgegeben werden kann.&lt;br /&gt;
&lt;br /&gt;
Auch wenn solche Probleme in der Praxis durchaus vorkommen, hat sich der Builder-Begriff davon mittlerweile losgelöst.&lt;br /&gt;
Die meisten Beschreibungen verzichten auf den zweiten Aspekt -- die Erzeugung der Repräsentationen --&lt;br /&gt;
und beschränken sich auf die Konstruktion. In diesem Sinne solle der Builder auch in diesem Pamphlet verstanden&lt;br /&gt;
werden. Es geht also um die Trennung der Konstruktion von der Verarbeitung des erzeugten Objekts.&lt;br /&gt;
Dem Builder geht es dabei ausschließlich um die Konstruktion und die Manipulation der Objekt;&lt;br /&gt;
was -- insbesondere fachlich -- weiter mit dem Objektgeschieht, interessiert den Builder nicht.&lt;br /&gt;
&lt;br /&gt;
== Paradigmen ==&lt;br /&gt;
Sucht man im Web nach dem Begriff &amp;quot;objektorientiert&amp;quot; so findet man allerhand, nur keine Definition;&lt;br /&gt;
nicht einmal ein Konsens darüber was OO eigentlich sein soll findet man.&lt;br /&gt;
Eine der ersten Sprachen die &amp;quot;Objekte&amp;quot; eingeführt hat, war [https://en.wikipedia.org/wiki/Simula SIMULA-67].&lt;br /&gt;
Wie der Name suggeriert, ist SIMULA im Umfeld von software-gestützten Simulationen entstanden in denen mehr oder weniger&lt;br /&gt;
selbständige &amp;quot;Dinge&amp;quot; mit einander interagieren. Die Definition von Grady Booth für das objektorienterte Design enstammt&lt;br /&gt;
der realen Welt, nicht der Programmierung; die Eigenschaften treffen jedoch auch beide zu. Demnach hat eine Objekt&lt;br /&gt;
* eine Identität&lt;br /&gt;
* einen (inneren) Zustand&lt;br /&gt;
* eine definiertes Verhalten&lt;br /&gt;
Das Objekt tackert damit Daten und Funktionen die damit arbeiten zusammen. Objekte &amp;quot;leben&amp;quot; über einen längeren Zeitraum&lt;br /&gt;
und verändern sich dabei. Seit dem Aufkommen in den 1990ern ist &amp;quot;Objektorientierung&amp;quot; das führende Paradigma,&lt;br /&gt;
tatsächlich zeichnet sich seit einiger Zeit eine Änderung des Trends ab. Massive Parallelität in allen Bereichen -- vom&lt;br /&gt;
Prozessor bis zum globalen Web führen immer wieder zu Problemen, weil die Daten im Objekt nicht für den parallelen Zugriff&lt;br /&gt;
vorgesehen sind. Auch wenn SOA kein moderner Begriff mehr ist, ist der Service zum Mantra der Gegenwart geworden.&lt;br /&gt;
Die Vorstellung eines Ablaufs, der gestartet und beendet wird, Eingaben aufnimmt und daraus ein Ergebnis berechnet;&lt;br /&gt;
unabhängig vom Rest der Welt, mit einer Lebensdauer von Millisekunden -- das ist das Gegenteil eines Objekts.&lt;br /&gt;
&lt;br /&gt;
Auch der Builder bricht mit dem OO-Paradigma indem er die Daten von ihrer Manipulation trennt.&lt;br /&gt;
Im Grunde genommen läßt sich die Verarbeitung von Daten nicht zufriedenstellend in der OO-Welt abbilden.&lt;br /&gt;
Eine Überweisung führt sich nicht selbst aus. Sie ist ein Auftrag, der im Rahmen eines Prozesses ausgeführt wird.&lt;br /&gt;
Die Überweisungs-Daten müssen also vom inneren Zustand der Überweisungsmaschine gertrennt werden. Die Maschine&lt;br /&gt;
mag ein Objekt sein, die Überweisungsdaten bilden keines; für sie ist das Datenstruktur- oder Datentyp-Modell angemessener.&lt;br /&gt;
&lt;br /&gt;
Folgt man diesem Gedankenm, führt das zum Konzept das typisierten funktionalen Programmiersprachen zugrunde liegt.&lt;br /&gt;
&lt;br /&gt;
== Die integrierte Factory ==&lt;br /&gt;
Im Pattern-Buch taucht &#039;&#039;die&#039;&#039; Factory als Pattern nicht auf. Statt dessen giebt es zwei speziellere Pattern&lt;br /&gt;
&amp;quot;Abstract Factory&amp;quot; und &amp;quot;Factory Method&amp;quot; deren Definition hier nicht wiederholt weren soll.&lt;br /&gt;
Stellen wir uns statt dessen die Frage: Was möchten wir unter einer &#039;&#039;Factory&#039;&#039; verstehen?&lt;br /&gt;
&lt;br /&gt;
Die kürzestmögliche Definition ist:&lt;br /&gt;
:Eine Factory ist ein Ding, das Objekte erzeugt.&lt;br /&gt;
Meistens handelt es sich da um ein Objekt, es kann aber auch eine Funktion oder eine Methode sein.&lt;br /&gt;
&lt;br /&gt;
Die Parametrisierung bzw. Konfigurierbarkeit zur Erzeugung von Objekten &#039;&#039;unterschiedlicher&#039;&#039; Klassen&lt;br /&gt;
ist zwar möglich, aber nicht wesentlich. Dieser Factory-Begriff kann also getrost auf den Builder angewandt&lt;br /&gt;
werden: Ein Builder erzeugt Objekte. Die Klasse des Generats kann für einen&lt;br /&gt;
Builder variieren, muß -- und tut es im allgemeinen -- aber nicht.&lt;br /&gt;
&lt;br /&gt;
Was den Builder von der landläufigen Vorstellung der Factory -- und der Gof&#039;schen factory method -- unterscheidet,&lt;br /&gt;
ist die Tatsache daß beim Builder zur Erzeugung von Objekten mehrere Methoden aufgerufen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Fluent Interfaces ==&lt;br /&gt;
Geprägt wurde der Begriff wohl von Eric Evens; Martin Fowler schreibt darüber 2005 in seinem&lt;br /&gt;
[https://martinfowler.com/bliki/FluentInterface.html Blog].&lt;br /&gt;
Die Idee dahinter ist, Folgen von Methoden-Aufrufen auf Objekte -- die so typisch sind für imperative Sprachen wie Java -- zu ersetzen durch verkettete Methoden-Aufrufe, die die Struktur einer domain specific languange aufweisen.&lt;br /&gt;
Fowlers Beispiel ähnelt nicht zufällig den Buildern wie sie hier beschrieben werden. Im folgenden soll nicht der Artikel nacherzählt werden, vielmehr geht es darum einen Eindruck vom &amp;quot;fluent interface&amp;quot;-Konzept zu geben.&lt;br /&gt;
&lt;br /&gt;
Manchmal werden fluent interfaces auch als Pattern bezeichnet. Das ist -- im ursprünglichen Sinne -- nicht korrekt.&lt;br /&gt;
Ihnen liegt keine fachliche Motivation zugrunde und sie dienen nicht der Lösung irgendeiner Problem-Kategorie.&lt;br /&gt;
Sie sind ein Design-Konzept für Programmier-Interfaces.  &lt;br /&gt;
&lt;br /&gt;
In Java könnte man sich folgenden Code vorstellen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Statement s = new select();&lt;br /&gt;
Fields f = new Fields();&lt;br /&gt;
f.setList(List.of(&amp;quot;x&amp;quot;, &amp;quot;y&amp;quot;, &amp;quot;z));&lt;br /&gt;
s.setFields(f);&lt;br /&gt;
Table t = new Table(&amp;quot;t&amp;quot;);&lt;br /&gt;
s.setTables(t);&lt;br /&gt;
Condition c = new Condition(&amp;quot;x = z&amp;quot;);&lt;br /&gt;
s.setConditions(c)&lt;br /&gt;
}}&lt;br /&gt;
Man kann -- anstelle der Verwendung lokaler Variablen -- die Objekt-Erzeugung inline durchführen,&lt;br /&gt;
aber das macht den Code nicht schöner. Man kommt beim Lesen nicht umhin, den Code sequentiell zu analysieren:&lt;br /&gt;
Erzeugt wird ein Statement, dann wird ein &amp;quot;Field&amp;quot;-Objekt erzeugt, das wird dem Statement&lt;br /&gt;
hinzugefügt, und so fort. Der Eingeweihte erkennt schnell das SQL-Statement das hier konstruiert wird.&lt;br /&gt;
&lt;br /&gt;
Man kann das -- anlehnend an die SQL-Syntax -- auch in Java anders formulieren:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Statement s = new Select() //&lt;br /&gt;
                  .fields(&amp;quot;x&amp;quot;, &amp;quot;y&amp;quot;, &amp;quot;z&amp;quot;) //&lt;br /&gt;
                  .from(new Table(&amp;quot;t&amp;quot;)) //&lt;br /&gt;
                  .where(Condition.equals(&amp;quot;x&amp;quot;, &amp;quot;z&amp;quot;));&lt;br /&gt;
}}&lt;br /&gt;
Anstelle der von einander unabhängigen Setter definiert die {{java|Select}}-Klasse Methoden, die immer wieder das gleiche&lt;br /&gt;
{{java|Select}}-Objekt als Ergebnis liefern. Die DSL die hier definiert wird, entspricht der SQL-Syntax und man kann sich&lt;br /&gt;
vorstellen, daß -- wenn die {{java|where}}-Methode entsprechend modelliert wird -- auch die Definition geschachtelter&lt;br /&gt;
Select-Statements möglich sind.&lt;br /&gt;
&lt;br /&gt;
Das sind denn auch die beiden Elemente der fluent interfaces, die hier wesentlich sind.&lt;br /&gt;
Zunächst einmal das &amp;quot;method chaining&amp;quot;: Man versteht darunter, daß die Methoden-Aufrufe nicht in einzelnene Befehlen&lt;br /&gt;
geschehen -- wie das bei Verwendung von Settern und lokalen Variablen der Fall ist -- sondern in einer (mehr oder weniger langen) &lt;br /&gt;
Kette von aufeinander angewandten Methoden, so daß für die komplette Folge nur ein einziger Befehl&lt;br /&gt;
(gewissermaßen ein einziges Semikolon) benötigt wird.&lt;br /&gt;
&lt;br /&gt;
Das zweite Element ist die Schachtelung. Statt Unter-Objekte in lokalen Variablen abzulegen und dort zu manipulieren,&lt;br /&gt;
werden sie -- wieder in einer einzigen Methoden-Kette erzeugt und dann direkt als Argumente an Methoden übergeben.&lt;br /&gt;
Das ganze Konstrukt erhält dadurch einen eher funktionalen Charakter. Das ist für den &amp;quot;prozeduralen&amp;quot; Java-Hacker&lt;br /&gt;
ein eher ungewohntes und damit befremdliches Konzept.&lt;br /&gt;
&lt;br /&gt;
Ich stand der &amp;quot;fluent interface&amp;quot;-Idee von Anfang an skeptisch gegenüber. Solange die dadurch definierte DSL den Charakter einer formalen&lt;br /&gt;
Sprache hat -- wie das bei SQL der Fall ist -- die einer eindeutig definierten inneren Logik folgt, giebt es eigentlich kein Problem.&lt;br /&gt;
Wenn man aber versucht -- und so wird es vielfach verkauft -- natürliche Sprache darüber nachzubilden wird die Sache schwierig.&lt;br /&gt;
Computer-Programme sind formal und lassen keine Unschärfe zu; das Gegenteil ist ein wesentliches Merkmal natürlicher Sprachen.&lt;br /&gt;
&lt;br /&gt;
Wie kann man nun zusammenfassen inwiefern fluent interfaces bei der Builder-Konstruktion bedeutsam sind?&lt;br /&gt;
&lt;br /&gt;
{{quotation|Der Builder verwendet Method Chaining und Schachtelung, um klassische Anweisungsfolgen durch eine DSL zu ersetzen.}}&lt;br /&gt;
&lt;br /&gt;
Dadurch wird einerseits eine bessere Lesbarkeit und eine bessere Verständlichkeit der zugrundeliegenden Semantik erreicht&lt;br /&gt;
und andererseits boiler plate code gekapselt, der sonst die die Aufmerksamkeit absaugen würde.&lt;br /&gt;
&lt;br /&gt;
== Separation  of Concerns ==&lt;br /&gt;
Wie im Abschnitt &amp;quot;Zugriffs-Kontolle&amp;quot; ausführlicher beschrieben wird, bietet der Builder eine Möglichkeit&lt;br /&gt;
die Zuständigkeiten über Entities so trennen. Das klingt zunächst einmal etwas merkwürdig; welche Zuständigkeiten&lt;br /&gt;
sollte man bei einem Entity -- das selbst keine Logik enthält -- trennen?&lt;br /&gt;
&lt;br /&gt;
Es geht hier um die Trennung von Erzeugung (bzw. Manipulation) des Objekts und dem Zugriff auf den Inhalt.&lt;br /&gt;
Die Idee des immutable Objekts ist Java grundsätzlich fremd, sie widerspricht geradezu der eigentlichen Objekt-Idee.&lt;br /&gt;
Aber tatsächlich haben unveränderliche Objekte in einer multithreading-Umgebung große Vorteile,&lt;br /&gt;
weil sie die Synchronisation stark vereinfachen. Nicht umsonst ist das funktionale Paradigma weiterhin auf dem Vormarsch.&lt;br /&gt;
&lt;br /&gt;
Konsequent durchgezogen, kann das Entity vollständig auf Setter verzichten indem es die Manipulation dem Builder überträgt&lt;br /&gt;
und sich darauf beschränken Daten zu halten und herauszugeben.&lt;br /&gt;
&lt;br /&gt;
== Statisch oder dynamisch? ==&lt;br /&gt;
Das ist für jede Programmiersprache die -- oder zumindest eine -- Gretchenfrage. Was ist damit gemeint?&lt;br /&gt;
Statisch heißt &amp;quot;zur Compile-Zeit&amp;quot;, dynamisch -- oder nicht-statisch -- bezeichnet das Gegenstück, nämlich &amp;quot;zur Laufzeit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wenn Tony Hoare die Einführung von &amp;quot;null&amp;quot; in ALGOL als &amp;quot;billion Dollar mistake&amp;quot; bezeichnet hat, meinte er damit,&lt;br /&gt;
daß die null- oder Ungültigkeitsprüfung optimalerweise zur Compile-Zeit stattfinden sollte. Es giebt mittlerweile&lt;br /&gt;
Sprachen, die Konzepte dafür implementieren -- in Java sind sie nur unzulänglich ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Inwiefern betrifft das den Builder? Bei jeder Prüfung muß man sich fragen, wann diese stattfinden soll.&lt;br /&gt;
Was ist mit Muß-Werten? Kann man das Vorhandensein zur Compile-Zeit prüfen -- was sicherer wäre -- oder soll man&lt;br /&gt;
die Prüfung auf die Laufzeit -- was einfacher wäre -- verlagern? Auf diese spezielle Frage wird später noch eingegangen,&lt;br /&gt;
betrachten wir die Frage etwas allgemeiner: &amp;quot;wann statisch, wann dynamisch&amp;quot;?&lt;br /&gt;
&lt;br /&gt;
Die Antwort lautet: -- wie überraschend -- kommt drauf an...&lt;br /&gt;
&lt;br /&gt;
Grundsätzlich kann man sagen: statische Prüfung ist immer aufwändiger als die dynamische. Definiert an einen einfachen&lt;br /&gt;
Builder mit mehrereren Konfigurations-Methoden, kann man die Methoden in beliebiger Reihenfolge aufrufen; im einfachsten&lt;br /&gt;
Falle sogar mehrfach. Möchte man eine Reihenfolge festlegen, die bereits zur Compile-Zeit eingehalten werden muß ist das&lt;br /&gt;
prinzipiell möglich. es erfordert allerdings zusätzliche Klassen und verursacht Aufwand.&lt;br /&gt;
&lt;br /&gt;
Möchte man zur Compile-Zeit sicher sein, daß Muß-Felder gefüllt sind, geht das nur über (häßliche) Konstruktoren und selbst&lt;br /&gt;
dann hat man nur eingeschränkte Kontrolle darüber, ob die Felder mit brauchbaren Werten gefüllt sind.&lt;br /&gt;
&lt;br /&gt;
Es bleibt also eine Abschätzung: Lohnt sich der Aufwand -- wenn es denn überhaupt geht?&lt;br /&gt;
&lt;br /&gt;
Der Aldi-Tip: Mach&#039;s dynamisch und schreib&#039; viele Unit-Tests.&lt;br /&gt;
&lt;br /&gt;
== Migration/Versionierung ==&lt;br /&gt;
Die Separation von Datenspeicherung -- im Entity -- und Manipulation -- im Builder -- macht es einfacher,&lt;br /&gt;
zwischen unterschiedlichen Versionen von Entities zu unterscheiden, diese zu erzeugen und Migration von&lt;br /&gt;
Daten zwischen Versionen durchzuführen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Builder:Motivation&amp;diff=210</id>
		<title>Builder:Motivation</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Builder:Motivation&amp;diff=210"/>
		<updated>2025-02-26T07:26:50Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Fluent Interfaces */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Java]]&lt;br /&gt;
[[Kategorie:Builder]]&lt;br /&gt;
= Motivation =&lt;br /&gt;
&lt;br /&gt;
Ber Begriff &amp;quot;Builder&amp;quot; tritt wohl zum ersten Mal im &amp;quot;Design Patterns&amp;quot;-Buch der Gang of Four auf.&lt;br /&gt;
Die Absicht des Builder Pattern wird dort definiert durch:&lt;br /&gt;
:Separate the construction of a complex object from its representation&amp;lt;br&amp;gt;&lt;br /&gt;
:so that the same construction process can create different representations&lt;br /&gt;
&lt;br /&gt;
Es geht dort also um die Trennung von Konstruktion und Repräsentation. Ein wesentlicher Aspekt&lt;br /&gt;
dabei ist die Anforderung &#039;&#039;verschiedene&#039;&#039; Repräsentationen aus dem Ergebnis des selben&lt;br /&gt;
Konstruktionsprozesses zu erzeugen. Als Beispiel führt das Buch die Konstruktion eines Textes an,&lt;br /&gt;
der dann in unterschiedliehen Formaten ausgegeben werden kann.&lt;br /&gt;
&lt;br /&gt;
Auch wenn solche Probleme in der Praxis durchaus vorkommen, hat sich der Builder-Begriff davon mittlerweile losgelöst.&lt;br /&gt;
Die meisten Beschreibungen verzichten auf den zweiten Aspekt -- die Erzeugung der Repräsentationen --&lt;br /&gt;
und beschränken sich auf die Konstruktion. In diesem Sinne solle der Builder auch in diesem Pamphlet verstanden&lt;br /&gt;
werden. Es geht also um die Trennung der Konstruktion von der Verarbeitung des erzeugten Objekts.&lt;br /&gt;
Dem Builder geht es dabei ausschließlich um die Konstruktion und die Manipulation der Objekt;&lt;br /&gt;
was -- insbesondere fachlich -- weiter mit dem Objektgeschieht, interessiert den Builder nicht.&lt;br /&gt;
&lt;br /&gt;
== Paradigmen ==&lt;br /&gt;
Sucht man im Web nach dem Begriff &amp;quot;objektorientiert&amp;quot; so findet man allerhand, nur keine Definition;&lt;br /&gt;
nicht einmal ein Konsens darüber was OO eigentlich sein soll findet man.&lt;br /&gt;
Eine der ersten Sprachen die &amp;quot;Objekte&amp;quot; eingeführt hat, war [https://en.wikipedia.org/wiki/Simula SIMULA-67].&lt;br /&gt;
Wie der Name suggeriert, ist SIMULA im Umfeld von software-gestützten Simulationen entstanden in denen mehr oder weniger&lt;br /&gt;
selbständige &amp;quot;Dinge&amp;quot; mit einander interagieren. Die Definition von Grady Booth für das objektorienterte Design enstammt&lt;br /&gt;
der realen Welt, nicht der Programmierung; die Eigenschaften treffen jedoch auch beide zu. Demnach hat eine Objekt&lt;br /&gt;
* eine Identität&lt;br /&gt;
* einen (inneren) Zustand&lt;br /&gt;
* eine definiertes Verhalten&lt;br /&gt;
Das Objekt tackert damit Daten und Funktionen die damit arbeiten zusammen. Objekte &amp;quot;leben&amp;quot; über einen längeren Zeitraum&lt;br /&gt;
und verändern sich dabei. Seit dem Aufkommen in den 1990ern ist &amp;quot;Objektorientierung&amp;quot; das führende Paradigma,&lt;br /&gt;
tatsächlich zeichnet sich seit einiger Zeit eine Änderung des Trends ab. Massive Parallelität in allen Bereichen -- vom&lt;br /&gt;
Prozessor bis zum globalen Web führen immer wieder zu Problemen, weil die Daten im Objekt nicht für den parallelen Zugriff&lt;br /&gt;
vorgesehen sind. Auch wenn SOA kein moderner Begriff mehr ist, ist der Service zum Mantra der Gegenwart geworden.&lt;br /&gt;
Die Vorstellung eines Ablaufs, der gestartet und beendet wird, Eingaben aufnimmt und daraus ein Ergebnis berechnet;&lt;br /&gt;
unabhängig vom Rest der Welt, mit einer Lebensdauer von Millisekunden -- das ist das Gegenteil eines Objekts.&lt;br /&gt;
&lt;br /&gt;
Auch der Builder bricht mit dem OO-Paradigma indem er die Daten von ihrer Manipulation trennt.&lt;br /&gt;
Im Grunde genommen läßt sich die Verarbeitung von Daten nicht zufriedenstellend in der OO-Welt abbilden.&lt;br /&gt;
Eine Überweisung führt sich nicht selbst aus. Sie ist ein Auftrag, der im Rahmen eines Prozesses ausgeführt wird.&lt;br /&gt;
Die Überweisungs-Daten müssen also vom inneren Zustand der Überweisungsmaschine gertrennt werden. Die Maschine&lt;br /&gt;
mag ein Objekt sein, die Überweisungsdaten bilden keines; für sie ist das Datenstruktur- oder Datentyp-Modell angemessener.&lt;br /&gt;
&lt;br /&gt;
Folgt man diesem Gedankenm, führt das zum Konzept das typisierten funktionalen Programmiersprachen zugrunde liegt.&lt;br /&gt;
&lt;br /&gt;
== Die integrierte Factory ==&lt;br /&gt;
Im Pattern-Buch taucht &#039;&#039;die&#039;&#039; Factory als Pattern nicht auf. Statt dessen giebt es zwei speziellere Pattern&lt;br /&gt;
&amp;quot;Abstract Factory&amp;quot; und &amp;quot;Factory Method&amp;quot; deren Definition hier nicht wiederholt weren soll.&lt;br /&gt;
Stellen wir uns statt dessen die Frage: Was möchten wir unter einer &#039;&#039;Factory&#039;&#039; verstehen?&lt;br /&gt;
&lt;br /&gt;
Die kürzestmögliche Definition ist:&lt;br /&gt;
:Eine Factory ist ein Ding, das Objekte erzeugt.&lt;br /&gt;
Meistens handelt es sich da um ein Objekt, es kann aber auch eine Funktion oder eine Methode sein.&lt;br /&gt;
&lt;br /&gt;
Die Parametrisierung bzw. Konfigurierbarkeit zur Erzeugung von Objekten &#039;&#039;unterschiedlicher&#039;&#039; Klassen&lt;br /&gt;
ist zwar möglich, aber nicht wesentlich. Dieser Factory-Begriff kann also getrost auf den Builder angewandt&lt;br /&gt;
werden: Ein Builder erzeugt Objekte. Die Klasse des Generats kann für einen&lt;br /&gt;
Builder variieren, muß -- und tut es im allgemeinen -- aber nicht.&lt;br /&gt;
&lt;br /&gt;
Was den Builder von der landläufigen Vorstellung der Factory -- und der Gof&#039;schen factory method -- unterscheidet,&lt;br /&gt;
ist die Tatsache daß beim Builder zur Erzeugung von Objekten mehrere Methoden aufgerufen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Fluent Interfaces ==&lt;br /&gt;
Geprägt wurde der Begriff wohl von Eric Evens; Martin Fowler schreibt darüber 2005 in seinem&lt;br /&gt;
[https://martinfowler.com/bliki/FluentInterface.html Blog].&lt;br /&gt;
Die Idee dahinter ist, Folgen von Methoden-Aufrufen auf Objekte -- die so typisch sind für imperative Sprachen wie Java -- zu ersetzen durch verkettete Methoden-Aufrufe, die die Struktur einer domain specific languange aufweisen.&lt;br /&gt;
Fowlers Beispiel ähnelt nicht zufällig den Buildern wie sie hier beschrieben werden. Im folgenden soll nicht der Artikel nacherzählt werden, vielmehr geht es darum einen Eindruck vom &amp;quot;fluent interface&amp;quot;-Konzept zu geben.&lt;br /&gt;
&lt;br /&gt;
Manchmal werden fluent interfaces auch als Pattern bezeichnet. Das ist -- im ursprünglichen Sinne -- nicht korrekt.&lt;br /&gt;
Ihnen liegt keine fachliche Motivation zugrunde und sie dienen nicht der Lösung irgendeiner Problem-Kategorie.&lt;br /&gt;
Sie sind ein Design-Konzept für Programmier-Interfaces.  &lt;br /&gt;
&lt;br /&gt;
In Java könnte man sich folgenden Code vorstellen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Statement s = new select();&lt;br /&gt;
Fields f = new Fields(&amp;quot;x, y, z&amp;quot;);&lt;br /&gt;
s.setFields(f);&lt;br /&gt;
Tables t = new Tables(&amp;quot;t&amp;quot;);&lt;br /&gt;
s.setTables(t);&lt;br /&gt;
Condition c = new Condition(&amp;quot;x = z&amp;quot;);&lt;br /&gt;
s.setConditions(c)&lt;br /&gt;
}}&lt;br /&gt;
Man kann -- anstelle der Verwendung lokaler Variablen -- die Objekt-Erzeugung inline durchführen,&lt;br /&gt;
aber das macht den Code nicht schöner. Man kommt beim Lesen nicht umhin, den Code sequentiell zu analysieren:&lt;br /&gt;
Erzeugt wird ein Statement, dann wird ein &amp;quot;Field&amp;quot;-Objekt erzeugt, das wird dem Statement&lt;br /&gt;
hinzugefügt, und so fort. Der Eingeweihte erkennt schnell das SQL-Statement das hier konstruiert wird.&lt;br /&gt;
&lt;br /&gt;
Man kann das -- anlehnend an die SQL-Syntax -- auch in Java anders formulieren:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Statement s = new Select() //&lt;br /&gt;
                  .fields(&amp;quot;x&amp;quot;, &amp;quot;y&amp;quot;, &amp;quot;z&amp;quot;) //&lt;br /&gt;
                  .from(new Table(&amp;quot;t&amp;quot;)) //&lt;br /&gt;
                  .where(Condition.equals(&amp;quot;x&amp;quot;, &amp;quot;z&amp;quot;));&lt;br /&gt;
}}&lt;br /&gt;
Anstelle der von einander unabhängigen Setter definiert die {{java|Select}}-Klasse Methoden, die immer wieder das gleiche&lt;br /&gt;
{{java|Select}}-Objekt als Ergebnis liefern. Die DSL die hier definiert wird, entspricht der SQL-Syntax und man kann sich&lt;br /&gt;
vorstellen, daß -- wenn die {{java|where}}-Methode entsprechend modelliert wird -- auch die Definition geschachtelter&lt;br /&gt;
Select-Statements möglich sind.&lt;br /&gt;
&lt;br /&gt;
Das sind denn auch die beiden Elemente der fluent interfaces, die hier wesentlich sind.&lt;br /&gt;
Zunächst einmal das &amp;quot;method chaining&amp;quot;: Man versteht darunter, daß die Methoden-Aufrufe nicht in einzelnene Befehlen&lt;br /&gt;
geschehen -- wie das bei Verwendung von Settern und lokalen Variablen der Fall ist -- sondern in einer (mehr oder weniger langen) &lt;br /&gt;
Kette von aufeinander angewandten Methoden, so daß für die komplette Folge nur ein einziger Befehl&lt;br /&gt;
(gewissermaßen ein einziges Semikolon) benötigt wird.&lt;br /&gt;
&lt;br /&gt;
Das zweite Element ist die Schachtelung. Statt Unter-Objekte in lokalen Variablen abzulegen und dort zu manipulieren,&lt;br /&gt;
werden sie -- wieder in einer einzigen Methoden-Kette erzeugt und dann direkt als Argumente an Methoden übergeben.&lt;br /&gt;
Das ganze Konstrukt erhält dadurch einen eher funktionalen Charakter. Das ist für den &amp;quot;prozeduralen&amp;quot; Java-Hacker&lt;br /&gt;
ein eher ungewohntes und damit befremdliches Konzept.&lt;br /&gt;
&lt;br /&gt;
Ich stand der &amp;quot;fluent interface&amp;quot;-Idee von Anfang an skeptisch gegenüber. Solange die dadurch definierte DSL den Charakter einer formalen&lt;br /&gt;
Sprache hat -- wie das bei SQL der Fall ist -- die einer eindeutig definierten inneren Logik folgt, giebt es eigentlich kein Problem.&lt;br /&gt;
Wenn man aber versucht -- und so wird es vielfach verkauft -- natürliche Sprache darüber nachzubilden wird die Sache schwierig.&lt;br /&gt;
Computer-Programme sind formal und lassen keine Unschärfe zu; das Gegenteil ist ein wesentliches Merkmal natürlicher Sprachen.&lt;br /&gt;
&lt;br /&gt;
Wie kann man nun zusammenfassen inwiefern fluent interfaces bei der Builder-Konstruktion bedeutsam sind?&lt;br /&gt;
&lt;br /&gt;
{{quotation|Der Builder verwendet Method Chaining und Schachtelung, um klassische Anweisungsfolgen durch eine DSL zu ersetzen.}}&lt;br /&gt;
&lt;br /&gt;
Dadurch wird einerseits eine bessere Lesbarkeit und eine bessere Verständlichkeit der zugrundeliegenden Semantik erreicht&lt;br /&gt;
und andererseits boiler plate code gekapselt, der sonst die die Aufmerksamkeit absaugen würde.&lt;br /&gt;
&lt;br /&gt;
== Separation  of Concerns ==&lt;br /&gt;
Wie im Abschnitt &amp;quot;Zugriffs-Kontolle&amp;quot; ausführlicher beschrieben wird, bietet der Builder eine Möglichkeit&lt;br /&gt;
die Zuständigkeiten über Entities so trennen. Das klingt zunächst einmal etwas merkwürdig; welche Zuständigkeiten&lt;br /&gt;
sollte man bei einem Entity -- das selbst keine Logik enthält -- trennen?&lt;br /&gt;
&lt;br /&gt;
Es geht hier um die Trennung von Erzeugung (bzw. Manipulation) des Objekts und dem Zugriff auf den Inhalt.&lt;br /&gt;
Die Idee des immutable Objekts ist Java grundsätzlich fremd, sie widerspricht geradezu der eigentlichen Objekt-Idee.&lt;br /&gt;
Aber tatsächlich haben unveränderliche Objekte in einer multithreading-Umgebung große Vorteile,&lt;br /&gt;
weil sie die Synchronisation stark vereinfachen. Nicht umsonst ist das funktionale Paradigma weiterhin auf dem Vormarsch.&lt;br /&gt;
&lt;br /&gt;
Konsequent durchgezogen, kann das Entity vollständig auf Setter verzichten indem es die Manipulation dem Builder überträgt&lt;br /&gt;
und sich darauf beschränken Daten zu halten und herauszugeben.&lt;br /&gt;
&lt;br /&gt;
== Statisch oder dynamisch? ==&lt;br /&gt;
Das ist für jede Programmiersprache die -- oder zumindest eine -- Gretchenfrage. Was ist damit gemeint?&lt;br /&gt;
Statisch heißt &amp;quot;zur Compile-Zeit&amp;quot;, dynamisch -- oder nicht-statisch -- bezeichnet das Gegenstück, nämlich &amp;quot;zur Laufzeit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wenn Tony Hoare die Einführung von &amp;quot;null&amp;quot; in ALGOL als &amp;quot;billion Dollar mistake&amp;quot; bezeichnet hat, meinte er damit,&lt;br /&gt;
daß die null- oder Ungültigkeitsprüfung optimalerweise zur Compile-Zeit stattfinden sollte. Es giebt mittlerweile&lt;br /&gt;
Sprachen, die Konzepte dafür implementieren -- in Java sind sie nur unzulänglich ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Inwiefern betrifft das den Builder? Bei jeder Prüfung muß man sich fragen, wann diese stattfinden soll.&lt;br /&gt;
Was ist mit Muß-Werten? Kann man das Vorhandensein zur Compile-Zeit prüfen -- was sicherer wäre -- oder soll man&lt;br /&gt;
die Prüfung auf die Laufzeit -- was einfacher wäre -- verlagern? Auf diese spezielle Frage wird später noch eingegangen,&lt;br /&gt;
betrachten wir die Frage etwas allgemeiner: &amp;quot;wann statisch, wann dynamisch&amp;quot;?&lt;br /&gt;
&lt;br /&gt;
Die Antwort lautet: -- wie überraschend -- kommt drauf an...&lt;br /&gt;
&lt;br /&gt;
Grundsätzlich kann man sagen: statische Prüfung ist immer aufwändiger als die dynamische. Definiert an einen einfachen&lt;br /&gt;
Builder mit mehrereren Konfigurations-Methoden, kann man die Methoden in beliebiger Reihenfolge aufrufen; im einfachsten&lt;br /&gt;
Falle sogar mehrfach. Möchte man eine Reihenfolge festlegen, die bereits zur Compile-Zeit eingehalten werden muß ist das&lt;br /&gt;
prinzipiell möglich. es erfordert allerdings zusätzliche Klassen und verursacht Aufwand.&lt;br /&gt;
&lt;br /&gt;
Möchte man zur Compile-Zeit sicher sein, daß Muß-Felder gefüllt sind, geht das nur über (häßliche) Konstruktoren und selbst&lt;br /&gt;
dann hat man nur eingeschränkte Kontrolle darüber, ob die Felder mit brauchbaren Werten gefüllt sind.&lt;br /&gt;
&lt;br /&gt;
Es bleibt also eine Abschätzung: Lohnt sich der Aufwand -- wenn es denn überhaupt geht?&lt;br /&gt;
&lt;br /&gt;
Der Aldi-Tip: Mach&#039;s dynamisch und schreib&#039; viele Unit-Tests.&lt;br /&gt;
&lt;br /&gt;
== Migration/Versionierung ==&lt;br /&gt;
Die Separation von Datenspeicherung -- im Entity -- und Manipulation -- im Builder -- macht es einfacher,&lt;br /&gt;
zwischen unterschiedlichen Versionen von Entities zu unterscheiden, diese zu erzeugen und Migration von&lt;br /&gt;
Daten zwischen Versionen durchzuführen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Kategorie:Builder&amp;diff=209</id>
		<title>Kategorie:Builder</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Kategorie:Builder&amp;diff=209"/>
		<updated>2025-02-24T16:15:32Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
Eine Heranführung in das Thema bietet die Seite [[Builder:Motivation|Motivation]].&lt;br /&gt;
&lt;br /&gt;
Die drei Teile des Builders beschreibt die Seite [[Builder:Komponenten|Komponenten]].&lt;br /&gt;
&lt;br /&gt;
Die zwei Orte an denen man den Builder definieren kann zeigt die Seite [[Builder:Location|Location]].&lt;br /&gt;
&lt;br /&gt;
Näheres über die Erzeugung der Generate bietet die Seite [[Builder:Objekt-Erzeugung]].&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Kategorie:Builder&amp;diff=208</id>
		<title>Kategorie:Builder</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Kategorie:Builder&amp;diff=208"/>
		<updated>2025-02-24T16:15:08Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
Eine Heranführung in das Thema bietet die Seite [[Builder:Motivation|Motivation]].&lt;br /&gt;
&lt;br /&gt;
Die drei Teile des Builders beschreibt die Seite [[Builder:Komponenten|Komponenten]].&lt;br /&gt;
&lt;br /&gt;
Die zwei Orte an denen man den Builder definieren kann zeigt die Seite [[Builder:Location|Location]].&lt;br /&gt;
&lt;br /&gt;
Näheres über die Erzeugung der Generate bietet die Seite [[Builder::Objekt-Erzeugung]].&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Kategorie:Builder&amp;diff=207</id>
		<title>Kategorie:Builder</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Kategorie:Builder&amp;diff=207"/>
		<updated>2025-02-24T16:11:09Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Category:Java“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Builder:Objekt-Erzeugung&amp;diff=206</id>
		<title>Builder:Objekt-Erzeugung</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Builder:Objekt-Erzeugung&amp;diff=206"/>
		<updated>2025-02-24T16:09:57Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Kategorie:Java Kategorie:Builder =Objekt-Erzeugung=  Wann soll das Objekt -- das der Builder bauen soll -- erzeugt werden? Auf diese Frage giebt es zwei Antworten: &amp;quot;Up front&amp;quot; oder &amp;quot;in time&amp;quot;. Für beide Varianten giebt es Argumente, welche man wählt hängt von den Umständen ab. Betrachten wir also beide...  ==Up font== Was so viel heißt: Wir erzeugen das Objekt und füllen die Daten direkt hinein. Die Erzeugung findet entweder bei der Deklaratio…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Java]]&lt;br /&gt;
[[Kategorie:Builder]]&lt;br /&gt;
=Objekt-Erzeugung=&lt;br /&gt;
&lt;br /&gt;
Wann soll das Objekt -- das der Builder bauen soll -- erzeugt werden? Auf diese Frage giebt es&lt;br /&gt;
zwei Antworten: &amp;quot;Up front&amp;quot; oder &amp;quot;in time&amp;quot;. Für beide Varianten giebt es Argumente, welche man wählt&lt;br /&gt;
hängt von den Umständen ab. Betrachten wir also beide...&lt;br /&gt;
&lt;br /&gt;
==Up font==&lt;br /&gt;
Was so viel heißt: Wir erzeugen das Objekt und füllen die Daten direkt hinein.&lt;br /&gt;
Die Erzeugung findet entweder bei der Deklaration des entsprechenden Feldes statt&lt;br /&gt;
oder im Konstruktor des Builders. Zu bevorzugen ist der erste Fall, das kann &lt;br /&gt;
zum Beispiel so aussehen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 Foo foo == new Foo();&lt;br /&gt;
 FooBuilder withName(String name) {&lt;br /&gt;
    foo.setName(name);&lt;br /&gt;
    return this;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Das Objekt das der Builder erzeugt wird erzeugt und von den with-Methoden direkt befüllt.&lt;br /&gt;
Der Vorteil ist ein sehr geringer Overhead, weil kein Zwischenspeicher für gesetzte Werte&lt;br /&gt;
benötigt wird. Die build-Methode kann das Objekt ohne weitere Aktionen ausliefern.&lt;br /&gt;
Wenn es darum geht, Entities zu erzeugen und zu befüllen ist das normalerweise das Mittel der Wahl.&lt;br /&gt;
&lt;br /&gt;
==in time==&lt;br /&gt;
Die Alternative ist, das Objekt erst dann zu erzeugen, wenn es tatsächlich benötigt wird,&lt;br /&gt;
in der Regel geschieht das dann in der build-Methode. Der offensichtliche Nachteil ist,&lt;br /&gt;
daß die with-Methoden ihre Daten nicht direkt in das zu erzeugende Objekt füllen können.&lt;br /&gt;
Es wird ein Buffer -- üblicherweise in Form von Builder-Feldern benötigt:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 private String name;&lt;br /&gt;
 FooBuilder withName(String name) {&lt;br /&gt;
    this.name = name;&lt;br /&gt;
    return this;&lt;br /&gt;
 }&lt;br /&gt;
&lt;br /&gt;
 Foo build() {&lt;br /&gt;
    Foo foo = new Foo();&lt;br /&gt;
    foo.setName(this.name);&lt;br /&gt;
    return foo;&lt;br /&gt;
 &amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
==Wann was?==&lt;br /&gt;
Wie man sieht ist der Aufwand bei der verzögerten Erzeugung spürbar höher als bei der Befüllung des sofort erzeugten Objekt.&lt;br /&gt;
Warum sollte man sich das antun? Man wird sich für die vergögerte Variante in der Regel nur dann entscheiden, wenn es gute&lt;br /&gt;
Gründe für die verzögerte Objekt-Erzeugung giebt. Wenn man etwa das Objekt nur dann anlegen möchte, wenn tatsächlich alle Daten&lt;br /&gt;
vorhanden sind bzw. alle Daten korrekt sind. Oder wenn die Erzeugung des Objektes besonders teuer ist.&lt;br /&gt;
&lt;br /&gt;
Und es giebt einen Fall, in dem es gar nicht anders geht. Nämlich wenn das zu erzeugende Objekt die&lt;br /&gt;
Daten -- oder zumindest einige der Daten -- im Konstruktor verlangt. Diese Variante wird im nächsten Abschnitt beschrieben.&lt;br /&gt;
&lt;br /&gt;
Einen wichtigen Punkt muß man dabei unbedingt berücksichtigen.&lt;br /&gt;
Wird das Objekt sofort erzeugt und von der Abschlußmethode des Builders geliefert, verändert jeder nachfolgende Aufruf&lt;br /&gt;
einer with-Methode des Builders dazu, daß das eben erzeugte Objekt nachträglich verändert wird!&lt;br /&gt;
&lt;br /&gt;
Die verzögerte Erzeugung kann verwendet werden, wenn der Builder als (Massen-)Factory verwendet werden soll.&lt;br /&gt;
Man konfiguriert damit ein Objekt, erzeugt es, verwendet die Konfiguration als Grundlage für das nächste Objekt&lt;br /&gt;
und so fort. &lt;br /&gt;
&lt;br /&gt;
==der Fall des ekelhaften Konstrukturs==&lt;br /&gt;
Ein formidables Beispiel liefert uns freundlicherweise der JDK. Es handelt sich um die Klasse NewCookie.&lt;br /&gt;
Der schlimmste Konstruktur -- es giebt im JDK 1.7 sieben Stück davon -- könnte im Aufruf so aussehen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 cookie = NewCookie(&amp;quot;myCookie&amp;quot;, null, null, 4711, &amp;quot;unused&amp;quot;, 10, null, true, true);&lt;br /&gt;
}}&lt;br /&gt;
Das ist so lesbar wie ansprechend... In diesem Falle bekommt der Builder für jeden Parameter ein Feld&lt;br /&gt;
und eine with-Methode. Erst in der build-Methode erzeugt man den Cookie mit den Werten der Builder-Felder.&lt;br /&gt;
Auf diese Weise werden im Builder-Aufruf nur die erforderlichen Werte gesetzt, die übrigen ggf. mit&lt;br /&gt;
default-Werten vorbelegt und der Benutzer braucht nicht nach dem passenden Konstruktor suchen.&lt;br /&gt;
&lt;br /&gt;
In diesem Falle ist es natürlich auch sinnvoll, in der build-Methode zu prüfen, ob alles da ist was benötigt wird.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Builder:Location&amp;diff=205</id>
		<title>Builder:Location</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Builder:Location&amp;diff=205"/>
		<updated>2025-02-24T16:08:46Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Kategorie:Java Kategorie:Builder =Wohin mit dem Builder?= Es giebt zwei Orte, an dem man den Builder unterbringen kann. Man kann ihn als separate Klasse &amp;#039;&amp;#039;irgendwo&amp;#039; ablegen,&amp;#039;&amp;#039; oder man kann ihn als member class in der Generat-Klasse ansiedeln. Wo man den Builder unterbringt ist  wohl im wesentlichen eine Geschmacksfrage. Hat man keine Möglichkeit die Generat-Klasse zu ändern, bleibt allerdings nur die Möglichkeit, den Builder als separate Klass…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Java]]&lt;br /&gt;
[[Kategorie:Builder]]&lt;br /&gt;
=Wohin mit dem Builder?=&lt;br /&gt;
Es giebt zwei Orte, an dem man den Builder unterbringen kann. Man kann ihn als separate Klasse &#039;&#039;irgendwo&#039; ablegen,&#039;&#039;&lt;br /&gt;
oder man kann ihn als member class in der Generat-Klasse ansiedeln. Wo man den Builder unterbringt ist  wohl im&lt;br /&gt;
wesentlichen eine Geschmacksfrage. Hat man keine Möglichkeit die Generat-Klasse zu ändern, bleibt allerdings nur&lt;br /&gt;
die Möglichkeit, den Builder als separate Klasse zu implementieren.&lt;br /&gt;
&lt;br /&gt;
==Der Builder als eigene Klasse==&lt;br /&gt;
Eigentlich giebt es hierzu nicht viel zu sagen, der Aufbau des Builder ist ziemlich simpel. nehmen wir als Beispiel&lt;br /&gt;
folgende Klasse als Beispiel:&lt;br /&gt;
{{java|code=&lt;br /&gt;
class Person {&lt;br /&gt;
   private String vorname;&lt;br /&gt;
   public String getVorname() {&lt;br /&gt;
      return vorname;&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   public String setVorname(String vorname) {&lt;br /&gt;
      this.vorname = vorname;&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
dann sieht der Builder dazu so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
class PersonBuilder {&lt;br /&gt;
   private Person person = new Person();&lt;br /&gt;
&lt;br /&gt;
   public PersonBuilder withVorname(String vorname) {&lt;br /&gt;
      person.setVorname(vorname);&lt;br /&gt;
      return this;&lt;br /&gt;
   }&lt;br /&gt;
   &lt;br /&gt;
   public Person get() {&lt;br /&gt;
      return person;&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Nichts Aufregendes hier. Wenn der Builder im gleichen Package angesiedelt ist wie die Generat-Klasse&lt;br /&gt;
und die Felder des Generats package visibility haben (public sollten sie niemals sein), dann können wir&lt;br /&gt;
die Modifier-Methoden darauf umschreiben und auf die Indirektion durch den setter verzichten:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public PersonBuilder withVorname(String vorname) {&lt;br /&gt;
   person.vorname = vorname;&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
In diesem Falle können wir auf den Setter in der Generat-Klasse verzichten und das Feld im Generat&lt;br /&gt;
immutable machen, oder wir können den Builder für die Manipulation verwenden. Auf diese Weise können &lt;br /&gt;
wir die vollkommene Kontrolle über die Generat-Felder halten.&lt;br /&gt;
&lt;br /&gt;
==Der Builder als member class==&lt;br /&gt;
Über den Unterschied zwischen member class und inner class sein an dieser Stelle auf die Java-Spec&lt;br /&gt;
verwiesen. Es genüge an dieser Stelle, daß die member class -- im Gegensatz zur inner class -- unabhängig&lt;br /&gt;
von der sie umgebenden Klasse zu erzeugen.&lt;br /&gt;
&lt;br /&gt;
Wir verwenden die gleiche Klasse wie oben und fügen den Builder dort ein:&lt;br /&gt;
{{java|code=&lt;br /&gt;
class Person {&lt;br /&gt;
   private String vorname;&lt;br /&gt;
   String getVorname() {&lt;br /&gt;
      return vorname;&lt;br /&gt;
   }&lt;br /&gt;
   public static class Builder {&lt;br /&gt;
      private Person person = new Person();&lt;br /&gt;
      Builder withVorname(String vorname) {&lt;br /&gt;
         person.vorname = vorname;&lt;br /&gt;
         return this;&lt;br /&gt;
      }&lt;br /&gt;
 &lt;br /&gt;
      Person get() {&lt;br /&gt;
         return person;&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Zwei Unterschiede fallen in&#039;s Auge: da der Builder in der Generat-Klasse liegt, können wir ihn&lt;br /&gt;
einfach &amp;quot;Builder&amp;quot; nennen, die Verwendeung sieht damit so aus:&lt;br /&gt;
{{java|code=Person person = new Person.Builder().withVorname(&amp;quot;Peter&amp;quot;).get();}}&lt;br /&gt;
Die Sichtbarkeit der Felder spielt nun keine Rolle mehr. Da die fiel class vollen Zugriff auch&lt;br /&gt;
auf die private-Felder der Klasse hat die sie enthält, brauchen wir keine Setter mehr. Natürlich können&lt;br /&gt;
wir welche definieren, brauchen sie aber nicht für den Builder und müssen die Sichtbarkeit nicht mehr&lt;br /&gt;
aufzuweichen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Builder:Motivation&amp;diff=204</id>
		<title>Builder:Motivation</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Builder:Motivation&amp;diff=204"/>
		<updated>2025-02-24T16:08:08Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Kategorie:Java Kategorie:Builder = Motivation =  Ber Begriff &amp;quot;Builder&amp;quot; tritt wohl zum ersten Mal im &amp;quot;Design Patterns&amp;quot;-Buch der Gang of Four auf. Die Absicht des Builder Pattern wird dort definiert durch: :Separate the construction of a complex object from its representation&amp;lt;br&amp;gt; :so that the same construction process can create different representations  Es geht dort also um die Trennung von Konstruktion und Repräsentation. Ein wesentlicher Aspekt…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Java]]&lt;br /&gt;
[[Kategorie:Builder]]&lt;br /&gt;
= Motivation =&lt;br /&gt;
&lt;br /&gt;
Ber Begriff &amp;quot;Builder&amp;quot; tritt wohl zum ersten Mal im &amp;quot;Design Patterns&amp;quot;-Buch der Gang of Four auf.&lt;br /&gt;
Die Absicht des Builder Pattern wird dort definiert durch:&lt;br /&gt;
:Separate the construction of a complex object from its representation&amp;lt;br&amp;gt;&lt;br /&gt;
:so that the same construction process can create different representations&lt;br /&gt;
&lt;br /&gt;
Es geht dort also um die Trennung von Konstruktion und Repräsentation. Ein wesentlicher Aspekt&lt;br /&gt;
dabei ist die Anforderung &#039;&#039;verschiedene&#039;&#039; Repräsentationen aus dem Ergebnis des selben&lt;br /&gt;
Konstruktionsprozesses zu erzeugen. Als Beispiel führt das Buch die Konstruktion eines Textes an,&lt;br /&gt;
der dann in unterschiedliehen Formaten ausgegeben werden kann.&lt;br /&gt;
&lt;br /&gt;
Auch wenn solche Probleme in der Praxis durchaus vorkommen, hat sich der Builder-Begriff davon mittlerweile losgelöst.&lt;br /&gt;
Die meisten Beschreibungen verzichten auf den zweiten Aspekt -- die Erzeugung der Repräsentationen --&lt;br /&gt;
und beschränken sich auf die Konstruktion. In diesem Sinne solle der Builder auch in diesem Pamphlet verstanden&lt;br /&gt;
werden. Es geht also um die Trennung der Konstruktion von der Verarbeitung des erzeugten Objekts.&lt;br /&gt;
Dem Builder geht es dabei ausschließlich um die Konstruktion und die Manipulation der Objekt;&lt;br /&gt;
was -- insbesondere fachlich -- weiter mit dem Objektgeschieht, interessiert den Builder nicht.&lt;br /&gt;
&lt;br /&gt;
== Paradigmen ==&lt;br /&gt;
Sucht man im Web nach dem Begriff &amp;quot;objektorientiert&amp;quot; so findet man allerhand, nur keine Definition;&lt;br /&gt;
nicht einmal ein Konsens darüber was OO eigentlich sein soll findet man.&lt;br /&gt;
Eine der ersten Sprachen die &amp;quot;Objekte&amp;quot; eingeführt hat, war [https://en.wikipedia.org/wiki/Simula SIMULA-67].&lt;br /&gt;
Wie der Name suggeriert, ist SIMULA im Umfeld von software-gestützten Simulationen entstanden in denen mehr oder weniger&lt;br /&gt;
selbständige &amp;quot;Dinge&amp;quot; mit einander interagieren. Die Definition von Grady Booth für das objektorienterte Design enstammt&lt;br /&gt;
der realen Welt, nicht der Programmierung; die Eigenschaften treffen jedoch auch beide zu. Demnach hat eine Objekt&lt;br /&gt;
* eine Identität&lt;br /&gt;
* einen (inneren) Zustand&lt;br /&gt;
* eine definiertes Verhalten&lt;br /&gt;
Das Objekt tackert damit Daten und Funktionen die damit arbeiten zusammen. Objekte &amp;quot;leben&amp;quot; über einen längeren Zeitraum&lt;br /&gt;
und verändern sich dabei. Seit dem Aufkommen in den 1990ern ist &amp;quot;Objektorientierung&amp;quot; das führende Paradigma,&lt;br /&gt;
tatsächlich zeichnet sich seit einiger Zeit eine Änderung des Trends ab. Massive Parallelität in allen Bereichen -- vom&lt;br /&gt;
Prozessor bis zum globalen Web führen immer wieder zu Problemen, weil die Daten im Objekt nicht für den parallelen Zugriff&lt;br /&gt;
vorgesehen sind. Auch wenn SOA kein moderner Begriff mehr ist, ist der Service zum Mantra der Gegenwart geworden.&lt;br /&gt;
Die Vorstellung eines Ablaufs, der gestartet und beendet wird, Eingaben aufnimmt und daraus ein Ergebnis berechnet;&lt;br /&gt;
unabhängig vom Rest der Welt, mit einer Lebensdauer von Millisekunden -- das ist das Gegenteil eines Objekts.&lt;br /&gt;
&lt;br /&gt;
Auch der Builder bricht mit dem OO-Paradigma indem er die Daten von ihrer Manipulation trennt.&lt;br /&gt;
Im Grunde genommen läßt sich die Verarbeitung von Daten nicht zufriedenstellend in der OO-Welt abbilden.&lt;br /&gt;
Eine Überweisung führt sich nicht selbst aus. Sie ist ein Auftrag, der im Rahmen eines Prozesses ausgeführt wird.&lt;br /&gt;
Die Überweisungs-Daten müssen also vom inneren Zustand der Überweisungsmaschine gertrennt werden. Die Maschine&lt;br /&gt;
mag ein Objekt sein, die Überweisungsdaten bilden keines; für sie ist das Datenstruktur- oder Datentyp-Modell angemessener.&lt;br /&gt;
&lt;br /&gt;
Folgt man diesem Gedankenm, führt das zum Konzept das typisierten funktionalen Programmiersprachen zugrunde liegt.&lt;br /&gt;
&lt;br /&gt;
== Die integrierte Factory ==&lt;br /&gt;
Im Pattern-Buch taucht &#039;&#039;die&#039;&#039; Factory als Pattern nicht auf. Statt dessen giebt es zwei speziellere Pattern&lt;br /&gt;
&amp;quot;Abstract Factory&amp;quot; und &amp;quot;Factory Method&amp;quot; deren Definition hier nicht wiederholt weren soll.&lt;br /&gt;
Stellen wir uns statt dessen die Frage: Was möchten wir unter einer &#039;&#039;Factory&#039;&#039; verstehen?&lt;br /&gt;
&lt;br /&gt;
Die kürzestmögliche Definition ist:&lt;br /&gt;
:Eine Factory ist ein Ding, das Objekte erzeugt.&lt;br /&gt;
Meistens handelt es sich da um ein Objekt, es kann aber auch eine Funktion oder eine Methode sein.&lt;br /&gt;
&lt;br /&gt;
Die Parametrisierung bzw. Konfigurierbarkeit zur Erzeugung von Objekten &#039;&#039;unterschiedlicher&#039;&#039; Klassen&lt;br /&gt;
ist zwar möglich, aber nicht wesentlich. Dieser Factory-Begriff kann also getrost auf den Builder angewandt&lt;br /&gt;
werden: Ein Builder erzeugt Objekte. Die Klasse des Generats kann für einen&lt;br /&gt;
Builder variieren, muß -- und tut es im allgemeinen -- aber nicht.&lt;br /&gt;
&lt;br /&gt;
Was den Builder von der landläufigen Vorstellung der Factory -- und der Gof&#039;schen factory method -- unterscheidet,&lt;br /&gt;
ist die Tatsache daß beim Builder zur Erzeugung von Objekten mehrere Methoden aufgerufen werden müssen.&lt;br /&gt;
&lt;br /&gt;
== Fluent Interfaces ==&lt;br /&gt;
Geprägt wurde der Begriff wohl von Eric Evens; Martin Fowler schreibt darüber 2005 in seinem&lt;br /&gt;
[https://martinfowler.com/bliki/FluentInterface.html Blog].&lt;br /&gt;
Die Idee dahinter ist, Folgen von Methoden-Aufrufen auf Objekte -- die so typisch sind für imperative Sprachen wie Java -- zu ersetzen durch verkettete Methoden-Aufrufe, die die Struktur einer domain specific languange aufweisen.&lt;br /&gt;
Fowlers Beispiel ähnelt nicht zufällig den Buildern wie sie hier beschrieben werden. Im folgenden soll nicht der Artikel nacherzählt werden, vielmehr geht es darum einen Eindruck vom &amp;quot;fluent interface&amp;quot;-Konzept zu geben.&lt;br /&gt;
&lt;br /&gt;
Manchmal werden fluent interfaces auch als Pattern bezeichnet. Das ist -- im ursprünglichen Sinne -- nicht korrekt.&lt;br /&gt;
Ihnen liegt keine fachliche Motivation zugrunde und sie dienen nicht der Lösung irgendeiner Problem-Kategorie.&lt;br /&gt;
Sie sind ein Design-Konzept für Programmier-Interfaces.  &lt;br /&gt;
&lt;br /&gt;
In Java könnte man sich folgenden Code vorstellen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Statement s = new select();&lt;br /&gt;
Fields f = new Fields(&amp;quot;x, y, z&amp;quot;);&lt;br /&gt;
s.setFields(f);&lt;br /&gt;
Tables t = new Tables(&amp;quot;t&amp;quot;);&lt;br /&gt;
s.setTables(t);&lt;br /&gt;
Condition c = new Condition(&amp;quot;x = z&amp;quot;);&lt;br /&gt;
s.setConditions(c)&lt;br /&gt;
}}&lt;br /&gt;
Man kann -- anstelle der Verwendung lokaler Variablen -- die Objekt-Erzeugung inline durchführen,&lt;br /&gt;
aber das macht den Code nicht schöner. Man kommt beim Lesen nicht umhin, den Code sequentiell zu analysieren:&lt;br /&gt;
Erzeugt wird ein Statement, dann wird ein &amp;quot;Field&amp;quot;-Objekt erzeugt, das wird dem Statement&lt;br /&gt;
hinzugefügt, und so fort. Der Eingeweihte erkennt schnell das SQL-Statement das hier konstruiert wird.&lt;br /&gt;
&lt;br /&gt;
Man kann das -- anlehnend an die SQL-Syntax -- auch in Java anders formulieren:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Statement s = new Select() //&lt;br /&gt;
                  .fields(&amp;quot;x, y, z&amp;quot;) //&lt;br /&gt;
                  .from(&amp;quot;t&amp;quot;) //&lt;br /&gt;
                  .where(&amp;quot;x = z&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
Anstelle der von einander unabhängigen Setter definiert die {{java|Select}}-Klasse Methoden, die immer wieder das gleiche&lt;br /&gt;
{{java|Select}}-Objekt als Ergebnis liefern. Die DSL die hier definiert wird, entspricht der SQL-Syntax und man kann sich&lt;br /&gt;
vorstellen, daß -- wenn die {{java|where}}-Methode entsprechend modelliert wird -- auch die Definition geschachtelter&lt;br /&gt;
Select-Statements möglich sind.&lt;br /&gt;
&lt;br /&gt;
Das sind denn auch die beiden Elemente der fluent interfaces, die hier wesentlich sind.&lt;br /&gt;
Zunächst einmal das &amp;quot;method chaining&amp;quot;: Man versteht darunter, daß die Methoden-Aufrufe nicht in einzelnene Befehlen&lt;br /&gt;
geschehen -- wie das bei Verwendung von Settern und lokalen Variablen der Fall ist -- sondern in einer (mehr oder weniger langen) &lt;br /&gt;
Kette von aufeinander angewandten Methoden, so daß für die komplette Folge nur ein einziger Befehl&lt;br /&gt;
(gewissermaßen ein einziges Semikolon) benötigt wird.&lt;br /&gt;
&lt;br /&gt;
Das zweite Element ist die Schachtelung. Statt Unter-Objekte in lokalen Variablen abzulegen und dort zu manipulieren,&lt;br /&gt;
werden sie -- wieder in einer einzigen Methoden-Kette erzeugt und dann direkt als Argumente an Methoden übergeben.&lt;br /&gt;
Das ganze Konstrukt erhält dadurch einen eher funktionalen Charakter. Das ist für den &amp;quot;prozeduralen&amp;quot; Java-Hacker&lt;br /&gt;
ein eher ungewohntes und damit befremdliches Konzept.&lt;br /&gt;
&lt;br /&gt;
Ich stand der &amp;quot;fluent interface&amp;quot;-Idee von Anfang an skeptisch gegenüber. Solange die dadurch definierte DSL den Charakter einer formalen&lt;br /&gt;
Sprache hat -- wie das bei SQL der Fall ist -- die einer eindeutig definierten inneren Logik folgt, giebt es eigentlich kein Problem.&lt;br /&gt;
Wenn man aber versucht -- und so wird es vielfach verkauft -- natürliche Sprache darüber nachzubilden wird die Sache schwierig.&lt;br /&gt;
Computer-Programme sind formal und lassen keine Unschärfe zu; das Gegenteil ist ein wesentliches Merkmal natürlicher Sprachen.&lt;br /&gt;
&lt;br /&gt;
Wie kann man nun zusammenfassen inwiefern fluent interfaces bei der Builder-Konstruktion bedeutsam sind?&lt;br /&gt;
&lt;br /&gt;
{{quotation|Der Builder verwendet Method Chaining und Schachtelung, um klassische Anweisungsfolgen durch eine DSL zu ersetzen.}}&lt;br /&gt;
&lt;br /&gt;
Dadurch wird einerseits eine bessere Lesbarkeit und eine bessere Verständlichkeit der zugrundeliegenden Semantik erreicht&lt;br /&gt;
und andererseits boiler plate code gekapselt, der sonst die die Aufmerksamkeit absaugen würde.&lt;br /&gt;
&lt;br /&gt;
== Separation  of Concerns ==&lt;br /&gt;
Wie im Abschnitt &amp;quot;Zugriffs-Kontolle&amp;quot; ausführlicher beschrieben wird, bietet der Builder eine Möglichkeit&lt;br /&gt;
die Zuständigkeiten über Entities so trennen. Das klingt zunächst einmal etwas merkwürdig; welche Zuständigkeiten&lt;br /&gt;
sollte man bei einem Entity -- das selbst keine Logik enthält -- trennen?&lt;br /&gt;
&lt;br /&gt;
Es geht hier um die Trennung von Erzeugung (bzw. Manipulation) des Objekts und dem Zugriff auf den Inhalt.&lt;br /&gt;
Die Idee des immutable Objekts ist Java grundsätzlich fremd, sie widerspricht geradezu der eigentlichen Objekt-Idee.&lt;br /&gt;
Aber tatsächlich haben unveränderliche Objekte in einer multithreading-Umgebung große Vorteile,&lt;br /&gt;
weil sie die Synchronisation stark vereinfachen. Nicht umsonst ist das funktionale Paradigma weiterhin auf dem Vormarsch.&lt;br /&gt;
&lt;br /&gt;
Konsequent durchgezogen, kann das Entity vollständig auf Setter verzichten indem es die Manipulation dem Builder überträgt&lt;br /&gt;
und sich darauf beschränken Daten zu halten und herauszugeben.&lt;br /&gt;
&lt;br /&gt;
== Statisch oder dynamisch? ==&lt;br /&gt;
Das ist für jede Programmiersprache die -- oder zumindest eine -- Gretchenfrage. Was ist damit gemeint?&lt;br /&gt;
Statisch heißt &amp;quot;zur Compile-Zeit&amp;quot;, dynamisch -- oder nicht-statisch -- bezeichnet das Gegenstück, nämlich &amp;quot;zur Laufzeit&amp;quot;.&lt;br /&gt;
&lt;br /&gt;
Wenn Tony Hoare die Einführung von &amp;quot;null&amp;quot; in ALGOL als &amp;quot;billion Dollar mistake&amp;quot; bezeichnet hat, meinte er damit,&lt;br /&gt;
daß die null- oder Ungültigkeitsprüfung optimalerweise zur Compile-Zeit stattfinden sollte. Es giebt mittlerweile&lt;br /&gt;
Sprachen, die Konzepte dafür implementieren -- in Java sind sie nur unzulänglich ausgeführt.&lt;br /&gt;
&lt;br /&gt;
Inwiefern betrifft das den Builder? Bei jeder Prüfung muß man sich fragen, wann diese stattfinden soll.&lt;br /&gt;
Was ist mit Muß-Werten? Kann man das Vorhandensein zur Compile-Zeit prüfen -- was sicherer wäre -- oder soll man&lt;br /&gt;
die Prüfung auf die Laufzeit -- was einfacher wäre -- verlagern? Auf diese spezielle Frage wird später noch eingegangen,&lt;br /&gt;
betrachten wir die Frage etwas allgemeiner: &amp;quot;wann statisch, wann dynamisch&amp;quot;?&lt;br /&gt;
&lt;br /&gt;
Die Antwort lautet: -- wie überraschend -- kommt drauf an...&lt;br /&gt;
&lt;br /&gt;
Grundsätzlich kann man sagen: statische Prüfung ist immer aufwändiger als die dynamische. Definiert an einen einfachen&lt;br /&gt;
Builder mit mehrereren Konfigurations-Methoden, kann man die Methoden in beliebiger Reihenfolge aufrufen; im einfachsten&lt;br /&gt;
Falle sogar mehrfach. Möchte man eine Reihenfolge festlegen, die bereits zur Compile-Zeit eingehalten werden muß ist das&lt;br /&gt;
prinzipiell möglich. es erfordert allerdings zusätzliche Klassen und verursacht Aufwand.&lt;br /&gt;
&lt;br /&gt;
Möchte man zur Compile-Zeit sicher sein, daß Muß-Felder gefüllt sind, geht das nur über (häßliche) Konstruktoren und selbst&lt;br /&gt;
dann hat man nur eingeschränkte Kontrolle darüber, ob die Felder mit brauchbaren Werten gefüllt sind.&lt;br /&gt;
&lt;br /&gt;
Es bleibt also eine Abschätzung: Lohnt sich der Aufwand -- wenn es denn überhaupt geht?&lt;br /&gt;
&lt;br /&gt;
Der Aldi-Tip: Mach&#039;s dynamisch und schreib&#039; viele Unit-Tests.&lt;br /&gt;
&lt;br /&gt;
== Migration/Versionierung ==&lt;br /&gt;
Die Separation von Datenspeicherung -- im Entity -- und Manipulation -- im Builder -- macht es einfacher,&lt;br /&gt;
zwischen unterschiedlichen Versionen von Entities zu unterscheiden, diese zu erzeugen und Migration von&lt;br /&gt;
Daten zwischen Versionen durchzuführen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Builder:Komponenten&amp;diff=203</id>
		<title>Builder:Komponenten</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Builder:Komponenten&amp;diff=203"/>
		<updated>2025-02-24T16:07:31Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Kategorie:Java Kategorie:Builder =Komponenten= Die Anwendung eines Buildes im Code erfolgt stets in drei Schritten, auch wenn diese nicht immer unmittelbar hintereinander ausgeführt werden müssen: #Erzeugen des Builders #Konfiguration oder Manipulation des vom Builder zu erzeugenden Objektes #Herausgabe des gewünschten Objekts Auch wenn es Variationen darüber giebt was die einzelnen Methoden des Builders tatsächlich tun, giebt es zu jeder der…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Java]]&lt;br /&gt;
[[Kategorie:Builder]]&lt;br /&gt;
=Komponenten=&lt;br /&gt;
Die Anwendung eines Buildes im Code erfolgt stets in drei Schritten, auch wenn diese nicht&lt;br /&gt;
immer unmittelbar hintereinander ausgeführt werden müssen:&lt;br /&gt;
#Erzeugen des Builders&lt;br /&gt;
#Konfiguration oder Manipulation des vom Builder zu erzeugenden Objektes&lt;br /&gt;
#Herausgabe des gewünschten Objekts&lt;br /&gt;
Auch wenn es Variationen darüber giebt was die einzelnen Methoden des Builders tatsächlich tun,&lt;br /&gt;
giebt es zu jeder der genannten Schritte auch eine Gruppe von Methoden die zur Ausführung des Schrittes&lt;br /&gt;
beitragen. Wir haben damit drei Gruppen von Methoden:&lt;br /&gt;
&lt;br /&gt;
#Creator-Methoden zur Erzeugung&lt;br /&gt;
#Modifier-Methoden zur Manipulation&lt;br /&gt;
#Generator-Methoden zur Auslieferung des Ergebnisses&lt;br /&gt;
&lt;br /&gt;
Während man oft nur eine Erzeugungs- und in der Regel nur eine Methode zur Auslieferung des Objekts benötigt,&lt;br /&gt;
hat man üblicherweise einige oder viele Konfigurations-Methoden. Der Begriff &amp;quot;Generator&amp;quot;-Methode ist dabei diskutabel,&lt;br /&gt;
weil das Objekt nicht notwendigerweise in der &amp;quot;Generator&amp;quot;-Methode erzeugt werden muß.&lt;br /&gt;
&lt;br /&gt;
==Builder erzeugen mit dem Creator==&lt;br /&gt;
Um mit einem Builder arbeiten zu können, muß man zunächst ein passendes Objekt erzeugen.&lt;br /&gt;
Dazu hat man in Java zwei Möglichkeiten: Mit einem passenden Konstruktor einerseits oder einer (in der Regel statischen)&lt;br /&gt;
Factory Methode -- die natürlich ihrerseits einen Konstruktor aufruft -- andererseits.&lt;br /&gt;
&lt;br /&gt;
Offensichtlich braucht man in jedem Fall einen Konstruktor, es geht also eher um die Frage ob man&lt;br /&gt;
diesen Konstruktor direkt oder über eine geeignete Methode zugänglich macht.&lt;br /&gt;
&lt;br /&gt;
===Konstruktor===&lt;br /&gt;
Die Konstruktor-Variante liegt den meisten Entwicklern wohl am nächsten.&lt;br /&gt;
Dabei wird für jede Art der Erzeugung ein Konstruktor definiert -- maximal einen ohne und beliebig viele mit Parametern.&lt;br /&gt;
Da die Befüllung in der Regel über Modifier-Methoden geschieht, steuert man mit den Konstruktor-Parametern&lt;br /&gt;
seltener die Erzeugung des Builders selbst, oftmals aber die Initial-Befüllung.&lt;br /&gt;
&lt;br /&gt;
Ein naheligendes Beispiel ist die Implementierung eines Konstruktors für die Erzeugung neuer Generate&lt;br /&gt;
und eines Konstruktors zur Manipulation existierender Generate:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class PersonBuilder {&lt;br /&gt;
   private Person person;&lt;br /&gt;
   public PersonBuilder() {&lt;br /&gt;
      person = new Person();&lt;br /&gt;
   }&lt;br /&gt;
   public PersonBuilder(Person person) {&lt;br /&gt;
      this.person = person;&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Man kann dem Konstruktor auch Werte zur Initial-Belegung mitgeben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class AmpelBuilder {&lt;br /&gt;
  private Ampel ampel = new Ampel();&lt;br /&gt;
  public AmpelBuilder(Color initial) {&lt;br /&gt;
     ampel.farbe = initial;&lt;br /&gt;
  }&lt;br /&gt;
  ...&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Von dem Konzept, im Konstruktor &#039;&#039;alle&#039;&#039; nicht-optionalen Werte zu setzen wird an dieser Stelle allerdings abgeraten.&lt;br /&gt;
Einerseits bietet es eine gewisse statische Sicherheit, führt aber in der Praxis zu immer häßlicheneren Konstruktoren.&lt;br /&gt;
Besser lesbar ist immer die Variante, die Konsistenz des Generats -- oder die Möglichkeit der Erzeugung -- in&lt;br /&gt;
der Generator-Methode zu prüfen.&lt;br /&gt;
&lt;br /&gt;
Die Verwendung von Konstruktoren findet ihre Grenze da, wo sich die Konstruktoren nicht mehr anhand der Typen&lt;br /&gt;
ihrer Parameter-Liste unterscheiden lassen. Das ist schlicht und ergreifend unmöglich zu implementieren.&lt;br /&gt;
&lt;br /&gt;
===Statische Methoden===&lt;br /&gt;
Der Personen-Builder des vorangegangenen Absatzes würde mit statischen Methoden so aussehen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class PersonBuilder {&lt;br /&gt;
   private Person person;&lt;br /&gt;
&lt;br /&gt;
   public static PersonBuilder empty() {&lt;br /&gt;
      return new PersonBuilder (new Person());&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   public static PersonBuilder use(Person person) {&lt;br /&gt;
      return new PersonBuilder (person);&lt;br /&gt;
   }&lt;br /&gt;
&lt;br /&gt;
   private PersonBuilder(Person person) {&lt;br /&gt;
      this.person = person;&lt;br /&gt;
   }&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Wir verwenden hier weiterhin den Konstruktor zur Initialisierung, machen ihn aber private und rufen ihn&lt;br /&gt;
über die statischen Methoden auf. Das macht im vorliegenden Beispiel keinen großen Unterschied, sieht nur etwas anders aus.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir nochmal das Ampel-Beispiel von vorhin. Der Aufruf&lt;br /&gt;
{{java|new AmpelBuilder(Color.BLUE)}}&lt;br /&gt;
ist nun nicht besonders sinnvoll. Wollten wir das mit der Konstruktor-Lösung verhindern, blieben nicht viel&lt;br /&gt;
Möglichkeiten. Wir könnten ein Enum definieren, dort nur die Ampel-Farben zulassen und einen Konstruktor mit &lt;br /&gt;
einem entsprechenden Enum-Parameter definieren. Statische Methoden bieten eine weniger aufwändige Möglichkeit:&lt;br /&gt;
{{java|code=&lt;br /&gt;
static AmpelBuilder rot() {&lt;br /&gt;
  return new AmpelBuilder(Color.RED);&lt;br /&gt;
}&lt;br /&gt;
static AmpelBuilder gelb() {&lt;br /&gt;
  return new AmpelBuilder(Color.YELLOW);&lt;br /&gt;
}&lt;br /&gt;
static AmpelBuilder gruen() {&lt;br /&gt;
  return new AmpelBuilder(Color.GREEN);&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Der Konstruktor wird dann wieder private deklariert.&lt;br /&gt;
&lt;br /&gt;
===Wann wählt man was?===&lt;br /&gt;
Wenn man die freie Wahl hat, ist die Entscheidung tatsächlich eine Geschmacksfrage.&lt;br /&gt;
Wenn man mehr Creator-Methoden braucht als die Konstruktor-Lösung es hergiebt, giebt es eigentlich keine Wahl.&lt;br /&gt;
Es sei denn, man bevorzugt seltsame Lösungen mit Selektor-Parametern.&lt;br /&gt;
&lt;br /&gt;
Auf jeden Fall sollte man dabei aber die Parameter-Listen so kurz wie möglich halten.&lt;br /&gt;
Und generische Parameter mit Typen wie {{java|int}} oder {{java|String}} sollten bei der Erzeugung nur dann verwendet werden,&lt;br /&gt;
wenn tatsächlich &#039;&#039;alle&#039;&#039; Werte erlaubt sind. Wenn man etwa eine eMail-Adresse als String übergiebt, kann man dem Konstruktor&lt;br /&gt;
nicht ansehen welche Bedeutung der übergeben String hat. Eine statische Methode könnte {{java|forMailAddress}} heißen.&lt;br /&gt;
&lt;br /&gt;
Eine viel elegantere Lösung bietet ein eigener Datentyp &amp;quot;EmailAdresse&amp;quot;, was mithilfe von {{java|record}} sehr schlank&lt;br /&gt;
zu implementieren ist.&lt;br /&gt;
&lt;br /&gt;
==Das Generat definieren mit dem Modifier==&lt;br /&gt;
Die Modifier-Methoden versorgen dem Builder mit Daten aus denen das Generat befüllt wird.&lt;br /&gt;
Sie haben alle den selben Aufbau:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Builder methode(Typ wert) {&lt;br /&gt;
   // übernehme Daten aus &amp;quot;wert&amp;quot;&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Die Modifier-Methoden sollten einen einzelnen Parameter haben. In Ausnahmen kann man auch&lt;br /&gt;
auf den Parameter verzichten. Mehr als einen Parameter sollte man aber nicht übergeben. Ausgenommen&lt;br /&gt;
ist die Übergabe beliebig vieler Parameter -- die vararg-Form.&lt;br /&gt;
&lt;br /&gt;
Wer unbedingt mehrere Parameter an die Modifier-Methode übergeben möchte, folge der &amp;quot;Clean Code&amp;quot;-Methode&lt;br /&gt;
und definiere ein Parameter-Objekt, das die Werte in &#039;&#039;einem&#039;&#039; Objekt zusammenfaßt. Dafür kann man sehr gut&lt;br /&gt;
einen Builder schreiben... &lt;br /&gt;
&lt;br /&gt;
===Einen Wert übernehmen===&lt;br /&gt;
Im einfachsten Fall wird ein einzelner Wert übergeben. Die Methode sollte&lt;br /&gt;
&#039;&#039;nicht&#039;&#039; {{java|setIrgendwas}} heißen, das giebt nur Verwirrung mit nicht-Builder-Klassen.&lt;br /&gt;
Empfehlenswert ist das Präfix &amp;quot;with&amp;quot;:&lt;br /&gt;
{{java|code=&lt;br /&gt;
FooBuilder withName(String name) {&lt;br /&gt;
   foo.setName(name);&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Der Wert wird übernommen und &#039;&#039;in Gänze&#039;&#039; in das Ergebnis-Objekt übernommen.&lt;br /&gt;
Sollen nur Teile des übergebenen Arguments verwendet werden, sollte man einen anderen Präfix&lt;br /&gt;
wählen, zum Beispiel &amp;quot;use&amp;quot; oder &amp;quot;from&amp;quot; oder entsprechende Konstrukte.&lt;br /&gt;
Hier soll nur der Name der übergebenen Person verwendet werden:&lt;br /&gt;
{{java|code=&lt;br /&gt;
FooBuilder useForName(Person person) {&lt;br /&gt;
   foo.setName(person.getName());&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Auf Namenskonventionen wird im Anschluß eingegangen.&lt;br /&gt;
&lt;br /&gt;
===Werte aus einem Objekt extrahieren===&lt;br /&gt;
Wenn nicht das gesamte übergebene Objekt verwendet werden soll&lt;br /&gt;
sondern nur ein Teil davon, sollte sich das in der Benamung niederschlagen.&lt;br /&gt;
&lt;br /&gt;
Soll etwa nur der Name einer person verwendet werden, kann man schreiben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public FooBuilder usePersonForName(Person person) {&lt;br /&gt;
   foo.setName(person.getName());&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Man kann das verwendete Objekt im Namen auch weglassen und {{java|useForName}} schreiben.&lt;br /&gt;
Werden generische Typen wie {{java|String}} oder Zahlen verwendet sollte man aber immer&lt;br /&gt;
dazuschreiben als was der Parameter übergeben wird, denn aus dem Datentyp geht es nicht hervor.&lt;br /&gt;
 &lt;br /&gt;
werden mehrere Komponenten des übergebenen Objekts verwendet kann man gegebenenfalls einfach&lt;br /&gt;
{{java|use}} schreiben. Dann muß aber aus dem Kontext bzw. im Team klar sein was da geschieht.&lt;br /&gt;
Grundsätzlich gilt: So genau wie nötig, so allgemein wie möglich.&lt;br /&gt;
===Generate anderer Builder===&lt;br /&gt;
Möchte man Objekte mit dem Builder setzen, verwendet man nicht selten Objekte die&lt;br /&gt;
andere Builder generieren. Zum Setzen der Adresse einer Person in der Klasse&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class Person {&lt;br /&gt;
   Adresse adresse;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
kann man im Builder die Methode&lt;br /&gt;
{{java|code=&lt;br /&gt;
public PersonBuilder with(Adresse adresse) {&lt;br /&gt;
    person.adresse = adresse;&lt;br /&gt;
    return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
definieren und wie folgt aufrufen:&lt;br /&gt;
{{java|code=new PersonBuilder().with(new AdressBuilder().get());}}&lt;br /&gt;
Wenn man die Modifier-Methode mit dem Builder als Parameter-Typ definiert:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public PersonBuilder with(AdressBuilder adresse) {&lt;br /&gt;
    person.adresse = adresse.get();&lt;br /&gt;
    return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Sieht der Aufruf so aus:&lt;br /&gt;
{{java|code=new PersonBuilder().with(new AdressBuilder());}}&lt;br /&gt;
Man spart sich immerhin den Aufruf der Generator-Methode.&lt;br /&gt;
Man schafft damit aber auch eine Möglichkeit für den einbettenden Builder, das übergeben Objekt&lt;br /&gt;
zu modifizieren. Das ist etwa dann hilfreich, wenn das eingebettete Objekt eine Referenz über&lt;br /&gt;
das einbettende Objekt haben soll (das Beispiel ist vielleicht nicht sehr sinnvoll):&lt;br /&gt;
{{java|code=&lt;br /&gt;
public PersonBuilder with(AdressBuilder adresse) {&lt;br /&gt;
   adresse.setBewohner(person);&lt;br /&gt;
   person.adresse = adresse.get();&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Da wir hier nur eine Referenz setzen wollen, werden wir nicht die Generator-Methode des Personen-Builder aufrufen.&lt;br /&gt;
&lt;br /&gt;
===Boolean-Werte===&lt;br /&gt;
Boolean-Parameter sind &#039;&#039;immer&#039;&#039; häßlich, weil die Bedeutung von {{java|true}} und {{java|false}}&lt;br /&gt;
nur aus dem Kontext erschlossen werden kann. Alternativ kann man hier zwei parameterlose Modifier-Methoden&lt;br /&gt;
anbieten -- eine für {{java|true}} und eine {{java|false}}. Ist der default-Wert klar,&lt;br /&gt;
kann man auch auf eine der beiden Methoden verzichten:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public FooBuilder enabled() {&lt;br /&gt;
   foo.setEnabled(true);&lt;br /&gt;
   return this;&lt;br /&gt;
}&lt;br /&gt;
public FooBuilder disabled() {&lt;br /&gt;
   foo.setEnabled(false);&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Für einen Manipulator-Builder kann man auch eine &amp;quot;toggle&amp;quot;-Methode anbieten, die den aktuellen Wert negiert.&lt;br /&gt;
&lt;br /&gt;
===Sammlungen manipulieren===&lt;br /&gt;
Enthält das Objekt eine Sammlung von anderen Objekten, benötigt man in der Regel eine Methode zum Hinzufügen&lt;br /&gt;
einzelner Elemente. Niemals sollte man eine Collection zur Manipulation herausrücken, das bringt nur Probleme.&lt;br /&gt;
Getter- und Setter für Collections anzubieten ist so ziemlich das Dümmste was man machen kann...&lt;br /&gt;
&lt;br /&gt;
Unter Sammlung wollen wir hier jedes Konstrukt verstehen, das Objekte einer gemeinsamen Klasse zusammenfaßt.&lt;br /&gt;
Also List-, Set-, Array-, und alle anderen Collection-Objekte sowie klassische Java-arrays und selbstgebaute&lt;br /&gt;
Objekte.&lt;br /&gt;
&lt;br /&gt;
Grundsätzlich lassen sich auch Methoden für das Entfernen von Listen-Elementen definieren,&lt;br /&gt;
aber beim Zusammenbauen von Objekten braucht man das eher selten.&lt;br /&gt;
&lt;br /&gt;
Als Präfix bietet sich hier &amp;quot;add&amp;quot; ganz von selbst an :-)&lt;br /&gt;
Im folgenden Code-Schnipsel wird bei Bedarf auch die Collection selbst erzeugt.&lt;br /&gt;
In der Regel ist es besser, sie bei der Objekt-Erzeugung selbst anzulegen.&lt;br /&gt;
&lt;br /&gt;
{{java|code=&lt;br /&gt;
public FooBuilder add(Adresse adresse) {&lt;br /&gt;
   if (foo.getAdressen() == null) {&lt;br /&gt;
      foo.setAdressen(new ArrayList&amp;lt;Adressen&amp;gt;());&lt;br /&gt;
   }&lt;br /&gt;
   foo.getAdressen().add(adresse);&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;&lt;br /&gt;
}}&lt;br /&gt;
Eine Liste von Objekten läßt sich damit so hinzufügen:&lt;br /&gt;
{{java|code=adresssListe.stream().forEach(FooBuilder::add);}}&lt;br /&gt;
&lt;br /&gt;
Bisweilen ist es aber eleganter eine Sammlung von Objekten komplett zu übergeben.&lt;br /&gt;
Der Stream ist auch hier der Parameter-Typ der Wahl, weil sich jede Sammlung ohne overhead in einen Stream&lt;br /&gt;
überführen läßt. Wir behalten in jedem Fall die {{java|add}}-Methode und fühen die Stream-Variante als convenience-Methode hinzu:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public FooBuilder add(Stream&amp;lt;Adresse&amp;gt; stream) {&lt;br /&gt;
   stream.forEach(this::add);&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;  &lt;br /&gt;
}}&lt;br /&gt;
Eine null-Prüfung sollte man bei Sammlungen eigentlich nicht brauchen. Sammlungen sollten niemals null sein, höchstens leer.&lt;br /&gt;
Eine weitere valide Variante ist die Verwendung einer variablen Parameter-Liste. Auch sie läßt sich über einen stream&lt;br /&gt;
verarbeiten:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public FooBuilder add(Adresse... adressen) {&lt;br /&gt;
   Arrays.stream(adressen).forEach(this::add);&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;  &lt;br /&gt;
}}&lt;br /&gt;
oder -- wenn wir die Stream-Variante ebenfalls implementiert haben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public FooBuilder add(Adresse... adressen) {&lt;br /&gt;
   add(Arrays.stream(adressen));&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;  &lt;br /&gt;
}}&lt;br /&gt;
Das &amp;quot;convenience-Prinzip&amp;quot; hat den Vorteil, daß man die Hinzufügung -- und mögliche zugehörige Logik -- nur &#039;&#039;einmal&#039;&#039;&lt;br /&gt;
implementieren muß. Gegebenenfalls muß man hier aber tatsächlich die Performance in Betracht ziehen. Die Abfrage ob das&lt;br /&gt;
Listen-Objekt vorhanden ist etwa sollte man nicht bei jedem add ausführen.&lt;br /&gt;
&lt;br /&gt;
zum Schluß sei noch die Variante angesprochen bei der der Inhalt der Sammlung ersetzt wird. Das kann zwar sinnvoll sein,&lt;br /&gt;
ist aber mit Vorsicht  zu genießen, weil dadurch vorangegangene Hinzufügungen Rückgängig gemacht werden. Das ist nicht&lt;br /&gt;
intuitiv und kann leicht zu Fehlern führen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public FooBuilder replace(Stream&amp;lt;Adresse&amp;gt; stream) {&lt;br /&gt;
   foo.setAdressen(stream.collect(Collectors.toList()));&lt;br /&gt;
   return this;&lt;br /&gt;
&amp;lt;nowiki&amp;gt;}&amp;lt;/nowiki&amp;gt;  &lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
===Namens-Konventionen===&lt;br /&gt;
Es giebt keine kanonischen Naming-Regeln, man sollte sich daher darum bemühen eine -- zumindest im Team --&lt;br /&gt;
allgemeinverständlicher Nomenklatur zu schaffen.&lt;br /&gt;
&lt;br /&gt;
Das empfohlene Namensschema in Java sieht für Methoden ein verbiales Konstrukt vor. Für Setter&lt;br /&gt;
verwendet man daher den Imperativ des Verbs &amp;quot;to set&amp;quot; mit dem Namen des Atrtributs.&lt;br /&gt;
&lt;br /&gt;
Da die Modifier-Methoden des Builders keine void-Methoden sind wie die Setter, sondern&lt;br /&gt;
die Instanz des verwendeten Builders liefern, verbietet sich &amp;quot;set&amp;quot; als Präfix.&lt;br /&gt;
&lt;br /&gt;
Eine Alternative ist die Verwendung von &amp;quot;with&amp;quot;:&lt;br /&gt;
{{java|code= public FooBuilder withName(String name);}}&lt;br /&gt;
Das bedeutet eine Abweichung vom Verb-Schema, drückt aber aus was geschieht.&lt;br /&gt;
Der Builder erhält dadurch einen eher statischen Charakter.&lt;br /&gt;
Legt der typ des übergebenen Objekt fest -- oder zumindestes nahe -- was gesetzt wird, kann man den&lt;br /&gt;
Attribut-Namen auch weglassen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
FooBuilder with(StatusEnum status);&lt;br /&gt;
FooBuilder with(Person person);&lt;br /&gt;
}}&lt;br /&gt;
Hat das {{java|Foo}}-Objekt mehr als eine Person oder mehr als einen Status,&lt;br /&gt;
kann man das Attribut natürlich nicht weglassen. Die Methode hieße dann aber&lt;br /&gt;
eher {{java|withAntragsteller}} bzw. {{java|withVorherigerStatus}} oder so ähnlich.&lt;br /&gt;
&lt;br /&gt;
Hier eine kleine Auflistung möglicher Präfixe:&lt;br /&gt;
{|&lt;br /&gt;
|add||Hinzufügen von Elementen zu einer Sammlung&lt;br /&gt;
|-&lt;br /&gt;
|use||Verwendung eines Objekts zur Manipulation&lt;br /&gt;
|-&lt;br /&gt;
|from||Extraktion von Daten aus einem Objekt&lt;br /&gt;
|-&lt;br /&gt;
|for||Verwendung des Parameters für einen bestimmten Zweck&lt;br /&gt;
|}&lt;br /&gt;
Die Namenskonventionen sollten &#039;&#039;immer&#039;&#039; Gegenstand einer Team-Debatte sein.&lt;br /&gt;
&lt;br /&gt;
==Den Bau abschließen mit dem Generator==&lt;br /&gt;
Ist die Konfiguration des Objekts abgeschlossen, kann es vom Benutzer abgeholt werden.&lt;br /&gt;
Der Builder beitet dafür in der Regel eine einzige Methode an, die üblicherweise {{java|build}}&lt;br /&gt;
oder kürzer {{java|get}} heißt. Der Name sollte im Projekt einheitlich gewählt werden.&lt;br /&gt;
Wenn der Benutzer beim Aufruf der Generator-Methode entscheiden kann, welche Art Objekt er&lt;br /&gt;
haben möchte, kann der Builder auch mehr als eine Generator-Methode anbieten.&lt;br /&gt;
&lt;br /&gt;
Das Objekt wurde entweder schon früher erzeugt und von der Generator-Methode nur ausgeliefert&lt;br /&gt;
oder es wird erst beim Aufrufen der Generator-Methode erzeugt. In der Generator-Methode kann auch&lt;br /&gt;
eine Validierung durchgeführt werden. Schlägt diese fehl, sollte kein Objekt geliefert werden.&lt;br /&gt;
Dann sollte entweder eine Exception fliegen oder das Objekt in ein Ergebnis-Objekt verpackt werden.&lt;br /&gt;
&lt;br /&gt;
Streng genommen ist der raison d&#039;être der Generator-Methode nicht das Erzeugen, sondern das Ausliefern.&lt;br /&gt;
Wir bleiben trotzdem beim Ausdruck &amp;quot;Generator&amp;quot;-Methode. Auch wenn es nicht immer akkurat ist, ist die&lt;br /&gt;
Vorstellung, daß die Genertor-Methode das gewünschte Objekt herstellt das vorher definiert wurde&lt;br /&gt;
ein adäquates Denk-Muster.&lt;br /&gt;
&lt;br /&gt;
===Das Objekt sichern===&lt;br /&gt;
Wenn das Objekt nicht erst in der Abschluß-Methode erzeugt wird, muß man dafür sorgen daß es&lt;br /&gt;
vom Builder nicht verändert wird. Hält der Builder weiterhin die Referenz auf das erzeugte Objekt,&lt;br /&gt;
verändert jeder Aufruf der with-Methode das erzeugte Objekt. Und ein wiederholter Aufruf der&lt;br /&gt;
Abschluß-Methode liefert &#039;&#039;jedesmal&#039;&#039; das selbe Objekt.&lt;br /&gt;
&lt;br /&gt;
Man kann im Team die Vereinbarung treffen, daß jedes Builder-Objekt nach Abholen des Objekts&lt;br /&gt;
nicht mehr verwendet wird. Das schützt aber nicht vor unbeabsichtigten Fehlern.&lt;br /&gt;
Die einfachste Sicherung sieht so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Foo build() {&lt;br /&gt;
   result = this.foo;&lt;br /&gt;
   this.foo = null;&lt;br /&gt;
   return result;&lt;br /&gt;
}}&lt;br /&gt;
Jeder Aufruf einer with-Methode führt nun zu einer {{java|NullpointerException}}.&lt;br /&gt;
Wenn nötig, kann man die with-Methoden nun mit einer entsprechenden Abfrage sichern um eine&lt;br /&gt;
schönere Exception zu erzeugen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Sch%C3%BCttelreim&amp;diff=202</id>
		<title>Schüttelreim</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Sch%C3%BCttelreim&amp;diff=202"/>
		<updated>2025-01-31T15:23:27Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Eigenes]]&lt;br /&gt;
&lt;br /&gt;
 Ich saß vor meinem Monitor&lt;br /&gt;
 Und hatte einen Ton im Ohr&lt;br /&gt;
undatiert&lt;br /&gt;
&lt;br /&gt;
 Ich werde einen Kuchen backen&lt;br /&gt;
 Und ihn dann zwischen Buchen kacken&lt;br /&gt;
19.7.2020&lt;br /&gt;
&lt;br /&gt;
 Ich traf dieselben Gecken&lt;br /&gt;
 Immer bei den gelben Säcken&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Er sitzt auf dem Geschirrspüler&lt;br /&gt;
 Und lehrt mit viel Gespür Schüler&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Weihnachten wird der Baumkuchen&lt;br /&gt;
 So knapp, man kann ihn kaum buchen&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Sie aßen ihre Salzstangen&lt;br /&gt;
 Fortan nur noch mit Stahlzangen&lt;br /&gt;
Januar 2023&lt;br /&gt;
&lt;br /&gt;
 Er repariert den ganzen Tag Lichtschalter&lt;br /&gt;
 Und nach der Schicht lallt er&lt;br /&gt;
Mai 2023&lt;br /&gt;
&lt;br /&gt;
 Das Schiff hat am Rand Latten&lt;br /&gt;
 Zum Schutz der doofen Landratten&lt;br /&gt;
9.7.2023&lt;br /&gt;
&lt;br /&gt;
 Die Masten meist im Wege steh&#039;n&lt;br /&gt;
 Wenn Fahnen an dem Stege weh&#039;n&lt;br /&gt;
22.7.2023&lt;br /&gt;
&lt;br /&gt;
 Er wollte die Fahne in heroischer Pose hissen&lt;br /&gt;
 Und mußte dabei sich in die Hose pissen&lt;br /&gt;
1.9.2023&lt;br /&gt;
&lt;br /&gt;
 Ich greif&#039; nach meiner Beißschiene&lt;br /&gt;
 Da sticht mich so &#039;ne Scheißbiene&lt;br /&gt;
18.1.2024&lt;br /&gt;
&lt;br /&gt;
 Ein Chirurg kann bei Lebewesen&lt;br /&gt;
 Sehr viel aus dem Gewebe lesen&lt;br /&gt;
31.1.2025&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Boy_Scout_Principle&amp;diff=201</id>
		<title>Boy Scout Principle</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Boy_Scout_Principle&amp;diff=201"/>
		<updated>2024-11-29T18:50:05Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Motivation */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
&lt;br /&gt;
= Motivation =&lt;br /&gt;
Zu den Regeln der Pfadfinderbewegung gehört der Satz:&lt;br /&gt;
{{quotation|Always leave the camp ground cleaner than you found it.}}&lt;br /&gt;
oder wie der Vater der Bewegung – Robert Baden Powell – es ausgedrückt hat:&lt;br /&gt;
{{quotation|Try and leave this world a little better than you found it.}}&lt;br /&gt;
In der Realität herrscht die gegenteilige Praxis vor (oder eben die gleiche Praxis mit negativem Vorzeichen):&lt;br /&gt;
Liegt irgendwo Müll herum, dann scheint das die Menschen dazu zu animieren dem herumliegenden Müll weiteren&lt;br /&gt;
Müll hinzuzufügen.&lt;br /&gt;
Dieses Phänomen wurde in den 80er Jahren als &amp;quot;Broken Window Effect&amp;quot; beschrieben.&lt;br /&gt;
Aber was hat das nun mit Software Engineering zu tun?&lt;br /&gt;
Zum Äquivalent des Broken Windows Effect im Software Engineering ist [https://blog.codinghorror.com/the-broken-window-theory/ hier] recht nett beschrieben.&lt;br /&gt;
Um dessen Vermeidung und die Frage was man statt dessen für die Software-Qualität tun kann soll es im Folgenden gehen.&lt;br /&gt;
&lt;br /&gt;
== Über das Problem ==&lt;br /&gt;
Wer lange genug programmiert hat, weiß wie schlimm schlechter Code aussehen kann. Und immer wenn man&lt;br /&gt;
denkt man hat schon alles gesehen tritt man in eine Java-Klasse die alles dagewesene in den Schatten stellt. Der&lt;br /&gt;
erste Reflex ist meistens &amp;quot;weg damit, alles neu machen&amp;quot;. Man bezeichnet dieses Refactoring-Vorgehen auch mit&lt;br /&gt;
dem treffenden Namen &amp;quot;Big Bang&amp;quot;. Die Umsetzung bereitet in der Praxis allerdings eine ganze Reihe von&lt;br /&gt;
Problemen. Das größte ist, daß eine umfassende Refactoring-Maßnahme Aufwände generiert die aus keinem&lt;br /&gt;
Budget zu bekommen sind. Das liegt nicht nur an knausrigen Budget-Verwaltern, das liegt auch in der Natur der&lt;br /&gt;
Entstehung solcher Code-Höllen. Wer sich beim Codieren nicht um die Qualität kümmert schafft technologische&lt;br /&gt;
Schulden, für die keine Deckung existiert und für die in der Regel keine Rücklagen gebildet werden. So kommt Müll&lt;br /&gt;
zu Müll und aus kleinen dreckigen Code-Ecken werden langsam aber sicher riesige Müllhalden.&lt;br /&gt;
Ein anderes Problem verbirgt sich hinter der Metapher vom Abreißen und Neuaufbau des Systems. Diese aus dem&lt;br /&gt;
Hausbau stammende Metapher läßt sich nicht eins zu eins auf die Software-Entwicklung übertragen. Denn das&lt;br /&gt;
neue System wird ja nicht einfach aus &amp;quot;neuem&amp;quot; Material gebaut, sondern soll die Substanz des abgerissenen&lt;br /&gt;
Systems wiederverwerten. Oder auf den Code bezogen: Die Business-Logik, die sich im Müllhaufen verbirgt – und&lt;br /&gt;
das ist ja das eigentliche Kapital der Software, das was das System wertvoll macht – muß erhalten bleiben. Das&lt;br /&gt;
funktioniert – vielleicht – wenn man eine exzellente und erschöpfende Dokumentation des Systems hat die genau&lt;br /&gt;
die im System enthaltene Fachlichkeit dokumentiert, aber zu welchem System hat man eine solche&lt;br /&gt;
Dokumentation?&lt;br /&gt;
&lt;br /&gt;
Der einzige Weg ist dann das akribsche Analysieren des bestehenden Codes und das Übertragen in die neue&lt;br /&gt;
Anwendung. Und da es sich um eine vollständige Neuentwicklung handelt muß jede Zeile im Rahmen der&lt;br /&gt;
Neuentwicklung untersucht werden; dazu gehört veralteter, nicht mehr verwendeter Code ebenso wie Code-&lt;br /&gt;
Gewölle deren Analyse aufgrund der Komplizierteit sehr zeitaufwändig ist. Es gibt keine Möglichkeit, auf&lt;br /&gt;
irgendeinen Teil dieser Analyse zu verzichten, denn mit der Migration muß sämtliche Funktionalität übertragen&lt;br /&gt;
werden. Sei sie nun offensichtlich oder unter hunderten verschachtelter Klassen vergraben.&lt;br /&gt;
Damit ist in vielen Fällen das Migrationsprojekt mangels Budget gestorben. Und weil die Komplettlösung nicht&lt;br /&gt;
umsetzbar ist, passiert meistens gar nichts. Dabei muß noch nicht einmal die gesamte Anwendung betroffen sein,&lt;br /&gt;
Oft geht es nur darum wesentliche Teile einem Refactoring zu unterziehen, was dann – Budget! Budget! – ebenfalls&lt;br /&gt;
nicht geschieht.&lt;br /&gt;
&lt;br /&gt;
= Über die Lösung =&lt;br /&gt;
Wenn also der Big-Bang-Ansatz nicht durchführbar ist, was dann? Die kleine, mühsamere und weniger beglückende&lt;br /&gt;
Lösung ist der Weg der kleine Schritte. Und wenn man vor lauter Chaos nicht weiß wo anfangen, fängt man am&lt;br /&gt;
besten da an wo man gerade steht: Wann immer der Entwickler ein Stück Code bearbeitet oder reviewt – und sei es&lt;br /&gt;
noch so klein – dann habe er dabei immer die Frage im Hinterkopf &lt;br /&gt;
: Was kann ich hier ohne viel Aufwand besser machen?&lt;br /&gt;
Das scheint erstmal für lange Zeit gar nichts zu bringen und es ersetzt auch nicht das kostenintensive&lt;br /&gt;
Refactoring größerer Programmteile – besonders, wenn die Architektur Probleme verursacht – aber es hilft auf&lt;br /&gt;
lange Sicht Aufwände zu senken und kann den Code so vorbereiten, daß große Refactoring-Maßnahmen überhaupt&lt;br /&gt;
erst möglich werden.&lt;br /&gt;
&lt;br /&gt;
= Was kann man konkret tun? =&lt;br /&gt;
Erlaubt ist alles, was die Code-Qualität verbessert, dabei aber die Funktionalität nicht beeinträchtigt und solange&lt;br /&gt;
man die Schnittstellen nicht anfaßt, ist praktisch alles erlaubt.&lt;br /&gt;
* Unit-Tests schreiben&lt;br /&gt;
* Dokumentation schreiben&lt;br /&gt;
* Kommentare korrigieren und ergänzen&lt;br /&gt;
* Methoden- und Klassennamen umbenennen&lt;br /&gt;
* Toten und auskommentierten Code entfernen&lt;br /&gt;
* Literale durch Konstanten und Konstanten durch Enums ersetzen&lt;br /&gt;
* Zweifelhafte Stellen als TODO oder FIXME markieren&lt;br /&gt;
* Ungenutzte Teile als &amp;quot;deprecated&amp;quot; markieren&lt;br /&gt;
* Code-Blöcke in Methoden auslagern&lt;br /&gt;
* Mehrfach verwendete Blöcke in Klassen auslagern&lt;br /&gt;
* if-Bedingungen umformen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Worauf sollte man achten? =&lt;br /&gt;
Entscheidend ist, daß durch das Refactoring nichts kaputt geht. Bevor man also anfängt den Code umzukrempeln&lt;br /&gt;
muß man sich darüber klar werden, welche Auswirkung die Änderung hat. Wenn kein eigenes und ausreichendes&lt;br /&gt;
Budget für die Überarbeitung zur Verfügung steht, gestaltet man die Änderungen so defensiv wie möglich. Am&lt;br /&gt;
besten sichert man die Änderungen immer durch automatische Unit-Tests ab.&lt;br /&gt;
&lt;br /&gt;
Aus diesem Grunde stehen die Unit-Tests in der Aufzählung oben auch ganz oben. Jeder Entwickler sollte immer&lt;br /&gt;
alles durch Unit-Tests abdecken – so die Theorie. Die Erhöhung der Testabdeckung ändert zwar überhaupt nichts&lt;br /&gt;
an der Code-Qualität, ist aber trotzdem sehr wertvoll. Tests sichern den Code gegen Änderungen ab. Bei der&lt;br /&gt;
nächsten Änderung, Erweiterung oder dem nächsten Refactoring merkt man hoffentlich sofort, wenn etwas kaputt&lt;br /&gt;
gegangen ist.&lt;br /&gt;
&lt;br /&gt;
Nicht umsonst antwortet Michael Feathers auf die Frage &amp;quot;Was ist Legacy Code?&amp;quot; ganz lapidar&lt;br /&gt;
{{quotation|To me, &#039;&#039;legacy code&#039;&#039; is simply code without tests}}&lt;br /&gt;
&lt;br /&gt;
= Noch was? =&lt;br /&gt;
Der brave Pfadfinder kümmert sich nicht darum, wer nach ihm kommt. Er sorgt einfach dafür, daß sich der Nächste&lt;br /&gt;
wohler fühlt wenn er sein Zelt aufschlägt. Wenn er aber weiß, daß demnächst eine große Gruppe zum Camping&lt;br /&gt;
anrückt, dann kann er – mit seinen Genossen – schon mal vorarbeiten. Was heißt das für den Softwerker?&lt;br /&gt;
Wenn man weiß, daß irgendwann die großen Refactorings anstehen, daß zum Beispiel das Datenbank-Modell&lt;br /&gt;
überholt wird oder ein anderes Framework verwendet werden soll; wenn man also planvoll auf irgendetwas hinarbeiten&lt;br /&gt;
möchte, dann kann man die Reinigungsarbeiten schon vorneweg in die richtige Richtung lenken. Hierzu konkrete&lt;br /&gt;
Anweisungen vorzugeben ist schwierig, am besten setzt man sich mit dem Team mal hin und überlegt, welches die&lt;br /&gt;
schlimmsten Probleme sind, wie man sie beseitigen möchte und wie man da hinkommen kann.&lt;br /&gt;
&lt;br /&gt;
Dazu ein einfaches Beispiel:&lt;br /&gt;
&lt;br /&gt;
Sind beispielsweise Zugriffe auf eine bestimmtes Modul (eine Datenbank oder ein Service) überall im Code verteilt&lt;br /&gt;
und auf unterschiedliche Weise implementiert, kann man ein Interface definieren, bei der nächsten Gelegenheit&lt;br /&gt;
den ersten Zugriff aus dem Code lösen, damit das Interface mit einer Klasse unterfüttern und verwenden. Kommt&lt;br /&gt;
der nächste Entwickler an anderer Stelle auf einen ähnlichen Zugriff, übernimmt er entweder die Implementierung&lt;br /&gt;
seines Vorgängers oder er implemetiert eine neue Klasse für das Interface und stellt sie neben die erste.&lt;br /&gt;
Irgendwann – wenn zeit ist – nimmt man sich die verschiedenen Implementierungen der Interface vor und konsolidiert die&lt;br /&gt;
Implementierungen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Der_Weg_zum_guten_Code&amp;diff=200</id>
		<title>Der Weg zum guten Code</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Der_Weg_zum_guten_Code&amp;diff=200"/>
		<updated>2024-11-28T10:34:27Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Arbeitstechniken */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
Um entscheiden zu können welcher [https://xkcd.com/844/ Weg zum guten Code] führt, muß man festlegen was&lt;br /&gt;
&#039;&#039;guten&#039;&#039; Code von schlechtem unterscheidet. Die Erkenntnis, daß es nicht gleichgültig ist, wie Code beschaffen&lt;br /&gt;
ist wurde ja offensichtlich schon gewonnen -- andernfalls wäre die Suche eine sinnlose.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Gut&amp;quot; ist der Code, wenn er über die blanke Funktionalität hinaus weitere Eigenschaften erfüllt. Über diese&lt;br /&gt;
nichtfunktionalen Eigenschaften giebt es eine große Literatur, die Worte &amp;quot;Qualiät&amp;quot; und &amp;quot;Architektur&amp;quot; fallen einem in diesem&lt;br /&gt;
Zusammenhang ein. Dabei geht es aber in der Regel um die Software-Qualität, also die Qualität des gesamten Erzeugnisses&lt;br /&gt;
im Zusammenspiel mit der Umgebung in der es betrieben wird.&lt;br /&gt;
&lt;br /&gt;
Diese Seite engt den Blick ganz bewußt auf den &amp;quot;Code&amp;quot; ein. Damit ist der Quelltext gemeint, aus dem das Erzeugnis&lt;br /&gt;
hergestellt wird. Noch genauer geht es dabei um den Programm-Code -- wann kann man diesen als &amp;quot;gut&amp;quot; bezeichnen?&lt;br /&gt;
&lt;br /&gt;
Für den Entwickler -- den Einzigen, der ursächlich an der [https://xkcd.com/1695/ Code-Qualität] interessiert ist --&lt;br /&gt;
muß der Code wartbar, erweiterbar und änderbar sein. Der Grad &#039;&#039;dieser&#039;&#039; Eigenschaften bestimmt die Güte des Codes. Die Optimierung dieser Eigenschaften steht bisweilen im Widerspruch zu anderen Eigenschaften -- insbesondere der Performance.&lt;br /&gt;
Das Abwägen ist Aufgabe des Architekten und liegt außerhalb des Scope dieses Textes; hier geht es ausschließlich darum&lt;br /&gt;
die Code-Qualität zu verbessern.&lt;br /&gt;
&lt;br /&gt;
Es giebt eine unüberschaubare Fülle an Regeln, Tipps, Techniken und Ideologien zum Thema. Nahezu jeder Entwickler,&lt;br /&gt;
den man zum Thema Code-Qualität befragt weiß einen anderen Strauß aus seinen Erfahrungen zu binden.&lt;br /&gt;
&lt;br /&gt;
Aus dem Wunsch heraus, einen Überblick über die verwirrende Vielzahl von Begriffe, Ansichten und Ansätzen zu gewinnen&lt;br /&gt;
ist die untige Sammlung entstanden. Sie ist weder vollständig noch verbindlich, bietet dem interessierten Leser aber&lt;br /&gt;
eine Basis für die weitere Erkundung der Materie. Es wird zwar der Versuch eine Einteilung gemacht um den Überblick zu&lt;br /&gt;
verbessern, aber es wird versucht zu vermeiden eine Wertung vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
= Leitgedanken =&lt;br /&gt;
Ein Leitgedanke zu dem es bislang noch kein vernünftiges Gegenargument giebt ist folgender:&lt;br /&gt;
{{quotation|Die Qualität von Code bemißt sich daran, wie leicht er zu lesen ist}}&lt;br /&gt;
Über die Frage, wie &amp;quot;lesbarer&amp;quot; Code konkret auszusehen hat giebt es allerdings unterschiedliche Auffassungen.&lt;br /&gt;
Daraus kann man auch ableiten, daß bessere Lesbarkeit nicht automatisch zu besserer Änderbarkeit führt.&lt;br /&gt;
Sie führt aber dazu, daß der Code besser zu verstehen ist, daher besser bearbeitet werden kann und damit besser&lt;br /&gt;
zu warten ist. &amp;quot;Lesbarkeit&amp;quot; bleibt ein Kernzeil des Qualitäts-Suchenden und er wird sich die Frage bei jeder Code-Zeile&lt;br /&gt;
zu stellen haben.&lt;br /&gt;
&lt;br /&gt;
{{quotation|Die Grenzen meiner Sprache sind die Grenzen meiner Welt}}&lt;br /&gt;
&lt;br /&gt;
Im Kontext der Code-Qualität bedeutet das: So klar meine Sprache ist, so klar ist mein Code. Computer-Sprachen&lt;br /&gt;
(formale Sprachen überhaupt) lassen keine Mehrdeutigkeiten zu. Wird der gleiche Code bei mehrfacher Ausführung&lt;br /&gt;
unterschiedlich interpretiert, so ist das ein Fehler. Eine klare Ausdrucksweise, als Ausdruck klarer Gedanken ist&lt;br /&gt;
eine Grundvoraussetzung klaren Programm-Codes.&lt;br /&gt;
&lt;br /&gt;
{{quotation|Separation of Concerns}}&lt;br /&gt;
&lt;br /&gt;
ToDo: Erklärung wie die Idee von Dijkstraa als Leitgedanke zu verstehen ist&lt;br /&gt;
&lt;br /&gt;
= Regeln =&lt;br /&gt;
Eine Regel ist eine Richtlinie die vermittelt was man tun – oder lassen – sollte, aber nicht vorgeben wie man das erreicht.&lt;br /&gt;
Regeln weisen die Richtung, bestimmen den Generalkurs; bieten aber wenig Hilfe bei der Überwindung konkreter Hindernisse.&lt;br /&gt;
Regeln sind keine Naturgesetze; es liegt in ihrer Natur, daß man auch von ihnen abweichen kann.&lt;br /&gt;
Es ist wichtig, den Wert einer Regel zu erkennen und daran die Maßnahmen auszuwählen die sie unterstützen.&lt;br /&gt;
&lt;br /&gt;
Die Abgrenzung von Regeln gegen best practices und auch gegen konkrete Maßnahmen ist nicht immer scharf auszumachen.&lt;br /&gt;
Aber bevor man sich in exegetische Schlachten begibt, sollte man sich immer fragen, worum es eigentlich geht.&lt;br /&gt;
Das Ziel ist klarer, handhabbarer Code, das zu erreichen ist jeder Weg erlaubt.&lt;br /&gt;
Das gilt im Übrigen auch für die Gewichtung von Regeln, Ideologie ist immer der falsche Weg -- egal wohin.&lt;br /&gt;
&lt;br /&gt;
* DRY - [[Don&#039;t repeat yourself]]&lt;br /&gt;
* KISS – Keep it simple stupid [http://www.commitstrip.com/en/2018/10/29/only-the-penitent-coder-will-pass/ commitstrip]&lt;br /&gt;
** Ockhams Razor&lt;br /&gt;
** Law of Parsimony&lt;br /&gt;
** Principle of Least Surprise&lt;br /&gt;
* SoC – Separation of Concerns (im Sinne von Aufgaben-Trennung)&lt;br /&gt;
* YAGNI – You Aren&#039;t Gonna Need It [https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it Wikipedia]&lt;br /&gt;
* [[Cohesion|high cohesion/loose coupling]]&lt;br /&gt;
* OCP – Open/Closed Principle&lt;br /&gt;
* SRP – Single Responsibility Principle&lt;br /&gt;
* Don’t make me think/write your code for everybody&lt;br /&gt;
* IoC – Inversion of Control / Dependency Inversion&lt;br /&gt;
* Form follows Function – Pragmatismus vor Ästhetik&lt;br /&gt;
* ISP – Interface Segregation Principle&lt;br /&gt;
* Stick to the Paradigm&lt;br /&gt;
* Tell don&#039;t ask ([https://martinfowler.com/bliki/TellDontAsk.html Martin Fowler])&lt;br /&gt;
&lt;br /&gt;
Was ist mit SOLID?&lt;br /&gt;
&lt;br /&gt;
Robert C. Martin hat fünf Prinzipien (SRP, open/closed, Liskov, ISP, DI) zusammengefaßt und damit ein tolles backronym zu bilden. Ob man dieser Kollektion einen besonderen Wert zuordnen möchte oder nicht sei mal dahingestellt. Das Liskov-Prinzip wurde hier - wegen seiner Konkretheit - unten den best practices eingeordnet. Die Frage wie man IoC und DI beschreibt und gegen einander abgrenzt ist noch zu diskutieren.&lt;br /&gt;
&lt;br /&gt;
= Best Practice =&lt;br /&gt;
Best Practices – auch Heuristiken genannt – sind Techniken oder Vorgehensweisen, die sich in der Praxis in irgendeiner Form&lt;br /&gt;
und iregndeiner Situation bewährt haben. Meist lassen sie Gestaltungsspielraum, wenn es um die konkrete Anwendung geht – die&lt;br /&gt;
Abgrenzung zwischen einer konkreten Regel und einer allgemeinen Heuristik ist fließend. Und man sollte immer bedenken,&lt;br /&gt;
daß best practices in der Regel aus konkreten Situationen heraus entstanden sind und nicht auf jede beliebige Situation übertragbar sind -- dazu giebt es unten ein Antipattern.&lt;br /&gt;
&lt;br /&gt;
* Clean Code (hier nur einige Heuristiken, die sich bei &#039;&#039;meiner&#039;&#039; Arbeit bewährt haben)&lt;br /&gt;
** Jeder Bezeichner soll exakt beschreiben, was das Bezeichnete tut oder enthält&lt;br /&gt;
** Eine Methode soll eine Wert liefern oder etwas tun, aber nicht beides&lt;br /&gt;
** Methoden (auch Konstruktoren) soll nicht mehr als drei Parameter haben&lt;br /&gt;
** Death to Magic numbers&lt;br /&gt;
** saubere Bezeichner sind besser als gute Kommentare sind besser als keine Kommentare sind besser als falsche Kommentare&lt;br /&gt;
** Eine Methode – eine Aufgabe&lt;br /&gt;
** lokale Variablen dort deklarieren, wo sie gebraucht werden&lt;br /&gt;
* Kent Beck&#039;s Design Rules (according to [http://martinfowler.com/bliki/BeckDesignRules.html Martin Fowler])&lt;br /&gt;
** Passes the Tests&lt;br /&gt;
** Reveals intention&lt;br /&gt;
** No Duplication&lt;br /&gt;
** Fewest Elements&lt;br /&gt;
* DI – Dependency Injection (als Implementierung von IoC)&lt;br /&gt;
* LSP - Liskov substitution principle&lt;br /&gt;
* Demeter-Prinzip&lt;br /&gt;
* Trennung von Abstraktions-Ebenen&lt;br /&gt;
* Trennung von Interface und Implementierung siehe dazu auch: Bridge-Pattern&lt;br /&gt;
* Interfaces sollen so schmal wie möglich sein und nur das enthalten was tatsächlich erforderlich ist.&lt;br /&gt;
* verwende Architektur-Pattern&lt;br /&gt;
* verwende das Schichten-Modell&lt;br /&gt;
* Integration Operation Segregation Principle (nach unten scrollen: [http://clean-code-developer.de/die-grade/roter-grad/#Integration_Operation_Segregation_Principle_IOSP IOSP])&lt;br /&gt;
* verwende Design-Pattern (hier einige GoF-Pattern, die ich besonders häufig verwende)&lt;br /&gt;
** Factory Method&lt;br /&gt;
** Adapter&lt;br /&gt;
** (simplified) Builder&lt;br /&gt;
** Singleton&lt;br /&gt;
** Proxy&lt;br /&gt;
** Facade&lt;br /&gt;
** Decorator&lt;br /&gt;
* Delegation statt Vererbung (Delegation wird im GoF-Buch nicht als Pattern sondern als Konzept beschrieben)&lt;br /&gt;
* Ein Konzept – ein Begriff&lt;br /&gt;
::Bsp: die eMail-Adresse sollte im Code nicht durcheinander als &amp;quot;eMail_Adresse&amp;quot;, &amp;quot;mail-Adresse&amp;quot;, &amp;quot;mail&amp;quot;, &amp;quot;eMail&amp;quot; oder sonstwie bezeichnet werden, sondern immer gleich&lt;br /&gt;
* vermeide Antipattern&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Interface_bloat Interface bloat] -- Interfaces verlangen mehr als erforderlich&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Inner-platform_effect Inner-platform effect] – Das System erlaubt soviel Customization, daß eine schlechte Plattform daraus geworden ist.&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Constant_interface Constant Interface] -- Interfaces dienen nur der Definition von Konstanten&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Sequential_coupling Sequential coupling] -– Die Klasse verlangt den Aufruf ihrer Methoden in einer bestimmten Reihenfolge&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Cargo_cult_programming Cargo cult programming] -– Pattern und Methoden verwenden ohne sie zu verstehen&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Golden_hammer Golden hammer] / [https://en.wikipedia.org/wiki/No_Silver_Bullet Silver bullet] -– Alle Probleme mit der gleichen (Lieblings-)Methode lösen&lt;br /&gt;
** Base Bean – Vererbung soll is-a-Beziehungen abbilden, nicht has-a&lt;br /&gt;
** Stellvertreter-Typen – Statt einen Datentyp zu definieren, existierende Klassen (besonders String) mißbrauchen&lt;br /&gt;
** [[Petting Zoo]] - keeping code that is not worth it&lt;br /&gt;
* vermeide [[Code Smell]]s&lt;br /&gt;
* führe regelmäßig Refactoring durch&lt;br /&gt;
* Verwende eine durchgehende Nomenklatur&lt;br /&gt;
* Stick to the Coding Guidelines&lt;br /&gt;
* Das gleiche Problem sollte immer auf gleiche Art und Weise gelöst werden&lt;br /&gt;
* Verwende für Kommentare und Bezeichner nur natürliche Sprachen die Du auch beherrschst&lt;br /&gt;
:actualValue für den aktuellen Wert (richtig ist current)&lt;br /&gt;
:bound als Übersetzung für &amp;quot;verknüpft&amp;quot; (richtig ist linked)&lt;br /&gt;
* Don&#039;t state the obvious:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Logger logger = LoggerFactory.obtainLogger();&lt;br /&gt;
String stringToBeLogged = &amp;quot;log: logging start of action Foo&amp;quot;;&lt;br /&gt;
logger.log(stringToBeLogged);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* {{java|toString()}} ist kein Serialisierungs-Tool&lt;br /&gt;
* zu viel von etwas ist selten gut:&lt;br /&gt;
: &amp;lt;q&amp;gt;If you know what you&#039;re doing, three layers is enough; if you don&#039;t, even seventeen levels won&#039;t help.&amp;lt;/q&amp;gt;&lt;br /&gt;
:([https://en.wikipedia.org/wiki/Michael_A._Padlipsky Michael Padlipsky])&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
Entgegen anderslautender Meinungen erhöht der Einsatz von Tools nicht automatisch die Qualität. Das Berechnen von Werten anhand von Metriken beispielsweise trägt zunächst gar nichts zur Qualität bei, erst die Auswertung und das Durchführen von Maßnahmen zur Änderung der Werte kann als qualitätsstiftende Maßnahme gelten. Nichtsdestotrotz unterstützt die Verwendung von Hilfsmitteln den Entwickler dabei den Weg zum Code hoher Qualität zu beschreiten.&lt;br /&gt;
&lt;br /&gt;
* automatisch durchgeführte Unit-Tests&lt;br /&gt;
:Unit-Tests als &amp;quot;Tool&amp;quot; zu beschreiben mag seltsam klingen. Tatsächlich sind Unit-Tests aber nicht Teil des produktiven Codes und daher kann man mit Fug und Recht von einem Tool sprechen.&lt;br /&gt;
* Metriken&lt;br /&gt;
* Tools zur Code-Analyse (sonar, java-Compiler-Warnings)&lt;br /&gt;
* Tools zur Messung der Test-Abdeckung (EclEmma)&lt;br /&gt;
* Automatische Code-Formatierung (Eclipse Code Formatter)&lt;br /&gt;
* Coding-Guidelines&lt;br /&gt;
* [http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html Sun Code Conventions]&lt;br /&gt;
:Sie werden seit 1999 nicht mehr gepflegt. Einige Regeln sind überholt, andere zweifelhaft (z.B. 6.2: Variablen-Deklarationen nur am Beginn eines Code-Blocks plazieren), Sie bilden aber die Grundlage für das Code-Layout und man sollte sie kennen und berücksichtigen.&amp;lt;br&amp;gt;&lt;br /&gt;
:(Fun fact: Der Autor hat anscheinend von C abgeschrieben – es sind tatsächlich ein paar Fehler im Dokument)&lt;br /&gt;
* Refactoring-Tools (IDEs wie Eclipse bringen eine Menge davon mit&lt;br /&gt;
&lt;br /&gt;
= Arbeitstechniken =&lt;br /&gt;
Die klassische Technik des Entwicklers ist das Zurückziehen hinter die Tastatur. Der Entwickler kriecht erst hervor, wenn das Werk vollendet ist. Das beschreibt einen Teil der Tätigkeit, reicht aber schon seit einem halben Jahrhundert nicht mehr aus. Und auch die Handgriffe, mit denen der Entwickler im stillen Kämmerlein den Wandel von Buchstaben in Code vollzieht wandeln sich im Laufe der Zeit. Man muß nicht jede Technik übernehmen, aber man sollte sich damit befassen und zumindest genau wissen, warum man sie nicht einsetzt.&lt;br /&gt;
&lt;br /&gt;
* [[Boy Scout Principle]]&lt;br /&gt;
* Code – fremden und eigenen – lesen und reflektieren&lt;br /&gt;
* Zuhören&lt;br /&gt;
* Diskussion über Code&lt;br /&gt;
* Code-Reviews&lt;br /&gt;
* XP – extreme Programming&lt;br /&gt;
** TDD – Test Driven Development&lt;br /&gt;
** Test First Ansatz&lt;br /&gt;
** Pair Programming&lt;br /&gt;
** Root Cause Analysis&lt;br /&gt;
** Incremental Design&lt;br /&gt;
* Embrace the CATSAN method&lt;br /&gt;
* Programming by Difference (→ Michael Feathers)&lt;br /&gt;
* Rubber Duck Debugging&lt;br /&gt;
* Technologische Schulden minimieren&lt;br /&gt;
&lt;br /&gt;
= Literatur =&lt;br /&gt;
* Edsger Dijkstra [https://www.cs.utexas.edu/users/EWD/transcriptions/EWD04xx/EWD447.html On the role of scientific thought]&lt;br /&gt;
* Refactoring: Improving the Design of Existing Code (Martin Fowler/Kent Beck)&lt;br /&gt;
* Working Effectively with Legacy Code (Michael C. Feathers)&lt;br /&gt;
* Clean Code (Robert C. Martin)&lt;br /&gt;
* Design Patterns: Elements of Reusable Object-Oriented Software (Gamma/Helm/Vlissides/Johnson)&lt;br /&gt;
* The Mythical Man Month (Fred Brooks)&lt;br /&gt;
* The Systems Bible – 3rd edition of &amp;quot;Systemantics&amp;quot; (John Gall) [https://en.wikipedia.org/wiki/Systemantics Überblick in der Wikipedia]&lt;br /&gt;
* [https://www.google.de/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=2&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwjKitDwvJ3NAhXFKMAKHQ0hBWEQFggpMAE&amp;amp;url=http%3A%2F%2Fworrydream.com%2Frefs%2FBrooks-NoSilverBullet.pdf&amp;amp;usg=AFQjCNGkOYvU4WQgqaHGAqGgicO0XTRcw&amp;amp;bvm=bv.124088155,d.bGg No Silver Bullet] (Fred Brooks)&lt;br /&gt;
* [https://www.google.de/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=1&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwiWtayRvZ3NAhUMDMAKHe_JDCYQFggcMAA&amp;amp;url=http%3A%2F%2Fhomepages.cwi.nl%2F~storm%2Fteaching%2Freader%2FDijkstra68.pdf&amp;amp;usg=AFQjCNFIgAgWJ_Aoph79yl9-tFusEGgglQ Goto Considered Harmful] (Edsger Dijkstra)&lt;br /&gt;
* [http://clean-code-developer.de/ clean code developer site]&lt;br /&gt;
* [http://chris.beams.io/posts/git-commit/ Regeln für GIT-commit-Kommentare]&lt;br /&gt;
* [http://www.cs.yale.edu/homes/perlis-alan/quotes.html Epigramme von Alan Perlis]&lt;br /&gt;
* [https://www.heise.de/newsticker/meldung/John-Romero-Von-id-Softwares-Anfaengen-und-World-of-Warcraft-Sucht-3296840.html Programmier-Regeln von John Romero]&lt;br /&gt;
* [https://sourcemaking.com Gute Sammlung von Pattern, Anti-Pattern etc.]&lt;br /&gt;
* [https://xkcd.com/1926 Bad Code in XKCD]&lt;br /&gt;
&lt;br /&gt;
= Zen =&lt;br /&gt;
Keine Richtlinien, keine Anweisungen, einfach Aussagen über die man nachdenken kann. Hier kann man beliebig hitzig diskutieren; wichtig ist nur, daß man darüber – möglichst unvoreingenommen – nachdenkt.&lt;br /&gt;
&lt;br /&gt;
* Wer sich nicht klar ausdrückt, denkt auch nicht klar&lt;br /&gt;
* big bang features lead to big bang&lt;br /&gt;
* Software Engineering ist agnostisch&lt;br /&gt;
* Ein Beispiel beweist nichts, widerlegt aber alles – soviel zu TDD- und Test-Abdeckungs-Fetischismus&lt;br /&gt;
* Ist TDD die zeitgemäße Formulierung für &amp;quot;trial and error&amp;quot;?&lt;br /&gt;
* Wenn Du weißt was Du tust, bist Du gesegnet&lt;br /&gt;
* If it ain&#039;t broken, don&#039;t fix it vs. Refactoring&lt;br /&gt;
* Verwende nur was Du auch verstehst ([https://xkcd.com/1597/ Wie XKCD GIT charakterisiert])&lt;br /&gt;
* Wer etwas ablehnt oder verteidigt sollte genau wissen warum&lt;br /&gt;
* Nichts hält so lange wie ein Provisorium&lt;br /&gt;
* Wer trennt schafft Abhängigkeiten, wer nicht trennt schafft Chaos&lt;br /&gt;
* Nichts ist so einfach, daß man es nicht falsch machen könnte&lt;br /&gt;
* Eine Entscheidung ist richtig, wenn sie rational begründet werden kann&lt;br /&gt;
* Was wert ist daß man es tut, ist wert daß man es richtig tut.&lt;br /&gt;
* Wenn man versucht Probleme auszusitzen, kriechen sie irgendwann hervor und treten einem in den Hintern&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Der_Weg_zum_guten_Code&amp;diff=199</id>
		<title>Der Weg zum guten Code</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Der_Weg_zum_guten_Code&amp;diff=199"/>
		<updated>2024-11-28T10:33:15Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Best Practice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
Um entscheiden zu können welcher [https://xkcd.com/844/ Weg zum guten Code] führt, muß man festlegen was&lt;br /&gt;
&#039;&#039;guten&#039;&#039; Code von schlechtem unterscheidet. Die Erkenntnis, daß es nicht gleichgültig ist, wie Code beschaffen&lt;br /&gt;
ist wurde ja offensichtlich schon gewonnen -- andernfalls wäre die Suche eine sinnlose.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Gut&amp;quot; ist der Code, wenn er über die blanke Funktionalität hinaus weitere Eigenschaften erfüllt. Über diese&lt;br /&gt;
nichtfunktionalen Eigenschaften giebt es eine große Literatur, die Worte &amp;quot;Qualiät&amp;quot; und &amp;quot;Architektur&amp;quot; fallen einem in diesem&lt;br /&gt;
Zusammenhang ein. Dabei geht es aber in der Regel um die Software-Qualität, also die Qualität des gesamten Erzeugnisses&lt;br /&gt;
im Zusammenspiel mit der Umgebung in der es betrieben wird.&lt;br /&gt;
&lt;br /&gt;
Diese Seite engt den Blick ganz bewußt auf den &amp;quot;Code&amp;quot; ein. Damit ist der Quelltext gemeint, aus dem das Erzeugnis&lt;br /&gt;
hergestellt wird. Noch genauer geht es dabei um den Programm-Code -- wann kann man diesen als &amp;quot;gut&amp;quot; bezeichnen?&lt;br /&gt;
&lt;br /&gt;
Für den Entwickler -- den Einzigen, der ursächlich an der [https://xkcd.com/1695/ Code-Qualität] interessiert ist --&lt;br /&gt;
muß der Code wartbar, erweiterbar und änderbar sein. Der Grad &#039;&#039;dieser&#039;&#039; Eigenschaften bestimmt die Güte des Codes. Die Optimierung dieser Eigenschaften steht bisweilen im Widerspruch zu anderen Eigenschaften -- insbesondere der Performance.&lt;br /&gt;
Das Abwägen ist Aufgabe des Architekten und liegt außerhalb des Scope dieses Textes; hier geht es ausschließlich darum&lt;br /&gt;
die Code-Qualität zu verbessern.&lt;br /&gt;
&lt;br /&gt;
Es giebt eine unüberschaubare Fülle an Regeln, Tipps, Techniken und Ideologien zum Thema. Nahezu jeder Entwickler,&lt;br /&gt;
den man zum Thema Code-Qualität befragt weiß einen anderen Strauß aus seinen Erfahrungen zu binden.&lt;br /&gt;
&lt;br /&gt;
Aus dem Wunsch heraus, einen Überblick über die verwirrende Vielzahl von Begriffe, Ansichten und Ansätzen zu gewinnen&lt;br /&gt;
ist die untige Sammlung entstanden. Sie ist weder vollständig noch verbindlich, bietet dem interessierten Leser aber&lt;br /&gt;
eine Basis für die weitere Erkundung der Materie. Es wird zwar der Versuch eine Einteilung gemacht um den Überblick zu&lt;br /&gt;
verbessern, aber es wird versucht zu vermeiden eine Wertung vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
= Leitgedanken =&lt;br /&gt;
Ein Leitgedanke zu dem es bislang noch kein vernünftiges Gegenargument giebt ist folgender:&lt;br /&gt;
{{quotation|Die Qualität von Code bemißt sich daran, wie leicht er zu lesen ist}}&lt;br /&gt;
Über die Frage, wie &amp;quot;lesbarer&amp;quot; Code konkret auszusehen hat giebt es allerdings unterschiedliche Auffassungen.&lt;br /&gt;
Daraus kann man auch ableiten, daß bessere Lesbarkeit nicht automatisch zu besserer Änderbarkeit führt.&lt;br /&gt;
Sie führt aber dazu, daß der Code besser zu verstehen ist, daher besser bearbeitet werden kann und damit besser&lt;br /&gt;
zu warten ist. &amp;quot;Lesbarkeit&amp;quot; bleibt ein Kernzeil des Qualitäts-Suchenden und er wird sich die Frage bei jeder Code-Zeile&lt;br /&gt;
zu stellen haben.&lt;br /&gt;
&lt;br /&gt;
{{quotation|Die Grenzen meiner Sprache sind die Grenzen meiner Welt}}&lt;br /&gt;
&lt;br /&gt;
Im Kontext der Code-Qualität bedeutet das: So klar meine Sprache ist, so klar ist mein Code. Computer-Sprachen&lt;br /&gt;
(formale Sprachen überhaupt) lassen keine Mehrdeutigkeiten zu. Wird der gleiche Code bei mehrfacher Ausführung&lt;br /&gt;
unterschiedlich interpretiert, so ist das ein Fehler. Eine klare Ausdrucksweise, als Ausdruck klarer Gedanken ist&lt;br /&gt;
eine Grundvoraussetzung klaren Programm-Codes.&lt;br /&gt;
&lt;br /&gt;
{{quotation|Separation of Concerns}}&lt;br /&gt;
&lt;br /&gt;
ToDo: Erklärung wie die Idee von Dijkstraa als Leitgedanke zu verstehen ist&lt;br /&gt;
&lt;br /&gt;
= Regeln =&lt;br /&gt;
Eine Regel ist eine Richtlinie die vermittelt was man tun – oder lassen – sollte, aber nicht vorgeben wie man das erreicht.&lt;br /&gt;
Regeln weisen die Richtung, bestimmen den Generalkurs; bieten aber wenig Hilfe bei der Überwindung konkreter Hindernisse.&lt;br /&gt;
Regeln sind keine Naturgesetze; es liegt in ihrer Natur, daß man auch von ihnen abweichen kann.&lt;br /&gt;
Es ist wichtig, den Wert einer Regel zu erkennen und daran die Maßnahmen auszuwählen die sie unterstützen.&lt;br /&gt;
&lt;br /&gt;
Die Abgrenzung von Regeln gegen best practices und auch gegen konkrete Maßnahmen ist nicht immer scharf auszumachen.&lt;br /&gt;
Aber bevor man sich in exegetische Schlachten begibt, sollte man sich immer fragen, worum es eigentlich geht.&lt;br /&gt;
Das Ziel ist klarer, handhabbarer Code, das zu erreichen ist jeder Weg erlaubt.&lt;br /&gt;
Das gilt im Übrigen auch für die Gewichtung von Regeln, Ideologie ist immer der falsche Weg -- egal wohin.&lt;br /&gt;
&lt;br /&gt;
* DRY - [[Don&#039;t repeat yourself]]&lt;br /&gt;
* KISS – Keep it simple stupid [http://www.commitstrip.com/en/2018/10/29/only-the-penitent-coder-will-pass/ commitstrip]&lt;br /&gt;
** Ockhams Razor&lt;br /&gt;
** Law of Parsimony&lt;br /&gt;
** Principle of Least Surprise&lt;br /&gt;
* SoC – Separation of Concerns (im Sinne von Aufgaben-Trennung)&lt;br /&gt;
* YAGNI – You Aren&#039;t Gonna Need It [https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it Wikipedia]&lt;br /&gt;
* [[Cohesion|high cohesion/loose coupling]]&lt;br /&gt;
* OCP – Open/Closed Principle&lt;br /&gt;
* SRP – Single Responsibility Principle&lt;br /&gt;
* Don’t make me think/write your code for everybody&lt;br /&gt;
* IoC – Inversion of Control / Dependency Inversion&lt;br /&gt;
* Form follows Function – Pragmatismus vor Ästhetik&lt;br /&gt;
* ISP – Interface Segregation Principle&lt;br /&gt;
* Stick to the Paradigm&lt;br /&gt;
* Tell don&#039;t ask ([https://martinfowler.com/bliki/TellDontAsk.html Martin Fowler])&lt;br /&gt;
&lt;br /&gt;
Was ist mit SOLID?&lt;br /&gt;
&lt;br /&gt;
Robert C. Martin hat fünf Prinzipien (SRP, open/closed, Liskov, ISP, DI) zusammengefaßt und damit ein tolles backronym zu bilden. Ob man dieser Kollektion einen besonderen Wert zuordnen möchte oder nicht sei mal dahingestellt. Das Liskov-Prinzip wurde hier - wegen seiner Konkretheit - unten den best practices eingeordnet. Die Frage wie man IoC und DI beschreibt und gegen einander abgrenzt ist noch zu diskutieren.&lt;br /&gt;
&lt;br /&gt;
= Best Practice =&lt;br /&gt;
Best Practices – auch Heuristiken genannt – sind Techniken oder Vorgehensweisen, die sich in der Praxis in irgendeiner Form&lt;br /&gt;
und iregndeiner Situation bewährt haben. Meist lassen sie Gestaltungsspielraum, wenn es um die konkrete Anwendung geht – die&lt;br /&gt;
Abgrenzung zwischen einer konkreten Regel und einer allgemeinen Heuristik ist fließend. Und man sollte immer bedenken,&lt;br /&gt;
daß best practices in der Regel aus konkreten Situationen heraus entstanden sind und nicht auf jede beliebige Situation übertragbar sind -- dazu giebt es unten ein Antipattern.&lt;br /&gt;
&lt;br /&gt;
* Clean Code (hier nur einige Heuristiken, die sich bei &#039;&#039;meiner&#039;&#039; Arbeit bewährt haben)&lt;br /&gt;
** Jeder Bezeichner soll exakt beschreiben, was das Bezeichnete tut oder enthält&lt;br /&gt;
** Eine Methode soll eine Wert liefern oder etwas tun, aber nicht beides&lt;br /&gt;
** Methoden (auch Konstruktoren) soll nicht mehr als drei Parameter haben&lt;br /&gt;
** Death to Magic numbers&lt;br /&gt;
** saubere Bezeichner sind besser als gute Kommentare sind besser als keine Kommentare sind besser als falsche Kommentare&lt;br /&gt;
** Eine Methode – eine Aufgabe&lt;br /&gt;
** lokale Variablen dort deklarieren, wo sie gebraucht werden&lt;br /&gt;
* Kent Beck&#039;s Design Rules (according to [http://martinfowler.com/bliki/BeckDesignRules.html Martin Fowler])&lt;br /&gt;
** Passes the Tests&lt;br /&gt;
** Reveals intention&lt;br /&gt;
** No Duplication&lt;br /&gt;
** Fewest Elements&lt;br /&gt;
* DI – Dependency Injection (als Implementierung von IoC)&lt;br /&gt;
* LSP - Liskov substitution principle&lt;br /&gt;
* Demeter-Prinzip&lt;br /&gt;
* Trennung von Abstraktions-Ebenen&lt;br /&gt;
* Trennung von Interface und Implementierung siehe dazu auch: Bridge-Pattern&lt;br /&gt;
* Interfaces sollen so schmal wie möglich sein und nur das enthalten was tatsächlich erforderlich ist.&lt;br /&gt;
* verwende Architektur-Pattern&lt;br /&gt;
* verwende das Schichten-Modell&lt;br /&gt;
* Integration Operation Segregation Principle (nach unten scrollen: [http://clean-code-developer.de/die-grade/roter-grad/#Integration_Operation_Segregation_Principle_IOSP IOSP])&lt;br /&gt;
* verwende Design-Pattern (hier einige GoF-Pattern, die ich besonders häufig verwende)&lt;br /&gt;
** Factory Method&lt;br /&gt;
** Adapter&lt;br /&gt;
** (simplified) Builder&lt;br /&gt;
** Singleton&lt;br /&gt;
** Proxy&lt;br /&gt;
** Facade&lt;br /&gt;
** Decorator&lt;br /&gt;
* Delegation statt Vererbung (Delegation wird im GoF-Buch nicht als Pattern sondern als Konzept beschrieben)&lt;br /&gt;
* Ein Konzept – ein Begriff&lt;br /&gt;
::Bsp: die eMail-Adresse sollte im Code nicht durcheinander als &amp;quot;eMail_Adresse&amp;quot;, &amp;quot;mail-Adresse&amp;quot;, &amp;quot;mail&amp;quot;, &amp;quot;eMail&amp;quot; oder sonstwie bezeichnet werden, sondern immer gleich&lt;br /&gt;
* vermeide Antipattern&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Interface_bloat Interface bloat] -- Interfaces verlangen mehr als erforderlich&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Inner-platform_effect Inner-platform effect] – Das System erlaubt soviel Customization, daß eine schlechte Plattform daraus geworden ist.&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Constant_interface Constant Interface] -- Interfaces dienen nur der Definition von Konstanten&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Sequential_coupling Sequential coupling] -– Die Klasse verlangt den Aufruf ihrer Methoden in einer bestimmten Reihenfolge&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Cargo_cult_programming Cargo cult programming] -– Pattern und Methoden verwenden ohne sie zu verstehen&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Golden_hammer Golden hammer] / [https://en.wikipedia.org/wiki/No_Silver_Bullet Silver bullet] -– Alle Probleme mit der gleichen (Lieblings-)Methode lösen&lt;br /&gt;
** Base Bean – Vererbung soll is-a-Beziehungen abbilden, nicht has-a&lt;br /&gt;
** Stellvertreter-Typen – Statt einen Datentyp zu definieren, existierende Klassen (besonders String) mißbrauchen&lt;br /&gt;
** [[Petting Zoo]] - keeping code that is not worth it&lt;br /&gt;
* vermeide [[Code Smell]]s&lt;br /&gt;
* führe regelmäßig Refactoring durch&lt;br /&gt;
* Verwende eine durchgehende Nomenklatur&lt;br /&gt;
* Stick to the Coding Guidelines&lt;br /&gt;
* Das gleiche Problem sollte immer auf gleiche Art und Weise gelöst werden&lt;br /&gt;
* Verwende für Kommentare und Bezeichner nur natürliche Sprachen die Du auch beherrschst&lt;br /&gt;
:actualValue für den aktuellen Wert (richtig ist current)&lt;br /&gt;
:bound als Übersetzung für &amp;quot;verknüpft&amp;quot; (richtig ist linked)&lt;br /&gt;
* Don&#039;t state the obvious:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Logger logger = LoggerFactory.obtainLogger();&lt;br /&gt;
String stringToBeLogged = &amp;quot;log: logging start of action Foo&amp;quot;;&lt;br /&gt;
logger.log(stringToBeLogged);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
* {{java|toString()}} ist kein Serialisierungs-Tool&lt;br /&gt;
* zu viel von etwas ist selten gut:&lt;br /&gt;
: &amp;lt;q&amp;gt;If you know what you&#039;re doing, three layers is enough; if you don&#039;t, even seventeen levels won&#039;t help.&amp;lt;/q&amp;gt;&lt;br /&gt;
:([https://en.wikipedia.org/wiki/Michael_A._Padlipsky Michael Padlipsky])&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
Entgegen anderslautender Meinungen erhöht der Einsatz von Tools nicht automatisch die Qualität. Das Berechnen von Werten anhand von Metriken beispielsweise trägt zunächst gar nichts zur Qualität bei, erst die Auswertung und das Durchführen von Maßnahmen zur Änderung der Werte kann als qualitätsstiftende Maßnahme gelten. Nichtsdestotrotz unterstützt die Verwendung von Hilfsmitteln den Entwickler dabei den Weg zum Code hoher Qualität zu beschreiten.&lt;br /&gt;
&lt;br /&gt;
* automatisch durchgeführte Unit-Tests&lt;br /&gt;
:Unit-Tests als &amp;quot;Tool&amp;quot; zu beschreiben mag seltsam klingen. Tatsächlich sind Unit-Tests aber nicht Teil des produktiven Codes und daher kann man mit Fug und Recht von einem Tool sprechen.&lt;br /&gt;
* Metriken&lt;br /&gt;
* Tools zur Code-Analyse (sonar, java-Compiler-Warnings)&lt;br /&gt;
* Tools zur Messung der Test-Abdeckung (EclEmma)&lt;br /&gt;
* Automatische Code-Formatierung (Eclipse Code Formatter)&lt;br /&gt;
* Coding-Guidelines&lt;br /&gt;
* [http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html Sun Code Conventions]&lt;br /&gt;
:Sie werden seit 1999 nicht mehr gepflegt. Einige Regeln sind überholt, andere zweifelhaft (z.B. 6.2: Variablen-Deklarationen nur am Beginn eines Code-Blocks plazieren), Sie bilden aber die Grundlage für das Code-Layout und man sollte sie kennen und berücksichtigen.&amp;lt;br&amp;gt;&lt;br /&gt;
:(Fun fact: Der Autor hat anscheinend von C abgeschrieben – es sind tatsächlich ein paar Fehler im Dokument)&lt;br /&gt;
* Refactoring-Tools (IDEs wie Eclipse bringen eine Menge davon mit&lt;br /&gt;
&lt;br /&gt;
= Arbeitstechniken =&lt;br /&gt;
Die klassische Technik des Entwicklers ist das Zurückziehen hinter die Tastatur. Der Entwickler kriecht erst hervor, wenn das Werk vollendet ist. Das beschreibt einen Teil der Tätigkeit, reicht aber schon seit einem halben Jahrhundert nicht mehr aus. Und auch die Handgriffe, mit denen der Entwickler im stillen Kämmerlein den Wandel von Buchstaben in Code vollzieht wandeln sich im Laufe der Zeit. Man muß nicht jede Technik übernehmen, aber man sollte sich damit befassen und zumindest genau wissen, warum man sie nicht einsetzt.&lt;br /&gt;
&lt;br /&gt;
* [[Boy Scout Principle]]&lt;br /&gt;
* Code – fremden und eigenen – lesen und reflektieren&lt;br /&gt;
* zuhören&lt;br /&gt;
* Diskussion über Code&lt;br /&gt;
* Code-Reviews&lt;br /&gt;
* XP – extreme Programming&lt;br /&gt;
** TDD – Test Driven Development&lt;br /&gt;
** Test First Ansatz&lt;br /&gt;
** Pair Programming&lt;br /&gt;
** Root Cause Analysis&lt;br /&gt;
** Incremental Design&lt;br /&gt;
* Embrace the CATSAN method&lt;br /&gt;
* Programming by Difference (→ Michael Feathers)&lt;br /&gt;
* Rubber Duck Debugging&lt;br /&gt;
* Technologische Schulden minimieren&lt;br /&gt;
&lt;br /&gt;
= Literatur =&lt;br /&gt;
* Edsger Dijkstra [https://www.cs.utexas.edu/users/EWD/transcriptions/EWD04xx/EWD447.html On the role of scientific thought]&lt;br /&gt;
* Refactoring: Improving the Design of Existing Code (Martin Fowler/Kent Beck)&lt;br /&gt;
* Working Effectively with Legacy Code (Michael C. Feathers)&lt;br /&gt;
* Clean Code (Robert C. Martin)&lt;br /&gt;
* Design Patterns: Elements of Reusable Object-Oriented Software (Gamma/Helm/Vlissides/Johnson)&lt;br /&gt;
* The Mythical Man Month (Fred Brooks)&lt;br /&gt;
* The Systems Bible – 3rd edition of &amp;quot;Systemantics&amp;quot; (John Gall) [https://en.wikipedia.org/wiki/Systemantics Überblick in der Wikipedia]&lt;br /&gt;
* [https://www.google.de/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=2&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwjKitDwvJ3NAhXFKMAKHQ0hBWEQFggpMAE&amp;amp;url=http%3A%2F%2Fworrydream.com%2Frefs%2FBrooks-NoSilverBullet.pdf&amp;amp;usg=AFQjCNGkOYvU4WQgqaHGAqGgicO0XTRcw&amp;amp;bvm=bv.124088155,d.bGg No Silver Bullet] (Fred Brooks)&lt;br /&gt;
* [https://www.google.de/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=1&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwiWtayRvZ3NAhUMDMAKHe_JDCYQFggcMAA&amp;amp;url=http%3A%2F%2Fhomepages.cwi.nl%2F~storm%2Fteaching%2Freader%2FDijkstra68.pdf&amp;amp;usg=AFQjCNFIgAgWJ_Aoph79yl9-tFusEGgglQ Goto Considered Harmful] (Edsger Dijkstra)&lt;br /&gt;
* [http://clean-code-developer.de/ clean code developer site]&lt;br /&gt;
* [http://chris.beams.io/posts/git-commit/ Regeln für GIT-commit-Kommentare]&lt;br /&gt;
* [http://www.cs.yale.edu/homes/perlis-alan/quotes.html Epigramme von Alan Perlis]&lt;br /&gt;
* [https://www.heise.de/newsticker/meldung/John-Romero-Von-id-Softwares-Anfaengen-und-World-of-Warcraft-Sucht-3296840.html Programmier-Regeln von John Romero]&lt;br /&gt;
* [https://sourcemaking.com Gute Sammlung von Pattern, Anti-Pattern etc.]&lt;br /&gt;
* [https://xkcd.com/1926 Bad Code in XKCD]&lt;br /&gt;
&lt;br /&gt;
= Zen =&lt;br /&gt;
Keine Richtlinien, keine Anweisungen, einfach Aussagen über die man nachdenken kann. Hier kann man beliebig hitzig diskutieren; wichtig ist nur, daß man darüber – möglichst unvoreingenommen – nachdenkt.&lt;br /&gt;
&lt;br /&gt;
* Wer sich nicht klar ausdrückt, denkt auch nicht klar&lt;br /&gt;
* big bang features lead to big bang&lt;br /&gt;
* Software Engineering ist agnostisch&lt;br /&gt;
* Ein Beispiel beweist nichts, widerlegt aber alles – soviel zu TDD- und Test-Abdeckungs-Fetischismus&lt;br /&gt;
* Ist TDD die zeitgemäße Formulierung für &amp;quot;trial and error&amp;quot;?&lt;br /&gt;
* Wenn Du weißt was Du tust, bist Du gesegnet&lt;br /&gt;
* If it ain&#039;t broken, don&#039;t fix it vs. Refactoring&lt;br /&gt;
* Verwende nur was Du auch verstehst ([https://xkcd.com/1597/ Wie XKCD GIT charakterisiert])&lt;br /&gt;
* Wer etwas ablehnt oder verteidigt sollte genau wissen warum&lt;br /&gt;
* Nichts hält so lange wie ein Provisorium&lt;br /&gt;
* Wer trennt schafft Abhängigkeiten, wer nicht trennt schafft Chaos&lt;br /&gt;
* Nichts ist so einfach, daß man es nicht falsch machen könnte&lt;br /&gt;
* Eine Entscheidung ist richtig, wenn sie rational begründet werden kann&lt;br /&gt;
* Was wert ist daß man es tut, ist wert daß man es richtig tut.&lt;br /&gt;
* Wenn man versucht Probleme auszusitzen, kriechen sie irgendwann hervor und treten einem in den Hintern&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Der_Weg_zum_guten_Code&amp;diff=198</id>
		<title>Der Weg zum guten Code</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Der_Weg_zum_guten_Code&amp;diff=198"/>
		<updated>2024-11-28T10:27:55Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Best Practice */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
Um entscheiden zu können welcher [https://xkcd.com/844/ Weg zum guten Code] führt, muß man festlegen was&lt;br /&gt;
&#039;&#039;guten&#039;&#039; Code von schlechtem unterscheidet. Die Erkenntnis, daß es nicht gleichgültig ist, wie Code beschaffen&lt;br /&gt;
ist wurde ja offensichtlich schon gewonnen -- andernfalls wäre die Suche eine sinnlose.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Gut&amp;quot; ist der Code, wenn er über die blanke Funktionalität hinaus weitere Eigenschaften erfüllt. Über diese&lt;br /&gt;
nichtfunktionalen Eigenschaften giebt es eine große Literatur, die Worte &amp;quot;Qualiät&amp;quot; und &amp;quot;Architektur&amp;quot; fallen einem in diesem&lt;br /&gt;
Zusammenhang ein. Dabei geht es aber in der Regel um die Software-Qualität, also die Qualität des gesamten Erzeugnisses&lt;br /&gt;
im Zusammenspiel mit der Umgebung in der es betrieben wird.&lt;br /&gt;
&lt;br /&gt;
Diese Seite engt den Blick ganz bewußt auf den &amp;quot;Code&amp;quot; ein. Damit ist der Quelltext gemeint, aus dem das Erzeugnis&lt;br /&gt;
hergestellt wird. Noch genauer geht es dabei um den Programm-Code -- wann kann man diesen als &amp;quot;gut&amp;quot; bezeichnen?&lt;br /&gt;
&lt;br /&gt;
Für den Entwickler -- den Einzigen, der ursächlich an der [https://xkcd.com/1695/ Code-Qualität] interessiert ist --&lt;br /&gt;
muß der Code wartbar, erweiterbar und änderbar sein. Der Grad &#039;&#039;dieser&#039;&#039; Eigenschaften bestimmt die Güte des Codes. Die Optimierung dieser Eigenschaften steht bisweilen im Widerspruch zu anderen Eigenschaften -- insbesondere der Performance.&lt;br /&gt;
Das Abwägen ist Aufgabe des Architekten und liegt außerhalb des Scope dieses Textes; hier geht es ausschließlich darum&lt;br /&gt;
die Code-Qualität zu verbessern.&lt;br /&gt;
&lt;br /&gt;
Es giebt eine unüberschaubare Fülle an Regeln, Tipps, Techniken und Ideologien zum Thema. Nahezu jeder Entwickler,&lt;br /&gt;
den man zum Thema Code-Qualität befragt weiß einen anderen Strauß aus seinen Erfahrungen zu binden.&lt;br /&gt;
&lt;br /&gt;
Aus dem Wunsch heraus, einen Überblick über die verwirrende Vielzahl von Begriffe, Ansichten und Ansätzen zu gewinnen&lt;br /&gt;
ist die untige Sammlung entstanden. Sie ist weder vollständig noch verbindlich, bietet dem interessierten Leser aber&lt;br /&gt;
eine Basis für die weitere Erkundung der Materie. Es wird zwar der Versuch eine Einteilung gemacht um den Überblick zu&lt;br /&gt;
verbessern, aber es wird versucht zu vermeiden eine Wertung vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
= Leitgedanken =&lt;br /&gt;
Ein Leitgedanke zu dem es bislang noch kein vernünftiges Gegenargument giebt ist folgender:&lt;br /&gt;
{{quotation|Die Qualität von Code bemißt sich daran, wie leicht er zu lesen ist}}&lt;br /&gt;
Über die Frage, wie &amp;quot;lesbarer&amp;quot; Code konkret auszusehen hat giebt es allerdings unterschiedliche Auffassungen.&lt;br /&gt;
Daraus kann man auch ableiten, daß bessere Lesbarkeit nicht automatisch zu besserer Änderbarkeit führt.&lt;br /&gt;
Sie führt aber dazu, daß der Code besser zu verstehen ist, daher besser bearbeitet werden kann und damit besser&lt;br /&gt;
zu warten ist. &amp;quot;Lesbarkeit&amp;quot; bleibt ein Kernzeil des Qualitäts-Suchenden und er wird sich die Frage bei jeder Code-Zeile&lt;br /&gt;
zu stellen haben.&lt;br /&gt;
&lt;br /&gt;
{{quotation|Die Grenzen meiner Sprache sind die Grenzen meiner Welt}}&lt;br /&gt;
&lt;br /&gt;
Im Kontext der Code-Qualität bedeutet das: So klar meine Sprache ist, so klar ist mein Code. Computer-Sprachen&lt;br /&gt;
(formale Sprachen überhaupt) lassen keine Mehrdeutigkeiten zu. Wird der gleiche Code bei mehrfacher Ausführung&lt;br /&gt;
unterschiedlich interpretiert, so ist das ein Fehler. Eine klare Ausdrucksweise, als Ausdruck klarer Gedanken ist&lt;br /&gt;
eine Grundvoraussetzung klaren Programm-Codes.&lt;br /&gt;
&lt;br /&gt;
{{quotation|Separation of Concerns}}&lt;br /&gt;
&lt;br /&gt;
ToDo: Erklärung wie die Idee von Dijkstraa als Leitgedanke zu verstehen ist&lt;br /&gt;
&lt;br /&gt;
= Regeln =&lt;br /&gt;
Eine Regel ist eine Richtlinie die vermittelt was man tun – oder lassen – sollte, aber nicht vorgeben wie man das erreicht.&lt;br /&gt;
Regeln weisen die Richtung, bestimmen den Generalkurs; bieten aber wenig Hilfe bei der Überwindung konkreter Hindernisse.&lt;br /&gt;
Regeln sind keine Naturgesetze; es liegt in ihrer Natur, daß man auch von ihnen abweichen kann.&lt;br /&gt;
Es ist wichtig, den Wert einer Regel zu erkennen und daran die Maßnahmen auszuwählen die sie unterstützen.&lt;br /&gt;
&lt;br /&gt;
Die Abgrenzung von Regeln gegen best practices und auch gegen konkrete Maßnahmen ist nicht immer scharf auszumachen.&lt;br /&gt;
Aber bevor man sich in exegetische Schlachten begibt, sollte man sich immer fragen, worum es eigentlich geht.&lt;br /&gt;
Das Ziel ist klarer, handhabbarer Code, das zu erreichen ist jeder Weg erlaubt.&lt;br /&gt;
Das gilt im Übrigen auch für die Gewichtung von Regeln, Ideologie ist immer der falsche Weg -- egal wohin.&lt;br /&gt;
&lt;br /&gt;
* DRY - [[Don&#039;t repeat yourself]]&lt;br /&gt;
* KISS – Keep it simple stupid [http://www.commitstrip.com/en/2018/10/29/only-the-penitent-coder-will-pass/ commitstrip]&lt;br /&gt;
** Ockhams Razor&lt;br /&gt;
** Law of Parsimony&lt;br /&gt;
** Principle of Least Surprise&lt;br /&gt;
* SoC – Separation of Concerns (im Sinne von Aufgaben-Trennung)&lt;br /&gt;
* YAGNI – You Aren&#039;t Gonna Need It [https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it Wikipedia]&lt;br /&gt;
* [[Cohesion|high cohesion/loose coupling]]&lt;br /&gt;
* OCP – Open/Closed Principle&lt;br /&gt;
* SRP – Single Responsibility Principle&lt;br /&gt;
* Don’t make me think/write your code for everybody&lt;br /&gt;
* IoC – Inversion of Control / Dependency Inversion&lt;br /&gt;
* Form follows Function – Pragmatismus vor Ästhetik&lt;br /&gt;
* ISP – Interface Segregation Principle&lt;br /&gt;
* Stick to the Paradigm&lt;br /&gt;
* Tell don&#039;t ask ([https://martinfowler.com/bliki/TellDontAsk.html Martin Fowler])&lt;br /&gt;
&lt;br /&gt;
Was ist mit SOLID?&lt;br /&gt;
&lt;br /&gt;
Robert C. Martin hat fünf Prinzipien (SRP, open/closed, Liskov, ISP, DI) zusammengefaßt und damit ein tolles backronym zu bilden. Ob man dieser Kollektion einen besonderen Wert zuordnen möchte oder nicht sei mal dahingestellt. Das Liskov-Prinzip wurde hier - wegen seiner Konkretheit - unten den best practices eingeordnet. Die Frage wie man IoC und DI beschreibt und gegen einander abgrenzt ist noch zu diskutieren.&lt;br /&gt;
&lt;br /&gt;
= Best Practice =&lt;br /&gt;
Best Practices – auch Heuristiken genannt – sind Techniken oder Vorgehensweisen, die sich in der Praxis in irgendeiner Form&lt;br /&gt;
und iregndeiner Situation bewährt haben. Meist lassen sie Gestaltungsspielraum, wenn es um die konkrete Anwendung geht – die&lt;br /&gt;
Abgrenzung zwischen einer konkreten Regel und einer allgemeinen Heuristik ist fließend. Und man sollte immer bedenken,&lt;br /&gt;
daß best practices in der Regel aus konkreten Situationen heraus entstanden sind und nicht auf jede beliebige Situation übertragbar sind -- dazu giebt es unten ein Antipattern.&lt;br /&gt;
&lt;br /&gt;
* Clean Code (hier nur einige Heuristiken, die sich bei &#039;&#039;meiner&#039;&#039; Arbeit bewährt haben)&lt;br /&gt;
** Jeder Bezeichner soll exakt beschreiben, was das Bezeichnete tut oder enthält&lt;br /&gt;
** Eine Methode soll eine Wert liefern oder etwas tun, aber nicht beides&lt;br /&gt;
** Methoden (auch Konstruktoren) soll nicht mehr als drei Parameter haben&lt;br /&gt;
** Death to Magic numbers&lt;br /&gt;
** saubere Bezeichner sind besser als gute Kommentare sind besser als keine Kommentare sind besser als falsche Kommentare&lt;br /&gt;
** Eine Methode – eine Aufgabe&lt;br /&gt;
** lokale Variablen dort deklarieren, wo sie gebraucht werden&lt;br /&gt;
* Kent Beck&#039;s Design Rules (according to [http://martinfowler.com/bliki/BeckDesignRules.html Martin Fowler])&lt;br /&gt;
** Passes the Tests&lt;br /&gt;
** Reveals intention&lt;br /&gt;
** No Duplication&lt;br /&gt;
** Fewest Elements&lt;br /&gt;
* DI – Dependency Injection (als Implementierung von IoC)&lt;br /&gt;
* LSP - Liskov substitution principle&lt;br /&gt;
* Demeter-Prinzip&lt;br /&gt;
* Trennung von Abstraktions-Ebenen&lt;br /&gt;
* Trennung von Interface und Implementierung siehe dazu auch: Bridge-Pattern&lt;br /&gt;
* Interfaces sollen so schmal wie möglich sein und nur das enthalten was tatsächlich erforderlich ist.&lt;br /&gt;
* verwende Architektur-Pattern&lt;br /&gt;
* verwende das Schichten-Modell&lt;br /&gt;
* Integration Operation Segregation Principle (nach unten scrollen: [http://clean-code-developer.de/die-grade/roter-grad/#Integration_Operation_Segregation_Principle_IOSP IOSP])&lt;br /&gt;
* verwende Design-Pattern (hier einige GoF-Pattern, die ich besonders häufig verwende)&lt;br /&gt;
** Factory Method&lt;br /&gt;
** Adapter&lt;br /&gt;
** (simplified) Builder&lt;br /&gt;
** Singleton&lt;br /&gt;
** Proxy&lt;br /&gt;
** Facade&lt;br /&gt;
** Decorator&lt;br /&gt;
* Delegation statt Vererbung (Delegation wird im GoF-Buch nicht als Pattern sondern als Konzept beschrieben)&lt;br /&gt;
* Ein Konzept – ein Begriff&lt;br /&gt;
::Bsp: die eMail-Adresse sollte im Code nicht durcheinander als &amp;quot;eMail_Adresse&amp;quot;, &amp;quot;mail-Adresse&amp;quot;, &amp;quot;mail&amp;quot;, &amp;quot;eMail&amp;quot; oder sonstwie bezeichnet werden, sondern immer gleich&lt;br /&gt;
* vermeide Antipattern&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Interface_bloat Interface bloat] -- Interfaces verlangen mehr als erforderlich&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Inner-platform_effect Inner-platform effect] – Das System erlaubt soviel Customization, daß eine schlechte Plattform daraus geworden ist.&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Constant_interface Constant Interface] -- Interfaces dienen nur der Definition von Konstanten&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Sequential_coupling Sequential coupling] -– Die Klasse verlangt den Aufruf ihrer Methoden in einer bestimmten Reihenfolge&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Cargo_cult_programming Cargo cult programming] -– Pattern und Methoden verwenden ohne sie zu verstehen&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Golden_hammer Golden hammer] / [https://en.wikipedia.org/wiki/No_Silver_Bullet Silver bullet] -– Alle Probleme mit der gleichen (Lieblings-)Methode lösen&lt;br /&gt;
** Base Bean – Vererbung soll is-a-Beziehungen abbilden, nicht has-a&lt;br /&gt;
** Stellvertreter-Typen – Statt einen Datentyp zu definieren, existierende Klassen (besonders String) mißbrauchen&lt;br /&gt;
** [[Petting Zoo]] - keeping code that is not worth it&lt;br /&gt;
* vermeide [[Code Smell]]s&lt;br /&gt;
* Refactoring&lt;br /&gt;
* Verwende eine durchgehende Nomenklatur&lt;br /&gt;
* Stick to the Coding Guidelines&lt;br /&gt;
* Das gleiche Problem sollte immer auf gleiche Art und Weise gelöst werden&lt;br /&gt;
* Verwende für Kommentare und Bezeichner nur natürliche Sprachen die Du auch beherrschst&lt;br /&gt;
:actualValue für den aktuellen Wert (richtig ist current)&lt;br /&gt;
* bound als Übersetzung für &amp;quot;verknüpft&amp;quot; (richtig ist linked)&lt;br /&gt;
* Don&#039;t state the obvious:&lt;br /&gt;
: Logger logger = LoggerFactory.obtainLogger();&lt;br /&gt;
: String stringToBeLogged = &amp;quot;log: logging start of action Foo&amp;quot;;&lt;br /&gt;
: logger.log(stringToBeLogged);&lt;br /&gt;
* toString() ist kein Serialisierungs-Tool&lt;br /&gt;
* zu viel von etwas ist selten gut:&lt;br /&gt;
: &amp;lt;q&amp;gt;If you know what you&#039;re doing, three layers is enough; if you don&#039;t, even seventeen levels won&#039;t help.&amp;lt;/q&amp;gt;&lt;br /&gt;
:([https://en.wikipedia.org/wiki/Michael_A._Padlipsky Michael Padlipsky])&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
Entgegen anderslautender Meinungen erhöht der Einsatz von Tools nicht automatisch die Qualität. Das Berechnen von Werten anhand von Metriken beispielsweise trägt zunächst gar nichts zur Qualität bei, erst die Auswertung und das Durchführen von Maßnahmen zur Änderung der Werte kann als qualitätsstiftende Maßnahme gelten. Nichtsdestotrotz unterstützt die Verwendung von Hilfsmitteln den Entwickler dabei den Weg zum Code hoher Qualität zu beschreiten.&lt;br /&gt;
&lt;br /&gt;
* automatisch durchgeführte Unit-Tests&lt;br /&gt;
:Unit-Tests als &amp;quot;Tool&amp;quot; zu beschreiben mag seltsam klingen. Tatsächlich sind Unit-Tests aber nicht Teil des produktiven Codes und daher kann man mit Fug und Recht von einem Tool sprechen.&lt;br /&gt;
* Metriken&lt;br /&gt;
* Tools zur Code-Analyse (sonar, java-Compiler-Warnings)&lt;br /&gt;
* Tools zur Messung der Test-Abdeckung (EclEmma)&lt;br /&gt;
* Automatische Code-Formatierung (Eclipse Code Formatter)&lt;br /&gt;
* Coding-Guidelines&lt;br /&gt;
* [http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html Sun Code Conventions]&lt;br /&gt;
:Sie werden seit 1999 nicht mehr gepflegt. Einige Regeln sind überholt, andere zweifelhaft (z.B. 6.2: Variablen-Deklarationen nur am Beginn eines Code-Blocks plazieren), Sie bilden aber die Grundlage für das Code-Layout und man sollte sie kennen und berücksichtigen.&amp;lt;br&amp;gt;&lt;br /&gt;
:(Fun fact: Der Autor hat anscheinend von C abgeschrieben – es sind tatsächlich ein paar Fehler im Dokument)&lt;br /&gt;
* Refactoring-Tools (IDEs wie Eclipse bringen eine Menge davon mit&lt;br /&gt;
&lt;br /&gt;
= Arbeitstechniken =&lt;br /&gt;
Die klassische Technik des Entwicklers ist das Zurückziehen hinter die Tastatur. Der Entwickler kriecht erst hervor, wenn das Werk vollendet ist. Das beschreibt einen Teil der Tätigkeit, reicht aber schon seit einem halben Jahrhundert nicht mehr aus. Und auch die Handgriffe, mit denen der Entwickler im stillen Kämmerlein den Wandel von Buchstaben in Code vollzieht wandeln sich im Laufe der Zeit. Man muß nicht jede Technik übernehmen, aber man sollte sich damit befassen und zumindest genau wissen, warum man sie nicht einsetzt.&lt;br /&gt;
&lt;br /&gt;
* [[Boy Scout Principle]]&lt;br /&gt;
* Code – fremden und eigenen – lesen und reflektieren&lt;br /&gt;
* zuhören&lt;br /&gt;
* Diskussion über Code&lt;br /&gt;
* Code-Reviews&lt;br /&gt;
* XP – extreme Programming&lt;br /&gt;
** TDD – Test Driven Development&lt;br /&gt;
** Test First Ansatz&lt;br /&gt;
** Pair Programming&lt;br /&gt;
** Root Cause Analysis&lt;br /&gt;
** Incremental Design&lt;br /&gt;
* Embrace the CATSAN method&lt;br /&gt;
* Programming by Difference (→ Michael Feathers)&lt;br /&gt;
* Rubber Duck Debugging&lt;br /&gt;
* Technologische Schulden minimieren&lt;br /&gt;
&lt;br /&gt;
= Literatur =&lt;br /&gt;
* Edsger Dijkstra [https://www.cs.utexas.edu/users/EWD/transcriptions/EWD04xx/EWD447.html On the role of scientific thought]&lt;br /&gt;
* Refactoring: Improving the Design of Existing Code (Martin Fowler/Kent Beck)&lt;br /&gt;
* Working Effectively with Legacy Code (Michael C. Feathers)&lt;br /&gt;
* Clean Code (Robert C. Martin)&lt;br /&gt;
* Design Patterns: Elements of Reusable Object-Oriented Software (Gamma/Helm/Vlissides/Johnson)&lt;br /&gt;
* The Mythical Man Month (Fred Brooks)&lt;br /&gt;
* The Systems Bible – 3rd edition of &amp;quot;Systemantics&amp;quot; (John Gall) [https://en.wikipedia.org/wiki/Systemantics Überblick in der Wikipedia]&lt;br /&gt;
* [https://www.google.de/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=2&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwjKitDwvJ3NAhXFKMAKHQ0hBWEQFggpMAE&amp;amp;url=http%3A%2F%2Fworrydream.com%2Frefs%2FBrooks-NoSilverBullet.pdf&amp;amp;usg=AFQjCNGkOYvU4WQgqaHGAqGgicO0XTRcw&amp;amp;bvm=bv.124088155,d.bGg No Silver Bullet] (Fred Brooks)&lt;br /&gt;
* [https://www.google.de/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=1&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwiWtayRvZ3NAhUMDMAKHe_JDCYQFggcMAA&amp;amp;url=http%3A%2F%2Fhomepages.cwi.nl%2F~storm%2Fteaching%2Freader%2FDijkstra68.pdf&amp;amp;usg=AFQjCNFIgAgWJ_Aoph79yl9-tFusEGgglQ Goto Considered Harmful] (Edsger Dijkstra)&lt;br /&gt;
* [http://clean-code-developer.de/ clean code developer site]&lt;br /&gt;
* [http://chris.beams.io/posts/git-commit/ Regeln für GIT-commit-Kommentare]&lt;br /&gt;
* [http://www.cs.yale.edu/homes/perlis-alan/quotes.html Epigramme von Alan Perlis]&lt;br /&gt;
* [https://www.heise.de/newsticker/meldung/John-Romero-Von-id-Softwares-Anfaengen-und-World-of-Warcraft-Sucht-3296840.html Programmier-Regeln von John Romero]&lt;br /&gt;
* [https://sourcemaking.com Gute Sammlung von Pattern, Anti-Pattern etc.]&lt;br /&gt;
* [https://xkcd.com/1926 Bad Code in XKCD]&lt;br /&gt;
&lt;br /&gt;
= Zen =&lt;br /&gt;
Keine Richtlinien, keine Anweisungen, einfach Aussagen über die man nachdenken kann. Hier kann man beliebig hitzig diskutieren; wichtig ist nur, daß man darüber – möglichst unvoreingenommen – nachdenkt.&lt;br /&gt;
&lt;br /&gt;
* Wer sich nicht klar ausdrückt, denkt auch nicht klar&lt;br /&gt;
* big bang features lead to big bang&lt;br /&gt;
* Software Engineering ist agnostisch&lt;br /&gt;
* Ein Beispiel beweist nichts, widerlegt aber alles – soviel zu TDD- und Test-Abdeckungs-Fetischismus&lt;br /&gt;
* Ist TDD die zeitgemäße Formulierung für &amp;quot;trial and error&amp;quot;?&lt;br /&gt;
* Wenn Du weißt was Du tust, bist Du gesegnet&lt;br /&gt;
* If it ain&#039;t broken, don&#039;t fix it vs. Refactoring&lt;br /&gt;
* Verwende nur was Du auch verstehst ([https://xkcd.com/1597/ Wie XKCD GIT charakterisiert])&lt;br /&gt;
* Wer etwas ablehnt oder verteidigt sollte genau wissen warum&lt;br /&gt;
* Nichts hält so lange wie ein Provisorium&lt;br /&gt;
* Wer trennt schafft Abhängigkeiten, wer nicht trennt schafft Chaos&lt;br /&gt;
* Nichts ist so einfach, daß man es nicht falsch machen könnte&lt;br /&gt;
* Eine Entscheidung ist richtig, wenn sie rational begründet werden kann&lt;br /&gt;
* Was wert ist daß man es tut, ist wert daß man es richtig tut.&lt;br /&gt;
* Wenn man versucht Probleme auszusitzen, kriechen sie irgendwann hervor und treten einem in den Hintern&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Boy_Scout_Principle&amp;diff=197</id>
		<title>Boy Scout Principle</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Boy_Scout_Principle&amp;diff=197"/>
		<updated>2024-11-28T10:24:18Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
&lt;br /&gt;
= Motivation =&lt;br /&gt;
Zu den Regeln der Pfadfinderbewegung gehört der Satz:&lt;br /&gt;
{{quotation|Always leave the camp ground cleaner than you found it.}}&lt;br /&gt;
oder wie der Vater der Bewegung – Robert Baden Powell – es ausgedrückt hat:&lt;br /&gt;
{{quotation|Try and leave this world a little better than you found it.}}&lt;br /&gt;
In der Realität herrscht die gegenteilige Praxis vor (oder eben die gleiche Praxis mit negativem Vorzeichen):&lt;br /&gt;
Liegt irgendwo Müll herum, dann scheint das die Menschen dazu zu animieren dem herumliegenden Müll weiteren&lt;br /&gt;
Müll hinzuzufügen.&lt;br /&gt;
Dieses Phänomen wurde in den 80er Jahren als &amp;quot;Broken Window Effect&amp;quot; beschrieben.&lt;br /&gt;
Aber was hat das nun mit Software Engineering zu tun?&lt;br /&gt;
Zum Äquivalent des Broken Windows Effect im Software Engineering ist hier recht nett beschrieben&lt;br /&gt;
(da ist wohl ein Link verloren gegangen).&lt;br /&gt;
Um dessen Vermeidung und die Frage was man statt dessen für die Software-Qualität tun kann soll es im Folgenden gehen.&lt;br /&gt;
&lt;br /&gt;
== Über das Problem ==&lt;br /&gt;
Wer lange genug programmiert hat, weiß wie schlimm schlechter Code aussehen kann. Und immer wenn man&lt;br /&gt;
denkt man hat schon alles gesehen tritt man in eine Java-Klasse die alles dagewesene in den Schatten stellt. Der&lt;br /&gt;
erste Reflex ist meistens &amp;quot;weg damit, alles neu machen&amp;quot;. Man bezeichnet dieses Refactoring-Vorgehen auch mit&lt;br /&gt;
dem treffenden Namen &amp;quot;Big Bang&amp;quot;. Die Umsetzung bereitet in der Praxis allerdings eine ganze Reihe von&lt;br /&gt;
Problemen. Das größte ist, daß eine umfassende Refactoring-Maßnahme Aufwände generiert die aus keinem&lt;br /&gt;
Budget zu bekommen sind. Das liegt nicht nur an knausrigen Budget-Verwaltern, das liegt auch in der Natur der&lt;br /&gt;
Entstehung solcher Code-Höllen. Wer sich beim Codieren nicht um die Qualität kümmert schafft technologische&lt;br /&gt;
Schulden, für die keine Deckung existiert und für die in der Regel keine Rücklagen gebildet werden. So kommt Müll&lt;br /&gt;
zu Müll und aus kleinen dreckigen Code-Ecken werden langsam aber sicher riesige Müllhalden.&lt;br /&gt;
Ein anderes Problem verbirgt sich hinter der Metapher vom Abreißen und Neuaufbau des Systems. Diese aus dem&lt;br /&gt;
Hausbau stammende Metapher läßt sich nicht eins zu eins auf die Software-Entwicklung übertragen. Denn das&lt;br /&gt;
neue System wird ja nicht einfach aus &amp;quot;neuem&amp;quot; Material gebaut, sondern soll die Substanz des abgerissenen&lt;br /&gt;
Systems wiederverwerten. Oder auf den Code bezogen: Die Business-Logik, die sich im Müllhaufen verbirgt – und&lt;br /&gt;
das ist ja das eigentliche Kapital der Software, das was das System wertvoll macht – muß erhalten bleiben. Das&lt;br /&gt;
funktioniert – vielleicht – wenn man eine exzellente und erschöpfende Dokumentation des Systems hat die genau&lt;br /&gt;
die im System enthaltene Fachlichkeit dokumentiert, aber zu welchem System hat man eine solche&lt;br /&gt;
Dokumentation?&lt;br /&gt;
&lt;br /&gt;
Der einzige Weg ist dann das akribsche Analysieren des bestehenden Codes und das Übertragen in die neue&lt;br /&gt;
Anwendung. Und da es sich um eine vollständige Neuentwicklung handelt muß jede Zeile im Rahmen der&lt;br /&gt;
Neuentwicklung untersucht werden; dazu gehört veralteter, nicht mehr verwendeter Code ebenso wie Code-&lt;br /&gt;
Gewölle deren Analyse aufgrund der Komplizierteit sehr zeitaufwändig ist. Es gibt keine Möglichkeit, auf&lt;br /&gt;
irgendeinen Teil dieser Analyse zu verzichten, denn mit der Migration muß sämtliche Funktionalität übertragen&lt;br /&gt;
werden. Sei sie nun offensichtlich oder unter hunderten verschachtelter Klassen vergraben.&lt;br /&gt;
Damit ist in vielen Fällen das Migrationsprojekt mangels Budget gestorben. Und weil die Komplettlösung nicht&lt;br /&gt;
umsetzbar ist, passiert meistens gar nichts. Dabei muß noch nicht einmal die gesamte Anwendung betroffen sein,&lt;br /&gt;
Oft geht es nur darum wesentliche Teile einem Refactoring zu unterziehen, was dann – Budget! Budget! – ebenfalls&lt;br /&gt;
nicht geschieht.&lt;br /&gt;
&lt;br /&gt;
= Über die Lösung =&lt;br /&gt;
Wenn also der Big-Bang-Ansatz nicht durchführbar ist, was dann? Die kleine, mühsamere und weniger beglückende&lt;br /&gt;
Lösung ist der Weg der kleine Schritte. Und wenn man vor lauter Chaos nicht weiß wo anfangen, fängt man am&lt;br /&gt;
besten da an wo man gerade steht: Wann immer der Entwickler ein Stück Code bearbeitet oder reviewt – und sei es&lt;br /&gt;
noch so klein – dann habe er dabei immer die Frage im Hinterkopf &lt;br /&gt;
: Was kann ich hier ohne viel Aufwand besser machen?&lt;br /&gt;
Das scheint erstmal für lange Zeit gar nichts zu bringen und es ersetzt auch nicht das kostenintensive&lt;br /&gt;
Refactoring größerer Programmteile – besonders, wenn die Architektur Probleme verursacht – aber es hilft auf&lt;br /&gt;
lange Sicht Aufwände zu senken und kann den Code so vorbereiten, daß große Refactoring-Maßnahmen überhaupt&lt;br /&gt;
erst möglich werden.&lt;br /&gt;
&lt;br /&gt;
= Was kann man konkret tun? =&lt;br /&gt;
Erlaubt ist alles, was die Code-Qualität verbessert, dabei aber die Funktionalität nicht beeinträchtigt und solange&lt;br /&gt;
man die Schnittstellen nicht anfaßt, ist praktisch alles erlaubt.&lt;br /&gt;
* Unit-Tests schreiben&lt;br /&gt;
* Dokumentation schreiben&lt;br /&gt;
* Kommentare korrigieren und ergänzen&lt;br /&gt;
* Methoden- und Klassennamen umbenennen&lt;br /&gt;
* Toten und auskommentierten Code entfernen&lt;br /&gt;
* Literale durch Konstanten und Konstanten durch Enums ersetzen&lt;br /&gt;
* Zweifelhafte Stellen als TODO oder FIXME markieren&lt;br /&gt;
* Ungenutzte Teile als &amp;quot;deprecated&amp;quot; markieren&lt;br /&gt;
* Code-Blöcke in Methoden auslagern&lt;br /&gt;
* Mehrfach verwendete Blöcke in Klassen auslagern&lt;br /&gt;
* if-Bedingungen umformen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Worauf sollte man achten? =&lt;br /&gt;
Entscheidend ist, daß durch das Refactoring nichts kaputt geht. Bevor man also anfängt den Code umzukrempeln&lt;br /&gt;
muß man sich darüber klar werden, welche Auswirkung die Änderung hat. Wenn kein eigenes und ausreichendes&lt;br /&gt;
Budget für die Überarbeitung zur Verfügung steht, gestaltet man die Änderungen so defensiv wie möglich. Am&lt;br /&gt;
besten sichert man die Änderungen immer durch automatische Unit-Tests ab.&lt;br /&gt;
&lt;br /&gt;
Aus diesem Grunde stehen die Unit-Tests in der Aufzählung oben auch ganz oben. Jeder Entwickler sollte immer&lt;br /&gt;
alles durch Unit-Tests abdecken – so die Theorie. Die Erhöhung der Testabdeckung ändert zwar überhaupt nichts&lt;br /&gt;
an der Code-Qualität, ist aber trotzdem sehr wertvoll. Tests sichern den Code gegen Änderungen ab. Bei der&lt;br /&gt;
nächsten Änderung, Erweiterung oder dem nächsten Refactoring merkt man hoffentlich sofort, wenn etwas kaputt&lt;br /&gt;
gegangen ist.&lt;br /&gt;
&lt;br /&gt;
Nicht umsonst antwortet Michael Feathers auf die Frage &amp;quot;Was ist Legacy Code?&amp;quot; ganz lapidar&lt;br /&gt;
{{quotation|To me, &#039;&#039;legacy code&#039;&#039; is simply code without tests}}&lt;br /&gt;
&lt;br /&gt;
= Noch was? =&lt;br /&gt;
Der brave Pfadfinder kümmert sich nicht darum, wer nach ihm kommt. Er sorgt einfach dafür, daß sich der Nächste&lt;br /&gt;
wohler fühlt wenn er sein Zelt aufschlägt. Wenn er aber weiß, daß demnächst eine große Gruppe zum Camping&lt;br /&gt;
anrückt, dann kann er – mit seinen Genossen – schon mal vorarbeiten. Was heißt das für den Softwerker?&lt;br /&gt;
Wenn man weiß, daß irgendwann die großen Refactorings anstehen, daß zum Beispiel das Datenbank-Modell&lt;br /&gt;
überholt wird oder ein anderes Framework verwendet werden soll; wenn man also planvoll auf irgendetwas hinarbeiten&lt;br /&gt;
möchte, dann kann man die Reinigungsarbeiten schon vorneweg in die richtige Richtung lenken. Hierzu konkrete&lt;br /&gt;
Anweisungen vorzugeben ist schwierig, am besten setzt man sich mit dem Team mal hin und überlegt, welches die&lt;br /&gt;
schlimmsten Probleme sind, wie man sie beseitigen möchte und wie man da hinkommen kann.&lt;br /&gt;
&lt;br /&gt;
Dazu ein einfaches Beispiel:&lt;br /&gt;
&lt;br /&gt;
Sind beispielsweise Zugriffe auf eine bestimmtes Modul (eine Datenbank oder ein Service) überall im Code verteilt&lt;br /&gt;
und auf unterschiedliche Weise implementiert, kann man ein Interface definieren, bei der nächsten Gelegenheit&lt;br /&gt;
den ersten Zugriff aus dem Code lösen, damit das Interface mit einer Klasse unterfüttern und verwenden. Kommt&lt;br /&gt;
der nächste Entwickler an anderer Stelle auf einen ähnlichen Zugriff, übernimmt er entweder die Implementierung&lt;br /&gt;
seines Vorgängers oder er implemetiert eine neue Klasse für das Interface und stellt sie neben die erste.&lt;br /&gt;
Irgendwann – wenn zeit ist – nimmt man sich die verschiedenen Implementierungen der Interface vor und konsolidiert die&lt;br /&gt;
Implementierungen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Boy_Scout_Principle&amp;diff=196</id>
		<title>Boy Scout Principle</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Boy_Scout_Principle&amp;diff=196"/>
		<updated>2024-11-28T10:23:38Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
&lt;br /&gt;
= Motivation =&lt;br /&gt;
Zu den Regeln der Pfadfinderbewegung gehört der Satz:&lt;br /&gt;
{quotation|Always leave the camp ground cleaner than you found it.}&lt;br /&gt;
oder wie der Vater der Bewegung – Robert Baden Powell – es ausgedrückt hat:&lt;br /&gt;
{quotation|Try and leave this world a little better than you found it.}&lt;br /&gt;
In der Realität herrscht die gegenteilige Praxis vor (oder eben die gleiche Praxis mit negativem Vorzeichen):&lt;br /&gt;
Liegt irgendwo Müll herum, dann scheint das die Menschen dazu zu animieren dem herumliegenden Müll weiteren&lt;br /&gt;
Müll hinzuzufügen.&lt;br /&gt;
Dieses Phänomen wurde in den 80er Jahren als &amp;quot;Broken Window Effect&amp;quot; beschrieben.&lt;br /&gt;
Aber was hat das nun mit Software Engineering zu tun?&lt;br /&gt;
Zum Äquivalent des Broken Windows Effect im Software Engineering ist hier recht nett beschrieben&lt;br /&gt;
(da ist wohl ein Link verloren gegangen).&lt;br /&gt;
Um dessen Vermeidung und die Frage was man statt dessen für die Software-Qualität tun kann soll es im Folgenden gehen.&lt;br /&gt;
&lt;br /&gt;
== Über das Problem ==&lt;br /&gt;
Wer lange genug programmiert hat, weiß wie schlimm schlechter Code aussehen kann. Und immer wenn man&lt;br /&gt;
denkt man hat schon alles gesehen tritt man in eine Java-Klasse die alles dagewesene in den Schatten stellt. Der&lt;br /&gt;
erste Reflex ist meistens &amp;quot;weg damit, alles neu machen&amp;quot;. Man bezeichnet dieses Refactoring-Vorgehen auch mit&lt;br /&gt;
dem treffenden Namen &amp;quot;Big Bang&amp;quot;. Die Umsetzung bereitet in der Praxis allerdings eine ganze Reihe von&lt;br /&gt;
Problemen. Das größte ist, daß eine umfassende Refactoring-Maßnahme Aufwände generiert die aus keinem&lt;br /&gt;
Budget zu bekommen sind. Das liegt nicht nur an knausrigen Budget-Verwaltern, das liegt auch in der Natur der&lt;br /&gt;
Entstehung solcher Code-Höllen. Wer sich beim Codieren nicht um die Qualität kümmert schafft technologische&lt;br /&gt;
Schulden, für die keine Deckung existiert und für die in der Regel keine Rücklagen gebildet werden. So kommt Müll&lt;br /&gt;
zu Müll und aus kleinen dreckigen Code-Ecken werden langsam aber sicher riesige Müllhalden.&lt;br /&gt;
Ein anderes Problem verbirgt sich hinter der Metapher vom Abreißen und Neuaufbau des Systems. Diese aus dem&lt;br /&gt;
Hausbau stammende Metapher läßt sich nicht eins zu eins auf die Software-Entwicklung übertragen. Denn das&lt;br /&gt;
neue System wird ja nicht einfach aus &amp;quot;neuem&amp;quot; Material gebaut, sondern soll die Substanz des abgerissenen&lt;br /&gt;
Systems wiederverwerten. Oder auf den Code bezogen: Die Business-Logik, die sich im Müllhaufen verbirgt – und&lt;br /&gt;
das ist ja das eigentliche Kapital der Software, das was das System wertvoll macht – muß erhalten bleiben. Das&lt;br /&gt;
funktioniert – vielleicht – wenn man eine exzellente und erschöpfende Dokumentation des Systems hat die genau&lt;br /&gt;
die im System enthaltene Fachlichkeit dokumentiert, aber zu welchem System hat man eine solche&lt;br /&gt;
Dokumentation?&lt;br /&gt;
&lt;br /&gt;
Der einzige Weg ist dann das akribsche Analysieren des bestehenden Codes und das Übertragen in die neue&lt;br /&gt;
Anwendung. Und da es sich um eine vollständige Neuentwicklung handelt muß jede Zeile im Rahmen der&lt;br /&gt;
Neuentwicklung untersucht werden; dazu gehört veralteter, nicht mehr verwendeter Code ebenso wie Code-&lt;br /&gt;
Gewölle deren Analyse aufgrund der Komplizierteit sehr zeitaufwändig ist. Es gibt keine Möglichkeit, auf&lt;br /&gt;
irgendeinen Teil dieser Analyse zu verzichten, denn mit der Migration muß sämtliche Funktionalität übertragen&lt;br /&gt;
werden. Sei sie nun offensichtlich oder unter hunderten verschachtelter Klassen vergraben.&lt;br /&gt;
Damit ist in vielen Fällen das Migrationsprojekt mangels Budget gestorben. Und weil die Komplettlösung nicht&lt;br /&gt;
umsetzbar ist, passiert meistens gar nichts. Dabei muß noch nicht einmal die gesamte Anwendung betroffen sein,&lt;br /&gt;
Oft geht es nur darum wesentliche Teile einem Refactoring zu unterziehen, was dann – Budget! Budget! – ebenfalls&lt;br /&gt;
nicht geschieht.&lt;br /&gt;
&lt;br /&gt;
= Über die Lösung =&lt;br /&gt;
Wenn also der Big-Bang-Ansatz nicht durchführbar ist, was dann? Die kleine, mühsamere und weniger beglückende&lt;br /&gt;
Lösung ist der Weg der kleine Schritte. Und wenn man vor lauter Chaos nicht weiß wo anfangen, fängt man am&lt;br /&gt;
besten da an wo man gerade steht: Wann immer der Entwickler ein Stück Code bearbeitet oder reviewt – und sei es&lt;br /&gt;
noch so klein – dann habe er dabei immer die Frage im Hinterkopf &lt;br /&gt;
: Was kann ich hier ohne viel Aufwand besser machen?&lt;br /&gt;
Das scheint erstmal für lange Zeit gar nichts zu bringen und es ersetzt auch nicht das kostenintensive&lt;br /&gt;
Refactoring größerer Programmteile – besonders, wenn die Architektur Probleme verursacht – aber es hilft auf&lt;br /&gt;
lange Sicht Aufwände zu senken und kann den Code so vorbereiten, daß große Refactoring-Maßnahmen überhaupt&lt;br /&gt;
erst möglich werden.&lt;br /&gt;
&lt;br /&gt;
= Was kann man konkret tun? =&lt;br /&gt;
Erlaubt ist alles, was die Code-Qualität verbessert, dabei aber die Funktionalität nicht beeinträchtigt und solange&lt;br /&gt;
man die Schnittstellen nicht anfaßt, ist praktisch alles erlaubt.&lt;br /&gt;
* Unit-Tests schreiben&lt;br /&gt;
* Dokumentation schreiben&lt;br /&gt;
* Kommentare korrigieren und ergänzen&lt;br /&gt;
* Methoden- und Klassennamen umbenennen&lt;br /&gt;
* Toten und auskommentierten Code entfernen&lt;br /&gt;
* Literale durch Konstanten und Konstanten durch Enums ersetzen&lt;br /&gt;
* Zweifelhafte Stellen als TODO oder FIXME markieren&lt;br /&gt;
* Ungenutzte Teile als &amp;quot;deprecated&amp;quot; markieren&lt;br /&gt;
* Code-Blöcke in Methoden auslagern&lt;br /&gt;
* Mehrfach verwendete Blöcke in Klassen auslagern&lt;br /&gt;
* if-Bedingungen umformen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Worauf sollte man achten? =&lt;br /&gt;
Entscheidend ist, daß durch das Refactoring nichts kaputt geht. Bevor man also anfängt den Code umzukrempeln&lt;br /&gt;
muß man sich darüber klar werden, welche Auswirkung die Änderung hat. Wenn kein eigenes und ausreichendes&lt;br /&gt;
Budget für die Überarbeitung zur Verfügung steht, gestaltet man die Änderungen so defensiv wie möglich. Am&lt;br /&gt;
besten sichert man die Änderungen immer durch automatische Unit-Tests ab.&lt;br /&gt;
&lt;br /&gt;
Aus diesem Grunde stehen die Unit-Tests in der Aufzählung oben auch ganz oben. Jeder Entwickler sollte immer&lt;br /&gt;
alles durch Unit-Tests abdecken – so die Theorie. Die Erhöhung der Testabdeckung ändert zwar überhaupt nichts&lt;br /&gt;
an der Code-Qualität, ist aber trotzdem sehr wertvoll. Tests sichern den Code gegen Änderungen ab. Bei der&lt;br /&gt;
nächsten Änderung, Erweiterung oder dem nächsten Refactoring merkt man hoffentlich sofort, wenn etwas kaputt&lt;br /&gt;
gegangen ist.&lt;br /&gt;
&lt;br /&gt;
Nicht umsonst antwortet Michael Feathers auf die Frage &amp;quot;Was ist Legacy Code?&amp;quot; ganz lapidar&lt;br /&gt;
{quotation|To me, &#039;&#039;legacy code&#039;&#039; is simply code without tests}&lt;br /&gt;
&lt;br /&gt;
= Noch was? =&lt;br /&gt;
Der brave Pfadfinder kümmert sich nicht darum, wer nach ihm kommt. Er sorgt einfach dafür, daß sich der Nächste&lt;br /&gt;
wohler fühlt wenn er sein Zelt aufschlägt. Wenn er aber weiß, daß demnächst eine große Gruppe zum Camping&lt;br /&gt;
anrückt, dann kann er – mit seinen Genossen – schon mal vorarbeiten. Was heißt das für den Softwerker?&lt;br /&gt;
Wenn man weiß, daß irgendwann die großen Refactorings anstehen, daß zum Beispiel das Datenbank-Modell&lt;br /&gt;
überholt wird oder ein anderes Framework verwendet werden soll; wenn man also planvoll auf irgendetwas hinarbeiten&lt;br /&gt;
möchte, dann kann man die Reinigungsarbeiten schon vorneweg in die richtige Richtung lenken. Hierzu konkrete&lt;br /&gt;
Anweisungen vorzugeben ist schwierig, am besten setzt man sich mit dem Team mal hin und überlegt, welches die&lt;br /&gt;
schlimmsten Probleme sind, wie man sie beseitigen möchte und wie man da hinkommen kann.&lt;br /&gt;
&lt;br /&gt;
Dazu ein einfaches Beispiel:&lt;br /&gt;
&lt;br /&gt;
Sind beispielsweise Zugriffe auf eine bestimmtes Modul (eine Datenbank oder ein Service) überall im Code verteilt&lt;br /&gt;
und auf unterschiedliche Weise implementiert, kann man ein Interface definieren, bei der nächsten Gelegenheit&lt;br /&gt;
den ersten Zugriff aus dem Code lösen, damit das Interface mit einer Klasse unterfüttern und verwenden. Kommt&lt;br /&gt;
der nächste Entwickler an anderer Stelle auf einen ähnlichen Zugriff, übernimmt er entweder die Implementierung&lt;br /&gt;
seines Vorgängers oder er implemetiert eine neue Klasse für das Interface und stellt sie neben die erste.&lt;br /&gt;
Irgendwann – wenn zeit ist – nimmt man sich die verschiedenen Implementierungen der Interface vor und konsolidiert die&lt;br /&gt;
Implementierungen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Boy_Scout_Principle&amp;diff=195</id>
		<title>Boy Scout Principle</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Boy_Scout_Principle&amp;diff=195"/>
		<updated>2024-11-28T10:20:58Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Category:Quality  = Motivation = Zu den Regeln der Pfadfinderbewegung gehört der Satz: :&amp;lt;q&amp;gt;Always leave the camp ground cleaner than you found it.&amp;lt;/q&amp;gt; oder wie der Vater der Bewegung – Robert Baden Powell – es ausgedrückt hat: :&amp;lt;q&amp;gt;Try and leave this world a little better than you found it.&amp;lt;/q&amp;gt; In der Realität herrscht die gegenteilige Praxis vor (oder eben die gleiche Praxis mit negativem Vorzeichen): Liegt irgendwo Müll herum, dann scheint da…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
&lt;br /&gt;
= Motivation =&lt;br /&gt;
Zu den Regeln der Pfadfinderbewegung gehört der Satz:&lt;br /&gt;
:&amp;lt;q&amp;gt;Always leave the camp ground cleaner than you found it.&amp;lt;/q&amp;gt;&lt;br /&gt;
oder wie der Vater der Bewegung – Robert Baden Powell – es ausgedrückt hat:&lt;br /&gt;
:&amp;lt;q&amp;gt;Try and leave this world a little better than you found it.&amp;lt;/q&amp;gt;&lt;br /&gt;
In der Realität herrscht die gegenteilige Praxis vor (oder eben die gleiche Praxis mit negativem Vorzeichen):&lt;br /&gt;
Liegt irgendwo Müll herum, dann scheint das die Menschen dazu zu animieren dem herumliegenden Müll weiteren&lt;br /&gt;
Müll hinzuzufügen.&lt;br /&gt;
Dieses Phänomen wurde in den 80er Jahren als &amp;quot;Broken Window Effect&amp;quot; beschrieben.&lt;br /&gt;
Aber was hat das nun mit Software Engineering zu tun?&lt;br /&gt;
Zum Äquivalent des Broken Windows Effect im Software Engineering ist hier recht nett beschrieben&lt;br /&gt;
(da ist wohl ein Link verloren gegangen).&lt;br /&gt;
Um dessen Vermeidung und die Frage was man statt dessen für die Software-Qualität tun kann soll es im Folgenden gehen.&lt;br /&gt;
&lt;br /&gt;
== Über das Problem ==&lt;br /&gt;
Wer lange genug programmiert hat, weiß wie schlimm schlechter Code aussehen kann. Und immer wenn man&lt;br /&gt;
denkt man hat schon alles gesehen tritt man in eine Java-Klasse die alles dagewesene in den Schatten stellt. Der&lt;br /&gt;
erste Reflex ist meistens &amp;quot;weg damit, alles neu machen&amp;quot;. Man bezeichnet dieses Refactoring-Vorgehen auch mit&lt;br /&gt;
dem treffenden Namen &amp;quot;Big Bang&amp;quot;. Die Umsetzung bereitet in der Praxis allerdings eine ganze Reihe von&lt;br /&gt;
Problemen. Das größte ist, daß eine umfassende Refactoring-Maßnahme Aufwände generiert die aus keinem&lt;br /&gt;
Budget zu bekommen sind. Das liegt nicht nur an knausrigen Budget-Verwaltern, das liegt auch in der Natur der&lt;br /&gt;
Entstehung solcher Code-Höllen. Wer sich beim Codieren nicht um die Qualität kümmert schafft technologische&lt;br /&gt;
Schulden, für die keine Deckung existiert und für die in der Regel keine Rücklagen gebildet werden. So kommt Müll&lt;br /&gt;
zu Müll und aus kleinen dreckigen Code-Ecken werden langsam aber sicher riesige Müllhalden.&lt;br /&gt;
Ein anderes Problem verbirgt sich hinter der Metapher vom Abreißen und Neuaufbau des Systems. Diese aus dem&lt;br /&gt;
Hausbau stammende Metapher läßt sich nicht eins zu eins auf die Software-Entwicklung übertragen. Denn das&lt;br /&gt;
neue System wird ja nicht einfach aus &amp;quot;neuem&amp;quot; Material gebaut, sondern soll die Substanz des abgerissenen&lt;br /&gt;
Systems wiederverwerten. Oder auf den Code bezogen: Die Business-Logik, die sich im Müllhaufen verbirgt – und&lt;br /&gt;
das ist ja das eigentliche Kapital der Software, das was das System wertvoll macht – muß erhalten bleiben. Das&lt;br /&gt;
funktioniert – vielleicht – wenn man eine exzellente und erschöpfende Dokumentation des Systems hat die genau&lt;br /&gt;
die im System enthaltene Fachlichkeit dokumentiert, aber zu welchem System hat man eine solche&lt;br /&gt;
Dokumentation?&lt;br /&gt;
&lt;br /&gt;
Der einzige Weg ist dann das akribsche Analysieren des bestehenden Codes und das Übertragen in die neue&lt;br /&gt;
Anwendung. Und da es sich um eine vollständige Neuentwicklung handelt muß jede Zeile im Rahmen der&lt;br /&gt;
Neuentwicklung untersucht werden; dazu gehört veralteter, nicht mehr verwendeter Code ebenso wie Code-&lt;br /&gt;
Gewölle deren Analyse aufgrund der Komplizierteit sehr zeitaufwändig ist. Es gibt keine Möglichkeit, auf&lt;br /&gt;
irgendeinen Teil dieser Analyse zu verzichten, denn mit der Migration muß sämtliche Funktionalität übertragen&lt;br /&gt;
werden. Sei sie nun offensichtlich oder unter hunderten verschachtelter Klassen vergraben.&lt;br /&gt;
Damit ist in vielen Fällen das Migrationsprojekt mangels Budget gestorben. Und weil die Komplettlösung nicht&lt;br /&gt;
umsetzbar ist, passiert meistens gar nichts. Dabei muß noch nicht einmal die gesamte Anwendung betroffen sein,&lt;br /&gt;
Oft geht es nur darum wesentliche Teile einem Refactoring zu unterziehen, was dann – Budget! Budget! – ebenfalls&lt;br /&gt;
nicht geschieht.&lt;br /&gt;
&lt;br /&gt;
= Über die Lösung =&lt;br /&gt;
Wenn also der Big-Bang-Ansatz nicht durchführbar ist, was dann? Die kleine, mühsamere und weniger beglückende&lt;br /&gt;
Lösung ist der Weg der kleine Schritte. Und wenn man vor lauter Chaos nicht weiß wo anfangen, fängt man am&lt;br /&gt;
besten da an wo man gerade steht: Wann immer der Entwickler ein Stück Code bearbeitet oder reviewt – und sei es&lt;br /&gt;
noch so klein – dann habe er dabei immer die Frage im Hinterkopf &lt;br /&gt;
: Was kann ich hier ohne viel Aufwand besser machen?&lt;br /&gt;
Das scheint erstmal für lange Zeit gar nichts zu bringen und es ersetzt auch nicht das kostenintensive&lt;br /&gt;
Refactoring größerer Programmteile – besonders, wenn die Architektur Probleme verursacht – aber es hilft auf&lt;br /&gt;
lange Sicht Aufwände zu senken und kann den Code so vorbereiten, daß große Refactoring-Maßnahmen überhaupt&lt;br /&gt;
erst möglich werden.&lt;br /&gt;
&lt;br /&gt;
= Was kann man konkret tun? =&lt;br /&gt;
Erlaubt ist alles, was die Code-Qualität verbessert, dabei aber die Funktionalität nicht beeinträchtigt und solange&lt;br /&gt;
man die Schnittstellen nicht anfaßt, ist praktisch alles erlaubt.&lt;br /&gt;
* Unit-Tests schreiben&lt;br /&gt;
* Dokumentation schreiben&lt;br /&gt;
* Kommentare korrigieren und ergänzen&lt;br /&gt;
* Methoden- und Klassennamen umbenennen&lt;br /&gt;
* Toten und auskommentierten Code entfernen&lt;br /&gt;
* Literale durch Konstanten und Konstanten durch Enums ersetzen&lt;br /&gt;
* Zweifelhafte Stellen als TODO oder FIXME markieren&lt;br /&gt;
* Ungenutzte Teile als &amp;quot;deprecated&amp;quot; markieren&lt;br /&gt;
* Code-Blöcke in Methoden auslagern&lt;br /&gt;
* Mehrfach verwendete Blöcke in Klassen auslagern&lt;br /&gt;
* if-Bedingungen umformen&lt;br /&gt;
* ...&lt;br /&gt;
&lt;br /&gt;
= Worauf sollte man achten? =&lt;br /&gt;
Entscheidend ist, daß durch das Refactoring nichts kaputt geht. Bevor man also anfängt den Code umzukrempeln&lt;br /&gt;
muß man sich darüber klar werden, welche Auswirkung die Änderung hat. Wenn kein eigenes und ausreichendes&lt;br /&gt;
Budget für die Überarbeitung zur Verfügung steht, gestaltet man die Änderungen so defensiv wie möglich. Am&lt;br /&gt;
besten sichert man die Änderungen immer durch automatische Unit-Tests ab.&lt;br /&gt;
&lt;br /&gt;
Aus diesem Grunde stehen die Unit-Tests in der Aufzählung oben auch ganz oben. Jeder Entwickler sollte immer&lt;br /&gt;
alles durch Unit-Tests abdecken – so die Theorie. Die Erhöhung der Testabdeckung ändert zwar überhaupt nichts&lt;br /&gt;
an der Code-Qualität, ist aber trotzdem sehr wertvoll. Tests sichern den Code gegen Änderungen ab. Bei der&lt;br /&gt;
nächsten Änderung, Erweiterung oder dem nächsten Refactoring merkt man hoffentlich sofort, wenn etwas kaputt&lt;br /&gt;
gegangen ist.&lt;br /&gt;
&lt;br /&gt;
Nicht umsonst antwortet Michael Feathers auf die Frage &amp;quot;Was ist Legacy Code?&amp;quot; ganz lapidar&lt;br /&gt;
: Legacy code is code without unit tests&lt;br /&gt;
&lt;br /&gt;
= Noch was? =&lt;br /&gt;
Der brave Pfadfinder kümmert sich nicht darum, wer nach ihm kommt. Er sorgt einfach dafür, daß sich der Nächste&lt;br /&gt;
wohler fühlt wenn er sein Zelt aufschlägt. Wenn er aber weiß, daß demnächst eine große Gruppe zum Camping&lt;br /&gt;
anrückt, dann kann er – mit seinen Genossen – schon mal vorarbeiten. Was heißt das für den Softwerker?&lt;br /&gt;
Wenn man weiß, daß irgendwann die großen Refactorings anstehen, daß zum Beispiel das Datenbank-Modell&lt;br /&gt;
überholt wird oder ein anderes Framework verwendet werden soll; wenn man also planvoll auf irgendetwas hinarbeiten&lt;br /&gt;
möchte, dann kann man die Reinigungsarbeiten schon vorneweg in die richtige Richtung lenken. Hierzu konkrete&lt;br /&gt;
Anweisungen vorzugeben ist schwierig, am besten setzt man sich mit dem Team mal hin und überlegt, welches die&lt;br /&gt;
schlimmsten Probleme sind, wie man sie beseitigen möchte und wie man da hinkommen kann.&lt;br /&gt;
&lt;br /&gt;
Dazu ein einfaches Beispiel:&lt;br /&gt;
&lt;br /&gt;
Sind beispielsweise Zugriffe auf eine bestimmtes Modul (eine Datenbank oder ein Service) überall im Code verteilt&lt;br /&gt;
und auf unterschiedliche Weise implementiert, kann man ein Interface definieren, bei der nächsten Gelegenheit&lt;br /&gt;
den ersten Zugriff aus dem Code lösen, damit das Interface mit einer Klasse unterfüttern und verwenden. Kommt&lt;br /&gt;
der nächste Entwickler an anderer Stelle auf einen ähnlichen Zugriff, übernimmt er entweder die Implementierung&lt;br /&gt;
seines Vorgängers oder er implemetiert eine neue Klasse für das Interface und stellt sie neben die erste.&lt;br /&gt;
Irgendwann – wenn zeit ist – nimmt man sich die verschiedenen Implementierungen der Interface vor und konsolidiert die&lt;br /&gt;
Implementierungen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=MediaWiki:Sidebar&amp;diff=194</id>
		<title>MediaWiki:Sidebar</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=MediaWiki:Sidebar&amp;diff=194"/>
		<updated>2024-11-28T10:07:31Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;* navigation&lt;br /&gt;
** mainpage|mainpage-description&lt;br /&gt;
** recentchanges-url|recentchanges&lt;br /&gt;
** helppage|help-mediawiki&lt;br /&gt;
* Kategorien&lt;br /&gt;
** Category:Java|Java&lt;br /&gt;
** Category:Quality|Qualität&lt;br /&gt;
** Category:Ausbildung|Ausbildung&lt;br /&gt;
&lt;br /&gt;
* SEARCH&lt;br /&gt;
* LANGUAGES&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Code_Smell&amp;diff=193</id>
		<title>Code Smell</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Code_Smell&amp;diff=193"/>
		<updated>2024-11-28T10:04:36Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
Die erste Erwähnung des Begriffs &amp;quot;code smell&amp;quot; findet sich in Martin Fowlers Buch &amp;quot;Refactoring&amp;quot;. Er verwendet ihn&lt;br /&gt;
dort als es darum geht die Code-Stellen zu identifizieren an denen Refactoring erforderlich ist. Fowler bleibt dabei&lt;br /&gt;
ausgesprochen vage, aber die Andeutung auf verunreinigte Baby-Windeln erzeugt den starken Eindruck, daß es sich&lt;br /&gt;
hier um ausgesprochen unangenehme Gerüche handeln muß...&lt;br /&gt;
&lt;br /&gt;
Ein Code Smell ist eine Stelle im Code mit bestimmten Eigenschaften, an denen sie zu erkennen ist. Diese&lt;br /&gt;
Eigenschaften bilden den bisweilen charakteristischen Geruch. Eine Methode mit einer langen Parameterliste ist ein Beispiel&lt;br /&gt;
dafür, mit jedem weiteren Parameter wird der Geruch intensiver.&lt;br /&gt;
&lt;br /&gt;
Viele Code Smells haben eine Ursache. Eine lange Parameterliste zum Beispiel kann das Ergebnis sukzessiver&lt;br /&gt;
Verallgemeinerung sein. Die ursprüngliche Methode hatte vielleicht nur zwei Parameter, aber mit jeder Anpassung&lt;br /&gt;
an die geänderten Anforderungen kam ein neuer Parameter hinzu. Nicht jeder Smell hat eine klare Ursache, für&lt;br /&gt;
manche Smells gibt es mehrere mögliche Ursachen. In aller Regel ist es sinnvoll die Ursache zu ergründen, denn&lt;br /&gt;
unterschiedliche Ursachen können unterschiedliche Refactoring-Maßnahmen nahelegen. Hier endet ein Zipfel der&lt;br /&gt;
Analogie, denn Baby-Kacke beseitigt man normalerweise immer auf die gleiche Weise...&lt;br /&gt;
&lt;br /&gt;
Nicht alle Gerüche sind per se unangenehm. Fowler beschreibt zum Beispiel den Geruch von Kommentaren als&lt;br /&gt;
angenehm – nachgerade verführerisch angenehm, denn fehlerhafte Kommentaren können Probleme – und die&lt;br /&gt;
damit verbundenen Gerüche – verdecken.&lt;br /&gt;
&lt;br /&gt;
Ich strecke die Analogie gerne in eine andere Richtung: Verschiedene Entwickler reagieren auf verschiedene&lt;br /&gt;
Gerüche unterschiedlich. Dem einen wird bei einer 10-Zeilen-Methode übel, der andere fühlt sich vom&lt;br /&gt;
100-Zeilen-Geruch noch nicht belästigt. Und wieder scheinen den Duft von Methoden um so angenehmer zu emfinden,&lt;br /&gt;
je länger sie wird.&lt;br /&gt;
&lt;br /&gt;
Es ist Aufgabe des Teams eine Umgebung zu schaffen die einen vernünftigen Kompromiß bringt.&lt;br /&gt;
Es wäre falsch, ganz auf die Beseitigung von Code-Smells zu verzichten. Ebenso falsch aber wäre es,&lt;br /&gt;
die Beseitigung bestimmter Smells zu erzwingen –- um bei der Analogie zu bleiben: der Geruch von&lt;br /&gt;
Desinfektionsmittel kann durchaus unangenehm sein.&lt;br /&gt;
&lt;br /&gt;
Wie im wirklichen Leben, können Gerüche auf tödliche Gefahren hinweisen -– der Geruch von Bittermandel ist nicht&lt;br /&gt;
unbedingt unangenehm, eine Zyanid-Vergiftung ist es aber auf jeden Fall... Doch nicht hinter jedem Geruch steckt ein&lt;br /&gt;
verrotteter Fäulnisherd, der die Anwendung in eine einsturzgefährdete Todesfalle verwandelt. Manchmal handelt&lt;br /&gt;
es sich lediglich um einen ungewohnten Eigengeruch, an dessen Aroma man sich erst gewöhnen muß.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun –- dem Duft der Analogie -– folgend um das eigentliche Thema herummäandert sind, bringen wir&lt;br /&gt;
die Sache mal auf den Punkt:&lt;br /&gt;
* Ein Code Smell ist der Hinweis auf eine Code-Stelle, die Beachtung verdient&lt;br /&gt;
* Ein Code-Smell ist nicht per se schlecht&lt;br /&gt;
* Ein Code Smell kann der Hinweis auf eine Schwachstelle sein, die zu ernsthaften Problemen führen kann&lt;br /&gt;
* Code-Smells müssen in der Regel mit Rücksicht auf die Ursache behandelt werden&lt;br /&gt;
Nachdem wir nun eine Vorsetllung davon haben was einen Code Smell ausmacht, können wir uns nun den&lt;br /&gt;
konkreten Beispielen befassen...&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Beliebte&amp;quot; Code Smells...&lt;br /&gt;
* Shot Gun Surgery (Martin Fowler)&lt;br /&gt;
* Speculative Generalization (Martin Fowler)&lt;br /&gt;
* Zu viele Zeilen in der Methoden oder Klasse&lt;br /&gt;
* Zu viele (mehr als drei) formale Parameter in der Methoden-Signatur&lt;br /&gt;
* Ungenutzte Felder, Parameter, Methoden, Code etc.&lt;br /&gt;
* Explizites type casting&lt;br /&gt;
* Unangemessener Gebrauch von null&lt;br /&gt;
* Auto-unboxing wegen unnötiger Verwendung von Wrapper-Klassen um int, long, etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachgedanke&lt;br /&gt;
:Worte wie &amp;quot;eigentlich&amp;quot; und &amp;quot;wirklich&amp;quot; sind code smells der natürlichen Sprache.&lt;br /&gt;
:Sie riechen nach &amp;quot;Ideologie&amp;quot;.&lt;br /&gt;
:Sie riechen nach &amp;quot;mir sind die rational-logischen Argumente ausgegangen&amp;quot;&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Don%27t_repeat_yourself&amp;diff=192</id>
		<title>Don&#039;t repeat yourself</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Don%27t_repeat_yourself&amp;diff=192"/>
		<updated>2024-11-28T10:04:06Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Category:Quality  = Motivation = Software-Entwicklung wird gerne mit der Herstellung von Gegenständen verglichen, also mit der produzierenden Industrie. Das schlägt sich auch in Begriffen wieder wie Software-Architektur oder dem Factory-Pattern. Der Vergleich geschieht nicht ohne Grund und solange man sich nicht scheut sich von der Analogie zu lösen wenn sie nicht mehr passt kann man viele nützliche Erkenntnisse daraus ziehen. Ein Punkt an dem die…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
&lt;br /&gt;
= Motivation =&lt;br /&gt;
Software-Entwicklung wird gerne mit der Herstellung von Gegenständen verglichen, also mit der produzierenden&lt;br /&gt;
Industrie. Das schlägt sich auch in Begriffen wieder wie Software-Architektur oder dem Factory-Pattern. Der&lt;br /&gt;
Vergleich geschieht nicht ohne Grund und solange man sich nicht scheut sich von der Analogie zu lösen wenn sie&lt;br /&gt;
nicht mehr passt kann man viele nützliche Erkenntnisse daraus ziehen. Ein Punkt an dem die Analogie versagt&lt;br /&gt;
scheint mir besonders wichtig zu sein:&lt;br /&gt;
&lt;br /&gt;
Ein kurzer Blick in die Historie:&lt;br /&gt;
&lt;br /&gt;
Die Industrialisierung hat einen großen Schritt nach vorne getan, als man begann Bauteile zu standardisieren. Die&lt;br /&gt;
Errichtung eines Doms erstreckte sich früher über Jahrzehnte. Ein Grund – wenn auch nicht der einzige – war, daß&lt;br /&gt;
das Gesamtgebilde aus vielen unterschiedlichen Steinen bestand von denen jeder für sich entworfen und&lt;br /&gt;
angefertigt werden mußte. Für dem Chrystal Palace, der anläßlich der Londoner Weltausstellung 1854 errichtet&lt;br /&gt;
wurde, ging man einen anderen Weg: Das – gleichfalls imposante – Bauwerk wurde aus verhältnismäßig wenigen&lt;br /&gt;
unterschiedlichen Baukasten-Teilen zusammengesetzt. Von jedem Teil wurden zwar große Mengen hergestellt,&lt;br /&gt;
aber es gab eben nur eine kleine Anzahl unterschiedlicher Teile.&lt;br /&gt;
&lt;br /&gt;
In der herstellenden Industrie versucht man nach Möglichkeit, immer wieder die gleichen Teile zu verwenden, die&lt;br /&gt;
man in großen Mengen produzieren kann. In der Software-Entwicklung marschiert man genau in die&lt;br /&gt;
entgegengesetzte Richtung. Ein physisches Bauteile (wie ein Niet, Träger oder Zahnrad) wird hergestellt, angepaßt&lt;br /&gt;
und eingebaut. Dann bleibt es dort – unverändert – bis es vielleicht irgendwann ersetzt werden muß. Ein Code-&lt;br /&gt;
Fragment – als Beispiel eines nicht physischen, gedanklichen Bauteils – wird irgendwoher kopiert, abgepaßt und an&lt;br /&gt;
beliebiger Stelle eingesetzt. Wenn es denn irgendwann nicht mehr paßt, wird es geändert, jederzeit. Das Code-&lt;br /&gt;
Fragment gleicht also einer Niete, die morgen ein Träger und übermorgen ein Zahnrad sein kann. Ein kopiertes&lt;br /&gt;
Code-Fragment führt vom Augenblick seiner Entstehung ein Eigenleben und ist vollkommen unabhängig von seiner&lt;br /&gt;
Vorlage.&lt;br /&gt;
&lt;br /&gt;
Mit jeder Code-Zeile erhöht sich die Komplexität der Anwendung. Denn jedes Code-Fragment hat seine eigene&lt;br /&gt;
Entwicklung, kann unabhängig vom Rest verändert werden und muß immer einzeln angepaßt werden.Denn jedes&lt;br /&gt;
Code-Fragment hat seine eigene Entwicklung, kann unabhängig vom Rest verändert werden und muß immer&lt;br /&gt;
einzeln angepaßt werden. Die Regel lautet daher:&lt;br /&gt;
&lt;br /&gt;
Für jedes Konzept soll es genau eine Implementierung geben.&lt;br /&gt;
&lt;br /&gt;
= Was heißt &amp;quot;wiederholen&amp;quot;? =&lt;br /&gt;
Das klingt jetzt erstmal so, als wäre Kopieren die einzige Möglichkeit der Wiederholung. Das stimmt natürlich nicht,&lt;br /&gt;
auch wenn es vermutlich die am häufigsten vorkommende Form ist (vielleicht weil &#039;C&#039; und &#039;V&#039; auf der Tastatur so&lt;br /&gt;
nahe bei einander liegen). Die andere Variante der Wiederholung ist das &amp;quot;nochmal schreiben&amp;quot;. Ein Beispiel:&lt;br /&gt;
Irgendwo in der Anwendung wird ein Algorithmus ausgeführt, eine Suche in einem Graphen, eine Sortierung, das&lt;br /&gt;
Vergleichen zweier Listen, oder auch nur der direkte Zugriff auf eine Datenbank durch öffnen einer Verbindung,&lt;br /&gt;
Zusammenbau eines SQL-Statements und auswerten der Antwort. Vergessen wir für einen Augenblick, daß es für&lt;br /&gt;
die meisten dieser Tätigkeiten coole Bibliotheken oder Frameworks gibt und nehmen an daß keine zur Verfügung&lt;br /&gt;
stünden, daß wir darauf angewiesen sind, unseren Algorithmus komplett selbst zu schreiben. Erstaunlich viele&lt;br /&gt;
Entwickler haben solche Algorithmen im Kopf und schreiben sie jedesmal neu, wann sie sie brauchen – so wie man&lt;br /&gt;
auch eine for-Schleife oder eine if-Anweisung heruntertippt ohne groß darüber nachzudenken. Das Resultat ist eine&lt;br /&gt;
wachsende Zahl von Boilder-Plate-Fragmenten, die – mit leichter Variation – immer wieder das Gleiche tun.&lt;br /&gt;
&lt;br /&gt;
= Wie hält man die Regel ein? =&lt;br /&gt;
Ein Verbot läßt sich nur auf eine Art einhalten: Indem man unterläßt. Die Alternative zum Kopieren lautet daher:&lt;br /&gt;
Statt das Fragment zu kopieren, lagert man es in eine Methode aus. Statt das Fragment einzufügen ruft man die&lt;br /&gt;
Methode auf. Das funktioniert allerdings nur solange, bis das Fragment eine Anpassung erfordert. Im einfachsten&lt;br /&gt;
Falle kann man das mit Methoden-Parametern durchführen, stößt damit aber – vor allem wenn das Fragment an&lt;br /&gt;
weiteren Stellen verwendet werden soll – schnell an Grenzen (Für Clean Code etwa sind drei Parameter bereits eine&lt;br /&gt;
Zumutung). Dann kommen Klassen, Factories und das ganze übrige Arsenal zum Einsatz. Welche Mittel man wählt&lt;br /&gt;
und wie weit man gehen sollte um Duplikate zu vermeiden läßt sich nicht pauschal beantworten. Erfahrung und ein&lt;br /&gt;
gesundes Urteilsvermögen leisten beim Design wie immer gute Dienste. Die Fragen die sich der Entwickler&lt;br /&gt;
zwischen Ctrl-C und Ctrl-V daher immer stellen sollte ist:&lt;br /&gt;
&lt;br /&gt;
Wo kann ich das noch verwenden?&lt;br /&gt;
&lt;br /&gt;
Und wie kann ich das verallgemeinern?&lt;br /&gt;
&lt;br /&gt;
Da Wiederholung auch dann entsteht, wenn man Fragmente wiederholt implementiert, sollte man sich die Fragen&lt;br /&gt;
immer dann stellen, wenn man ein Teilproblem implementieren möchte das so klein ist, daß es nicht von&lt;br /&gt;
vornherein als eigenes Module konzipiert wurde.&lt;br /&gt;
&lt;br /&gt;
Bliebe noch die Frage, wieviele Code-Zeilen man denn überhaupt noch kopieren darf. Man orientiert sich bei der&lt;br /&gt;
Verallgemeinerung am Zweck und nicht an der Menge. Eine Serie von Zuweisungen für eine Objekt-Initialisierung&lt;br /&gt;
läßt sich oft gar nicht verallgemeinern, hingegen kann eine Berechnung die nur eine einzelne Zeile durchaus&lt;br /&gt;
Wiederverwendungswert haben (man denke da zum Beispiel an die Berechnung der Mehrwertsteuer). Man&lt;br /&gt;
orientiert sich da auch an den anderen Regeln: „Separation of Concerns“, „One function, one purpose“, „separation&lt;br /&gt;
of abstractations“ etc. Dann sollen die Klassen und Methoden ganz von alleine und im richtigen Format entstehen.&lt;br /&gt;
&lt;br /&gt;
= Spezialfall „Distributed Repetition“ =&lt;br /&gt;
In großen Projekten mit vielen Entwicklern verteilt man die Aufgaben gerne so, daß sich die Entwickler möglichst&lt;br /&gt;
nicht in die Quere kommen. Da es für viele Algorithmen eine bevorzugte Standard-Implementierung gibt, geschieht&lt;br /&gt;
es leicht, daß mehrere Entwickler – mehr oder minder – identischen Code produzieren. Man mag einwenden, daß&lt;br /&gt;
hier keine Wiederholung im Wortessinne vorliegt, doch der Effekt ist der gleiche: ein Code-Fragmnet existiert&lt;br /&gt;
mehrfach und jede Emanation startet sofort ihre individuelle Entwicklung.&lt;br /&gt;
== Was kann man dagegen tun? ==&lt;br /&gt;
Grundsätzlich gilt auch hier die oben genannten Fragen, allerdings kommt noch das Problem dazu, daß Entwickler&lt;br /&gt;
A in der Regel nicht weiß, was Entwickler B so alles implementiert. Daher kann er auch nicht wissen ob für sein&lt;br /&gt;
Teilproblem vielleicht schon irgendwo eine Lösung existiert. Dieses Problem kann man nur organisatorisch lösen&lt;br /&gt;
oder zumindest abmildern. Die Kernfrage lautet dabei „Wo finde ich...?“ bzw. &amp;quot;Wohin packe ich?&amp;quot;&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Struktur definieren&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Das Team legt fest, wo in der Code-Basis Lösungen abgelegt werden für Teilprobleme die von allgemeinem&lt;br /&gt;
Interesse sind. Also zum Beispiel für Konvertierungs-Funktionen, Graphen-Suche, Sortierung etc. Dazu gehören&lt;br /&gt;
auch anwendungsspezifische Probleme die allgemein gelöst werden sollten (z.B. Ausgabe von Meldungen an den&lt;br /&gt;
Benutzer, Formatierung von Log-Ausgaben, fachspezifische Berechnungen), für die es aber keine Vorgabe oder&lt;br /&gt;
Lösung aus höherer Ebene gibt. Lösungen aus verwendeten Frameworks (z.B. EAP) werden natürlich bevorzugt.&lt;br /&gt;
Damit haben alle Entwickler ein gemeinsames Source-Forum für allgemeine Lösungen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Dokumentation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Umfangreiche Code-Basen sind unübersichtlich und komplexe Problemlösungen erklären sich nicht von selbst. Es&lt;br /&gt;
ist empfehlenswert – z. B. mit einem Wiki – neben der Kernfunktionalität der Anwendung auch die Utility-Klassen&lt;br /&gt;
und die verwendeten, allgemeinen Algorithmen zu beschreiben und das Customizing zu beschreiben und über die&lt;br /&gt;
Dokumentation die Ablagestruktur zu beschreiben. Das ist allerdings zeitintensiv und lohnt sich eigentlich nur bei&lt;br /&gt;
Anwendungen die über einen langen Zeitraum gewartet und geändert werden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Kommunikation&#039;&#039;&#039;&lt;br /&gt;
&lt;br /&gt;
Entwickler sollten über ihre Arbeit sprechen und von gefundenen Lösungen erzählen. Im Daily geht es meist nur&lt;br /&gt;
darum ob die Aufgaben umgesetzt wurden und ob dabei Probleme auftraten, nicht aber darum wie Aufgaben&lt;br /&gt;
gelöst wurden und was man mit der Lösung noch anderes anfangen kann. Pair Programming hilft schon etwas&lt;br /&gt;
mehr, weil sich die Entwickler gemeinsam mit dem Lösungsweg auseinandersetzen. Allerdings ist die Verbreitung&lt;br /&gt;
dabei gering, weil in der Regel nur zwei Entwickler mit einander sprechen. Optimal sind Entwickler-Runden in&lt;br /&gt;
denen Entwickler von ihren Lösungen erzählen. Dabei geht es nicht in erster Line darum den Code zu reviewen,&lt;br /&gt;
sondern darum daß das Wissen um das Vorhandensein von Lösungen schnell verbreitet wird. Bei dieser&lt;br /&gt;
Gelegenheit kann auch über Ablage-Orte gesprochen werden und selbstverständlich kann auch darüber diskutiert&lt;br /&gt;
werden, welche Lösungen allgemein verwendet werden sollen und welche nicht. Der Fokus sollte aber immer auf&lt;br /&gt;
dem Austausch von Information liegen, nicht auf der Bewertung.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Der_Weg_zum_guten_Code&amp;diff=191</id>
		<title>Der Weg zum guten Code</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Der_Weg_zum_guten_Code&amp;diff=191"/>
		<updated>2024-11-28T10:02:54Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Quality]]&lt;br /&gt;
Um entscheiden zu können welcher [https://xkcd.com/844/ Weg zum guten Code] führt, muß man festlegen was&lt;br /&gt;
&#039;&#039;guten&#039;&#039; Code von schlechtem unterscheidet. Die Erkenntnis, daß es nicht gleichgültig ist, wie Code beschaffen&lt;br /&gt;
ist wurde ja offensichtlich schon gewonnen -- andernfalls wäre die Suche eine sinnlose.&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Gut&amp;quot; ist der Code, wenn er über die blanke Funktionalität hinaus weitere Eigenschaften erfüllt. Über diese&lt;br /&gt;
nichtfunktionalen Eigenschaften giebt es eine große Literatur, die Worte &amp;quot;Qualiät&amp;quot; und &amp;quot;Architektur&amp;quot; fallen einem in diesem&lt;br /&gt;
Zusammenhang ein. Dabei geht es aber in der Regel um die Software-Qualität, also die Qualität des gesamten Erzeugnisses&lt;br /&gt;
im Zusammenspiel mit der Umgebung in der es betrieben wird.&lt;br /&gt;
&lt;br /&gt;
Diese Seite engt den Blick ganz bewußt auf den &amp;quot;Code&amp;quot; ein. Damit ist der Quelltext gemeint, aus dem das Erzeugnis&lt;br /&gt;
hergestellt wird. Noch genauer geht es dabei um den Programm-Code -- wann kann man diesen als &amp;quot;gut&amp;quot; bezeichnen?&lt;br /&gt;
&lt;br /&gt;
Für den Entwickler -- den Einzigen, der ursächlich an der [https://xkcd.com/1695/ Code-Qualität] interessiert ist --&lt;br /&gt;
muß der Code wartbar, erweiterbar und änderbar sein. Der Grad &#039;&#039;dieser&#039;&#039; Eigenschaften bestimmt die Güte des Codes. Die Optimierung dieser Eigenschaften steht bisweilen im Widerspruch zu anderen Eigenschaften -- insbesondere der Performance.&lt;br /&gt;
Das Abwägen ist Aufgabe des Architekten und liegt außerhalb des Scope dieses Textes; hier geht es ausschließlich darum&lt;br /&gt;
die Code-Qualität zu verbessern.&lt;br /&gt;
&lt;br /&gt;
Es giebt eine unüberschaubare Fülle an Regeln, Tipps, Techniken und Ideologien zum Thema. Nahezu jeder Entwickler,&lt;br /&gt;
den man zum Thema Code-Qualität befragt weiß einen anderen Strauß aus seinen Erfahrungen zu binden.&lt;br /&gt;
&lt;br /&gt;
Aus dem Wunsch heraus, einen Überblick über die verwirrende Vielzahl von Begriffe, Ansichten und Ansätzen zu gewinnen&lt;br /&gt;
ist die untige Sammlung entstanden. Sie ist weder vollständig noch verbindlich, bietet dem interessierten Leser aber&lt;br /&gt;
eine Basis für die weitere Erkundung der Materie. Es wird zwar der Versuch eine Einteilung gemacht um den Überblick zu&lt;br /&gt;
verbessern, aber es wird versucht zu vermeiden eine Wertung vorzunehmen.&lt;br /&gt;
&lt;br /&gt;
= Leitgedanken =&lt;br /&gt;
Ein Leitgedanke zu dem es bislang noch kein vernünftiges Gegenargument giebt ist folgender:&lt;br /&gt;
{{quotation|Die Qualität von Code bemißt sich daran, wie leicht er zu lesen ist}}&lt;br /&gt;
Über die Frage, wie &amp;quot;lesbarer&amp;quot; Code konkret auszusehen hat giebt es allerdings unterschiedliche Auffassungen.&lt;br /&gt;
Daraus kann man auch ableiten, daß bessere Lesbarkeit nicht automatisch zu besserer Änderbarkeit führt.&lt;br /&gt;
Sie führt aber dazu, daß der Code besser zu verstehen ist, daher besser bearbeitet werden kann und damit besser&lt;br /&gt;
zu warten ist. &amp;quot;Lesbarkeit&amp;quot; bleibt ein Kernzeil des Qualitäts-Suchenden und er wird sich die Frage bei jeder Code-Zeile&lt;br /&gt;
zu stellen haben.&lt;br /&gt;
&lt;br /&gt;
{{quotation|Die Grenzen meiner Sprache sind die Grenzen meiner Welt}}&lt;br /&gt;
&lt;br /&gt;
Im Kontext der Code-Qualität bedeutet das: So klar meine Sprache ist, so klar ist mein Code. Computer-Sprachen&lt;br /&gt;
(formale Sprachen überhaupt) lassen keine Mehrdeutigkeiten zu. Wird der gleiche Code bei mehrfacher Ausführung&lt;br /&gt;
unterschiedlich interpretiert, so ist das ein Fehler. Eine klare Ausdrucksweise, als Ausdruck klarer Gedanken ist&lt;br /&gt;
eine Grundvoraussetzung klaren Programm-Codes.&lt;br /&gt;
&lt;br /&gt;
{{quotation|Separation of Concerns}}&lt;br /&gt;
&lt;br /&gt;
ToDo: Erklärung wie die Idee von Dijkstraa als Leitgedanke zu verstehen ist&lt;br /&gt;
&lt;br /&gt;
= Regeln =&lt;br /&gt;
Eine Regel ist eine Richtlinie die vermittelt was man tun – oder lassen – sollte, aber nicht vorgeben wie man das erreicht.&lt;br /&gt;
Regeln weisen die Richtung, bestimmen den Generalkurs; bieten aber wenig Hilfe bei der Überwindung konkreter Hindernisse.&lt;br /&gt;
Regeln sind keine Naturgesetze; es liegt in ihrer Natur, daß man auch von ihnen abweichen kann.&lt;br /&gt;
Es ist wichtig, den Wert einer Regel zu erkennen und daran die Maßnahmen auszuwählen die sie unterstützen.&lt;br /&gt;
&lt;br /&gt;
Die Abgrenzung von Regeln gegen best practices und auch gegen konkrete Maßnahmen ist nicht immer scharf auszumachen.&lt;br /&gt;
Aber bevor man sich in exegetische Schlachten begibt, sollte man sich immer fragen, worum es eigentlich geht.&lt;br /&gt;
Das Ziel ist klarer, handhabbarer Code, das zu erreichen ist jeder Weg erlaubt.&lt;br /&gt;
Das gilt im Übrigen auch für die Gewichtung von Regeln, Ideologie ist immer der falsche Weg -- egal wohin.&lt;br /&gt;
&lt;br /&gt;
* DRY - [[Don&#039;t repeat yourself]]&lt;br /&gt;
* KISS – Keep it simple stupid [http://www.commitstrip.com/en/2018/10/29/only-the-penitent-coder-will-pass/ commitstrip]&lt;br /&gt;
** Ockhams Razor&lt;br /&gt;
** Law of Parsimony&lt;br /&gt;
** Principle of Least Surprise&lt;br /&gt;
* SoC – Separation of Concerns (im Sinne von Aufgaben-Trennung)&lt;br /&gt;
* YAGNI – You Aren&#039;t Gonna Need It [https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it Wikipedia]&lt;br /&gt;
* [[Cohesion|high cohesion/loose coupling]]&lt;br /&gt;
* OCP – Open/Closed Principle&lt;br /&gt;
* SRP – Single Responsibility Principle&lt;br /&gt;
* Don’t make me think/write your code for everybody&lt;br /&gt;
* IoC – Inversion of Control / Dependency Inversion&lt;br /&gt;
* Form follows Function – Pragmatismus vor Ästhetik&lt;br /&gt;
* ISP – Interface Segregation Principle&lt;br /&gt;
* Stick to the Paradigm&lt;br /&gt;
* Tell don&#039;t ask ([https://martinfowler.com/bliki/TellDontAsk.html Martin Fowler])&lt;br /&gt;
&lt;br /&gt;
Was ist mit SOLID?&lt;br /&gt;
&lt;br /&gt;
Robert C. Martin hat fünf Prinzipien (SRP, open/closed, Liskov, ISP, DI) zusammengefaßt und damit ein tolles backronym zu bilden. Ob man dieser Kollektion einen besonderen Wert zuordnen möchte oder nicht sei mal dahingestellt. Das Liskov-Prinzip wurde hier - wegen seiner Konkretheit - unten den best practices eingeordnet. Die Frage wie man IoC und DI beschreibt und gegen einander abgrenzt ist noch zu diskutieren.&lt;br /&gt;
&lt;br /&gt;
= Best Practice =&lt;br /&gt;
Best Practices – auch Heuristiken genannt – sind Techniken oder Vorgehensweisen, die sich in der Praxis in irgendeiner Form&lt;br /&gt;
und iregndeiner Situation bewährt haben. Meist lassen sie Gestaltungsspielraum, wenn es um die konkrete Anwendung geht – die&lt;br /&gt;
Abgrenzung zwischen einer konkreten Regel und einer allgemeinen Heuristik ist fließend. Und man sollte immer bedenken,&lt;br /&gt;
daß best practices in der Regel aus konkreten Situationen heraus entstanden sind und nicht auf jede beliebige Situation übertragbar sind -- dazu giebt es unten ein Antipattern.&lt;br /&gt;
&lt;br /&gt;
* Clean Code (hier nur einige Heuristiken, die sich bei &#039;&#039;meiner&#039;&#039; Arbeit bewährt haben)&lt;br /&gt;
** Jeder Bezeichner soll exakt beschreiben, was das Bezeichnete tut oder enthält&lt;br /&gt;
** Eine Methode soll eine Wert liefern oder etwas tun, aber nicht beides&lt;br /&gt;
** Methoden (auch Konstruktoren) soll nicht mehr als drei Parameter haben&lt;br /&gt;
** Death to Magic numbers&lt;br /&gt;
** saubere Bezeichner sind besser als gute Kommentare sind besser als keine Kommentare sind besser als falsche Kommentare&lt;br /&gt;
** Eine Methode – eine Aufgabe&lt;br /&gt;
** lokale Variablen dort deklarieren, wo sie gebraucht werden&lt;br /&gt;
* Kent Beck&#039;s Design Rules (according to [http://martinfowler.com/bliki/BeckDesignRules.html Martin Fowler])&lt;br /&gt;
** Passes the Tests&lt;br /&gt;
** Reveals intention&lt;br /&gt;
** No Duplication&lt;br /&gt;
** Fewest Elements&lt;br /&gt;
* DI – Dependency Injection (als Implementierung von IoC)&lt;br /&gt;
* LSP - Liskov substitution principle&lt;br /&gt;
* Demeter-Prinzip&lt;br /&gt;
* Trennung von Abstraktions-Ebenen&lt;br /&gt;
* Trennung von Interface und Implementierung siehe dazu auch: Bridge-Pattern&lt;br /&gt;
* Interfaces sollen so schmal wie möglich sein und nur das enthalten was tatsächlich erforderlich ist.&lt;br /&gt;
* verwende Architektur-Pattern&lt;br /&gt;
* verwende das Schichten-Modell&lt;br /&gt;
* [http://clean-code-developer.de/die-grade/roter-grad/#Integration_Operation_Segregation_Principle_IOSP IOSP]– Integration Operation Segregation Principle&lt;br /&gt;
* verwende Design-Pattern (hier einige GoF-Pattern, die ich besonders häufig verwende)&lt;br /&gt;
** Factory Method&lt;br /&gt;
** Adapter&lt;br /&gt;
** (simplified) Builder&lt;br /&gt;
** Singleton&lt;br /&gt;
** Proxy&lt;br /&gt;
** Facade&lt;br /&gt;
** Decorator&lt;br /&gt;
* Delegation statt Vererbung (Delegation wird im GoF-Buch nicht als Pattern sondern als Konzept beschrieben)&lt;br /&gt;
* Ein Konzept – ein Begriff&lt;br /&gt;
::Bsp: die eMail-Adresse sollte im Code nicht durcheinander als &amp;quot;eMail_Adresse&amp;quot;, &amp;quot;mail-Adresse&amp;quot;, &amp;quot;mail&amp;quot;, &amp;quot;eMail&amp;quot; oder sonstwie bezeichnet werden, sondern immer gleich&lt;br /&gt;
* vermeide Antipattern&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Interface_bloat Interface bloat] -- Interfaces verlangen mehr als erforderlich&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Inner-platform_effect Inner-platform effect] – Das System erlaubt soviel Customization, daß eine schlechte Plattform daraus geworden ist.&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Constant_interface Constant Interface] -- Interfaces dienen nur der Definition von Konstanten&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Sequential_coupling Sequential coupling] -– Die Klasse verlangt den Aufruf ihrer Methoden in einer bestimmten Reihenfolge&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Cargo_cult_programming Cargo cult programming] -– Pattern und Methoden verwenden ohne sie zu verstehen&lt;br /&gt;
** [https://en.wikipedia.org/wiki/Golden_hammer Golden hammer] / [https://en.wikipedia.org/wiki/No_Silver_Bullet Silver bullet] -– Alle Probleme mit der gleichen (Lieblings-)Methode lösen&lt;br /&gt;
** Base Bean – Vererbung soll is-a-Beziehungen abbilden, nicht has-a&lt;br /&gt;
** Stellvertreter-Typen – Statt einen Datentyp zu definieren, existierende Klassen (besonders String) mißbrauchen&lt;br /&gt;
** [[Petting Zoo]] - keeping code that is not worth it&lt;br /&gt;
* vermeide [[Code Smell]]s&lt;br /&gt;
* Refactoring&lt;br /&gt;
* Verwende eine durchgehende Nomenklatur&lt;br /&gt;
* Stick to the Coding Guidelines&lt;br /&gt;
* Das gleiche Problem sollte immer auf gleiche Art und Weise gelöst werden&lt;br /&gt;
* Verwende für Kommentare und Bezeichner nur natürliche Sprachen die Du auch beherrschst&lt;br /&gt;
:actualValue für den aktuellen Wert (richtig ist current)&lt;br /&gt;
* bound als Übersetzung für &amp;quot;verknüpft&amp;quot; (richtig ist linked)&lt;br /&gt;
* Don&#039;t state the obvious:&lt;br /&gt;
: Logger logger = LoggerFactory.obtainLogger();&lt;br /&gt;
: String stringToBeLogged = &amp;quot;log: logging start of action Foo&amp;quot;;&lt;br /&gt;
: logger.log(stringToBeLogged);&lt;br /&gt;
* toString() ist kein Serialisierungs-Tool&lt;br /&gt;
* zu viel von etwas ist selten gut:&lt;br /&gt;
: &amp;lt;q&amp;gt;If you know what you&#039;re doing, three layers is enough; if you don&#039;t, even seventeen levels won&#039;t help.&amp;lt;/q&amp;gt;&lt;br /&gt;
:([https://en.wikipedia.org/wiki/Michael_A._Padlipsky Michael Padlipsky])&lt;br /&gt;
&lt;br /&gt;
= Hilfsmittel =&lt;br /&gt;
Entgegen anderslautender Meinungen erhöht der Einsatz von Tools nicht automatisch die Qualität. Das Berechnen von Werten anhand von Metriken beispielsweise trägt zunächst gar nichts zur Qualität bei, erst die Auswertung und das Durchführen von Maßnahmen zur Änderung der Werte kann als qualitätsstiftende Maßnahme gelten. Nichtsdestotrotz unterstützt die Verwendung von Hilfsmitteln den Entwickler dabei den Weg zum Code hoher Qualität zu beschreiten.&lt;br /&gt;
&lt;br /&gt;
* automatisch durchgeführte Unit-Tests&lt;br /&gt;
:Unit-Tests als &amp;quot;Tool&amp;quot; zu beschreiben mag seltsam klingen. Tatsächlich sind Unit-Tests aber nicht Teil des produktiven Codes und daher kann man mit Fug und Recht von einem Tool sprechen.&lt;br /&gt;
* Metriken&lt;br /&gt;
* Tools zur Code-Analyse (sonar, java-Compiler-Warnings)&lt;br /&gt;
* Tools zur Messung der Test-Abdeckung (EclEmma)&lt;br /&gt;
* Automatische Code-Formatierung (Eclipse Code Formatter)&lt;br /&gt;
* Coding-Guidelines&lt;br /&gt;
* [http://www.oracle.com/technetwork/java/javase/documentation/codeconvtoc-136057.html Sun Code Conventions]&lt;br /&gt;
:Sie werden seit 1999 nicht mehr gepflegt. Einige Regeln sind überholt, andere zweifelhaft (z.B. 6.2: Variablen-Deklarationen nur am Beginn eines Code-Blocks plazieren), Sie bilden aber die Grundlage für das Code-Layout und man sollte sie kennen und berücksichtigen.&amp;lt;br&amp;gt;&lt;br /&gt;
:(Fun fact: Der Autor hat anscheinend von C abgeschrieben – es sind tatsächlich ein paar Fehler im Dokument)&lt;br /&gt;
* Refactoring-Tools (IDEs wie Eclipse bringen eine Menge davon mit&lt;br /&gt;
&lt;br /&gt;
= Arbeitstechniken =&lt;br /&gt;
Die klassische Technik des Entwicklers ist das Zurückziehen hinter die Tastatur. Der Entwickler kriecht erst hervor, wenn das Werk vollendet ist. Das beschreibt einen Teil der Tätigkeit, reicht aber schon seit einem halben Jahrhundert nicht mehr aus. Und auch die Handgriffe, mit denen der Entwickler im stillen Kämmerlein den Wandel von Buchstaben in Code vollzieht wandeln sich im Laufe der Zeit. Man muß nicht jede Technik übernehmen, aber man sollte sich damit befassen und zumindest genau wissen, warum man sie nicht einsetzt.&lt;br /&gt;
&lt;br /&gt;
* [[Boy Scout Principle]]&lt;br /&gt;
* Code – fremden und eigenen – lesen und reflektieren&lt;br /&gt;
* zuhören&lt;br /&gt;
* Diskussion über Code&lt;br /&gt;
* Code-Reviews&lt;br /&gt;
* XP – extreme Programming&lt;br /&gt;
** TDD – Test Driven Development&lt;br /&gt;
** Test First Ansatz&lt;br /&gt;
** Pair Programming&lt;br /&gt;
** Root Cause Analysis&lt;br /&gt;
** Incremental Design&lt;br /&gt;
* Embrace the CATSAN method&lt;br /&gt;
* Programming by Difference (→ Michael Feathers)&lt;br /&gt;
* Rubber Duck Debugging&lt;br /&gt;
* Technologische Schulden minimieren&lt;br /&gt;
&lt;br /&gt;
= Literatur =&lt;br /&gt;
* Edsger Dijkstra [https://www.cs.utexas.edu/users/EWD/transcriptions/EWD04xx/EWD447.html On the role of scientific thought]&lt;br /&gt;
* Refactoring: Improving the Design of Existing Code (Martin Fowler/Kent Beck)&lt;br /&gt;
* Working Effectively with Legacy Code (Michael C. Feathers)&lt;br /&gt;
* Clean Code (Robert C. Martin)&lt;br /&gt;
* Design Patterns: Elements of Reusable Object-Oriented Software (Gamma/Helm/Vlissides/Johnson)&lt;br /&gt;
* The Mythical Man Month (Fred Brooks)&lt;br /&gt;
* The Systems Bible – 3rd edition of &amp;quot;Systemantics&amp;quot; (John Gall) [https://en.wikipedia.org/wiki/Systemantics Überblick in der Wikipedia]&lt;br /&gt;
* [https://www.google.de/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=2&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwjKitDwvJ3NAhXFKMAKHQ0hBWEQFggpMAE&amp;amp;url=http%3A%2F%2Fworrydream.com%2Frefs%2FBrooks-NoSilverBullet.pdf&amp;amp;usg=AFQjCNGkOYvU4WQgqaHGAqGgicO0XTRcw&amp;amp;bvm=bv.124088155,d.bGg No Silver Bullet] (Fred Brooks)&lt;br /&gt;
* [https://www.google.de/url?sa=t&amp;amp;rct=j&amp;amp;q=&amp;amp;esrc=s&amp;amp;source=web&amp;amp;cd=1&amp;amp;cad=rja&amp;amp;uact=8&amp;amp;ved=0ahUKEwiWtayRvZ3NAhUMDMAKHe_JDCYQFggcMAA&amp;amp;url=http%3A%2F%2Fhomepages.cwi.nl%2F~storm%2Fteaching%2Freader%2FDijkstra68.pdf&amp;amp;usg=AFQjCNFIgAgWJ_Aoph79yl9-tFusEGgglQ Goto Considered Harmful] (Edsger Dijkstra)&lt;br /&gt;
* [http://clean-code-developer.de/ clean code developer site]&lt;br /&gt;
* [http://chris.beams.io/posts/git-commit/ Regeln für GIT-commit-Kommentare]&lt;br /&gt;
* [http://www.cs.yale.edu/homes/perlis-alan/quotes.html Epigramme von Alan Perlis]&lt;br /&gt;
* [https://www.heise.de/newsticker/meldung/John-Romero-Von-id-Softwares-Anfaengen-und-World-of-Warcraft-Sucht-3296840.html Programmier-Regeln von John Romero]&lt;br /&gt;
* [https://sourcemaking.com Gute Sammlung von Pattern, Anti-Pattern etc.]&lt;br /&gt;
* [https://xkcd.com/1926 Bad Code in XKCD]&lt;br /&gt;
&lt;br /&gt;
= Zen =&lt;br /&gt;
Keine Richtlinien, keine Anweisungen, einfach Aussagen über die man nachdenken kann. Hier kann man beliebig hitzig diskutieren; wichtig ist nur, daß man darüber – möglichst unvoreingenommen – nachdenkt.&lt;br /&gt;
&lt;br /&gt;
* Wer sich nicht klar ausdrückt, denkt auch nicht klar&lt;br /&gt;
* big bang features lead to big bang&lt;br /&gt;
* Software Engineering ist agnostisch&lt;br /&gt;
* Ein Beispiel beweist nichts, widerlegt aber alles – soviel zu TDD- und Test-Abdeckungs-Fetischismus&lt;br /&gt;
* Ist TDD die zeitgemäße Formulierung für &amp;quot;trial and error&amp;quot;?&lt;br /&gt;
* Wenn Du weißt was Du tust, bist Du gesegnet&lt;br /&gt;
* If it ain&#039;t broken, don&#039;t fix it vs. Refactoring&lt;br /&gt;
* Verwende nur was Du auch verstehst ([https://xkcd.com/1597/ Wie XKCD GIT charakterisiert])&lt;br /&gt;
* Wer etwas ablehnt oder verteidigt sollte genau wissen warum&lt;br /&gt;
* Nichts hält so lange wie ein Provisorium&lt;br /&gt;
* Wer trennt schafft Abhängigkeiten, wer nicht trennt schafft Chaos&lt;br /&gt;
* Nichts ist so einfach, daß man es nicht falsch machen könnte&lt;br /&gt;
* Eine Entscheidung ist richtig, wenn sie rational begründet werden kann&lt;br /&gt;
* Was wert ist daß man es tut, ist wert daß man es richtig tut.&lt;br /&gt;
* Wenn man versucht Probleme auszusitzen, kriechen sie irgendwann hervor und treten einem in den Hintern&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Code_Smell&amp;diff=190</id>
		<title>Code Smell</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Code_Smell&amp;diff=190"/>
		<updated>2024-11-28T10:02:05Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Category:IT Die erste Erwähnung des Begriffs &amp;quot;code smell&amp;quot; findet sich in Martin Fowlers Buch &amp;quot;Refactoring&amp;quot;. Er verwendet ihn dort als es darum geht die Code-Stellen zu identifizieren an denen Refactoring erforderlich ist. Fowler bleibt dabei ausgesprochen vage, aber die Andeutung auf verunreinigte Baby-Windeln erzeugt den starken Eindruck, daß es sich hier um ausgesprochen unangenehme Gerüche handeln muß...  Ein Code Smell ist eine Stelle im Code…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:IT]]&lt;br /&gt;
Die erste Erwähnung des Begriffs &amp;quot;code smell&amp;quot; findet sich in Martin Fowlers Buch &amp;quot;Refactoring&amp;quot;. Er verwendet ihn&lt;br /&gt;
dort als es darum geht die Code-Stellen zu identifizieren an denen Refactoring erforderlich ist. Fowler bleibt dabei&lt;br /&gt;
ausgesprochen vage, aber die Andeutung auf verunreinigte Baby-Windeln erzeugt den starken Eindruck, daß es sich&lt;br /&gt;
hier um ausgesprochen unangenehme Gerüche handeln muß...&lt;br /&gt;
&lt;br /&gt;
Ein Code Smell ist eine Stelle im Code mit bestimmten Eigenschaften, an denen sie zu erkennen ist. Diese&lt;br /&gt;
Eigenschaften bilden den bisweilen charakteristischen Geruch. Eine Methode mit einer langen Parameterliste ist ein Beispiel&lt;br /&gt;
dafür, mit jedem weiteren Parameter wird der Geruch intensiver.&lt;br /&gt;
&lt;br /&gt;
Viele Code Smells haben eine Ursache. Eine lange Parameterliste zum Beispiel kann das Ergebnis sukzessiver&lt;br /&gt;
Verallgemeinerung sein. Die ursprüngliche Methode hatte vielleicht nur zwei Parameter, aber mit jeder Anpassung&lt;br /&gt;
an die geänderten Anforderungen kam ein neuer Parameter hinzu. Nicht jeder Smell hat eine klare Ursache, für&lt;br /&gt;
manche Smells gibt es mehrere mögliche Ursachen. In aller Regel ist es sinnvoll die Ursache zu ergründen, denn&lt;br /&gt;
unterschiedliche Ursachen können unterschiedliche Refactoring-Maßnahmen nahelegen. Hier endet ein Zipfel der&lt;br /&gt;
Analogie, denn Baby-Kacke beseitigt man normalerweise immer auf die gleiche Weise...&lt;br /&gt;
&lt;br /&gt;
Nicht alle Gerüche sind per se unangenehm. Fowler beschreibt zum Beispiel den Geruch von Kommentaren als&lt;br /&gt;
angenehm – nachgerade verführerisch angenehm, denn fehlerhafte Kommentaren können Probleme – und die&lt;br /&gt;
damit verbundenen Gerüche – verdecken.&lt;br /&gt;
&lt;br /&gt;
Ich strecke die Analogie gerne in eine andere Richtung: Verschiedene Entwickler reagieren auf verschiedene&lt;br /&gt;
Gerüche unterschiedlich. Dem einen wird bei einer 10-Zeilen-Methode übel, der andere fühlt sich vom&lt;br /&gt;
100-Zeilen-Geruch noch nicht belästigt. Und wieder scheinen den Duft von Methoden um so angenehmer zu emfinden,&lt;br /&gt;
je länger sie wird.&lt;br /&gt;
&lt;br /&gt;
Es ist Aufgabe des Teams eine Umgebung zu schaffen die einen vernünftigen Kompromiß bringt.&lt;br /&gt;
Es wäre falsch, ganz auf die Beseitigung von Code-Smells zu verzichten. Ebenso falsch aber wäre es,&lt;br /&gt;
die Beseitigung bestimmter Smells zu erzwingen –- um bei der Analogie zu bleiben: der Geruch von&lt;br /&gt;
Desinfektionsmittel kann durchaus unangenehm sein.&lt;br /&gt;
&lt;br /&gt;
Wie im wirklichen Leben, können Gerüche auf tödliche Gefahren hinweisen -– der Geruch von Bittermandel ist nicht&lt;br /&gt;
unbedingt unangenehm, eine Zyanid-Vergiftung ist es aber auf jeden Fall... Doch nicht hinter jedem Geruch steckt ein&lt;br /&gt;
verrotteter Fäulnisherd, der die Anwendung in eine einsturzgefährdete Todesfalle verwandelt. Manchmal handelt&lt;br /&gt;
es sich lediglich um einen ungewohnten Eigengeruch, an dessen Aroma man sich erst gewöhnen muß.&lt;br /&gt;
&lt;br /&gt;
Nachdem wir nun –- dem Duft der Analogie -– folgend um das eigentliche Thema herummäandert sind, bringen wir&lt;br /&gt;
die Sache mal auf den Punkt:&lt;br /&gt;
* Ein Code Smell ist der Hinweis auf eine Code-Stelle, die Beachtung verdient&lt;br /&gt;
* Ein Code-Smell ist nicht per se schlecht&lt;br /&gt;
* Ein Code Smell kann der Hinweis auf eine Schwachstelle sein, die zu ernsthaften Problemen führen kann&lt;br /&gt;
* Code-Smells müssen in der Regel mit Rücksicht auf die Ursache behandelt werden&lt;br /&gt;
Nachdem wir nun eine Vorsetllung davon haben was einen Code Smell ausmacht, können wir uns nun den&lt;br /&gt;
konkreten Beispielen befassen...&lt;br /&gt;
&lt;br /&gt;
&amp;quot;Beliebte&amp;quot; Code Smells...&lt;br /&gt;
* Shot Gun Surgery (Martin Fowler)&lt;br /&gt;
* Speculative Generalization (Martin Fowler)&lt;br /&gt;
* Zu viele Zeilen in der Methoden oder Klasse&lt;br /&gt;
* Zu viele (mehr als drei) formale Parameter in der Methoden-Signatur&lt;br /&gt;
* Ungenutzte Felder, Parameter, Methoden, Code etc.&lt;br /&gt;
* Explizites type casting&lt;br /&gt;
* Unangemessener Gebrauch von null&lt;br /&gt;
* Auto-unboxing wegen unnötiger Verwendung von Wrapper-Klassen um int, long, etc.&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Nachgedanke&lt;br /&gt;
:Worte wie &amp;quot;eigentlich&amp;quot; und &amp;quot;wirklich&amp;quot; sind code smells der natürlichen Sprache.&lt;br /&gt;
:Sie riechen nach &amp;quot;Ideologie&amp;quot;.&lt;br /&gt;
:Sie riechen nach &amp;quot;mir sind die rational-logischen Argumente ausgegangen&amp;quot;&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Parametrisierte_Tests&amp;diff=189</id>
		<title>Parametrisierte Tests</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Parametrisierte_Tests&amp;diff=189"/>
		<updated>2024-11-19T18:39:27Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
[[Category:junit]]&lt;br /&gt;
Ein einzelner Unit-Tests befaßt sich mit einem einzelnen Test-Fall und hat im Regelfall eine einzelne Assertion.&lt;br /&gt;
Dieses einfache Beispiel testet die korrekte Konvertierung von Datum-Strings in ein Date-Objekt. Die drei Assertions&lt;br /&gt;
prüfen hier zusammen, ob das Datum korrekt ist:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@Test&lt;br /&gt;
public void toDateLiefertKorrektesDatum() {&lt;br /&gt;
    Date convertedDate = Convert.toDate(&amp;quot;01.5.1985&amp;quot;);&lt;br /&gt;
    assertThat(convertedDate).hasDayOfMonth(1);&lt;br /&gt;
    assertThat(convertedDate).hasMonth(5);&lt;br /&gt;
    assertThat(convertedDate).hasYear(1985);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Nun soll er Konverter mit unterschiedlichen Datums-Angaben umgehen: Mit und ohne führende Nullen, mit und&lt;br /&gt;
ohne Jahrhundert, vielleicht soll auch ein Minuszeichen anstelle des Punkts erlaubt sein. Für jeden Testfall kann&lt;br /&gt;
man nun die Test-Methode kopieren und entsprechend anpassen. Die Folgen sind klar: jede Menge Test-Code,&lt;br /&gt;
sinkende Übersichtlichkeit und für jede neue Test-Methode braucht es einen neuen Namen. Das DRY-Prinzip soll&lt;br /&gt;
auch für Test-Code gelten.&lt;br /&gt;
&lt;br /&gt;
Eine wesentliche Bereicherung von JUnit-5 ist die Unterstützung von Parameter-gesteuerten Test-Methoden die&lt;br /&gt;
weit über das hinausgeht was JUnit-4 oder Test-NG zu bieten hatten. Eine Vielzahl von Test-Situationen läßt sich&lt;br /&gt;
damit abdecken und vor allem eindampfen.&lt;br /&gt;
== Eine Liste einzelner Parameter ==&lt;br /&gt;
Betrachten wir –- angelehnt an das einleitende Beispiel -– die einfachste Situation: Einen Testfall soll mit einer Reihe&lt;br /&gt;
einzelner Strings aufgerufen werden. Dazu parametrisieren wir zunächst die Test-Methode und ziehen den Datum-String als Parameter heraus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
void toDateLiefertKorrektesDatum(String datum) {&lt;br /&gt;
    Date convertedDate = Convert.toDate(datum);&lt;br /&gt;
    assertThat(convertedDate).hasDayOfMonth(1);&lt;br /&gt;
    assertThat(convertedDate).hasMonth(5);&lt;br /&gt;
    assertThat(convertedDate).hasYear(1985);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Dann legen wir die Datum-Strings fest mit denen getestet werden soll:&lt;br /&gt;
{{java|&amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot;}}.&lt;br /&gt;
Um die neue Test-Methode mit den Test-Fälle zu verknüpfen, verwenden wir JUnit5-Annotationen und setzen sie&lt;br /&gt;
über unsere parametrisierte Test-Methode:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@ValueSource(strings = { &amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot; })&lt;br /&gt;
}}&lt;br /&gt;
Die erste Annotation ersetzt die {{java|@Test}}-Annotation und macht die Methode zum (parametrisierten) Test.&lt;br /&gt;
Die zweite Annotation legt die Quelle der zu verwendenden Werte fest.&lt;br /&gt;
In diesem Falle ist dies eine Liste von Strings. Der Test wird bei der&lt;br /&gt;
Ausführung für jeden String einmal aufgerufen, wobei der jeweilige String als Argument übergeben wird.&lt;br /&gt;
Anstelle von Strings sind hier auch alle numerischen, primitiven Typen int, long, float und einiges mehr erlaubt.&lt;br /&gt;
Die Anntotations-Parameter kann man in Eclipse mit Code-Assist erkunden oder in der JUnit5-Doku nachlesen.&lt;br /&gt;
&lt;br /&gt;
Beachtenswert ist, daß Annotationen nur Konstanten als Argumente übernehmen,&lt;br /&gt;
also Ausdrücke die zur Compile-Zeit ausgewertet werden können. Objekte zu übergeben ist so nicht möglich.&lt;br /&gt;
&lt;br /&gt;
Wie man damit umgeht, sehen wir in den folgenden Abschnitten.&lt;br /&gt;
Vorher aber noch ein Wort zu {{java|null}}.&lt;br /&gt;
&lt;br /&gt;
=== Was ist mit null? ===&lt;br /&gt;
Die eben vorgestellte Werte-Liste hat einen kleinen Haken: Es ist nicht möglich, den Wert null als Argument zu&lt;br /&gt;
verwenden. Um einen Testfall für null zu erzeugen, kann man nun freilich eine neue Test-Methode erstellen und&lt;br /&gt;
null separat in diesem Test prüfen. Man kann dem Test aber auch zusätzlich die Annotation {{java|@NullSource}}&lt;br /&gt;
hinzufügen. JUnit5 erzeugt dann einen zusätzlichen Testfall für {{java|null}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@NullSource&lt;br /&gt;
@ValueSource(strings = { &amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot; })&lt;br /&gt;
public void toDateLiefertKorrektesDatum(String datum) {&lt;br /&gt;
    // hier kommt der Test-Code hin...&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Unterstützt wird {{java|@NullSource}} ab Version 5.4.&lt;br /&gt;
&lt;br /&gt;
== Einzelne Argumente aus einer Methode ==&lt;br /&gt;
Anstelle der Angabe von Annotations-Parametern kann man eine Methode schreiben die die Argumente liefert.&lt;br /&gt;
Die Methode muß {{java|static}} sein und einen {{java|Stream}} von &amp;quot;irgendwas&amp;quot; liefern.&lt;br /&gt;
Das obige Beispiel kann man dann so schreiben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@MethodSource(&amp;quot;testDatenMethode&amp;quot;)&lt;br /&gt;
void toDateLiefertKorrektesDatum(String datum) {&lt;br /&gt;
    // sieht genauso aus wie oben&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
static Stream&amp;lt;String&amp;gt; testDatenMethode() {&lt;br /&gt;
    return Stream.of(&amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Das Beispiel hat den gleichen Effekt wie die Implementierung im vorabgegangenen Abschnitt,&lt;br /&gt;
aber die Möglichkeiten sind offensichtlich viel weiterreichend. In der Test-Daten-Methode lassen&lt;br /&gt;
sich beliebige Objete liefern, die bei bedarf auch dynamisch erzeugt werden können.&lt;br /&gt;
Der Wert {{java|null} ist hier kein Problem, er darf im Stream enthalten sein.&lt;br /&gt;
&lt;br /&gt;
Hat die Testdaten-Methode den gleichen Namen wie die parameterisierte Test-Methode,&lt;br /&gt;
kann man den Parameter der Annotation {{java|@MethodSource}} übrigens weglassen.&lt;br /&gt;
&lt;br /&gt;
== Mehrere Parameter für die Test-Methode ==&lt;br /&gt;
Für viele Unit-Tests reicht die Extraktion eines einzelnen Parameters nicht aus. Im folgenden Beispiel wird die&lt;br /&gt;
Qualität von Passworten getestet. Das Wort &amp;quot;Hallo&amp;quot; zum Beispiel wird abgewiesen, weil es nur Buchstaben enthält:&lt;br /&gt;
 public void passwortWirdNichtAkzeptiert() {&lt;br /&gt;
     assertThat(policy.validate(&amp;quot;Hallo&amp;quot;)).as(&amp;quot;nur Buchstaben&amp;quot;).isFalse();&lt;br /&gt;
 }&lt;br /&gt;
Wofür die Parameter in der Test-Methode verwendet werden, spielen keine Rolle, es geht nur darum, den Test&lt;br /&gt;
mehrfach aufzurufen und dabei &#039;&#039;mehrere&#039;&#039; Parameter zu übergeben. Im vorliegenden Falle möchten wir&lt;br /&gt;
unterschiedliche Passwort-Kandidaten testen und dabei jeden Test mit einer Beschreibung versehen, der Auskunft&lt;br /&gt;
gibt warum das Wort nicht als Passwort akzeptiert wird. Die Test-Methode sieht nun so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void passwortWirdNichtAkzeptiert(String passwort, String grund) {&lt;br /&gt;
    assertThat(policy.validate(passwort)).as(grund).isFalse();&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Für die Erzeugung der Test-Daten schreiben wir diesmal eine weitere Methode.&lt;br /&gt;
Sie erzeugt einen Stream von Arguments-Objekten von denen jedes die Daten für &#039;&#039;einen&#039;&#039; Test-Aufruf enthält:&lt;br /&gt;
{{java|code=&lt;br /&gt;
static Stream&amp;lt;Arguments&amp;gt; pwdWirdNichtAkzeptiert() {&lt;br /&gt;
    return Stream.of(&lt;br /&gt;
        Arguments.of(&amp;quot;Hallo&amp;quot;, &amp;quot;nur Buchstaben&amp;quot;),&lt;br /&gt;
        Arguments.of(&amp;quot;1234567&amp;quot;, &amp;quot;nur Ziffern&amp;quot;),&lt;br /&gt;
        Arguments.of(&amp;quot;!%#&amp;amp;/()&amp;quot;, &amp;quot;nur Sonderzeichen&amp;quot;)&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Die Methode für die Testdaten-Erzeugung muß folgende Eigenschaften haben:&lt;br /&gt;
*sie muß static deklariert sein&lt;br /&gt;
*sie muß zur Test-Klasse gehören&lt;br /&gt;
*sie darf keinen Parameter haben und muß einen Stream von Arguments-Objekten liefern&lt;br /&gt;
*sie darf in beliebiger Sichtbarkeit deklariert werden&lt;br /&gt;
Die Methode darf zwar private deklariert werden, Java wird sich aber darüber beschweren, daß die Methode&lt;br /&gt;
nirgends verwendet wird. Warum das so ist, erfahren wir weiter unten.&lt;br /&gt;
Am einfachsten deklariert man sie daher package visible.&lt;br /&gt;
&lt;br /&gt;
Die Klasse&lt;br /&gt;
{{java|org.junit.jupiter.params.provider.Arguments}}&lt;br /&gt;
ist ein Container, der eine Reihe von Werten beliebigen Typs (mit Ausnahme von {{Lambda}}-Ausdrücken) in fester&lt;br /&gt;
Reihenfolge aufnimmt. JUnit5 mappt die Werte der {{java|Arguments}}-Objekte auf die Parameter der Test-Methode. Das&lt;br /&gt;
geschieht allerdings erst zur Laufzeit, der Entwickler ist daher selbst dafür verantwortlich die Typen zwischen&lt;br /&gt;
Testdaten-Provider und Test-Methode in Übereinstimmung zu halten.&lt;br /&gt;
&lt;br /&gt;
Wir bringen nun Test-Methode und Testdaten-Provider-Methode zusammen. Das geschieht mithilfe folgender JUnit5-Annotationen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@MethodSource(&amp;quot;pwdWirdNichtAkzeptiert&amp;quot;)&lt;br /&gt;
}}&lt;br /&gt;
Die erste Annotation kennen wir schon aus dem vorangegangenen Abschnitt. Die zweite Annotation weist die Test-Methode an&lt;br /&gt;
die Testdaten aus der Methode &amp;quot;pwdWirdNichtAkzeptiert&amp;quot; zu beziehen. Der Name der Methode wird als String angegeben.&lt;br /&gt;
Das bedeutet, daß der Entwickler für die korrekte Schreibweise verantwortlich ist, Fehler treten auch hier erst zur Laufzeit auf.&lt;br /&gt;
Hat die Test-Daten-Methode den gleichen Namen wie die Test-Methode kann sie in&lt;br /&gt;
der Annotation auch weggelassen werden. Die Annotation selbst hingegen kann &#039;&#039;nicht&#039;&#039; weggelassen werden.&lt;br /&gt;
Da die Methode nur über den Namen referenziert wird, muß der Compiler tatsächlich annehmen,&lt;br /&gt;
daß die Method nicht verwendet wird wenn sie als private deklariert wurde.&lt;br /&gt;
=== Lambda-Ausdrücke ===&lt;br /&gt;
Warum sollte man {{lambda}}-Ausdrücke in einem parametrisierten Test verwenden?&lt;br /&gt;
Denkt man etwa an ein Objekt mit einer Reihe von getter- und setter-Methoden,&lt;br /&gt;
läßt sich mithilfe von {{lambda}}-Ausdrücken die Objekt-Bestückung sehr kompakt vertesten.&lt;br /&gt;
&lt;br /&gt;
ersetzt man in der oben vorgestellten Befüll-Methode ein String-Argument durch einen {{lambda}}-Ausdruck&lt;br /&gt;
läuft der compiler allerdings ganz flott auf einen Fehler, weil der {{lambda}}-Ausdruck nicht in ein Objekt&lt;br /&gt;
gecastet werden kann. Dazu braucht es eines (funktionalen) Interfaces. Man kann dazu die vom JDK bereitgestellten&lt;br /&gt;
Interfaces nutzen oder eigene Interfaces definieren. Für Unit-Tests ist das zweitere vorzuziehen.&lt;br /&gt;
&lt;br /&gt;
Stellen wir uns also mal eine POJO mit dem klassischen Getter und Setter vor:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class Person {&lt;br /&gt;
  private String vorname;&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
==Weitere Test-Daten-Provider==&lt;br /&gt;
JUnit5 unterstützt noch eine Reihe weiterer Möglichkeiten, Testdaten für parametrisierte Tests zur Verfügung zu&lt;br /&gt;
stellen:&lt;br /&gt;
*Java-enums&lt;br /&gt;
*CSV-Dateien&lt;br /&gt;
*Daten im CSV-Format&lt;br /&gt;
*separate Klassen&lt;br /&gt;
==Enums==&lt;br /&gt;
Eine besondere Unterstützung bei der Erstellung parametrisierter Tests erfahren die Java-enums. Grundsätzlich&lt;br /&gt;
erfolgt die Parametrisierung wie dies hier am Beispiel von String-Argumenten beschrieben wurde. Auf die&lt;br /&gt;
spezifischen Eigenschaften von enums und ihrem besonderen Wert für Unit-Tests wird hier eingegangen.&lt;br /&gt;
Betrachten wir ein enum das Versandwege beschreibt:&lt;br /&gt;
{{java|code=&lt;br /&gt;
enum Versandweg {&lt;br /&gt;
    E_MAIL,&lt;br /&gt;
    SMS,&lt;br /&gt;
    POST&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
und die zu testende Methode die eine TAN über einen Versandweg verschickt:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class Versender {&lt;br /&gt;
    Response sendTan(Versandweg weg) {&lt;br /&gt;
        ...&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
===Alle Ausprägungen testen===&lt;br /&gt;
Wir können nun für jeden Versandweg eine Test-Methode schreiben. Das geht auch einfacher, wenn wir immer das&lt;br /&gt;
gleiche Ergebnis erwarten:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@EnumSource(value=Versandweg.class)&lt;br /&gt;
void verwandWegLiefertOk(Versandweg weg) {&lt;br /&gt;
    Assertions.assertThat(new Versender().sendTan(weg)).isEqualTo(Response.OK);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Die erste Annotation weist die Methode als parametrisierten Test aus. Die zweite Annotation gibt an, welches enum&lt;br /&gt;
für den Test zu verwenden ist. Die Test-Methode selbst muß ein Argument vom Typ des Enums akzeptieren.&lt;br /&gt;
Die parametrisierte Version ist nicht nur kompakter. Wird das enum um weitere Ausprägungen ergänzt, werden&lt;br /&gt;
automatisch Test dafür generiert. Ob das Ergebnis tatsächlich der gewünschten Anforderung entspricht kann JUnit&lt;br /&gt;
natürlich nicht vorhersehen, aber die neue enum-Ausprägung wird zumindest betrachtet und läuft günstigenfalls&lt;br /&gt;
auf einen Fehler.&lt;br /&gt;
=== Einzelne Ausprägungen testen ===&lt;br /&gt;
Möchte man nicht alle Ausprägungen testen sondern nur ganz bestimmte, kann man das der Annotation mitgeben.&lt;br /&gt;
dafür gibt es zwei Modes: &#039;&#039;einschließend&#039;&#039; und &#039;&#039;ausschließend&#039;&#039;.&lt;br /&gt;
Möchten wir etwa nur die Versandwege eMail und SMS testen, können wir die Annotation so schreiben (der ganze Rest bleibt gleich):&lt;br /&gt;
{{java|code=@EnumSource(value = Versandweg.class, mode = Mode.INCLUDE, names = { &amp;quot;E_MAIL&amp;quot;, &amp;quot;SMS&amp;quot; })}}&lt;br /&gt;
Der Parameter {{java|mod}} gibt an, daß nur die angegebenen Ausprägungen getestet werden sollen. Da &amp;quot;Include&amp;quot; der&lt;br /&gt;
default ist, kann de Mo in diesem Falle auch weggelassen werden. Der Parameter {{java|names}} ist eine Liste von enum-Ausprägung-Namen die als Strings angegeben werden.&lt;br /&gt;
Man kann das vorgehen auch umdrehen un den Versandweg &amp;quot;POST&amp;quot; – als einzigen nicht-elektronischen Weg&lt;br /&gt;
ausschließen. Die Annotation sieht dann so aus:&lt;br /&gt;
{{java|code=@EnumSource(value = Versandweg.class, mode = Mode.EXCLUDE, names = { &amp;quot;POST&amp;quot; })}}&lt;br /&gt;
Der {{java|mode}}-Parameter hat nun den Wert {{java|EXCLUDE}} und darf natürlich nicht weggelassen werden. Der Parameter&lt;br /&gt;
{{java|names}} ist wieder eine Liste von enum-Ausprägung-Namen die hier aus einem einzigen Wert besteht.&lt;br /&gt;
In beiden Fällen ist der Entwickler für die korrekte Schreibweise der Namen der enum-Ausprägungen&lt;br /&gt;
verantwortlich. Stimmt sie nicht überein, giebt&#039;s einen Laufzeitfehler bei der Test-Ausführung.&lt;br /&gt;
Während bei &amp;quot;INCLUDE&amp;quot; nur so viel Tests erzeugt werden, wie enum-Ausprägungen spezifiziert wurden, werden bei&lt;br /&gt;
&amp;quot;EXCLUDE&amp;quot; Tests für alle Ausprägungen erzeugt die nicht angegeben sind. Wird das enum um Ausprägungen&lt;br /&gt;
erweitert, dann werden im EXCLUDE-Falle neue Tests generiert, im INCLUDE-Falle nicht.&lt;br /&gt;
&lt;br /&gt;
===Pattern-Matching===&lt;br /&gt;
Mit den beiden Modes MATCH_ALL und MATCH_ANY können die Namen von enum-Ausprägungen mit Hilfe von&lt;br /&gt;
regulären Ausdrücken spezifiziert werden. Dieses Vorgehen ist jedoch problematisch und soll hier nicht weiter&lt;br /&gt;
erörtert werden. Macht man bei Definition der Ausdrücke Fehler, kann es beispielsweise passieren, daß&lt;br /&gt;
Ausprägungen ausgelassen werden und für diese dann keine Tests erzeugt werden. Das fällt nur auf wenn die TestAusführung manuell überprüft wird.&lt;br /&gt;
===Test-Fälle als Enumerationen===&lt;br /&gt;
bei der Verwendung von enum-Sources ist man nicht auf &amp;quot;produktive&amp;quot; enums beschränkt. Man kann auch Test-Situationen über enums definieren und diese&lt;br /&gt;
enums dann verwenden um parametrisierte Tests zu füttern. Man kann zum Beispiel für die Test-Klasse enum &amp;quot;Kunde&amp;quot; definieren, dessen Ausprägungen&lt;br /&gt;
jeweils einzelne Test-Konstellationen beschreiben. Damit lassen sich parametrisierte Tests definieren, die alle oder ausgewählte Konstellationen testen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@EnumSource(value = Kunde.class, names = { &amp;quot;MIT_KDNR&amp;quot;, &amp;quot;MIT_IHNR&amp;quot;, &amp;quot;MIT_KDNR_UND_IHNR&amp;quot; })&lt;br /&gt;
void darfElektronischeDokumentEinstellungSehen(Kunde kunde) {&lt;br /&gt;
    assertThat(verwalter(kunde).darfElectronicDocumentsSehen()).isTrue();&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
In diesem Beispiel wurde Kunden konfiguriert die ein Kunden- oder Inhabernummer oder beides haben. Jeder der&lt;br /&gt;
Kunden muß seine elektronischen Dokumente sehen dürfen.&lt;br /&gt;
&lt;br /&gt;
== Test-Beschreibung ==&lt;br /&gt;
Parameterisierte Tests unterscheiden sich zunächst nur in ihren Argumenten. Wenn JUnit die Tests ausführt,&lt;br /&gt;
wird aus den Argumenten eine beschreibung generiert die nicht immer leicht zu entziffern ist.&lt;br /&gt;
&lt;br /&gt;
Alternativ kann man der Annotation einen String mitgeben aus dem der Name generiert wird:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest(name = &amp;quot;Test&amp;quot;)&lt;br /&gt;
}}&lt;br /&gt;
Das Beispiel ist extrem unnütz, denn jetzt haben alle Einzel-Tests die gleiche Beschreibung -- &amp;quot;Test&amp;quot;.&lt;br /&gt;
Um daraus eine brauchbare Beschreibung zu machen bietet JUnit5 Textersatz an:&lt;br /&gt;
&lt;br /&gt;
Verwendet man {{java|{index}}} in der Beschreibung, wird die Nummer des Tests angezeigt. Sehr praktisch, wenn man den Testfall später sucht.&lt;br /&gt;
&lt;br /&gt;
Die übergebenen Parameter kann man mit {{java|{x}}} anzeigen, wobei {{java|x}} für die Positions-Nummer eines Parameters steht -- beginnend mit 0.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=188</id>
		<title>Java 17: Switch</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=188"/>
		<updated>2024-03-28T20:04:49Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
Um die Erwartungen vorab zu dämpfen:&lt;br /&gt;
Auch Java 17 erlaubt nur die aufzählbaren Daten-Type sowie String, aber keine anderne Objekt-Typen.&lt;br /&gt;
Auch führt der Aufruf mit {{java|null}} weiterhin unweigerlich zu einer Null-Pointer-Exception.&lt;br /&gt;
So &#039;&#039;richtig&#039;&#039; cool wird das {{java|switch}} allerdings mit Java 21...&lt;br /&gt;
&lt;br /&gt;
Betrachten wir die klassische Anwendung der {{java|switch}}-Kontrollstruktur:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleOhneBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der Aufruf von {{java|oldStyleOhneBreak(Animal.ANT)}} liefert:&lt;br /&gt;
 6 legs&lt;br /&gt;
 strange animal&lt;br /&gt;
Wegen des &amp;quot;fall-through&amp;quot;-Verhaltens (was man berechtigterweise mit &amp;quot;Durchfall&amp;quot; übersetzen kann) werden&lt;br /&gt;
alle nachfolgenden Fälle durchlaufen, sobald der erste Match auftritt. Um das zu verhindern, muß man nach&lt;br /&gt;
jeder {{java|case}}-Anweisung ein {{java|break}} einfügen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleWithBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Das ist viel Code, unübersichtlich, fehleranfällig -- und kontrovers.&lt;br /&gt;
Java 17 bietet nun eine Alternative, bei der der {{java|:}} in der Case-Anweisung durch {{java|-&amp;gt;}}.&lt;br /&gt;
Es muß aber ausdrücklich darauf hingeweisen werden, daß es sich hier um &#039;&#039;&#039;keinen&#039;&#039;&#039; {{lambda}}-Ausdruck handelt.&lt;br /&gt;
Das Ergebnis der ersten Fassung sieht nun so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyle(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE -&amp;gt; System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default -&amp;gt; System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Da für jeden Fall hier nur eine Zeile verwendet wird, ist der gesamte Ausdruck kompakter.&lt;br /&gt;
Das könnte man durchaus auch mit dem klassischen {{java|case}}-Konstrukt hinkriegen.&lt;br /&gt;
&lt;br /&gt;
Überraschender ist aber das Ergebnis, wenn man {{java|newStyle(Animal.ANT)}} ausführt:&lt;br /&gt;
 6 legs&lt;br /&gt;
Das {{java|break}} wird nicht mehr benötigt, der neue Stil hat keine Durchfall-Symptome mehr!&lt;br /&gt;
&lt;br /&gt;
Nach dem {{java|-&amp;gt;}} darf eine beliebige Anweisung kommen.&lt;br /&gt;
Anstelle einer &#039;&#039;einzelnen&#039;&#039; Anweisung ist also auch ein beliebig großer Code-Block erlaubt.&lt;br /&gt;
&lt;br /&gt;
Da wir in jedem der Fälle die gleiche Aktion ausführen, könnten wir uns auch den Ausgabe-Text liefern lassen&lt;br /&gt;
und ihn im Anschluß ausgeben. Genau dafür bietet das neue {{java|switch}} eine Möglichkeit:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithReturnValue(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Man kann sich vorstellen, daß {{java|switch}} &#039;&#039;immer&#039;&#039; einen Rückgabe-Typ hat, der allerdings in den vorangehenden Beispielen&lt;br /&gt;
{{java|void}} war und daher nicht gespeichert werden konnte. Java prüft in jedem Fall den Typ und meldet Verstöße die durch&lt;br /&gt;
Inkompatibilität entstehen.&lt;br /&gt;
&lt;br /&gt;
Was machen wir nun, wenn nach dem {{java|-&amp;gt;}} kein Ausdruck vom gewünschten Typ kommt, sondern ein ganzer Code-Block?&lt;br /&gt;
Hier hilft das {{java|yield}}. Es kommt am Ende des Code-Blocks und giebt den Wert zurück:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    case CENTIPEDE -&amp;gt; {&lt;br /&gt;
        System.err.println(&amp;quot;lost count&amp;quot;);&lt;br /&gt;
        yield &amp;quot;many legs&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{java|yield}} ist -- entgegen der ersten Vermutung -- &#039;&#039;kein&#039;&#039; keyword, sondern ein &amp;quot;reservierter Identifier&amp;quot;.&lt;br /&gt;
So ist die Anweisung &lt;br /&gt;
{{java|code=&lt;br /&gt;
int yield = 5;&lt;br /&gt;
}}&lt;br /&gt;
durchaus erlaubt. Es erübrigt sich, darauf hinzuweisen diese Verwendung zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
Freundlicherweise darf man das {{java|yield}} auch mit dem {{java|switch}} im alten Stil verwenden.&lt;br /&gt;
Da dabei das {{java|switch}} unmittelbar verlassen wird, spart man sich dabei das {{java|break}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void oldStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        yield &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        yield &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default:&lt;br /&gt;
        yield &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Fazit ==&lt;br /&gt;
&lt;br /&gt;
Das gemeine {{java|switch}} wird durch die Verwendung von {{java|-&amp;gt;}} kompakter und veständlicher.&lt;br /&gt;
Folgt man allerdings der Regel möglichst kleine Methoden zu schreiben, wird man praktisch jedes {{java|witch}}&lt;br /&gt;
in eine eigene Methode auslagern. Die Rückgabe-Notation bietet dann keine nennenswerten Gewinn mehr,&lt;br /&gt;
man spart sich allerdings bei Verwendung von {{java|-&amp;gt;}} das {{java|return}}.&lt;br /&gt;
&lt;br /&gt;
Nichstdestotrotz hilft das Feature dabei, legacy-Code zu optimieren und darüber zu refactorn.&lt;br /&gt;
Dazu schreibt man das {{java|switch}} erst auf die Rückgabe-Notation um und lagert sie dann in eine eigene Methode aus.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=187</id>
		<title>Java 17: Switch</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=187"/>
		<updated>2024-03-28T20:04:31Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
Um die Erwartungen vorab zu dämpfen:&lt;br /&gt;
Auch Java 17 erlaubt nur die aufzählbaren Daten-Type sowie String, aber keine anderne Objekt-Typen.&lt;br /&gt;
Auch führt der Aufruf mit {{java|null}} weiterhin unweigerlich zu einer Null-Pointer-Exception.&lt;br /&gt;
So richtig &#039;&#039;cool&#039;&#039; wird das {{java|switch}} allerdings mit Java 21...&lt;br /&gt;
&lt;br /&gt;
Betrachten wir die klassische Anwendung der {{java|switch}}-Kontrollstruktur:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleOhneBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der Aufruf von {{java|oldStyleOhneBreak(Animal.ANT)}} liefert:&lt;br /&gt;
 6 legs&lt;br /&gt;
 strange animal&lt;br /&gt;
Wegen des &amp;quot;fall-through&amp;quot;-Verhaltens (was man berechtigterweise mit &amp;quot;Durchfall&amp;quot; übersetzen kann) werden&lt;br /&gt;
alle nachfolgenden Fälle durchlaufen, sobald der erste Match auftritt. Um das zu verhindern, muß man nach&lt;br /&gt;
jeder {{java|case}}-Anweisung ein {{java|break}} einfügen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleWithBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Das ist viel Code, unübersichtlich, fehleranfällig -- und kontrovers.&lt;br /&gt;
Java 17 bietet nun eine Alternative, bei der der {{java|:}} in der Case-Anweisung durch {{java|-&amp;gt;}}.&lt;br /&gt;
Es muß aber ausdrücklich darauf hingeweisen werden, daß es sich hier um &#039;&#039;&#039;keinen&#039;&#039;&#039; {{lambda}}-Ausdruck handelt.&lt;br /&gt;
Das Ergebnis der ersten Fassung sieht nun so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyle(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE -&amp;gt; System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default -&amp;gt; System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Da für jeden Fall hier nur eine Zeile verwendet wird, ist der gesamte Ausdruck kompakter.&lt;br /&gt;
Das könnte man durchaus auch mit dem klassischen {{java|case}}-Konstrukt hinkriegen.&lt;br /&gt;
&lt;br /&gt;
Überraschender ist aber das Ergebnis, wenn man {{java|newStyle(Animal.ANT)}} ausführt:&lt;br /&gt;
 6 legs&lt;br /&gt;
Das {{java|break}} wird nicht mehr benötigt, der neue Stil hat keine Durchfall-Symptome mehr!&lt;br /&gt;
&lt;br /&gt;
Nach dem {{java|-&amp;gt;}} darf eine beliebige Anweisung kommen.&lt;br /&gt;
Anstelle einer &#039;&#039;einzelnen&#039;&#039; Anweisung ist also auch ein beliebig großer Code-Block erlaubt.&lt;br /&gt;
&lt;br /&gt;
Da wir in jedem der Fälle die gleiche Aktion ausführen, könnten wir uns auch den Ausgabe-Text liefern lassen&lt;br /&gt;
und ihn im Anschluß ausgeben. Genau dafür bietet das neue {{java|switch}} eine Möglichkeit:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithReturnValue(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Man kann sich vorstellen, daß {{java|switch}} &#039;&#039;immer&#039;&#039; einen Rückgabe-Typ hat, der allerdings in den vorangehenden Beispielen&lt;br /&gt;
{{java|void}} war und daher nicht gespeichert werden konnte. Java prüft in jedem Fall den Typ und meldet Verstöße die durch&lt;br /&gt;
Inkompatibilität entstehen.&lt;br /&gt;
&lt;br /&gt;
Was machen wir nun, wenn nach dem {{java|-&amp;gt;}} kein Ausdruck vom gewünschten Typ kommt, sondern ein ganzer Code-Block?&lt;br /&gt;
Hier hilft das {{java|yield}}. Es kommt am Ende des Code-Blocks und giebt den Wert zurück:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    case CENTIPEDE -&amp;gt; {&lt;br /&gt;
        System.err.println(&amp;quot;lost count&amp;quot;);&lt;br /&gt;
        yield &amp;quot;many legs&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{java|yield}} ist -- entgegen der ersten Vermutung -- &#039;&#039;kein&#039;&#039; keyword, sondern ein &amp;quot;reservierter Identifier&amp;quot;.&lt;br /&gt;
So ist die Anweisung &lt;br /&gt;
{{java|code=&lt;br /&gt;
int yield = 5;&lt;br /&gt;
}}&lt;br /&gt;
durchaus erlaubt. Es erübrigt sich, darauf hinzuweisen diese Verwendung zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
Freundlicherweise darf man das {{java|yield}} auch mit dem {{java|switch}} im alten Stil verwenden.&lt;br /&gt;
Da dabei das {{java|switch}} unmittelbar verlassen wird, spart man sich dabei das {{java|break}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void oldStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        yield &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        yield &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default:&lt;br /&gt;
        yield &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Fazit ==&lt;br /&gt;
&lt;br /&gt;
Das gemeine {{java|switch}} wird durch die Verwendung von {{java|-&amp;gt;}} kompakter und veständlicher.&lt;br /&gt;
Folgt man allerdings der Regel möglichst kleine Methoden zu schreiben, wird man praktisch jedes {{java|witch}}&lt;br /&gt;
in eine eigene Methode auslagern. Die Rückgabe-Notation bietet dann keine nennenswerten Gewinn mehr,&lt;br /&gt;
man spart sich allerdings bei Verwendung von {{java|-&amp;gt;}} das {{java|return}}.&lt;br /&gt;
&lt;br /&gt;
Nichstdestotrotz hilft das Feature dabei, legacy-Code zu optimieren und darüber zu refactorn.&lt;br /&gt;
Dazu schreibt man das {{java|switch}} erst auf die Rückgabe-Notation um und lagert sie dann in eine eigene Methode aus.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=186</id>
		<title>Java 17: Switch</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=186"/>
		<updated>2024-03-28T20:03:03Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
Um die Erwartungen vorab zu dämpfen:&lt;br /&gt;
Auch Java 17 erlaubt nur die aufzählbaren Daten-Type sowie String, aber keine anderne Objekt-Typen.&lt;br /&gt;
Auch führt der Aufruf mit {{java|null}} weiterhin unweigerlich zu einer Null-Pointer-Exception.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir die klassische Anwendung der {{java|switch}}-Kontrollstruktur:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleOhneBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der Aufruf von {{java|oldStyleOhneBreak(Animal.ANT)}} liefert:&lt;br /&gt;
 6 legs&lt;br /&gt;
 strange animal&lt;br /&gt;
Wegen des &amp;quot;fall-through&amp;quot;-Verhaltens (was man berechtigterweise mit &amp;quot;Durchfall&amp;quot; übersetzen kann) werden&lt;br /&gt;
alle nachfolgenden Fälle durchlaufen, sobald der erste Match auftritt. Um das zu verhindern, muß man nach&lt;br /&gt;
jeder {{java|case}}-Anweisung ein {{java|break}} einfügen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleWithBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Das ist viel Code, unübersichtlich, fehleranfällig -- und kontrovers.&lt;br /&gt;
Java 17 bietet nun eine Alternative, bei der der {{java|:}} in der Case-Anweisung durch {{java|-&amp;gt;}}.&lt;br /&gt;
Es muß aber ausdrücklich darauf hingeweisen werden, daß es sich hier um &#039;&#039;&#039;keinen&#039;&#039;&#039; {{lambda}}-Ausdruck handelt.&lt;br /&gt;
Das Ergebnis der ersten Fassung sieht nun so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyle(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE -&amp;gt; System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default -&amp;gt; System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Da für jeden Fall hier nur eine Zeile verwendet wird, ist der gesamte Ausdruck kompakter.&lt;br /&gt;
Das könnte man durchaus auch mit dem klassischen {{java|case}}-Konstrukt hinkriegen.&lt;br /&gt;
&lt;br /&gt;
Überraschender ist aber das Ergebnis, wenn man {{java|newStyle(Animal.ANT)}} ausführt:&lt;br /&gt;
 6 legs&lt;br /&gt;
Das {{java|break}} wird nicht mehr benötigt, der neue Stil hat keine Durchfall-Symptome mehr!&lt;br /&gt;
&lt;br /&gt;
Nach dem {{java|-&amp;gt;}} darf eine beliebige Anweisung kommen.&lt;br /&gt;
Anstelle einer &#039;&#039;einzelnen&#039;&#039; Anweisung ist also auch ein beliebig großer Code-Block erlaubt.&lt;br /&gt;
&lt;br /&gt;
Da wir in jedem der Fälle die gleiche Aktion ausführen, könnten wir uns auch den Ausgabe-Text liefern lassen&lt;br /&gt;
und ihn im Anschluß ausgeben. Genau dafür bietet das neue {{java|switch}} eine Möglichkeit:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithReturnValue(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Man kann sich vorstellen, daß {{java|switch}} &#039;&#039;immer&#039;&#039; einen Rückgabe-Typ hat, der allerdings in den vorangehenden Beispielen&lt;br /&gt;
{{java|void}} war und daher nicht gespeichert werden konnte. Java prüft in jedem Fall den Typ und meldet Verstöße die durch&lt;br /&gt;
Inkompatibilität entstehen.&lt;br /&gt;
&lt;br /&gt;
Was machen wir nun, wenn nach dem {{java|-&amp;gt;}} kein Ausdruck vom gewünschten Typ kommt, sondern ein ganzer Code-Block?&lt;br /&gt;
Hier hilft das {{java|yield}}. Es kommt am Ende des Code-Blocks und giebt den Wert zurück:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    case CENTIPEDE -&amp;gt; {&lt;br /&gt;
        System.err.println(&amp;quot;lost count&amp;quot;);&lt;br /&gt;
        yield &amp;quot;many legs&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{java|yield}} ist -- entgegen der ersten Vermutung -- &#039;&#039;kein&#039;&#039; keyword, sondern ein &amp;quot;reservierter Identifier&amp;quot;.&lt;br /&gt;
So ist die Anweisung &lt;br /&gt;
{{java|code=&lt;br /&gt;
int yield = 5;&lt;br /&gt;
}}&lt;br /&gt;
durchaus erlaubt. Es erübrigt sich, darauf hinzuweisen diese Verwendung zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
Freundlicherweise darf man das {{java|yield}} auch mit dem {{java|switch}} im alten Stil verwenden.&lt;br /&gt;
Da dabei das {{java|switch}} unmittelbar verlassen wird, spart man sich dabei das {{java|break}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void oldStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        yield &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        yield &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default:&lt;br /&gt;
        yield &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Fazit ==&lt;br /&gt;
&lt;br /&gt;
Das gemeine {{java|switch}} wird durch die Verwendung von {{java|-&amp;gt;}} kompakter und veständlicher.&lt;br /&gt;
Folgt man allerdings der Regel möglichst kleine Methoden zu schreiben, wird man praktisch jedes {{java|witch}}&lt;br /&gt;
in eine eigene Methode auslagern. Die Rückgabe-Notation bietet dann keine nennenswerten Gewinn mehr,&lt;br /&gt;
man spart sich allerdings bei Verwendung von {{java|-&amp;gt;}} das {{java|return}}.&lt;br /&gt;
&lt;br /&gt;
Nichstdestotrotz hilft das Feature dabei, legacy-Code zu optimieren und darüber zu refactorn.&lt;br /&gt;
Dazu schreibt man das {{java|switch}} erst auf die Rückgabe-Notation um und lagert sie dann in eine eigene Methode aus.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=185</id>
		<title>Java 17: Switch</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=185"/>
		<updated>2024-03-28T19:59:03Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
Um die Erwartungen vorab zu dämpfen:&lt;br /&gt;
Auch Java 17 erlaubt nur die aufzählbaren Daten-Type sowie String, aber keine anderne Objekt-Typen.&lt;br /&gt;
Auch führt der Aufruf mit {{java|null}} weiterhin unweigerlich zu einer Null-Pointer-Exception.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir die klassische Anwendung der {{java|switch}}-Kontrollstruktur:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleOhneBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der Aufruf von {{java|oldStyleOhneBreak(Animal.ANT)}} liefert:&lt;br /&gt;
 6 legs&lt;br /&gt;
 strange animal&lt;br /&gt;
Wegen des &amp;quot;fall-through&amp;quot;-Verhaltens (was man berechtigterweise mit &amp;quot;Durchfall&amp;quot; übersetzen kann) werden&lt;br /&gt;
alle nachfolgenden Fälle durchlaufen, sobald der erste Match auftritt. Um das zu verhindern, muß man nach&lt;br /&gt;
jeder {{java|case}}-Anweisung ein {{java|break}} einfügen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleWithBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Das ist viel Code, unübersichtlich, fehleranfällig -- und kontrovers.&lt;br /&gt;
Java 17 bietet nun eine Alternative, bei der der {{java|:}} in der Case-Anweisung durch {{java|-&amp;gt;}}.&lt;br /&gt;
Es muß aber ausdrücklich darauf hingeweisen werden, daß es sich hier um &#039;&#039;&#039;keinen&#039;&#039;&#039; {{lambda}}-Ausdruck handelt.&lt;br /&gt;
Das Ergebnis der ersten Fassung sieht nun so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyle(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE -&amp;gt; System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default -&amp;gt; System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Da für jeden Fall hier nur eine Zeile verwendet wird, ist der gesamte Ausdruck kompakter.&lt;br /&gt;
Das könnte man durchaus auch mit dem klassischen {{java|case}}-Konstrukt hinkriegen.&lt;br /&gt;
&lt;br /&gt;
Überraschender ist aber das Ergebnis, wenn man {{java|newStyle(Animal.ANT)}} ausführt:&lt;br /&gt;
 6 legs&lt;br /&gt;
Das {{java|break}} wird nicht mehr benötigt, der neue Stil hat keine Durchfall-Symptome mehr!&lt;br /&gt;
&lt;br /&gt;
Nach dem {{java|-&amp;gt;}} darf eine beliebige Anweisung kommen.&lt;br /&gt;
Anstelle einer &#039;&#039;einzelnen&#039;&#039; Anweisung ist also auch ein beliebig großer Code-Block erlaubt.&lt;br /&gt;
&lt;br /&gt;
Da wir in jedem der Fälle die gleiche Aktion ausführen, könnten wir uns auch den Ausgabe-Text liefern lassen&lt;br /&gt;
und ihn im Anschluß ausgeben. Genau dafür bietet das neue switch eine Möglichkeit:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithReturnValue(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Man kann sich vorstellen, daß switch &#039;&#039;immer&#039;&#039; einen Rückgabe-Typ hat, der allerdings in den vorangehenden Beispielen&lt;br /&gt;
{{java|void}} war und daher nicht gespeichert werden konnte. Java prüft in jedem Fall den typ und meldet Verstöße die durch&lt;br /&gt;
Inkompatibilität entstehen.&lt;br /&gt;
&lt;br /&gt;
Was machen wir nun, wenn nach dem {{java|-&amp;gt;}} kein Ausdruck vom gewünschten Typ kommt, sondern ein ganzer Code-Block?&lt;br /&gt;
Hier hilft das {{java|yield}}. Es kommt am Ende des Code-Blocks und giebt den Wert zurück:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    case CENTIPEDE -&amp;gt; {&lt;br /&gt;
        System.err.println(&amp;quot;lost count&amp;quot;);&lt;br /&gt;
        yield &amp;quot;many legs&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{java|yield}} ist -- entgegen der ersten Vermutung -- &#039;&#039;kein&#039;&#039; keyword, sondern ein &amp;quot;reservierter Identifier&amp;quot;.&lt;br /&gt;
So ist die Anweisung &lt;br /&gt;
{{java|code=&lt;br /&gt;
int yield = 5;&lt;br /&gt;
}}&lt;br /&gt;
duirchaus erlaubt. Es erübrigt sich, darauf hinzuweisen diese Verwendung zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
Freundlicherweise darf man das {{java|yield}} auch mit dem {{java|switch}} im alten Stil verwenden.&lt;br /&gt;
Da dabei das {{java|switch}} unmittelbar verlassen wird, spart man sich dabei das {{java|break}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void oldStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        yield &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        yield &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default:&lt;br /&gt;
        yield &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Fazit ==&lt;br /&gt;
&lt;br /&gt;
Das gemeine {{java|switch}} wird durch die Verwendung von {{java|-&amp;gt;}} kompakter und veständlicher.&lt;br /&gt;
Folgt man allerdings der Regel möglichst kleine Methoden zu schreiben, wird man praktisch jedes {{java|witch}}&lt;br /&gt;
in eine eigene Methode auslagern. Die Rückgabe-Notation bietet dann keine nennenswerten Gewinn mehr.&lt;br /&gt;
&lt;br /&gt;
Nichstdestotrotz hilft das Feature dabei, legacy-Code zu optimieren und darüber zu refactorn.&lt;br /&gt;
Dazu schreibt man das {{java|switch}} erst auf die Rückgabe-Notation um und lagert sie dann in eine eigene Methode aus.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=184</id>
		<title>Java 17: Switch</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=184"/>
		<updated>2024-03-28T19:57:55Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
Um die Erwartungen vorab zu dämpfen:&lt;br /&gt;
Auch Java 17 erlaubt nur die aufzählbaren Daten-Type sowie String, aber keine anderne Objekt-Typen.&lt;br /&gt;
Auch führt der Aufruf mit {{java|null}} weiterhin unweigerlich zu einer Null-Pointer-Exception.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir die klassische Anwendung der {{java|switch}}-Kontrollstruktur:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleOhneBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der Aufruf von {{java|oldStyleOhneBreak(Animal.ANT)}} liefert:&lt;br /&gt;
 6 legs&lt;br /&gt;
 strange animal&lt;br /&gt;
Wegen des &amp;quot;fall-through&amp;quot;-Verhaltens (was man berechtigterweise mit &amp;quot;Durchfall&amp;quot; übersetzen kann) werden&lt;br /&gt;
alle nachfolgenden Fälle durchlaufen, sobald der erste Match auftritt. Um das zu verhindern, muß man nach&lt;br /&gt;
jeder {{java|case}}-Anweisung ein {{java|break}} einfügen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleWithBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Das ist viel Code, unübersichtlich, fehleranfällig -- und kontrovers.&lt;br /&gt;
Java 17 bietet nun eine Alternative, bei der der {{java|:}} in der Case-Anweisung durch {{java|-&amp;gt;}}.&lt;br /&gt;
Es muß aber ausdrücklich darauf hingeweisen werden, daß es sich hier um &#039;&#039;&#039;keinen&#039;&#039;&#039; {{lambda}}-Ausdruck handelt.&lt;br /&gt;
Das Ergebnis der ersten Fassung sieht nun so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyle(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE -&amp;gt; System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default -&amp;gt; System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Da für jeden Fall hier nur eine Zeile verwendet wird, ist der gesamte Ausdruck kompakter.&lt;br /&gt;
Das könnte man durchaus auch mit dem klassischen {{java|case}}-Konstrukt hinkriegen.&lt;br /&gt;
&lt;br /&gt;
Überraschender ist aber das Ergebnis, wenn man {{java|newStyle(Animal.ANT)}} ausführt:&lt;br /&gt;
 6 legs&lt;br /&gt;
Das {{java|break}} wird nicht mehr benötigt, der neue Stil hat keine Durchfall-Symptome mehr!&lt;br /&gt;
&lt;br /&gt;
Nach dem {{java|-&amp;gt;}} darf eine beliebige Anweisung kommen.&lt;br /&gt;
Anstelle einer &#039;&#039;einzelnen&#039;&#039; Anweisung ist also auch ein beliebig großer Code-Block erlaubt.&lt;br /&gt;
&lt;br /&gt;
Da wir in jedem der Fälle die gleiche Aktion ausführen, könnten wir uns auch den Ausgabe-Text liefern lassen&lt;br /&gt;
und ihn im Anschluß ausgeben. Genau dafür bietet das neue switch eine Möglichkeit:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithReturnValue(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Man kann sich vorstellen, daß switch &#039;&#039;immer&#039;&#039; einen Rückgabe-Typ hat, der allerdings in den vorangehenden Beispielen&lt;br /&gt;
{{java|void}} war und daher nicht gespeichert werden konnte. Java prüft in jedem Fall den typ und meldet Verstöße die durch&lt;br /&gt;
Inkompatibilität entstehen.&lt;br /&gt;
&lt;br /&gt;
Was machen wir nun, wenn nach dem {{java|-&amp;gt;}} kein Ausdruck vom gewünschten Typ kommt, sondern ein ganzer Code-Block?&lt;br /&gt;
Hier hilft das {{java|yield}}. Es kommt am Ende des Code-Blocks und giebt den Wert zurück:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    case CENTIPEDE -&amp;gt; {&lt;br /&gt;
        System.err.println(&amp;quot;lost count&amp;quot;);&lt;br /&gt;
        yield &amp;quot;many legs&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{java|yield}} ist -- entgegen der ersten Vermutung -- &#039;&#039;kein&#039;&#039; keyword, sondern ein &amp;quot;reservierter Identifier&amp;quot;.&lt;br /&gt;
So ist die Anweisung &lt;br /&gt;
{{java|code=&lt;br /&gt;
int yield = 5;&lt;br /&gt;
}}&lt;br /&gt;
duirchaus erlaubt. Es erübrigt sich, darauf hinzuweisen diese Verwendung zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
Freundlicherweise darf man das {{java|yield}} auch mit dem {{java|switch}} im alten Stil verwenden.&lt;br /&gt;
Da dabei das {{java|switch}} unmittelbar verlassen wird, spart man sich dabei das {{break}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void oldStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        yield &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        yield &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default:&lt;br /&gt;
        yield &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Fazit ==&lt;br /&gt;
&lt;br /&gt;
Das gemeine {{java|switch}} wird durch die Verwendung von {{java|-&amp;gt;}} kompakter und veständlicher.&lt;br /&gt;
Folgt man allerdings der Regel möglichst kleine Methoden zu schreiben, wird man praktisch jedes {{java|witch}}&lt;br /&gt;
in eine eigene Methode auslagern. Die Rückgabe-Notation bietet dann keine nennenswerten Gewinn mehr.&lt;br /&gt;
&lt;br /&gt;
Nichstdestotrotz hilft das Feature dabei, legacy-Code zu optimieren und darüber zu refactorn.&lt;br /&gt;
Dazu schreibt man das {{java|switch}} erst auf die Rückgabe-Notation um und lagert sie dann in eine eigene Methode aus.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Parametrisierte_Tests&amp;diff=183</id>
		<title>Parametrisierte Tests</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Parametrisierte_Tests&amp;diff=183"/>
		<updated>2024-03-19T19:19:52Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Und was ist mit null? */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
[[Category:junit]]&lt;br /&gt;
Ein einzelner Unit-Tests befaßt sich mit einem einzelnen Test-Fall und hat im Regelfall eine einzelne Assertion.&lt;br /&gt;
Dieses einfache Beispiel testet die korrekte Konvertierung von Datum-Strings in ein Date-Objekt. Die drei Assertions&lt;br /&gt;
prüfen hier zusammen, ob das Datum korrekt ist:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@Test&lt;br /&gt;
public void toDateLiefertKorrektesDatum() {&lt;br /&gt;
    Date convertedDate = Convert.toDate(&amp;quot;01.5.1985&amp;quot;);&lt;br /&gt;
    assertThat(convertedDate).hasDayOfMonth(1);&lt;br /&gt;
    assertThat(convertedDate).hasMonth(5);&lt;br /&gt;
    assertThat(convertedDate).hasYear(1985);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Nun soll er Konverter mit unterschiedlichen Datums-Angaben umgehen: Mit und ohne führende Nullen, mit und&lt;br /&gt;
ohne Jahrhundert, vielleicht soll auch ein Minuszeichen anstelle des Punkts erlaubt sein. Für jeden Testfall kann&lt;br /&gt;
man nun die Test-Methode kopieren und entsprechend anpassen. Die Folgen sind klar: jede Menge Test-Code,&lt;br /&gt;
sinkende Übersichtlichkeit und für jede neue Test-Methode braucht es einen neuen Namen. Das DRY-Prinzip soll&lt;br /&gt;
auch für Test-Code gelten.&lt;br /&gt;
&lt;br /&gt;
Eine wesentliche Bereicherung von JUnit-5 ist die Unterstützung von Parameter-gesteuerten Test-Methoden die&lt;br /&gt;
weit über das hinausgeht was JUnit-4 oder Test-NG zu bieten hatten. Eine Vielzahl von Test-Situationen läßt sich&lt;br /&gt;
damit abdecken und vor allem eindampfen.&lt;br /&gt;
==Eine Liste einzelner Parameter==&lt;br /&gt;
Betrachten wir –- angelehnt an das einleitende Beispiel -– die einfachste Situation: Einen Testfall soll mit einer Reihe&lt;br /&gt;
einzelner Strings aufgerufen werden. Dazu parametrisieren wir zunächst die Test-Methode und ziehen den Datum-String als Parameter heraus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void toDateLiefertKorrektesDatum(String datum) {&lt;br /&gt;
    Date convertedDate = Convert.toDate(datum);&lt;br /&gt;
    assertThat(convertedDate).hasDayOfMonth(1);&lt;br /&gt;
    assertThat(convertedDate).hasMonth(5);&lt;br /&gt;
    assertThat(convertedDate).hasYear(1985);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Dann legen wir die Datum-Strings fest mit denen getestet werden soll:&lt;br /&gt;
{{java|&amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot;}}&lt;br /&gt;
Um die neue Test-Methode mit den Test-Fälle zu verknüpfen verwenden wir JUnit5-Annotations und setzen sie&lt;br /&gt;
über unsere parametrisierte Test-Methode:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@ValueSource(strings = { &amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot; })&lt;br /&gt;
}}&lt;br /&gt;
Die erste Annotation ersetzt die @Test-Annotation und macht die Methode zum (parametrisierten) Test.&lt;br /&gt;
Die zweite Annotation legt die Quelle der zu verwendenden Werte fest.&lt;br /&gt;
In diesem Falle ist dies eine Liste von Strings. Der Test wird bei der&lt;br /&gt;
Ausführung für jeden String einmal aufgerufen, wobei der jeweilige String als Argument übergeben wird.&lt;br /&gt;
Anstelle von Strings sind hier auch alle numerischen, primitiven Typen int, long, float und einiges mehr erlaubt.&lt;br /&gt;
Die Anntotations-Parameter kann man in Eclipse mit Code-Assist erkunden oder in der JUnit5-Doku nachlesen.&lt;br /&gt;
=== Und was ist mit null? ===&lt;br /&gt;
Die eben vorgestellte Werte-Liste hat einen kleinen Haken: Es ist nicht möglich, den Wert null als Argument zu&lt;br /&gt;
verwenden. Um einen Testfall für null zu erzeugen, kann man nun freilich eine neue Test-Methode erstellen und&lt;br /&gt;
null separat in diesem Test prüfen. Man kann dem Test aber auch zusätzlich die Annotation {{java|@NullSource}}&lt;br /&gt;
hinzufügen. JUnit5 erzeugt dann einen zusätzlichen Testfall für null:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@NullSource&lt;br /&gt;
@ValueSource(strings = { &amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot; })&lt;br /&gt;
public void toDateLiefertKorrektesDatum(String datum) {&lt;br /&gt;
    // hier kommt der Test-Code hin...&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Unterstützt wird {{java|@NullSource}} ab Version 5.4&lt;br /&gt;
&lt;br /&gt;
== Mehrere Parameter für die Test-Methode ==&lt;br /&gt;
Dieser Abschnitt beschreibt die einfachste Variante, weitere Möglichkeiten werden [[Testdaten-Provider|hier]] beschrieben.&lt;br /&gt;
&lt;br /&gt;
Für viele Unit-Tests reicht die Extraktion eines einzelnen Parameters nicht aus. Im folgenden Beispiel wird die&lt;br /&gt;
Qualität von Passworten getestet. Das Wort &amp;quot;Hallo&amp;quot; zum Beispiel wird abgewiesen, weil es nur Buchstaben enthält:&lt;br /&gt;
 public void passwortWirdNichtAkzeptiert() {&lt;br /&gt;
     assertThat(policy.validate(&amp;quot;Hallo&amp;quot;)).as(&amp;quot;nur Buchstaben&amp;quot;).isFalse();&lt;br /&gt;
 }&lt;br /&gt;
Wofür die Parameter in der Test-Methode verwendet werden, spielen keine Rolle, es geht nur darum, den Test&lt;br /&gt;
mehrfach aufzurufen und dabei &#039;&#039;mehrere&#039;&#039; Parameter zu übergeben. Im vorliegenden Falle möchten wir&lt;br /&gt;
unterschiedliche Passwort-Kandidaten testen und dabei jeden Test mit einer Beschreibung versehen, der Auskunft&lt;br /&gt;
gibt warum das Wort nicht als Passwort akzeptiert wird. Die Test-Methode sieht nun so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void passwortWirdNichtAkzeptiert(String passwort, String grund) {&lt;br /&gt;
    assertThat(policy.validate(passwort)).as(grund).isFalse();&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Für die Erzeugung der Test-Daten schreiben wir diesmal eine weitere Methode.&lt;br /&gt;
Sie erzeugt einen Stream von Arguments-Objekten von denen jedes die Daten für &#039;&#039;einen&#039;&#039; Test-Aufruf enthält:&lt;br /&gt;
{{java|code=&lt;br /&gt;
static Stream&amp;lt;Arguments&amp;gt; pwdWirdNichtAkzeptiert() {&lt;br /&gt;
    return Stream.of(&lt;br /&gt;
        Arguments.of(&amp;quot;Hallo&amp;quot;, &amp;quot;nur Buchstaben&amp;quot;),&lt;br /&gt;
        Arguments.of(&amp;quot;1234567&amp;quot;, &amp;quot;nur Ziffern&amp;quot;),&lt;br /&gt;
        Arguments.of(&amp;quot;!%#&amp;amp;/()&amp;quot;, &amp;quot;nur Sonderzeichen&amp;quot;)&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Die Methode für die Testdaten-Erzeugung muß folgende Eigenschaften haben:&lt;br /&gt;
*sie muß static deklariert sein&lt;br /&gt;
*sie muß zur Test-Klasse gehören&lt;br /&gt;
*sie darf keinen Parameter haben und muß einen Stream von Arguments-Objekten liefern&lt;br /&gt;
*sie darf in beliebiger Sichtbarkeit deklariert werden&lt;br /&gt;
Die Methode darf zwar private deklariert werden, Java wird sich aber darüber beschweren, daß die Methode&lt;br /&gt;
nirgends verwendet wird. Warum das so ist, erfahren wir weiter unten.&lt;br /&gt;
Am einfachsten deklariert man sie daher package visible.&lt;br /&gt;
&lt;br /&gt;
Die Klasse&lt;br /&gt;
{{java|org.junit.jupiter.params.provider.Arguments}}&lt;br /&gt;
ist ein Container, der eine Reihe von Werten beliebigen Typs (mit Ausnahme von {{Lambda}}-Ausdrücken) in fester&lt;br /&gt;
Reihenfolge aufnimmt. JUnit5 mappt die Werte der {{java|Arguments}}-Objekte auf die Parameter der Test-Methode. Das&lt;br /&gt;
geschieht allerdings erst zur Laufzeit, der Entwickler ist daher selbst dafür verantwortlich die Typen zwischen&lt;br /&gt;
Testdaten-Provider und Test-Methode in Übereinstimmung zu halten.&lt;br /&gt;
&lt;br /&gt;
Wir bringen nun Test-Methode und Testdaten-Provider-Methode zusammen. Das geschieht mithilfe folgender JUnit5-Annotationen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@MethodSource(&amp;quot;pwdWirdNichtAkzeptiert&amp;quot;)&lt;br /&gt;
}}&lt;br /&gt;
Die erste Annotation kennen wir schon aus dem vorangegangenen Abschnitt. Die zweite Annotation weist die Test-Methode an&lt;br /&gt;
die Testdaten aus der Methode &amp;quot;pwdWirdNichtAkzeptiert&amp;quot; zu beziehen. Der Name der Methode wird als String angegeben.&lt;br /&gt;
Das bedeutet, daß der Entwickler für die korrekte Schreibweise verantwortlich ist, Fehler treten auch hier erst zur Laufzeit auf.&lt;br /&gt;
Hat die Test-Daten-Methode den gleichen Namen wie die Test-Methode kann sie in&lt;br /&gt;
der Annotation auch weggelassen werden. Die Annotation selbst hingegen kann &#039;&#039;nicht&#039;&#039; weggelassen werden.&lt;br /&gt;
Da die Methode nur über den Namen referenziert wird, muß der Compiler tatsächlich annehmen,&lt;br /&gt;
daß die Method nicht verwendet wird wenn sie als private deklariert wurde.&lt;br /&gt;
=== Lambda-Ausdrücke ===&lt;br /&gt;
&lt;br /&gt;
==Weitere Test-Daten-Provider==&lt;br /&gt;
JUnit5 unterstützt noch eine Reihe weiterer Möglichkeiten, Testdaten für parametrisierte Tests zur Verfügung zu&lt;br /&gt;
stellen:&lt;br /&gt;
*Java-enums&lt;br /&gt;
*CSV-Dateien&lt;br /&gt;
*Daten im CSV-Format&lt;br /&gt;
*separate Klassen&lt;br /&gt;
==Enums==&lt;br /&gt;
Eine besondere Unterstützung bei der Erstellung parametrisierter Tests erfahren die Java-enums. Grundsätzlich&lt;br /&gt;
erfolgt die Parametrisierung wie dies hier am Beispiel von String-Argumenten beschrieben wurde. Auf die&lt;br /&gt;
spezifischen Eigenschaften von enums und ihrem besonderen Wert für Unit-Tests wird hier eingegangen.&lt;br /&gt;
Betrachten wir ein enum das Versandwege beschreibt:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    enum Versandweg {&lt;br /&gt;
        E_MAIL,&lt;br /&gt;
        SMS,&lt;br /&gt;
        POST&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
und die zu testende Methode die eine TAN über einen Versandweg verschickt:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public class Versender {&lt;br /&gt;
    Response sendTan(Versandweg weg) {&lt;br /&gt;
        ...&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
===Alle Ausprägungen testen===&lt;br /&gt;
Wir können nun für jeden Versandweg eine Test-Methode schreiben. Das geht auch einfacher, wenn wir immer das&lt;br /&gt;
gleiche Ergebnis erwarten:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 @ParameterizedTest&lt;br /&gt;
 @EnumSource(value=Versandweg.class)&lt;br /&gt;
 void verwandWegLiefertOk(Versandweg weg) {&lt;br /&gt;
    Assertions.assertThat(new Versender().sendTan(weg)).isEqualTo(Response.OK);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Die erste Annotation weist die Methode als parametrisierten Test aus. Die zweite Annotation gibt an, welches enum&lt;br /&gt;
für den Test zu verwenden ist. Die Test-Methode selbst muß ein Argument vom Typ des Enums akzeptieren.&lt;br /&gt;
Die parametrisierte Version ist nicht nur kompakter. Wird das enum um weitere Ausprägungen ergänzt, werden&lt;br /&gt;
automatisch Test dafür generiert. Ob das Ergebnis tatsächlich der gewünschten Anforderung entspricht kann JUnit&lt;br /&gt;
natürlich nicht vorhersehen, aber die neue enum-Ausprägung wird zumindest betrachtet und läuft günstigenfalls&lt;br /&gt;
auf einen Fehler.&lt;br /&gt;
=== Einzelne Ausprägungen testen ===&lt;br /&gt;
Möchte man nicht alle Ausprägungen testen sondern nur ganz bestimmte, kann man das der Annotation mitgeben.&lt;br /&gt;
dafür gibt es zwei Modes: &#039;&#039;einschließend&#039;&#039; und &#039;&#039;ausschließend&#039;&#039;.&lt;br /&gt;
Möchten wir etwa nur die Versandwege eMail und SMS testen, können wir die Annotation so schreiben (der ganze Rest bleibt gleich):&lt;br /&gt;
{{java|code=@EnumSource(value = Versandweg.class, mode = Mode.INCLUDE, names = { &amp;quot;E_MAIL&amp;quot;, &amp;quot;SMS&amp;quot; })}}&lt;br /&gt;
Der Parameter {{java|mod}} gibt an, daß nur die angegebenen Ausprägungen getestet werden sollen. Da &amp;quot;Include&amp;quot; der&lt;br /&gt;
default ist, kann de Mo in diesem Falle auch weggelassen werden. Der Parameter {{java|names}} ist eine Liste von enum-Ausprägung-Namen die als Strings angegeben werden.&lt;br /&gt;
Man kann das vorgehen auch umdrehen un den Versandweg &amp;quot;POST&amp;quot; – als einzigen nicht-elektronischen Weg&lt;br /&gt;
ausschließen. Die Annotation sieht dann so aus:&lt;br /&gt;
{{java|code=@EnumSource(value = Versandweg.class, mode = Mode.EXCLUDE, names = { &amp;quot;POST&amp;quot; })}}&lt;br /&gt;
Der {{java|mode}}-Parameter hat nun den Wert {{java|EXCLUDE}} und darf natürlich nicht weggelassen werden. Der Parameter&lt;br /&gt;
{{java|names}} ist wieder eine Liste von enum-Ausprägung-Namen die hier aus einem einzigen Wert besteht.&lt;br /&gt;
In beiden Fällen ist der Entwickler für die korrekte Schreibweise der Namen der enum-Ausprägungen&lt;br /&gt;
verantwortlich. Stimmt sie nicht überein, giebt&#039;s einen Laufzeitfehler bei der Test-Ausführung.&lt;br /&gt;
Während bei &amp;quot;INCLUDE&amp;quot; nur so viel Tests erzeugt werden, wie enum-Ausprägungen spezifiziert wurden, werden bei&lt;br /&gt;
&amp;quot;EXCLUDE&amp;quot; Tests für alle Ausprägungen erzeugt die nicht angegeben sind. Wird das enum um Ausprägungen&lt;br /&gt;
erweitert, dann werden im EXCLUDE-Falle neue Tests generiert, im INCLUDE-Falle nicht.&lt;br /&gt;
&lt;br /&gt;
===Pattern-Matching===&lt;br /&gt;
Mit den beiden Modes MATCH_ALL und MATCH_ANY können die Namen von enum-Ausprägungen mit Hilfe von&lt;br /&gt;
regulären Ausdrücken spezifiziert werden. Dieses Vorgehen ist jedoch problematisch und soll hier nicht weiter&lt;br /&gt;
erörtert werden. Macht man bei Definition der Ausdrücke Fehler, kann es beispielsweise passieren, daß&lt;br /&gt;
Ausprägungen ausgelassen werden und für diese dann keine Tests erzeugt werden. Das fällt nur auf wenn die TestAusführung manuell überprüft wird.&lt;br /&gt;
===Test-Fälle als Enumerationen===&lt;br /&gt;
bei der Verwendung von enum-Sources ist man nicht auf &amp;quot;produktive&amp;quot; enums beschränkt. Man kann auch Test-Situationen über enums definieren und diese&lt;br /&gt;
enums dann verwenden um parametrisierte Tests zu füttern. Man kann zum Beispiel für die Test-Klasse enum &amp;quot;Kunde&amp;quot; definieren, dessen Ausprägungen&lt;br /&gt;
jeweils einzelne Test-Konstellationen beschreiben. Damit lassen sich parametrisierte Tests definieren, die alle oder ausgewählte Konstellationen testen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 @ParameterizedTest&lt;br /&gt;
 @EnumSource(value = Kunde.class, names = { &amp;quot;MIT_KDNR&amp;quot;, &amp;quot;MIT_IHNR&amp;quot;, &amp;quot;MIT_KDNR_UND_IHNR&amp;quot; })&lt;br /&gt;
 void darfElektronischeDokumentEinstellungSehen(Kunde kunde) {&lt;br /&gt;
    assertThat(verwalter(kunde).darfElectronicDocumentsSehen()).isTrue();&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
In diesem Beispiel wurde Kunden konfiguriert die ein Kunden- oder Inhabernummer oder beides haben. Jeder der&lt;br /&gt;
Kunden muß seine elektronischen Dokumente sehen dürfen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Parametrisierte_Tests&amp;diff=182</id>
		<title>Parametrisierte Tests</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Parametrisierte_Tests&amp;diff=182"/>
		<updated>2024-03-19T19:17:11Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Mehrere Parameter für die Test-Methode */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
[[Category:junit]]&lt;br /&gt;
Ein einzelner Unit-Tests befaßt sich mit einem einzelnen Test-Fall und hat im Regelfall eine einzelne Assertion.&lt;br /&gt;
Dieses einfache Beispiel testet die korrekte Konvertierung von Datum-Strings in ein Date-Objekt. Die drei Assertions&lt;br /&gt;
prüfen hier zusammen, ob das Datum korrekt ist:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@Test&lt;br /&gt;
public void toDateLiefertKorrektesDatum() {&lt;br /&gt;
    Date convertedDate = Convert.toDate(&amp;quot;01.5.1985&amp;quot;);&lt;br /&gt;
    assertThat(convertedDate).hasDayOfMonth(1);&lt;br /&gt;
    assertThat(convertedDate).hasMonth(5);&lt;br /&gt;
    assertThat(convertedDate).hasYear(1985);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Nun soll er Konverter mit unterschiedlichen Datums-Angaben umgehen: Mit und ohne führende Nullen, mit und&lt;br /&gt;
ohne Jahrhundert, vielleicht soll auch ein Minuszeichen anstelle des Punkts erlaubt sein. Für jeden Testfall kann&lt;br /&gt;
man nun die Test-Methode kopieren und entsprechend anpassen. Die Folgen sind klar: jede Menge Test-Code,&lt;br /&gt;
sinkende Übersichtlichkeit und für jede neue Test-Methode braucht es einen neuen Namen. Das DRY-Prinzip soll&lt;br /&gt;
auch für Test-Code gelten.&lt;br /&gt;
&lt;br /&gt;
Eine wesentliche Bereicherung von JUnit-5 ist die Unterstützung von Parameter-gesteuerten Test-Methoden die&lt;br /&gt;
weit über das hinausgeht was JUnit-4 oder Test-NG zu bieten hatten. Eine Vielzahl von Test-Situationen läßt sich&lt;br /&gt;
damit abdecken und vor allem eindampfen.&lt;br /&gt;
==Eine Liste einzelner Parameter==&lt;br /&gt;
Betrachten wir –- angelehnt an das einleitende Beispiel -– die einfachste Situation: Einen Testfall soll mit einer Reihe&lt;br /&gt;
einzelner Strings aufgerufen werden. Dazu parametrisieren wir zunächst die Test-Methode und ziehen den Datum-String als Parameter heraus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void toDateLiefertKorrektesDatum(String datum) {&lt;br /&gt;
    Date convertedDate = Convert.toDate(datum);&lt;br /&gt;
    assertThat(convertedDate).hasDayOfMonth(1);&lt;br /&gt;
    assertThat(convertedDate).hasMonth(5);&lt;br /&gt;
    assertThat(convertedDate).hasYear(1985);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Dann legen wir die Datum-Strings fest mit denen getestet werden soll:&lt;br /&gt;
{{java|&amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot;}}&lt;br /&gt;
Um die neue Test-Methode mit den Test-Fälle zu verknüpfen verwenden wir JUnit5-Annotations und setzen sie&lt;br /&gt;
über unsere parametrisierte Test-Methode:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@ValueSource(strings = { &amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot; })&lt;br /&gt;
}}&lt;br /&gt;
Die erste Annotation ersetzt die @Test-Annotation und macht die Methode zum (parametrisierten) Test.&lt;br /&gt;
Die zweite Annotation legt die Quelle der zu verwendenden Werte fest.&lt;br /&gt;
In diesem Falle ist dies eine Liste von Strings. Der Test wird bei der&lt;br /&gt;
Ausführung für jeden String einmal aufgerufen, wobei der jeweilige String als Argument übergeben wird.&lt;br /&gt;
Anstelle von Strings sind hier auch alle numerischen, primitiven Typen int, long, float und einiges mehr erlaubt.&lt;br /&gt;
Die Anntotations-Parameter kann man in Eclipse mit Code-Assist erkunden oder in der JUnit5-Doku nachlesen.&lt;br /&gt;
===Und was ist mit null?===&lt;br /&gt;
Die eben vorgestellte Werte-Liste hat einen kleinen Haken: Es ist nicht möglich, den Wert null als Argument zu&lt;br /&gt;
verwenden. Um einen Testfall für null zu erzeugen, kann man nun freilich eine neue Test-Methode erstellen und&lt;br /&gt;
null separat in diesem Test prüfen. Man kann dem Test aber auch zusätzlich die Annotation @NullSource&lt;br /&gt;
hinzufügen. JUnit5 erzeugt dann einen zusätzlichen Testfall für null:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@NullSource&lt;br /&gt;
@ValueSource(strings = { &amp;quot;1.5.1985&amp;quot;, &amp;quot;01.5.1985&amp;quot;, &amp;quot;1.05.1985&amp;quot;, &amp;quot;01.05.1985&amp;quot; })&lt;br /&gt;
public void toDateLiefertKorrektesDatum(String datum) {&lt;br /&gt;
    // hier kommt der Test-Code hin...&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Unterstützt wird {{java|@NullSource}} ab Version 5.4&lt;br /&gt;
&lt;br /&gt;
== Mehrere Parameter für die Test-Methode ==&lt;br /&gt;
Dieser Abschnitt beschreibt die einfachste Variante, weitere Möglichkeiten werden [[Testdaten-Provider|hier]] beschrieben.&lt;br /&gt;
&lt;br /&gt;
Für viele Unit-Tests reicht die Extraktion eines einzelnen Parameters nicht aus. Im folgenden Beispiel wird die&lt;br /&gt;
Qualität von Passworten getestet. Das Wort &amp;quot;Hallo&amp;quot; zum Beispiel wird abgewiesen, weil es nur Buchstaben enthält:&lt;br /&gt;
 public void passwortWirdNichtAkzeptiert() {&lt;br /&gt;
     assertThat(policy.validate(&amp;quot;Hallo&amp;quot;)).as(&amp;quot;nur Buchstaben&amp;quot;).isFalse();&lt;br /&gt;
 }&lt;br /&gt;
Wofür die Parameter in der Test-Methode verwendet werden, spielen keine Rolle, es geht nur darum, den Test&lt;br /&gt;
mehrfach aufzurufen und dabei &#039;&#039;mehrere&#039;&#039; Parameter zu übergeben. Im vorliegenden Falle möchten wir&lt;br /&gt;
unterschiedliche Passwort-Kandidaten testen und dabei jeden Test mit einer Beschreibung versehen, der Auskunft&lt;br /&gt;
gibt warum das Wort nicht als Passwort akzeptiert wird. Die Test-Methode sieht nun so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void passwortWirdNichtAkzeptiert(String passwort, String grund) {&lt;br /&gt;
    assertThat(policy.validate(passwort)).as(grund).isFalse();&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Für die Erzeugung der Test-Daten schreiben wir diesmal eine weitere Methode.&lt;br /&gt;
Sie erzeugt einen Stream von Arguments-Objekten von denen jedes die Daten für &#039;&#039;einen&#039;&#039; Test-Aufruf enthält:&lt;br /&gt;
{{java|code=&lt;br /&gt;
static Stream&amp;lt;Arguments&amp;gt; pwdWirdNichtAkzeptiert() {&lt;br /&gt;
    return Stream.of(&lt;br /&gt;
        Arguments.of(&amp;quot;Hallo&amp;quot;, &amp;quot;nur Buchstaben&amp;quot;),&lt;br /&gt;
        Arguments.of(&amp;quot;1234567&amp;quot;, &amp;quot;nur Ziffern&amp;quot;),&lt;br /&gt;
        Arguments.of(&amp;quot;!%#&amp;amp;/()&amp;quot;, &amp;quot;nur Sonderzeichen&amp;quot;)&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Die Methode für die Testdaten-Erzeugung muß folgende Eigenschaften haben:&lt;br /&gt;
*sie muß static deklariert sein&lt;br /&gt;
*sie muß zur Test-Klasse gehören&lt;br /&gt;
*sie darf keinen Parameter haben und muß einen Stream von Arguments-Objekten liefern&lt;br /&gt;
*sie darf in beliebiger Sichtbarkeit deklariert werden&lt;br /&gt;
Die Methode darf zwar private deklariert werden, Java wird sich aber darüber beschweren, daß die Methode&lt;br /&gt;
nirgends verwendet wird. Warum das so ist, erfahren wir weiter unten.&lt;br /&gt;
Am einfachsten deklariert man sie daher package visible.&lt;br /&gt;
&lt;br /&gt;
Die Klasse&lt;br /&gt;
{{java|org.junit.jupiter.params.provider.Arguments}}&lt;br /&gt;
ist ein Container, der eine Reihe von Werten beliebigen Typs (mit Ausnahme von {{Lambda}}-Ausdrücken) in fester&lt;br /&gt;
Reihenfolge aufnimmt. JUnit5 mappt die Werte der {{java|Arguments}}-Objekte auf die Parameter der Test-Methode. Das&lt;br /&gt;
geschieht allerdings erst zur Laufzeit, der Entwickler ist daher selbst dafür verantwortlich die Typen zwischen&lt;br /&gt;
Testdaten-Provider und Test-Methode in Übereinstimmung zu halten.&lt;br /&gt;
&lt;br /&gt;
Wir bringen nun Test-Methode und Testdaten-Provider-Methode zusammen. Das geschieht mithilfe folgender JUnit5-Annotationen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
@MethodSource(&amp;quot;pwdWirdNichtAkzeptiert&amp;quot;)&lt;br /&gt;
}}&lt;br /&gt;
Die erste Annotation kennen wir schon aus dem vorangegangenen Abschnitt. Die zweite Annotation weist die Test-Methode an&lt;br /&gt;
die Testdaten aus der Methode &amp;quot;pwdWirdNichtAkzeptiert&amp;quot; zu beziehen. Der Name der Methode wird als String angegeben.&lt;br /&gt;
Das bedeutet, daß der Entwickler für die korrekte Schreibweise verantwortlich ist, Fehler treten auch hier erst zur Laufzeit auf.&lt;br /&gt;
Hat die Test-Daten-Methode den gleichen Namen wie die Test-Methode kann sie in&lt;br /&gt;
der Annotation auch weggelassen werden. Die Annotation selbst hingegen kann &#039;&#039;nicht&#039;&#039; weggelassen werden.&lt;br /&gt;
Da die Methode nur über den Namen referenziert wird, muß der Compiler tatsächlich annehmen,&lt;br /&gt;
daß die Method nicht verwendet wird wenn sie als private deklariert wurde.&lt;br /&gt;
=== Lambda-Ausdrücke ===&lt;br /&gt;
&lt;br /&gt;
==Weitere Test-Daten-Provider==&lt;br /&gt;
JUnit5 unterstützt noch eine Reihe weiterer Möglichkeiten, Testdaten für parametrisierte Tests zur Verfügung zu&lt;br /&gt;
stellen:&lt;br /&gt;
*Java-enums&lt;br /&gt;
*CSV-Dateien&lt;br /&gt;
*Daten im CSV-Format&lt;br /&gt;
*separate Klassen&lt;br /&gt;
==Enums==&lt;br /&gt;
Eine besondere Unterstützung bei der Erstellung parametrisierter Tests erfahren die Java-enums. Grundsätzlich&lt;br /&gt;
erfolgt die Parametrisierung wie dies hier am Beispiel von String-Argumenten beschrieben wurde. Auf die&lt;br /&gt;
spezifischen Eigenschaften von enums und ihrem besonderen Wert für Unit-Tests wird hier eingegangen.&lt;br /&gt;
Betrachten wir ein enum das Versandwege beschreibt:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    enum Versandweg {&lt;br /&gt;
        E_MAIL,&lt;br /&gt;
        SMS,&lt;br /&gt;
        POST&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
und die zu testende Methode die eine TAN über einen Versandweg verschickt:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public class Versender {&lt;br /&gt;
    Response sendTan(Versandweg weg) {&lt;br /&gt;
        ...&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
===Alle Ausprägungen testen===&lt;br /&gt;
Wir können nun für jeden Versandweg eine Test-Methode schreiben. Das geht auch einfacher, wenn wir immer das&lt;br /&gt;
gleiche Ergebnis erwarten:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 @ParameterizedTest&lt;br /&gt;
 @EnumSource(value=Versandweg.class)&lt;br /&gt;
 void verwandWegLiefertOk(Versandweg weg) {&lt;br /&gt;
    Assertions.assertThat(new Versender().sendTan(weg)).isEqualTo(Response.OK);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Die erste Annotation weist die Methode als parametrisierten Test aus. Die zweite Annotation gibt an, welches enum&lt;br /&gt;
für den Test zu verwenden ist. Die Test-Methode selbst muß ein Argument vom Typ des Enums akzeptieren.&lt;br /&gt;
Die parametrisierte Version ist nicht nur kompakter. Wird das enum um weitere Ausprägungen ergänzt, werden&lt;br /&gt;
automatisch Test dafür generiert. Ob das Ergebnis tatsächlich der gewünschten Anforderung entspricht kann JUnit&lt;br /&gt;
natürlich nicht vorhersehen, aber die neue enum-Ausprägung wird zumindest betrachtet und läuft günstigenfalls&lt;br /&gt;
auf einen Fehler.&lt;br /&gt;
=== Einzelne Ausprägungen testen ===&lt;br /&gt;
Möchte man nicht alle Ausprägungen testen sondern nur ganz bestimmte, kann man das der Annotation mitgeben.&lt;br /&gt;
dafür gibt es zwei Modes: &#039;&#039;einschließend&#039;&#039; und &#039;&#039;ausschließend&#039;&#039;.&lt;br /&gt;
Möchten wir etwa nur die Versandwege eMail und SMS testen, können wir die Annotation so schreiben (der ganze Rest bleibt gleich):&lt;br /&gt;
{{java|code=@EnumSource(value = Versandweg.class, mode = Mode.INCLUDE, names = { &amp;quot;E_MAIL&amp;quot;, &amp;quot;SMS&amp;quot; })}}&lt;br /&gt;
Der Parameter {{java|mod}} gibt an, daß nur die angegebenen Ausprägungen getestet werden sollen. Da &amp;quot;Include&amp;quot; der&lt;br /&gt;
default ist, kann de Mo in diesem Falle auch weggelassen werden. Der Parameter {{java|names}} ist eine Liste von enum-Ausprägung-Namen die als Strings angegeben werden.&lt;br /&gt;
Man kann das vorgehen auch umdrehen un den Versandweg &amp;quot;POST&amp;quot; – als einzigen nicht-elektronischen Weg&lt;br /&gt;
ausschließen. Die Annotation sieht dann so aus:&lt;br /&gt;
{{java|code=@EnumSource(value = Versandweg.class, mode = Mode.EXCLUDE, names = { &amp;quot;POST&amp;quot; })}}&lt;br /&gt;
Der {{java|mode}}-Parameter hat nun den Wert {{java|EXCLUDE}} und darf natürlich nicht weggelassen werden. Der Parameter&lt;br /&gt;
{{java|names}} ist wieder eine Liste von enum-Ausprägung-Namen die hier aus einem einzigen Wert besteht.&lt;br /&gt;
In beiden Fällen ist der Entwickler für die korrekte Schreibweise der Namen der enum-Ausprägungen&lt;br /&gt;
verantwortlich. Stimmt sie nicht überein, giebt&#039;s einen Laufzeitfehler bei der Test-Ausführung.&lt;br /&gt;
Während bei &amp;quot;INCLUDE&amp;quot; nur so viel Tests erzeugt werden, wie enum-Ausprägungen spezifiziert wurden, werden bei&lt;br /&gt;
&amp;quot;EXCLUDE&amp;quot; Tests für alle Ausprägungen erzeugt die nicht angegeben sind. Wird das enum um Ausprägungen&lt;br /&gt;
erweitert, dann werden im EXCLUDE-Falle neue Tests generiert, im INCLUDE-Falle nicht.&lt;br /&gt;
&lt;br /&gt;
===Pattern-Matching===&lt;br /&gt;
Mit den beiden Modes MATCH_ALL und MATCH_ANY können die Namen von enum-Ausprägungen mit Hilfe von&lt;br /&gt;
regulären Ausdrücken spezifiziert werden. Dieses Vorgehen ist jedoch problematisch und soll hier nicht weiter&lt;br /&gt;
erörtert werden. Macht man bei Definition der Ausdrücke Fehler, kann es beispielsweise passieren, daß&lt;br /&gt;
Ausprägungen ausgelassen werden und für diese dann keine Tests erzeugt werden. Das fällt nur auf wenn die TestAusführung manuell überprüft wird.&lt;br /&gt;
===Test-Fälle als Enumerationen===&lt;br /&gt;
bei der Verwendung von enum-Sources ist man nicht auf &amp;quot;produktive&amp;quot; enums beschränkt. Man kann auch Test-Situationen über enums definieren und diese&lt;br /&gt;
enums dann verwenden um parametrisierte Tests zu füttern. Man kann zum Beispiel für die Test-Klasse enum &amp;quot;Kunde&amp;quot; definieren, dessen Ausprägungen&lt;br /&gt;
jeweils einzelne Test-Konstellationen beschreiben. Damit lassen sich parametrisierte Tests definieren, die alle oder ausgewählte Konstellationen testen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 @ParameterizedTest&lt;br /&gt;
 @EnumSource(value = Kunde.class, names = { &amp;quot;MIT_KDNR&amp;quot;, &amp;quot;MIT_IHNR&amp;quot;, &amp;quot;MIT_KDNR_UND_IHNR&amp;quot; })&lt;br /&gt;
 void darfElektronischeDokumentEinstellungSehen(Kunde kunde) {&lt;br /&gt;
    assertThat(verwalter(kunde).darfElectronicDocumentsSehen()).isTrue();&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
In diesem Beispiel wurde Kunden konfiguriert die ein Kunden- oder Inhabernummer oder beides haben. Jeder der&lt;br /&gt;
Kunden muß seine elektronischen Dokumente sehen dürfen.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Testdaten-Provider&amp;diff=181</id>
		<title>Testdaten-Provider</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Testdaten-Provider&amp;diff=181"/>
		<updated>2024-03-19T19:15:17Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Category:Java Category:junit Um einen parametrisierte Test-Methode mit Daten zu versorgen bieten sich Methoden als Testdaten-Provider an. Eine solcher Provider-Methode liefert einen {{java|Stream}} von Testdaten-Sätzen. Ein Testdaten-Satz besteht in der Regel auf mehreren Einzeldaten, er kann aber natürlich auch aus einem einzelnen Datum bestehen. Jeder Satz ist in ein {{java|Arguments}}-Objekt verpackt und besteht daher immer aus Objekten; Date…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
[[Category:junit]]&lt;br /&gt;
Um einen parametrisierte Test-Methode mit Daten zu versorgen bieten sich Methoden als Testdaten-Provider an.&lt;br /&gt;
Eine solcher Provider-Methode liefert einen {{java|Stream}} von Testdaten-Sätzen. Ein Testdaten-Satz besteht in der Regel&lt;br /&gt;
auf mehreren Einzeldaten, er kann aber natürlich auch aus einem einzelnen Datum bestehen. Jeder Satz ist in&lt;br /&gt;
ein {{java|Arguments}}-Objekt verpackt und besteht daher immer aus Objekten; Daten atomarer Typen werden dabei in &lt;br /&gt;
Objekte der korrespondierenden Klassen verpackt.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir eine einfache Test-Methode die für die Ausführung zwei Strings benötigt.&lt;br /&gt;
Wie jede Test-Methode die eine nichtleere Parameterliste hat, muß sie mit der Annotation {{java|@ParameterizedTest}}&lt;br /&gt;
versehen sein:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ParameterizedTest&lt;br /&gt;
void passwortWirdNichtAkzeptiert(String passwort, String grund) {&lt;br /&gt;
    assertThat(policy.validate(passwort)).as(grund).isFalse();&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
== Variante 1: die statische Methode ==&lt;br /&gt;
Der einfachste Weg einen Testdaten-Provider zu definieren führt über eine statische Methode&lt;br /&gt;
die sich in der selben Klasse befindet wie die Test-Methode:&lt;br /&gt;
{{java|code=&lt;br /&gt;
static Stream&amp;lt;Arguments&amp;gt; pwdWirdNichtAkzeptiert() {&lt;br /&gt;
    return Stream.of(&lt;br /&gt;
        Arguments.of(&amp;quot;Hallo&amp;quot;, &amp;quot;nur Buchstaben&amp;quot;),&lt;br /&gt;
        Arguments.of(&amp;quot;1234567&amp;quot;, &amp;quot;nur Ziffern&amp;quot;),&lt;br /&gt;
        Arguments.of(&amp;quot;!%#&amp;amp;/()&amp;quot;, &amp;quot;nur Sonderzeichen&amp;quot;)&lt;br /&gt;
    );&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Stimmt der Name des Testdaten-Providers mit dem Namen der Test-Methode überein, kann man den Parameter&lt;br /&gt;
in der Annotation auch weglassen. Für diese Variante gelten folgende Einschränkungen:&lt;br /&gt;
* Die Methode muß in der gleichen Klasse liegen wie die Test-Methode&lt;br /&gt;
* Die Methode muß als {{java|static}} deklariert sein&lt;br /&gt;
* Die Methode darf &#039;&#039;nicht&#039;&#039; {{java|private}} deklariert sein&lt;br /&gt;
&lt;br /&gt;
== Variante 2: die qualifizierte statische Methode ==&lt;br /&gt;
Nachteil der ersten Variante ist, daß sich der Testdaten-Provider in der gleichen Klasse befinden muß&lt;br /&gt;
wie die Test-Methode. Das gilt auch, wenn sich die Methode in einer Member Class oder einer Inner Class befindet.&lt;br /&gt;
Damit lassen sich keine Testdaten-Provider definieren, die von mehreren geschachtelte Test-Klassen &lt;br /&gt;
-- per Annotation {{java|@Nested}} -- gemeinsam genutzt werden.&lt;br /&gt;
&lt;br /&gt;
Befindet sich der Testdaten-Provider in einer anderen Klasse als die Test-Methode, kann man zusätzlich zur Methode&lt;br /&gt;
die Klasse angeben in der sich die Methode befindet. Die Package-Angabe muß &#039;&#039;&#039;voll qualifiziert&#039;&#039;&#039; sein, die Methode&lt;br /&gt;
wird mit {{java|#}} getrennt angefügt:&lt;br /&gt;
{{java|code=&lt;br /&gt;
MethodSource(&amp;quot;org.mletkin.unittest.TestDaten#pwdWirdNichtAkzeptiert&amp;quot;)&lt;br /&gt;
}}&lt;br /&gt;
Wie in Variante 1 erfolgt die Angabe in Form eines Strings. Das ist fehleranfällg, weil die Klasse und die Methode&lt;br /&gt;
erst zur Laufzeit -- also bei der Test-Ausführung -- auf Existenz geprüft werden.&lt;br /&gt;
&lt;br /&gt;
Man kann das mitigieren, indem man den String in eine Konstante auslagert:&lt;br /&gt;
{{java|code=&lt;br /&gt;
private static final String TEST_DATA = &amp;quot;org.mletkin.unittest.TestDaten#pwdWirdNichtAkzeptiert&amp;quot;;&lt;br /&gt;
...&lt;br /&gt;
@MethodSource(TEST_DATA)&lt;br /&gt;
}}&lt;br /&gt;
Das eröffnet zum einen die Möglichkeit Test-Methoden zentral bereitzustellen und zum anderen die Möglichkeit&lt;br /&gt;
die Strings auf Gültigkeit zu überprüfen. Das geschieht dann zwar auch erst zur Laufzeit, der Fehler tritt &lt;br /&gt;
dann aber wenigstens da auf wo er geschehen ist.&lt;br /&gt;
&lt;br /&gt;
== Variante 3: die Testdaten-Provider-Klasse ==&lt;br /&gt;
Eine weitere Möglichkeit den Testdaten-Provider zu implementieren ist die Definition in einer eigenen Klasse.&lt;br /&gt;
Eine solche Klasse kann allerdings nur eine einzige Testdaten-Methode anbieten, da der Zugriff über ein Interface erfolgt:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class UngueltigePassworte implements ArgumentsProvider {&lt;br /&gt;
    @Override&lt;br /&gt;
    public Stream&amp;lt;Arguments&amp;gt; provideArguments(ExtensionContext context) {&lt;br /&gt;
        return Stream.of(&lt;br /&gt;
            Arguments.of(&amp;quot;Hallo&amp;quot;, &amp;quot;nur Buchstaben&amp;quot;),&lt;br /&gt;
            Arguments.of(&amp;quot;1234567&amp;quot;, &amp;quot;nur Ziffern&amp;quot;),&lt;br /&gt;
            Arguments.of(&amp;quot;!%#&amp;amp;/()&amp;quot;, &amp;quot;nur Sonderzeichen&amp;quot;)&lt;br /&gt;
        );&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Die Testdaten-Provider-Klasse muß das Interface {{java|ArgumentsProvider}} implementieren und dazu die oben gezeigte Methode&lt;br /&gt;
implementierten. Sie erhält als Argument ein Kontext-Objekt das Informationen zur Umgebung der Test-Ausführung enthält.&lt;br /&gt;
In unserem Beispiel machen wir keinen Gebrauch davon.&lt;br /&gt;
&lt;br /&gt;
Die Verwendung erfolgt über die Annotation {{java|@ArgumentsSource}}, der jetzt die Testdaten-Provider-Klasse in Form eines&lt;br /&gt;
{{java|Class}}-Objekts übergeben wird:&lt;br /&gt;
{{java|code=&lt;br /&gt;
@ArgumentSource(UngueltigePassworte .class)&lt;br /&gt;
}}&lt;br /&gt;
Im Gegensatz zur {{java|@MethodSource}}-Verwendung in den vorangegangenen Varianten wird hier schon zur Compile-Zeit sichergestellt&lt;br /&gt;
daß die Testdaten-Provider-Klasse und die -Methode existieren.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Sch%C3%BCttelreim&amp;diff=180</id>
		<title>Schüttelreim</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Sch%C3%BCttelreim&amp;diff=180"/>
		<updated>2024-01-19T10:48:21Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Eigenes]]&lt;br /&gt;
&lt;br /&gt;
 Ich saß vor meinem Monitor&lt;br /&gt;
 Und hatte einen Ton im Ohr&lt;br /&gt;
undatiert&lt;br /&gt;
&lt;br /&gt;
 Ich werde einen Kuchen backen&lt;br /&gt;
 Und ihn dann zwischen Buchen kacken&lt;br /&gt;
19.7.2020&lt;br /&gt;
&lt;br /&gt;
 Ich traf dieselben Gecken&lt;br /&gt;
 Immer bei den gelben Säcken&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Er sitzt auf dem Geschirrspüler&lt;br /&gt;
 Und lehrt mit viel Gespür Schüler&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Weihnachten wird der Baumkuchen&lt;br /&gt;
 So knapp, man kann ihn kaum buchen&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Sie aßen ihre Salzstangen&lt;br /&gt;
 Fortan nur noch mit Stahlzangen&lt;br /&gt;
Januar 2023&lt;br /&gt;
&lt;br /&gt;
 Er repariert den ganzen Tag Lichtschalter&lt;br /&gt;
 Und nach der Schicht lallt er&lt;br /&gt;
Mai 2023&lt;br /&gt;
&lt;br /&gt;
 Das Schiff hat am Rand Latten&lt;br /&gt;
 Zum Schutz der doofen Landratten&lt;br /&gt;
9.7.2023&lt;br /&gt;
&lt;br /&gt;
 Die Masten meist im Wege steh&#039;n&lt;br /&gt;
 Wenn Fahnen an dem Stege weh&#039;n&lt;br /&gt;
22.7.2023&lt;br /&gt;
&lt;br /&gt;
 Er wollte die Fahne in heroischer Pose hissen&lt;br /&gt;
 Und mußte dabei sich in die Hose pissen&lt;br /&gt;
1.9.2023&lt;br /&gt;
&lt;br /&gt;
 Ich griff nach meiner Beißschiene&lt;br /&gt;
 Da sticht mich so &#039;ne Scheißbiene&lt;br /&gt;
18.1.2024&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Sch%C3%BCttelreim&amp;diff=179</id>
		<title>Schüttelreim</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Sch%C3%BCttelreim&amp;diff=179"/>
		<updated>2024-01-19T10:39:37Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Eigenes]]&lt;br /&gt;
&lt;br /&gt;
 Er saß vor seinem Monitor&lt;br /&gt;
 Und hatte einen Ton im Ohr&lt;br /&gt;
undatiert&lt;br /&gt;
&lt;br /&gt;
 Ich werde einen Kuchen backen&lt;br /&gt;
 Und ihn dann zwischen Buchen kacken&lt;br /&gt;
19.7.2020&lt;br /&gt;
&lt;br /&gt;
 Ich traf dieselben Gecken&lt;br /&gt;
 Immer bei den gelben Säcken&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Er sitzt auf dem Geschirrspüler&lt;br /&gt;
 Und lehrt mit viel Gespür Schüler&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Weihnachten wird der Baumkuchen&lt;br /&gt;
 So knapp, man kann ihn kaum buchen&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Sie aßen ihre Salzstangen&lt;br /&gt;
 Fortan nur noch mit Stahlzangen&lt;br /&gt;
Januar 2023&lt;br /&gt;
&lt;br /&gt;
 Er repariert den ganzen Tag Lichtschalter&lt;br /&gt;
 Und nach der Schicht lallt er&lt;br /&gt;
Mai 2023&lt;br /&gt;
&lt;br /&gt;
 Das Schiff hat am Rand Latten&lt;br /&gt;
 Zum Schutz der doofen Landratten&lt;br /&gt;
9.7.2023&lt;br /&gt;
&lt;br /&gt;
 Die Masten meist im Wege steh&#039;n&lt;br /&gt;
 Wenn Fahnen an dem Stege weh&#039;n&lt;br /&gt;
22.7.2023&lt;br /&gt;
&lt;br /&gt;
 Er wollte die Fahne in heroischer Pose hissen&lt;br /&gt;
 Und mußte dabei sich in die Hose pissen&lt;br /&gt;
1.9.2023&lt;br /&gt;
&lt;br /&gt;
 ich griff nach meiner Beißschiene&lt;br /&gt;
 Da sticht mich so &#039;ne Scheißbiene&lt;br /&gt;
18.1.2024&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Sch%C3%BCttelreim&amp;diff=178</id>
		<title>Schüttelreim</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Sch%C3%BCttelreim&amp;diff=178"/>
		<updated>2024-01-19T10:37:45Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Eigenes]]&lt;br /&gt;
&lt;br /&gt;
 Er saß vor seinem Monitor&lt;br /&gt;
 Und hatte einen Ton im Ohr&lt;br /&gt;
undatiert&lt;br /&gt;
&lt;br /&gt;
 Ich werde einen Kuchen backen&lt;br /&gt;
 Und ihn dann zwischen Buchen kacken&lt;br /&gt;
19.7.2020&lt;br /&gt;
&lt;br /&gt;
 Ich traf dieselben Gecken&lt;br /&gt;
 Immer bei den gelben Säcken&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Er sitzt auf dem Geschirrspüler&lt;br /&gt;
 Und lehrt mit viel Gespür Schüler&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Weihnachten wird der Baumkuchen&lt;br /&gt;
 So knapp, man kann ihn kaum buchen&lt;br /&gt;
Januar 2022&lt;br /&gt;
&lt;br /&gt;
 Sie aßen ihre Salzstangen&lt;br /&gt;
 Fortan nur noch mit Stahlzangen&lt;br /&gt;
Januar 2023&lt;br /&gt;
&lt;br /&gt;
 Er repariert den ganzen Tag Lichtschalter&lt;br /&gt;
 Und nach der Schicht lallt er&lt;br /&gt;
Mai 2023&lt;br /&gt;
&lt;br /&gt;
 Das Schiff hat am Rand Latten&lt;br /&gt;
 Zum Schutz der doofen Landratten&lt;br /&gt;
9.7.2023&lt;br /&gt;
&lt;br /&gt;
 Die Masten meist im Wege steh&#039;n&lt;br /&gt;
 Wenn Fahnen an dem Stege weh&#039;n&lt;br /&gt;
22.7.2023&lt;br /&gt;
&lt;br /&gt;
 Er wollte die Fahne in heroischer Pose hissen&lt;br /&gt;
 Und mußt dabei in die Hose pissen&lt;br /&gt;
1.9.2023&lt;br /&gt;
&lt;br /&gt;
 Er greift nach seiner Beißschiene&lt;br /&gt;
 Da sticht ihn so &#039;ne Scheißbiene&lt;br /&gt;
18.1.2024&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Mockito:_Verify&amp;diff=177</id>
		<title>Mockito: Verify</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Mockito:_Verify&amp;diff=177"/>
		<updated>2024-01-11T08:13:59Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Ullrich verschob die Seite Mockito Verify nach Mockito: Verify, ohne dabei eine Weiterleitung anzulegen&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Kategorie:Java]]&lt;br /&gt;
[[Kategorie:Mockito]]&lt;br /&gt;
== Voraussetzungen ==&lt;br /&gt;
Die Voraussetzungen für die Anwendung von {{java|verify}} sind simpel.&lt;br /&gt;
Man benötigt dazu einen Mock oder einen Spy der ein &amp;quot;echtes&amp;quot; Objekt umwickelt.&lt;br /&gt;
Mocks und Spies werden [[Partieller Mock|hier]] beschrieben.&lt;br /&gt;
&lt;br /&gt;
== Die grundsätzliche Anwendung ==&lt;br /&gt;
Wir stellen uns hier einen Handler vor, dessen {{java|onMessage}}-Methode die {{java|send}}-Methode&lt;br /&gt;
des {{java|WebSocketConnection}}-Objekts aufrufen soll.&lt;br /&gt;
{{java|code=&lt;br /&gt;
@Test&lt;br /&gt;
public void auftragNullSendetFehlermeldung() {&lt;br /&gt;
    WebSocketConnection connection = Mockito.mock(WebSocketConnection.class);&lt;br /&gt;
    handler.onMessage(connection, (String) null);&lt;br /&gt;
    Mockito.verify(connection, Mockito.atLeastOnce())&lt;br /&gt;
           .send(&amp;quot;Die Anfrage kann nicht verarbeitet werden.&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
Die ersten beiden Zeilen führen den Test durch, die dritte Zeile prüft, daß die {{java|send}}-Methode&lt;br /&gt;
mit dem angegebenen Text mindestens einmal aufgerufen wird.&lt;br /&gt;
&lt;br /&gt;
Der erste Parameter von {{java|verify}} ist das zu untersuchende Objekt. Der zweite Parameter giebt die das erwartete&lt;br /&gt;
Ergebnis an. Auf das Ergebnis wird die Methode aufgerufen, deren Aufruf überprüft werden soll.&lt;br /&gt;
&lt;br /&gt;
Das gleiche {{java|verify}} würde auch funktioneren, wenn statt des Mocks eine echte Connection erzeugt um mit spy&lt;br /&gt;
ummantelt würde:&lt;br /&gt;
{{java|code=WebSocketConnection connection = Mockito.spy(new MyWebSocketConnectionImplementation());}}&lt;br /&gt;
&lt;br /&gt;
== Prüfungen ==&lt;br /&gt;
:&#039;&#039;&#039;atLeastOnce&#039;&#039;&#039;&lt;br /&gt;
:: Die Methode wurde mindestens einmal aufgerufen&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;times(n)&#039;&#039;&#039;&lt;br /&gt;
:: Die Methode wurde &#039;&#039;n&#039;&#039; mal aufgerufen&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;times(0)&#039;&#039;&#039; oder &#039;&#039;&#039;never()&#039;&#039;&#039;&lt;br /&gt;
:: Die Methode wurde nicht aufgerufen&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Mockito:_Einf%C3%BChrung&amp;diff=176</id>
		<title>Mockito: Einführung</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Mockito:_Einf%C3%BChrung&amp;diff=176"/>
		<updated>2024-01-11T08:13:26Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Ullrich verschob die Seite Mockito Einführung nach Mockito: Einführung, ohne dabei eine Weiterleitung anzulegen&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
[[Category:Mockito]]&lt;br /&gt;
= Einführung =&lt;br /&gt;
Ein Mock – im Sinne dieser Einführung  – ist ein Objekt, das so aussieht aber sich nicht so verhält wie das &amp;quot;echte&amp;quot; Objekt das es ersetzt.&lt;br /&gt;
Man kann sich das vorstellen wie eine Theater-Requisite: Benötigt man auf der Bühne ein Buch, verwendet man einen Pappkarton,&lt;br /&gt;
der von außen aussieht wie ein Buch aber keines ist. So versteht diese Einführung unter einem &amp;quot;Mock&amp;quot; -- salopp ausgedrückt:&lt;br /&gt;
{{Quotation|&lt;br /&gt;
ein Objekt, das ein anderes ersetzt und dabei das originale Objekt in bestimmten Aspekten nachahmen kann,&lt;br /&gt;
&lt;br /&gt;
aber niemals dessen vollständige Funtionalität hat.&lt;br /&gt;
Es kann Funktionalität und Seiteneffekte hinzufügen falls erforderlich.}}&lt;br /&gt;
&lt;br /&gt;
Tatsächlich ist die Verwendung der Begriffe Dummy, Fake, Stub und Mock durchaus uneinheitlich.&lt;br /&gt;
Für diese Einführung verzichten wir auf eine akademische Unterscheidung, gehen pragmatisch vor,&lt;br /&gt;
sprechen durchgehend vom &amp;quot;Mock&amp;quot; und meinen das oben genannte.&lt;br /&gt;
Dem Sprachenthusiasten, der an einer genaueren Definition interessiert ist,&lt;br /&gt;
sei zum Einstieg der Blog-Artikel von&lt;br /&gt;
[https://martinfowler.com/articles/mocksArentStubs.html Martin Fowler] empfohlen.&lt;br /&gt;
&lt;br /&gt;
== Aufgaben ==&lt;br /&gt;
Ein Mock kann bei der Implementierung von Unit-Tests für verschiedene Aufgaben genutzt werden.&lt;br /&gt;
Man kann diese Aufgaben in der Regel auch anders lösen, aber wir möchten hier natürlich erörtern &lt;br /&gt;
wie &#039;&#039;Mockito&#039;&#039; uns bei der Erfüllung unterstützen kann.&lt;br /&gt;
&lt;br /&gt;
Typische Aufgaben für Mocks sind&lt;br /&gt;
*Das Emulieren von Klassen, deren wahre Funktionalität nicht ausgeführt werden kann, darf oder soll&lt;br /&gt;
*Das Erzeugen von Instanzen von Interfaces und Klassen, von denen keine konkrete Implementierung erzeugt werden kann&lt;br /&gt;
*Der Überprüfung, ob –- und mit welchen Argumenten -– Methoden einer Klasse aufgerufen wurden.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;So tun als täte es:&#039;&#039;&#039; Jeder Unit-Test muß isoliert und ohne externe Abhängigkeiten ausgeführt werden können. Es&lt;br /&gt;
reicht nicht, wenn der Test lokal im Eclipse läuft, er muß auch jederzeit vom Jenkins-Build ausgeführt werden&lt;br /&gt;
können. Greift beispielsweise eine Methode auf einen Web-Service oder eine lokale Datenbank zu, kann der Test&lt;br /&gt;
nicht ausgeführt werden. Man kann dann Mock-Implementierungen der Service-Klasse bzw. der Persistenz-Schicht&lt;br /&gt;
erzeugen und mit diesen als Ersatz den Unit-Test durchführen.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;So tun als gäbe es:&#039;&#039;&#039; Der Typ eines Parameters der zu testenden Methode sei ein Interface. Dann benötigt man&lt;br /&gt;
für den Aufruf der Methode im Rahmen des Unit-Tests eine Objekt-Instanz einer Klasse die das Interface implementiert.&lt;br /&gt;
Statt das Interface selbst zu implementieren, überläßt man Mockito die Fußarbeit und nutzt einen Mock.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;Prüfen, ob:&#039;&#039;&#039; In vielen Unit-Tests möchte man sicherstellen, daß beim Durchlauf eine bestimmte Methode&lt;br /&gt;
aufgerufen wird (oder garantiert nicht aufgerufen wird) oder daß eine Methode mit bestimmten Argumenten aufgerufen wird.&lt;br /&gt;
Das läßt sich bei allen Mockito-Mocks serienmäßig überprüfen, Mockito erlaubt es aber auch, &amp;quot;echte&amp;quot; Objekte&lt;br /&gt;
mit einem Spy-Objekt zu umwickeln über das die entsprechende Information abgerufen werden kann.&lt;br /&gt;
&lt;br /&gt;
== Abgrenzung ==&lt;br /&gt;
Anstelle von Mockito-Mocks kann man auch einfach &lt;br /&gt;
Interfaces implementieren und Klassen ableiten um zu Mock-Implementierungen zu kommen. Java-Interfaces&lt;br /&gt;
wurden ja auch zu dem Zweck geschaffen, unterschiedlicher Implementierungen mit der gleichen Schnittstelle zu&lt;br /&gt;
schaffen – warum also Mockito nutzen? Die Erzeugung eines Mockito-Mocks nimmt eine Zeile Code in Anspruch;&lt;br /&gt;
gleichgültig wieviele Methoden implementiert oder überschrieben werden. Eine konkrete Klasse braucht eine&lt;br /&gt;
explizite Implementierung und das wird schnell unübersichtlich. Zudem aktualisiert sich der Mock automatisch,&lt;br /&gt;
weil er erst zur Laufzeit entsteht. Eine händische Implementierung eines Interface muß jedesmal angefaßt werden,&lt;br /&gt;
wenn sich das Interface ändert – ein Mockito-Mock nicht.&lt;br /&gt;
&lt;br /&gt;
Zum Schluß der Einleitung sei darauf hingewiesen, was Mockito nicht mocken kann:&lt;br /&gt;
*statische Methoden&lt;br /&gt;
*private Methoden&lt;br /&gt;
*finale Klassen und Methoden&lt;br /&gt;
&lt;br /&gt;
Auf dieser Seite geht es um die Erstellung von Mocks. Spies und alternative Vorgehen werden [[Partieller Mock|hier]]&lt;br /&gt;
behandelt, um das Überprüfen des Aufrufverhaltens [[Mockito Verify|hier]].&lt;br /&gt;
&lt;br /&gt;
= Mocking =&lt;br /&gt;
Mocking hat zwei Schritte. Zunächst wird ein Mock-Objekt von der gewünschten Klasse erzeugt,&lt;br /&gt;
dann werden Methoden des Objekts in der Weise implementiert wie es für den Test erforderlich ist.&lt;br /&gt;
&lt;br /&gt;
Der zweite Schritt ist optional, ein vollständig funktionsloser Mock ist in vielen Fällen schon&lt;br /&gt;
ausreichend. In aller Regel wird man dem Mock jedoch Funktionalität hinzufügen wollen.&lt;br /&gt;
Diese Einführung folgt diesem Vorgehen und beschreibt die nötigen Werkzeuge. Alternative&lt;br /&gt;
Ansätze werden hier [[Partieller_Mock|besprochen]].&lt;br /&gt;
&lt;br /&gt;
== Das Mock-Objekt ==&lt;br /&gt;
&lt;br /&gt;
Der einfachste Mock für ein Objekte einer Klasse oder eines Interfaces erlaubt den Aufruf jeder nicht-statischen,&lt;br /&gt;
non-private, non-final Methode ohne daß dabei eine Exception auftritt.&lt;br /&gt;
Er wird so erzeugt:&lt;br /&gt;
{{java|code=Foo mock = Mockito.mock(Foo.class);}}&lt;br /&gt;
Die Methoden des Mocks tun nichts, sie rufen auch keine super-Methoden auf. Es wird nur sichergestellt daß jede Methode&lt;br /&gt;
gefahrlos aufgerufen werden kann und ggf. einen gültigen, wenn auch bedeutungslosen Wert liefert. Anstelle von Objekten&lt;br /&gt;
(dazu gehören auch Strings) erhält man stets {{java|null}}, numerische Ergebnisse sind immer &#039;&#039;0&#039;&#039;&lt;br /&gt;
und boolean-Methoden liefern immer {{java|false}}.&lt;br /&gt;
&lt;br /&gt;
Wird eine Klasse gemockt, erzeugt Mockito eine Ableitung der zu mockenden Klasse. In der Folge können weder finale&lt;br /&gt;
Klassen noch finale Methoden gemockt werden. Gleiches gilt für statische Methoden, die nicht vererbt werden.&lt;br /&gt;
&lt;br /&gt;
Der Mock kann auf Felder der gemockten Klasse zugreifen, solange diese nicht private sind. Allerdings kann&lt;br /&gt;
er keine eigenen Felder definieren. Auf public und package visible Felder kann auch von außen zugegriffen werden.&lt;br /&gt;
&lt;br /&gt;
== Mocken von Methoden ==&lt;br /&gt;
&lt;br /&gt;
Wie erwähnt, liefern Methoden gemockter Klassen nur default-Werte; das ist selten ausreichend.&lt;br /&gt;
Betrachten wir zunächst die einfachste Variante:&lt;br /&gt;
bei jedem Aufruf der Methode solleb die gleichen, feste Werte geliefert werden.&lt;br /&gt;
Wir mocken dafür das folgende Interface:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public interface Person {&lt;br /&gt;
    String id();&lt;br /&gt;
    String abteilung();&lt;br /&gt;
    int foo(String dings);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
=== Parameterlose Methoden ===&lt;br /&gt;
Soll etwa die ID der Person immer den Wert 5 liefern, könnte das so aussehen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
person = Mockito.mock(Person.class);&lt;br /&gt;
Mockito.when(person.id()).thenReturn(5);&lt;br /&gt;
}}&lt;br /&gt;
Das Argument der {{java|when}}-Methode ist ein Methoden-Aufruf auf den Mock,&lt;br /&gt;
das Argument der {{java|thenReturn}}-Methode ist der zu liefernde Wert.&lt;br /&gt;
Soll die Methode eine Abfolge fester Werte liefern, kann man eine Liste angeben:&lt;br /&gt;
{{java|code=Mockito.when(person.abteilung()).thenReturn(&amp;quot;BLA&amp;quot;, &amp;quot;FOO&amp;quot;);}}&lt;br /&gt;
Beim ersten Aufruf liefert die Methode den String {{java|BLA}} und beim zweiten {{java|FOO}}.&lt;br /&gt;
Man kann die Werte auch einzeln angeben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Mockito.when(person.abteilung())&lt;br /&gt;
    .thenReturn(&amp;quot;BLA&amp;quot;)&lt;br /&gt;
    .thenReturn(&amp;quot;FOO&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
Verwendet man die zweite Variante, kann man die gemockte Methode auch dazu bringen, zwischendurch Exceptions zu werfen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Mockito.when(person.abteilung())&lt;br /&gt;
    .thenReturn(&amp;quot;BLA&amp;quot;)&lt;br /&gt;
    .thenThrow(new RuntimeException());&lt;br /&gt;
    .thenReturn(&amp;quot;FOO&amp;quot;);&lt;br /&gt;
}}&lt;br /&gt;
Sind alle Werte durch Aufruf verbraucht, liefert die Methode wieder den default-Wert.&lt;br /&gt;
&lt;br /&gt;
=== Methoden mit Parametern ===&lt;br /&gt;
Die meisten Methoden haben einen oder mehrere Parameter. Will man solche Methoden mocken, muß man&lt;br /&gt;
spezifizieren bei welchen Argumenten welche Ergebnisse geliefert werden sollen. Im einfachsten Falle gibt man den&lt;br /&gt;
Argument-Wert als Literal vor:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Foo p = Mockito.mock(Person.class);&lt;br /&gt;
Mockito.when(p.foo(&amp;quot;x&amp;quot;)).thenReturn(10);&lt;br /&gt;
Assertions.assertThat(p.foo(&amp;quot;x&amp;quot;)).isEqualTo(10);&lt;br /&gt;
}}&lt;br /&gt;
Die Methode {{java|foo}} liefert für {{java|foo(&amp;quot;X&amp;quot;)}} nun den Wert &#039;&#039;10&#039;&#039; und für alle anderen Argumente einen undefinierten Wert.&lt;br /&gt;
Wie erwähnt wird die Methode für alle anderen Argumente den Wert &#039;&#039;0&#039;&#039; liefern, aber man sollte sich nicht darauf verlassen,&lt;br /&gt;
daß das auch immer und unter allen Umständen so sein wird.&lt;br /&gt;
&lt;br /&gt;
In den meisten Fällen wird man nicht auf einzelne Werte reagieren wollen, sondern auf Gruppen von Werten oder&lt;br /&gt;
auf alle möglichen Werte. Um das zu bewerkstelligen werden Matcher benötigt, die beim Aufruf versuchen die Argumente zu matchen.&lt;br /&gt;
Die Mockito-Matcher werden über statische Methoden der Klasse {{java|ArgumentMatchers}} bereitgestellt.&lt;br /&gt;
&lt;br /&gt;
Da unsere Einstiegsklasse {{java|Mockito}} davon ableitet, &amp;quot;erbt&amp;quot; sie alle dort beheimateten statischen Methodem. Der Kürze halber&lt;br /&gt;
wird man sie also –- wie hier dargestellt –- über die Mockito-Klasse referenzieren. Das ist nach der reinen Java-Lehre eigentlich&lt;br /&gt;
nicht sauber, da statische Methoden nicht vererbbar sind. Aber da hier keine Probleme zu erwaretn sind, darf der Test-Code sich das erlauben. &lt;br /&gt;
&lt;br /&gt;
Im Folgenden werden einige häufig benutzte Matcher vorgestellt.&lt;br /&gt;
&lt;br /&gt;
==== Immer das Gleiche ====&lt;br /&gt;
Um für &#039;&#039;jedes&#039;&#039; beliebige Argument den gleichen Wert zuliefern, verwendet man einen der vielen {{java|any}}-Matcher.&lt;br /&gt;
{{java|Mockito.anyString()}} etwa akzeptiert jeden String mit Ausnahme von {{java|null}} -- dazu später:&lt;br /&gt;
{{java|code=Mockito.when(p.foo(Mockito.anyString())).thenReturn(12);}}&lt;br /&gt;
Die Methode {{java|foo}} liefert nun für jedes beliebige String-Argument – ganz verläßlich – den Wert &#039;&#039;12&#039;&#039;.&lt;br /&gt;
Analog zu String bietet Mockito für eine Vielzahl von Typen – darunter auch für alle simplen Typen&lt;br /&gt;
wie {{java|int}} oder {{java|boolean}} – Matcher an, die jeweils mit &amp;quot;any&amp;quot; beginnen.&lt;br /&gt;
Kann der Compiler den Typ selbst erkennen, geht auch das generische {{java|any()}}:&lt;br /&gt;
{{java|code=Mockito.when(p.foo(Mockito.any())).thenReturn(10);}}&lt;br /&gt;
Handelt es sich um eine Klasse, kann man den Typ auch explizit angeben:&lt;br /&gt;
{{java|code=Mockito.when(p.foo(Mockito.any(String.class))).thenReturn(10);}}&lt;br /&gt;
Soll neben echten Objekten auch {{java|null}} als Argument akzeptiert werden, verwendet man {{java|nullable}};&lt;br /&gt;
das geht nur unter Angabe einer Klasse:&lt;br /&gt;
{{java|code=Mockito.when(p.foo(Mockito.nullabe(String.class))).thenReturn(10);}}&lt;br /&gt;
Möchte man &#039;&#039;nur&#039;&#039; auf {{java|null}} reagieren geht das auch, diesmal ohne Klasse:&lt;br /&gt;
{{java|code=Mockito.when(p.foo(Mockito.isNull())).thenReturn(10);}}&lt;br /&gt;
&lt;br /&gt;
==== Manchmal das Gleiche ====&lt;br /&gt;
Das Konstrukt {{java|Mockito.anyString()}} liefert einen Matcher. Das ist ein Objekt, das beim Aufruf den Eingabe-Wert&lt;br /&gt;
analysiert und Übereinstimmungen signalisiert. Erkennt der Matcher im {{java|when()}}-Teil das definierte Muster,&lt;br /&gt;
wird der Wert des {{java|thenReturn()}} als Ergebnis geliefert.&lt;br /&gt;
&lt;br /&gt;
Neben den any-Matchern giebt es eine Fülle anderer Matcher die auf verschiedene Auswahlen von Argumenten passen.&lt;br /&gt;
Zum Gebrauch sei auf die API-Doku von {{java|ArgumentMatchers}} verwiesen.&lt;br /&gt;
&lt;br /&gt;
Die meisten Fälle lassen sich aber mit dem Universal-Matcher {{java|argThat}} behandeln. Er verlangt als Argument&lt;br /&gt;
eine Implementierung des (funktionalen) Interfaces {{java|ArgumentMatcher &amp;lt;T&amp;gt;}} (&#039;&#039;&#039;ohne -s!&#039;&#039;&#039;).&lt;br /&gt;
Das Interface ist äquivalent zum JDK-Interface {{java|Predicate}}, es hat einen Objekt-Parameter und liefert&lt;br /&gt;
{{java|true}} für &amp;quot;Match&amp;quot; oder {{java|false}} oder &amp;quot;kein Match&amp;quot;.&lt;br /&gt;
Dadurch läßt sich jeder passende {{lambda}}-Ausdruck als Matcher verwenden. &lt;br /&gt;
In voller {{lambda}}-Geschwätzigkeit sieht das zum Beispiel so aus:&lt;br /&gt;
{{java|code=Mockito.when(p.foo(ArgumentMatchers.argThat((String s) -&amp;gt; s.length() &amp;gt; 5))).thenReturn(10);}}&lt;br /&gt;
Wenn das das alles nicht reicht, findet man in der hamcrest-Bibliothek eine unglaubliche Fülle weiterer Matcher.&lt;br /&gt;
&lt;br /&gt;
==== Mal dies -- mal das ====&lt;br /&gt;
Man kann beliebig viele {{java|.when}}-Konstrukte verwenden um den Mock für unterschiedlichen Argumente&lt;br /&gt;
unterschiedliche Ergebnisse liefern zu lassen. Mockito wendet die Matcher bei der späteren Ausführung in der&lt;br /&gt;
&#039;&#039;&#039;umgekehrten&#039;&#039;&#039; Reihenfolge ihrer Definition an. In der folgenden Kombination&lt;br /&gt;
{{java|code=&lt;br /&gt;
Foo p = Mockito.mock(Foo.class);&lt;br /&gt;
Mockito.when(p.foo(Mockito.anyString())).thenReturn(12);&lt;br /&gt;
Mockito.when(p.foo(&amp;quot;x&amp;quot;)).thenReturn(10);&lt;br /&gt;
}}&lt;br /&gt;
liefert {{java|foo(&amp;quot;x&amp;quot;)}} daher den Wert &#039;&#039;10&#039;&#039; und für jedes andere Argument liefert {{java|foo}} den Wert &#039;&#039;12&#039;&#039;.&lt;br /&gt;
Selbstverständlich lassen sich in jedem Ausdruck beliebige Matcher verwenden.&lt;br /&gt;
Man muß bei der Definition aber darauf achten, daß die allgemeineren Matcher zuerst kommen.&lt;br /&gt;
Fügt man dem letzten Beispiel etwa noch ein {{java|.when}} mit einem {{java|anyString()}} an:&lt;br /&gt;
{{java|code=Mockito.when(Mockito.anyString()).thenReturn(4711);}}&lt;br /&gt;
dann werden alle vorher definierten Regeln ignoriert weil die letzte und allgemeinste Regel zuerst zieht.&lt;br /&gt;
&lt;br /&gt;
=== Methoden responsive mocken ===&lt;br /&gt;
Die oben vorgestellten Verfahren liefern bei jedem Methoden-Aufruf feste Werte die bei der Mock-Definition festgelegt werden.&lt;br /&gt;
Oft ist es aber erforderlich, daß bei Aufruf der gemockten Methode Werte zurückgeliefert die aus den Argumenten errechnet werden.&lt;br /&gt;
Oder es ist erforderlich, daß die gemockte Methode irgendwelche Aktivitäten ausführt.&lt;br /&gt;
&lt;br /&gt;
Mit den genannten Verfahren ist das nicht möglich, man benötigt eine &amp;quot;Answer&amp;quot;. Dazu stehen zwei Varianten&lt;br /&gt;
zur Verfügung die sich in der Reihenfolge der Definition unterscheiden. Welche Variante man bevorzugt ist in vielen&lt;br /&gt;
Fällen unerheblich, when ... thenAnswer ist vielleicht etwas &amp;quot;intuitiver&amp;quot;. Keine Wahl hat man, wenn man eine &lt;br /&gt;
void-Methode mocken möchte. Auch beim Mocken einzelner Methoden eines [[Partieller_Mock|Spys]] muß man die zweite Variante verwenden.&lt;br /&gt;
Als Beispiel sei für das Interface&lt;br /&gt;
{{java|code=&lt;br /&gt;
public interface Transform {&lt;br /&gt;
    String calc(int value);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
ein Mock definiert durch:&lt;br /&gt;
{{java|code=Transform trans = Mockito.mock(Transform.class);}}&lt;br /&gt;
&lt;br /&gt;
Um das Verhalten der Methode {{java|calc}} zu definieren bauen wir ein Objekt vom Typ {{java|Answer&amp;lt;T&amp;gt;}}.&lt;br /&gt;
Der Typ {{java|T}} wird ersetzt durch den Ergebnis-Typ der zu mockenden Methode -- in diesem Falle {{java|String}}.&lt;br /&gt;
&lt;br /&gt;
Das {{java|Answer&amp;lt;T&amp;gt;}}-Objekt muß eine Methode überschreiben die ein Objekt der Klasse {{java|InvocationOnMock}}&lt;br /&gt;
als Argument nimmt. Über dieses Objekt erhalten wir Informtionen zu den Argumenten beim Aufruf der Mock-Methode.&lt;br /&gt;
Wir können sie mit der Methode {{java|getArgument}} über ihren Index abrufen, der Index beginnt bei 0.&lt;br /&gt;
Für die weiteren Methoden der Klasse sei auf die API-Dokumentation verwiesen.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir dazu eine konkrete Implementierung.&lt;br /&gt;
&lt;br /&gt;
==== when ... thenAnswer ====&lt;br /&gt;
Die erste Variante nennt &#039;&#039;erst&#039;&#039; den Mock und &#039;&#039;dann&#039;&#039; die zu mockende Methode:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Mockito.when(trans.calc(Mockito.anyString())).thenAnswer(new Answer&amp;lt;String&amp;gt;() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public String answer(InvocationOnMock invocation) throws Throwable {&lt;br /&gt;
        Integer value = invocation.getArgument(0);&lt;br /&gt;
        return value.toString();&lt;br /&gt;
    }&lt;br /&gt;
});&lt;br /&gt;
}}&lt;br /&gt;
Mit Java-8 läßt sich die anonyme Klasse auch eleganter mit einem {{lambda}}-Ausdruck schreiben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Mockito.when(trans.calc(Mockito.anyString())).thenAnswer(&lt;br /&gt;
   (Answer&amp;lt;String&amp;gt;) invocation -&amp;gt; {&lt;br /&gt;
       Integer value = invocation.getArgument(0);&lt;br /&gt;
       return value.toUpperCase();&lt;br /&gt;
   }&lt;br /&gt;
);&lt;br /&gt;
}}&lt;br /&gt;
Der Ergebnis-Typ von {{java|getArgument}} wird hier durch die Variable bestimmt der das Ergebnis zugewiesen wird.&lt;br /&gt;
Ob die Argument-Typen tatsächlich übereinstimmen, kann Java zur Compile-Zeit leider nicht kontrollieren.&lt;br /&gt;
Der Entwickler muß also selber darauf achten, daß alle Typen korrekt angegeben werden.&lt;br /&gt;
&lt;br /&gt;
Im Gegensatz zur anonymen-Klasse-Variante kann im {{lambda}}-Ausdruck der Ergebnis-Typ {{java|Answer&amp;lt;String&amp;gt;}} &lt;br /&gt;
weggelassen werden. Man sollte ihn aber trotzdem hinschreiben, damit der Typ dokumentiert ist – man tut sich damit&lt;br /&gt;
bei der Fehlersuche erheblich leichter.&lt;br /&gt;
&lt;br /&gt;
In den obigen Beispielen werden die Argumente vor Gebrauch in lokale Variablen abgefüllt, bevor diese im return-Ausdruck&lt;br /&gt;
verwendet werden. Das ist in der Regel nicht erforderlich, man kann die Typen von der Java-Magie bestimmern lassen.&lt;br /&gt;
Die geschwätzige Variante mit den lokalen Variablen hat aber den Vorteil, daß die Typen auf den ersten Blick zu erkennen&lt;br /&gt;
sind. Werden schrecklich Methoden mit vielen Parametern aufgerufen, wird das schnell zum Geduldspiel.&lt;br /&gt;
&lt;br /&gt;
==== doAnswer ... when ====&lt;br /&gt;
Bei dieser Variante wird &#039;&#039;erst&#039;&#039; die Answer definiert und &#039;&#039;hinterher&#039;&#039; der Mock und die aufzurufende Methode.&lt;br /&gt;
Auch hier gewinnt der Aufruf durch die Verwendung von {{lambda}}-Ausdrücken durchaus an Lesbarkeit --&lt;br /&gt;
wir lassen die konventionelle Variante diesmal weg:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Mockito.doAnswer(&lt;br /&gt;
    (Answer&amp;lt;String&amp;gt;) invocation -&amp;gt; {&lt;br /&gt;
        Integer value = invocation.getArgument(0);&lt;br /&gt;
        return value.toString();&lt;br /&gt;
    }&lt;br /&gt;
).when(trans.calc(Mockito.anyString()));&lt;br /&gt;
}}&lt;br /&gt;
Das Konstrukt funktioniert genauso wie das im vorangegangenen Abschnitt beschrieben.&lt;br /&gt;
&lt;br /&gt;
Allerdings kann man den Aufruf auch subtil anders gestalten (hier wird nur die {{lambda}}-Variante wiedergegeben):&lt;br /&gt;
{{java|code=&lt;br /&gt;
Mockito.doAnswer(&lt;br /&gt;
    (Answer&amp;lt;String&amp;gt;) invocation -&amp;gt; {&lt;br /&gt;
        Integer value = invocation.getArgument(0);&lt;br /&gt;
        return value.toString();&lt;br /&gt;
    }&lt;br /&gt;
).when(trans).calc(Mockito.anyString());&lt;br /&gt;
}}&lt;br /&gt;
Der Unterschied liegt in der letzten Zeile. Im ersten Falle wird {{java|.when()}} mit dem Mock der gemockten &#039;&#039;Methode&#039;&#039; aufgerufen.&lt;br /&gt;
Im zweiten Falle wird {{java|.when()}} mit dem Mock der gemockten &#039;&#039;Klasse&#039;&#039; aufgerufen. Die zweite Variante macht das&lt;br /&gt;
Mocking von void-Methoden möglich und erlaubt, einzelne Methoden von Spy-Objekten zu mocken und damit [[Partieller Mock|partielle Mocks]] zu erzeugen.&lt;br /&gt;
&lt;br /&gt;
=== void-Methoden: Methoden ohne Ergebnis ===&lt;br /&gt;
Eine void-Methode ist eine Methode, die kein Ergebnis liefert – was sollte man hier mocken?&lt;br /&gt;
Betrachten wir dazu folgendes Beispiel:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public class CustomerManager {&lt;br /&gt;
    public void save(Customer customer) {&lt;br /&gt;
        getDatabaseLink().merge(customer);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Die {{java|save}}-Methode nimmt als Parameter ein Entity und persistiert dessen Inhalt in der Datenbank. &lt;br /&gt;
Das ist etwas, was wir im Unit-Test normalerweise nicht tun möchten. Wir würden stattdessen &lt;br /&gt;
den vielleicht den Aufruf protokollieren oder die Persistierung in einem Java-Objekt emulieren.&lt;br /&gt;
&lt;br /&gt;
Beim Mocking geht es also darum, beim Ausführen der gemockten void-Methode einen Seiteneffekt herbeizuführen.&lt;br /&gt;
Wie bereits beschrieben, giebt es prinzipiell zwei Muster nach denen sich in Mockito Methoden-Verhalten&lt;br /&gt;
implementieren läßt. Im Falle von void-Methoden fällt das when...then-Pattern jedoch aus, da die&lt;br /&gt;
Methode {{java|Mockito.when()}} keine void-Methoden verdauen kann.&lt;br /&gt;
&lt;br /&gt;
Wir erzeugen also erstmal einen Mock:&lt;br /&gt;
{{java|code=Transform mock = Mockito.mock(CustomerManager.class);}}&lt;br /&gt;
und definieren die Antwort so:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Mockito.doAnswer(new Answer&amp;lt;Void&amp;gt;() {&lt;br /&gt;
    @Override&lt;br /&gt;
    public Void answer(InvocationOnMock invocation) throws Throwable {&lt;br /&gt;
        // Seiteneffekt&lt;br /&gt;
        return null;&lt;br /&gt;
    }&lt;br /&gt;
}).when(mock).save(Mockito.any(Customer.class));&lt;br /&gt;
}}&lt;br /&gt;
Der Trick ist die Verwendung der – übrigens schon seit JDK 1.1 existierenden – Klasse {{java|Void}}(mit großem Vau).&lt;br /&gt;
Zu jedem primitiven Typ gibt es in Java eine passende Wrapper-Klasse; ein Analogon hat der Ergebnis-Typ {{java|void}} in der&lt;br /&gt;
{{java|Void}}-Klasse. Da es keine {{java|void}}-Werte giebt, giebt es auch keine Instanzen der {{java|Void}}-Klasse;&lt;br /&gt;
die Klasse selbst gibt es aber und hier finden wir eine Gelegenheit sie zu nutzen: wir definieren damit den Ergebnis-Typ&lt;br /&gt;
der Answer-Methode. &lt;br /&gt;
&lt;br /&gt;
Da {{java|Void}} – im Gegensatz zu {{java|void}} – eine Klasse ist, muß die {{java|answer}}-Methode ein Ergebnis liefern und&lt;br /&gt;
benötigt daher am Ende die Anweisung {{java|return null}}.&lt;br /&gt;
&lt;br /&gt;
Natürlich läßt sich das auch mit einem {{lambda}}-Ausdruck schreiben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
Mockito.doAnswer((Answer&amp;lt;Void&amp;gt;) invocation -&amp;gt; {&lt;br /&gt;
    // Seiteneffekt&lt;br /&gt;
    return null;&lt;br /&gt;
}).when(mock).save(Mockito.any(Customer .class));&lt;br /&gt;
}}&lt;br /&gt;
=== Methoden die Class-Objekte liefern ===&lt;br /&gt;
Dieses Problem wird [[Mockito: Methoden die Class-Objekte liefern|hier]] beschrieben&lt;br /&gt;
=== Methoden mit Variablen Argument-Listen ===&lt;br /&gt;
Weichen wir mal der Diskussion aus, ob Var-Arg-Methoden schön, sinnvoll oder wünschenswert sind und welche&lt;br /&gt;
Probleme sie mit sich bringen (könnten). Nehmen wir einfach an, wir hätten so ein Ding und &#039;&#039;müßten&#039;&#039; es mocken -- wie geht das?&lt;br /&gt;
Die Methode {{java|process}} akzeptiere eine beliebige Anzahl von {{java|Customer}}-Objekten, tue irgendwas damit und liefere&lt;br /&gt;
die Anzahl der verarbeiteten Objekte.&lt;br /&gt;
{{java|code=&lt;br /&gt;
public interface Transform {&lt;br /&gt;
    int process(Customer... customer);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Wie bereits beschrieben, können wir über ein Objekt der Klasse {{java|InvocationOnMock}} auf die Argumente zugreifen&lt;br /&gt;
die beim Aufruf der gemockten Methode übergeben werden. Die vararg-Argumente erhalten wir so als array und können z.B.&lt;br /&gt;
mit einer for-Schleife darüber iterieren. Versuchen wir es hier etwas hübscher aussehen zu lassen, indem wir das array in&lt;br /&gt;
eine typisierte Liste überführen.&lt;br /&gt;
&lt;br /&gt;
Wir schreiben zunächst die Mock-Methode mit dem doAnswer...when-Pattern:&lt;br /&gt;
{{java|code=&lt;br /&gt;
void test() {&lt;br /&gt;
    Mockito.doAnswer(new Answer&amp;lt;Integer&amp;gt;() {&lt;br /&gt;
        @Override&lt;br /&gt;
        public Integer answer(InvocationOnMock invocation) throws Throwable {&lt;br /&gt;
            List&amp;lt;Customer&amp;gt; kunden = argliste(invocation.getArguments());&lt;br /&gt;
            return kunden.size();&lt;br /&gt;
        }&lt;br /&gt;
    }).when(mock).process(Mockito.any());&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Und nun zur {{java|.argliste()}}-Methode, die das Object-array in ein {{java|List&amp;lt;Customer&amp;gt;}}-Objekt umwandelt. Es giebt&lt;br /&gt;
viele Möglichkeiten, die elegantesten arbeitet natürlich mit einem Stream. Das Delikate daran ist das erforderliche Casting, wir&lt;br /&gt;
verwenden dazu die .class-Klasse für die Customer-Klasse:&lt;br /&gt;
{{java|code=&lt;br /&gt;
List&amp;lt;Customer&amp;gt; argliste(Object liste[]) {&lt;br /&gt;
    return Stream.of(liste)&lt;br /&gt;
        .filter(Customer.class::isInstance)&lt;br /&gt;
        .map(Customer.class::cast)&lt;br /&gt;
        .collect(Collectors.toList());&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Was hierbei nicht offensichtlich ist, ist daß die {{java|arguments}}-Methode von {{java|InvocationOnMock}}&lt;br /&gt;
&#039;&#039;alle&#039;&#039; Argumente liefert –- nicht nur die vararg-Argumente. Im folgenden Beispiel&lt;br /&gt;
{{java|int process(String beschreibung, Customer... customer);}}&lt;br /&gt;
liefert {{java|.arguments()[0]}} das Argument für den String-Parameter und erst ab {{java|.arguments()[1]}} kommen die vararg-Argumente.&lt;br /&gt;
Die obige Methode {{java|argliste}} funktioniert auch in diesem Falle unmittelbar, weil der nicht-variable Teil der ParameterListe&lt;br /&gt;
keine {{java|Customer}}-Objekte enthält. Das String-Argument wird einfach herausgefiltert.&lt;br /&gt;
Anders sieht es in diesem Beispiel aus:&lt;br /&gt;
{{java|code=int process(Customer referenz, String beschreibung, Customer... customer);}}&lt;br /&gt;
Offensichtlich soll das erste Customer-Objekt anders behandelt werden als die der vararg-Liste. Aber auch das geht&lt;br /&gt;
mit Streams ganz einfach. Wir müssen ja nur die ersten beiden Argumente bei der Verarbeitung überspringen; das&lt;br /&gt;
geht mit der {{java|.skip()}}-Methode:&lt;br /&gt;
{{java|code=&lt;br /&gt;
List&amp;lt;Customer&amp;gt; argliste(Object liste[]) {&lt;br /&gt;
    return Stream.of(liste)&lt;br /&gt;
        .skip(2)&lt;br /&gt;
        .filter(Customer.class::isInstance)&lt;br /&gt;
        .map(Customer.class::cast)&lt;br /&gt;
        .collect(Collectors.toList());&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Und wenn wir die Methode noch öfter brauchen, können wir den start-Index (beginnend bei 0) und das verwendete&lt;br /&gt;
{{java|Class}}-Objekt noch parametrisieren:&lt;br /&gt;
{{java|code=&lt;br /&gt;
&amp;lt;T&amp;gt; List&amp;lt;T&amp;gt; argliste(Object liste[], int startIndex, Class&amp;lt;T&amp;gt; klasse) {&lt;br /&gt;
    return Stream.of(liste)&lt;br /&gt;
        .skip(startIndex)&lt;br /&gt;
        .filter(klasse::isInstance)&lt;br /&gt;
        .map(klasse::cast)&lt;br /&gt;
        .collect(Collectors.toList());&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Diese letzte Variante können wir nun für das Mocking jeder Varag-Methode für jeden Varag-Typ verwenden.&lt;br /&gt;
&lt;br /&gt;
== Abstrakte Klassen mocken ==&lt;br /&gt;
Der gemeine Mockito-Mock ersetzt alle Methoden der gemockten Klasse durch leere Mock-Aufrufe die –&lt;br /&gt;
defaultmäßig – gar nichts tun. Das kann man verhindern durch Angabe eines zusätzlichen Parameters:&lt;br /&gt;
{{java|code=MeineKlasse meinMock = mock(MeineKlasse.class, Mockito.CALLS_REAL_METHODS);}}&lt;br /&gt;
&lt;br /&gt;
Wird jetzt eine Methode des Mocks aufgerufen, ruft dieser die originale Methode der Klasse {{java|MeineKlasse}} auf.&lt;br /&gt;
Anschließend kann man einzelne Methoden mocken und so einen partiellen Mock zu erzeugen.&lt;br /&gt;
Bei abstrakten Klassen tritt der Mock in&#039;s leere, sobald eine abstrakte Methode aufgerufen wird, weil es für diese&lt;br /&gt;
naturgemäß keine &amp;quot;echte&amp;quot; Methode giebt, die aufgerufen werden könnte. Um eine abstrakte Klasse so zu mocken,&lt;br /&gt;
daß genau die abstrakten Methoden gemockt werden, muß man also jede abstrakte Methode durch eine mock-Methode ersetzen – wie öde...&lt;br /&gt;
Mit der folgenden Klasse kann man das – Reflection sei dank – vollautomatisch erledigen lassen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
import java.lang.reflect.Modifier;&lt;br /&gt;
...&lt;br /&gt;
public class MockerForAbstractMethods implements Answer&amp;lt;Object&amp;gt; {&lt;br /&gt;
    @Override&lt;br /&gt;
    public Object answer(InvocationOnMock invocation) throws Throwable {&lt;br /&gt;
        if (Modifier.isAbstract(invocation.getMethod().getModifiers())) {&lt;br /&gt;
            return Mockito.RETURNS_DEFAULTS.answer(invocation);&lt;br /&gt;
        }&lt;br /&gt;
        return Mockito.CALLS_REAL_METHODS.answer(invocation);&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Diese Klasse legt man an geeigneter Stelle ab, irgendwo im test-Ordner des Projekts. Die Anwendung im Unit-Tests&lt;br /&gt;
sieht dann so aus:&lt;br /&gt;
{{java|code=MeineKlasse meinMock = mock(MeineKlasse.class, new MockerForAbstractMethods());}}&lt;br /&gt;
&lt;br /&gt;
Das Objekt prüft bei jedem Aufruf ob da eine abstrakte Methode aufgerufen wird und ersetzt den Aufruf durch einen&lt;br /&gt;
Mock-Aufruf. Ist die Methode nicht abstrakt, wird die &amp;quot;echte&amp;quot; Methode aufgerufen. Um das ganze in der Anwendung&lt;br /&gt;
etwas gefälliger zu machen, kann man die Instanz statisch erzeugen und eine Konstante dafür definieren:&lt;br /&gt;
{{java|code=public static final Answer&amp;lt;Object&amp;gt; MOCK_ABSTRACT_METHODS = new MockerForAbstractMethod();}}&lt;br /&gt;
Die Konstante kann man statisch importieren und dann schreiben:&lt;br /&gt;
{{java|code=MeineKlasse meinMock = mock(MeineKlasse.class, MOCK_ABSTRACT_METHODS);}}&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=175</id>
		<title>Java 17: Records</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=175"/>
		<updated>2023-10-21T19:00:45Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Komplexe Zahlen */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
== Records ==&lt;br /&gt;
Der {{java|record}} ist eine neue Java-Komponente die auf einer Ebene liegt mit Klassen und Interfaces.&lt;br /&gt;
Man kann ihn beschreiben als eine nicht ableitbare Klasse unveränderlicher (immutable) Objekte.&lt;br /&gt;
&lt;br /&gt;
Das schöne am {{java|record}} ist, daß er eine ganze Reihe von default-Implementierungen bietet,&lt;br /&gt;
ohne daß man den ganzen boiler plate code dazu tippen muß.&lt;br /&gt;
Die Deklaration erfolgt nicht mit dem Keyword {{java|class}}, sondern mit dem [[Keywords|context keyword]] {{java|record}}.&lt;br /&gt;
&lt;br /&gt;
Hier ist eine ganz einfache Deklaration:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public record Kilometer(double dist) {};&lt;br /&gt;
}}&lt;br /&gt;
Was bietet uns der record {{java|Kilometer}}?&lt;br /&gt;
&lt;br /&gt;
* Ein {{java|Kilometer}}-Objekt hat ein einziges Feld {{java|dist}} from Typ {{java|double}}&lt;br /&gt;
* Objekte werden erzeugt über {{java|new Kilometer(42.195)}}&lt;br /&gt;
* Auf den Wert wird zugegriffen über den Getter {{java|dist()}}&lt;br /&gt;
* Die Methode {{java|toString()}} liefert etwas wie &amp;quot;Kilometer [dist=42.195]&amp;quot;&lt;br /&gt;
* Die Methoden {{java|equals}} und {{java|hashCode}} werden -- gemäß Kontrakt implementiert&lt;br /&gt;
&lt;br /&gt;
All&#039; das erzeugt der Compiler automatisch.&lt;br /&gt;
Natürlich ist die Erzeugungung von records mit beliebig vielen Feldern möglich,&lt;br /&gt;
weiter unten ist eine Beispiel mit zwei Feldern geschrieben.&lt;br /&gt;
&lt;br /&gt;
Was kann man nun mit dem {{java|record}} anstellen?&lt;br /&gt;
&lt;br /&gt;
Neben der offensichtlichen Möglichkeit, damit Data-Container ohne großen Overhead zu generieren,&lt;br /&gt;
Kann man damit auch eigene Datentypen definieren. Denn ein {{java|record}} kann -- wie jede andere Klasse auch --&lt;br /&gt;
statische und nicht-statische Methoden enthalten. Das Einzige was nicht erlaubt ist, ist die Definition von nicht-statischen Feldern.&lt;br /&gt;
Mit anderen Worten:&lt;br /&gt;
{{quote|Der Status eines record-Objektes wird durch die initiale Befüllung der implizit definierten Felder bestimmt und ändert sich niemals.}}&lt;br /&gt;
&lt;br /&gt;
=== Nur syntaktischer Zucker? ===&lt;br /&gt;
Records lassen uns also eine ganze Menge Code sparen, aber strenggenommen können wir damit nicht mehr machen&lt;br /&gt;
als mit klassischen Klassen bereits möglich war. Lohnt sich die Erweiterung dann überhaupt&lt;br /&gt;
&lt;br /&gt;
Tatsächlich sind Records zunächst Java-Klassen, allerdings haben sie ein eigenes Flag&lt;br /&gt;
das sie für die JVM von normalen Klassen unterscheidbar macht. Sie werden von der JVM anders behandelt, sind effizienter&lt;br /&gt;
und können beim Optimieren der JVM noch besser gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== Komplexe Zahlen ===&lt;br /&gt;
Ein ganz hübsches Beispiel ist die Definition [https://de.wikipedia.org/wiki/Komplexe_Zahl komplexer Zahlen].&lt;br /&gt;
Die Deklaration sieht zunächst so aus:&lt;br /&gt;
{{java | code=&lt;br /&gt;
 public record Complex(double real, double img) {&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der reale Anteil wird mit {{java|real}} bezeichnet, der imaginäre -- wir sind tippfaul -- mit {{java|img}}.&lt;br /&gt;
Sie werden mit den Gettern {{java|real()}} und {{java|img()}} angefragt. Der Compiler erzeugt uns einen Konstruktor&lt;br /&gt;
mit zwei {{java|double}}-Werten die der Reihenfolge der Deklaration entsprechen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
  public Complex(double real, double img) {&lt;br /&gt;
     this.real = real;&lt;br /&gt;
     this.img = img;&lt;br /&gt;
  }&lt;br /&gt;
}}&lt;br /&gt;
Jetzt können wir Methoden implementieren um mit den Zahlen zu rechnen -- etwa die Addition:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public Complex plus(Complex b) {&lt;br /&gt;
        return new Complex(this.real + b.real, this.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Da record-Objekte nicht verändert werden können, wird bei der Addition jedesmal ein neues Objekt erzeugt.&lt;br /&gt;
Das ist typisch für immutable objects und  entspricht auch der Implementierung  von Klassen wie {{java|LocalDate}}.&lt;br /&gt;
&lt;br /&gt;
Die Additions-Methode lternativ könnte man auch statisch definieren:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public static Complex plus(Complex a, Complex b) {&lt;br /&gt;
        return new Complex(a.real + b.real, a.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Will man keine extra-Methode für die Ausgabe implementieren, kann man für eine hübschere Ausgabe die {{java|toString}}-Methode überschreiben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    @Override&lt;br /&gt;
    public String toString() {&lt;br /&gt;
        return real + &amp;quot; + &amp;quot; + img + &amp;quot;i&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Warum ist das cool? Mit herkömmlichen Klassen ist das schon seit Java 1.1 möglich?&lt;br /&gt;
&lt;br /&gt;
# Der Code wird sehr übersichtlich, weil Java uns eine ganze Menge abnimmt&lt;br /&gt;
# Die Objekte sind immutable, ohne daß dafür irgendwelche Maßnahmen erforderlich wären&lt;br /&gt;
# Die Java-VM kann die Verarbeitung der records in diesem Sinne optimieren&lt;br /&gt;
&lt;br /&gt;
Den kompletten Code [https://github.com/mletkin/java17/blob/main/src/main/java/org/mletkin/java17/rec/Complex.java giebt&#039;s hier].&lt;br /&gt;
&lt;br /&gt;
=== Integrierte Validierung ===&lt;br /&gt;
Um eine eMail-Adresse zu speichern verwenden die meisten Entwickler den Java-Typ {{java|String}}.&lt;br /&gt;
Das ist grundsätzlich verkehrt, wenn man die die Zeichenkette &amp;quot;balfasel&amp;quot; betrachtet, denn das ist definitiv keine keine gültige eMail-Adresse.&lt;br /&gt;
&lt;br /&gt;
Weil ein String immer gegene einen beliebigen anderen String ausgetauscht werden kann, muß der String vor jeder Verwednung&lt;br /&gt;
daraufhin geprüft werden ob er tatsächlich eine gültige eMail-Adresse enthält. Stellen wir uns eine Anwendung vor die ganz am Anfang&lt;br /&gt;
eine eMail-Adresse beschafft und dann durch viele Schichten durchreicht bevor sie denn endlich irgendwann verwendet wird.&lt;br /&gt;
Wenn sich dann tatsächlich herausstellt, daß die eMail-Adresse korrupt ist, was macht man dann mit dem Fehler?&lt;br /&gt;
&lt;br /&gt;
Der objektorientierte Weg ist -- auch hier -- den String in einer eigenen Klasse zu kapseln.&lt;br /&gt;
Dazu hat keine Entwickler lust. Niemand mag den ganzen Code schreiben, niemand mag die mögliche Performance-Einbuße in kauf nehmen.&lt;br /&gt;
&lt;br /&gt;
Java 17 diesen Ausreden mit dem {{java|record}} ein Ende.&lt;br /&gt;
&lt;br /&gt;
Folgende einfache Impementierung verdeutlicht die Idee&lt;br /&gt;
{{java|code=&lt;br /&gt;
public record EmailAdress(String adr) {&lt;br /&gt;
   public EmailAdress(String adr) {&lt;br /&gt;
        if (!(adr == null &amp;amp;&amp;amp; adr.contains(&amp;quot;@&amp;quot;)));&lt;br /&gt;
            throw new RuntimeException(&amp;quot;not an eMail address: &amp;quot; + adr);&lt;br /&gt;
        }&lt;br /&gt;
        this.adr = adr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Genau wie der default-Konstruktor kann auch der für den {{java|record}} vom Compiler automatisch erzeugte Konstruktur&lt;br /&gt;
durch einen Selbstgeschriebenen ersetzt werden. Im obigen Beispiel wird das {{java|record}}-Objekt nur dann erzeugt,&lt;br /&gt;
wenn der als eMail-Adresse angebotene String eine Affenschaukel enthält.&lt;br /&gt;
&lt;br /&gt;
Der Beispiel-Code ist auf [https://github.com/mletkin/java17/tree/main/src/main/java/org/mletkin/java17/rec GitHub] zu finden.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Vorlage:Java&amp;diff=174</id>
		<title>Vorlage:Java</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Vorlage:Java&amp;diff=174"/>
		<updated>2023-10-21T18:59:13Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Änderung 173 von Ullrich (Diskussion) rückgängig gemacht.&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#if: {{{code|}}} | {{#tag:pre|{{{code}}}}} | &amp;lt;code&amp;gt;{{{1}}}&amp;lt;/code&amp;gt;}}&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Vorlage:Java&amp;diff=173</id>
		<title>Vorlage:Java</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Vorlage:Java&amp;diff=173"/>
		<updated>2023-10-21T18:56:35Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;{{#if: {{{code|}}} | {{#tag:syntaxhighlight|{{{code}}}|lang=java}} | &amp;lt;code&amp;gt;{{{1}}}&amp;lt;/code&amp;gt;}}&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=172</id>
		<title>Java 17: Records</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=172"/>
		<updated>2023-10-21T18:39:02Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: /* Integrierte Validierung */&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
== Records ==&lt;br /&gt;
Der {{java|record}} ist eine neue Java-Komponente die auf einer Ebene liegt mit Klassen und Interfaces.&lt;br /&gt;
Man kann ihn beschreiben als eine nicht ableitbare Klasse unveränderlicher (immutable) Objekte.&lt;br /&gt;
&lt;br /&gt;
Das schöne am {{java|record}} ist, daß er eine ganze Reihe von default-Implementierungen bietet,&lt;br /&gt;
ohne daß man den ganzen boiler plate code dazu tippen muß.&lt;br /&gt;
Die Deklaration erfolgt nicht mit dem Keyword {{java|class}}, sondern mit dem [[Keywords|context keyword]] {{java|record}}.&lt;br /&gt;
&lt;br /&gt;
Hier ist eine ganz einfache Deklaration:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public record Kilometer(double dist) {};&lt;br /&gt;
}}&lt;br /&gt;
Was bietet uns der record {{java|Kilometer}}?&lt;br /&gt;
&lt;br /&gt;
* Ein {{java|Kilometer}}-Objekt hat ein einziges Feld {{java|dist}} from Typ {{java|double}}&lt;br /&gt;
* Objekte werden erzeugt über {{java|new Kilometer(42.195)}}&lt;br /&gt;
* Auf den Wert wird zugegriffen über den Getter {{java|dist()}}&lt;br /&gt;
* Die Methode {{java|toString()}} liefert etwas wie &amp;quot;Kilometer [dist=42.195]&amp;quot;&lt;br /&gt;
* Die Methoden {{java|equals}} und {{java|hashCode}} werden -- gemäß Kontrakt implementiert&lt;br /&gt;
&lt;br /&gt;
All&#039; das erzeugt der Compiler automatisch.&lt;br /&gt;
Natürlich ist die Erzeugungung von records mit beliebig vielen Feldern möglich,&lt;br /&gt;
weiter unten ist eine Beispiel mit zwei Feldern geschrieben.&lt;br /&gt;
&lt;br /&gt;
Was kann man nun mit dem {{java|record}} anstellen?&lt;br /&gt;
&lt;br /&gt;
Neben der offensichtlichen Möglichkeit, damit Data-Container ohne großen Overhead zu generieren,&lt;br /&gt;
Kann man damit auch eigene Datentypen definieren. Denn ein {{java|record}} kann -- wie jede andere Klasse auch --&lt;br /&gt;
statische und nicht-statische Methoden enthalten. Das Einzige was nicht erlaubt ist, ist die Definition von nicht-statischen Feldern.&lt;br /&gt;
Mit anderen Worten:&lt;br /&gt;
{{quote|Der Status eines record-Objektes wird durch die initiale Befüllung der implizit definierten Felder bestimmt und ändert sich niemals.}}&lt;br /&gt;
&lt;br /&gt;
=== Nur syntaktischer Zucker? ===&lt;br /&gt;
Records lassen uns also eine ganze Menge Code sparen, aber strenggenommen können wir damit nicht mehr machen&lt;br /&gt;
als mit klassischen Klassen bereits möglich war. Lohnt sich die Erweiterung dann überhaupt&lt;br /&gt;
&lt;br /&gt;
Tatsächlich sind Records zunächst Java-Klassen, allerdings haben sie ein eigenes Flag&lt;br /&gt;
das sie für die JVM von normalen Klassen unterscheidbar macht. Sie werden von der JVM anders behandelt, sind effizienter&lt;br /&gt;
und können beim Optimieren der JVM noch besser gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== Komplexe Zahlen ===&lt;br /&gt;
Ein ganz hübsches Beispiel ist die Definition [https://de.wikipedia.org/wiki/Komplexe_Zahl komplexer Zahlen].&lt;br /&gt;
Die Deklaration sieht zunächst so aus:&lt;br /&gt;
{{java | code=&lt;br /&gt;
 public record Complex(double real, double img) {&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der reale Anteil wird mit {{java|real}} bezeichnet, der imaginäre -- wir sind tippfaul -- mit {{java|img}}.&lt;br /&gt;
Sie werden mit den Gettern {{java|real()}} und {{java|img()}} angefragt. Der Compiler erzeugt uns einen Konstruktor&lt;br /&gt;
mit zwei {{java|double}}-Werten die der Reihenfolge der Deklaration entsprechen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public Complex(double real, double img) {&lt;br /&gt;
     this.real = real;&lt;br /&gt;
     this.img = img;&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Jetzt können wir Methoden implementieren um mit den Zahlen zu rechnen -- etwa die Addition:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public Complex plus(Complex b) {&lt;br /&gt;
        return new Complex(this.real + b.real, this.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Da record-Objekte nicht verändert werden können, wird bei der Addition jedesmal ein neues Objekt erzeugt.&lt;br /&gt;
Das ist typisch für immutable objects und  entspricht auch der Implementierung  von Klassen wie {{java|LocalDate}}.&lt;br /&gt;
&lt;br /&gt;
Die Additions-Methode lternativ könnte man auch statisch definieren:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public static Complex plus(Complex a, Complex b) {&lt;br /&gt;
        return new Complex(a.real + b.real, a.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Will man keine extra-Methode für die Ausgabe implementieren, kann man für eine hübschere Ausgabe die {{java|toString}}-Methode überschreiben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    @Override&lt;br /&gt;
    public String toString() {&lt;br /&gt;
        return real + &amp;quot; + &amp;quot; + img + &amp;quot;i&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Warum ist das cool? Mit herkömmlichen Klassen ist das schon seit Java 1.1 möglich?&lt;br /&gt;
&lt;br /&gt;
# Der Code wird sehr übersichtlich, weil Java uns eine ganze Menge abnimmt&lt;br /&gt;
# Die Objekte sind immutable, ohne daß dafür irgendwelche Maßnahmen erforderlich wären&lt;br /&gt;
# Die Java-VM kann die Verarbeitung der records in diesem Sinne optimieren&lt;br /&gt;
&lt;br /&gt;
Den kompletten Code [https://github.com/mletkin/java17/blob/main/src/main/java/org/mletkin/java17/rec/Complex.java giebt&#039;s hier].&lt;br /&gt;
&lt;br /&gt;
=== Integrierte Validierung ===&lt;br /&gt;
Um eine eMail-Adresse zu speichern verwenden die meisten Entwickler den Java-Typ {{java|String}}.&lt;br /&gt;
Das ist grundsätzlich verkehrt, wenn man die die Zeichenkette &amp;quot;balfasel&amp;quot; betrachtet, denn das ist definitiv keine keine gültige eMail-Adresse.&lt;br /&gt;
&lt;br /&gt;
Weil ein String immer gegene einen beliebigen anderen String ausgetauscht werden kann, muß der String vor jeder Verwednung&lt;br /&gt;
daraufhin geprüft werden ob er tatsächlich eine gültige eMail-Adresse enthält. Stellen wir uns eine Anwendung vor die ganz am Anfang&lt;br /&gt;
eine eMail-Adresse beschafft und dann durch viele Schichten durchreicht bevor sie denn endlich irgendwann verwendet wird.&lt;br /&gt;
Wenn sich dann tatsächlich herausstellt, daß die eMail-Adresse korrupt ist, was macht man dann mit dem Fehler?&lt;br /&gt;
&lt;br /&gt;
Der objektorientierte Weg ist -- auch hier -- den String in einer eigenen Klasse zu kapseln.&lt;br /&gt;
Dazu hat keine Entwickler lust. Niemand mag den ganzen Code schreiben, niemand mag die mögliche Performance-Einbuße in kauf nehmen.&lt;br /&gt;
&lt;br /&gt;
Java 17 diesen Ausreden mit dem {{java|record}} ein Ende.&lt;br /&gt;
&lt;br /&gt;
Folgende einfache Impementierung verdeutlicht die Idee&lt;br /&gt;
{{java|code=&lt;br /&gt;
public record EmailAdress(String adr) {&lt;br /&gt;
   public EmailAdress(String adr) {&lt;br /&gt;
        if (!(adr == null &amp;amp;&amp;amp; adr.contains(&amp;quot;@&amp;quot;)));&lt;br /&gt;
            throw new RuntimeException(&amp;quot;not an eMail address: &amp;quot; + adr);&lt;br /&gt;
        }&lt;br /&gt;
        this.adr = adr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Genau wie der default-Konstruktor kann auch der für den {{java|record}} vom Compiler automatisch erzeugte Konstruktur&lt;br /&gt;
durch einen Selbstgeschriebenen ersetzt werden. Im obigen Beispiel wird das {{java|record}}-Objekt nur dann erzeugt,&lt;br /&gt;
wenn der als eMail-Adresse angebotene String eine Affenschaukel enthält.&lt;br /&gt;
&lt;br /&gt;
Der Beispiel-Code ist auf [https://github.com/mletkin/java17/tree/main/src/main/java/org/mletkin/java17/rec GitHub] zu finden.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=171</id>
		<title>Java 17: Records</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=171"/>
		<updated>2023-10-21T18:37:44Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
== Records ==&lt;br /&gt;
Der {{java|record}} ist eine neue Java-Komponente die auf einer Ebene liegt mit Klassen und Interfaces.&lt;br /&gt;
Man kann ihn beschreiben als eine nicht ableitbare Klasse unveränderlicher (immutable) Objekte.&lt;br /&gt;
&lt;br /&gt;
Das schöne am {{java|record}} ist, daß er eine ganze Reihe von default-Implementierungen bietet,&lt;br /&gt;
ohne daß man den ganzen boiler plate code dazu tippen muß.&lt;br /&gt;
Die Deklaration erfolgt nicht mit dem Keyword {{java|class}}, sondern mit dem [[Keywords|context keyword]] {{java|record}}.&lt;br /&gt;
&lt;br /&gt;
Hier ist eine ganz einfache Deklaration:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public record Kilometer(double dist) {};&lt;br /&gt;
}}&lt;br /&gt;
Was bietet uns der record {{java|Kilometer}}?&lt;br /&gt;
&lt;br /&gt;
* Ein {{java|Kilometer}}-Objekt hat ein einziges Feld {{java|dist}} from Typ {{java|double}}&lt;br /&gt;
* Objekte werden erzeugt über {{java|new Kilometer(42.195)}}&lt;br /&gt;
* Auf den Wert wird zugegriffen über den Getter {{java|dist()}}&lt;br /&gt;
* Die Methode {{java|toString()}} liefert etwas wie &amp;quot;Kilometer [dist=42.195]&amp;quot;&lt;br /&gt;
* Die Methoden {{java|equals}} und {{java|hashCode}} werden -- gemäß Kontrakt implementiert&lt;br /&gt;
&lt;br /&gt;
All&#039; das erzeugt der Compiler automatisch.&lt;br /&gt;
Natürlich ist die Erzeugungung von records mit beliebig vielen Feldern möglich,&lt;br /&gt;
weiter unten ist eine Beispiel mit zwei Feldern geschrieben.&lt;br /&gt;
&lt;br /&gt;
Was kann man nun mit dem {{java|record}} anstellen?&lt;br /&gt;
&lt;br /&gt;
Neben der offensichtlichen Möglichkeit, damit Data-Container ohne großen Overhead zu generieren,&lt;br /&gt;
Kann man damit auch eigene Datentypen definieren. Denn ein {{java|record}} kann -- wie jede andere Klasse auch --&lt;br /&gt;
statische und nicht-statische Methoden enthalten. Das Einzige was nicht erlaubt ist, ist die Definition von nicht-statischen Feldern.&lt;br /&gt;
Mit anderen Worten:&lt;br /&gt;
{{quote|Der Status eines record-Objektes wird durch die initiale Befüllung der implizit definierten Felder bestimmt und ändert sich niemals.}}&lt;br /&gt;
&lt;br /&gt;
=== Nur syntaktischer Zucker? ===&lt;br /&gt;
Records lassen uns also eine ganze Menge Code sparen, aber strenggenommen können wir damit nicht mehr machen&lt;br /&gt;
als mit klassischen Klassen bereits möglich war. Lohnt sich die Erweiterung dann überhaupt&lt;br /&gt;
&lt;br /&gt;
Tatsächlich sind Records zunächst Java-Klassen, allerdings haben sie ein eigenes Flag&lt;br /&gt;
das sie für die JVM von normalen Klassen unterscheidbar macht. Sie werden von der JVM anders behandelt, sind effizienter&lt;br /&gt;
und können beim Optimieren der JVM noch besser gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== Komplexe Zahlen ===&lt;br /&gt;
Ein ganz hübsches Beispiel ist die Definition [https://de.wikipedia.org/wiki/Komplexe_Zahl komplexer Zahlen].&lt;br /&gt;
Die Deklaration sieht zunächst so aus:&lt;br /&gt;
{{java | code=&lt;br /&gt;
 public record Complex(double real, double img) {&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der reale Anteil wird mit {{java|real}} bezeichnet, der imaginäre -- wir sind tippfaul -- mit {{java|img}}.&lt;br /&gt;
Sie werden mit den Gettern {{java|real()}} und {{java|img()}} angefragt. Der Compiler erzeugt uns einen Konstruktor&lt;br /&gt;
mit zwei {{java|double}}-Werten die der Reihenfolge der Deklaration entsprechen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public Complex(double real, double img) {&lt;br /&gt;
     this.real = real;&lt;br /&gt;
     this.img = img;&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Jetzt können wir Methoden implementieren um mit den Zahlen zu rechnen -- etwa die Addition:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public Complex plus(Complex b) {&lt;br /&gt;
        return new Complex(this.real + b.real, this.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Da record-Objekte nicht verändert werden können, wird bei der Addition jedesmal ein neues Objekt erzeugt.&lt;br /&gt;
Das ist typisch für immutable objects und  entspricht auch der Implementierung  von Klassen wie {{java|LocalDate}}.&lt;br /&gt;
&lt;br /&gt;
Die Additions-Methode lternativ könnte man auch statisch definieren:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public static Complex plus(Complex a, Complex b) {&lt;br /&gt;
        return new Complex(a.real + b.real, a.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Will man keine extra-Methode für die Ausgabe implementieren, kann man für eine hübschere Ausgabe die {{java|toString}}-Methode überschreiben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    @Override&lt;br /&gt;
    public String toString() {&lt;br /&gt;
        return real + &amp;quot; + &amp;quot; + img + &amp;quot;i&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Warum ist das cool? Mit herkömmlichen Klassen ist das schon seit Java 1.1 möglich?&lt;br /&gt;
&lt;br /&gt;
# Der Code wird sehr übersichtlich, weil Java uns eine ganze Menge abnimmt&lt;br /&gt;
# Die Objekte sind immutable, ohne daß dafür irgendwelche Maßnahmen erforderlich wären&lt;br /&gt;
# Die Java-VM kann die Verarbeitung der records in diesem Sinne optimieren&lt;br /&gt;
&lt;br /&gt;
Den kompletten Code [https://github.com/mletkin/java17/blob/main/src/main/java/org/mletkin/java17/rec/Complex.java giebt&#039;s hier].&lt;br /&gt;
&lt;br /&gt;
=== Integrierte Validierung ===&lt;br /&gt;
Um eine eMail-Adresse zu speichern verwenden die meisten Entwickler den Java-Typ {{java|String}}.&lt;br /&gt;
Das ist grundsätzlich verkehrt, wenn man die die Zeichenkette &amp;quot;balfasel&amp;quot; betrachtet, denn das ist definitiv keine keine gültige eMail-Adresse.&lt;br /&gt;
&lt;br /&gt;
Weil ein String immer gegene einen beliebigen anderen String ausgetauscht werden kann, muß der String vor jeder Verwednung&lt;br /&gt;
daraufhin geprüft werden ob er tatsächlich eine gültige eMail-Adresse enthält. Stellen wir uns eine Anwendung vor die ganz am Anfang&lt;br /&gt;
eine eMail-Adresse beschafft und dann durch viele Schichten durchreicht bevor sie denn endlich irgendwann verwendet wird.&lt;br /&gt;
Wenn sich dann tatsächlich herausstellt, daß die eMail-Adresse korrupt ist, was macht man dann mit dem Fehler?&lt;br /&gt;
&lt;br /&gt;
Der objektorientierte Weg ist -- auch hier -- den String in einer eigenen Klasse zu kapseln.&lt;br /&gt;
Dazu hat keine Entwickler lust. Niemand mag den ganzen Code schreiben, niemand mag die mögliche Performance-Einbuße in kauf nehmen.&lt;br /&gt;
&lt;br /&gt;
Java 17 diesen Ausreden mit dem {{java|record}} ein Ende.&lt;br /&gt;
&lt;br /&gt;
Folgende einfache Impementierung verdeutlicht die Idee&lt;br /&gt;
{{java|code=&lt;br /&gt;
public record EmailAdress(String adr) {&lt;br /&gt;
   public EmailAdress(String adr) {&lt;br /&gt;
        if (adr == null || !adr.contains(&amp;quot;@&amp;quot;));&lt;br /&gt;
            throw new RuntimeException(&amp;quot;not an eMail address: &amp;quot; + adr);&lt;br /&gt;
        }&lt;br /&gt;
        this.adr = adr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Genau wie der default-Konstruktor kann auch der für den {{java|record}} vom Compiler automatisch erzeugte Konstruktur&lt;br /&gt;
durch einen Selbstgeschriebenen ersetzt werden. Im obigen Beispiel wird das {{java|record}}-Objekt nur dann erzeugt,&lt;br /&gt;
wenn der als eMail-Adresse angebotene String eine Affenschaukel enthält.&lt;br /&gt;
&lt;br /&gt;
Der Beispiel-Code ist auf [https://github.com/mletkin/java17/tree/main/src/main/java/org/mletkin/java17/rec GitHub] zu finden.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=170</id>
		<title>Java 17: Records</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=170"/>
		<updated>2023-10-21T18:34:41Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Ullrich verschob die Seite Java 17:Records nach Java 17: Records, ohne dabei eine Weiterleitung anzulegen&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
== Records ==&lt;br /&gt;
Der {{java|record}} ist eine neue Java-Komponente die auf einer Ebene liegt mit Klassen und Interfaces.&lt;br /&gt;
Man kann ihn beschreiben als eine nicht ableitbare Klasse unveränderlicher (immutable) Objekte.&lt;br /&gt;
&lt;br /&gt;
Das schöne am {{java|record}} ist, daß er eine ganze Reihe von default-Implementierungen bietet,&lt;br /&gt;
ohne daß man den ganzen boiler plate code dazu tippen muß.&lt;br /&gt;
Die Deklaration erfolgt nicht mit dem Keyword {{java|class}}, sondern mit dem [[Keywords|context keyword]] {{java|record}}.&lt;br /&gt;
&lt;br /&gt;
Hier ist eine ganz einfache Deklaration:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public record Kilometer(double dist) {};&lt;br /&gt;
}}&lt;br /&gt;
Was bietet uns der record {{java|Kilometer}}?&lt;br /&gt;
&lt;br /&gt;
* Ein {{java|Kilometer}}-Objekt hat ein einziges Feld {{java|dist}} from Typ {{java|double}}&lt;br /&gt;
* Objekte werden erzeugt über {{java|new Kilometer(42.195)}}&lt;br /&gt;
* Auf den Wert wird zugegriffen über den Getter {{java|dist()}}&lt;br /&gt;
* Die Methode {{java|toString()}} liefert etwas wie &amp;quot;Kilometer [dist=42.195]&amp;quot;&lt;br /&gt;
* Die Methoden {{java|equals}} und {{java|hashCode}} werden -- gemäß Kontrakt implementiert&lt;br /&gt;
&lt;br /&gt;
All&#039; das erzeugt der Compiler automatisch.&lt;br /&gt;
Natürlich ist die Erzeugungung von records mit beliebig vielen Feldern möglich,&lt;br /&gt;
weiter unten ist eine Beispiel mit zwei Feldern geschrieben.&lt;br /&gt;
&lt;br /&gt;
Was kann man nun mit dem {{java|record}} anstellen?&lt;br /&gt;
&lt;br /&gt;
Neben der offensichtlichen Möglichkeit, damit Data-Container ohne großen Overhead zu generieren,&lt;br /&gt;
Kann man damit auch eigene Datentypen definieren. Denn ein {{java|record}} kann -- wie jede andere Klasse auch --&lt;br /&gt;
statische und nicht-statische Methoden enthalten. Das Einzige was nicht erlaubt ist, ist die Definition von nicht-statischen Feldern.&lt;br /&gt;
Mit anderen Worten:&lt;br /&gt;
 Der Status eines record-Objektes wird durch die initiale Befüllung der implizit definierten Felder bestimmt und ändert sich niemals.&lt;br /&gt;
&lt;br /&gt;
=== Nur syntaktischer Zucker? ===&lt;br /&gt;
Records lassen uns also eine ganze Menge Code sparen, aber strenggenommen können wir damit nicht mehr machen&lt;br /&gt;
als mit klassischen Klassen bereits möglich war. Lohnt sich die Erweiterung dann überhaupt&lt;br /&gt;
&lt;br /&gt;
Tatsächlich sind Records zunächst Java-Klassen, allerdings haben sie ein eigenes Flag&lt;br /&gt;
das sie für die JVM von normalen Klassen unterscheidbar macht. Sie werden von der JVM anders behandelt, sind effizienter&lt;br /&gt;
und können beim Optimieren der JVM noch besser gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== Komplexe Zahlen ===&lt;br /&gt;
Ein ganz hübsches Beispiel ist die Definition [https://de.wikipedia.org/wiki/Komplexe_Zahl komplexer Zahlen].&lt;br /&gt;
Die Deklaration sieht zunächst so aus:&lt;br /&gt;
{{java | code=&lt;br /&gt;
public record Complex(double real, double img) {&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Der reale Anteil wird mit {{java|real}} bezeichnet, der imaginäre -- wir sind tippfaul -- mit {{java|img}}.&lt;br /&gt;
Sie werden mit den Gettern {{java|real()}} und {{java|img()}} angefragt. Der Compiler erzeugt uns einen Konstruktor&lt;br /&gt;
mit zwei {{java|double}}-Werten die der Reihenfolge der Deklaration entsprechen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public Complex(double real, double img) {&lt;br /&gt;
     this.real = real;&lt;br /&gt;
     this.img = img;&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Jetzt können wir Methoden implementieren um mit den Zahlen zu rechnen -- etwa die Addition:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public Complex plus(Complex b) {&lt;br /&gt;
        return new Complex(this.real + b.real, this.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Da record-Objekte nicht verändert werden können, wird bei der Addition jedesmal ein neues Objekt erzeugt.&lt;br /&gt;
Das ist typisch für immutable objects und  entspricht auch der Implementierung  von Klassen wie {{java|LocalDate}}.&lt;br /&gt;
&lt;br /&gt;
Die Additions-Methode lternativ könnte man auch statisch definieren:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public static Complex plus(Complex a, Complex b) {&lt;br /&gt;
        return new Complex(a.real + b.real, a.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Will man keine extra-Methode für die Ausgabe implementieren, kann man für eine hübschere Ausgabe die {{java|toString}}-Methode überschreiben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    @Override&lt;br /&gt;
    public String toString() {&lt;br /&gt;
        return real + &amp;quot; + &amp;quot; + img + &amp;quot;i&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Warum ist das cool? Mit herkömmlichen Klassen ist das schon seit Java 1.1 möglich?&lt;br /&gt;
&lt;br /&gt;
# Der Code wird sehr übersichtlich, weil Java uns eine ganze Menge abnimmt&lt;br /&gt;
# Die Objekte sind immutable, ohne daß dafür irgendwelche Maßnahmen erforderlich wären&lt;br /&gt;
# Die Java-VM kann die Verarbeitung der records in diesem Sinne optimieren&lt;br /&gt;
&lt;br /&gt;
Den kompletten Code [https://github.com/mletkin/java17/blob/main/src/main/java/org/mletkin/java17/rec/Complex.java giebt&#039;s hier].&lt;br /&gt;
&lt;br /&gt;
=== Integrierte Validierung ===&lt;br /&gt;
Um eine eMail-Adresse zu speichern verwenden die meisten Entwickler den Java-Typ {{java|String}}.&lt;br /&gt;
Das ist grundsätzlich verkehrt, wenn man die die Zeichenkette &amp;quot;balfasel&amp;quot; betrachtet, denn das ist definitiv keine keine gültige eMail-Adresse.&lt;br /&gt;
&lt;br /&gt;
Weil ein String immer gegene einen beliebigen anderen String ausgetauscht werden kann, muß der String vor jeder Verwednung&lt;br /&gt;
daraufhin geprüft werden ob er tatsächlich eine gültige eMail-Adresse enthält. Stellen wir uns eine Anwendung vor die ganz am Anfang&lt;br /&gt;
eine eMail-Adresse beschafft und dann durch viele Schichten durchreicht bevor sie denn endlich irgendwann verwendet wird.&lt;br /&gt;
Wenn sich dann tatsächlich herausstellt, daß die eMail-Adresse korrupt ist, was macht man dann mit dem Fehler?&lt;br /&gt;
&lt;br /&gt;
Der objektorientierte Weg ist -- auch hier -- den String in einer eigenen Klasse zu kapseln.&lt;br /&gt;
Dazu hat keine Entwickler lust. Niemand mag den ganzen Code schreiben, niemand mag die mögliche Performance-Einbuße in kauf nehmen.&lt;br /&gt;
&lt;br /&gt;
Java 17 diesen Ausreden mit dem {{java|record}} ein Ende.&lt;br /&gt;
&lt;br /&gt;
Folgende einfache Impementierung verdeutlicht die Idee&lt;br /&gt;
{{java|code=&lt;br /&gt;
public record EmailAdress(String adr) {&lt;br /&gt;
   public EmailAdress(String adr) {&lt;br /&gt;
        if (adr == null || !adr.contains(&amp;quot;@&amp;quot;));&lt;br /&gt;
            throw new RuntimeException(&amp;quot;not an eMail address: &amp;quot; + adr);&lt;br /&gt;
        }&lt;br /&gt;
        this.adr = adr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Genau wie der default-Konstruktor kann auch der für den {{java|record}} vom Compiler automatisch erzeugte Konstruktur&lt;br /&gt;
durch einen Selbstgeschriebenen ersetzt werden. Im obigen Beispiel wird das {{java|record}}-Objekt nur dann erzeugt,&lt;br /&gt;
wenn der als eMail-Adresse angebotene String eine Affenschaukel enthält.&lt;br /&gt;
&lt;br /&gt;
Der Beispiel-Code ist auf [https://github.com/mletkin/java17/tree/main/src/main/java/org/mletkin/java17/rec GitHub] zu finden.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Neue_Java_Features&amp;diff=169</id>
		<title>Neue Java Features</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Neue_Java_Features&amp;diff=169"/>
		<updated>2023-10-21T18:33:45Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Category:Java == Java 17 == Die neuen Sprach-Features sind separat auf folgenen Seiten beschrieben *Java 17: Text Block Mehrzeilige String-Literale *Java 17: instanceof Erweiterung des {{java|instanceof}}-Operators *Java 17: Switch Erweiterung der {{java|switch}}-Kontrollstruktur *Java 17: Sealed Classes Die Ableitbarkeit von Klassen steuern *Java 17: Records Definition unveränderlicher Daten-Objekte   Der Beispiel-Code ist auf [h…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
== Java 17 ==&lt;br /&gt;
Die neuen Sprach-Features sind separat auf folgenen Seiten beschrieben&lt;br /&gt;
*[[Java 17: Text Block]] Mehrzeilige String-Literale&lt;br /&gt;
*[[Java 17: instanceof]] Erweiterung des {{java|instanceof}}-Operators&lt;br /&gt;
*[[Java 17: Switch]] Erweiterung der {{java|switch}}-Kontrollstruktur&lt;br /&gt;
*[[Java 17: Sealed Classes]] Die Ableitbarkeit von Klassen steuern&lt;br /&gt;
*[[Java 17: Records]] Definition unveränderlicher Daten-Objekte &lt;br /&gt;
&lt;br /&gt;
Der Beispiel-Code ist auf [https://github.com/mletkin/java17/tree/main GitHub] verfügbar&lt;br /&gt;
&lt;br /&gt;
Nicht beschrieben werden die erweiterung der JDK-Bibliotheken, der Tools und der JVM.&lt;br /&gt;
&lt;br /&gt;
Vollumfänglich werden alle Änderungen in den [https://www.oracle.com/java/technologies/javase/17-relnote-issues.html Release Notes] beschrieben&lt;br /&gt;
&lt;br /&gt;
Alle Details zur Sprache findet sich in der [https://docs.oracle.com/javase/specs/jls/se17/html/ Java-Spezifikation]&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=168</id>
		<title>Java 17: Records</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Records&amp;diff=168"/>
		<updated>2023-10-21T18:32:18Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Category:Java == Records == Der {{java|record}} ist eine neue Java-Komponente die auf einer Ebene liegt mit Klassen und Interfaces. Man kann ihn beschreiben als eine nicht ableitbare Klasse unveränderlicher (immutable) Objekte.  Das schöne am {{java|record}} ist, daß er eine ganze Reihe von default-Implementierungen bietet, ohne daß man den ganzen boiler plate code dazu tippen muß. Die Deklaration erfolgt nicht mit dem Keyword {{java|class}}, son…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
== Records ==&lt;br /&gt;
Der {{java|record}} ist eine neue Java-Komponente die auf einer Ebene liegt mit Klassen und Interfaces.&lt;br /&gt;
Man kann ihn beschreiben als eine nicht ableitbare Klasse unveränderlicher (immutable) Objekte.&lt;br /&gt;
&lt;br /&gt;
Das schöne am {{java|record}} ist, daß er eine ganze Reihe von default-Implementierungen bietet,&lt;br /&gt;
ohne daß man den ganzen boiler plate code dazu tippen muß.&lt;br /&gt;
Die Deklaration erfolgt nicht mit dem Keyword {{java|class}}, sondern mit dem [[Keywords|context keyword]] {{java|record}}.&lt;br /&gt;
&lt;br /&gt;
Hier ist eine ganz einfache Deklaration:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public record Kilometer(double dist) {};&lt;br /&gt;
}}&lt;br /&gt;
Was bietet uns der record {{java|Kilometer}}?&lt;br /&gt;
&lt;br /&gt;
* Ein {{java|Kilometer}}-Objekt hat ein einziges Feld {{java|dist}} from Typ {{java|double}}&lt;br /&gt;
* Objekte werden erzeugt über {{java|new Kilometer(42.195)}}&lt;br /&gt;
* Auf den Wert wird zugegriffen über den Getter {{java|dist()}}&lt;br /&gt;
* Die Methode {{java|toString()}} liefert etwas wie &amp;quot;Kilometer [dist=42.195]&amp;quot;&lt;br /&gt;
* Die Methoden {{java|equals}} und {{java|hashCode}} werden -- gemäß Kontrakt implementiert&lt;br /&gt;
&lt;br /&gt;
All&#039; das erzeugt der Compiler automatisch.&lt;br /&gt;
Natürlich ist die Erzeugungung von records mit beliebig vielen Feldern möglich,&lt;br /&gt;
weiter unten ist eine Beispiel mit zwei Feldern geschrieben.&lt;br /&gt;
&lt;br /&gt;
Was kann man nun mit dem {{java|record}} anstellen?&lt;br /&gt;
&lt;br /&gt;
Neben der offensichtlichen Möglichkeit, damit Data-Container ohne großen Overhead zu generieren,&lt;br /&gt;
Kann man damit auch eigene Datentypen definieren. Denn ein {{java|record}} kann -- wie jede andere Klasse auch --&lt;br /&gt;
statische und nicht-statische Methoden enthalten. Das Einzige was nicht erlaubt ist, ist die Definition von nicht-statischen Feldern.&lt;br /&gt;
Mit anderen Worten:&lt;br /&gt;
 Der Status eines record-Objektes wird durch die initiale Befüllung der implizit definierten Felder bestimmt und ändert sich niemals.&lt;br /&gt;
&lt;br /&gt;
=== Nur syntaktischer Zucker? ===&lt;br /&gt;
Records lassen uns also eine ganze Menge Code sparen, aber strenggenommen können wir damit nicht mehr machen&lt;br /&gt;
als mit klassischen Klassen bereits möglich war. Lohnt sich die Erweiterung dann überhaupt&lt;br /&gt;
&lt;br /&gt;
Tatsächlich sind Records zunächst Java-Klassen, allerdings haben sie ein eigenes Flag&lt;br /&gt;
das sie für die JVM von normalen Klassen unterscheidbar macht. Sie werden von der JVM anders behandelt, sind effizienter&lt;br /&gt;
und können beim Optimieren der JVM noch besser gemacht werden.&lt;br /&gt;
&lt;br /&gt;
=== Komplexe Zahlen ===&lt;br /&gt;
Ein ganz hübsches Beispiel ist die Definition [https://de.wikipedia.org/wiki/Komplexe_Zahl komplexer Zahlen].&lt;br /&gt;
Die Deklaration sieht zunächst so aus:&lt;br /&gt;
{{java | code=&lt;br /&gt;
public record Complex(double real, double img) {&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Der reale Anteil wird mit {{java|real}} bezeichnet, der imaginäre -- wir sind tippfaul -- mit {{java|img}}.&lt;br /&gt;
Sie werden mit den Gettern {{java|real()}} und {{java|img()}} angefragt. Der Compiler erzeugt uns einen Konstruktor&lt;br /&gt;
mit zwei {{java|double}}-Werten die der Reihenfolge der Deklaration entsprechen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public Complex(double real, double img) {&lt;br /&gt;
     this.real = real;&lt;br /&gt;
     this.img = img;&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Jetzt können wir Methoden implementieren um mit den Zahlen zu rechnen -- etwa die Addition:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public Complex plus(Complex b) {&lt;br /&gt;
        return new Complex(this.real + b.real, this.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Da record-Objekte nicht verändert werden können, wird bei der Addition jedesmal ein neues Objekt erzeugt.&lt;br /&gt;
Das ist typisch für immutable objects und  entspricht auch der Implementierung  von Klassen wie {{java|LocalDate}}.&lt;br /&gt;
&lt;br /&gt;
Die Additions-Methode lternativ könnte man auch statisch definieren:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    public static Complex plus(Complex a, Complex b) {&lt;br /&gt;
        return new Complex(a.real + b.real, a.img + b.img);&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
Will man keine extra-Methode für die Ausgabe implementieren, kann man für eine hübschere Ausgabe die {{java|toString}}-Methode überschreiben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
    @Override&lt;br /&gt;
    public String toString() {&lt;br /&gt;
        return real + &amp;quot; + &amp;quot; + img + &amp;quot;i&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Warum ist das cool? Mit herkömmlichen Klassen ist das schon seit Java 1.1 möglich?&lt;br /&gt;
&lt;br /&gt;
# Der Code wird sehr übersichtlich, weil Java uns eine ganze Menge abnimmt&lt;br /&gt;
# Die Objekte sind immutable, ohne daß dafür irgendwelche Maßnahmen erforderlich wären&lt;br /&gt;
# Die Java-VM kann die Verarbeitung der records in diesem Sinne optimieren&lt;br /&gt;
&lt;br /&gt;
Den kompletten Code [https://github.com/mletkin/java17/blob/main/src/main/java/org/mletkin/java17/rec/Complex.java giebt&#039;s hier].&lt;br /&gt;
&lt;br /&gt;
=== Integrierte Validierung ===&lt;br /&gt;
Um eine eMail-Adresse zu speichern verwenden die meisten Entwickler den Java-Typ {{java|String}}.&lt;br /&gt;
Das ist grundsätzlich verkehrt, wenn man die die Zeichenkette &amp;quot;balfasel&amp;quot; betrachtet, denn das ist definitiv keine keine gültige eMail-Adresse.&lt;br /&gt;
&lt;br /&gt;
Weil ein String immer gegene einen beliebigen anderen String ausgetauscht werden kann, muß der String vor jeder Verwednung&lt;br /&gt;
daraufhin geprüft werden ob er tatsächlich eine gültige eMail-Adresse enthält. Stellen wir uns eine Anwendung vor die ganz am Anfang&lt;br /&gt;
eine eMail-Adresse beschafft und dann durch viele Schichten durchreicht bevor sie denn endlich irgendwann verwendet wird.&lt;br /&gt;
Wenn sich dann tatsächlich herausstellt, daß die eMail-Adresse korrupt ist, was macht man dann mit dem Fehler?&lt;br /&gt;
&lt;br /&gt;
Der objektorientierte Weg ist -- auch hier -- den String in einer eigenen Klasse zu kapseln.&lt;br /&gt;
Dazu hat keine Entwickler lust. Niemand mag den ganzen Code schreiben, niemand mag die mögliche Performance-Einbuße in kauf nehmen.&lt;br /&gt;
&lt;br /&gt;
Java 17 diesen Ausreden mit dem {{java|record}} ein Ende.&lt;br /&gt;
&lt;br /&gt;
Folgende einfache Impementierung verdeutlicht die Idee&lt;br /&gt;
{{java|code=&lt;br /&gt;
public record EmailAdress(String adr) {&lt;br /&gt;
   public EmailAdress(String adr) {&lt;br /&gt;
        if (adr == null || !adr.contains(&amp;quot;@&amp;quot;));&lt;br /&gt;
            throw new RuntimeException(&amp;quot;not an eMail address: &amp;quot; + adr);&lt;br /&gt;
        }&lt;br /&gt;
        this.adr = adr;&lt;br /&gt;
    }&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
Genau wie der default-Konstruktor kann auch der für den {{java|record}} vom Compiler automatisch erzeugte Konstruktur&lt;br /&gt;
durch einen Selbstgeschriebenen ersetzt werden. Im obigen Beispiel wird das {{java|record}}-Objekt nur dann erzeugt,&lt;br /&gt;
wenn der als eMail-Adresse angebotene String eine Affenschaukel enthält.&lt;br /&gt;
&lt;br /&gt;
Der Beispiel-Code ist auf [https://github.com/mletkin/java17/tree/main/src/main/java/org/mletkin/java17/rec GitHub] zu finden.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=167</id>
		<title>Java 17: Switch</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Switch&amp;diff=167"/>
		<updated>2023-10-21T18:31:15Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Um die Erwartungen vorab zu dämpfen: Auch Java 17 erlaubt nur die aufzählbaren Daten-Type sowie String, aber keine anderne Objekt-Typen. Auch führt der Aufruf mit {{java|null}} weiterhin unweigerlich zu einer Null-Pointer-Exception.  Betrachten wir die klassische Anwendung der {{java|switch}}-Kontrollstruktur: {{java|code=  public void oldStyleOhneBreak(Animal animal) {     switch (animal) {     case SPIDER:         System.out.println(&amp;quot;8 legs&amp;quot;);     ca…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;Um die Erwartungen vorab zu dämpfen:&lt;br /&gt;
Auch Java 17 erlaubt nur die aufzählbaren Daten-Type sowie String, aber keine anderne Objekt-Typen.&lt;br /&gt;
Auch führt der Aufruf mit {{java|null}} weiterhin unweigerlich zu einer Null-Pointer-Exception.&lt;br /&gt;
&lt;br /&gt;
Betrachten wir die klassische Anwendung der {{java|switch}}-Kontrollstruktur:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleOhneBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der Aufruf von {{java|oldStyleOhneBreak(Animal.ANT)}} liefert:&lt;br /&gt;
 6 legs&lt;br /&gt;
 strange animal&lt;br /&gt;
Wegen des &amp;quot;fall-through&amp;quot;-Verhaltens (was man berechtigterweise mit &amp;quot;Durchfall&amp;quot; übersetzen kann) werden&lt;br /&gt;
alle nachfolgenden Fälle durchlaufen, sobald der erste Match auftritt. Um das zu verhindern, muß man nach&lt;br /&gt;
jeder {{java|case}}-Anweisung ein {{java|break}} einfügen:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void oldStyleWithBreak(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
        break;&lt;br /&gt;
    default:&lt;br /&gt;
        System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Das ist viel Code, unübersichtlich, fehleranfällig -- und kontrovers.&lt;br /&gt;
Java 17 bietet nun eine Alternative, bei der der {{java|:}} in der Case-Anweisung durch {{java|-&amp;gt;}}.&lt;br /&gt;
Es muß aber ausdrücklich darauf hingeweisen werden, daß es sich hier um &#039;&#039;&#039;keinen&#039;&#039;&#039; {{lambda}}-Ausdruck handelt.&lt;br /&gt;
Das Ergebnis der ersten Fassung sieht nun so aus:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyle(Animal animal) {&lt;br /&gt;
    switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; System.out.println(&amp;quot;8 legs&amp;quot;);&lt;br /&gt;
    case ANT, BEE -&amp;gt; System.out.println(&amp;quot;6 legs&amp;quot;);&lt;br /&gt;
    default -&amp;gt; System.out.println(&amp;quot;strange animal&amp;quot;);&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Da für jeden Fall hier nur eine Zeile verwendet wird, ist der gesamte Ausdruck kompakter.&lt;br /&gt;
Das könnte man durchaus auch mit dem klassischen {{java|case}}-Konstrukt hinkriegen.&lt;br /&gt;
&lt;br /&gt;
Überraschender ist aber das Ergebnis, wenn man {{java|newStyle(Animal.ANT)}} ausführt:&lt;br /&gt;
 6 legs&lt;br /&gt;
Das {{java|break}} wird nicht mehr benötigt, der neue Stil hat keine Durchfall-Symptome mehr!&lt;br /&gt;
&lt;br /&gt;
Nach dem {{java|-&amp;gt;}} darf eine beliebige Anweisung kommen.&lt;br /&gt;
Anstelle einer &#039;&#039;einzelnen&#039;&#039; Anweisung ist also auch ein beliebig großer Code-Block erlaubt.&lt;br /&gt;
&lt;br /&gt;
Da wir in jedem der Fälle die gleiche Aktion ausführen, könnten wir uns auch den Ausgabe-Text liefern lassen&lt;br /&gt;
und ihn im Anschluß ausgeben. Genau dafür bietet das neue switch eine Möglichkeit:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithReturnValue(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Man kann sich vorstellen, daß switch &#039;&#039;immer&#039;&#039; einen Rückgabe-Typ hat, der allerdings in den vorangehenden Beispielen&lt;br /&gt;
{{java|void}} war und daher nicht gespeichert werden konnte. Java prüft in jedem Fall den typ und meldet Verstöße die durch&lt;br /&gt;
Inkompatibilität entstehen.&lt;br /&gt;
&lt;br /&gt;
Was machen wir nun, wenn nach dem {{java|-&amp;gt;}} kein Ausdruck vom gewünschten Typ kommt, sondern ein ganzer Code-Block?&lt;br /&gt;
Hier hilft das {{java|yield}}. Es kommt am Ende des Code-Blocks und giebt den Wert zurück:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 public void newStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER -&amp;gt; &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE -&amp;gt; &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    case CENTIPEDE -&amp;gt; {&lt;br /&gt;
        System.err.println(&amp;quot;lost count&amp;quot;);&lt;br /&gt;
        yield &amp;quot;many legs&amp;quot;;&lt;br /&gt;
    }&lt;br /&gt;
    default -&amp;gt; &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
{{java|yield}} ist -- entgegen der ersten Vermutung -- &#039;&#039;kein&#039;&#039; keyword, sondern ein &amp;quot;reservierter Identifier&amp;quot;.&lt;br /&gt;
So ist die Anweisung &lt;br /&gt;
{{java|code=&lt;br /&gt;
int yield = 5;&lt;br /&gt;
}}&lt;br /&gt;
duirchaus erlaubt. Es erübrigt sich, darauf hinzuweisen diese Verwendung zu vermeiden.&lt;br /&gt;
&lt;br /&gt;
Freundlicherweise darf man das {{java|yield}} auch mit dem {{java|switch}} im alten Stil verwenden.&lt;br /&gt;
Da dabei das {{java|switch}} unmittelbar verlassen wird, spart man sich dabei das {{break}}:&lt;br /&gt;
{{java|code=&lt;br /&gt;
public void oldStyleWithYield(Animal animal) {&lt;br /&gt;
    String legs = switch (animal) {&lt;br /&gt;
    case SPIDER:&lt;br /&gt;
        yield &amp;quot;8 legs&amp;quot;;&lt;br /&gt;
    case ANT, BEE:&lt;br /&gt;
        yield &amp;quot;6 legs&amp;quot;;&lt;br /&gt;
    default:&lt;br /&gt;
        yield &amp;quot;strange animal&amp;quot;;&lt;br /&gt;
    };&lt;br /&gt;
    System.out.println(legs);&lt;br /&gt;
}&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
== Fazit ==&lt;br /&gt;
&lt;br /&gt;
Das gemeine {{java|switch}} wird durch die Verwendung von {{java|-&amp;gt;}} kompakter und veständlicher.&lt;br /&gt;
Folgt man allerdings der Regel möglichst kleine Methoden zu schreiben, wird man praktisch jedes {{java|witch}}&lt;br /&gt;
in eine eigene Methode auslagern. Die Rückgabe-Notation bietet dann keine nennenswerten Gewinn mehr.&lt;br /&gt;
&lt;br /&gt;
Nichstdestotrotz hilft das Feature dabei, legacy-Code zu optimieren und darüber zu refactorn.&lt;br /&gt;
Dazu schreibt man das {{java|switch}} erst auf die Rückgabe-Notation um und lagert sie dann in eine eigene Methode aus.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Sealed_Classes&amp;diff=166</id>
		<title>Java 17: Sealed Classes</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Sealed_Classes&amp;diff=166"/>
		<updated>2023-10-21T14:52:03Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Category:Java __TOC__ Um die Ableitbarkeit von Klassen zu steuern bietet Java bis Versuion 16 nur eine einzige Möglichkeit, den Modifier {{java|final}}. Ist eine Klasse als {{java|final}} markiert, ist es unmöglich eine weitere Klasse von ihr abzuleiten. Ist die nicht {{java|final}}, kann jeder der Zugriff auf die Klasse hat von ihr beliebige Klassen ableiten.  Das folgt dem Gedanken, daß die Klassen-Hierarchie nichts anderes ist als ein Erweiterun…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
__TOC__&lt;br /&gt;
Um die Ableitbarkeit von Klassen zu steuern bietet Java bis Versuion 16 nur eine einzige Möglichkeit, den Modifier {{java|final}}.&lt;br /&gt;
Ist eine Klasse als {{java|final}} markiert, ist es unmöglich eine weitere Klasse von ihr abzuleiten.&lt;br /&gt;
Ist die nicht {{java|final}}, kann jeder der Zugriff auf die Klasse hat von ihr beliebige Klassen ableiten.&lt;br /&gt;
&lt;br /&gt;
Das folgt dem Gedanken, daß die Klassen-Hierarchie nichts anderes ist als ein Erweiterungs-Konzept.&lt;br /&gt;
Möchte man Klassen so modellieren, daß dabei eine abgegrenzten DSL entsteht, eine Abstraktion über die die&lt;br /&gt;
Elemente einer bestimmten Domäne der Verarbeitung zugänglich gemacht wird, benötigt man eine feinere Steuerung.&lt;br /&gt;
Denn dann möchte man die Ableitung innerhalb der Anwendung einschränken und ggf. nach außen hin ganz unterbinden.&lt;br /&gt;
&lt;br /&gt;
Das Konzept der {{Java|sealed classes}} läßt uns Teile der Klassen-Hierarchie unserer Anwendung vollständig gegen Vererbung abschotten,&lt;br /&gt;
wärend Teile der Hierarchie der Vererbung offen bleiben.&lt;br /&gt;
&lt;br /&gt;
== sealed classes ==&lt;br /&gt;
&lt;br /&gt;
Betrachten wir die Klasse {{Java|Shape}} von der nur zwei Klassen abgeleitet werden können sollen:&lt;br /&gt;
{{Java|code=&lt;br /&gt;
public sealed class Shape permits Quadrangle, Ellipse { ... }&lt;br /&gt;
}}&lt;br /&gt;
Das [[Keywords|context keyword]] {{Java|sealed}} verschließt die Klasse gegen direkte, nicht vorgesehene Vererbung,&lt;br /&gt;
wärend hinter dem [[Keywords|context keyword]] {{Java|permits}} alle Klassen aufgezählt werden die von der Klasse ableiten dürfen.&lt;br /&gt;
&lt;br /&gt;
Was verhält es sich nun mit den beiden abgeleiteten Klassen? Java verlangt, daß für jede Klasse die von&lt;br /&gt;
einer {{Java|sealed}} Klasse abgeleitet wird festgelegt wird, wie von ihr abgeleitet werden kann:&lt;br /&gt;
&lt;br /&gt;
:&#039;&#039;&#039;final&#039;&#039;&#039; von der Klasse ist überhaupt keine Ableitung mehr möglich&lt;br /&gt;
:&#039;&#039;&#039;non-sealed&#039;&#039;&#039; von der Klasse können wieder beliebige weitere Klassen abgeleitet werden&lt;br /&gt;
:&#039;&#039;&#039;sealed&#039;&#039;&#039; wie bei der Super-Klasse werden alle ableitenden Klassen angegeben.&lt;br /&gt;
&lt;br /&gt;
== sealed interfaces ==&lt;br /&gt;
Analog zu Klassen können auch Interfaces abgeschottet werden. Hier bieten sich nun zwei Möglichkeiten der&lt;br /&gt;
Erweiterung: Zum Einen können von einem Interface neue Interfaces abgeleitet werden,&lt;br /&gt;
zum Anderen können Klassen das Interface implementieren. Es entstehen also zwei Varianten der Versiegelung.&lt;br /&gt;
&lt;br /&gt;
Bei der Ableitung verhalten sich die Dinge genauso wie oben für Klassen beschrieben:&lt;br /&gt;
Ist das Interface {{java|sealed}}, müssen bei der Definition &#039;&#039;alle&#039;&#039; abgeleiteten Interfaces angegeben werden:&lt;br /&gt;
{{Java|code=&lt;br /&gt;
public sealed interface Length permits Convex, NonConvex { ... }&lt;br /&gt;
}}&lt;br /&gt;
Alle abgeleiteten Interfaces verhalten sich wieder wie Klassen, sie müssen entweder {{Java|sealed}} oder {{Java|non-sealed}} sein.&lt;br /&gt;
Interfaces können -- weil das absurd wäre -- niemals {{Java|final}} sein.&lt;br /&gt;
&lt;br /&gt;
Implementiert eine Klasse ein {{Java|sealed}} Interface, kommt es in den gleichen Zustand als wäre es von einer {{Java|sealed}} Klasse abgeleitet.&lt;br /&gt;
Es muß entweder als {{Java|sealed}}, {{Java|non-sealed}} oder {{Java|final}} markiert sein.&lt;br /&gt;
&lt;br /&gt;
== enums ==&lt;br /&gt;
Da das klassische {{java|enum}} implizit -- zumindest fast immer -- {{java|final}} ist, kann es nicht {{java|sealed}} sein.&lt;br /&gt;
Da es aber interfaces implementieren kann, kann es auch {{java|sealed}} interfaces implementieren. Da das enum implizit {{java|final}} ist,&lt;br /&gt;
braucht es aber nicht weiter markiert zu werden.&lt;br /&gt;
&lt;br /&gt;
In a nutshell: Ein {{java|enum}} kann ein {{java|sealed}} interface implementieren, als wäre es ein normales Interface.&lt;br /&gt;
&lt;br /&gt;
Was sollte im vorangehenden Absatz aber der Einschub &amp;quot;fast immer&amp;quot;?&lt;br /&gt;
&lt;br /&gt;
Betrachten wir dieses kleine -- zugegebenermaßen etwas unsinnige -- enum:&lt;br /&gt;
{{Java|code=&lt;br /&gt;
 public enum Foo {&lt;br /&gt;
     BLA,&lt;br /&gt;
     FASEL {&lt;br /&gt;
            public int wert = 5;&lt;br /&gt;
            }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
&lt;br /&gt;
Es soll nur eines verdeutlichen:&lt;br /&gt;
&lt;br /&gt;
Das enum {{java|Foo}} ist implizit {{java|sealed}} und die einzige Klasse die davon ableitet&lt;br /&gt;
ist die namenlose Klasse die den Typ des Objekts {{java|FASEL}} darstellt; diese namenlose Klasse ist imlizit {{java|final}}.&lt;br /&gt;
&lt;br /&gt;
Vereinfacht ausgedrückt:&lt;br /&gt;
&lt;br /&gt;
enums die sealed Interfaces implementieren sind implizit final, Objekte des enums können aber finale Sub-Klassen des enums bilden.&lt;br /&gt;
&lt;br /&gt;
== Mocking ==&lt;br /&gt;
Da sealed classes keine Ableitung erlauben, stellt sich die Frage ob man sie mocken kann.&lt;br /&gt;
Mit Mockito ist das möglich ab Version 5.0.0, Version 4 kompiliert zwar, wirft bei der Ausführung aber eine Exception.&lt;br /&gt;
Gleiches gilt für den Spy, der ebenfalls ab Version 5.0.0 erzeugt werden kann.&lt;br /&gt;
&lt;br /&gt;
An dieser Stelle sei der Vollständigkeit halber darauf hingewiesen,&lt;br /&gt;
daß Mockito auch final Klassen mocken und spyen kann -- aber auch erst mit Version 5.0.0&lt;br /&gt;
&lt;br /&gt;
== Fazit ==&lt;br /&gt;
Sealed Klasses und Interfaces sind für Java ein Konzept, das das Paradigma nicht gerade ändert, aber doch in eine ungewohnte Richtung biegt.&lt;br /&gt;
Formal werden dadurch -- eigentlich unerwünschte -- zyklische Abhängigkeit zwischen Super- und Sub-Klasse geschaffen, weil plötzlich die&lt;br /&gt;
Superklasse ihre Subklasses kennt. Inhaltlich aber macht die Superklasse ja davon gar keine Verwendung, es ist in Wirklichkeit eine Compiler-Anweisung.&lt;br /&gt;
&lt;br /&gt;
Man muß die (teil)ge-sealte Hierarchie als ein Ganzes sehen, das einen Teil einer fachlichen Domäne abbildet.&lt;br /&gt;
Weil die Domäne als geschlossen betrachtet wird, läßt sie auch keine unkontrollierte Erweiterung zu.&lt;br /&gt;
Verwendet man diese Hierarchie nur, hat man keine Wahl und muß sie nehmen wie sie ist.&lt;br /&gt;
Arbeitet man an der Hierarchie, weist einen die Versiegelung darauf hin, daß eine Erweiterung vom Konzept an dieser Stelle nicht vorgesehen ist.&lt;br /&gt;
Eine Veränderung bedarf zunächst der fachlichen Klärung und die Versiegelung schützt uns davor, voreilige Änderungen durchzuführen.&lt;br /&gt;
&lt;br /&gt;
Wenn eine Programmiersprache Möglichkeiten der Einschränkung schafft, ist das keine Behinderung des Coders.&lt;br /&gt;
Es ist die Möglichkeit, Consraints der Domäne explizit zu machen -- und das ist ein wertvolles Hilfsmittel.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_Text_Block&amp;diff=165</id>
		<title>Java 17: Text Block</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_Text_Block&amp;diff=165"/>
		<updated>2023-10-21T14:21:48Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „Category:java Der Text-Block ist vorgesehen für Fälle, in denen ein String-Literal definiert werden soll das mehrere Zeilen -- getrennt durch den System-Zeilen-Trenner -- enthalten soll.  Gezeigt wird hier die einfachste Anwendung. Wer tiefer in&amp;#039;s Detail gehen mag, sei auf die JavaSpec und das Internet verwiesen.  In Java Version &amp;lt;= 16 sieht das in der Regel so aus: {{Java|code=  void oldStyle() {    String text = &amp;quot;{\n&amp;quot; + //       &amp;quot;  \&amp;quot;name\&amp;quot;: \&amp;quot;Alf…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:java]]&lt;br /&gt;
Der Text-Block ist vorgesehen für Fälle, in denen ein String-Literal definiert werden soll&lt;br /&gt;
das mehrere Zeilen -- getrennt durch den System-Zeilen-Trenner -- enthalten soll.&lt;br /&gt;
&lt;br /&gt;
Gezeigt wird hier die einfachste Anwendung. Wer tiefer in&#039;s Detail gehen mag, sei auf die&lt;br /&gt;
JavaSpec und das Internet verwiesen.&lt;br /&gt;
&lt;br /&gt;
In Java Version &amp;lt;= 16 sieht das in der Regel so aus:&lt;br /&gt;
{{Java|code=&lt;br /&gt;
 void oldStyle() {&lt;br /&gt;
   String text = &amp;quot;{\n&amp;quot; + //&lt;br /&gt;
      &amp;quot;  \&amp;quot;name\&amp;quot;: \&amp;quot;Alfred Döblin\&amp;quot;,\n&amp;quot; + //&lt;br /&gt;
      &amp;quot;  \&amp;quot;alter\&amp;quot;: 79,\n&amp;quot; + //&lt;br /&gt;
      &amp;quot;  \&amp;quot;ort\&amp;quot;: \&amp;quot;Berlin Alexanderplatz\&amp;quot;\n&amp;quot; + //&lt;br /&gt;
      &amp;quot;}&amp;quot;;&lt;br /&gt;
      System.out.println(text);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Um den Formatter davon abzuhalten die Zeilen zusammenzutackern, werden die Enden mit {{java|//}}-Kommentaren geschützt.&lt;br /&gt;
Der Mix aus Anführungszeichen und Backslashes trägt nicht unwesentlich zur Unlesbarkeit bei...&lt;br /&gt;
&lt;br /&gt;
So sieht das nun mit einem Text-Block aus -- das Ergebnis ist identisch:&lt;br /&gt;
{{Java|code=&lt;br /&gt;
 void newStyleNoIndentation() {&lt;br /&gt;
     String text = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
                   {&lt;br /&gt;
                     name: Alfred Döblin,&lt;br /&gt;
                     alter: 79,&lt;br /&gt;
                     ort: Berlin Alexanderplatz&lt;br /&gt;
                   }&lt;br /&gt;
                   &amp;quot;&amp;quot;&amp;quot;;&lt;br /&gt;
     System.out.println(text);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der Text-Block beginnt mit dreifachen Anführungszeichen und endet auch so.&lt;br /&gt;
Innerhalb des Text-Block ist die Verwendung von Anführungszeichen &#039;&#039;ohne&#039;&#039; Backslash davor möglich.&lt;br /&gt;
&lt;br /&gt;
In der ersten Variante war es notwendig, die Zeilen durch das vorangehende Anführungszeichen in jeder Zeile&lt;br /&gt;
vor weiterer Einrückung zu schützen. Beim Text-Block ist das nicht erforderlich, der vorangehende Leerraum&lt;br /&gt;
wird bei der Ausgabe verschluckt -- warum?&lt;br /&gt;
&lt;br /&gt;
Betrachten wir die Ausgabe dieser Methode:&lt;br /&gt;
{{Java|code=&lt;br /&gt;
 void newStyleNoIndentation() {&lt;br /&gt;
     String text = &amp;quot;&amp;quot;&amp;quot;&lt;br /&gt;
                   {&lt;br /&gt;
                     name: Alfred Döblin,&lt;br /&gt;
                     alter: 79,&lt;br /&gt;
                     ort: Berlin Alexanderplatz&lt;br /&gt;
                   }&lt;br /&gt;
                 &amp;quot;&amp;quot;&amp;quot;;&lt;br /&gt;
     System.out.println(text);&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Jede Zeile der Ausgabe ist nun um zwei Leerzeichen nach rechts eingerückt.&lt;br /&gt;
Java bestimmt das anhand der negativen Einrückung der abschließenden Triple-Gänsefüße.&lt;br /&gt;
Je weiter wir den Abschuß nach links schieben, umso weiter schiebt sich die Ausgabe nach rechts.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Java_17:_instanceof&amp;diff=164</id>
		<title>Java 17: instanceof</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Java_17:_instanceof&amp;diff=164"/>
		<updated>2023-10-21T14:19:40Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: Die Seite wurde neu angelegt: „category:Java Die Diskussion ob {{java|instanceof}} gut oder schlecht, ob Downcasting un-objektorientiert ist oder nicht, soll ein anderesmal geführt werden, hier soll es nur darum gehen, was Java 17 neues für den umstrittensten aller  Java-Operatoren bringt.  {{java|instanceof}} wird meist zusammen mit einem Downcast verwendet um zu prüfen, ob dieser überhaupt möglich ist. zur Erinnerung: Downcasting heißt, ein Objekt auf eine Subclass der Klas…“&lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[category:Java]]&lt;br /&gt;
Die Diskussion ob {{java|instanceof}} gut oder schlecht, ob Downcasting un-objektorientiert ist oder nicht,&lt;br /&gt;
soll ein anderesmal geführt werden, hier soll es nur darum gehen, was Java 17 neues für den umstrittensten aller &lt;br /&gt;
Java-Operatoren bringt.&lt;br /&gt;
&lt;br /&gt;
{{java|instanceof}} wird meist zusammen mit einem Downcast verwendet um zu prüfen, ob dieser überhaupt möglich ist.&lt;br /&gt;
zur Erinnerung: Downcasting heißt, ein Objekt auf eine Subclass der Klasse zu casten unter der man es erhalten hat.&lt;br /&gt;
Am einfachsten sieht man das an einem Beispiel:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 void foo(Object obj) {&lt;br /&gt;
    if (obj instanceof Integer) {&lt;br /&gt;
        Integer zahl = (Integer)obj;&lt;br /&gt;
        system.out.println(&amp;quot;Wert:&amp;quot; + zahl.intValue());&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Ohne den Downcast könnte man nicht auf die Methode {{java|intValue}} zugreifen und ohne die Prüfung mit&lt;br /&gt;
{{java| instanceof}} liefe man gefahr eine {{java|ClassCastException}} zu werfen.&lt;br /&gt;
&lt;br /&gt;
Java 17 erlaubt uns nun, die Prüfung und den Cast zusammenzufassen und dabei die Variable anzugeben:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 void foo(Object obj) {&lt;br /&gt;
    if (obj instanceof Integer zahl) {&lt;br /&gt;
        system.out.println(&amp;quot;Wert:&amp;quot; + zahl.intValue());&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Nicht viel, spart nur eine Zeile -- aber immerhin eine Zeile weniger.&lt;br /&gt;
&lt;br /&gt;
Dieser etwas merkwürdige Scope (Bereich der Sichtbarkeit) der Variable ist uns seit Java 7 vom try...with resources her vertraut:&lt;br /&gt;
er erstreckt sich aus den runden Klammern der if-Bedingung hinaus über den nachfolgenden Block.&lt;br /&gt;
&lt;br /&gt;
Etwas bizarr wird&#039;s allerdings hier:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 void foo(Object obj) {&lt;br /&gt;
    if (! obj instanceof Integer zahl) {&lt;br /&gt;
        throw new RuntimeException();&lt;br /&gt;
    }&lt;br /&gt;
    system.out.println(&amp;quot;Wert:&amp;quot; + zahl.intValue());&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Der Compiler erkennt, daß das Casting im if-Block keinen Sinn ergiebt und verzichtet auf die&lt;br /&gt;
Erzeugung der lokalen Variable. Dafür merkt er, daß das Cast &#039;&#039;nach&#039;&#039; dem if-Block möglich ist&lt;br /&gt;
und stellt sie dort auch zur Verfügung. Ob dieses Feature wirklich sinnvolle Anwendungen hat sei mal dahingestellt,&lt;br /&gt;
an das Konstrukt an sich muß man sich aber erstmal gewöhnen. Ohne IDE hat man da schlechte Karten den Überblick zu wahren.&lt;br /&gt;
&lt;br /&gt;
In der Java-Spec ist da auch von &amp;quot;Type Pattern Matching&amp;quot; die Rede. Ein Hinweis darauf, daß es sich hier nur um die Spitze eines&lt;br /&gt;
neuen Konzept-Eisbergs handelt. in Java 21 sieht man denn auch, wie das pattern matching das switch-Konstrukt so richtig aufzumischen vermag.&lt;br /&gt;
&lt;br /&gt;
Bis dahin nehmen wir aber auf jeden Fall die Ein-Zeilen-Ersparnis gerne mit.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Keywords&amp;diff=163</id>
		<title>Keywords</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Keywords&amp;diff=163"/>
		<updated>2023-10-21T14:11:56Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
__TOC__&lt;br /&gt;
== Was ist ein Keyword? ==&lt;br /&gt;
Unter einem Keyword vesteht man in einer Programmiersprache eine Zeichenfolge, die nur mit ganz bestimmter Bedeutung eingesetzt werden darf.&lt;br /&gt;
So darf das {{java|if}} ausschließlich verwendet werden um ein Konstrukt zur bedingten Ausführung einzuleiten; nicht aber als Bezeichner,&lt;br /&gt;
auch nicht als Teil eines package-Namens.&lt;br /&gt;
&lt;br /&gt;
== Java Keywords ==&lt;br /&gt;
Mit Java 5 kam {{java|enum}} als 50tes Keyword hinzu:&lt;br /&gt;
 abstract   continue   for          new         switch&lt;br /&gt;
 assert     default    if           package     synchronized&lt;br /&gt;
 boolean    do         goto         private     this&lt;br /&gt;
 break      double     implements   protected   throw&lt;br /&gt;
 byte       else       import       public      throws&lt;br /&gt;
 case       enum       instanceof   return      transient&lt;br /&gt;
 catch      extends    int          short       try&lt;br /&gt;
 char       final      interface    static      void&lt;br /&gt;
 class      finally    long         strictfp    volatile&lt;br /&gt;
 const      float      native       super       while&lt;br /&gt;
In Java 9 kam mit dem einzelnen Underscore {{java|_}} das 51te und bislang letzte Keyword hinzu.&lt;br /&gt;
&lt;br /&gt;
Der Grund für die sparsame Einführung neuer Keywords liegt an den unvermeidlichen Kompilier-Fehlern die beim Update entstehen,&lt;br /&gt;
wenn das -- bis dahin erlaubte -- Keyword bona fide verwendet wurde. Das ist durchaus problematisch, da die gestörte Abwärts-Komaptibilität&lt;br /&gt;
zu erhöhtem Aufwand und zu Verzögerungen beim Update führt.&lt;br /&gt;
&lt;br /&gt;
Da aber eine strukturelle Spracherweiterung nur möglich ist, wenn neue Konstrukte eindeutig identifzierbar sind,&lt;br /&gt;
wurde ein alternativer Weg gefunden der die Abwärts-Kompatibilität nicht gefährdet.&lt;br /&gt;
&lt;br /&gt;
== Contextual Keywords ==&lt;br /&gt;
Die Sequenz {{java|var}} wurde in Java 11 eingeführt um Varaiblen deklarieren zu können, deren Typ der Compiler aus dem Kontext bestimmt.&lt;br /&gt;
So definiert etwa der Ausdruck&lt;br /&gt;
{{java|code=&lt;br /&gt;
var x = &amp;quot;fünf&amp;quot;;&lt;br /&gt;
}} &lt;br /&gt;
eine Variable mit dem Bezeichner {{java|x}} und dem Typ {{java|String}}.&lt;br /&gt;
&lt;br /&gt;
Im Gegensazu zu den Keywords kann {{java|var}} aber weiterhin als Bezeichner genutzt werden. Zumindest der Compiler hat nichts gegen diese Deklaration:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 class Var {&lt;br /&gt;
    static int var = 5;&lt;br /&gt;
    {&lt;br /&gt;
        var var = Var.var;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Einzige Einschränkung ist, daß {{java|var}} nicht als Typ-Identifier erlaubt ist, was aber nicht geschieht wenn sich der Coder an die &amp;quot;Sun&amp;quot;-Code-Convention hält.&lt;br /&gt;
&lt;br /&gt;
Mit Java 9 wurden die Sequenzen&lt;br /&gt;
 open         module      requires    transitive   exports&lt;br /&gt;
 opens        to          uses        provides     with&lt;br /&gt;
im Rahmen von Project &amp;quot;Jigsaw&amp;quot; eingeführt, das neue Java-Modul-Konzept. Die Spec bezeichnet sie als &#039;&#039;Restricted Keywords&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
Erst mit Java 17 wurde in der Java-Spec dafür der Begriff &#039;&#039;Contextual Keyword&#039;&#039; geprägt. Java 17 führten die folgenden sequenzen ein:&lt;br /&gt;
 permits      sealed     non-sealed    record      yield&lt;br /&gt;
Mit Ausnahme von {{java|non-sealed}} sind alle Contextual Keywords als Bezeichner -- etwa für Variablen -- verwendbar.&lt;br /&gt;
&lt;br /&gt;
== Ungenutzte Keywords ==&lt;br /&gt;
In der Liste der echten Keywords fallen einige auf, die in der normalen Programmierung nicht auftauchen:&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;const&#039;&#039;&#039; und &#039;&#039;&#039;goto&#039;&#039;&#039; wurden in der ersten Java-Spezifikation definiert, aber niemals mit einer Semantik versehen.&lt;br /&gt;
Sie können nicht verwendet werden und würden auch nichts tun wenn man es könnte.&lt;br /&gt;
&lt;br /&gt;
&#039;&#039;&#039;_&#039;&#039;&#039; (der Underscore) wurde präventiv eingeführt, hat auch in Java 21 noch keine Bedeutung erhalten.&lt;br /&gt;
Er wird vermutlich im Zusammenhang mit dem type pattern matching einmal Bedeutung erhalten.&lt;br /&gt;
&lt;br /&gt;
== Nicht-Keywords ==&lt;br /&gt;
Obwohl man das vermuten könnte, sind die Sequenzen {{java|true}}, {{java|false}} und {{java|null}} &#039;&#039;keine&#039;&#039; Keywords -- auch keine Kontext-Keywords.&lt;br /&gt;
Tatsächlich handelt sich bei allen drei um Literale, also Sequenzen die Konstanten definieren.&lt;br /&gt;
&lt;br /&gt;
Dadurch verhalten sich die drei ähnlich wie Keywords, sie können nicht als Bezeichner verwendet werden, auch nicht als Teil eines Package-Bezeichners.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
	<entry>
		<id>https://mletkin.net/index.php?title=Keywords&amp;diff=162</id>
		<title>Keywords</title>
		<link rel="alternate" type="text/html" href="https://mletkin.net/index.php?title=Keywords&amp;diff=162"/>
		<updated>2023-10-19T19:10:28Z</updated>

		<summary type="html">&lt;p&gt;Ullrich: &lt;/p&gt;
&lt;hr /&gt;
&lt;div&gt;[[Category:Java]]&lt;br /&gt;
Unter einem Keyword vesteht man eine Zeichenfolge, die in Java nur mit ganz bestimmter Bedeutung eingesetzt werden darf.&lt;br /&gt;
So darf das {{java|if}} ausschließlich verwendet werden um ein Konstrukt zur Bedingten Ausführung einzuleiten.&lt;br /&gt;
Nicht aber als bezeichner, auch nicht als Teil eines package-Namens.&lt;br /&gt;
&lt;br /&gt;
Mit Java 5 kam {{java|enum}} als 50tes keyword hinzu:&lt;br /&gt;
 abstract   continue   for          new         switch&lt;br /&gt;
 assert     default    if           package     synchronized&lt;br /&gt;
 boolean    do         goto         private     this&lt;br /&gt;
 break      double     implements   protected   throw&lt;br /&gt;
 byte       else       import       public      throws&lt;br /&gt;
 case       enum       instanceof   return      transient&lt;br /&gt;
 catch      extends    int          short       try&lt;br /&gt;
 char       final      interface    static      void&lt;br /&gt;
 class      finally    long         strictfp    volatile&lt;br /&gt;
 const      float      native       super       while&lt;br /&gt;
Java 9 brachte mit dem einzelnen Underscore {{java|_}} das 51te und bislang letzte keyword hinzu.&lt;br /&gt;
&lt;br /&gt;
Der Grund für die sparsame Einführung neuer keywords liegt an der unvermeidlichen Kompilier-Fehlern die beim Update entstehen,&lt;br /&gt;
wenn das -- bis dahin erlaubte -- keyword bona fide verwendet wurde.&lt;br /&gt;
&lt;br /&gt;
Da aber eine Spracherweiterung nur möglich ist, wenn neue Konstrukte eindeutig identifzierbar sind, wurde ein alternativer Weg gefunden.&lt;br /&gt;
&lt;br /&gt;
Die Sequenz {{java|var}} wurde in Java 11 eingeführt um Varaiblen deklarieren zu können, deren Typ der Compiler aus dem Kontext bestimmt.&lt;br /&gt;
So definiert der Ausdruck&lt;br /&gt;
{{java|code=&lt;br /&gt;
 var x = &amp;quot;fünf&amp;quot;;&lt;br /&gt;
}} &lt;br /&gt;
die Variable &#039;&#039;x&#039;&#039; mit dem Typ &#039;&#039;String&#039;&#039;.&lt;br /&gt;
&lt;br /&gt;
{{java|var}} kann aber weiterhin als Bezeichner genutzt werden. Zumindest der Compiler hat nichts gegen diese Deklaration:&lt;br /&gt;
{{java|code=&lt;br /&gt;
 class Var {&lt;br /&gt;
    static int var = 5;&lt;br /&gt;
    {&lt;br /&gt;
        var var = Var.var;&lt;br /&gt;
    }&lt;br /&gt;
 }&lt;br /&gt;
}}&lt;br /&gt;
Als Typ-Identifier hingegen ist &amp;quot;var&amp;quot; nicht erlaubt.&lt;br /&gt;
&lt;br /&gt;
Mit Java 17 wurde in der Java-Spec ein neuer Begriff geprägt: das Contextual Keyword. Die Spec listet 16 solcher Sequenzen auf:&lt;br /&gt;
 exports      opens      requires     uses&lt;br /&gt;
 module       permits    sealed       var&lt;br /&gt;
 non-sealed   provides   to           with&lt;br /&gt;
 open         record     transitive   yield&lt;br /&gt;
Mit Ausnahme von {{java|non-sealed}} sind die contextual keywords als Bezeichner -- etwa für Varaiblen oder Klassen -- verwendbar.&lt;br /&gt;
&lt;br /&gt;
Die Sequenzen {{java|true}}, {{java|false}} und {{java|null}} sind im übrigen &#039;&#039;keine&#039;&#039; keywords -- auch keine Kontext-Keywords --&lt;br /&gt;
sondern Literale, also Bezeichner für Konstanten.&lt;/div&gt;</summary>
		<author><name>Ullrich</name></author>
	</entry>
</feed>