Slide 1

Slide 1 text

PHP 8.4の新機能 「プロパティフック」から学ぶ オブジェクト指向設計と リスコフの置換原則

Slide 2

Slide 2 text

アジェンダ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 1 Ø⾃⼰紹介 • プロパティフックの紹介 • プロパティフックと継承 • リスコフの置換原則‧共変と反変 • まとめ

Slide 3

Slide 3 text

⾃⼰紹介: @KentarouTakeda / 武⽥ 憲太郎 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 2 PHP 8.4 新機能(PostgreSQL関連)追加 PHP 8.4 「プロパティフック」初版翻訳

Slide 4

Slide 4 text

アジェンダ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 3 • ⾃⼰紹介 Øプロパティフックの紹介 • プロパティフックと継承 • リスコフの置換原則‧共変と反変 • まとめ

Slide 5

Slide 5 text

基本的な例 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 4 • インスタンスにセットした値が ⾃動的に書き換わっている • プロパティ宣⾔と共にメソッド のようなものが書かれている class User { public function __construct(string $name) { $this->name = $name; } public string $name { get { return ucfirst($this->name); } set(string $value) { $this->name = strtolower($value); } } } $user = new User('ILIJA'); echo $user->name . "¥n"; // Ilija var_dump($user); // object(User)#1 (1) { // ["name"]=> // string(5) "ilija" // }

Slide 6

Slide 6 text

基本的な例 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 5 class User { public function __construct(string $name) { $this->name = $name; } public string $name { get { return ucfirst($this->name); } set(string $value) { $this->name = strtolower($value); } } } $user = new User('ILIJA'); echo $user->name . "¥n"; // Ilija var_dump($user); // object(User)#1 (1) { // ["name"]=> // string(5) "ilija" // } • 値の書き込みは set フックを 経由する • 値の読み込みは get フックを 経由する

Slide 7

Slide 7 text

なぜこの機能が必要なのか? 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 6 動機: 簡潔なコードでオブジェクトを安全に扱いたい 1. プロパティの⼊出⼒を制限しオブジェクトを安全に扱いたい • 🏛 private プロパティと getFoo(), setFoo($value) • 🔥 ⼤量のボイラープレート 2. 🎉 PHP 7.4: 型付きプロパティ • 😄 型として表現可能なプロパティは setFoo($value) を使う必要がなくなった • 😅 public フィールドは外部からの再代⼊を防げない • 😰 再代⼊を防ぐために getFoo() が必要になる本末転倒 3. 🎉 PHP 8.1: readonly プロパティ • 🚀 public フィールドだけで不変なオブジェクトを作れるようになった

Slide 8

Slide 8 text

なぜこの機能が必要なのか? 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 7 • 書き⽅を統⼀できない • 半径: $circle->radius • ⾯積: $circle->getArea() • 円周: $circle->getCircumference() • 仕様追加時の変更箇所 • 🙆 半径を変更すれば他は⾃動で計算 • ❌ 「⾯積を上書き」という追加要件 • ❌ 「半径も計算」する追加要件 • 書き⽅を統⼀し仕様追加も容易にする • 予め getFoo(), setFoo($value) で統⼀ • 5年前の書き⽅へ逆戻り • $circle->getRadiius() class Circle { public function __construct( public float $radius ) { } public function getArea(): float { return pi() * $this->radius ** 2; } public function getCircumference(): float { return 2 * pi() * $this->radius; } }

Slide 9

Slide 9 text

