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
コードに語らせよう 自己ドキュメント化が内包する楽しさについて / Let the Code ...
Search
コドモン開発チーム
PRO
May 31, 2025
130
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
330
関数型プログラミングに出会って考え方の幅が広がった話 / server_side_kotlin_meetup_20_functional_fujimura
codmoninc
PRO
0
16
無理せず続ける、子育てエンジニアの学び
codmoninc
PRO
0
860
ペアプロの価値はコードを書くことだけじゃない
codmoninc
PRO
0
420
スクラムで身についていた動き方を、XPで捉え直してみた
codmoninc
PRO
1
640
「正解の仕様」を求めて、決断する
codmoninc
PRO
0
99
AI時代のPHP開発にASTクエリツール で コードベースの地図を作る / ast-query-tool-php-codebase-map
codmoninc
PRO
0
480
コネクションをピン留めさせずに SELECTクエリのタイムアウトを設定した話
codmoninc
PRO
0
480
コドモンに入社してAI活用により、 設計がより重要だと感じた背景
codmoninc
PRO
0
150
Featured
See All Featured
Principles of Awesome APIs and How to Build Them.
keavy
128
18k
Un-Boring Meetings
codingconduct
0
460
Documentation Writing (for coders)
carmenintech
77
5.6k
Building a Modern Day E-commerce SEO Strategy
aleyda
45
9.3k
Ruling the World: When Life Gets Gamed
codingconduct
0
400
What’s in a name? Adding method to the madness
productmarketing
PRO
24
4.2k
Odyssey Design
rkendrick25
PRO
2
870
DBのスキルで生き残る技術 - AI時代におけるテーブル設計の勘所
soudai
PRO
68
58k
Writing Fast Ruby
sferik
630
63k
How to Think Like a Performance Engineer
csswizardry
28
2.9k
Skip the Path - Find Your Career Trail
mkilby
1
260
How to Talk to Developers About Accessibility
jct
2
580
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 おしまい