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

長期運用を目指す『Shadowverse』におけるリファクタ事例の紹介 〜テストの導入とメンバーへの普及法〜

Cygames
December 23, 2020

長期運用を目指す『Shadowverse』におけるリファクタ事例の紹介 〜テストの導入とメンバーへの普及法〜

2020/12/12 PHP カンファレンス 2020 オンライン

Cygames

December 23, 2020
Tweet

More Decks by Cygames

Other Decks in Technology

Transcript

  1. アジェンダ • はじめに • 5年続けたアップデートがもたらした課題 • 課題解決のためにテストを導⼊した話 • テストを⽤いた『ミッション』機能のリファクタ •

    プロジェクトにテスト⽂化を根付かせる話 • テスト駆動開発もできるようになった話 • テスト導⼊の成果 • むすび 2/67
  2. アジェンダ • はじめに • 5年続けたアップデートがもたらした課題 • 課題解決のためにテストを導⼊した話 • テストを⽤いた『ミッション』機能のリファクタ •

    プロジェクトにテスト⽂化を根付かせる話 • テスト駆動開発もできるようになった話 • テスト導⼊の成果 • むすび 3/67
  3. 3ヶ⽉に⼀度のメジャーアップデート • 新規機能の追加 • 既存機能の改修 • 不具合の修正 追 加 実

    装 不 具 合 修 正 CS調査・対応 2020 6⽉ 9⽉ 実装 試遊 限られた時間のなかで、『最⾼のコンテンツ』を サーバー側だけで 約1400コミット、約40000行の変更 11/67
  4. アジェンダ • はじめに • 5年続けたアップデートがもたらした課題 • 課題解決のためにテストを導⼊した話 • テストを⽤いた『ミッション』機能のリファクタ •

    プロジェクトにテスト⽂化を根付かせる話 • テスト駆動開発もできるようになった話 • テスト導⼊の成果 • むすび 12/67
  5. 現在の多様化した『ミッション』機能 初⼼者 向け ストーリー バトル系 ソロプレイ 期間限定 ストーリー N章まで デイリー

    ルムマ勝利 Open 6 アカウント 連携 100万円 特別ルーム プレイ • 『ミッション』数も350種類を超える – バトル系のミッションが特に増加 16/67
  6. アジェンダ • はじめに • 5年続けたアップデートがもたらした課題 • 課題解決のためにテストを導⼊した話 • テストを⽤いた『ミッション』機能のリファクタ •

    プロジェクトにテスト⽂化を根付かせる話 • テスト駆動開発もできるようになった話 • テスト導⼊の成果 • むすび 18/67
  7. ゲーム開発にテスト導⼊して期待できること② • 期間限定イベントの挙動確認 – 11⽉中だけイベントが開催されていることを確認したい場合 テストなしの場合 テストありの場合 10⽉ サーバー 時間変更

    サーバー 時間変更 11⽉ サーバー 時間変更 12⽉ イベント イベント イベント イベント期間 イベントが開催されているか チェックするテスト 10⽉として実⾏ 11⽉として実⾏ 12⽉として実⾏ 22/67
  8. テスト導⼊のフロー(概要) 1. テスト実⾏環境を作成 – テストが動くようにする 2. テスト環境の管理⽅法検討 – テストを書きやすくする 3.

    ⾃動テスト環境を作成 – ⾃動でテストを回せるようにする 各⼿順において⼤切なのは「まずやってみる」こと 限られた時間で、まずはテスト導⼊をやりきる 25/67
  9. FW修正の⽅向性の確認 FW修正のコードレビュー テストDBのマイグレーションについて 1.テスト実⾏環境の作成 -データベースの分離- • アプリ⽤とテスト⽤のDBは分離が必要 – アプリ⽤:ユーザーデータを作成 –

    テスト⽤:ユーザーデータを作成&削除 • DBの分離のためFWの修正が必要 Tips:テストの初期化 ユーザーデータはDBに⼊っているの で、テストのたびに初期値を⼊れ直 して再現性を担保する。 コード API実⾏ テスト実⾏ アプリDB テストDB リファクタが得意なメンバーと相談 27/67
  10. 2.テスト環境の管理⽅法検討 • フォルダ階層をどうするか – 将来的にファイルが散らばってしまう • リポジトリ管理をどうするか yml テスト1の初期化ファイル.yml 機能Aのテスト1.php

    機能A 機能Aのテスト2.php テスト2の初期化ファイル.yml 開発環境 (共通サーバー) (エンジニアのみ) 本番環境 (お客様のみ) テスト テスト 本番環境にcloneしない サーバー サーバー 機能ごとにファイルを管理 サーバーとテストはリポジトリを分ける └テストコードは本番環境に不要 Git submoduleは使⽤しない └⾯倒になってきて敬遠されるようになってしまう テスト経験者と相談 機能ごとにファイル管理 28/67
  11. 3.⾃動テスト環境の作成 • ⾃動テストの必要条件 – 定時に実⾏できる – 実⾏結果を通知できる あとで拡張 指定パスの テストを実⾏

    「とりあえず」の対応で実現 固定メンバーに 失敗通知 新規テストは ⼿動で追加 理想系 新規テストも ⾃動で実⾏ テスト作成者 にだけ通知 CIツールおじさん CIツールおじさん 29/67
  12. テストを書き始める準備が完了 • テスト導⼊チームの結成 • テスト導⼊のフロー決定 • テスト環境の作成 • テスト環境の設計 •

    ⾃動テスト環境の作成 テストを⽤いて『ミッション』機能をリファクタしていく テストで『ミッション』機能をリファクタできるのでは︖ 『ミッション』機能を リファクタしたい… テストの社内勉強会 という”きっかけ” 30/67
  13. アジェンダ • はじめに • 5年続けたアップデートがもたらした課題 • 課題解決のためにテストを導⼊した話 • テストを⽤いた『ミッション』機能のリファクタ •

    プロジェクトにテスト⽂化を根付かせる話 • テスト駆動開発もできるようになった話 • テスト導⼊の成果 • むすび 31/67
  14. テスト ✔ テスト ✔ リファクタの担保としてのテスト 1. in/outを確認できるテストを書く 2. リファクタを⾏う 3.

    in/outの結果が変わっていなければリファクタ成功 in out APIや 関数 in out リファクタ後 32/67
  15. どれだけテストを書く必要があるか︖ • 【理想】すべての『ミッション』についてテストを書く – リファクタによって、すべてのミッションにバグが置きてないことを担保したい • 【現実】⼀部の『ミッション』についてテストを書く – 「エルフで1勝」「ロイヤルで1勝」というようなミッションは同種扱いする –

    ⼤体10種類くらいのミッション種に分ける • テストが必要な要素を抜き出す – ミッションを進⾏ – ミッションを達成 – ミッション報酬を受け取る – ミッションを受注 バトル系 ・進⾏ ・達成 ・報酬 ・受注 35/67
  16. テストを⽤いたリファクタの流れ 1. ⼤きなスコープでテストを書く 2. ⼤きな処理を切り出す 3. 処理の切り出しの繰り返し 4. テストを増やす 5.

    切り出した処理をリファクタ 6. リファクタの繰り返し ⼤きなスコープでテストを書いてから テストを細分化していくのが重要 36/67
  17. テスト 1.⼤きなスコープでテストを書く 関数() { ミッション進⾏処理 ミッション達成処理 報酬付与処理 新ミッション受注処理 } ミッション達成条件

    引数、レコード 達成結果 レコードの変化、返り値 • 条件を満たせば、特定の状態になる、というテストを書く ✔ 37/67
  18. アジェンダ • はじめに • 5年続けたアップデートがもたらした課題 • 課題解決のためにテストを導⼊した話 • テストを⽤いた『ミッション』機能のリファクタ •

    プロジェクトにテスト⽂化を根付かせる話 • テスト駆動開発もできるようになった話 • テスト導⼊の成果 • むすび 46/67
  19. メンバーにテストを普及させる • Shadowverseは10年、20年の運⽤を⽬指している – その間、多くのリファクタが必要になる • メンバーの多くがテストを書けるようにする – ◦ 積極的に書く

    – △ 書けるけど、書かない – ✕ 知らないので書かない いきなり「テストを書いて」と⾔ってもなかなか普及しない テストを書く⽂化を根付かせるため、どうすればいいか︖ 47/67
  20. 環境構築のハードルを下げる • ⽬的 – 興味を持った⼈がすぐにテストに着⼿できるようにする • 必要な要素 – テスト⽤フレームワークのインストール –

    テスト環境⽤DBの構築 • 対策 – 各種インストール⼿順書の作成 • ⼿順書通りにコマンドをコピペして実⾏すれば環境構築できるレベル – DB更新スクリプトの作成 • コマンド⼀つ実⾏すればDB構築できるレベルのもの 50/67
  21. テスト作成のハードルを下げる • ⽬的 – まだテストを書いたことがない⼈への機会提供・フォロー • 必要な要素 – テストの書き⽅の学習機会の提供 –

    テストを書くきっかけの提供 • 対策 – テストコードのレビューをしてもらう – リファクタ案件を「テストを書いてリファクタする」案件に昇華 51/67
  22. ⾃動テスト実⾏のハードルを下げる • ⽬的 – ⾃動テストの整備が嫌でテストを敬遠されないようにする • 必要な要素 – 簡単に実⾏できる –

    結果を確認する⼿間を減らす • 対策 – CIツールによる⾃動テストの⽤意 – CIツールが社内SNSにテスト結果の通知を送るようにする 52/67
  23. アジェンダ • はじめに • 5年続けたアップデートがもたらした課題 • 課題解決のためにテストを導⼊した話 • テストを⽤いた『ミッション』機能のリファクタ •

    プロジェクトにテスト⽂化を根付かせる話 • テスト駆動開発もできるようになった話 • テスト導⼊の成果 • むすび 55/67
  24. テスト駆動開発について 概要 1. 設計要件をもとに失敗するテストコードを書く 2. テストが成功するようにコードを書く 3. テスト成功を維持しつつコードを綺麗にしていく メリット 1.

    テストによりコードの動作を担保しながら実装できるので、 後⼯程で⼿戻りが発⽣しない 2. 出来上がるコードは要件をすべてパスしたものであり、 バグが少なく、実装者の⼼理的安⼼感もある 56/67
  25. ゲーム開発におけるテスト駆動開発の流れ 概要 1. 設計要件をもとに失敗するテストコードを書く 2. テストが成功するようにコードを書く 3. テスト成功を維持しつつコードを綺麗にしていく 4. APIとして各処理を組み⽴て

    5. Unity(実機)による動作確認 6. デバッグ 考慮漏れによるバグ 仕様で想定外のバグ テストを書いていてもデバッグはいつもどおりやる (テストケースの考慮漏れを⾒逃さない) 57/67
  26. テスト駆動開発をしてみて • ⾼速に実装できた – コマンドライン上での動作確認が主となるため(Unityを起動しない) – バグ報告がきても素早く対応可能 • ⾮常に可読性の⾼いコードが書けた –

    要件ごとに単体テストを書くと、各処理が⼩さくなるため – 実装から1年ほどたっても満⾜のいくコードに • リファクタでテストを書く経験をしておいてよかった – 「テストを書きやすい単位で関数を書く」スキルが必要 – このスキルはリファクタ時のテスト導⼊で養える 60/67
  27. アジェンダ • はじめに • 5年続けたアップデートがもたらした課題 • 課題解決のためにテストを導⼊した話 • テストを⽤いた『ミッション』機能のリファクタ •

    プロジェクトにテスト⽂化を根付かせる話 • テスト駆動開発もできるようになった話 • テスト導⼊の成果 • むすび 61/67
  28. テストコード導⼊した箇所の変化 • コードの可読性が低下 – コードの綺麗さ優先で実装してばかりはいられない – 限られた時間で実装するには、デバッグ範囲を絞れるよう実装する必要があるため • コードの属⼈化 –

    機能の追加実装をする場合、もともと担当だったメンバーに再度仕事を割り当てることが多い – 限られた時間で実装するには、素早く実装に移れるメンバーを割り当てるのが適当なため • コードの可読性が向上 – 単体テストとして細かく関数を実装するため – テストが仕様と実装の橋渡しをするためコード読解しやすい • コードの属⼈化に解消の兆し – コード読解しやすいため、もともと担当でないメンバーに仕事を割り当てしやすい – テストの増築は簡単なため、⼿が空いたときに⾮担当タスクをメンバーに割り当てられる 62/67
  29. アジェンダ • はじめに • 5年続けたアップデートがもたらした課題 • 課題解決のためにテストを導⼊した話 • テストを⽤いた『ミッション』機能のリファクタ •

    プロジェクトにテスト⽂化を根付かせる話 • テスト駆動開発もできるようになった話 • テスト導⼊の成果 • むすび 66/67
  30. むすび • ⻑期運⽤中の⼤規模プロジェクトコードに対しテストを導⼊ – 準備は⼤変だが、まずやってみることが重要 – コードの可読性、属⼈化に解消の兆し – テスト駆動開発ではなく、リファクタから •

    プロジェクトにテスト⽂化を根付かせるプロセス – まずは少⼈数でテストがかける環境を整える – テストを書くハードルをできる限り下げ、テストを書く機会を増やす 67/67