Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
スキーマ駆動開発による品質とスピードの両立 - 私達は何故、スキーマを書くのか
Search
武田 憲太郎
April 17, 2024
Programming
1.4k
1
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
スキーマ駆動開発による品質とスピードの両立 - 私達は何故、スキーマを書くのか
Postman API Night Tokyo 2024 Spring
https://postman.connpass.com/event/309418/
#APINight
武田 憲太郎
April 17, 2024
More Decks by 武田 憲太郎
See All by 武田 憲太郎
Why Laravel apps break—Mastering the fundamentals to keep them maintainable
kentaroutakeda
1
360
「接続」—パフォーマンスチューニングの最後の一手 〜点と点を結ぶ、その一瞬のために〜
kentaroutakeda
6
2.9k
PHP 8.4の新機能「プロパティフック」から学ぶオブジェクト指向設計とリスコフの置換原則
kentaroutakeda
2
2k
php-src is waitingfor your contribution or: How to Level Up Your PHP Skills with php-src
kentaroutakeda
0
96
REST API設計の実践 – ベストプラクティスとその落とし穴
kentaroutakeda
4
2k
Inertia.jsのサーバサイド実装から学ぶ依存逆転原則の応用
kentaroutakeda
1
230
私の愛したLaravel 〜レールを超えたその先へ〜
kentaroutakeda
13
6k
見えないメモリを観測する: PHP 8.4 `pg_result_memory_size()` とSQL結果のメモリ管理
kentaroutakeda
0
2.3k
Serverless or Not: 選択やリプレイスに悩まないために
kentaroutakeda
1
460
Other Decks in Programming
See All in Programming
スマートグラスで並列バイブコーディング
hyshu
0
150
dRuby over BLE
makicamel
2
380
作って学ぶ、 JSX (TSX) ランタイムの基本
syumai
7
1.6k
PHPで使える日時の表現と、その知り方 #frontend_phpcon_do
o0h
PRO
0
250
TAKTでAI駆動開発の品質を設計する
j5ik2o
7
1.3k
JJUG CCC 2026 Spring: JSpecify で実現する Kotlin フレンドリーな Java API 設計
ternbusty
1
180
Skillsは効率化、Agentsは"自分の拡張"——Builder時代のエージェント編成(CC Night 2026)
wemra
1
140
Signal Forms: Details & Live Coding @enterJS 2026 in Mannheim
manfredsteyer
PRO
0
150
脅威をエンジニアリングの糧にして――現場編 / Turning Threats into Engineering Fuel — Field Edition
nrslib
0
280
フロントエンドとバックエンドで「1文字」を揃えよう
youkidearitai
PRO
0
710
TypeScript+Orvalで実現する型安全かつ堅牢でスケーラブルなマルチチャネル通知基盤 / TSKaigi Night talks ~after conference~
d0riven
0
340
Vue × Nuxt × Oxc どこまで使える?実運用の現在地
andpad
0
260
Featured
See All Featured
Building Better People: How to give real-time feedback that sticks.
wjessup
370
20k
The Cult of Friendly URLs
andyhume
79
6.9k
HTML-Aware ERB: The Path to Reactive Rendering @ RubyCon 2026, Rimini, Italy
marcoroth
1
200
Documentation Writing (for coders)
carmenintech
77
5.4k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.6k
Marketing Yourself as an Engineer | Alaka | Gurzu
gurzu
0
240
How People are Using Generative and Agentic AI to Supercharge Their Products, Projects, Services and Value Streams Today
helenjbeal
1
220
Rails Girls Zürich Keynote
gr2m
96
14k
Money Talks: Using Revenue to Get Sh*t Done
nikkihalliwell
0
250
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
AI Search: Implications for SEO and How to Move Forward - #ShenzhenSEOConference
aleyda
1
1.3k
Testing 201, or: Great Expectations
jmmastey
46
8.2k
Transcript
スキーマ駆動開発による 品質とスピードの両⽴ 私達は何故、スキーマを書くのか 2024/4/18 #APINight
⾃⼰紹介 2024/4/18 #APINight @KentarouTakeda / 武⽥ 憲太郎 Webアプリケーションエンジニア • サーバサイド:
PHP - 2002年頃〜 • 型の扱いが⽐較的緩かった⾔語 • フロントエンド: TypeScript - 2013年頃〜 • 発表当初より厳密な型システムを持っていた⾔語 APIへの型付けや仕様と実装の乖離に、 課題感を持ち続けている。 スキーマ駆動開発による品質とスピードの両⽴ 1
アジェンダ 2024/4/18 #APINight •APIファーストが 解決した課題ともたらした困難 •スキーマ駆動開発による 品質とスピードの両⽴ スキーマ駆動開発による品質とスピードの両⽴ 2
APIファーストが解決した課題ともたらした困難 2024/4/18 #APINight • 仕様書の無い開発 • 仕様書のある開発 • 「仕様書」は依存に値するか? •
仕様書の冗⻑化に過ぎない実装 • 隠蔽されない知識 スキーマ駆動開発による品質とスピードの両⽴ 3
仕様書の無い開発 2024/4/18 #APINight • サーバサイドが出⼒するプロパティ名と フロントエンドのそれとが連動 • フロントエンドのコンポーネントが サーバサイドの実装に依存 //
サーバサイド: UserController.php public function show(User $user): array { return response()->json([ 'name' => $user->name, 'email' => $user->email, 'birthdate' => $user->birthdate ->toIso8601String(), ]); } // フロントエンド: UserComponent.tsx useEffect(() => { axios.get("/api/users/" + id) .then(response => setUser({ name: response.data.name, email: response.data.email, birthdate: new Date(response.data.birthdate), }) }); スキーマ駆動開発による品質とスピードの両⽴ 4
仕様書の無い開発 2024/4/18 #APINight 依存関係 • インターネットを跨いで依存している。 • 担当者を跨いで依存している。 • リポジトリを跨いで依存している。
スキーマ駆動開発による品質とスピードの両⽴ 5
仕様書のある開発 2024/4/18 #APINight SOLID原則: 依存関係逆転の原則 上位のモジュールは下位のモジュールに依存してはならない。どちらの モジュールも「抽象」に依存すべきである。 抽象(仕様書)への依存により詳細(インターネット)を隠蔽 APIファーストはここが出発点 スキーマ駆動開発による品質とスピードの両⽴
6
「仕様書」は依存に値するか? 2024/4/18 #APINight • ⾃然⾔語 • 表現⼒の限界 • 解釈の余地 •
管理 • リビジョン • ブランチ • マージ • 強制⼒ • 仕様と実装の乖離 スキーマ駆動開発による品質とスピードの両⽴ 7
仕様書の冗⻑化に過ぎない実装 2024/4/18 #APINight <label for="email">メールアドレス</label> <input type="email" name="email" id="email" maxlength="128">
<label for="password">パスワード</label> <input type="password" name="password" id="password" maxlength="32"> <label for="name">名前</label> <input type="text" name="name" id="name" maxlength="20"> <label for="birthdate">生年月日</label> <input type="date" name="birthdate" id="birthdate"> <!-- 省略 --> スキーマ駆動開発による品質とスピードの両⽴ 8
仕様書の冗⻑化に過ぎない実装 2024/4/18 #APINight スキーマ駆動開発による品質とスピードの両⽴ 9 axios.post("/api/users", { email: form.email, password:
form.password, name: form.name, birthdate: form.birthdate, // 省略 }).then(response => { // 省略: レスポンスを描画 });
仕様書の冗⻑化に過ぎない実装 2024/4/18 #APINight class CreateUserRequest extends FormRequest { public function
rules(): array { return [ 'email' => [ 'required', 'email', 'max:128' ], 'password' => [ 'required', 'string', 'max:32' ], 'name' => [ 'required', 'string', 'max:20' ], 'birthdate' => [ 'nullable', 'date' ], 'organizations' => [ 'required', 'array' ], 'organizations.*' => [ 'string' ], ]; } } スキーマ駆動開発による品質とスピードの両⽴ 10
仕様書の冗⻑化に過ぎない実装 2024/4/18 #APINight 仕様書と全く同じ内容を 別の書き⽅に書き直しているに過ぎない • ⾔語もコードベースも異なるため、再利⽤が効かない。 • ⼿作業にによるコードのため、ミスのリスクが付きまとう。 単純作業に割かれる多くの時間
スキーマ駆動開発による品質とスピードの両⽴ 11
隠蔽されない知識 2024/4/18 #APINight API仕様書に準拠した実装 • ⽬的: IDを指定しユーザー情 報を取得する。 • ⼿段:
仕様通りに URLを組み ⽴てGETリクエストを送る。 ネットワークの知識が フロントに漏れ出している。 抽象化された実装 • ⽬的: IDを指定しユーザー情 報を取得する。 • ⼿段: IDを指定しユーザー情 報を取得する。 適切な隠蔽が ⽬的と⼿段を⼀致させる。 // GET /api/users/{id} const users = await axios .get('/api/users/' + id); // UserApiクラスのメソッド呼び出し const user = await userApi .getUserById(id); スキーマ駆動開発による品質とスピードの両⽴ 12
スキーマ駆動開発による品質とスピードの両⽴ 2024/4/18 #APINight • ⾼品質で安定したものに依存する • フロントエンド開発 • サーバサイドでのスキーマ管理と統合 •
TDDとスキーマ駆動開発 • スキーマの破壊的変更 • エラー原因の提供 • リリース後の品質向上 スキーマ駆動開発による品質とスピードの両⽴ 13
⾼品質で安定したものに依存する 2024/4/18 #APINight プリミティブな値は Json Schemaで表現可能 • 数値 { "type":
"number" } • 整数 { "type": "integer" } • ⾃然数 { "type": "integer", "minimum": 1 } • non-empty-array<string> { "type": "array": "items": { "type": "string" }, minItems: 1 } プリミティブなドメインは OpenAPI Specificationで表現可能 • ⽂字列・UI上はマスクを推奨・8⽂字以上 { "type": "string", "format": "password", "minLength": 8 } • ⽇時・ISO8601形式の⽂字列 { "type": "string", "format": "date-time" } • URL⽂字列 { "type": "string", "format": "uri" } 「解釈の余地」が問題を招く → インターフェース記述⾔語による厳密化 スキーマ駆動開発による品質とスピードの両⽴ 14
⾼品質で安定したものに依存する 2024/4/18 #APINight インターフェース記述⾔語の導⼊により: • 間違いが機械的に指摘される。 • 補完(エディタ・IDE) • Lint
/ 静的解析 • Spectral • IBM OpenAPI Validator • 実⾏時検査 • 履歴が残る。 • Git ⼈間の判断は間違える → マシンリーダブルな⾔語で判断を⾃動化 スキーマ駆動開発による品質とスピードの両⽴ 15
⾼品質で安定したものに依存する 2024/4/18 #APINight 安定したインターフェース記述⾔語へ依存することで、 秩序を強制し、品質を向上させる、開発⼿法 •強制が、メリットでありデメリット。 •強制のコントロールが、開発の成否を決める。 スキーマ駆動開発による品質とスピードの両⽴ 16 「スキーマ駆動開発」とは
⾼品質で安定したものに依存する 2024/4/18 #APINight OpenAPIドキュメントそれ⾃体に強制⼒は無い。 実⽤的に使うには、これと同じ強制が必要。 class User implements Authenticatable {
} // Fatal error: // Class UserModel contains 6 abstract methods and must therefore be declared ... スキーマ駆動開発による品質とスピードの両⽴ 17
⾼品質で安定したものに依存する 2024/4/18 #APINight • コード⾃動⽣成: OpenAPI Generator • 仕様に準拠(=正しく依存)したライブラリが⾃動⽣成される •
「ビルドが通れば問題なし」と判断できる • バリデーション⾃動化 - OpenAPI PSR-7 Message Validator • ドキュメント: Redocly • ⼿動テスト: Swagger UI • APIテスト: runn • プラットフォーム: Integrate Postman with OpenAPI • ドキュメント /⼿動テスト / APIテスト / バリデーション⾃動化 • デリバリー / 監視 スキーマ駆動開発による品質とスピードの両⽴ 18
⾼品質で安定したものに依存する 2024/4/18 #APINight OpenAPIによるスキーマ駆動開発 多くの⽤途への正しい転⽤がポイント スキーマ駆動開発による品質とスピードの両⽴ 19
フロントエンド開発 2024/4/18 #APINight スキーマ駆動開発による品質とスピードの両⽴ 20 OpenAPI Generatorによる⾃動⽣成ライブラリは: • tagがクライアントライブラリのクラスに変換される。 •
operationIdが各クラスのメソッドに変換される。 • schemaが各⾔語の型定義やクラスに変換される。 • enumが各⾔語のenumや定数に変換される。 • リクエストレスポンスへの型付けが⾏われる。 • descriptionやsummaryが各⾔語のDocBlockに反映される。 • deprecatedなどのメタデータもDocBlockに反映される。 • date-timeが各⾔語の⽇時型と透過的に変換される。 以上の機能を持つ。
フロントエンド開発 2024/4/18 #APINight スキーマ駆動開発による品質とスピードの両⽴ 21 • 型安全 • エディタ補完・ホバーヒント •
静的解析・コンパイルチェック • 抽象化 • URLやHTTPメソッドを隠蔽したAPIクライアント // UserApiクラスのメソッド呼び出し const user = await userApi .getUserById(id); // メソッド補完
サーバサイドでのスキーマ管理と統合 2024/4/18 #APINight • デメリット • サーバサイド(APIサーバ)のコードに責務が集中する • メリット •
API仕様はサーバサイドの担当者が書くことが多い • URL(ルーティング)はサーバサイドに実装される • 型(バリデーション)はサーバサイドに実装される • 仕様と実装とを⼀致させやすい • 他の⽅法にいつでも移⾏できる スキーマ駆動開発による品質とスピードの両⽴ 22
サーバサイドでのスキーマ管理と統合 2024/4/18 #APINight • 仕様をアノテーションで宣⾔。すぐ下に実装。 • レスポンスの型定義(仕様)と⽣成(実装)とを紐づけ。 ここでの定義はOpenAPIドキュメントとしていつでも出⼒可能 #[OA¥Schema( title:
'User', properties: [ new OA¥Property(property: 'name', type: 'string'), new OA¥Property(property: 'email', type: 'string', format: 'email'), new OA¥Property(property: 'birthdate', type: 'string', format: 'date-time'), ], required: ['name', 'email', 'birthdate'], )] class UserResource extends JsonResource { public function toArray(Request $request): array { return [ 'name' => $this->resource->name, 'email' => $this->resource->email, 'birthdate' => $this->resource->birthdate->toIso8601String(), ]; } } スキーマ駆動開発による品質とスピードの両⽴ 23 仕様 実装
サーバサイドでのスキーマ管理と統合 2024/4/18 #APINight スキーマ駆動開発による品質とスピードの両⽴ 24 • 全てのリクエストレスポ ンスに強制的に介⼊ • OpenAPIドキュメントに
基づきバリデーション • 400 Bad Request • 500 Internal Server Error • 成功時のみ200 OK • 200 OK時の仕様準拠を 保証
TDDとスキーマ駆動開発 2024/4/18 #APINight スキーマ駆動開発による品質とスピードの両⽴ 25 • Red: • 失敗するテストを書く •
テストは失敗する • Green: • テストに通るコードを書く • テストは成功する • Refactor: • テスト成功を維持しつつリファクタ リング • Schema: • スキーマを先に書く • リクエストは失敗する • Code: • 仕様準拠したコードを書く • リクエストは成功する • Refactor: • リクエスト成功を維持しつつリファ クタリング リクエストレスポンスのテストを1本書けば Red / Green / Refactor が回る。
TDDとスキーマ駆動開発 2024/4/18 #APINight スキーマ駆動開発による品質とスピードの両⽴ 26 コードファースト • 迅速なプロトタイピング • 柔軟性
APIファースト • 設計品質 • DX向上 スキーマ駆動 • イテレーティブ • 仕様と実装の同期
スキーマの破壊的変更 2024/4/18 #APINight スキーマ駆動開発による品質とスピードの両⽴ 27 破壊的変更の発⽣条件 • リクエストの型を狭める • レスポンスの型を広げる
• 型を変更する SOLID原則: リスコフの置換原則への違反 • 事前条件を、派⽣型で強めることはできない。 • 事後条件を、派⽣型で弱めることはできない。 破壊的変更の条件を予め知っておくことで 発⽣の際の対応も容易に
エラー原因の提供 2024/4/18 #APINight •400 Bad Request フロントエンドに不⾜なく理由を 知らせる(レスポンス) •500 Internal
Server Error サーバ再度が容易に理由を知れる ようにする(ログ・レスポンス) { "title": "Response Validation Failed", "status": 500, // エラー位置 "pointer": [ "data", "status" ], // エラー理由 "detail": "Value cannot be null", // オリジナルのレスポンス "originalResponse": { "data": { "id": 42, "status": null, "name": "yokawasa", "content": "APINight" } } } スキーマ駆動開発による品質とスピードの両⽴ 28
エラー原因の提供 2024/4/18 #APINight スキーマ駆動開発による品質とスピードの両⽴ 29 本番リリース後も仕様外レスポンスを追跡 • クラッシュさせずログに残しアラートと連携 • リリース直後など⼗分に安定していないサービス
• 既存サービスへ後からスキーマ駆動開発を導⼊するケース • 開発時と同じようにエラーとする • 堅牢性よりも正当性を優先しなければならないサービス • バリデーションそのものを外す • ⻑期の運⽤を経て⼗分に安定したサービス • スループットが重要なサービス
私達は何故、スキーマを書くのか 30
⽯をどのように積むのかは、君次第だ。 31 © 2023 Hayao Miyazaki/Studio Ghibli
だけど、残念ながら世界には まだまだ良いAPIが少ないんだ THE API-FIRST WORLD Abhinav Asthana / © POSTMAN,
INC.
積みやすい⽯を作るのが、私達の仕事だ。 #APINight