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
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
コードに語らせよう 自己ドキュメント化が内包する楽しさについて / Let the Code ...
Search
コドモン開発チーム
PRO
May 31, 2025
120
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
コードに語らせよう 自己ドキュメント化が内包する楽しさについて / Let the Code Speak: The Joy of Self-Documenting Code
コドモン開発チーム
PRO
May 31, 2025
More Decks by コドモン開発チーム
See All by コドモン開発チーム
ペアプロの価値はコードを書くことだけじゃない
codmoninc
PRO
0
150
スクラムで身についていた動き方を、XPで捉え直してみた
codmoninc
PRO
1
330
「正解の仕様」を求めて、決断する
codmoninc
PRO
0
71
AI時代のPHP開発にASTクエリツール で コードベースの地図を作る / ast-query-tool-php-codebase-map
codmoninc
PRO
0
360
コネクションをピン留めさせずに SELECTクエリのタイムアウトを設定した話
codmoninc
PRO
0
370
コドモンに入社してAI活用により、 設計がより重要だと感じた背景
codmoninc
PRO
0
120
実装・設計だけでなく、運用・保守にもAIを広げてみた / We Took AI Beyond Coding and Into Operations and Maintenance
codmoninc
PRO
0
110
AIが無かった頃の素敵な出会いの話
codmoninc
PRO
1
570
5分で問診!Composer セキュリティ健康診断
codmoninc
PRO
0
1.3k
Featured
See All Featured
How to Build an AI Search Optimization Roadmap - Criteria and Steps to Take #SEOIRL
aleyda
1
2.2k
So, you think you're a good person
axbom
PRO
2
2.1k
Future Trends and Review - Lecture 12 - Web Technologies (1019888BNR)
signer
PRO
0
3.7k
How to Think Like a Performance Engineer
csswizardry
28
2.8k
AI: The stuff that nobody shows you
jnunemaker
PRO
9
980
Distributed Sagas: A Protocol for Coordinating Microservices
caitiem20
333
23k
Digital Projects Gone Horribly Wrong (And the UX Pros Who Still Save the Day) - Dean Schuster
uxyall
1
2.8k
RailsConf 2023
tenderlove
30
1.5k
Building an army of robots
kneath
306
46k
[RailsConf 2023] Rails as a piece of cake
palkan
59
7k
State of Search Keynote: SEO is Dead Long Live SEO
ryanjones
0
260
What's in a price? How to price your products and services
michaelherold
247
13k
Transcript
コードに語らせよう 自己ドキュメント化が内包する楽しさについて nrs
2 Profile nrs(成瀬 允宣) @nrslib コドモンのCTO 趣味: カンファレンス講演 学生支援 小学校支援
写真
3 今日のお話
4 今日のお話
5 今日のお話
6 今日のお話
はじめに 自己ドキュメント化が内包する楽しさ コードで見る自己ドキュメント化 楽しさの根源 楽しくないを避ける環境づくり まとめ コードに語らせよう
はじめに 自己ドキュメント化が内包する楽しさ コードで見る自己ドキュメント化 楽しさの根源 楽しくないを避ける環境づくり まとめ コードに語らせよう
こんな経験ありませんか?
10 • ドキュメントが陳腐化している こんな経験ありませんか?
11 • ドキュメントがそもそもない こんな経験ありませんか?
12 • Gitのログが最高にロック こんな経験ありませんか?
13 • コメントに騙された こんな経験ありませんか?
こんな課題を解決するには?
15 • コードはドキュメントと無関係に存在する こんな問題を解決するための道筋
16 • コードをドキュメントにすればいい こんな問題を解決するための道筋
あれ? 楽しい……?
はじめに 自己ドキュメント化が内包する楽しさ コードで見る自己ドキュメント化 楽しさの根源 楽しくないを避ける環境づくり まとめ コードに語らせよう
19 • 複雑なものをできるだけシンプルに • 機能美との両立 • 制限プレイ パズルに似た楽しさ
20 • 頭の中のモヤモヤをコードで明文化 • 「あ、これだよこれ!」というすっきり感 • 「関連資料を見る必要がない!」 言語化の喜び
21 • 受け取るのは自分だったりするけどな!!! 未来の誰かへの贈り物
はじめに 自己ドキュメント化が内包する楽しさ コードで見る自己ドキュメント化 楽しさの根源 楽しくないを避ける環境づくり まとめ コードに語らせよう
具体的にはどんなコードなのさ!
無口なコード
function check($c, $t, $s) { if ($t < 9 ||
$t > 18) return false; if ($s == 1 && count($c->getP()) >= 30) return false; if ($s == 2 && count($c->getP()) >= 20) return false; if ($c->age < 3 && $s != 1) return false; return true; }
function check($c, $t, $s) { if ($t < 9 ||
$t > 18) return false; if ($s == 1 && count($c->getP()) >= 30) return false; if ($s == 2 && count($c->getP()) >= 20) return false; if ($c->age < 3 && $s != 1) return false; return true; } なにやってんだこれー?
語り始めたコード
class EnrollmentService { public function canAcceptNewChild( Classroom $classroom, int $desiredStartHour,
int $childAge): bool { if ($this->isOutsideOperatingHours($desiredStartHour)) { return false; } if ($this->isClassroomAtCapacity($classroom)) { return false; } if ($this->isToddlerRequiringSpecializedCare($childAge, $classroom)) { return false; } return true; } :
class EnrollmentService { public function canAcceptNewChild( Classroom $classroom, int $desiredStartHour,
int $childAge): bool { if ($this->isOutsideOperatingHours($desiredStartHour)) { return false; } if ($this->isClassroomAtCapacity($classroom)) { return false; } if ($this->isToddlerRequiringSpecializedCare($childAge, $classroom)) { return false; } return true; } : 子どもを受け入れられるか
class EnrollmentService { public function canAcceptNewChild( Classroom $classroom, int $desiredStartHour,
int $childAge): bool { if ($this->isOutsideOperatingHours($desiredStartHour)) { return false; } if ($this->isClassroomAtCapacity($classroom)) { return false; } if ($this->isToddlerRequiringSpecializedCare($childAge, $classroom)) { return false; } return true; } : クラス
class EnrollmentService { public function canAcceptNewChild( Classroom $classroom, int $desiredStartHour,
int $childAge): bool { if ($this->isOutsideOperatingHours($desiredStartHour)) { return false; } if ($this->isClassroomAtCapacity($classroom)) { return false; } if ($this->isToddlerRequiringSpecializedCare($childAge, $classroom)) { return false; } return true; } : 何時からを希望? 何歳?
class EnrollmentService { public function canAcceptNewChild( Classroom $classroom, int $desiredStartHour,
int $childAge): bool { if ($this->isOutsideOperatingHours($desiredStartHour)) { return false; } if ($this->isClassroomAtCapacity($classroom)) { return false; } if ($this->isToddlerRequiringSpecializedCare($childAge, $classroom)) { return false; } return true; } : 時間外じゃないかの確認
class EnrollmentService { public function canAcceptNewChild( Classroom $classroom, int $desiredStartHour,
int $childAge): bool { if ($this->isOutsideOperatingHours($desiredStartHour)) { return false; } if ($this->isClassroomAtCapacity($classroom)) { return false; } if ($this->isToddlerRequiringSpecializedCare($childAge, $classroom)) { return false; } return true; } : クラスのキャパを確認
class EnrollmentService { public function canAcceptNewChild( Classroom $classroom, int $desiredStartHour,
int $childAge): bool { if ($this->isOutsideOperatingHours($desiredStartHour)) { return false; } if ($this->isClassroomAtCapacity($classroom)) { return false; } if ($this->isToddlerRequiringSpecializedCare($childAge, $classroom)) { return false; } return true; } : 専門的なケアが必要?
private function isOutsideOperatingHours(int $hour): bool { return $hour < 9
|| $hour > 18; } private function isClassroomAtCapacity(Classroom $classroom): bool { return count($classroom->getEnrolledChildren()) >= $classroom->getMaxCapacity(); } private function isToddlerRequiringSpecializedCare(int $childAge, Classroom $classroom) : bool { return $childAge < 3 && !$classroom->isToddlerSpecialized(); }
private function isOutsideOperatingHours(int $hour): bool { return $hour < 9
|| $hour > 18; } private function isClassroomAtCapacity(Classroom $classroom): bool { return count($classroom->getEnrolledChildren()) >= $classroom->getMaxCapacity(); } private function isToddlerRequiringSpecializedCare(int $childAge, Classroom $classroom) : bool { return $childAge < 3 && !$classroom->isToddlerSpecialized(); } 9時〜18時
private function isOutsideOperatingHours(int $hour): bool { return $hour < 9
|| $hour > 18; } private function isClassroomAtCapacity(Classroom $classroom): bool { return count($classroom->getEnrolledChildren()) >= $classroom->getMaxCapacity(); } private function isToddlerRequiringSpecializedCare(int $childAge, Classroom $classroom) : bool { return $childAge < 3 && !$classroom->isToddlerSpecialized(); } 教室キャパと人数確認
private function isOutsideOperatingHours(int $hour): bool { return $hour < 9
|| $hour > 18; } private function isClassroomAtCapacity(Classroom $classroom): bool { return count($classroom->getEnrolledChildren()) >= $classroom->getMaxCapacity(); } private function isToddlerRequiringSpecializedCare(int $childAge, Classroom $classroom) : bool { return $childAge < 3 && !$classroom->isToddlerSpecialized(); } 3歳未満で幼児向けに特化されてない
流暢なコード
class EnrollmentPolicy { public function canAccept(Child $child, Classroom $classroom, int
$desiredStartHour) : EnrollmentResult { if ($desiredStartHour < 9 || $desiredStartHour > 18) { return EnrollmentResult::rejected('outside_operating_hours'); } if (!$classroom->hasCapacityFor($child)) { return EnrollmentResult::rejected('classroom_at_capacity'); } if ($child->getAge() < 3 && !$classroom->isToddlerSpecialized()) { return EnrollmentResult::rejected('classroom_not_suitable_for_age'); } return EnrollmentResult::accepted(); } }
class EnrollmentPolicy { public function canAccept(Child $child, Classroom $classroom, int
$desiredStartHour) : EnrollmentResult { if ($desiredStartHour < 9 || $desiredStartHour > 18) { return EnrollmentResult::rejected('outside_operating_hours'); } if (!$classroom->hasCapacityFor($child)) { return EnrollmentResult::rejected('classroom_at_capacity'); } if ($child->getAge() < 3 && !$classroom->isToddlerSpecialized()) { return EnrollmentResult::rejected('classroom_not_suitable_for_age'); } return EnrollmentResult::accepted(); } } Serviceとは別軸の処理に切り出し
class EnrollmentPolicy { public function canAccept(Child $child, Classroom $classroom, int
$desiredStartHour) : EnrollmentResult { if ($desiredStartHour < 9 || $desiredStartHour > 18) { return EnrollmentResult::rejected('outside_operating_hours'); } if (!$classroom->hasCapacityFor($child)) { return EnrollmentResult::rejected('classroom_at_capacity'); } if ($child->getAge() < 3 && !$classroom->isToddlerSpecialized()) { return EnrollmentResult::rejected('classroom_not_suitable_for_age'); } return EnrollmentResult::accepted(); } } true / false から脱却
class EnrollmentResult { private bool $accepted; private ?string $rejectionReason; :
public static function accepted(): self { return new self(true); } public static function rejected(string $reason): self { return new self(false, $reason); } }
もはや喋りすぎ?
class Age { private int $value; public function __construct(int $value)
{ $this->value = $value; } public function isUnderThree(): bool { return $this->value < 3; } } class DesiredStartTime { private int $hour; public function isWithinOperatingHours(): bool { return $this->hour >= 9 && $this->hour <= 18; } } 一長一短に思う
無口なコード②
function recordAttendance($child_id, $action, $timestamp) { $db = new PDO(‘sqlite:attendance.db’); $today
= date(‘Y-m-d’, $timestamp); // 今日の記録を取得 $stmt = $db->prepare(“SELECT * FROM attendance WHERE child_id = ? AND date = ?”); $stmt->execute([$child_id, $today]); $record = $stmt->fetch(); if ($action == ‘checkin’) { if ($record && $record[‘checkin_time’]) { return [‘success’ => false, ‘message’ => ‘既に登園済みです’]; } if ($record) { $stmt = $db->prepare(“UPDATE attendance SET checkin_time = ? WHERE id = ?”); $stmt->execute([date(‘H:i:s’, $timestamp), $record[‘id’]]); } else { $stmt = $db->prepare(“INSERT INTO attendance (child_id, date, checkin_time) VALUES (?, ?, ?)”) $stmt->execute([$child_id, $today, date(‘H:i:s’, $timestamp)]); } return [‘success’ => true, ‘message’ => ‘登園を記録しました’]; } :
function recordAttendance($child_id, $action, $timestamp) { $db = new PDO(‘sqlite:attendance.db’); $today
= date(‘Y-m-d’, $timestamp); // 今日の記録を取得 $stmt = $db->prepare(“SELECT * FROM attendance WHERE child_id = ? AND date = ?”); $stmt->execute([$child_id, $today]); $record = $stmt->fetch(); if ($action == ‘checkin’) { if ($record && $record[‘checkin_time’]) { return [‘success’ => false, ‘message’ => ‘既に登園済みです’]; } if ($record) { $stmt = $db->prepare(“UPDATE attendance SET checkin_time = ? WHERE id = ?”); $stmt->execute([date(‘H:i:s’, $timestamp), $record[‘id’]]); } else { $stmt = $db->prepare(“INSERT INTO attendance (child_id, date, checkin_time) VALUES (?, ?, ?)”) $stmt->execute([$child_id, $today, date(‘H:i:s’, $timestamp)]); } return [‘success’ => true, ‘message’ => ‘登園を記録しました’]; } : ちゃんと読めば分かる →ちゃんと読まないとわからん
function recordAttendance($child_id, $action, $timestamp) { $db = new PDO(‘sqlite:attendance.db’); $today
= date(‘Y-m-d’, $timestamp); // 今日の記録を取得 $stmt = $db->prepare(“SELECT * FROM attendance WHERE child_id = ? AND date = ?”); $stmt->execute([$child_id, $today]); $record = $stmt->fetch(); if ($action == ‘checkin’) { if ($record && $record[‘checkin_time’]) { return [‘success’ => false, ‘message’ => ‘既に登園済みです’]; } if ($record) { $stmt = $db->prepare(“UPDATE attendance SET checkin_time = ? WHERE id = ?”); $stmt->execute([date(‘H:i:s’, $timestamp), $record[‘id’]]); } else { $stmt = $db->prepare(“INSERT INTO attendance (child_id, date, checkin_time) VALUES (?, ?, ?)”) $stmt->execute([$child_id, $today, date(‘H:i:s’, $timestamp)]); } return [‘success’ => true, ‘message’ => ‘登園を記録しました’]; } : 配列かぁ
語り始めたコード②
public function recordAttendance(int $childId, string $action, DateTime $timestamp) : AttendanceResult
{ $today = $timestamp->format('Y-m-d'); switch ($action) { case 'checkin': return $this->processCheckIn($childId, $today, $timestamp); case 'checkout': return $this->processCheckOut($childId, $today, $timestamp); default: return new AttendanceResult(false, '無効な操作です'); } }
public function recordAttendance(int $childId, string $action, DateTime $timestamp) : AttendanceResult
{ $today = $timestamp->format('Y-m-d'); switch ($action) { case 'checkin': return $this->processCheckIn($childId, $today, $timestamp); case 'checkout': return $this->processCheckOut($childId, $today, $timestamp); default: return new AttendanceResult(false, '無効な操作です'); } } 読む気になる!!
public function recordAttendance(int $childId, string $action, DateTime $timestamp) : AttendanceResult
{ $today = $timestamp->format('Y-m-d'); switch ($action) { case 'checkin': return $this->processCheckIn($childId, $today, $timestamp); case 'checkout': return $this->processCheckOut($childId, $today, $timestamp); default: return new AttendanceResult(false, '無効な操作です'); } } 登園
public function recordAttendance(int $childId, string $action, DateTime $timestamp) : AttendanceResult
{ $today = $timestamp->format('Y-m-d'); switch ($action) { case 'checkin': return $this->processCheckIn($childId, $today, $timestamp); case 'checkout': return $this->processCheckOut($childId, $today, $timestamp); default: return new AttendanceResult(false, '無効な操作です'); } } 降園
private function processCheckIn(int $childId, string $date, DateTime $timestamp): AttendanceResult {
$record = $this->dao->findTodaysRecord($childId, $date); if ($record && $record->checkinTime) { return new AttendanceResult(false, '既に登園済みです'); } if (!$record) { $record = new AttendanceRecord(); $record->childId = $childId; $record->date = $date; } $record->checkinTime = $timestamp->format('H:i:s'); $this->dao->save($record); return new AttendanceResult(true, '登園を記録しました'); }
private function processCheckIn(int $childId, string $date, DateTime $timestamp): AttendanceResult {
$record = $this->dao->findTodaysRecord($childId, $date); if ($record && $record->checkinTime) { return new AttendanceResult(false, '既に登園済みです'); } if (!$record) { $record = new AttendanceRecord(); $record->childId = $childId; $record->date = $date; } $record->checkinTime = $timestamp->format('H:i:s'); $this->dao->save($record); return new AttendanceResult(true, '登園を記録しました'); } 意図を語ってくれてる (SQLの意図を理解しなくていい)
流暢なコード②
public function recordAttendance(ChildId $childId, AttendanceAction $action, DateTime $timestamp): AttendanceResult {
$todaysRecord = $this->repository->findTodaysRecord($childId); try { if ($action->isCheckIn()) { $record = $todaysRecord ?: new AttendanceRecord($childId, new Date($timestamp)); $record->recordCheckIn($timestamp); $this->repository->save($record); return AttendanceResult::checkInSuccess(); } if ($action->isCheckOut()) { if (!$todaysRecord) { return AttendanceResult::notCheckedIn(); } $todaysRecord->recordCheckOut($timestamp); $this->repository->save($todaysRecord); return AttendanceResult::checkOutSuccess(); } :
public function recordAttendance(ChildId $childId, AttendanceAction $action, DateTime $timestamp): AttendanceResult {
$todaysRecord = $this->repository->findTodaysRecord($childId); try { if ($action->isCheckIn()) { $record = $todaysRecord ?: new AttendanceRecord($childId, new Date($timestamp)); $record->recordCheckIn($timestamp); $this->repository->save($record); return AttendanceResult::checkInSuccess(); } if ($action->isCheckOut()) { if (!$todaysRecord) { return AttendanceResult::notCheckedIn(); } $todaysRecord->recordCheckOut($timestamp); $this->repository->save($todaysRecord); return AttendanceResult::checkOutSuccess(); } : データを主語でなく、モデルを主語に
public function recordAttendance(ChildId $childId, AttendanceAction $action, DateTime $timestamp): AttendanceResult {
$todaysRecord = $this->repository->findTodaysRecord($childId); try { if ($action->isCheckIn()) { $record = $todaysRecord ?: new AttendanceRecord($childId, new Date($timestamp)); $record->recordCheckIn($timestamp); $this->repository->save($record); return AttendanceResult::checkInSuccess(); } if ($action->isCheckOut()) { if (!$todaysRecord) { return AttendanceResult::notCheckedIn(); } $todaysRecord->recordCheckOut($timestamp); $this->repository->save($todaysRecord); return AttendanceResult::checkOutSuccess(); } : データを確認するのでなく、オブジェクトに移譲
無口なコード③
function validatePickup($person_id, $child_id, $current_time) { $db = new PDO('sqlite:nursery.db'); //
子供の情報を取得 $stmt = $db->prepare("SELECT * FROM children WHERE id = ? AND status = 'present'"); $stmt->execute([$child_id]); $child = $stmt->fetch(); if (!$child) { return ['success' => false, 'message' => '子供が見つからないか、まだ登園していません']; } // 迎えに来た人の情報を取得 $stmt = $db->prepare("SELECT * FROM persons WHERE id = ?"); $stmt->execute([$person_id]); $person = $stmt->fetch(); if (!$person) { return ['success' => false, 'message' => '迎えに来た方の情報が見つかりません']; } // 親または保護者の場合は常に許可 if ($person['type'] == 'parent' || $person['type'] == 'guardian') { return ['success' => true, 'message' => 'お迎え可能です']; } // 事前に承認された人の場合 $stmt = $db->prepare("SELECT * FROM authorized_persons WHERE child_id = ? AND person_id = ? AND is_active = 1"); $stmt->execute([$child_id, $person_id]); $authorized = $stmt->fetch(); if ($authorized) { return ['success' => true, 'message' => 'お迎え可能です']; } // 緊急連絡先の場合(15分前までに連絡が必要) if ($person['type'] == 'emergency') { $stmt = $db->prepare("SELECT * FROM pickup_notifications WHERE child_id = ? AND person_id = ? AND notify_time <= ?"); $notify_deadline = $current_time - (15 * 60); // 15分前 $stmt->execute([$child_id, $person_id, $notify_deadline]); $notification = $stmt->fetch(); if ($notification) { return ['success' => true, 'message' => 'お迎え可能です']; } else { return ['success' => false, 'message' => '緊急連絡先の方は15分前までにご連絡ください']; } } return ['success' => false, 'message' => 'お迎えの権限がありません']; }
語り始めたコード③
public function validatePickup(int $personId, int $childId, DateTime $currentTime): PickupResult {
$child = $this->childDAO->find($childId); if (!$child || !$child->isPresentAtNursery()) { return new PickupResult(false, '子供が見つからないか、まだ登園していません'); } $person = $this->personDAO->find($personId); if (!$person) { return new PickupResult(false, '迎えに来た方の情報が見つかりません'); } if ($this->canPickupChild($person, $childId, $currentTime)) { return new PickupResult(true, 'お迎え可能です'); } return new PickupResult(false, 'お迎えの権限がありません'); }
public function validatePickup(int $personId, int $childId, DateTime $currentTime): PickupResult {
$child = $this->childDAO->find($childId); if (!$child || !$child->isPresentAtNursery()) { return new PickupResult(false, '子供が見つからないか、まだ登園していません'); } $person = $this->personDAO->find($personId); if (!$person) { return new PickupResult(false, '迎えに来た方の情報が見つかりません'); } if ($this->canPickupChild($person, $childId, $currentTime)) { return new PickupResult(true, 'お迎え可能です'); } return new PickupResult(false, 'お迎えの権限がありません'); } 同じ内容でも見るべき場所がここであると語っている
private function canPickupChild(Person $person, int $childId, DateTime $currentTime): bool {
if ($person->isParentOrGuardian()) { return true; } if ($this->authorizationDAO->isAuthorized($childId, $person->id)) { return true; } if ($person->isEmergencyContact() && $this->hasValidEmergencyNotification($childId, $person->id, $currentTime)) { return true; } return false; }
保護者か? private function canPickupChild(Person $person, int $childId, DateTime $currentTime): bool
{ if ($person->isParentOrGuardian()) { return true; } if ($this->authorizationDAO->isAuthorized($childId, $person->id)) { return true; } if ($person->isEmergencyContact() && $this->hasValidEmergencyNotification($childId, $person->id, $currentTime)) { return true; } return false; }
private function canPickupChild(Person $person, int $childId, DateTime $currentTime): bool {
if ($person->isParentOrGuardian()) { return true; } if ($this->authorizationDAO->isAuthorized($childId, $person->id)) { return true; } if ($person->isEmergencyContact() && $this->hasValidEmergencyNotification($childId, $person->id, $currentTime)) { return true; } return false; } 権限はあるか
private function canPickupChild(Person $person, int $childId, DateTime $currentTime): bool {
if ($person->isParentOrGuardian()) { return true; } if ($this->authorizationDAO->isAuthorized($childId, $person->id)) { return true; } if ($person->isEmergencyContact() && $this->hasValidEmergencyNotification($childId, $person->id, $currentTime)) { return true; } return false; } 緊急連絡先であり、有効な緊急通知権限をもっているか
流暢なコード③
class PickupAuthorizationPolicy { : public function canPickUp(Person $person, Child $child,
DateTime $requestTime): PickupAuthorization { if ($person->isParentOf($child) || $person->isGuardianOf($child)) { return PickupAuthorization::approved(); } if ($child->hasAuthorizedPerson($person)) { return PickupAuthorization::approved(); } if ($person->isEmergencyContactFor($child)) { $notificationDeadline = (clone $requestTime)->modify('-15 minutes'); if ($this->notificationRepository->hasAdvanceNotificationFor( $child->getId(), $person->getId(), $notificationDeadline)) { return PickupAuthorization::approved(); } return PickupAuthorization::denied('emergency_no_notification'); } return PickupAuthorization::denied('unauthorized_person'); } }
class PickupAuthorizationPolicy { : public function canPickUp(Person $person, Child $child,
DateTime $requestTime): PickupAuthorization { if ($person->isParentOf($child) || $person->isGuardianOf($child)) { return PickupAuthorization::approved(); } if ($child->hasAuthorizedPerson($person)) { return PickupAuthorization::approved(); } if ($person->isEmergencyContactFor($child)) { $notificationDeadline = (clone $requestTime)->modify('-15 minutes'); if ($this->notificationRepository->hasAdvanceNotificationFor( $child->getId(), $person->getId(), $notificationDeadline)) { return PickupAuthorization::approved(); } return PickupAuthorization::denied('emergency_no_notification'); } return PickupAuthorization::denied('unauthorized_person'); } } <「お迎えできるかは私を見なさい」
実はコード以外も語るよ!
74 • 重要なのは実は構造 何かを伝えるのは文字に限らない PHPカンファレンス新潟2025用 コードは大きく3パターン 1stだけは過剰パターンがある
はじめに 自己ドキュメント化が内包する楽しさ コードで見る自己ドキュメント化 楽しさの根源 楽しくないを避ける環境づくり まとめ コードに語らせよう
何が楽しいんだい?
77 • 時間的プレッシャー 制限される楽しさ マリオだって制限時間がある RTAという文化がある
78 • 今できる最高に挑戦 最大限への挑戦 自分との戦い アスリートの気持ち
どういうとき楽しくなくなるの?
80 • 時間がなさすぎる • 知識・スキルが不足しすぎている • 最初の一歩が怖い 楽しくなくなる要素
楽しさを取り戻すには?
82 • 時間がなさすぎるに対する解 楽しさを取り戻す方法 一般的に言われることは 丁寧に時間をかけて 保守性を高くする時間も含めて 工数にする ※開発者には楽観的工数を 言いがちな方もいる
83 • 時間がなさすぎるに対する解 楽しさを取り戻す方法 (脳筋な)自分としては 時間をかけても 品質は変わらないので 常に最高を書けるよう精進せよ 物事の多くは ある程度までは知識ゲー
84 • 知識・スキルが不足しすぎているに対する解 楽しさを取り戻す方法 そりゃペアプロよ あとはとにかく読むこと 今なら生成AIもあるしなー(※)
85 • 最初の一歩が怖い 楽しさを取り戻す方法 そりゃペアプロよ
はじめに 自己ドキュメント化が内包する楽しさ コードで見る自己ドキュメント化 楽しさの根源 楽しくないを避ける環境づくり まとめ コードに語らせよう
87 • それを支えるには環境づくりが重要 楽しさは失われやすい
88 • チーム 環境づくり ・レビューで学び合い ・ペアプロでナレッジの共有 ・自己ドキュメント性という指標
89 • 組織 環境づくり 文化として根付く組織作り ・評価/認知の仕組み ・学習/共有の場作り
はじめに 自己ドキュメント化が内包する楽しさ コードで見る自己ドキュメント化 楽しさの根源 楽しくないを避ける環境づくり まとめ コードに語らせよう
91 • 自己ドキュメント化は…… まとめ 思考の整理、表現の喜び、問題への挑戦 人間の知的好奇心を満たす行為のひとつ コードが仕様書と胸を張って言えるコードを目指そう
92 仲間を探しています 子どもを取り巻く環境をテクノロジーの力でよりよいものにしていく仲間を大募集! • 子育てしやすい環境です ◦ 子育てにドメイン知識がありすぎるメンバー ◦ フレックス/フルリモート可 •
開発者体験が最高です ◦ アジャイル(XP) ◦ バーチャルオフィス(Gather) ◦ ペアプロでコードについて議論できます ◦ CTOが財布
93 「募集中ポジション」や 「カジュアル面談の申込み」から ぜひご連絡ください!
94 • X ◦ @nrslib • HomePage ◦ https://nrslib.com/ •
YouTube ◦ https://www.youtube.com/@nrslib おしまい