なぜこの機能が必要なのか? 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 8 従来の動的プロパティ • __get() に switch 相当の コードがひたすら続く • typoされた $name が⼊⼒ される可能性 • エラーハンドリングはユー ザーの責任 • 静的解析の恩恵を受けられ ない class Circle { public function __get(string $name): mixed { if ($name === 'area') { return pi() * $this->radius ** 2; } if ($name === 'circumference') { return 2 * pi() * $this->radius; } // 全ての動的プロパティを一箇所で扱う // ここに到達したらどうする? } }

Slide 10

Slide 10 text

なぜこの機能が必要なのか? 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 9 •「プロパティ」に統⼀ • $circle->radius • $circle->area • $circle->circumference •静的解析を利⽤可能 •仕様追加も容易 • set を後から実装すれば良い class Circle { public function __construct( public float $radius ) { } public float $area { get { return pi() * $this->radius ** 2; } } public float $circumference { get { return 2 * pi() * $this->radius; } } }

Slide 11

Slide 11 text

多くのフレームワークに既にある機能 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 10 •$posts というプロパティは User クラスにはない • あるのは posts() メソッド (リレーションシップ) •Laravelがリレーションシッ プを「フック」として呼び 出し「投稿⼀覧」を取得 class User extends Model { public function posts() { return $this->hasMany(Post::class); } } class PostController { public function index(User $user) { return $user->posts; } }

Slide 12

Slide 12 text

多くのフレームワークに既にある機能 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 11 • Eloquentの「アクセサ」「ミューテータ」はプロパティフックとほ ぼ同じ機能 • 注: 計算結果オブジェクトのキャッシュなどEloquentに特化した機能も追 加で実装されている • 上の実装は冒頭のプロパティフックの例とほぼ等価 class User extends Model { protected function Name(): Attribute { return Attribute::make( get: fn (string $value) => ucfirst($value), set: fn (string $value) => strtolower($value), ); } } $user->name で 読み書き可能

Slide 13

Slide 13 text

Vue.js 算出プロパティ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 12

私の名前は: {{ formattedName }} です

export default { props: { name: { type: String, required: true }, }, computed: { formattedName() { return this.name.charAt(0).toUpperCase() + this.name.slice(1).toLowerCase(); }, }, }; テンプレートからは 単純に変数を参照 裏側で get フックが呼ばれる フック通過後の値をレンダ

Slide 14

Slide 14 text

JavaScript ゲッター‧セッター 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 13 @Component({ selector: 'self-introduction', template: `

私の名前は: {{ name }} です

`, }) export class SelfIntroductionComponent { private _name = ''; @Input() set name(value: string) { this._name = value.charAt(0).toUpperCase() + value.slice(1).toLowerCase(); } get name(): string { return this._name; } } コンポーネント初期化時に set フックを通る

Slide 15

Slide 15 text

PHP RFC: Property hooks 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 14 • ⼀⾒シンプルな機能だがRFCは⻑⼤ • 発展的な使い⽅での動作を全て網羅 • 配列アクセス • シリアライズ‧デリジアライズ • 抽象プロパティ • 継承と変性 これらを読み解くことが オブジェクト指向や型システムの 理解につながる (以下、スクロール30画⾯分)

Slide 16

Slide 16 text

set の型の拡張 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 15 class User { public DateTime $birthDate { set(DateTimeInterface|Stringable|Closure|int|float|string $value) { if($value instanceof Closure) { $value = $value(); } if($value instanceof DateTime) { $this->birthDate = DateTime::createFromInterface($value); return; } if(is_int($value) || is_float($value)) { $this->birthDate = DateTime::createFromTimestamp($value) ->setTime(0, 0); return; } if($value instanceof Stringable) { $value = $value->__toString(); } $this->birthDate = new DateTime ($value) ->setTime(0, 0); } } } $user = new User(); $user->birthDate = '2006-01-02'; var_dump($user->birthDate); $user->birthDate = 1136160000; var_dump($user->birthDate); $user->birthDate = new DateTimeImmurable('2006-01-02'); var_dump($user->birthDate); $user->birthDate = fn() => '2006-01-02'; var_dump($user->birthDate); $user->birthDate = new class { public function __toString(): string { return '2006-01-02'; } }; var_dump($user->birthDate); • プロパティの型は DateTime • 代⼊時はそれ以外の型も受け⼊れる これらのvar_dumpは全て 等値な値を返す

Slide 17

Slide 17 text

アロー関数と引数の省略 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 16 class User { public string $name { get { return ucfirst($this->name); } set(string $value) { $this->name = strtolower($value); } } } class User { public string $name { get => ucfirst($this->name); set(string $value) => strtolower($value); } } class User { public string $name { get => ucfirst($this->name); set => strtolower($value); } } ⼀⽂の場合アロー関数で短縮可能 setの型が変わらない場合引数を省略可能 最も柔軟に実装できる書き⽅

Slide 18

Slide 18 text

仮想プロパティとバックドプロパティ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 17 class Circle { public function __construct( public float $radius ) { } public float $area { get => pi() * $this->radius ** 2; } public float $circumference { get => 2 * pi() * $this->radius; } } $circle = new Circle(5); var_dump($circle); // object(Circle)#1 (1) { // ["radius"]=> // float(5) // } var_dump($circle->area); // float(78.53981633974483) var_dump($circle->circumference); // float(31.41592653589793) 実体を持つ = バックドプロパティ 実体を持たない = 仮想プロパティ

Slide 19

Slide 19 text

仮想プロパティの条件 バックドプロパティ: •$name のフックで •$this->name を参照する 仮想プロパティ • $area のフックで • $this->area を参照しない 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 18 class User { public string $name { get => ucfirst($this->name); } } class Circle { public float $area { get => pi() * $this->radius ** 2; } } フックの中で⾃⾝で同名の実体を正確に参照していればバックドプロパティ

Slide 20

Slide 20 text

誤った仮想プロパティによるエラー 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 19 • $this->foo を「正確に」参照していないため仮想プロパティ • 仮想プロパティなので $this->>foo には実体が無い • 存在しないもの参照しようとしエラー class Example { public string $foo { get { $temp = 'foo'; return $this->$temp; // 展開すると $this->foo } } } new Example()->foo; // Uncaught Error: Must not read from virtual property Example::$foo

Slide 21

Slide 21 text

&get によるリファレンスの取得 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 20 • 取得を &get とすればリファレンスを⼊⼿できる • リファレンスを経由し get から set できる class User { public ?string $name = null { &get { return $this->name; } } } $user = new User(); $name =& $user->name; $name = 'Gina'; var_dump($user); // object(User)#1 (1) { // ["name"]=> // &string(4) "Gina"

Slide 22

Slide 22 text

&get と set の併⽤ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 21 • バックドプロパティでの &get と set の併⽤は禁⽌ • 仮想プロパティでは併⽤できる(set する実体が無いため) class User { public ?string $name = null { &get { return $this->name; } set(?string $value) { $this->name = strtolower($value); } } } // Fatal error: // Get hook of backed property User::name with set hook may not return by reference

Slide 23

Slide 23 text

コンストラクタプロモーションとの併⽤ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 22 class User { private string $name; public function __construct( string $name, ) { $this->name = $name; } } class User { public function __construct( private string $name, ) { } } class User { public function __construct( public string $name { get => ucfirst($this->name); set => strtolower($value); } ) { } } 型宣⾔を コンストラクタへ移動 移動した先へ 同じようにフックを定義

Slide 24

Slide 24 text

コンストラクタプロモーションと型拡張 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 23 class User { public function __construct( public DateTime $birthDate { set(DateTimeInterface|Stringable|string|Closure|int|float $value) { // 省略 } } ) { } } $user = new User(new DateTime ('2006-01-02')); // 問題なし $user->birthDate = '2006-01-02'; // 問題なし $user = new User('2006-01-02'); // User::__construct(): // Argument #1 ($birthDate) must be of type DateTime, string given 広げたのはあくまで set の型 コンストラクタの型は DateTime のまま

Slide 25

Slide 25 text

コンストラクタプロモーションと型拡張 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 24 コンストラクタの型から set の型へ • 「広げる」ことは可能 • 「狭める」「変更する」のは不可能 class User { public DateTime $birthDate { set(string $value) { $this->birthDate = new DateTime ($value) ->setTime(0, 0); } } } // Type of parameter $value of hook User::$birthDate::set // must be compatible with property type set の型を「変更した」場合 型エラー

Slide 26

Slide 26 text

アジェンダ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 25 • ⾃⼰紹介 • プロパティフックの紹介 Øプロパティフックと継承 • リスコフの置換原則‧共変と反変 • まとめ

Slide 27

Slide 27 text

「整数」を継承し「⾃然数」を作成 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 26 • set フックでのバリデーションで値を制限 • ここではPHP上の型は変わらない(共に int 型) class Integer { public function __construct( public int $value, ) { } } $integer = new Integer(-1); // 問題なし class NaturalNumber extends Integer { public int $value { set { assert($value > 0); $this->value = $value; } } } $naruralNumber = new NaturalNumber(-1); // Uncaught AssertionError: // assert($value > 0)

Slide 28

Slide 28 text

「数」を継承し「整数」を作成 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 27 class Number { public function __construct( public int|float $value ) { } } class Integer extends Number { public int|float $value { set { assert(floor($value) === (float)$value); $this->value = $value; } } } $integer = new Integer(-1); // 問題なし $integer = new Integer(-1.1); // Uncaught AssertionError: // assert(floor($value) === (double)$value) ¥PHPStan¥dumpType(new Integer(1)->value) // int|float int に変更したい 変更できない(何故?) Type of Integer::$value must be int|float (as in class Number)

Slide 29

Slide 29 text

仮想プロパティと継承先の型変更 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 28 class Number { public function __construct( protected int|float $_value ) { } public int|float $value { get => $this->_value; } } var_dump(new Number(42.23)->value); // float(42.23) ¥PHPStan¥dumpType(new Number()->value); // Dumped type: float|int class Integer extends Number { public int $value { get => (int)$this->_value; } } var_dump(new Integer(42.23)->value); // int(42) ¥PHPStan¥dumpType(new Integer()->value); // Dumped type: int 仮想プロパティにすれば 変更できる(何故?) この理由を紐解けば リスコフの置換原則を理解できる

Slide 30

Slide 30 text

アジェンダ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 29 • ⾃⼰紹介 • プロパティフックの紹介 • プロパティフックと継承 Øリスコフの置換原則‧共変と反変 • まとめ

Slide 31

Slide 31 text

リスコフの置換原則‧共変と反変 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 30 •「共変」とは? •「反変」とは? •「不変」とは? PHPマニュアル: 共変性と反変性 /プロパティの共変性と反変性

Slide 32

Slide 32 text

リスコフの置換原則‧共変と反変 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 31 • 反変: (⼊⼒‧引数 の型を)狭めてはいけない • 共変: (出⼒‧返却 の型を)広げてはいけない • 不変: 反変かつ共変 = 型を狭めても広げてもいけない = 変更してはいけない

Slide 33

Slide 33 text

リスコフの置換原則‧共変と反変 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 32 • 昔は⼀部出来たことを、今は敢えて出来なくしている • 今でもやる⽅法はある • 型宣⾔を書かなければ良い なぜ敢えて出来なくしているのか?

Slide 34

Slide 34 text

現実世界の例で考える「毎朝の散歩」 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 33 1. 幾つかの100円⽟と10円⽟を持ち出発 2. ⾃販機で150円のペットボトル飲料(500ml)を買う • 売り切れが多くいつも同じ飲料を変えるとは限らない • 必ず何か買う。「買わない」という選択肢は無しとする 3. 買った飲料をペットボトルホルダー(500ml⽤)に⼊ れて出発 「⾃販機」が交換されることになったとして このワークフローが「壊れる or 壊れない」条件を考える

Slide 35

Slide 35 text

現実世界の例で考える「毎朝の散歩」 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 34 ⾃販機で150円のペットボトル飲料(500ml)を買う • ⼊⼒: ⼗円⽟と百円⽟の組み合わせ • 出⼒: 500mlペットボトル飲料 VendingMachine::buyDrink( list<硬貨<100円|10円>> $coins ): ペットボトル<500ml>

Slide 36

Slide 36 text

⼊⼒型の変更 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 35 元の⼊⼒型: list<硬貨<100円|10円>> $coins • 🙆 飲料が値下げされた。150円から100円になった。 • 価格は変わったが型(受け⼊れる硬貨の種類)は変わっていない。 • ❌ 値下げに伴い⾃動販売機が「100円⽟専⽤」になった。 • 10円⽟10枚を持ってきていたケース。 • 「⼊⼒を狭める」の例: list<硬貨<100円>> $coins • 🙆 ⾃動販売機が硬貨に加えQRコード決済にも対応した。 • 100円⽟や10円⽟はそのまま使える。 • 「⼊⼒を広げる」の例: list<硬貨<100円|10円>>|QRコード決済 $coins • ❌ ⾃動販売機がQRコード決済専⽤になった。 • 100円⽟や10円⽟はもう使えない。 • 互換性のない型: QRコード決済 $coins

Slide 37

Slide 37 text

出⼒型の変更 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 36 元の出⼒型: ペットボトル<500ml> • 🙆 取り扱う飲料の種類が増えた • 飲料の種類は増えても出⼒型(飲料のパッケージ形態)は変わっていない • ❌ 1lのペットボトル飲料も扱うようになった • ペットボトルホルダー(500ml⽤)に⼊らない • 「出⼒を広げる」の例: ペットボトル<500ml|1l> • ❌ ⽸を扱うようになった • ペットボトルホルダー(500ml⽤)に⼊らない • ⽸「も」扱う → 「出⼒を広げる」に相当: ペットボトル<500ml>|缶 • ⽸「だけ」扱う → 互換性のない型: ⽸

Slide 38

Slide 38 text

反変‧共変とは 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 37 ⾔葉の意味: How 反変: (⼊⼒‧引数 の型を)狭めてはいけない 共変: (出⼒‧返却 の型を)広げてはいけない 設計の意味: Why • ❌: わざわざ守らなければならない⾯倒なルール • ✅: 実装を破壊的変更から守る安全装置 • 👍: ⾔葉の難しさに⼾惑うが考え⽅は簡単

Slide 39

Slide 39 text

余談: Animal メンタルモデルの問題点 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 38 • PHPマニュアル ❌ 反変性とは、親クラスのものよりも、より 抽象的な、広い型を引数に指定することを許 すものです。 • リスコフの置換原則 - Wikipedia ❌ 事前条件(preconditions)を、派⽣型で 強めることはできない。派⽣型では同じか弱 められる。 abstract class Animal { abstract public function eat(PetFood $food); } class Cat extends Animal { public function eat(CatFood $food) { // } } class Kitten extends Cat { public function eat(Milk $food) { // } } 例題で頻出する Animal, Dog, Cat は リスコフの置換原則に全く適合しない

Slide 40

Slide 40 text

プロパティフックで型変更を⾏える理由 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 39 $value は: • 仮想プロパティ • フックのは⾃⾝の実体を参照しない • set操作を持たない • getしか実装していない • 仮想プロパティなのでデフォルトの set 操 作(単なる代⼊)も無い • 「出⼒」しかない • 以上より、共変である • = 型を「狭める」ことができる class Number { public function __construct( protected int|float $_value ) { } public int|float $value { get => $this->_value; } } class Integer extends Number { public int $value { get => (int)$this->_value; } } 狭める

Slide 41

Slide 41 text

アジェンダ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 40 • ⾃⼰紹介 • プロパティフックの紹介 • プロパティフックと継承 • リスコフの置換原則‧共変と反変 Øまとめ

Slide 42

Slide 42 text

まとめ 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 41 • プロパティフックの紹介 • 他の⾔語やフレームワークでは既に広く使われている機能 • 「基本形」はシンプルなのできっと簡単に使える • PHPの型システムとの適合のため⼀部難解な箇所もある • ほとんどは「継承」に関するものなので、それを避ければ⼤丈夫 • 継承とリスコフの置換原則‧共変性と反変性 • 反変: (⼊⼒‧引数 の型を)狭めてはいけない • 共変: (出⼒‧返却 の型を)広げてはいけない • 「守るべき⾯倒なルール」ではなく「実装を破壊的変更から守る安全装置」 • プロパティフックによる型システムのパラダイムシフト • プロパティが変性(共変性‧反変性)を持てるようになった • 「抽象プロパティ」が可能になった

Slide 43

Slide 43 text

リスコフの置換原則を使いこなす 2025-06-28 PHP 8.4の新機能「プロパティフック」から学ぶ オブジェクト指向設計とリスコフの置換原則 42 • 現実世界の例(⾃動販売機) • 「⼊⾨」には適切でない例もあるので注意 • Animal メンタルモデル • 応⽤可能な範囲は広い • スキーマ駆動開発による 品質とスピードの両⽴