PHPカンファレンス2020 レポート

PHPカンファレンス2020 レポート[前編]

12月12日(土⁠⁠、PHPカンファレンス2020が開催されました。 PHPカンファレンスは今年20周年の節目を迎え、初のオンライン開催となりました。 本稿ではその模様をお伝えしていきます。前編では2つのセッションを取り上げます。

成瀬允宣さん「PHP WEBアプリケーション設計入門 —⁠—10年先を見据えて作る」

GMOインターネットの成瀬允宣さんは、10年続くサービスを開発するために必要な考え方や知識、具体的な実装テクニックやプラクティスなどについて話しました

画像

10年続くサービスと、PHPやフレームワークの移り変わり

10年という言葉にどのようなイメージを持つでしょうか? 10年続くサービスはそれほど存在しないのではないかというイメージがあるかもしれません。しかし、GMOインターネットではお名前.comやまるごとサーバー、お名前.comレンタルサーバー、GMOアプリクラウド、ConoHa byGMOなど10年続いているサービスはたくさん存在します。成瀬さんは「これほど多くのサービスが存在していれば現実味を感じてもらえるはず」と述べていました。

しかし、10年前に書かれたコードが今現在も同じということはなく、存在し続ける以上確実に変わってきているそうです。この10年で変わったことはコードはもちろんのこと、フレームワークやデータベースなどの特定の技術も挙げられると語りました。

そしてPHPの歴史はPHP toolsから始まり、25年の月日を経て、最近ではPHP8.0がリリースされています。フレームワークについてはphrameというものが最初に現れました。その後、様々な激しい変化を経てCakePHPやFuelPHP、Laravelなど多くの方が知っているフレームワークが登場してきます。

また、10年も続ける予定はないと思いながら開発を進めるサービスでも、よくできたそのプログラムは他の開発者に参考にされることがあります。そのようにプログラムは分身を続け、いつだって当初の想定よりも広く長く使われることがあるのです。成瀬さんは「心血を注ぐなら10年動くことを信じたほうが楽しい」と述べていました。

フレームワークの選定と、設計する際のアーキテクチャ

フレームワークを選定する際にまずすべきことは、ルーティングやORM、スキャフォールディングなど、必要な機能をまず列挙することです。そして、それらの条件を満たすフレームワークを候補として、その中でチームの士気が上がるかどうか、10年後に残っているかどうかということを考えながら選定します。10年後もそのフレームワークが存在するかは運次第ですので、むしろ10年後に残らないものとし、特定の技術スタックから乗り換えを前提にします。総じて言えることとして、フレームワークから一定の距離を保つことが大切だと指摘します。

画像

アーキテクチャは重要な要素ですが、アーキテクチャ自体がそもそもよくわからなかったり、どれが最適であるかを選ぶのが難しいといった声があがります。そこでお勧めするのがレイヤードアーキテクチャです。レイヤードアーキテクチャは上から順に、User Interface(MVC⁠フレームワーク)⁠、Application(ドメインオブジェクトなどを利用するコード⁠⁠、Domain(ビジネスルール⁠⁠、Infrastructure(DBなど)の4階層に分けられ、上位層から下位層への依存は許されますが、下位層から上位層の依存は許されません。

テスタビリティの確保

次にテストの話に移りました。⁠テストできない時に開発者にできることはなんでしょうか?」と問いかけ、なにもしない期間を祈りながら過ごすよりも、自分の書いたコードを自信を持って正しいと言えるために、テストをできるようになっていること、つまり、テスタビリティの確保が重要であると話しました。

そのために必要な知識がDIP(Dependency Inversion Principle;依存関係逆転の原則)です。DIPは、上位レベルのモジュールは下位レベルのモジュールに依存してはならず、また、どちらのモジュールも抽象に依存するべきで、抽象が実装の詳細に依存してはならないというものです。

たとえば、ORMに依存するコードを書いてしまうと、テストがしづらいなどの問題点があります。それを解決するには、インターフェースとIoC Containerを利用して、モジュールを切り替えられるようにすることが良い方法です。そうすることで、初期開発や新規機能開発にありがちな、モデリングやコーディングをしていたらデータが違ったためテーブル定義から変更せざるを得ないことになるような場合でも、スタブを使っていればパラメータを書き換えるだけで済むようになるからです。これによりプロダクションとデバッグの環境を分けられるため、開発がしやすくなります。

データモデルとドメインオブジェクト

10年経てばインフラも変わります。たとえばデータベースが変わることがあります。よって、Infrastructureに依存してしまうと気軽に挿げ替えができなくなります。そのため、Infrastnructure層とDomain層を分けておく必要があります。ただここで、レイヤードアーキテクチャにしたがうと、Application層やDomain層からInfrastructure層への依存が肯定されてしまうと言及しました。

そこでApplication Domain Others Patternというアーキテクチャを成瀬さんは提案しました。このアーキテクチャではUser Interface層とInfrastructure層を挿げ替え可能にし、Application層とDomain層を10年後も使えるようにしたことを説明しました。

画像

エラー設計について

10年とはあまり関係のない話としつつ言及されたのが、エラー設計の話です。成瀬さんは、エラー設計こそがサービスの質だと考えられると言います。

エラーには2種類あって、システムエラーと呼ばれるデータベースが落ちるなどのようなユーザーに伝えても意味のないものと、ユーザーエラーと呼ばれるIDの重複など情報(価値)をユーザーに伝えるべきものがあります。サービス内で起こったエラーをコントローラ内でtry-catchなどを使わず、ユーザーに伝えるべきものは伝え、伝えなくてもよいものはこちらで処理を進めるなどの動作をコードに落とし込むことが大切だとしました。

まとめ

最後に成瀬さんは、⁠⁠実際にはこれほど立派に作らなくてもサービスが10年続くことはあると思います。しかし、そのサービスが継続できたのは、誰かの血と汗と涙の結晶であることもあるのです。なるべく血と汗と涙を流さないために10年先を見据えて設計をしましょう」と述べ、発表を締めくくりました。

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

Cygamesの髙野祐輝さんは、サービス5年目を迎えたShadowverseがこれから10年、20年と続くコンテンツへと成長させていくためのテストを活用したリファクタについて話しました

画像

Shadowverseにおける開発と、そこから生じた課題

Cygamesでは「最高のコンテンツ」を作る会社として、プリンセスコネクトRe:Dive、Shadowverse、グランブルーファンタジーなどのゲームを企画・開発・運営しています。

Shadowverseはサービス5年目を迎えたカードイラストの対戦型DCGで、eスポーツイベントも行われています。現在でも3ヶ月に一度大型アップデートを行っており、新規機能の追加や既存機能の改修、不具合の修正などをしています。サーバー側では実に1,400コミット、約4万行の変更を行っています。髙野さんは「限られた時間の中で最高のコンテンツを届けられるよう各メンバーが心がけている」と話しました。

画像

限られた時間でアップデートを行うため、様々な問題が発生します。たとえば、コードの綺麗さだけでなくスケジュール等を意識した結果、コードの可読性が低下することや、機能の追加実装を効率重視で元の担当者に依頼する事が続き、コードの属人化が進むことなどが挙げられます。

ユーザーが特定の条件を満たした際、ユーザーにカードパックやゲーム内通貨などのインセンティブが発生する「ミッション」という機能があります。リリース初期のミッションはストーリー、デッキ編集、バトル系、アカウント連携など、種類が少なく管理も簡単でした。それが増改築を繰り返し、現在ではバトル系のミッションが特に増加し、その数が350種類を超えました。そこで、新規ミッションの追加が容易で、デバッグ工数が低いコードにしたいと考えるようになったそうです。

しかし、こういった大規模な機能のリファクタリングは、リスクとデバッグコストの懸念があり、なかなか着手できない状態にありました。

課題解決のためにテストを導入

転機となったのは、社内で開かれた勉強会で、外部講師を招きテストについて学ぶことができたそうです。

テストとは書いたコードが正しく動作しているかを確認するためのプログラムのことです。テストが失敗していたらコードを修正し、テストがすべて成功なら実装完了となります。また、入力と出力が明確であるほどテストが書きやすくなるので、テストの書きやすさを意識する事は良いコードを書くことに繋がります。

テストを導入することによって期待できることは、不正操作による異常系、通信のタイミングによって発生する異常系などの動作確認が容易になることです。他にも、イベント開催処理を変更したあとの動作確認時、テストコードを書いていれば、実機での動作確認に比べ素早く挙動確認がとれることなどを挙げていました。ミッション機能をリファクタしたいという思いと、テストの社内勉強会というきっかけから、テストを活用してミッション機能をリファクタしようと動き出すことになったそうです。

テストを用いた、ミッション機能のリファクタ

今回リファクタにおいて気をつけたいのは、テストが、リファクタの成否を担保するためのツールだということです。in/outを確認できるテストを書き、リファクタを行い、in/outの結果が変わってなければリファクタ成功という流れになります。

では、どれだけテストを書くといいのでしょうか? すべてのミッションについてテストを書くのが理想ですが、その数は膨大なため、ある程度の粒度でミッションを絞ったり、テストが必要な要素を抜き出したりして、一部のミッションについてテストを書いていったそうです。大きなスコープでテストを書いてからテストを細分化していくのが重要だということです。

ミッション機能のリファクタの結果、巨大になっていた処理を細分化できたこと、またテストによってコードが単一責任原則に立ち返ることでコードの品質が向上したと言います。他にも、大規模リファクタにも関わらずバグがほとんどでなかったことを挙げていました。しかしテストで想定できていない箇所にバグがあることもあったそうです。テストを書いていてもきちんとデバッグが必要だと述べていました。

プロジェクトにテスト文化を根づかせる

Shadowverseは10年、20年の運用を目標としており、その間に多くのリファクタが必要になります。そのため、メンバーの多くがテストをかけるようになるとよりよいと考えているそうです。しかし、いきなりテストを書いてと言ってもなかなか普及しません。テストを書く文化を根付かせるため、テストが普及しづらい原因を探ったところ、テストを書く環境がないことや書き方がわからないなど、テスト初心者に立ちはだかる壁が存在していることがわかったそうです。

そこでこのハードルを徹底して下げることが重要だと考え、支援することにしました。まず、テストを行う環境構築は手順書やスクリプトの作成をしました。テスト作成についてはテストコードのレビュー、リファクタ案件をテストを書いてリファクタする案件にしました。また、CIツールによる自動テストを行い、テスト結果を社内ツールに通知するようにしました。

テストのハードル下げにこだわった理由は、テストに触れてみようと思ってもらうことと、カスタマーサポート最優先にしてユーザーのことを最優先に考えているため、不具合対応を素早くおこなえるようになるためだと言います。テスト駆動開発をするようになって、高速に実装でき、可読性の高いコードを書くことができるようになったと話していました。コードの属人化に解消の兆しもみえるようになりました。

そしてテストコードを整備することで、保守コストに図に挙げる変化がみられるようになったと紹介しました。

画像

まとめ

髙野さんは、長期運用中の大規模プロジェクトコードに対しテストを導入したことと、プロジェクトにテスト文化を根付かせるプロセスについて説明しました。⁠最高のコンテンツを目指してテストを導入し、成果を挙げることができた」と述べていました。

おすすめ記事

記事・ニュース一覧