Was heißt eigentlich "validieren"?
"Validierung" ist einer dieser Begriffe, die für mich ein rotes Tuch sind, weil expliziter Code zur Validierung in vielen Fällen ein Design Smell ist.
Warum ist das so? Weil die Plausibilitätsprüfungen für eine IBAN nach meiner Meinung nicht etwa in einen IBANValidator
gehören, der an das Framework gekoppelt ist, und schon gar nicht in eine Konfigurationsdatei, sondern am besten als expliziter PHP-Code in eine Klasse IBAN
.
Wenn jemand die Frage stellt, welche Regeln in der Anwendung für eine IBAN gelten, dann ist es für mich ein sehr geradliniges Vorgehen, im Code nach dem Bezeichner IBAN
zu suchen und dort nachzuschauen. Zudem können wir eine unabhängige Klasse IBAN
auch viel einfacher in einem anderen Projekt wiederverwenden.
Oft meinen wir eigentlich Geschäftsregeln, wenn wir von Validierung sprechen. Wenn beispielsweise sagen "wir akzeptieren nur deutsche IBANs", was wir ja weiter schon so angedeutet hatten, dann ist das eine Geschäftsregel und keine Regel zur Validierung. Eine IBAN ist ja nicht ungültig, nur weil das Bankkonto in Österreich ist. Wir akzeptieren sie vielleicht nicht, aber technisch gesehen gültig ist sie trotzdem. Das ist eine Geschäftsregel.
Genau deswegen vermeide ich es, von Validierung zu sprechen. Stattdessen sollten wir uns auf die Erstellung von Objekten fokussieren, die fachlich relevant sind. So wie IBAN
eben.
Solche fachlichen Objekte müssen immer gültig sein und dürfen niemals ungültig werden.
Genau deswegen werfen wir im Konstruktor eine Exception, wenn wir an IBAN
etwas übergeben,
das nach unserem Dafürhalten gar keine IBAN sein kann. Ja, das ist ein Wertobjekt.
Mit diesem Wertobjekt machen wir aber keine Aussage darüber, ob eine IBAN ein tatsächlich existierendes Bankkonto repräsentiert. Das kann uns vermutlich nur die Bank selbst sagen, und möglicherweise will sie das aus Gründen der Sicherheit nicht tun. Im besten Fall gibt es einen Online-Service, den wir nach einer IBAN fragen und der uns sagt, ob diese IBAN ein existierendes Konto ist oder nicht. Im schlechtesten Fall müssen wir einen Prozess etablieren, um das selbst zu prüfen. Das könnten wir beispielsweise tun, indem wir einen Cent auf das Konto überweisen. Wenn wir diese Überweisung zurückerhalten, dann existiert offenbar kein Konto mit dieser IBAN.
Das ist übrigens eine Annahme, die nicht für jede Bank gelten muss. Eine Bank könnte sich ja auch über den unerwarteten Geldsegen freuen und den Cent in die Kaffeekasse der Angestellten buchen. Aber wir wollen es hier jetzt nicht übertreiben. Daher ignorieren wir für dieses Beispiel geflissentlich auch die Temporalität der Welt ("letzte Woche hat das Konto noch existiert ...").
Wir haben jetzt also sozusagen drei Klassen von Kandidaten-IBANs:
- Irgendein String, der gar keine gültige IBAN sein kann
- Ein String, der wie eine gültige IBAN aussieht
- Eine IBAN, von der wir wissen, dass dazu ein Bankkonto existiert
Mit dem ersten Fall können und wollen wir nichts weiter anfangen, außer vielleicht irgendwo eine Fehlermeldung anzuzeigen, dass der Benutzer eine falsche IBAN angegeben hat. Das ist der Fall, bei dem wir im Konstruktor von IBAN
eine Exception werfen, denn wir wollen verhindern, dass ein IBAN
-Objekt einen ungültigen Zustand hat.
Das ist übrigens ein Grund dafür, dass wir Wertobjekte unveränderlich machen, denn ein anfangs gültiger Wert bleibt per Definition gültig, weil und wenn er nicht unveränderlich ist.
Im zweiten Fall würden wir um diesen String sozusagen ein Wertobjekt wickeln, das implizit die Information "mein Inhalt sieht gut aus" transportiert. Das ist ein echter Mehrwert gegenüber der Arbeit mit skalaren Daten.
Bleibt der dritte Fall. Wenn unser IBAN
-Objekt semantisch aussagt, dass ein String nach einer gültigen IBAN aussieht, wie repräsentieren wir dann eine IBAN, von der wir zusätzlich wissen, dass dazu ein Bankkonto existiert?
Sollten wir dem Objekt IBAN
einen Status geben? Das würde allerdings der Unveränderlichkeit von Wertobjekten widersprechen.