Upgrade to Pro — share decks privately, control downloads, hide ads and more …

[PHPerKaigi 2026]PHPerKaigi2025の企画CodeGolfが最高すぎ...

Sponsored · Your Podcast. Everywhere. Effortlessly. Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
Avatar for Z.O.E. Z.O.E.
March 20, 2026

[PHPerKaigi 2026]PHPerKaigi2025の企画CodeGolfが最高すぎて社内で内製して半年運営して得た内製と運営の知見

Avatar for Z.O.E.

Z.O.E.

March 20, 2026
Tweet

More Decks by Z.O.E.

Other Decks in Programming

Transcript

  1. X(旧twitter): @for__3 #phperkaigi #b 社内で 内製して半年運営 して得た 内製と 運営の 知⾒

    2026/03/20 PHPerKaigi 2026 @zoe 1 PHPerKaigi2025の企画 CodeGolfが最⾼すぎて
  2. X(旧twitter): @for__3 #phperkaigi #b • コードが仕様にあってるかどうかすぐ確認できる • コードの良さ(短さ)が定量化されている • コードを⾃分で考えて改善できる

    • ⼀つのやり⽅に縛られず、さまざまなアプローチができる • まだAIを使っても最適コードを出すのは難しい ◦ 競技性がある コードゴルフの⾯⽩いところ 12
  3. X(旧twitter): @for__3 #phperkaigi #b コードゴルフの⾯⽩いところ • コードが仕様にあってるかどうかすぐ確認できる • コードの良さ(短さ)が定量化されている •

    コードを⾃分で考えて改善できる • ⼀つのやり⽅に縛られず、さまざまなアプローチができる • まだAIを使っても最適コードを出すのは難しい ◦ 競技性がある • 複数のことを同時に実現する⽅法を思い つくとめっちゃ気持ちいい 13
  4. X(旧twitter): @for__3 #phperkaigi #b この⽩熱を持って帰ってもっとシェアしたい • コードが仕様にあってるかどうかすぐ確認できる • コードの良さ(短さ)が定量化されている •

    コードを⾃分で考えて改善できる • ⼀つのやり⽅に縛られず、さまざまなアプローチができる • まだAIを使っても最適コードを出すのは難しい ◦ 競技性がある • 複数のことを同時に実現する⽅法を思い つくとめっちゃ気持ちいい 14
  5. X(旧twitter): @for__3 #phperkaigi #b 私(GitHub Copilot)が3⽇で作りました 15 • GitHub Copilot

    • PHP8.4 • Laravel12 • Docker on Docker https://github.com/IkezoeMakoto/code-champs
  6. X(旧twitter): @for__3 #phperkaigi #b 社内で 内製して半年運営 して得た 内製と 運営の 知⾒

    2026/03/20 PHPerKaigi 2026 @zoe 17 PHPerKaigi2025の企画 CodeGolfが最⾼すぎて
  7. X(旧twitter): @for__3 #phperkaigi #b ⽬次 • 導⼊ • CodeChampsの仕組み ◦

    構成、実⾏環境、セキュリティ、DooD、採点ロジック、複数 ⾔語対応 • イベント運営 ◦ 運営で⼯夫した点、実際に出した問題、うまく⾏かなかった点 • CodeGolfテクニック ◦ 時間があれば 18
  8. X(旧twitter): @for__3 #phperkaigi #b 19 株式会社ウィルゲート ゼネラルマネージャー∕VPoE やってること 組織‧技術戦略/教育/採⽤/PM/SRE/インフラ 興味あること

    - コードゴルフ/⾃動化/開発⽣産性/PHP/スノボ 執筆 - 【第3回】Dockerで実現! 効率的で⾼速な開発環境 ……makeコマンド⼀発でできる! - 【最終回】パフォーマンスチューニングをしよう ……PHP 8でXdebugとWebgrindを使ってプロファイ リング 池添 誠(いけぞえ まこと)
  9. X(旧twitter): @for__3 #phperkaigi #b • 導⼊ • CodeChampsの仕組み ◦ 構成、実⾏環境、セキュリティ、DooD、採点ロジック、複数

    ⾔語対応 • イベント運営 ◦ 運営で⼯夫した点、実際に出した問題、うまく⾏かなかった点 • まとめ、CodeGolfテクニック ⽬次 20
  10. X(旧twitter): @for__3 #phperkaigi #b お題と提出コードの実⾏環境の仕組み 32 TOP画⾯ (お題⼀覧) お題詳細 画⾯

    [管理者]お題登録 ‧編集‧削除 コード提出 提出コード確認⽤ 隔離コンテナで 実⾏確認
  11. X(旧twitter): @for__3 #phperkaigi #b お題と提出コードの実⾏環境の仕組み 33 TOP画⾯ (お題⼀覧) お題詳細 画⾯

    [管理者]お題登録 ‧編集‧削除 コード提出 提出コード確認⽤ 隔離コンテナで 実⾏確認 FAIL
  12. X(旧twitter): @for__3 #phperkaigi #b お題と提出コードの実⾏環境の仕組み 34 TOP画⾯ (お題⼀覧) お題詳細 画⾯

    [管理者]お題登録 ‧編集‧削除 コード提出 提出コード確認⽤ 隔離コンテナで 実⾏確認 スコア算出‧ ランキング登録 PASS FAIL
  13. X(旧twitter): @for__3 #phperkaigi #b 8割はCopilotで楽に実装(約3⼈⽇) ⼀般的なWebにあるような機能についてはほぼ⼿直しなしで 実装可能 • ユーザ登録‧ログイン •

    お題の登録‧編集‧削除 • お題の期間制御‧コードの提出‧ランキング • ベストスコアのslack通知 39
  14. X(旧twitter): @for__3 #phperkaigi #b 8割はCopilotで楽に実装(約3⼈⽇) ⼀般的なWebにあるような機能についてはほぼ⼿直しなしで 実装可能 • ユーザ登録‧ログイン •

    お題の登録‧編集‧削除 • お題の期間制御‧コードの提出‧ランキング • ベストスコアのslack通知 • 複数⾔語対応のための拡張 40
  15. X(旧twitter): @for__3 #phperkaigi #b お題と提出コードの実⾏環境の仕組み 48 Docker(ホスト) APP (PHP-FPM) APP

    (Nginx) APP (MySQL) アプリケーションコンテナと別で管理している Submission Executerコンテナ Submission executer (PHP8.4) Submission executer (PHP8.4) Submission executer (PHP8.4) Submission executer (PHP8.4) ソケット共有
  16. X(旧twitter): @for__3 #phperkaigi #b お題と提出コードの実⾏環境の仕組み 49 Docker(ホスト) APP (PHP-FPM) APP

    (Nginx) APP (MySQL) APP(PHP-FPM)からDocker(ホスト)のソケットを経由して Submission executerコンテナをホスト上で起動 Submission executer (PHP8.4) Submission executer (PHP8.4) Submission executer (PHP8.4) Submission executer (PHP8.4) ソケット共有
  17. X(旧twitter): @for__3 #phperkaigi #b APP(PHP-FPM)からは指定の⾔語のコンテナ上に テストケース、提出コードをマウントしてrun-tests.shを実⾏するだけ お題と提出コードの実⾏環境の仕組み 50 Docker(ホスト) APP

    (PHP-FPM) APP (Nginx) APP (MySQL) Submission executer (PHP8.4) Submission executer (PHP8.4) Submission executer (PHP8.4) Submission executer (PHP8.4) run-tests.sh run-tests.sh run-tests.sh run-tests.sh テスト ケース 提出 コード マウントして実⾏ ソケット共有
  18. X(旧twitter): @for__3 #phperkaigi #b セキュリティ アプリケーション本体と提出コード実⾏を別コンテナに分離 52 Docker(ホスト) APP (PHP-FPM)

    APP (Nginx) APP (MySQL) Submission executer (PHP8.4) Submission executer (PHP8.4) Submission executer (PHP8.4) Submission executer (PHP8.4) run-tests.sh run-tests.sh run-tests.sh run-tests.sh テスト ケース 提出 コード ソケット共有
  19. X(旧twitter): @for__3 #phperkaigi #b セキュリティ 提出コード実⾏⽤コンテナに セキュリティ⽤オプションを設定 53 x-sandbox-defaults: &sandbox-defaults

    volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  20. X(旧twitter): @for__3 #phperkaigi #b セキュリティ 実⾏ごとの⼀時ファイルを分離 54 x-sandbox-defaults: &sandbox-defaults volumes:

    - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  21. X(旧twitter): @for__3 #phperkaigi #b セキュリティ ネットワーク完全遮断 • 外部通信による情報漏洩防⽌ • 外部サービスへの攻撃防⽌

    • 不正なダウンロード‧C2通信の 遮断 55 x-sandbox-defaults: &sandbox-defaults volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  22. X(旧twitter): @for__3 #phperkaigi #b セキュリティ nobodyユーザーで実⾏ • root権限の剥奪 • コンテナ内での権限昇格リスク

    低減 56 x-sandbox-defaults: &sandbox-defaults volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  23. X(旧twitter): @for__3 #phperkaigi #b セキュリティ root filesystem を読み取り専⽤化 • バイナリ改ざん‧永続化防⽌

    • 書き込みは tmpfs や volume に 限定 57 x-sandbox-defaults: &sandbox-defaults volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  24. X(旧twitter): @for__3 #phperkaigi #b セキュリティ メモリ上の⼀時ファイル領域を作 成 • noexec ◦

    ファイルを実⾏不可 • nosuid ◦ 権限昇格不可 • size=16m ◦ サイズ制限 58 x-sandbox-defaults: &sandbox-defaults volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  25. X(旧twitter): @for__3 #phperkaigi #b セキュリティ Linux capability をすべて削除 • rootでなくてもできる特権操作

    を封じる ◦ ネットワーク設定変更、マウント など • コンテナ脱出リスクの低減 59 x-sandbox-defaults: &sandbox-defaults volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  26. X(旧twitter): @for__3 #phperkaigi #b セキュリティ 実⾏中に権限昇格を禁⽌ • setuidバイナリなどによる権限 取得を防⽌ •

    exploitの成⽴条件を潰す 60 x-sandbox-defaults: &sandbox-defaults volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  27. X(旧twitter): @for__3 #phperkaigi #b セキュリティ プロセス数の上限設定 • fork bomb対策 •

    リソース枯渇防⽌ 61 x-sandbox-defaults: &sandbox-defaults volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  28. X(旧twitter): @for__3 #phperkaigi #b セキュリティ OSレベルのリソース制限 • nproc ◦ ユーザーが作れるプロセス数

    • nofile ◦ 開けるファイル数 62 x-sandbox-defaults: &sandbox-defaults volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  29. X(旧twitter): @for__3 #phperkaigi #b セキュリティ Tiniを使⽤ • ゾンビプロセス処理 • SIGTERM/SIGKILLの正しい伝播

    • コンテナ終了の安定化 63 x-sandbox-defaults: &sandbox-defaults volumes: - code-champs_submission-tests:/tmp working_dir: /app network_mode: none user: "65534:65534" read_only: true tmpfs: - /run:rw,noexec,nosuid,size=16m - /var/tmp:rw,noexec,nosuid,size=16m cap_drop: - ALL security_opt: - no-new-privileges:true pids_limit: 128 ulimits: nproc: 128 nofile: soft: 1024 hard: 1024 init: true
  30. X(旧twitter): @for__3 #phperkaigi #b 採点ロジック phpタグ、及び不可視⽂字を除外した⽂字数をカウント 64 $submission->score = strlen(

    preg_replace( [ '/<\?php|\?>/', // PHPタグを削除 '/\s+/' // 空白を削除 ], '', $validated['code'] ) ); function updateScore() { const code = document.getElementById('code').value; const cleanedCode = code.replace(/<\?php|\?>|\s+/g, ''); document.getElementById('score') .textContent = cleanedCode.length; }
  31. X(旧twitter): @for__3 #phperkaigi #b 実⾏環境はsubmission-executer/compose.yamlで管理 • submission-executer/ ◦ compose.yaml ◦

    php8.4/ ▪ run-tests.sh ▪ Dockerfile ◦ php7.4/ ▪ run-tests.sh ▪ Dockerfile ◦ node22/ ▪ run-tests.sh ▪ Dockerfile ◦ bash5.2/ ▪ run-tests.sh ▪ Dockerfile 複数⾔語対応 〜省略〜 services: php8.4: build: ./php8.4 php7.4: build: ./php7.4 node22: build: ./node22 bash5.2: build: ./bash5.2 volumes: code-champs_submission-tests: external: true 65
  32. X(旧twitter): @for__3 #phperkaigi #b 複数⾔語対応 〜省略〜 services: php8.4: build: ./php8.4

    php7.4: build: ./php7.4 node22: build: ./node22 bash5.2: build: ./bash5.2 volumes: code-champs_submission-tests: external: true 66 実⾏環境はsubmission-executer/compose.yamlで管理 • submission-executer/ ◦ compose.yaml ◦ php8.4/ ▪ run-tests.sh ▪ Dockerfile ◦ php7.4/ ▪ run-tests.sh ▪ Dockerfile ◦ node22/ ▪ run-tests.sh ▪ Dockerfile ◦ bash5.2/ ▪ run-tests.sh ▪ Dockerfile
  33. X(旧twitter): @for__3 #phperkaigi #b アプリからは提出⾔語のコンテナ上でrun-tesets.shを実⾏して、⼊⼒ としてテストケースと提出コードを渡すだけ 簡単に複数⾔語対応できる仕組み 67 Docker(ホスト) APP

    (PHP-FPM) APP (Nginx) APP (MySQL) Submission executer (PHP7.4) Submission executer (PHP8.4) Submission executer (Node22) Submission executer (Bash5.2) run-tests.sh run-tests.sh run-tests.sh run-tests.sh テスト ケース 提出 コード マウントして実⾏ ソケット共有
  34. X(旧twitter): @for__3 #phperkaigi #b アプリからは提出⾔語のコンテナ上でrun-tesets.shを実⾏して、⼊⼒ としてテストケースと提出コードを渡すだけ 簡単に複数⾔語対応できる仕組み 68 Docker(ホスト) APP

    (PHP-FPM) APP (Nginx) APP (MySQL) Submission executer (PHP7.4) Submission executer (PHP8.4) Submission executer (Node22) Submission executer (Bash5.2) run-tests.sh run-tests.sh run-tests.sh run-tests.sh テスト ケース 提出 コード マウントして実⾏ これがインターフェース! ソケット共有
  35. X(旧twitter): @for__3 #phperkaigi #b お題側でも提出⾔語指定 69 お題 テスト ケース サンプル

    コード ⾔語 提出 コード お題に紐づくサンプルコードは ⾔語テーブルに紐づいて登録される サンプルコードも⾔語ごと登録が必要
  36. X(旧twitter): @for__3 #phperkaigi #b ⽬次 • 導⼊ • CodeChampsの仕組み ◦

    構成、実⾏環境、セキュリティ、DooD、採点ロジック、複数 ⾔語対応 • イベント運営 ◦ 運営で⼯夫した点、実際に出した問題、うまく⾏かなかった点 • まとめ、CodeGolfテクニック 70
  37. X(旧twitter): @for__3 #phperkaigi #b 運営⽅針 73 • 基本⽉1でお題を掲載 ◦ 業務時間などで多忙な時期に偏りがあることがある

    • 最初期は“簡単そうな”お題を作成して掲載 ◦ ⾃分も参加したいので、お題はAIと協⼒して作成
  38. X(旧twitter): @for__3 #phperkaigi #b 運営⽅針 74 • 基本⽉1でお題を掲載 ◦ 業務時間などで多忙な時期に偏りがあることがある

    • 最初期は“簡単そうな”お題を作成して掲載 ◦ ⾃分も参加したいので、お題はAIと協⼒して作成
  39. X(旧twitter): @for__3 #phperkaigi #b 運営⽅針 75 • 基本⽉1でお題を掲載 ◦ 業務時間などで多忙な時期に偏りがあることがある

    • 最初期は“簡単そうな”お題を作成して掲載 ◦ ⾃分も参加したいので、お題はAIと協⼒して作成
  40. X(旧twitter): @for__3 #phperkaigi #b 運営⽅針 76 • 基本⽉1でお題を掲載 ◦ 業務時間などで多忙な時期に偏りがあることがある

    • 最初期は“簡単そうな”お題を作成して掲載 ◦ ⾃分も参加したいので、お題はAIと協⼒して作成
  41. X(旧twitter): @for__3 #phperkaigi #b 運営⽅針 77 • 基本⽉1でお題を掲載 ◦ 業務時間などで多忙な時期に偏りがあることがある

    • 最初期は“簡単そうな”お題を作成して掲載 ◦ ⾃分も参加したいので、お題はAIと協⼒して作成
  42. X(旧twitter): @for__3 #phperkaigi #b 運営⽅針 • 基本⽉1でお題を掲載 ◦ 業務時間などで多忙な時期に偏りがあることがある •

    最初期は“簡単そうな”お題を作成して掲載 ◦ ⾃分も参加したいので、お題はAIと協⼒して作成 • 期間中、Code Champsランチを企画 ◦ 活性化と難易度調整のため意⾒交換を実施 ◦ 前⽉優勝者はランチ無料特典! 78
  43. X(旧twitter): @for__3 #phperkaigi #b • 定期的にCode Champsランチを実施 ◦ → 業務多忙で何もしないと徐々に参加者減少傾向

    ◦ お題をみんなで解く会、先⽉の優勝者の解説 • お題の掲載を2つに変更 ◦ → ランキング上位者の固定化への対策 ◦ Begginer:少し簡単、過去1位とった⼈は卒業 ◦ Master:解きごたえのある難しめ、提出⾃由 ⼯夫した点 81
  44. X(旧twitter): @for__3 #phperkaigi #b ⼯夫した点 83 • paizaさんのOnline PHP Editorの活⽤

    ◦ CodeChamps上ではDebugが仕様上できない error_reporting(E_ALL & ~E_WARNING & ~E_NOTICE);
  45. X(旧twitter): @for__3 #phperkaigi #b うまく⾏かなかった点 86 • 参加者の継続 • 難易度調整

    ◦ AIを使っての出題&⾃⾝も参加したいため、どの程度まで削れ そうか、ロジックがどの程度難解かが不確実 ◦ とはいえ、シンプル版→複雑化させる⽅法で作ることである程 度コントロール可
  46. X(旧twitter): @for__3 #phperkaigi #b うまく⾏かなかった点 • 参加者の継続 • 難易度調整 ◦

    AIを使っての出題&⾃⾝も参加したいため、どの程度まで削れ そうか、ロジックがどの程度難解かが不確実 ◦ とはいえ、シンプル版→複雑化させる⽅法で作ることである程 度コントロール可 • 複数⾔語での仕様差異を使った出題 ◦ PHPerが多い&PHPがそこそこ短くかけることでPHPが多い ◦ バージョン差異も狙って出題が難しい 87
  47. X(旧twitter): @for__3 #phperkaigi #b ⽬次 88 • 導⼊ • CodeChampsの仕組み

    ◦ 構成、実⾏環境、セキュリティ、DooD、採点ロジック、複数 ⾔語対応 • イベント運営 ◦ 運営で⼯夫した点、実際に出した問題、うまく⾏かなかった点 • まとめ、CodeGolfテクニック