Upgrade to PRO for Only $50/Year—Limited-Time Offer! 🔥
Speaker Deck
Features
Speaker Deck
PRO
Sign in
Sign up for free
Search
Search
詳細の決定を遅らせつつ実装を早くする
Search
shimabox
November 08, 2025
Programming
2
1.4k
詳細の決定を遅らせつつ実装を早くする
PHPカンファレンス福岡2025 の発表資料になります
#phpconfuk #hall_hz
shimabox
November 08, 2025
Tweet
Share
More Decks by shimabox
See All by shimabox
明示と暗黙 ー PHPとGoの インターフェイスの違いを知る
shimabox
2
960
人には人それぞれのサービス層がある
shimabox
3
970
自分のためから誰かのためへ
shimabox
10
4.1k
情報処理安全確保支援士をとった話
shimabox
1
250
クリーンアーキテクチャから見る依存の向きの大切さ
shimabox
5
2.1k
GoとPHPのインターフェイスの違い
shimabox
2
470
並行処理を学びGuzzleと仲良くなる
shimabox
3
2.5k
擬人化で完全に理解するクリーンアーキテクチャ
shimabox
20
11k
Unit of Workパターンで永続化とトランザクションを制御する
shimabox
11
7.3k
Other Decks in Programming
See All in Programming
20 years of Symfony, what's next?
fabpot
2
280
AIエージェントでのJava開発がはかどるMCPをAIを使って開発してみた / java mcp for jjug
kishida
5
850
全員アーキテクトで挑む、 巨大で高密度なドメインの紐解き方
agatan
8
17k
AI時代もSEOを頑張っている話
shirahama_x
0
210
Rediscover the Console - SymfonyCon Amsterdam 2025
chalasr
2
120
なあ兄弟、 余白の意味を考えてから UI実装してくれ!
ktcryomm
10
10k
TypeScriptで設計する 堅牢さとUXを両立した非同期ワークフローの実現
moeka__c
6
2.8k
【レイトレ合宿11】kagayaki_v4
runningoutrate
0
210
AIエージェントを活かすPM術 AI駆動開発の現場から
gyuta
0
190
目的で駆動する、AI時代のアーキテクチャ設計 / purpose-driven-architecture
minodriven
11
3.8k
しっかり学ぶ java.lang.*
nagise
1
470
AIコードレビューがチームの"文脈"を 読めるようになるまで
marutaku
0
260
Featured
See All Featured
We Have a Design System, Now What?
morganepeng
54
7.9k
Scaling GitHub
holman
464
140k
The Psychology of Web Performance [Beyond Tellerrand 2023]
tammyeverts
49
3.2k
Rebuilding a faster, lazier Slack
samanthasiow
84
9.3k
Keith and Marios Guide to Fast Websites
keithpitt
413
23k
[RailsConf 2023] Rails as a piece of cake
palkan
58
6.1k
Mobile First: as difficult as doing things right
swwweet
225
10k
Navigating Team Friction
lara
191
16k
Templates, Plugins, & Blocks: Oh My! Creating the theme that thinks of everything
marktimemedia
31
2.6k
CSS Pre-Processors: Stylus, Less & Sass
bermonpainter
359
30k
Embracing the Ebb and Flow
colly
88
4.9k
The World Runs on Bad Software
bkeepers
PRO
72
12k
Transcript
詳細の決定を遅らせつつ 実装を早くする 2025/11/08 PHPカンファレンス福岡2025 しまぶ@shimabox
NAME: "しまぶ" SNS: "@shimabox" TAMASHII: "沖縄" COMPANY: "カオナビ" SKILL: -
"PHP" - "Go" FUKUOKA: "SB⚾, アビスパ⚽おめ" whoami.yml 2 はいさい
こんな経験はありませんか 3 ステークホルダー XXX画面作成の進捗は どうでしょうか? ステークホルダー (まだ!!?) おれたち ただいま絶賛DB設計中で...
こんな経験はありませんか 4 ステークホルダー XXX画面作成の進捗は どうでしょうか? ステークホルダー (まだ!!?) おれたち ただいま絶賛DB設計中で... まれによくある
「完璧なDB設計になるまで 実装を始められない」 「どの外部APIを選ぶべきか 決められず1ヶ月が経過」 「仕様が決まらないので 手を動かせない」 まれによくある 5
1. 境界を作る(インターフェース) 2. かんたんな実装で動かす(デモする) 3. フィードバックを得てから本実装 6 この3つのステップを使って解決していきます
なぜ、手が止まるのか 7 そもそも
8 なぜ手が止まるのか 完璧を求めすぎている (最初からいいものを作ろうとしている)
• 「最初から正解を出さないと...」 • 「失敗したくない...」 • 「後から変更できないと思っている」 9 なぜ手が止まるのか
完璧なもの、正解なんてものはない 10 気持ちはわかる、でもね
要求は変わる 11 完璧なもの、正解なんてものはない このサイクルを回したい 作 る 試 す 直 す
→ →
詳細の決定を遅らせつつ 実装を早くする 12 そこで
13 詳細の決定は後回し Clean Architecture 達人に学ぶソフトウェアの構造と設計 詳細の決定を遅らせろ • 詳細の決定は後回しにできる • いや、後回しにすべきだと
言っている
詳細 • DB, フレームワーク, UI, 外部ライブラリ(API), テスト, などなど • 本質的な目的に直接は貢献しないが、目的を実
現するのに必要な技術的なツールや仕組み • 詳細は目的ではなく、手段 14 詳細とはなんでしょう
これらは詳細 なので後回し 「完璧なDB設計になるまで 実装を始められない」 「どの外部APIを選ぶべきか 決められず1ヶ月が経過」 「仕様が決まらないので 手を動かせない」 15 まれによくある
なぜこれで実装が早くなるのか 16 詳細の決定を遅らせる
グルメ情報サイトを作る (福岡市に特化) 17 かんたんな例で見ていきます
イメージ 18 福岡市のグルメスポット
API定義を決める ↓ DB設計を考える ↓ アーキテクチャを考える ↓ 実装 19 よくある 実装まで終わっ
てから、フィー ドバックをもら う
• 「何を受け取って、何を返すか」 • OpenAPI Specification (OAS) を用意したりする 20 API定義を決める
{ "data": [ { "area_name": "中央区", "spots": [ { "id":
1, "name": "◯蘭 天神店", "category": "ラーメン", "location": "福岡市中央区天神x-x-x", "description": "天然とんこつラーメン専門店", "note": "xxxxx", "image_url": "/images/xxxxx.jpg" }, ] }, { "area_name": "博多区", "spots": [ {// 〜 }, {// 〜 }, {// 〜 } ] }, ] } 21 レスポンスJson (正常系)
22 よくある思考 「テーブル設計、クエリはどうしよ うかな」 「正規化は?インデックスは?」 ↓ 1週間経過...まだエンドポイントが 叩けない DB設計
これは詳細 「テーブル設計、クエリはどうしよ うかな」 「正規化は?インデックスは?」 23 DB設計
1. 境界を作る(インターフェース) 2. かんたんな実装で動かす(デモする) 3. フィードバックを得てから本実装 24 そこで、この3つのステップ
• 「何を受け取って、何を返すか」 25 API定義を決める(従来通り)
26 1. 境界を作る // インターフェースで境界を作る interface GourmetSpotInterface { public function
findAll(): array; } ポイント • 「何をするか」だけ定義 • 「どうやるか」は決めない
27 2. かんたんな実装 class InMemoryGourmetSpot implements GourmetSpotInterface { private array
$gourmetSpots = [ [ 'id' => 1, 'name' => '◯蘭 天神店', 'location' => '福岡市中央区天神x-x-x', // 〜 ], [ 'id' => 2, 'name' => 'うどん◯', 'location' => '福岡市博多区住吉x-xx-xxx', // 〜 ], [// 〜], [// 〜], , , ]; public function findAll(): array { return $this->gourmetSpots; } } DB設計は知らんけど、動く!
28 2.5 依存先を変える ここでテストを書いておくと良い class GourmetSpotController { public function __construct(
private GourmetSpotInterface $gourmetSpot ) {} public function index(): JsonResponse { $gourmetSpots = $this->gourmetSpot->findAll(); // エリア別にグルーピング → ビジネスロジック $groupedByArea = $this->groupByArea($gourmetSpots); return response()->json(['data' => $groupedByArea]); } private function groupByArea(array $gourmetSpots): array { // 住所から「中央区」「博多区」などを抽出 } }
29 デモをしてフィードバックを得る おれたち 動くもの作ったので 見てもらえますか? ステークホルダー うーん、料金とか評価とか 項目をもう少し増やしたいです おれたち 了解です!
デモをしてフィードバックを得る おれたち (とりあえず配列いじればいいか) (PHPの配列マジで神) 修正楽勝だな〜 おれたち 修正したので 見てもらえますか? ステークホルダー ぺきかん!
30
// フィードバックを得た上で実装 class GourmetSpot implements GourmetSpotInterface { public function findAll():
array { // この中でDBを触っていく // インターフェースを守っていれば、 試行錯誤が可能 // ----- 以下の選択肢がある ----- // DBじゃなくていいかも // 誰でも編集できるようにファイルでいいかも } } 31 3. フィードバックを得てから本実装 選択肢を残せる / Controllerの修正は不要
32 よくある 詳細の決定を遅らせる • Week 1 ◦ API定義を決める • Week
2 ◦ DB設計、アーキテクチャを考 える • Week 3 ◦ ようやく実装開始 • Week 4 ◦ そしてデモ ↓ 1ヶ月後にやっとフィードバック • Week 1 ◦ API定義を決める • Week 2 ◦ インターフェース定義 ◦ メモリ実装 ◦ デモ ↓ 2週間目からフィードバック! • Week 3以降 ◦ 確信を持って設計、本実装
ステークホルダー 福岡市のお天気情報を表示す るようにしてください おれたち (お天気情報はどこから?) (そもそも必要なんか?) APIは何を使いますか? それが...まだ決まってないです なにかが降ってきた 33
イメージ 34 福岡市のグルメスポット ☀ 23℃(お出かけ日和です) これ
35 やっぱり、この3つのステップ 1. 境界を作る 2. かんたんな実装で動かす 3. フィードバックを得てから本実装
{ "temperature": 23, "weather": "sunny", // これで画像を決める "message": "お出かけ日和です" }
36 API定義を決める
37 1. 境界を作る interface WeatherServiceInterface { // モデルを返す(配列でもいいけど) public function
getWeather(): Weather; } ポイント • OpenWeatherMap? WeatherAPI? 気象庁API? → 後で決める!
38 2. かんたんな実装 class MockWeatherService implements WeatherServiceInterface { public function
getWeather(): Weather { // APIは呼ばずにモデルを返す return new Weather( temperature: 23, weather: 'sunny' ); } } APIの仕様は知らんけど、動かす!
39 2. かんたんな実装 final class Weather { public function __construct(
public readonly int $temperature, public readonly string $weather ) {} public function toArray(): array { return [ 'temperature' => $this->temperature, 'weather' => $this->weather, 'message' => $this->message(), ]; } // ビジネスロジック private function message(): string { return match ($this->weather) { 'sunny' => $this->temperature > 20 ? 'お出かけ日和です' : '少し肌寒いです', default => '今日も一日頑張りましょう' }; } } モデルは単独でテストが書ける!
class GourmetSpotController { public function __construct( private GourmetSpotInterface $gourmetSpot, private
WeatherServiceInterface $weatherService ) {} public function index(): JsonResponse { $gourmetSpots = $this->gourmetSpot->findAll(); $groupedByArea = $this->groupByArea($gourmetSpots); $weather = $this->weatherService->getWeather(); return response()->json([ 'data' => $groupedByArea, 'weather' => $weather->toArray() ]); } private function groupByArea(array $gourmetSpots): array {} } 40 2.5 依存先を変える ここでもテストは書いておく
うーん、、いらないです 了解です!(やっぱりな) デモをしてフィードバックをもらう 41 仮実装のおかげで • 外部API契約してない • 複雑な実装はしてない •
✅ すぐ削除できる
42 3. 採用となってもフィードバックを得ているので実装に入れる class WeatherService implements WeatherServiceInterface { public function
getWeather(): Weather { // 外部APIを叩いて本物のデータを取得 // キャッシュしたりとかも // (実際はHTTPクライアント使う) $data = file_get_contents('https://api.xxxx.org/...'); return $this->createWeather($data); } private function createWeather($data): Weather {}; } 差し替えるだけ
43 よくある 詳細の決定を遅らせる • Week 1-2 ◦ どのAPIを使うか悩む ◦ 料金は?
レスポンス速度は? • Week 3 ◦ 実装開始 • Week 4 ◦ デモ ↓ 「やっぱり、いらないです」🔥 • Week 1 ◦ 仮実装でデモ ◦ 「やっぱり、いらないです」✅ または、 • Week 1 ◦ 仮実装でデモ「よいですね!」 • Week 2-3 ◦ 仕様明確 → API選定👍 → 実装 フィードバックが早いと、 無駄なし!
白状します。 外部APIの選定に1ヶ月以上かけたことがあります。 APIの使い方や、料金、レスポンス速度ばかり調べてい ました。 今となればもう少しうまく進めることが出来たんじゃな いかなぁと反省しながら喋っています。 44 昔の思い出
閑話休題 45
46 アプローチをふりかえる
47 アプローチをふりかえる 1. 境界を作る (詳細の決定は後回し)
48 アプローチをふりかえる 2. 仮実装 (動くものを早く作る)
49 アプローチをふりかえる 3. 本実装 (確信を持って実装)
質問 「必ずインターフェースを用意しな いといけないの?」 50 唐突にQ&A
51 回答:必ずしも必要ではない ベタ書きでもOK • まずは動かすことが大事 • 変わらなそうであればコントローラにベタ書き 詳細はあとでじっくり考えたいところ • 変わりそうなものと、変わらないものを分ける
• そこに境界を作る
52 境界(抽象)をひくのは難しい • 変わりそうなものと、変わらないものを分ける • そして、変わらないものに依存したい • 抽象は変わらないものとして用意したい 抽象は安定化させたい(が、これが難しい)
53 完成までは難しい • PHPの配列は最強だからといって、そのままだ と辛い、Immutableにしたい • グルメスポット一覧は、`GourmetSpot[]` な どで表現できるようになるといい •
動くものは早く作れるけど、完成が早くなると は言っていない
まとめ 54
55 今日話したこと ✅ 詳細の決定は後回しにできる (今まで先に悩んでいたところ) ✅ インターフェースで境界を作れば 実装の置き換えが可能、試行錯誤も可能 ✅
動くものを早く作ると、フィードバックも早まる
56 動くものを早く作ると、フィードバックも早まる ↓ 早期のフィードバックで間違った方向へ進むのを 防げる だいじなこと
57 1. 境界を作る 2. かんたんな実装で動かす 3. フィードバックを得てから本実装 このパターンを身につければ 仕様が未確定でも、手は動かせるはず💪 この3つのステップを試してみよう
58 完璧なもの、正解なんてものはない 手を動かしていきましょう💪 この3つのステップで何かを作ってみてほしい 1. 境界を作る 2. かんたんな実装で動かす 3. フィードバックを得てから本実装
X @shimabox 59 おわりに この発表も「完璧を目指さず」 作られました。 私自身、まだ実践の途中です。 フィードバックをお待ちしてい ます。
60 📖 共著で本を書いています 📖(時間があれば宣伝)
ご清聴ありがとうございました 61