Effective ML: Errors, Abstraction and Managing Complexity

A Jane Street engineer discusses explicit failure, boilerplate, type-system restraint and the practical role of side effects.

チャンネル
Jane Street
公開日
2016年3月31日
動画
23:58
読了時間
5 分
原文
英語
YouTube で開く
スクロールすると動画は右下に小さくなって再生を続けます。字幕は閲覧言語に合わせて切り替わります。
閲覧言語2 言語で読めます
この記事はまだ日本語に翻訳されていないため、英語の原文を表示しています。
要約

30 秒でわかる

In the second part of an Effective ML lecture, the speaker argues that readable, robust software makes failure explicit and abstracts repeated patterns without introducing unnecessary complexity. He also discusses mutation, code review, team size, human involvement in trading and the historical choice of OCaml.

  1. 1Options and exceptionsA search can return an option or provide an explicitly named exception-raising variant, depending on caller needs.
  2. 2Boilerplate hides changeRepeated code is hard to update consistently and tedious to review.
  3. 3Complexity is the enemyA sophisticated type-level invariant is not helpful if it makes the interface incomprehensible.
  4. 4Mutation as communicationShared mutable state links parts of a program and can make local reasoning harder.
  5. 5Reviewing critical codeThe speaker describes multiple reviewers and tests for the trading system’s critical path.

ポイント

  1. Expose expected failure in types when callers need to handle it, and name exception-raising alternatives clearly.
  2. Abstract repeated patterns so common behavior and meaningful variations are visible.
  3. More static guarantees are not automatically better if they make interfaces too complex to understand.
  4. Avoid unnecessary mutation while recognizing that useful programs need side effects.
  5. Code review, tests and small coherent projects support dependable systems.
  6. Language choices depend on the performance and operational needs of the application.
全文

チャプターごとに整えた全文を読む

文字起こしのみ
01

Make errors explicit

The speaker contrasts option-returning interfaces and exceptions. He explains why error-handling choices depend on the consequences of failure.

A key idea in effective ML programming is to make common errors in called functions clear and explicit. The familiar advice to use exceptions for exceptional circumstances reflects two concerns: exceptions create a nonlocal control flow, and implicit error handling makes it easy not to think about failure.

I do not argue against exceptions altogether; they are useful. But whether a failure is exceptional depends on the caller’s context. A list search might be expected always to find an element in one piece of code, while another caller genuinely does not know whether it exists.

A list interface can offer both find, which returns an option, and find_exn, which may raise an exception. The former makes absence visible in the type and forces the caller to handle it; the latter makes the possible exception visible in its name. Our convention uses the _exn suffix for operations that can commonly fail on their inputs.

Usually the option-returning version is preferable because the type system carries the possibility of failure rather than relying solely on a naming convention. We learned this through experience and revised much of our code in this style to improve robustness.

Context matters to error-handling design. Stephen Weeks, author of the MLton compiler, observed a change in perspective when moving to Jane Street: a compiler that exits with an exception and stack trace is inconvenient, but a trading system that dies in the middle of the day is a much more serious problem.

Some interfaces avoid the problem entirely. A fold can operate on an empty list, unlike an operation that requires a head or a successful search. A function with simple error behavior is easier to use confidently, while explicit failure conditions make the remaining cases easier to reason about.

02

Avoid boilerplate

Repeated patterns can hide mistakes and become hard to update. ML abstractions can make the common pattern and its variations explicit.

Next, avoid boilerplate: similar code copied repeatedly with small but important changes. Even good programmers use it when the language does not provide an easy abstraction for the pattern, or when they do not know how to express that abstraction.

Repetition creates two problems. A pattern evolves, and developers may miss one of its many copies when changing it. Repetitive code is also dull to review; people examine the first instance carefully and can overlook a significant difference in later copies.

C provides relatively limited abstraction tools for this kind of pattern, leaving macros or copying as common choices. ML offers functors and higher-order functions. I suggest a low tolerance for duplication: even two copies are a reason to look for an abstraction.

An abstraction can be worthwhile even when it makes the code longer. A local function states the common pattern once, and its arguments show what varies. The resulting code can be more explicit and easier to follow than several nearly identical copies.

03

Control complexity

Type-level guarantees and purity are valuable, but excessive sophistication can make code harder to understand. The goal is a practical balance.

Powerful type systems create the opposite temptation: encoding increasingly intricate invariants because it is fun and possible. I have seen interfaces that experienced ML programmers cannot understand even after explanation. At that point the extra static guarantee may have increased overall complexity rather than helping.

