Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
詳細の決定を遅らせつつ実装を早くする
Search
shimabox
November 08, 2025
Programming
2.6k
2
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
詳細の決定を遅らせつつ実装を早くする
PHPカンファレンス福岡2025 の発表資料になります
#phpconfuk #hall_hz
shimabox
November 08, 2025
More Decks by shimabox
See All by shimabox
明示と暗黙 ー PHPとGoの インターフェイスの違いを知る
shimabox
2
1.5k
人には人それぞれのサービス層がある
shimabox
3
1.5k
自分のためから誰かのためへ
shimabox
10
4.9k
情報処理安全確保支援士をとった話
shimabox
1
300
クリーンアーキテクチャから見る依存の向きの大切さ
shimabox
5
3.1k
GoとPHPのインターフェイスの違い
shimabox
2
590
並行処理を学びGuzzleと仲良くなる
shimabox
3
3.4k
擬人化で完全に理解するクリーンアーキテクチャ
shimabox
20
13k
Unit of Workパターンで永続化とトランザクションを制御する
shimabox
12
8.8k
Other Decks in Programming
See All in Programming
GraphQL の onError と Nullability のこれから
quramy
0
200
Modernizing iOS Apps
seyfoyun
0
150
ActionController meets Protocol Buffers
sorah
1
770
React Native에 현대적인 빌드 도구 더하기: Rollipop 구현기
leegeunhyeok
0
180
느린 네트워크와 저사양 디바이스 사용자를 위한 웹뷰 로딩 시간 개선기
kmkim
0
140
Groovy as a human and AI friendly programming language
paulk
0
170
作れる、でも消せるか?──安全に「枯らして消す」機能削除術 / Drain, Then Delete
chobishiba
3
1.4k
Enforcing Your Architecture with Unit Tests in the AI Era (Swift Connection X)
steliosf
PRO
1
110
AI時代のFlutter品質設計 — アプリ品質を守るQuality Layers
omatty198
0
340
Event is what happens
moro
2
2.8k
HTML-in-Canvasで作る未来のWeb UI表現
clockmaker
5
6.1k
Web3Dライブラリを作ってVue Custom Rendererの仕組みを理解しよう / lets learn vue custom renderer by making 3d library
drumath2237
1
120
Featured
See All Featured
Designing Powerful Visuals for Engaging Learning
tmiket
1
630
Design and Strategy: How to Deal with People Who Don’t "Get" Design
morganepeng
133
20k
KATA
mclloyd
PRO
35
16k
JavaScript: Past, Present, and Future - NDC Porto 2020
reverentgeek
52
6.2k
Data-driven link building: lessons from a $708K investment (BrightonSEO talk)
szymonslowik
1
1.4k
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Visualization
eitanlees
153
17k
Abbi's Birthday
coloredviolet
4
11k
Fight the Zombie Pattern Library - RWD Summit 2016
marcelosomers
234
18k
My Coaching Mixtape
mlcsv
0
380
Noah Learner - AI + Me: how we built a GSC Bulk Export data pipeline
techseoconnect
PRO
0
470
30 Presentation Tips
portentint
PRO
1
450
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