Two More Billion Dollar Mistakes
Find the English version below
Hi ,
Du hast bestimmt schon mal mitbekommen, dass null
von seinem Erfinder Tony Hoare als "Billion Dollar Mistake" bezeichnet wird. 2009 entschuldigte er sich auf der QCon öffentlich, dafür dass er 1965 den leichten Weg gegangen ist und null
erfunden hat:
"I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object-oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
~ Tony Hoare (2009)
Doch darüber möchte ich heute gar nicht reden. Ich rede heute über zwei weitere Anti-Pattern. Sie haben mit Sicherheit auch eine Milliarde Dollar an Schmerz und Schaden verursacht:
Unit-Tests haben nichts mit TDD zu tun
Das mag dich überraschen. Wenn du TDD machst, dann schreibst du wahrscheinlich Unit-Tests. Oder zumindest nutzt du JUnit. Ist JUnit eigentlich ein Unit Test? Wir nutzen diese Begriffe im Sprachgebrauch bereits äquivalent. JUnit ist nur ein Tool zum Schreiben von Tests. Mit JUnit können wir natürlich auch Integrationstests, Systemtests oder Akzeptanztests schreiben.
Wenn wir heute über Unit-Tests sprechen, dann denken wir schnell an einen Test, der eine Klasse in Isolation testet.
Als TDD in den verschiedenen Software-Communities weltweit entstand, gab es diese Definition von Unit-Tests aber noch nicht. TDD hatte die Idee, erst die Anforderung an den Code in Form eines Tests auszudrücken und danach die Implementierung dafür zu schreiben. Und das in möglichst kleinen Iterationen.
Dabei soll der Test immer spezifischer werden und die Implementierung über die Zeit generischer.
Und genau in dieser Idee liegt der Konflikt mit der heutigen Praxis. Wenn wir einen Test semantisch an eine Klasse binden - was wir tun, wenn wir mit dem CustomerServiceTest
den CustomerService
testen - dann können wir unsere Implementierung nur zu einem gewissen Grad verändern, ohne die Tests und deren Struktur anzupassen.
Die heutige Praxis von Unit-Testing steht im Weg zum effektivem Praktizieren von TDD. Die Testklassen, deren Namen, deren Packages und dessen Architektur sollte nichts mit der Implementierung zu tun haben.
Unit-Tests haben nichts mit TDD zu tun. Es sind zwei fundamental unterschiedliche Begriffe, die sich tangieren, aber nicht gleich sind. Durch diese Fehleinschätzung sind Milliarden Zeilen Testcode entstanden, der schwer zu warten und fragil ist.
Microservices sind nicht Micro
Der Begriff Microservice impliziert, dass wir von kleinen Services sprechen. Aber wann ist ein Service klein? Wenn er nur eine Sache tut? Wenn er nur einen Endpunkt hat? Wenn er nur 100 Zeilen Code hat? Ist ein Service mit 2 Endpunkten immer noch klein? Sind 10 Endpunkte in Ordnung?
Das sieht jeder Entwickler etwas anders. Nach DDD sollte ein Service eine Domäne abbilden. Da DDD und Microservices häufig in einen Topf geworfen werden, wird also probiert, eine Domäne als einen Microservice zu designen.
Und jetzt beißt uns das "Micro" in Microservice. Durch diese Bezeichnung wird oft angenommen, eine Domäne muss klein sein. Und das sorgt für viel zu kleine Schnitte.
Das verführt uns dazu, Domänen zu sehen, wo keine sind.
Plötzlich entsteht ein Customer-Microservice. Und ein Tenant-Microservice. Und ein Payment-Microservice. Aber bei meinen Kunden - die aus dem deutschen Mittelstand kommen - gibt es meistens nur eine einzige Domäne. Diese Services sind nur entstanden, weil der Begriff uns dazu verführt.
Dieser Trugschluss hat Milliarden Dollar an unnötigem Entwickleraufwand, Performanceproblemen, Fehlern in Folge von Inkonsistenzen und Kopfschmerzen verursacht.
Microservices sind nicht micro!
ps. Seit Montag ist mein neuer Artikel "Mittelstand, Finger weg von Microservices!" auf golem plus verfügbar. Lies doch mal rein, wenn du Abonnent bist 🙂
Rule the Backend,
~ Marcus
Hi ,
You might have heard that null
was referred to by its creator, Tony Hoare, as the "billion-dollar mistake." In 2009, he publicly apologized at QCon for taking the easy path in 1965 by inventing null
:
"I call it my billion-dollar mistake. It was the invention of the null reference in 1965. At that time, I was designing the first comprehensive type system for references in an object-oriented language (ALGOL W). My goal was to ensure that all use of references should be absolutely safe, with checking performed automatically by the compiler. But I couldn't resist the temptation to put in a null reference, simply because it was so easy to implement. This has led to innumerable errors, vulnerabilities, and system crashes, which have probably caused a billion dollars of pain and damage in the last forty years."
~ Tony Hoare (2009)
However, that's not what I want to talk about today. I want to discuss two other anti-patterns that have likely also caused a billion dollars in pain and damage:
Unit Tests are Unrelated to TDD
This might surprise you. If you practice TDD, you probably write unit tests. Or at least, you might use JUnit. But is JUnit a unit test? We've come to use these terms interchangeably. JUnit is merely a tool for writing tests. With JUnit, we can also write integration tests, system tests, or acceptance tests.
When we talk about unit tests today, we often think of a test that isolates and tests a single class.
However, when TDD was emerging in various software communities around the world, this definition of unit tests did not exist. TDD was based on the idea of first expressing a code requirement in the form of a test and then writing the implementation for it, in as small iterations as possible.
The goal is for the test to become more specific over time while the implementation becomes more generic.
This is where the conflict with current practices lies. If we semantically tie a test to a class - as we do when we test CustomerService
with CustomerServiceTest
- we can only change our implementation to a certain degree without having to adjust the tests and their structure.
Current unit testing practices obstruct the effective practice of TDD. The test classes, their names, packages, and architecture should not be tied to the implementation.
Unit tests are unrelated to TDD. They are two fundamentally different concepts that intersect but are not identical. This misconception has led to the creation of billions of lines of test code that are difficult to maintain and fragile.
Microservices are Not Micro
The term "Microservice" suggests that we are talking about small services. But when is a service considered small? When it does just one thing? When it has just one endpoint? When it consists of only 100 lines of code? Is a service with two endpoints still small? Are 10 endpoints acceptable?
Each developer might see this differently. According to DDD (Domain-Driven Design), a service should represent a domain. Since DDD and microservices are often lumped together, there is an attempt to design a domain as a microservice.
And that's where the "Micro" in Microservice becomes problematic. This label often leads to the assumption that a domain must be small, resulting in overly fine-grained divisions.
It tempts us to see domains where there are none.
Suddenly, a Customer Microservice emerges. Then a Tenant Microservice. And a Payment Microservice. But with my clients, who typically come from the German Mittelstand, there is usually only one domain. These services only arose because the term led us astray.
This misconception has caused billions of dollars in unnecessary development effort, performance issues, errors due to inconsistencies, and headaches.
Microservices are not micro!
ps. Since Monday, my new article "Mittelstand, Stay Away from Microservices!" has been available on golem plus. Check it out if you're a subscriber 🙂
Rule the Backend,
~ Marcus