Vorwort
Diese Arbeit wurde mithilfe von KI übersetzt. Wir freuen uns über dein Feedback und deine Kommentare: translation-feedback@oreilly.com
Testgetriebene Entwicklung ist eine Methode, um Ängste während der Programmierung zu bewältigen.
Kent Beck
Wir haben so ein unbeschreibliches Glück! Wir haben schon seit Jahren eine testgetriebene Entwicklung.
Mehrere Jahrzehnte sind vergangen, seit die Entwickler, die den Code für das Mercury-Raumfahrtprogramm schrieben, Punch Card TDD (testgetriebene Entwicklung) praktizierten. Die XUnit-Bibliotheken, die die Einführung der testgetriebenen Entwicklung erleichtern, stammen aus der Zeit um die Jahrhundertwende. Tatsächlich hat Kent Beck, der das Buch Test-Driven Development: By Example (Addison-Wesley Professional, 2002) geschrieben und das JUnit-Framework entwickelt hat, bezeichnet sich selbst als "Wiederentdecker" (und nicht als Erfinder) der TDD-Praxis. Diese Aussage zeugt von seiner Bescheidenheit, entspricht aber auch der Wahrheit. TDD ist so alt wie die Softwareentwicklung selbst.
Warum ist die testgetriebene Entwicklung dann immer noch weit davon entfernt, die Standardmethode zum Schreiben von Code zu sein? Warum wird sie oft als Erstes geopfert, wenn der Zeitplan unter Druck gerät, wenn die IT-Budgets gekürzt werden müssen oder (mein persönlicher Favorit) wenn der Wunsch besteht, "die Geschwindigkeit des Software-Entwicklungsteams zu erhöhen"? All diese Gründe werden angeführt, obwohl es empirische und experimentelle Beweise dafür gibt, dass TDD die Anzahl der Fehler reduziert, das Design vereinfacht und das Vertrauen der Entwickler in ihren eigenen Code stärkt.
Warum wird TDD nur widerwillig angenommen und schnell wieder aufgegeben? Die folgenden Argumente, die man oft von denjenigen hört, die TDD nur widerwillig praktizieren, können den Grund dafür erklären:
- Ich weiß nicht, wo und wie ich anfangen soll.
-
Der vielleicht häufigste Grund ist mangelndes Bewusstsein und fehlende Erfahrung. Wie jede andere Fähigkeit muss auch das Schreiben von Code im testgetriebenen Stil gelernt werden. Vielen Entwicklern fehlt entweder der äußere Anreiz (Zeit, Ressourcen, Anleitung, Ermutigung) oder die innere Motivation (Überwindung des eigenen Widerwillens und der Angst), um diese Fähigkeit zu erlernen.
- TDD funktioniert in Spielzeugprogrammen oder bei Programmiergesprächen, aber nicht beim Schreiben von "echtem" Code.
-
Das ist unwahr und doch verständlich. Die meisten Tutorials und Bücher zur testgetriebenen Entwicklung - einschließlich dieses Buches - beschränken sich auf relativ einfache Beispiele aus einem naheliegenden Bereich. Es ist schwierig, einen TDD-Artikel oder ein Buch mit dem Code einer Software zu schreiben, die aus einer kommerziell genutzten Anwendung stammt (z. B. von einem Finanzinstitut, einem Gesundheitssystem oder einem selbstfahrenden Auto). Zum einen ist ein Großteil des Codes aus der Praxis proprietär und nicht Open Source. Zum anderen ist es die Aufgabe des Autors, Code aus einem Bereich zu zeigen, der ein möglichst großes Publikum anspricht. Es wäre unlogisch und grenzt an Obskurantismus, TDD im Zusammenhang mit einem hochspezialisierten Bereich zu zeigen. Dies würde vor allem eine lange Erklärung des Fachjargons und der Fachsprache dieses Bereichs erfordern. Das würde das eigentliche Ziel des Autors zunichte machen: TDD verständlich, zugänglich und sogar liebenswert zu machen.
Ungeachtet dieser Hindernisse für die Verwendung von echtem Code in der TDD-Literatur schreiben Entwickler/innen regelmäßig Produktionssoftware mit Hilfe von testgetriebener Entwicklung. Das vielleicht beste und überzeugendste Beispiel ist die Suite von Unit-Tests für das JUnit-Framework selbst. Der Linux-Kernel - das wahrscheinlich am meisten genutzte Stück Software der Welt - wird mit Unit-Tests verbessert.
- Das Schreiben von Tests im Nachhinein ist ausreichend; TDD ist zu restriktiv und/oder pedantisch.
-
Das ist erfrischender als das gelegentliche Gerede, dass "Unit-Tests überbewertet" sind! Das Schreiben von Tests nach dem Schreiben von Produktionscode ist eine Verbesserung gegenüber dem Schreiben von gar keinen Tests. Alles, was das Vertrauen der Entwickler in ihren Code stärkt, die Komplexität reduziert und eine authentische Dokumentation liefert, ist eine gute Sache. Das Schreiben von Unit-Tests vor dem Schreiben des Produktionscodes verhindert jedoch, dass willkürliche Komplexität entsteht.
TDD führt uns zu einem einfacheren Design, weil es diese beiden praktischen Regeln als Leitplanken bereitstellt:
-
Schreibe nur Produktionscode, um einen fehlgeschlagenen Test zu beheben.
-
Refaktoriere energisch, wenn, und nur wenn, die Tests grün sind.
-
Ist die testgetriebene Entwicklung eine Garantie dafür, dass der gesamte Code, den wir jemals schreiben, automatisch und zwangsläufig der einfachste Code ist, der funktioniert? Nein, das tut sie nicht. Keine Praxis, keine Regel, kein Buch und kein Manifest kann das leisten. Es liegt an den Menschen, die diese Praktiken in die Tat umsetzen, um sicherzustellen, dass Einfachheit erreicht und beibehalten wird.
Der Inhalt dieses Buches erklärt und lehrt, wie testgetriebene Entwicklung in drei verschiedenen Programmiersprachen funktioniert. Sein Ziel ist es, Entwicklern die Gewohnheit und das Selbstvertrauen zu vermitteln, TDD als regelmäßige Praxis anzuwenden. Dieses Ziel mag ehrgeizig sein, aber ich bin zuversichtlich, dass es nicht schwer zu erreichen ist.
Was ist testgetriebene Entwicklung?
Testgetriebene Entwicklung ist eine Technik zum Entwerfen und Strukturieren von Code, die die Einfachheit fördert und das Vertrauen in den Code erhöht, selbst wenn dieser größer wird.
Werfen wir einen Blick auf die verschiedenen Teile dieser Definition.
Eine Technik
Testgetriebene Entwicklung ist eine Technik. Es stimmt, dass diese Technik auf einer Reihe von Überzeugungen über Code beruht, nämlich:
-
Diese Einfachheit - die Kunst, die Menge der nicht erledigten Arbeit zu maximieren - ist entscheidend1
-
Dass Offensichtlichkeit und Klarheit tugendhafter sind als Cleverness
-
Dass das Schreiben von übersichtlichem Code eine Schlüsselkomponente ist, um erfolgreich zu sein
Obwohl TDD auf diesen Überzeugungen beruht, ist es in der Praxis eine Technik. Wie Fahrradfahren, Teig kneten oder Differentialgleichungen lösen ist es eine Fähigkeit, mit der niemand geboren wird und die jeder lernen muss.
Abgesehen von diesem Abschnitt geht dieses Buch nicht auf das Glaubenssystem hinter der testgetriebenen Entwicklung ein. Es wird davon ausgegangen, dass du es entweder bereits vertrittst oder bereit bist, TDD als neue (oder vergessene) Fähigkeit auszuprobieren.
Die Mechanismen dieser Technik - zuerst einen fehlgeschlagenen Unit-Test schreiben, dann zügig gerade so viel Code schreiben, dass er bestanden wird, und sich dann die Zeit nehmen, ihn zu bereinigen - nehmen den größten Teil dieses Buches ein. Es wird reichlich Gelegenheit geben, diese Technik selbst auszuprobieren.
Letztendlich ist es befriedigender, eine Fähigkeit zu erlernen und sich die Überzeugungen anzueignen, die sie unterstützen - so wie das Fahrradfahren mehr Spaß macht, wenn du dir bewusst machst, dass es gut für deine Gesundheit und die Umwelt ist!
Code entwerfen und strukturieren
Beachte, dass es bei TDD nicht grundsätzlich um das Testen von Code geht. Es stimmt zwar, dass wir Unit-Tests verwenden, um den Code zu testen, aber der Zweck von TDD ist es, das Design und die Struktur des Codes zu verbessern.
Dieser Fokus ist entscheidend. Wenn es bei TDD nur um das Testen ginge, könnten wir nicht wirksam dafür plädieren, Tests vor und nicht nach dem Schreiben des Geschäftscodes zu schreiben. Es ist das Ziel, bessere Software zu entwickeln, das uns anspornt; die Tests sind lediglich ein Vehikel für diesen Fortschritt. Die Unit-Tests, die wir durch TDD erhalten, sind ein zusätzlicher Bonus; der Hauptvorteil ist die Einfachheit des Designs, die wir erhalten.
Wie erreichen wir diese Einfachheit? Durch den Mechanismus des Rot-Grün-Refactors, der am Anfang von Kapitel 1 ausführlich beschrieben wird.
Eine Neigung zur Einfachheit
Einfachheit ist nicht nur ein esoterischer Begriff. Bei Software können wir sie messen. Weniger Codezeilen pro Funktion, geringere zyklomatische Komplexität, weniger Seiteneffekte, geringere Laufzeit- oder Speicheranforderungen - jede Teilmenge dieser (oder anderer) Anforderungen kann als objektives Maß für Einfachheit herangezogen werden.
Die testgetriebene Entwicklung zwingt uns dazu, "das Einfachste zu entwickeln, das funktioniert" (d.h. das, was alle Tests bestehen kann), und stößt uns so immer wieder zu diesen Maßstäben der Einfachheit. Wir dürfen keinen überflüssigen Code hinzufügen, "für den Fall, dass wir ihn brauchen" oder weil "wir ihn kommen sehen". Wir müssen erst einen fehlgeschlagenen Test schreiben, um das Schreiben solchen Codes zu rechtfertigen. Die Tatsache, dass wir zuerst einen Test schreiben, wirkt wie eine Zwangsfunktion - sie zwingt uns dazu, uns frühzeitig mit beliebiger Komplexität auseinanderzusetzen. Wenn die Funktion, die wir entwickeln wollen, schlecht definiert ist oder wir sie nicht richtig verstehen, wird es uns schwer fallen, einen guten Test zu schreiben. Das zwingt uns dazu, diese Probleme anzugehen , bevor wir eine Zeile Produktionscode schreiben. Das ist der Vorteil von TDD: Indem wir unseren Code diszipliniert durch Tests steuern, vermeiden wir an jeder Stelle willkürliche Komplexität.
Diese Tugend ist nicht mystisch: Mit testgetriebener Entwicklung kannst du weder die Entwicklungszeit noch die Codezeilen oder die Anzahl der Fehler um die Hälfte reduzieren. Aber du kannst damit der Versuchung widerstehen, künstliche und künstliche Komplexität einzuführen. Der daraus resultierende Code wird durch die Disziplin, zuerst fehlgeschlagene Tests zu schreiben, zum einfachsten Weg, die Aufgabe zu erledigen, d.h. zum einfachsten Code, der die Anforderungen der Tests erfüllt.
Gestärktes Selbstvertrauen
Code sollte Vertrauen erwecken, vor allem Code, den wir selbst verfasst haben. Dieses Vertrauen ist zwar ein nebulöses Gefühl, aber es beruht auf der Erwartung von Vorhersehbarkeit. Wir haben Vertrauen in Dinge, deren Verhalten wir vorhersagen können. Wenn mir das Café an der Ecke an einem Tag zu wenig und am nächsten Tag zu viel berechnet, verliere ich wahrscheinlich das Vertrauen in das Personal, auch wenn ich an den beiden Tagen nichts verdiene. Es liegt in der menschlichen Natur, dass wir Regelmäßigkeit und Vorhersehbarkeit noch mehr schätzen als den Nettowert. Der glücklichste Glücksspieler der Welt, der vielleicht gerade zehnmal hintereinander am Roulettetisch gewonnen hat, würde nicht sagen, dass er dem Rad "vertraut" oder "Vertrauen" in es hat. Unsere Vorliebe für Vorhersehbarkeit überlebt sogar das Glück.
Testgetriebene Entwicklung erhöht das Vertrauen in unseren Code, weil jeder neue Test das System auf neue und bisher ungetestete Weise verändert - im wahrsten Sinne des Wortes! Im Laufe der Zeit schützt uns die Testreihe, die wir erstellen, vor Regressionsfehlern.
Diese stetig wachsende Zahl von Tests ist der Grund dafür, dass mit dem Umfang des Codes auch seine Qualität und unser Vertrauen in ihn wächst.
Für wen ist dieses Buch?
Dies ist ein Buch für Entwickler - Menschen, die Software schreiben.
Es gibt viele Berufsbezeichnungen, die mit diesem Beruf verbunden sind: "Softwareentwickler", "Anwendungsarchitekt", "Devops Engineer", "Testautomatisierungsingenieur", "Programmierer", "Hacker", "Codeflüsterer" und unzählige andere. Die Bezeichnungen können beeindruckend oder bescheiden sein, trendy oder feierlich, traditionell oder modern. Eines haben die Menschen, die diese Titel tragen, jedoch gemeinsam: Sie verbringen mindestens einen Teil ihrer Woche - wenn nicht sogar jeden Tag - vor einem Computer und lesen und/oder schreiben Quellcode.
Ich habe den Begriff " Entwickler" gewählt, um diese Gemeinschaft zu repräsentieren, in der ich ein bescheidenes und dankbares Mitglied bin.
Code zu schreiben ist eine der befreiendsten und egalitärsten Tätigkeiten, die man sich vorstellen kann. Theoretisch ist alles, was man an körperlichen Fähigkeiten braucht, der Besitz eines Gehirns. Alter, Geschlecht, Nationalität, nationale Herkunft - nichts davon sollte ein Hindernis sein. Auch eine körperliche Behinderung sollte kein Hindernis sein.
Es wäre jedoch naiv anzunehmen, dass die Realität so ordentlich oder fair ist. Der Zugang zu Rechenressourcen ist nicht gleichberechtigt. Ein gewisses Maß an Wohlstand, Freiheit von Not und Sicherheit ist notwendig. Der Zugang wird noch weiter erschwert durch schlecht geschriebene Software, schlecht konstruierte Hardware und unzählige andere Einschränkungen der Benutzerfreundlichkeit, die verhindern, dass alle Menschen das Programmieren lernen können, nur weil sie Interesse und Mühe haben.
Ich habe versucht, dieses Buch für so viele Menschen wie möglich zugänglich zu machen. Vor allem habe ich versucht, es für Menschen mit körperlichen Behinderungen zugänglich zu machen. Die Bilder sind mit Alt-Text versehen, um das elektronische Lesen zu erleichtern. Der Code ist über GitHub verfügbar. Und die Prosa ist einfach gehalten.
Dieses Buch richtet sich sowohl an Personen, die das Programmieren noch lernen, als auch an diejenigen, die bereits programmieren können. Wenn du mit einer (oder mehreren) der drei Sprachen in diesem Buch anfängst, bist du genau in der richtigen Zielgruppe.
In diesem Buch werden jedoch nicht die Grundlagen der Programmierung in einer beliebigen Sprache vermittelt, auch nicht in Go, JavaScript oder Python. Die Fähigkeit, Code in mindestens einer der Programmiersprachen zu lesen und zu schreiben, ist eine Voraussetzung. Wenn du ein absoluter Neuling in der Programmierung bist, wäre es ratsam, die Grundlagen des Codeschreibens in einer der drei Sprachen zu festigen, bevor du mit diesem Buch weitermachst.
Die Zielgruppe für dieses Buch reicht von Entwicklern, die ihre ersten Gehversuche im Programmieren hinter sich haben, bis hin zu erfahrenen Architekten, wie in Abbildung P-1 dargestellt. (Kent Beck ist ein Ausreißer.)
Code zu schreiben kann abwechselnd aufregend und ärgerlich sein. Aber selbst wenn es am frustrierendsten ist, sollte immer ein Funken Optimismus und Zuversicht mitschwingen, dass wir den Code dazu bringen können, unseren Willen zu erfüllen. Wenn du beharrlich bist, wirst du feststellen, dass deine Reise durch dieses Buch fruchtbar ist und dass du die Freude am testgetriebenen Schreiben von Code noch lange nach dem Lesen von Kapitel 14 genießen wirst.
Was sind die Voraussetzungen, um dieses Buch zu lesen?
Was die Ausrüstung und die technischen Fähigkeiten angeht, solltest du das tun:
-
Du musst Zugang zu einem Computer mit Internetanschluss haben.
-
Du musst in der Lage sein, Software auf diesem Computer zu installieren und zu löschen. Das heißt, dein Zugriff auf den Computer sollte nicht eingeschränkt sein; in den meisten Fällen erfordert dies, dass du als "Administrator" oder "Superuser" Zugriff auf den Computer hast.
-
In der Lage sein, ein Shell-Programm, einen Webbrowser, einen Texteditor und optional eine integrierte Entwicklungsumgebung (IDE) auf dem Computer zu starten und zu verwenden.
-
Du musst die Laufzeitwerkzeuge für eine der in diesem Buch verwendeten Sprachen installiert haben (oder in der Lage sein, sie zu installieren).
-
In der Lage sein, ein einfaches Programm - "Hello World" - in einer der in diesem Buch verwendeten Sprachen zu schreiben und auszuführen.
Unter "Einrichten deiner Entwicklungsumgebung" in Kapitel 0 findest du weitere Details zur Installation.
Wie man dieses Buch liest
Das Thema dieses Buches ist "Testgetriebene Entwicklung in Go, JavaScript und Python". Die besprochenen Konzepte sind zwar auf alle drei Sprachen anwendbar, aber die Behandlung der einzelnen Sprachen erfordert eine gewisse Trennung des Materials in den einzelnen Kapiteln. Der beste Weg, testgetriebene Entwicklung zu lernen, ist (wie jede andere erworbene Fähigkeit) die Praxis. Ich ermutige dich, sowohl den Text zu lesen als auch den Code selbst zu schreiben. Ich nenne diesen Stil "dem Buch folgen", weil er aktives Lesen und aktives Programmieren beinhaltet.
Tipp
Um den größten Nutzen aus diesem Buch zu ziehen, schreibe den Code für das Money-Beispiel in allen drei Sprachen.
Die meisten Kapitel enthalten allgemeine Abschnitte, die auf alle drei Sprachen anwendbar sind. Daran schließen sich sprachspezifische Abschnitte an, in denen der Code für eine der drei Sprachen beschrieben und entwickelt wird. Diese sprachspezifischen Abschnitte sind immer deutlich durch ihre Überschriften gekennzeichnet: Go, JavaScript oder Python. Am Ende jedes Kapitels stehen ein oder zwei Abschnitte, die zusammenfassen, was wir bisher erreicht haben und was als Nächstes kommt.
Die Kapitel 5 bis 7 sind insofern einzigartig, als sie sich jeweils ausschließlich mit einer der drei Sprachen befassen: Go, JavaScript bzw. Python.
Abbildung P-2 zeigt ein Flussdiagramm, das den Aufbau dieses Buches und die verschiedenen Möglichkeiten, ihm zu folgen, beschreibt.
Hier sind einige "Lesewege", wie du diesem Buch am besten folgen kannst.
Folge dem Buch, eine Sprache nach der anderen
Ich empfehle diesen Weg, wenn eine oder mehrere dieser Bedingungen auf dich zutreffen:
-
Ich möchte unbedingt in eine dieser Sprachen eintauchen, bevor ich die beiden anderen in Angriff nehme.
-
Ich bin besonders neugierig (oder skeptisch!), wie TDD in einer der drei Sprachen funktioniert.
-
Ich lerne am besten, wenn ich eine Sprache nach der anderen bearbeite und nicht mehrere Sprachen gleichzeitig.
Folge dem Flussdiagramm in Abbildung P-2 eine Zeile nach der anderen. Wenn du zum Beispiel zuerst TDD in Go lernen möchtest, überspringe die Abschnitte, die mit JavaScript und Python gekennzeichnet sind, bei der ersten Lektüre. Lies dann das Buch ein zweites Mal für JavaScript und ein drittes Mal für Python durch. Du kannst die Sprachen auch in einer anderen Reihenfolge durcharbeiten. Der zweite und dritte Durchgang sollte schneller gehen als der erste; sei aber auf die Eigenheiten jeder Sprache vorbereitet!
Wenn du dem Buch auf diese Weise folgst, wirst du feststellen, dass du durch das sukzessive Schreiben des Codes in jeder Sprache einen besseren Einblick in TDD als Prinzipbekommst - über dieDetails des Testens als Sprachfunktion hinaus. Die Gewöhnung an das Schreiben von Tests ist notwendig, aber noch wichtiger ist es, die Gründe zu verstehen, warum testgetriebene Entwicklung in allen Sprachen funktioniert.
Befolge das Buch zuerst in zwei Sprachen und dann in der dritten Sprache
Ich empfehle diesen Weg, wenn du dich mit einer der folgenden Aussagen identifizieren kannst:
-
Ich möchte die Lösungen für dasselbe Problem in zwei Sprachen erstellen und vergleichen.
-
Ich fühle mich mit einer der Sprachen weniger wohl und möchte sie erst nach den anderen beiden in Angriff nehmen.
-
Ich kann in zwei Sprachen gleichzeitig programmieren, aber es würde mir schwerfallen, alle drei gleichzeitig zu jonglieren.
Folge dem in Abbildung P-2 gezeigten Flussdiagramm zwei Zeilen auf einmal. Wenn du das Geldproblem für zwei Sprachen gelöst hast, blätterst du das Buch noch einmal durch, um die dritte Sprache zu lösen.
Es kann vorkommen, dass du im ersten Durchgang zwei Sprachen verfolgen willst, dich aber nicht entscheiden kannst, welche Sprache du auf eine zweite Lesung verschieben willst. Hier sind einige Vorschläge, wie du zwei der drei Sprachen auswählen kannst:
-
Willst du eine dynamisch typisierte Sprache mit einer statisch typisierten Sprache vergleichen und den Tech-Stack der Sprache einfach halten? Folge zuerst Go und Python und dann JavaScript.
-
Bist du bereit, unterschiedliche Methoden zur Codeerstellung in zwei verschiedenen Sprachen kennenzulernen und dich mit verschiedenen Tech-Stacks auseinanderzusetzen? Folge zuerst Go und JavaScript und später Python.
-
Willst du zwei dynamisch typisierte Sprachen vergleichen und gegenüberstellen? Schau dir zuerst JavaScript und Python an und dann Go.
Wenn du das Buch auf diese Weise liest, wirst du schnell die Gemeinsamkeiten und Unterschiede bei der Durchführung von TDD in verschiedenen Sprachen entdecken. Während die syntaktischen und gestalterischen Unterschiede in den Sprachen zu offensichtlichen Unterschieden führen, wirst du vielleicht überrascht sein, wie tief die TDD-Disziplin in die Art und Weise eindringt , wie du Code schreibst, unabhängig von der Sprache, in der du Code schreibst.
Verfolge das Buch in allen drei Sprachen gleichzeitig
Ich empfehle diesen Weg, wenn eine dieser Aussagen auf dich zutrifft:
-
Du willst den besten Nutzen daraus ziehen, indem du die Gegensätze und Gemeinsamkeiten der drei Sprachen lernst.
-
Du findest es einfacher, ein Buch von Anfang bis Ende zu lesen, anstatt es mehrmals durchzugehen.
-
Du hast einige Erfahrung in allen drei Sprachen, aber du hast in keiner von ihnen TDD praktiziert.
Wenn du Code in drei Sprachen gleichzeitig schreiben kannst, ohne überfordert zu sein, empfehle ich dir diesen Weg.
Unabhängig davon, welchen Weg du wählst, solltest du bedenken, dass du beim Schreiben von Code wahrscheinlich auf Herausforderungen stoßen wirst, die mit deiner speziellen Entwicklungsumgebung zu tun haben. Der Code in diesem Buch wurde zwar auf Korrektheit getestet (und sein Continuous Integration Build ist grün), aber das bedeutet nicht, dass er auf deinem Computer auf Anhieb funktioniert. (Ganz im Gegenteil, ich kann dir fast garantieren, dass du interessant steile Abschnitte auf der Lernkurve finden wirst.) Einer der wichtigsten Vorteile von TDD ist, dass du die Geschwindigkeit, mit der du vorgehst, selbst bestimmen kannst. Wenn du nicht weiterkommst, mach langsamer. Wenn du in kleineren Schritten vorankommst, ist es einfacher, herauszufinden, wo der Code in die Irre gegangen ist. Wenn du Software schreibst, musst du mit fehlerhaften Abhängigkeiten, unzuverlässigen Netzwerkverbindungen, merkwürdigen Tools und den tausend natürlichen Erschütterungen umgehen, denen Code ausgesetzt ist. Mach langsam, wenn du dich überfordert fühlst: Mach deine Änderungen kleiner und diskreter. Erinnere dich: TDD ist ein Weg, die Angst vor dem Schreiben von Code zu bewältigen!
In diesem Buch verwendete Konventionen
Es gibt zwei Kategorien von Konventionen, die in diesem Buch verwendet werden und die einer Erklärung bedürfen: typografische und kontextuelle.
Typografische Konventionen
Die Prosa in diesem Buch ist in der Schriftart, die in diesem Satz verwendet wird. Er soll gelesen und nicht wortwörtlich als Code eingegeben werden. Wenn in der Prosa Wörter verwendet werden, die auch im Code vorkommen - wie z. B. class
, interface
oder Exception
- wird eine Schriftart mit fester Breite verwendet. Dies weist dich darauf hin, dass der Begriff im Code verwendet wird oder werden wird - und zwar in genau derselben Schreibweise.
Längere Codesegmente werden in eigene Blöcke unterteilt, wie unten gezeigt.
package
main
import
"fmt"
...
func
main
(
)
{
fmt
.
Println
(
"hello world"
)
}
Alles in einem Codeblock ist entweder etwas, das du wortwörtlich eingibst , oder etwas, das das Programm als wörtliche Ausgabe produziert, mit zwei Ausnahmen.
-
Innerhalb von Codeblöcken werden Ellipsen (
...
) verwendet, um entweder ausgelassenen Code oder ausgelassene Ausgaben anzuzeigen. In beiden Fällen ist das, was ausgelassen wird, für das aktuelle Thema irrelevant. Du solltest diese Ellipsen nicht in den Code eingeben und auch nicht erwarten, dass sie in der Ausgabe zu sehen sind. Ein Beispiel ist im obigen Codeblock zu sehen. -
Innerhalb von Codeblöcken, die Ausgaben zeigen, kann es flüchtige Werte geben - Speicheradressen, Zeitstempel, verstrichene Zeit, Zeilennummern, automatisch generierte Dateinamen usw. -, diefür dich mit Sicherheit anders aussehen werden. Wenn du solche Ausgaben liest, kannst du die spezifischen flüchtigen Werte, wie z. B. die Speicheradressen im folgenden Block, getrost ignorieren:
AssertionError
:
<
money
.
Money
object
at
0x10417b2e0
>
!=
<
money
.
Money
object
at
0x10417b400
>
Tipp
Tipps sind Vorschläge, die dir beim Schreiben von Code hilfreich sein können. Sie sind vom Haupttext getrennt, damit du sie leicht nachschlagen kannst.
Wichtig
Wichtige Informationen, die für das Thema wichtig sind, werden so gekennzeichnet. Oft gibt es Hyperlinks oder Fußnoten zu Quellen, die weitere Informationen zu dem Thema liefern.
In den meisten Kapiteln wird der Code in jeder der drei Sprachen ausführlich entwickelt und diskutiert. (Die Ausnahmen sind die Kapitel 5, 6 und 7, die sich ausschließlich mit Go, JavaScript bzw. Python befassen). Um die Diskussion der einzelnen Sprachen zu trennen, weisen eine Überschrift und ein Symbol am Rand auf die Sprache hin, die ausschließlich in diesem Abschnitt behandelt wird. Halte die Augen nach diesen drei Überschriften und Symbolen offen:
-
Geh
-
JavaScript
-
Python
Lexikalische Konventionen
In diesem Buch werden zentrale Softwarekonzepte diskutiert und mit Code in drei verschiedenen Sprachen untermauert. Die Sprachen unterscheiden sich in ihrer individuellen Terminologie so stark, dass es schwierig ist, gemeinsame Konzepte zu diskutieren.
In Go gibt es zum Beispiel keine Klassen oder klassenbasierte Vererbung. Das Typensystem von JavaScript hat prototypenbasierte Objekte, was bedeutet, dass alles ein Objekt ist, auch Dinge, die normalerweise als Klassen betrachtet werden. Python, wie es in diesem Buch verwendet wird, hat die eher "traditionellen" klassenbasierten Objekte.2 Ein Satz wie "Wir werden eine neue Klasse mit dem Namen Money
erstellen" ist nicht nur verwirrend, sondern im Kontext von Go geradezu falsch interpretiert.
Um die Gefahr von Verwechslungen zu verringern, habe ich die allgemeine Terminologie in Tabelle P-1 übernommen, um auf die wichtigsten Konzepte hinzuweisen.
Begriff | Bedeutung | Äquivalent in Go | Äquivalent in JavaScript | Äquivalent in Python |
---|---|---|---|---|
Entität |
Ein singuläres, unabhängig bedeutungsvolles Domänenkonzept; ein Schlüsselnomen |
Strukturtyp |
Klasse |
Klasse |
Objekt |
Ein Beispiel für eine Entität; ein verdinglichtes Substantiv |
Struktur-Instanz |
Objekt |
Objekt |
Sequenz |
Eine sequentielle Liste von Objekten mit dynamischer Länge |
Slice |
Array |
Array |
Hashmap |
Eine Menge von (Schlüssel-Wert-)Paaren, bei denen sowohl Schlüssel als auch Werte beliebige Objekte sein können und keine zwei Schlüssel gleich sein können |
Karte |
Karte |
Wörterbuch |
Funktion |
Ein Satz von Operationen mit einem bestimmten Namen; Funktionen können (oder auch nicht) Entitäten mit Eingängen und Ausgängen haben, aber sie sind nicht direkt mit einer Entität verbunden |
Funktion |
Funktion |
Funktion |
Methode |
Eine Funktion, die mit einer Entität verbunden ist. Eine Methode wird auf einer Instanz dieser Entität (d. h. einem Objekt) "aufgerufen". |
Methode |
Methode |
Methode |
Einen Fehler melden |
Mechanismus, durch den eine Funktion oder Methode einen Fehler anzeigt |
Fehlerrückgabewert (üblicherweise der letzte Rückgabewert einer Funktion/Methode) |
Eine Ausnahme auslösen |
Eine Ausnahme auslösen |
Das Ziel ist es, Begriffe zu verwenden, die die Konzepte erklären, ohne die Terminologie einer Programmiersprache gegenüber anderen zu bevorzugen. Die wichtigste Erkenntnis aus diesem Buch sollte schließlich sein, dass testgetriebene Entwicklung eine Disziplin ist, die in jeder Programmiersprache praktiziert werden kann.
In den Abschnitten des Buches, die sich mit einer der drei Sprachen befassen (die in der Überschrift deutlich gekennzeichnet sind), verwendet der Text sprachspezifische Begriffe. Zum Beispiel wird in einem Go-Abschnitt die Anweisung gegeben, "eine neue Struktur namens Money
zu definieren". Der Kontext macht deutlich, dass sich diese Anweisung auf eine bestimmte Sprache bezieht.
Code-Beispiele verwenden
Der Quellcode für dieses Buch ist unter https://github.com/saleem/tdd-book-code verfügbar .
Wenn du eine technische Frage oder ein Problem mit den Codebeispielen hast, schicke bitte eine E-Mail an bookquestions@oreilly.com.
Dieses Buch soll dir helfen, die Kunst der testgetriebenen Entwicklung zu erlernen und zu üben. Generell darfst du jeden Code in diesem Buch in deinen Programmen und deiner Dokumentation verwenden. Du musst uns nicht um Erlaubnis fragen, es sei denn, du reproduzierst einen großen Teil des Codes. Wenn du zum Beispiel ein Programm schreibst, das mehrere Teile des Codes aus diesem Buch verwendet, brauchst du keine Erlaubnis. Der Verkauf oder die Verbreitung von Beispielen aus O'Reilly-Büchern erfordert jedoch eine Genehmigung. Die Beantwortung einer Frage mit einem Zitat aus diesem Buch und einem Beispielcode erfordert keine Genehmigung. Wenn du einen großen Teil des Beispielcodes aus diesem Buch in die Dokumentation deines Produkts aufnimmst, ist eine Genehmigung erforderlich.
Wir freuen uns über eine Namensnennung, verlangen sie aber in der Regel nicht. Eine Quellenangabe umfasst normalerweise den Titel, den Autor, den Verlag und die ISBN. Ein Beispiel: "Learning Test-Driven Development von Saleem Siddiqui (O'Reilly). Copyright 2022 Saleem Siddiqui, 978-1-098-10647-8."
Wenn du der Meinung bist, dass die Verwendung von Code-Beispielen nicht unter die Fair-Use-Regelung oder die oben genannte Erlaubnis fällt, kannst du uns gerne unter permissions@oreilly.com kontaktieren .
Wie du uns kontaktierst
Wir haben eine Webseite für dieses Buch, auf der wir Errata, Beispiele und zusätzliche Informationen auflisten. Du kannst diese Seite unter https://oreil.ly/learningTDDbook aufrufen .
Schreib eine E-Mail an bookquestions@oreilly.com, um Kommentare oder technische Fragen zu diesem Buch zu stellen.
Neuigkeiten und Informationen über unsere Bücher und Kurse findest du unter http://oreilly.com.
TDD - Die Gründe
Die Kritik an TDD - und damit auch an diesem Buch - kann in verschiedenen Formen erfolgen. Einige von ihnen sind kreativ und humorvoll, wie der erfrischende Cartoon von Jim Kersey in Abbildung P-3 zeigt.
Weniger scherzhaft: Es ist ganz natürlich, dass du Fragen zum Inhalt und zur Struktur des Buches hast. Im Folgenden findest du Antworten auf ein paar solcher Fragen.
Warum werden in diesem Buch Go, JavaScript und Python verwendet?
In diesem Buch werden Go, JavaScript und Python als die drei Sprachen verwendet, mit denen die Praxis der testgetriebenen Entwicklung demonstriert wird. Es ist eine berechtigte Frage: Warum gerade diese drei Sprachen?
Hier sind einige Gründe.
1. Sorte
Die drei Sprachen in diesem Buch repräsentieren eine Vielfalt von Gestaltungsmöglichkeiten, wie in Tabelle P-2 dargestellt.
Feature | Geh | JavaScript | Python |
---|---|---|---|
Objektorientiert |
Ja (als ES.next-konforme Sprache) |
Ja |
|
Statische vs. dynamische Typen |
Statisch typisiert |
Dynamisch typisiert |
Dynamisch typisiert |
Explizite vs. Implizite Typen |
Meistens explizit, Variablentypen können implizit sein |
Implizit typisiert |
Implizit typisiert |
Automatischer Typenzwang |
Kein Typenzwang |
Teilweise Typüberwindung (für Boolean, Number, String, Object). Keine Zwangsbehandlung für beliebige |
Einige implizite Typenzwänge (z.B. |
Ausnahmemechanismus |
Laut Konvention ist der zweite Rückgabetyp von Methoden |
Das Schlüsselwort |
Das Schlüsselwort |
Generika |
Nicht erforderlich aufgrund der dynamischen Typisierung |
Nicht erforderlich aufgrund der dynamischen Typisierung |
|
Unterstützung beim Testen |
Teil der Sprache (d. h. das Paket |
Nicht Teil der Sprache, viele Bibliotheken verfügbar (z. B. Jasmine, Mocha, Jest) |
Teil der Sprache (d. h. der |
2. Beliebtheit
Python, JavaScript und Go sind die drei wichtigsten neuen Sprachen, die Entwickler/innen lernen wollen. Das haben mehrere jährliche Umfragen von Stack Overflow in den Jahren 2017, 2018, 2019 und 2020 ergeben. Abbildung P-4 zeigt das Ergebnis der Umfrage aus dem Jahr 2020.
In der Stack Overflow-Umfrage 2021 klettert TypeScript auf den zweiten Platz und verdrängt JavaScript und Go auf den dritten bzw. vierten Platz. Python behält seinen Spitzenplatz.
Syntaktisch gesehen ist TypeScript eine strenge Obermenge von JavaScript. Daher könnte man sagen, dass jeder Entwickler, der TypeScript lernen möchte, JavaScript kennen muss. Ich hege die Hoffnung, dass auch TypeScript-Entwickler/innen dieses Buch wertvoll finden werden.
3. Ein persönlicher Grund
In den letzten fünf Jahren hatte ich die Gelegenheit, an mehreren Projekten zu arbeiten, bei denen eine dieser drei Sprachen die Hauptprogrammiersprache darstellte. Bei der Arbeit mit anderen Entwicklern stellte ich fest, dass sie TDD lernen und praktizieren wollten, aber nicht die nötigen Ressourcen (oder die nötige Disziplin) dafür aufbringen konnten. Sie wollten TDD praktizieren, wussten aber nicht wie oder fanden keine Zeit dafür. Bezeichnenderweise galt das für erfahrene Entwickler/innen genauso wie für "Noobs".
Ich hoffe, dass dieses Buch sowohl als praktischer Leitfaden als auch als Inspirationsquelle für alle dient, die TDD in jeder Sprache lernen und praktizieren wollen - nicht nur in Go, JavaScript oder Python.
Warum nicht diese andere Sprache?
Zunächst einmal gibt es eine riesige Anzahl von Programmiersprachen. Man könnte ein halbes Dutzend Bücher wie dieses schreiben und würde trotzdem nur einen kleinen Teil der Sprachen abdecken, die Entwicklerinnen und Entwickler auf der ganzen Welt täglich verwenden, um Code für akademische, geschäftliche und Freizeitzwecke zu schreiben.3
Außerdem gibt es bereits ein hervorragendes Buch zur testgetriebenen Entwicklung in Java. Kent Becks bahnbrechendes Werk hat mich, wie auch unzählige andere Entwickler, dazu inspiriert, mich in die Kunst und Wissenschaft von TDD zu verlieben. Es hat auch das "Geldproblem" ausgelöst, das in diesem Buch ein wichtiges Thema ist.
Ich bin sicher, dass es viele andere Sprachen gibt, für die ein praktischer TDD-Leitfaden nützlich wäre. Wie wäre es mit R? Oder SQL? Oder sogar COBOL?
Ich versichere dir: Der Verweis auf COBOL war weder ein Strohmann-Argument noch ein billiger Schuss. Mitte der 2000er Jahre arbeitete ich an einem Projekt, in dem ich die Fähigkeit demonstrierte, TDD in COBOL mit COBOLUnit durchzuführen. Das war der größte Spaß, den ich je in einer Sprache hatte, die mehr als ein Jahrzehnt älter ist als ich selbst!
Ich hoffe, dass du diese Aufgabe übernimmst. Dass du die Fähigkeiten und die Disziplin, die notwendig sind, um testgetriebene Entwicklung in anderen Sprachen zu praktizieren, lernst, lehrst und vertrittst. Dass du einen Blog, ein Open-Source-Projekt oder das nächste Buch in dieser Reihe schreibst.
Warum hat dieses Buch ein "Kapitel 0"?
Die große Mehrheit der Programmiersprachen verwendet eine 0-basierte Indizierung für Arrays und andere abzählbare Sequenzen.4 Das gilt auch für die drei Programmiersprachen, die die Grundlage dieses Buches bilden. In gewisser Weise ehrt dieses Buch die reiche Geschichte der Programmierkultur, indem es die Kapitel mit 0 beginnend nummeriert.
Ich möchte auch der Zahl Null selbst eine Hommage erweisen, die eine radikale Idee ist. Charles Seife hat ein ganzes Buch über diese einsame Zahl geschrieben. Indem er die Geschichte der Null nachzeichnet, stellt Seife fest, dass die Griechen Vorbehalte gegen eine Zahl hatten, die für nichts steht:
In diesem [d.h. dem griechischen] Universum gibt es so etwas wie das Nichts nicht. Es gibt keine Null. Aus diesem Grund konnte der Westen die Null fast zwei Jahrtausende lang nicht akzeptieren. Die Folgen waren verheerend. Die Abwesenheit der Null würde das Wachstum der Mathematik bremsen, die Innovation in der Wissenschaft hemmen und ganz nebenbei auch den Kalender durcheinander bringen. Bevor sie die Null akzeptieren konnten, mussten die Philosophen des Westens ihr Universum zerstören.
Charles Seife, Zero: Die Biografie einer gefährlichen Idee
Auf die Gefahr hin, zu erhaben zu werden: Die testgetriebene Entwicklung nimmt in der heutigen Programmierkultur einen ähnlichen Platz ein wie die Null in der westlichen Philosophie vor ein paar Jahrtausenden. Es gibt einen Widerstand dagegen, der aus einer seltsamen Kombination aus Ablehnung, Unbehagen und der Überzeugung entsteht, dass es einfach zu viel Lärm um nichts ist. "Warum soll ich erst Tests schreiben - ich weiß doch schon, wie ich die Funktion programmieren werde!" "Testgetriebene Entwicklung ist pedantisch: Sie funktioniert nur in der Theorie und nie in der Praxis. "Das Schreiben von Tests nach dem Schreiben des Produktionscodes ist mindestens genauso effektiv wie das Schreiben von Tests am Anfang, wenn nicht sogar effektiver. Diese und andere Einwände gegen TDD ähneln in ihrer Radikalität der Zahl Null!
Die Praxis, dass ein Buch ein Kapitel 0 hat, ist ohnehin nicht ganz radikal. Carol Schumacher hat ein ganzes Buch mit dem Titel Kapitel Null geschrieben : Fundamental Notions of Abstract Mathematics (Grundbegriffe der abstrakten Mathematik) geschrieben, das in vielen College-Lehrplänen ein Standardlehrbuch für fortgeschrittene Mathematik ist. Du darfst nicht raten, mit welchem nummerierten Kapitel das Buch beginnt!
Dr. Schumacher sagt im Lehrerhandbuch zu ihrem Buch etwas, das ich sehr erhellend finde:
Deine Aufgabe als Autorin oder Autor ist es, deinen Leserinnen und Lesern die richtigen Hinweise zu geben, die es ihnen so leicht wie möglich machen, zu verstehen, was du sagen willst.
Carol Schumacher, Instructor's Resource Manual für die Verwendung mit Kapitel Null
Ich habe mir diesen Rat zu Herzen genommen. Pragmatischerweise hilft ein Titel mit "0", das Kapitel 0 von der darauf folgenden Abhandlung zu unterscheiden. Kapitel 1 dieses Buches nimmt uns mit auf eine TDD-Reise, die sich durch das nächste Dutzend Kapitel zieht. In Kapitel 0 geht es darum, zu beschreiben, was diese Reise ist, was wir wissen und haben müssen, bevor wir sie antreten, und was wir erwarten können, wenn wir uns auf ihr befinden.
Damit sind die Erklärungen aus dem Weg geräumt und wir können direkt mit Kapitel 0 weitermachen!
1 Diese Definition von Einfachheit ist in einem der 12 Prinzipien des Agilen Manifests verankert.
2 Python unterstützt die objektorientierte Programmierung (OOP) sehr gut. Siehe zum Beispiel prototype.py
das prototypenbasierte Objekte in Python implementiert.
3 Obwohl es unwahrscheinlich ist, dass ein Buch über TDD in einer bestimmten Sprache die Zustimmung der Verlage erhält. Sein Name beginnt mit "Brain" und endet mit einem Schimpfwort!
4 Lua ist eine bemerkenswerte Ausnahme. Mein Freund Kent Spillner hat einmal einen faszinierenden Vortrag zu diesem Thema gehalten, den ich hier zusammengefasst habe.
Get Testgetriebene Entwicklung lernen now with the O’Reilly learning platform.
O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.