- Đây là nền tảng banking-as-a-service cho phép fintech tích hợp trực tiếp các chức năng mở tài khoản, thanh toán và onboarding như API ngân hàng; vào tháng 3/2023, Griffin nhận giấy phép ngân hàng tại Anh và trở thành ngân hàng được quản lý
- Hệ thống chạy trên Clojure on Kubernetes on AWS, kết hợp kiến trúc event sourcing biến hầu hết input thành event với kho lưu trữ FoundationDB
- FoundationDB là strict-serializable key-value store hỗ trợ transaction và ghi đồng thời; Griffin xây dựng các thao tác đọc/ghi nguyên tử bằng một lớp tương tự Datomic được port từ Datascript
- Logic nghiệp vụ được tách xoay quanh các log processor nhỏ, nhận Clojure map và xuất Clojure map; việc truy cập hệ thống bên ngoài được giới hạn qua protocol và proc chuyên dụng
- Griffin cho rằng tính bất biến và sự phù hợp với audit log của Clojure đáp ứng nhu cầu dịch vụ tài chính; khi kết hợp với tuyển dụng từ xa, họ dễ tìm được kỹ sư chất lượng cao ngay cả trong một nhóm ứng viên nhỏ
Nền tảng ngân hàng được quản lý cung cấp qua API
- Griffin là nền tảng banking-as-a-service giúp các công ty fintech tích hợp chức năng ngân hàng nhanh chóng và an toàn
- Tháng 3/2023, Griffin nhận UK banking license từ Financial Conduct Authority, trở thành ngân hàng Anh được quản lý đầy đủ
- Griffin tự gọi mình là “the bank you can build on”, hướng tới việc trở thành nền tảng giống AWS cho ngân hàng
- API onboarding khách hàng
- API tạo tài khoản ngân hàng
- API thanh toán
- Để fintech cung cấp các chức năng này, về mặt pháp lý họ phải hợp tác với ngân hàng; hiện nay nhiều trường hợp vẫn làm việc với các high street bank truyền thống dùng mainframe
- Griffin muốn cung cấp cả giấy phép ngân hàng lẫn nền tảng công nghệ, trở thành nền móng để fintech trong tương lai xây dựng dịch vụ phía trên
- Dù đã nhận giấy phép, vào thời điểm đó Griffin vẫn ở giai đoạn mobilization; giai đoạn này kết thúc sau khi hoàn tất audit, huy động thêm vốn và hoàn thành việc viết code
- Mốc mục tiêu là Q3 hoặc Q4 của năm đó
Bối cảnh chọn Clojure
- Clojure được chọn làm ngôn ngữ nền tảng nhờ tính bất biến, khả năng biểu đạt và sự phù hợp với dịch vụ tài chính cần audit log
- Allen Rohner xem bài trình bày Clojure của Rich Hickey vào khoảng năm 2007 và đánh giá nó tốt hơn Lisp mà ông đang tự xây dựng
- Sau khi sáng lập CircleCI vào năm 2011, ông sử dụng Clojure trong thời gian dài; Clojure cũng hoạt động tốt ở CircleCI và được xem là phù hợp với dịch vụ tài chính
- Trong vài năm đầu, ông chưa nhận ra đầy đủ ưu điểm của JVM, nhưng về sau đánh giá lại đây là một lợi thế lớn
- Các niche startup language khác có thể gặp vấn đề thiếu thư viện, hiệu năng compiler/runtime
- JVM trở thành nền tảng giúp giảm các rủi ro này
- Việc chọn ngôn ngữ thể hiện tính cách của công ty, và Griffin đánh giá Clojure là lựa chọn mạnh hơn Python hay Java
- Griffin cho rằng dùng niche language có thể làm giảm số lượng ứng viên, nhưng tăng tỷ lệ nhân tài cấp cao
Lớp dữ liệu xây bằng FoundationDB
- Kiến trúc Griffin chạy trên Clojure, Kubernetes và AWS, gần như toàn bộ được tổ chức theo event sourcing
- Cơ sở dữ liệu sử dụng FoundationDB
- FoundationDB là strict-serializable key-value store hỗ trợ transaction
- Bắt đầu là startup ở Silicon Valley
- Được Apple mua lại năm 2015
- Khoảng năm 2018, Apple mở mã nguồn lại
- Apple sử dụng trong production của iCloud
- Apple đã thực hiện benchmark cho thấy FoundationDB chạy khoảng 1 triệu transaction mỗi giây
- Strict serializable là mức cao nhất về tính nhất quán cơ sở dữ liệu
- API cơ bản gần với
get a key,set a key, chứ không phải SQL - Griffin port Datascript sang FoundationDB để xây dựng lớp tương tự Datomic
- Cho phép truy vấn nguyên tử trên kho dữ liệu strict-serializable
- Hỗ trợ đọc và ghi dựa trên transaction
- FoundationDB không phải single writer mà hỗ trợ concurrent writes
- Griffin cần hơn 1.000 transaction mỗi giây, và FoundationDB đang đáp ứng yêu cầu này
Event sourcing và log processor
- Mọi input trong hệ thống Griffin đều trở thành event
- API request
- Webhook bên thứ ba
- Event được đưa vào message log; trong Griffin, event là Clojure map có trường
type, key/value và spec - Toàn bộ hệ thống được cấu thành như các phản ứng với event
- Các log processor nhỏ được gọi là
proc- proc hoạt động theo kiểu “lắng nghe message type A, rồi emit B hoặc C để phản hồi”
- Mỗi proc có private state riêng
- Luồng message có thể được cấu trúc thành graph, và event di chuyển cho đến khi tới terminal node
- Ví dụ, web server nhận HTTP event và ghi nhận yêu cầu thanh toán, sau đó chờ event
payment createdhoặcpayment rejectedrồi phản hồi client- Luồng này dùng Netty asynchronous HTTP handler
- Mọi event được ghi vào FoundationDB
- Mỗi log processor có private data giống namespace riêng bên trong FoundationDB
- proc theo dõi việc một loại event cụ thể được ghi lại, rồi ghi event của chính nó trở lại FoundationDB
- FoundationDB cung cấp khả năng theo dõi thay đổi DB key, giúp xây dựng reactive system hiệu quả
- Nếu dùng cơ sở dữ liệu cùng với một hệ thống messaging riêng, có thể phát sinh race condition
- Ví dụ, khi một message đi xuống đĩa và một message đi qua mạng, observer có thể thấy chúng theo thứ tự khác nhau
- Griffin dùng cách ghi vào FoundationDB để đơn giản hóa thành một đường đi duy nhất
Monorepo và cô lập logic nghiệp vụ
- Griffin sử dụng monorepo
- Hiện tại, để tối ưu hiệu quả, nhiều log process chạy trong cùng một JVM
- Mỗi log process độc lập nên cũng có thể chạy như JVM process riêng
- Hiện tại họ chạy quy mô vài trăm proc thấp trong một JVM duy nhất
- Logic nghiệp vụ được giữ đơn giản và sạch nhất có thể
- Namespace của từng log processor gần như hoàn toàn là pure Clojure
- Gần như không có thư viện bên thứ ba
- Side effect cũng rất ít
- Log processor gần giống một hàm nhận Clojure map làm input và trả về một hoặc nhiều Clojure map
- proc state có protocol nên không cần biết implementation ở phía bên kia
- Khi test có thể dùng như in-memory database
- Khi chạy thực tế có thể ghi vào FoundationDB
- Interface với thế giới bên ngoài được giữ nhỏ nhất có thể
- Phần lớn proc chỉ có thể ghi vào internal state của mình và emit message
- Không được gọi network
- Không được gọi AWS
- Không có hành vi bên ngoài nào khác
- Khi cần giao tiếp với hệ thống bên ngoài, Griffin dùng proc đặc biệt có dispatch handler chuyên dụng
- proc giao tiếp với AWS
- proc giao tiếp với clearing bank
- proc giao tiếp với API khác
Hệ sinh thái Clojure được sử dụng
- Bên trong logic nghiệp vụ, Griffin gần như không dùng thư viện
- Ở các phần tiếp xúc với thế giới bên ngoài, như API web server hoặc service gateway, họ dùng:
ringnettyreitit
- Clojure spec được sử dụng rộng rãi
- Tích hợp AWS dùng thư viện Cognitect
aws-api - Cấu hình ứng dụng và quản lý tài nguyên dùng cách tiếp cận dựa trên bài blog closeable
- Cách tiếp cận này cho rằng
with-openlà đủ, không cần Component hay Integrant - Có được lexical scope, và thứ tự khai báo binding buộc thứ tự cấu hình
- Griffin dùng helper nhỏ để khai báo các state object không implement
Closeablehoặc stateless object trong blockwith-open
- Cách tiếp cận này cho rằng
Tuyển dụng và cấu trúc đội ngũ
- Griffin cho rằng tuyển Clojure có ít ứng viên hơn nhưng tỷ lệ ứng viên tốt cao hơn
- Tuyển Java có thể nhận 1.000 CV nhưng chỉ có 10 ứng viên tốt
- Tuyển Clojure được mô tả là có thể nhận 13 CV mà có 10 ứng viên tốt
- Với pool tuyển dụng nhỏ, làm việc từ xa rất quan trọng
- Khi giảm ràng buộc địa lý, có thể tạo pool lớn hơn trên toàn cầu, trong phạm vi 3 múi giờ, hoặc ở châu Âu
- Griffin xem tình huống phải tuyển 100 kỹ sư trong thời gian ngắn là anti-pattern
- Tổng số nhân sự toàn công ty khoảng 70 người
- Engineering khoảng 22–24 người
- Khoảng 2/3 ở UK
- Khoảng 1/3 ở EU
- Khoảng 4 người ở Đức, 4 người ở Thụy Điển, 1 người ở Ireland
- Trụ sở chính ở London, nhưng phần lớn developer ở UK nằm ngoài London
Kiểm thử khả năng phục hồi vận hành ở cấp độ ngân hàng
- Là một ngân hàng, Griffin phải operationally resilient, điều này gần với yêu cầu không được có downtime
- Vì xử lý tiền, họ phải chứng minh thực tế rằng dù có sự cố cũng không làm mất tiền của khách hàng
- Hướng kiểm thử Griffin quan tâm tương tự cách của đội FoundationDB
- Đội FoundationDB xây dựng database simulator
- Viết khoảng 20 process type, tức các vai trò trong cluster, dưới dạng ứng dụng C++ single-threaded
- Xây dựng actor-model concurrency compiler trên C++
- Thực hiện mọi system call và network call qua protocol để có thể tiêm lỗi
- Multi-threading cũng được xử lý qua actor model dựa trên message sending
- Trong môi trường này có thể tiêm lỗi một cách deterministic
- Gửi message A và B nhưng phía bên kia nhận theo thứ tự B, A
- Xảy ra lỗi ghi đĩa khi đang xử lý message
- Có thể xem đây giống generative testing của
test.check, theo nghĩa mọi tính bất định của hệ thống được seed từ một random number duy nhất có thể kiểm soát - Các đối tượng muốn kiểm soát là disk errors, network errors, message reordering
- Vấn đề hiện tại là không có cách kiểm soát hành vi của Java threading libraries, NIO và disk write
- Cách này có cùng tinh thần với Jepsen nhưng có khác biệt
- Griffin xem Jepsen gần với brute force kiểu dùng nhiều VM rồi kill process
- Khó kiểm tra trạng thái cơ sở dữ liệu từ bên trong nên khó biết coverage
- Trong môi trường hoàn toàn có thể kiểm soát, có thể liệt kê system call hoặc message interleaving, và vì chạy in-memory nên kiểm tra rất nhanh
- Đội FoundationDB đã xây dựng môi trường kiểm thử như vậy từ sớm, và đây là yếu tố tạo niềm tin vào FoundationDB
- Griffin đang tuyển dụng; có thể xem thông tin tại Griffin careers page
1 bình luận
Ý kiến trên Hacker News
James Trunk, VP of Engineering hiện tại của Griffin, đã có một bài trình bày nhập môn kỹ thuật Clojure rõ ràng và thú vị nhất mà tôi từng xem. Khuyến nghị nên xem
https://youtu.be/C-kF25fWTO8?si=PnjMNLdBLJ8zqSu-
Vấn đề hiện nay là không có cách nào kiểm soát các thư viện threading Java nền tảng, NIO, hay hành vi ghi đĩa; và với bản chất của những hệ thống như vậy, có vẻ điều đó cũng sẽ không thể làm được trong tương lai
Trong các hệ thống dùng thứ tự yêu cầu hoặc lập lịch tác vụ không tất định, bạn không thể có được thực thi tất định. Điều đó xảy ra nếu luôn dùng nhiều thread OS, hoặc khởi chạy nhiều tiến trình riêng trong kiểm thử
Có thể ép nó trở nên tất định, nhưng sẽ rất khó vì phải cài các điểm đồng bộ hóa mà kiểm thử có thể kiểm soát vào mọi chuyển tiếp của state machine ứng dụng
Về mặt thực tế, có vẻ cách duy nhất là thiết kế phần lõi của hệ thống hoàn toàn đồng bộ, rồi thêm tính đồng thời ở các tầng cao hơn tại thời điểm thực thi
procskhông có tác dụng phụ, ngoại trừ những gì xảy ra bên ngoài Clojure protocol (Java interface)Vì vậy trong khi kiểm thử, có thể thay mọi tác dụng phụ bằng stub. Mã “người dùng” của chúng tôi không được truy cập thư viện threading, còn threading diễn ra trong mã “kernel”
Trên thực tế, có thể xem một ví dụ tốt đã triển khai theo cách này tại https://www.youtube.com/watch?v=4fFDFbi3toc
Hiện missionary đã instrumentation các flow của chính nó và xác minh chuyển tiếp trạng thái cho các bài kiểm thử của missionary
Khá hay khi hai nhà sáng lập đã cùng viết một cuốn sách tên Learning ClojureScript
https://www.packtpub.com/product/learning-clojurescript/9781...
Câu “Chúng tôi thường đùa rằng mình là một công ty công nghệ có giấy phép ngân hàng” là một trích dẫn có thể trông rất tệ về sau nếu mọi chuyện đi sai hướng
Chủ lao động của tôi tự gọi mình là một công ty nghiên cứu giáo dục thương mại hóa kết quả nghiên cứu bằng phần mềm; với tôi điều đó thuyết phục hơn nhiều và cũng tạo ra văn hóa tốt hơn
Trong ngành ngân hàng, chi phí học lại những tri thức đó có thể rất đắt đỏ
Hỏi thật lòng và xin lỗi vì nói hơi thô, nhưng tại sao tôi phải quan tâm dịch vụ mình dùng được viết bằng ngôn ngữ nào? Tại sao việc nó được viết bằng Clojure lại quan trọng? Về nghề nghiệp, tôi là lập trình viên Clojure nên thấy một thứ như thế được viết bằng Clojure là rất hay, nhưng tôi không hiểu tại sao mình phải quan tâm đến điều đó
Đây là một trong những điều tôi thực sự ghét ở cộng đồng này. Clojure là một ngôn ngữ mạnh và tôi cũng dùng nó rất vui, nhưng trong cộng đồng có cảm giác như một dạng hội chứng kẻ mạo danh, rằng phải nói với người khác và biện minh việc một dự án nào đó dùng ngôn ngữ này; điều đó thật kỳ lạ
Tôi không hiểu ý chính là gì. Chẳng lẽ đây là hành vi không phù hợp trong xã hội văn minh sao?
Nghe khá thiếu hiểu biết. Nếu “không quan tâm” thì không cần tham gia, cứ để tác giả viết điều họ muốn viết
Tôi nhớ hồi thập niên 90, các lập trình viên PHP và Python chia sẻ những ví dụ như vậy để trả lời các câu hỏi kinh doanh kiểu “tại sao không dùng Microsoft ASP”
Hoặc cũng có thể họ đang muốn thu hút lập trình viên về công ty mình
Tại sao các ngân hàng API kiểu này lúc nào cũng ở Anh vậy? Tôi đã muốn làm nghiệp vụ ngân hàng bằng curl suốt mấy năm nay, mà ở Mỹ chẳng ai cung cấp cả
Ngược lại, Anh đã tích cực khuyến khích các ngân hàng mới và công nghệ mới. Chuyển tiền tức thời miễn phí giữa các tài khoản cá nhân đã có từ gần 20 năm trước, thanh toán không tiếp xúc ít nhất 10 năm, mobile banking thì hàng chục năm, và API ngân hàng do chính phủ bắt buộc cũng đã gần 5 năm
Tóm lại, xét theo chuẩn ngân hàng thì Anh có một lĩnh vực ngân hàng rất năng động, đã đổi mới nhanh, và có môi trường cùng hệ sinh thái phát triển tốt để đổi mới nhanh hơn nữa
Ở Mỹ, có vẻ các ngân hàng đã từ bỏ đổi mới công nghệ từ nhiều thập kỷ trước, và thích đổi mới trong việc thu phí cùng cách đối xử mang tính trừng phạt với khách hàng hơn. Vì vậy không có môi trường đổi mới mới, còn các ngân hàng hiện hữu thì dẹp đối thủ dễ hơn nhiều so với cạnh tranh
Cho đến gần đây, Anh cũng có số lượng ngân hàng độc lập ít đến đáng kinh ngạc; lý do chuyện tương tự không xảy ra có lẽ phần lớn là do bản chất của luật pháp và quy định: bảo vệ nhiều quyền của khách hàng và tích cực xử phạt các ngân hàng không tuân thủ
Các ngân hàng có API ở Mỹ có xu hướng tập trung vào quan hệ đối tác fintech lớn, nên ngay cả API đơn giản cũng sẽ đắt hơn so với tài khoản ngân hàng thông thường. Ví dụ Grasshopper Bank ở Mỹ là một trong số ít ngân hàng cung cấp API bên trên tài khoản ngân hàng thương mại thông thường
Tôi làm việc tại Treasury Prime, nơi hỗ trợ nhiều ngân hàng Mỹ có cung cấp API
Ở mảng tài khoản cá nhân, Monzo và Starling là những cái tên nổi tiếng nhất trong nhóm được gọi là ngân hàng challenger[1]
[1]: https://en.wikipedia.org/wiki/Challenger_bank
Column – ngân hàng được cấp phép dành cho nhà phát triển
https://news.ycombinator.com/item?id=31109170
“Còn một công nghệ độc quyền nữa cần được mã nguồn mở. Chúng tôi đã port Datascript sang FoundationDB” — làm ơn công bố đi
Tôi tò mò không biết nó sẽ hoạt động như thế nào với vai trò một lựa chọn thay thế Datomic
Câu “Về mặt pháp lý, fintech phải hợp tác với ngân hàng để làm những việc này, và hiện nay điều đó có nghĩa là các ngân hàng lớn truyền thống dùng mainframe. Griffin là ngân hàng và nền tảng công nghệ mà mọi fintech trong tương lai sẽ xây dựng trên đó” nghe như được viết vào năm 2016 vậy
Thị trường đã dịch chuyển rồi. Griffin trông có vẻ tốt, nhưng đang chậm hơn nhiều nơi vài năm, và các đơn vị đã vững như ClearBank đã cung cấp API ngân hàng rất ổn
Vẫn còn chỗ cho nhiều bên tham gia hơn, nên việc Griffin gia nhập thị trường là điều đáng mừng, nhưng giá như bài pitch đừng yếu như vậy
Và chỉ API tốt thôi là chưa đủ. Cần cả mô hình vận hành phù hợp với nhóm khách hàng, mà xây dựng được thứ đó khó hơn nhiều
Chưa đâu. Bài viết nói “khi hoàn tất kiểm toán, gọi thêm vốn và viết xong code, chúng tôi sẽ tháo bánh phụ. Có lẽ vào khoảng quý 3 hoặc quý 4 năm nay”
Tôi rất ghét khi bài viết mở đầu bằng “trong startup, bạn nên dùng ngôn ngữ mạnh nhất có thể, và đó là Clojure”
Đó chỉ là quan điểm của bạn thôi. Trong startup, nên dùng ngôn ngữ giúp đội ngũ xây và ra mắt MVP nhanh nhất để có khách hàng đầu tiên hoặc gọi được vốn. Với một startup thông thường, đó có thể là nền tảng low-code hoặc no-code, dù trong fintech thì nhiều khả năng không phải vậy
Nếu nhất định phải nói, vì LLM và machine learning, cũng có thể nói Python là ngôn ngữ mạnh nhất, và tôi thường là lập trình viên PHP. Python thậm chí có thể còn mạnh hơn nhờ Mojo, thứ được cho là làm Python nhanh hơn 36000 lần
Nhưng tôi sẽ không bao giờ nói một ngôn ngữ X nào đó là ngôn ngữ duy nhất và mạnh nhất để dùng trong startup. Điều đó hoàn toàn sai và chỉ là quan điểm
Ví dụ, theo quan điểm của tôi thì tôi đồng ý với quan điểm ấy :-) Công ty một người của tôi đã không thể tồn tại nếu thiếu Clojure và ClojureScript, và điều này cho thấy “sức mạnh” của ngôn ngữ đó
Tôi xem ngôn ngữ này là “mạnh” vì nó cho phép một lập trình viên duy nhất viết và bảo trì các ứng dụng phức tạp trong nhiều năm. Nó trao sức mạnh cho tôi
Clojure có một cộng đồng khá hướng nội, giao thoa với các Lisp khác nhiều hơn là với những ngôn ngữ phổ biến hơn như Python hay PHP. Vì vậy câu sáo ngữ Clojure là ngôn ngữ mạnh nhất tuy có phần đúng, nhưng có thể nghe rất bất ngờ với người không dùng nó
Chúng tôi, các lập trình viên Clojure, đã quen rồi; giờ nói chuyện với tiền đề về sự vượt trội gần như đã thành lời chào hỏi
Tôi cũng thích dùng Clojure hơn để xử lý đầu ra của LLM. Tất nhiên, nơi nào Python thật sự phù hợp thì tôi vẫn dùng Python