The central challenge in software engineering is managing complexity. Learn clever techniques and use them where they help, but exercise restraint. Code must fit the minds of the people who will maintain it, not merely an elegant abstract model.

Side effects and mutation deserve similar balance. Prefer code without unnecessary mutation because a shared reference is a communication channel between different parts of a program. Such channels connect distant code and make it harder to understand a component in isolation.

Do not turn purity into a religion. Useful programs interact with the outside world: reading a socket, writing a file or checking the clock is a side effect. Haskell disciplines the separation between pure and effectful code; it does not eliminate effects from useful programs.

Pushing effects outward can help, but not if the result becomes more complicated than a straightforward imperative solution. Sometimes an imperative algorithm is easier to understand or reaches good performance without elaborate machinery. The aim is the simplest system that serves the task.

04

Questions on engineering and trading

The discussion covers review, small teams and the role of people in trading systems. The speaker closes with the historical choice of OCaml.

Asked about review, I explain that Jane Street treats code between a trading decision and the market as a critical path. Multiple people—at least two, usually three—are assigned to read changes before production, and an internal system tracks that review. Unit and regression tests also matter, but review is central to keeping the systems safe and coherent.

We try to organize development into coherent projects with small groups, roughly one to six people at the outside. Small, relatively independent pieces can fit in individuals’ heads and fit together into a larger system. I would find a large group working directly on one piece of infrastructure difficult to manage.

Asked about automation, I say the business varies widely. Some work involves people negotiating by phone, while other systems run for hours with humans watching rather than continually changing them. Most systems involve substantial human interaction; the firm is not simply a machine that runs unattended and produces money.

Trading is a game involving someone on the other side of every transaction. A model of the market must account for that other participant. Human attention, from both traders and technologists, is a central part of the integrated human and technical system.

Jane Street had used OCaml for about nine years at the time of this talk, after earlier systems using Excel, Java and C#. The choice was partly contingent on my familiarity with the language. OCaml also offered a useful balance: declarative code with a comparatively straightforward, efficient compilation strategy.

One reason we did not choose Haskell was that its performance, especially space usage, was harder to reason about for our needs at the time. Its implementation has improved, but the effort needed to make it efficient adds complexity. Language choice depends on the requirements of the system being built.

同じチャンネルの記事

1:48:29EN
JSJane Street· 2026年10月16日How AI Is Changing Programming: John Krazit and Ron MinskyRon Minsky, John Krazit · Jane StreetJane Street’s AI tooling lead and the Signals and Threads host examine agent infrastructure, security, code review and the changing experience of writing software.コーディングエージェントDeveloper productivity評価(Evals)+2
1:36:37EN
JSJane Street· 2026年9月23日Aaron Bauer on Teaching Software Engineering in the Age of AIRon Minsky, Aaron Bauer · Jane StreetHow learning goals, active practice and editor design shape engineering education when models can generate the code.AI in EducationSoftware engineeringEducation+2
スライド 9 枚1:05:45EN
JSJane Street· 2026年9月11日Cyrus Omar on Live Programming and a Computational Commons for Humans and AICyrus OmarA demonstration of Hazel shows how immediate feedback, structured collaboration and carefully scoped permissions could support people and AI agents working together.Programming LanguagesHuman-AI Collaboration開発ワークフローとテスト+2
1:25:00EN
JSJane Street· 2026年9月2日Eric Mannes on Turning Messy External Data Into Trading ResearchRon, Eric Mannes · Jane StreetFrom commodity futures and an Excel risk system to point-in-time datasets and AI, Eric Mannes explains the domain knowledge behind data engineering at Jane Street.Data quality & curation開発ワークフローとテストInvesting+2
スライド 7 枚1:16:29EN
JSJane Street· 2026年8月26日Grant Sanderson and Alok Puranik: Positional Encodings Through Group TheoryGrant Sanderson, Alok Puranik · 3Blue1BrownStarting with assumptions about attention, they derive matrix exponentials and connect rotations, decay and Jordan blocks to RoPE and ALiBi.Transformers & attentionMathematics機械学習の基礎+1
27:39EN
JSJane Street· 2026年8月21日3Blue1Brown and Jane Street on Trading, Machine Learning and CultureGrant Sanderson, Nitya, In Young, Craig, Alok · 3Blue1BrownGrant Sanderson talks with Jane Street colleagues about market making, shared compute, research and the paths that brought them to the firm.Machine LearningFintechCompany Culture+2