数百万行ものHaskell:Mercury社の生産エンジニアリング
Mercury社は、30万人以上の顧客に銀行サービスを提供し、年間2480億ドルの取引量を処理するフィンテック企業です。
同社は200万行を超えるHaskellコードベースで、高い成長と変化に対応し、大規模な金融システムを運用しています。
従来の信頼性確保のための失敗防止策に加え、システムの変動を吸収し、オペレーターが対応できるような設計を重視しています。
Haskellの型システムは、単なるエラー防止だけでなく、組織的な知識をコードに落とし込み、人材の流出による知識喪失を防ぐための運用上の助けとなっています。
大手フィンテック企業Mercury社が、約200万行に及ぶ大規模なHaskellコードベースを本番環境で運用している実態を公開しました。Haskellは、その強力な型システムによりバグを未然に防ぐ「美しい」言語として知られています。しかし、本記事は、単なる言語の美しさではなく、急速に成長し、膨大な資金を扱う現場で「いかにしてシステムを安定稼働させるか」という、より実践的なエンジニアリングの知見に焦点を当てています。
大規模コードベースの現実と課題
Mercury社は、30万人以上のビジネス顧客を抱え、年間6.5億ドルの収益を上げる急成長中の企業です。彼らのエンジニアリング組織は、Haskellの経験がないジェネラリスト(汎用的なスキルを持つエンジニア)を多く採用しています。約200万行に及ぶHaskellコードを、現場で言語を習得したメンバーが維持しているという状況は、従来の常識からすれば「大惨事」と見なされるかもしれません。しかし、彼らのシステムは、ハイパーグロースや金融危機といった極限状況下でも安定して稼働し続けているとのことです。
信頼性に対する新しい考え方
システム開発における信頼性について、Mercury社は従来の「障害を未然に防ぐ」アプローチに疑問を呈しています。単にバグを洗い出し、テストで悪いケースを網羅するだけでは不十分だと考えているそうです。彼らが目指すのは、「適応能力(Adaptive Capacity)」を持つシステムです。これは、予期せぬ変化や負荷がかかった際にも、システムが優雅に劣化し、機能し続ける能力を指します。
運用上の実践的な問いかけ
大規模なコードベースでは、組織的な課題が深刻化します。新しく入ったメンバーがモジュールを読んで内容を理解できるか、データベースが遅くなった際にサービスが落ちずに劣化するか、といった「運用上の問い」が重要になると説明しています。コンパイラがエラーを教えてくれるだけでなく、誰かがインターフェースを誤用した際に、オンコール担当者がアラートを受ける前に問題が検出できる仕組みが求められているとのことです。
まとめ
Mercury社の事例は、Haskellのような高度な言語を導入する際、言語の理論的な美しさだけでなく、急速な組織成長や大規模運用という「現実の重み」をどう乗り越えるかが鍵となることを示唆しています。技術的なエレガンスと、実務的な持続可能性の両立が求められていると言えるでしょう。
原文の冒頭を表示(英語・3段落のみ)
A Couple Million Lines of Haskell: Production Engineering at Mercury
Ian Duncan March 30, 2026 [Haskellers from the trenches] #Production #Mercury
The editors of the Haskell Blog are happy to announce a new series of articles called "Haskellers from the trenches",
※ 著作権に配慮し、引用は冒頭3段落までです。続きは元記事をご覧ください。
Hacker News コメント
機械翻訳。HN の元スレッド ↗
I think perhaps contrary to popular belief, Mercury choosing Haskell and their early leadership having such a storied experience in it probably played some non-insignificant role in their success.As a customer of Mercury, it's truly one of the critical companies my toolkit, and I just can't help but feel that their choosing of Haskell made their progress, development and overall journey that much better. I realize that you can make this argument with most languages, and it's not to say that a FP lang like Haskell is a recipe for success, but this intentional decision particularly pre "vibe coding" and the LLM era seems particularly prescient, of course combined with their engineering culture that was detailed in the post.
It’s hard to imagine what two millions lines of Haskell could possibly be doing. I mean that’s a lot of code and I have the impression that Haskell is “tight” meaning a little code can do a lot. Maybe they have a lot of libraries to do things like json serializing/deserializing, rest api frameworks, logging etc?
> Haskell gives you tools to encode these incantations in types so they cannot be forgotten. This is, for my money, the single most valuable thing the language offers a production engineering organization.Haskell is admittedly, probably the most powerful widely (or even somewhat widely) used language for doing this, but this general pattern works really well in Rust and TypeScript too and is one of my very favorite tools for writing better code.I also really like doing things like User -> LoggedInUser -> AccessControlledLoggedInUser to prevent the kind of really obvious AuthZ bugs people make in web applications time and time again.I've found this pattern to be massively underutilized in industry.
My bestie works at this company and looking from the outside they have a good engineering culture. I do think Haskell is the right tool for the job, and they are playing to it's strengths, but part of me wonders if a lot of their success is attributable to the place just being well run in general.
I loved working in Haskell for a few years. I wasn't actively looking it, but the opportunity just sort of landed in my lap. It was exciting and mentally stimulating. But the unfortunate fact is, I am easily twice as productive in Rust as I am Haskell, even after 3 years of nothing but Haskell. There are more pitfalls in Haskell that you have to just know how to avoid. It can be very difficult to digest as the language can be borderline write-only at times, depending on the author of the code. The tooling is often married to Nix, which is it's own complex beast. And it feels like language extensions are all over the place. Cabal files are not my favorite. And the compiler errors take some time to get get used to.
A similar Haskell success story (from Bellroy) is the subject of an upcoming Melbourne Compose meeting: https://luma.com/uhdgct1v
I worked on a somewhat similar system in a fringe language (Scheme, and later, Racket) that got huge, but that remained manageable and high-velocity over a long period by a small team.We didn't create many bugs, and usually functionality could be added very rapidly (e.g., we were the first to achieve a certain certification for hosting sensitive data on AWS).Though occasionally functionality had to be added more slowly, because we had to write from scratch what would be an off-the-shelf component in a more popular platform. But once we did it, it worked, and we were back to our old velocity, and not slowed by the bloat and complexity of dozens of off-the-shelf frameworks. We could also adapt rapidly because we controlled a manageable platform, which is how we were able to move fast to AWS when there was a need.The system also had some technical bits of architectural secret sauce from the start (for complex data, and Web interaction), which enabled a lot of rapid development of functionality, and also set the tone for later empowering smartness.One difference with our system, from the Haskell fintech, was that our team size was very small (only 2-3 software engineers at a time, and someone who managed all the ops). So we didn't have the challenges of hundreds of people trying to coordinate and have a coherent system while getting their things done. Instead, there was usually one person doing more technical and architectural changes to the code, and a prolific other person doing huge amounts business logic functionality for complex processes.With careful use of current/near-term LLM-ish AI tools, software development might find some related efficiencies of very small and incredibly effective teams. But the model that comes to mind is having a small number of very sharp thinkers keeping things on an empowering and manageable path -- not churning massive bloat to knock off story points and letting sustainability be someone else's problem.
I am currently reading Real-World Ocaml and I am really learning more about functional programming, though I was already familiar with a few things.Looks to me like you can build amazingly robust pieces of software with functional programming.However, I am divided.I have a backend that works in NiceGUI for a product. It does the job. The code is reasonable and MVVM. The most important task it does is connecting to a websocket per customer and consume data to present some analytics.I will not have a great deal of customers, maybe in the tens or maximum hundreds visiting the website.I also want REPL and/or hot reload, but I am aware that as I grow features (users admin panels, more analytics, etc) maybe functional programming can do a good job transforming data pipelines.But Haskell or Ocaml are static. I guess if I want something later that grows and scales and is still dynamic Clojure or Elixir should be a good choice. But at the same time I am afraid that if at some point I need to refactor, things will go wrong.Currently I use Python with Mypy. All is written in the backend: the frontend is generated by NiceGUI from the backend.
It's a double-edged sword. Two million lines is a major feat. It's also represents a significant maintenance burden.The advantages to Haskell are theoretically obvious. The downsides are harder to intuit.The temptation is to model _everything_ as types. The codebase itseld becomes a _business specification_, not an application. Every policy change is a major refactor (some of which are shockingly high-touch thanks to Haskell safety).The lesson is you cannot have your cake and eat it too. Eventually you become trapped by your types.Haskell is really impressive and powerful, perhaps especially at this scale. However it brings its own unique problems. The temptation to model business logic as types leads to rigid structures. And the safety these structures bring can blind you to other classes of risk.
The problem I have with functional programming is debugging. Or more precisely, I would say it is a strength of imperative programming, especially the procedural kind.In functional/declarative style, you generally describe how things should be, not how things are made, and you let the language piece everything together to get the expected result in the end. It is all well and good (and even better) if you did everything right, but what if you didn't and you don't get the expected result? How do you find the bug?In a language like C, it is relatively straightforward: go line by line, look at the execution state (the RAM, essentially) between each step and if it isn't as expected, something wrong must happen at that line, so you step in and progress like that. Harder to do when the language goes out of its way to hide the state from you, as it is the case for functional programming.It is interesting that the longest section of the article is about this problem: "design for introspection", where the author has to go out of his way to make his code debuggable. A good insight on the often overlooked practical use of Haskell.