- Eine Banking-as-a-Service-Plattform, mit der FinTechs Kontoeröffnung, Zahlungen und Onboarding direkt wie an eine Bank-API anbinden können; erhielt im März 2023 eine britische Banklizenz und wurde damit zu einer regulierten Bank
- Das System läuft auf Clojure on Kubernetes on AWS und kombiniert eine Event-Sourcing-Architektur, die die meisten Eingaben in Events umwandelt, mit einem FoundationDB-Storage
- FoundationDB ist ein strict-serializable Key-Value-Store, der Transaktionen und gleichzeitige Schreibvorgänge unterstützt; Griffin baut darauf atomare Lese- und Schreibvorgänge über eine Datomic-ähnliche Schicht auf, die von Datascript portiert wurde
- Die Business-Logik ist rund um kleine Log Processor getrennt aufgebaut, die Clojure-Maps annehmen und Clojure-Maps ausgeben; Zugriffe auf externe Systeme sind auf Protokolle und dedizierte Procs beschränkt
- Die Unveränderlichkeit von Clojure und die Eignung für Audit-Logs passen zu den Anforderungen von Finanzdiensten; kombiniert mit Remote Hiring soll es dadurch leichter sein, selbst aus einem kleinen Kandidatenpool sehr gute Engineers zu finden
Eine regulierte Bankenplattform als API
- Griffin ist eine Banking-as-a-Service-Plattform, die FinTech-Unternehmen hilft, Bankfunktionen schnell und sicher zu integrieren
- Im März 2023 erhielt das Unternehmen von der Financial Conduct Authority eine UK-Banklizenz und wurde damit zu einer vollständig regulierten britischen Bank
- Griffin bezeichnet sich selbst als „the bank you can build on“ und verfolgt das Ziel, eine Art AWS für Banken zu sein
- API für Kunden-Onboarding
- API zur Erstellung von Bankkonten
- Zahlungs-API
- Um solche Funktionen anzubieten, müssen FinTechs rechtlich mit einer Bank zusammenarbeiten; derzeit geschieht das oft mit etablierten High-Street-Banken, die noch Mainframes nutzen
- Griffin will Banklizenz und Technologieplattform gemeinsam anbieten, um die Grundlage zu werden, auf der künftige FinTechs ihre Services aufbauen können
- Die Lizenz war bereits erteilt, aber zu diesem Zeitpunkt befand sich das Unternehmen noch in der Mobilisierungsphase; diese endet nach abgeschlossener Prüfung, zusätzlicher Finanzierung und Fertigstellung des Codes
- Der Zielzeitpunkt war Q3 oder Q4 desselben Jahres
Warum Clojure gewählt wurde
- Clojure wurde als Plattformsprache gewählt wegen Unveränderlichkeit, Ausdrucksstärke und der guten Eignung für Finanzservices, die Audit-Logs benötigen
- Allen Rohner sah um 2007 einen Clojure-Vortrag von Rich Hickey und kam zu dem Schluss, dass es besser sei als das Lisp, das er selbst baute
- Nach der Gründung von CircleCI im Jahr 2011 setzte er Clojure über lange Zeit ein; dort funktionierte es gut und erschien ihm auch für Finanzservices passend
- Die Vorteile der JVM erkannte er in den ersten Jahren noch nicht vollständig, bewertete sie später aber als großen Pluspunkt
- Andere Nischen-Startup-Sprachen können unter fehlenden Bibliotheken sowie Problemen bei Compiler- oder Runtime-Performance leiden
- Die JVM reduziert diese Risiken
- Die Wahl der Sprache zeigt auch den Charakter eines Unternehmens; Clojure wurde als stärkere Wahl als Python oder Java gesehen
- Auch wenn eine Nischensprache die Zahl der Kandidaten verringert, kann der Anteil an Top-Talenten höher sein
Die Datenschicht auf FoundationDB
- Die Griffin-Architektur läuft auf Clojure, Kubernetes und AWS und ist fast vollständig als Event Sourcing aufgebaut
- Als Datenbank wird FoundationDB eingesetzt
- FoundationDB ist ein strict-serializable Key-Value-Store mit Transaktionsunterstützung
- Begann als Startup im Silicon Valley
- Wurde 2015 von Apple übernommen
- Um 2018 stellte Apple die Software wieder als Open Source bereit
- Apple nutzt sie in der iCloud-Produktion
- Apple führte Benchmarks durch, in denen FoundationDB mit etwa 1 Million Transaktionen pro Sekunde lief
- Strict serializable entspricht beim Thema Datenbankkonsistenz der höchsten Stufe
- Die Basis-API ist eher
get a key,set a keyund kein SQL - Griffin portierte Datascript auf FoundationDB und baute damit eine Datomic-ähnliche Schicht
- Dadurch sind atomare Abfragen auf einem strict-serializable Datenspeicher möglich
- Unterstützt transaktionsbasierte Lese- und Schreibvorgänge
- FoundationDB ist kein Single-Writer-System, sondern unterstützt concurrent writes
- Griffin benötigt mehr als 1.000 Transaktionen pro Sekunde und erfüllt diese Anforderung
Event Sourcing und Log Processor
- Jede Eingabe in das Griffin-System wird zu einem Event
- API-Request
- Third-Party-Webhook
- Events landen in einem Message Log; bei Griffin ist ein Event eine Clojure-Map mit einem
type-Feld, Key/Value-Daten und einer Spec - Das gesamte System ist als Reaktion auf Events aufgebaut
- Ein kleiner Log Processor wird
procgenannt- Ein Proc arbeitet nach dem Muster: „höre auf Message-Typ A und emittiere als Reaktion B oder C“
- Jeder Proc besitzt einen eigenen privaten State
- Der Nachrichtenfluss lässt sich als Graph darstellen, und Events bewegen sich darin, bis sie einen Terminalknoten erreichen
- Ein Beispiel: Der Webserver empfängt ein HTTP-Event, protokolliert eine Zahlungsanfrage und wartet dann auf ein
payment created- oderpayment rejected-Event, bevor er dem Client antwortet- Dieser Ablauf nutzt einen asynchronen HTTP-Handler von Netty
- Alle Events werden in FoundationDB geschrieben
- Jeder Log Processor hat darin private Daten, ähnlich einem eigenen Namespace
- Ein Proc überwacht, wann bestimmte Event-Typen geschrieben werden, und schreibt seine eigenen Events wieder in FoundationDB zurück
- FoundationDB bietet die Möglichkeit, Änderungen an DB-Keys zu überwachen, wodurch sich reaktive Systeme effizient bauen lassen
- Wenn man Datenbank und separates Messaging-System kombiniert, entsteht die Möglichkeit von Race Conditions
- Zum Beispiel kann eine Nachricht auf die Platte geschrieben werden und eine andere über das Netzwerk gehen, sodass ein Beobachter beide in unterschiedlicher Reihenfolge sieht
- Griffin schreibt deshalb alles in FoundationDB, um es auf einen einzigen Pfad zu vereinfachen
Monorepo und Isolierung der Business-Logik
- Griffin verwendet ein Monorepo
- Derzeit laufen aus Effizienzgründen viele Log Processes in derselben JVM
- Sie sind jeweils unabhängig und könnten auch als separate JVM-Prozesse laufen
- Aktuell laufen Proc-Komponenten im niedrigen Hunderterbereich in einer einzigen JVM
- Die Business-Logik wird so einfach und sauber wie möglich gehalten
- Die einzelnen Log-Processor-Namespaces bestehen fast vollständig aus purem Clojure
- Es gibt kaum Third-Party-Bibliotheken
- Auch Side Effects sind sehr selten
- Ein Log Processor ähnelt einer Funktion, die eine Clojure-Map als Eingabe nimmt und eine oder mehrere Clojure-Maps zurückgibt
- Für den Proc-State gibt es Protokolle, sodass die Gegenimplementierung nicht bekannt sein muss
- In Tests kann ein In-Memory-Database-Ersatz verwendet werden
- Im echten Betrieb kann auf FoundationDB geschrieben werden
- Die Schnittstelle zur Außenwelt wird so klein wie möglich gehalten
- Die meisten Procs dürfen nur in ihren internen State schreiben und Nachrichten emittieren
- Keine Netzwerkaufrufe
- Keine AWS-Aufrufe
- Keine anderen externen Aktionen
- Wenn Kommunikation mit externen Systemen nötig ist, gibt es spezielle Procs mit dediziertem Dispatch-Handler
- Ein Proc für die Kommunikation mit AWS
- Ein Proc für die Kommunikation mit der Clearing-Bank
- Ein Proc für die Kommunikation mit anderen APIs
Das verwendete Clojure-Ökosystem
- Innerhalb der Business-Logik werden fast keine Bibliotheken verwendet
- In Bereichen mit Kontakt zur Außenwelt wie API-Webserver oder Service-Gateway wird Folgendes eingesetzt
ringnettyreitit
- Clojure spec wird umfassend verwendet
- Für die AWS-Integration wird die Bibliothek Cognitect
aws-apieingesetzt - Für Applikationskonfiguration und Ressourcenmanagement wird ein Ansatz auf Basis des Blogposts closeable genutzt
- Die Idee ist, dass
with-openauch ohne Component oder Integrant ausreicht - Man erhält lexical scope, und die Reihenfolge der Binding-Deklarationen erzwingt die Reihenfolge der Konfiguration
- Für State-Objekte oder zustandslose Objekte, die
Closeablenicht implementieren, wird ein kleiner Helper verwendet, damit sie in einemwith-open-Block deklariert werden können
- Die Idee ist, dass
Hiring und Teamaufbau
- Griffin sieht bei Clojure-Hiring zwar weniger Kandidaten, aber einen höheren Anteil guter Bewerber
- Bei Java-Hiring können 1.000 CVs eingehen, von denen 10 gute Kandidaten sind
- Bei Clojure-Hiring könnten 13 CVs eingehen, von denen 10 gute Kandidaten sind
- Bei einem kleinen Hiring-Pool ist Remote-Arbeit wichtig
- Wenn regionale Einschränkungen wegfallen, lässt sich ein größerer Pool über die ganze Welt, innerhalb von drei Zeitzonen oder in Europa aufbauen
- Die Situation, in kurzer Zeit 100 Engineers einstellen zu müssen, wird als Anti-Pattern gesehen
- Das Unternehmen hat insgesamt etwa 70 Mitarbeitende
- Engineering umfasst etwa 22 bis 24 Personen
- Etwa zwei Drittel sind im UK
- Etwa ein Drittel in der EU
- Rund 4 in Deutschland, 4 in Schweden und 1 in Irland
- Der Hauptsitz ist in London, aber die meisten Entwickler sitzen anderswo im UK
Tests der operativen Resilienz auf Bankniveau
- Als Bank muss Griffin operativ resilient sein; das wird fast als Anforderung an null Downtime verstanden
- Da das Unternehmen mit Geld arbeitet, muss es praktisch nachweisen können, dass Kundengelder selbst bei Problemen nicht verloren gehen
- Eine interessante Test-Richtung ähnelt dem Ansatz des FoundationDB-Teams
- Das FoundationDB-Team baute einen Datenbank-Simulator
- Etwa 20 Prozesstypen beziehungsweise Rollen innerhalb des Clusters wurden als Single-Threaded-C++-Apps geschrieben
- Auf C++ wurde ein Actor-Model-Concurrency-Compiler aufgebaut
- Jeder System-Call und Network-Call läuft über Protokolle, damit Fehler injiziert werden können
- Auch Multithreading wird über ein nachrichtenbasiertes Actor-Modell verarbeitet
- In dieser Umgebung lassen sich Fehler deterministisch injizieren
- Der Fall, dass Message A und B gesendet werden, aber auf der Gegenseite in der Reihenfolge B, A ankommen
- Der Fall, dass während der Verarbeitung einer Nachricht ein Fehler beim Schreiben auf die Festplatte auftritt
- Das ähnelt dem generativen Testen mit
test.check, bei dem die gesamte Nichtdeterministik des Systems aus einer einzelnen kontrollierbaren Zufallszahl gesät wird - Kontrollieren möchte man insbesondere Disk Errors, Network Errors und Message Reordering
- Das aktuelle Problem ist, dass es keine Möglichkeit gibt, das Verhalten von Java-Threading-Bibliotheken, NIO und Disk Writes zu steuern
- Es gibt eine geistige Nähe zu Jepsen, aber auch Unterschiede
- Jepsen wirkt eher wie rohe Gewalt mit mehreren VMs und dem Abschießen von Prozessen
- Da sich der Datenbankzustand intern schwer prüfen lässt, ist die Abdeckung schwer einzuschätzen
- In einer vollständig kontrollierbaren Umgebung kann man System-Calls oder Message-Interleavings aufzählen und im Speicher sehr schnell prüfen
- Das FoundationDB-Team hat eine solche Testumgebung früh aufgebaut; das ist ein wichtiger Grund für das Vertrauen in FoundationDB
- Griffin stellt ein; Informationen gibt es auf der Griffin careers page
1 Kommentare
Hacker-News-Kommentare
James Trunk, der aktuelle VP of Engineering bei Griffin, hat die klarste und unterhaltsamste Einführung in Clojure als Technologie gehalten, die ich je gesehen habe. Empfehlenswert.
https://youtu.be/C-kF25fWTO8?si=PnjMNLdBLJ8zqSu-
Das Problem ist derzeit, dass man keine Möglichkeit hat, die zugrunde liegenden Java-Threading-Bibliotheken, NIO und das Verhalten beim Schreiben auf die Festplatte zu steuern; und angesichts der Natur solcher Systeme scheint das auch in Zukunft unmöglich zu sein.
In Systemen, die nichtdeterministische Request-Reihenfolgen oder Task-Scheduling verwenden, kann man keine deterministische Ausführung erreichen. Genau das passiert, wenn immer mehrere OS-Threads verwendet werden oder in Tests mehrere separate Prozesse gestartet werden.
Man könnte es mit Gewalt deterministisch machen, aber dafür müsste man in jede Transition der Zustandsmaschine der Anwendung Synchronisationspunkte einbauen, die der Test steuern kann, was sehr schwierig ist.
Praktisch gesehen scheint es nur den Weg zu geben, den Kern des Systems vollständig synchron zu entwerfen und die Nebenläufigkeit zur Laufzeit in einer höheren Schicht hinzuzufügen.
procshaben keine Seiteneffekte, abgesehen von dem, was jenseits von Clojure-Protokollen (Java-Interfaces) passiert.Deshalb lassen sich während der Tests alle Seiteneffekte durch Stubs ersetzen. Unser „User“-Code hat keinen Zugriff auf Threading-Bibliotheken; Threading findet im „Kernel“-Code statt.
Ein gutes Beispiel, in dem dieser Ansatz tatsächlich bereits umgesetzt ist, findet man hier: https://www.youtube.com/watch?v=4fFDFbi3toc
Für die Tests von missionary selbst werden missionary-Flows bereits instrumentiert und Zustandsübergänge verifiziert.
Ziemlich cool, dass die beiden Gründer gemeinsam ein Buch namens Learning ClojureScript geschrieben haben.
https://www.packtpub.com/product/learning-clojurescript/9781...
Der Satz „Wir scherzen gern, dass wir ein Technologieunternehmen mit Banklizenz sind“ ist ein Zitat, das später ziemlich schlecht aussehen könnte, wenn etwas schiefgeht.
Mein Arbeitgeber bezeichnete sich als Bildungs- und Forschungsunternehmen, das Forschungsergebnisse mit Software kommerzialisiert; das war für mich viel plausibler und hat auch die Kultur besser gemacht.
In der Bankenbranche kann es sehr teuer sein, dieses Wissen erneut zu lernen.
Ernst gemeinte Frage, und sorry für die schroffe Formulierung: Warum sollte es mich interessieren, in welcher Sprache ein Dienst geschrieben ist, den ich nutze? Warum ist es wichtig, dass er in Clojure geschrieben ist? Beruflich bin ich Clojure-Entwickler, daher ist es cool zu sehen, dass so etwas in Clojure geschrieben wurde, aber ich weiß nicht, warum mich das interessieren sollte.
Das ist einer der Aspekte, die ich an der Community wirklich nicht mag. Clojure ist eine mächtige Sprache und ich nutze sie gern, aber in der Community gibt es irgendwie so etwas wie ein Impostor-Syndrom, als müsse man anderen erzählen und rechtfertigen, dass diese Sprache in einem Projekt verwendet wird; das fühlt sich seltsam an.
Ich verstehe den Punkt nicht ganz. Soll das in einer zivilisierten Gesellschaft etwa unangemessenes Verhalten sein?
Das klingt ziemlich ignorant. Wenn es dich „nicht interessiert“, musst du dich nicht damit befassen; lass die Autoren einfach schreiben, worüber sie schreiben wollen.
Ich erinnere mich, dass PHP- und Python-Entwickler in den 90ern solche Beispiele geteilt haben, um Business-Fragen wie „Warum verwendet ihr nicht Microsoft ASP?“ zu beantworten.
Oder es geht vielleicht darum, Entwickler für das eigene Unternehmen zu gewinnen.
Warum sind solche API-Banken eigentlich immer im Vereinigten Königreich? Ich wollte seit Jahren Banking per curl machen, aber in den USA bietet das niemand an.
Dagegen hat das Vereinigte Königreich neue Banken und neue Technologien aktiv gefördert. Kostenlose Sofortüberweisungen zwischen Privatkonten gibt es seit fast 20 Jahren, kontaktloses Bezahlen seit mindestens 10 Jahren, Mobile Banking seit Jahrzehnten, und staatlich vorgeschriebene Bank-APIs seit fast 5 Jahren.
Kurz gesagt: Das Vereinigte Königreich hat, gemessen an Bankstandards, einen sehr dynamischen Bankensektor, der schnell innoviert hat, sowie ein gut entwickeltes Umfeld und Ökosystem für noch schnellere Innovation.
In den USA scheinen die Banken technologische Innovation vor Jahrzehnten aufgegeben zu haben und stattdessen lieber bei Gebühren und bei der strafenden Behandlung von Kunden zu innovieren. Deshalb gibt es kein neues Innovationsumfeld, und für etablierte Banken ist es viel einfacher, Wettbewerber zu erdrücken, als mit ihnen zu konkurrieren.
Auch im Vereinigten Königreich gab es bis vor Kurzem erstaunlich wenige unabhängige Banken. Dass dort nicht dasselbe passiert ist, liegt wahrscheinlich an der Art der Gesetze und Regulierung, die Kundenrechte stark absichern und Banken aktiv bestrafen, wenn sie diese nicht einhalten.
Banken mit APIs in den USA konzentrieren sich tendenziell auf Partnerschaften mit großen Fintechs, daher dürfte selbst eine einfache API im Vergleich zu einem normalen Bankkonto teuer sein. Die Grasshopper Bank in den USA ist zum Beispiel eine der wenigen Banken, die eine API zusätzlich zu einem normalen Geschäftskonto anbietet.
Ich arbeite bei Treasury Prime, das mehrere US-Banken mit APIs unterstützt.
Im Bereich Privatkonten sind Monzo und Starling die bekanntesten der sogenannten Challenger Banks[1].
[1]: https://en.wikipedia.org/wiki/Challenger_bank
Column – eine lizenzierte Bank für Entwickler
https://news.ycombinator.com/item?id=31109170
„Es gibt noch eine weitere proprietäre Technologie, die wir als Open Source veröffentlichen sollten. Wir haben Datascript auf FoundationDB portiert“ – bitte veröffentlicht das doch.
Mich würde interessieren, wie das als Datomic-Alternative funktionieren würde.
Der Satz „Rechtlich müssen Fintechs für solche Dinge mit einer Bank zusammenarbeiten, und derzeit bedeutet das traditionelle Großbanken, die Mainframes verwenden. Griffin ist die Bank und Technologieplattform, auf der alle Fintechs der Zukunft aufbauen werden“ klingt, als wäre er 2016 geschrieben worden.
Der Markt hat sich längst bewegt. Griffin sieht gut aus, ist aber vielen anderen um Jahre hinterher, und etablierte Anbieter wie ClearBank liefern bereits gute Bank-APIs.
Es gibt Platz für weitere Anbieter, daher ist Griffins Markteintritt erfreulich, aber ich wünschte, der Pitch wäre nicht so schwach.
Und eine gute API allein reicht nicht. Man braucht ein gesamtes Betriebsmodell, das zur Kundengruppe passt, und das aufzubauen ist deutlich schwieriger.
Noch nicht. Dort steht: „Wenn wir unser Audit abgeschlossen, mehr Kapital aufgenommen und den Code fertig geschrieben haben, nehmen wir die Stützräder ab. Das wird etwa im dritten oder vierten Quartal dieses Jahres sein.“
Ich hasse es wirklich, wenn ein Artikel mit „In einem Startup sollte man die mächtigste Sprache verwenden, die verfügbar ist, und das ist Clojure“ beginnt.
Das ist einfach nur deine Meinung. In einem Startup sollte man die Sprache verwenden, mit der das Team am schnellsten ein MVP bauen und veröffentlichen kann, um die ersten Kunden oder Investitionen zu bekommen. Für ein gewöhnliches Startup könnte das auch eine Low-Code- oder No-Code-Plattform sein, auch wenn das im Fintech-Bereich eher unwahrscheinlich ist.
Wenn man unbedingt so argumentieren will, könnte man wegen LLMs und Machine Learning sagen, dass Python die mächtigste Sprache ist, und ich bin normalerweise PHP-Entwickler. Python könnte durch Mojo, das Python angeblich 36.000-mal schneller machen soll, noch mächtiger werden.
Aber ich würde niemals sagen, dass irgendeine Sprache X die einzige und mächtigste Sprache für Startups ist. Das ist schlicht falsch und nur eine Meinung.
Zum Beispiel stimme ich dieser Meinung meiner Meinung nach zu :-) Mein Ein-Personen-Business wäre ohne Clojure und ClojureScript unmöglich gewesen, und das zeigt die „Macht“ dieser Sprache.
Ich halte sie für „mächtig“, weil sie einem einzelnen Entwickler ermöglicht, komplexe Apps über Jahre hinweg zu schreiben und zu warten. Sie gibt mir Macht.
Clojure hat eine ziemlich nach innen gerichtete Community, die sich stärker mit anderen Lisps überschneidet als mit populäreren Sprachen wie Python oder PHP. Deshalb kann das Klischee, dass Clojure die mächtigste Sprache sei, für Nichtnutzer überraschend klingen, auch wenn etwas Wahres daran ist.
Wir Clojure-Entwickler sind daran längst gewöhnt, und inzwischen ist es fast zu einer Begrüßungsformel geworden, von Überlegenheit auszugehen.
Auch für den Umgang mit LLM-Ausgaben bevorzuge ich Clojure. Natürlich nutze ich weiterhin Python dort, wo Python genau passt.