---
title: 一冊の本が変えた、型システムの使い方
tags: 
author: [Yohei Kajiro](https://docswell.com/user/yoheiyohei4)
site: [Docswell](https://www.docswell.com/)
thumbnail: https://bcdn.docswell.com/page/DJY49ZZP7M.jpg?width=480
description: 一冊の本が変えた、型システムの使い方 by Yohei Kajiro
published: June 24, 26
canonical: https://docswell.com/s/yoheiyohei4/ZR882N-one-book-changed-how-i-use-types
---
# Page. 1

![Page Image](https://bcdn.docswell.com/page/DJY49ZZP7M.jpg)

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


# Page. 2

![Page Image](https://bcdn.docswell.com/page/V7NYL33ME8.jpg)

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


# Page. 3

![Page Image](https://bcdn.docswell.com/page/YJ9P499W73.jpg)

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


# Page. 4

![Page Image](https://bcdn.docswell.com/page/GJ8DQ99RJD.jpg)

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


# Page. 5

![Page Image](https://bcdn.docswell.com/page/LJLMXWW2ER.jpg)

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


# Page. 6

![Page Image](https://bcdn.docswell.com/page/47MYL9997W.jpg)

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


# Page. 7

![Page Image](https://bcdn.docswell.com/page/P7R9KGG9E9.jpg)

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


# Page. 8

![Page Image](https://bcdn.docswell.com/page/PJXQLXX37X.jpg)

本編おさらい After： パターンマッチで処理漏れを防ぐ
CanceledBill result = switch (bill) {
case IssuedBill b -&gt; billRepository.saveCancellation(b.cancel(cancellation));
case CanceledBill b -&gt; throw new CancelUseCaseException(&quot;既にキャンセル済みです&quot;);
case PaidBill b
-&gt; throw new CancelUseCaseException(&quot;支払済みのためキャンセルできませ
ん&quot;);
case RefundedBill b -&gt; throw new CancelUseCaseException(&quot;返金済みのためキャンセルできま
せん&quot;);
};
● 全ケースを網羅しないとコンパイルエラー
● 新しい状態を追加 → 全 switch 箇所でコンパイルエラー
8


# Page. 9

![Page Image](https://bcdn.docswell.com/page/3JK9LWWNJD.jpg)

本編おさらい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


# Page. 10

![Page Image](https://bcdn.docswell.com/page/LE3W311ZE5.jpg)

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


# Page. 11

![Page Image](https://bcdn.docswell.com/page/8EDK4XX47G.jpg)

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


# Page. 12

![Page Image](https://bcdn.docswell.com/page/V7PKMPPVJ8.jpg)

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


# Page. 13

![Page Image](https://bcdn.docswell.com/page/2JVV922RJQ.jpg)

Smart Constructor
public final class EmailAddress {
private final String value;
private EmailAddress(String value) { this.value = value; }
public static Optional&lt;EmailAddress&gt; of(String raw) {
if (raw == null || !raw.contains(&quot;@&quot;)) return Optional.empty();
return Optional.of(new EmailAddress(raw));
}
}
13


# Page. 14

![Page Image](https://bcdn.docswell.com/page/5EGLZRR6JL.jpg)

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


# Page. 15

![Page Image](https://bcdn.docswell.com/page/4JQYLVV27P.jpg)

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


# Page. 16

![Page Image](https://bcdn.docswell.com/page/K74WDMMPE1.jpg)

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


