一冊の本が変えた、型システムの使い方

267 Views

June 24, 26

スライド概要

profile-image

エンジニアリングマネージャー at コドモン Kotlinをよく書いてます。Goも好きです。

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

ダウンロード

関連スライド

各ページのテキスト
1.

一冊の本が変えた、型システムの使い方 JJUG CCC 2026 Spring延長戦 上代 洋平

2.

自己紹介 上代 洋平 かじろ ようへい 2022.12 コドモンに入社 現在 エンジニアリングマネージャー 2

3.

アジェンダ ● 本編おさらい ● 本の紹介 3

4.

本編おさらい 題材と課題 本編の題材は請求書(Bill)の状態管理 ● 請求書には「発行済み・支払済み・返金済み・キャンセル済み」という状態 がある ● 発行済みの時のみキャンセルできる 4

5.

本編おさらい Before:nullable フィールドの問題 public class Bill { // ... private final Cancellation cancellation; // nullable: キャンセル済みのみ private final Refund refund; private final Payment payment; // nullable: 返金済みのみ // nullable: 支払済みのみ } → null の組み合わせで状態を管理すると問題が多い 5

6.

本編おさらい Before:nullable フィールドの問題 public Bill cancel(EmployeeId canceledBy) { if (isPaid()) throw new BillDomainException("支払済みのためキャンセルでき ません"); if (isCanceled()) throw new BillDomainException("既にキャンセル済みです"); if (isRefunded()) throw new BillDomainException("返金済みのためキャンセルで きません"); // ... } → 状態が増えるたびにガード節を追加しなければならない 6

7.

本編おさらい After:sealed interface で状態を型に public sealed interface Bill permits IssuedBill, CanceledBill, PaidBill, RefundedBill { } ● 不正な状態を型として表現できない ● switch 式で処理漏れをコンパイルエラーに 7

8.
[beta]
本編おさらい After: パターンマッチで処理漏れを防ぐ
CanceledBill result = switch (bill) {
case IssuedBill b -> billRepository.saveCancellation(b.cancel(cancellation));
case CanceledBill b -> throw new CancelUseCaseException("既にキャンセル済みです");
case PaidBill b

-> throw new CancelUseCaseException("支払済みのためキャンセルできませ

ん");
case RefundedBill b -> throw new CancelUseCaseException("返金済みのためキャンセルできま
せん");
};

● 全ケースを網羅しないとコンパイルエラー
● 新しい状態を追加 → 全 switch 箇所でコンパイルエラー

8

9.

本編おさらいAfter: cancel() は IssuedBill だけが持つ public final class IssuedBill implements Bill { // ... public CanceledBill cancel(String canceledBy) { return new CanceledBill(id, billNumber, amount, Cancellation.of(canceledBy)); } } CanceledBill や PaidBill に対して cancel() を呼ぼうとすると コンパイルエラー になる 9

10.

きっかけになった一冊 Scott Wlaschin 著、猪股健太郎 訳 『関数型ドメインモデリング』(アスキードワンゴ、2024) ● F# で書かれているが、考え方は言語を問わない ● 普段 Kotlinで開発しているが、この本から設計のヒントを得た 10

11.

Make Illegal States Unrepresentable 「不正な状態を表現不可能にする」 この考え方に出会って、型の使い方への見方が変わりました。 11

12.

関数型に学ぶ設計思想 ● Make Illegal States Unrepresentable ● Smart Constructor ● Parse, don't validate ● Errors as values ● Functional core, imperative shell これらはすべて『関数型ドメインモデリング』で扱われています 関数型言語でなくても、その考え方は普段の設計のヒントになります 12

13.
[beta]
Smart Constructor
public final class EmailAddress {
private final String value;
private EmailAddress(String value) { this.value = value; }

public static Optional<EmailAddress> of(String raw) {
if (raw == null || !raw.contains("@")) return Optional.empty();
return Optional.of(new EmailAddress(raw));
}
}
13

14.
[beta]
Parse, don't validate
// validate: boolean を返すだけ。呼び出し元が何もしなくても通る
boolean isValid = EmailValidator.validate(raw);
// parse: 型に変換。不正な値は Optional.empty() になる
Optional<EmailAddress> email = EmailAddress.of(raw);
● booleanではなく Optional<T> で「変換できたか」を型で表現する

14

15.

この本が変えたこと 関数型ドメインモデリングを読んだことで 自分が使う言語の型システムの見え方が変わった 型はコンパイラのためにあるのではなく、設計を表現する言語 15

16.

ご清聴ありがとうございました!