JUGEM PHP

レガシーPHPプロダクトのアプリケーションアーキテクチャ改善活動(第3回/全3回)

JUGEM PHP

こちらは前回の記事からの続きとなっております。

第1回の記事で「上と下から同時に攻める」という方針を掲げ、そのうち下から攻める(既存のロジックの切り出し)の部分の改善をこの記事でご紹介していきます。

下から攻める

1. 外部ライブラリをComposer管理へ移行

JUGEMの既存のコードの問題として、ダウンロードしてきた外部ライブラリ(主にPEAR)があちこちに配置され、どこまでが自分たちのコードでどこまでがそうではないのか分からなくなっている問題がありました。まずは自分たちで管理すべきコードのみが残るように外部ライブラリを整理していきます。

こちらは全ての外部ライブラリを根こそぎ調査してバージョンの特定を行い、Composer管理へ移動できそうなら全て移動していきました。

move_external_libraries.png

こちらの内容はYAPC::Asia Hachioji 2016 mid in Shinagawaにて発表した資料がありますので、詳細はそちらをご覧いただければと思います。

2. 既存クラスの整理と移動

Laravelはデフォルトではappディレクトリ配下に全てのアプリケーションコードが配置されるようになっていて、このディレクトリ配下はPSR-4に従った作り方さえすれば自動的にオートローディング可能なように設定されています。そのためLaravelでは特にファイルの読み込み(require_once)など行わずとも目的のクラスを呼び出せるようになっています。こういった形式は昨今のPHP開発では一般的になってきていて、特定のディレクトリ配下にコードを集約し、そこをオートローディングによって手軽に呼び出せるようにしておいて、効率的なコーディングを可能にしています。JUGEMでもこういった状態を目指しました。

JUGEMの既存コードにはあちこちにクラスが書かれたPHPファイルが置かれていました。まず全てのクラスの置き場所を決め、そこへの一元化を目指しました。このディレクトリはLaravelでいうappディレクトリに相当します。内部のディレクトリ構造もなるべくLaravelに従った構造にしますが、元々Laravelのディレクトリ構造は柔軟なのでそれほど気にせず必要に応じて構造は変えています。

次にこのディレクトリ配下をオートローディングできるようにComposerのオートローダ生成機能を使います。Composerには自分たちのプロジェクトのオートローダを代わりに作ってくれる機能があり、そちらを使用します。既存のクラスはPSR-4のようなオートローディング規約に従っていませんが、それでもオートローディング可能にするclassmapというオプションがあるのでそれを使用します。もちろん可能ならPSR-0、PSR-4といったオートローディング規約に従った方が良いです。

これでこのディレクトリ配下に設置されたクラスはオートローディングが可能になります。次に既存のクラスをこのディレクトリへ少しずつ移動させていきます。ファイルの移動はPhpStormのリファクタリング機能を使うと非常に効率的です。移動によって発生する影響箇所の修正も自動的に行ってくれます。名前空間の移動や、あるいは名前空間がなかったクラスに追加する場合もとても賢く修正してくれます。

move_class.png

残念ながらPHPという言語の特性上、どうしてもPhpStormのリファクタリング機能には修正が漏れてしまうケースがなくもないのですが、PhpStormの癖をしっかり覚えればかなり安心して使うことが出来ると思います。リファクタリング機能には何度助けられたか分からないくらい助けられているので、あまり使っていない方は是非使ってみてください。動きの癖を知りたい方は以下の発表資料を見ていただくと参考になるかもしれません。結論だけ書いてしまえば変数の型推論に成功させてやれば概ね動いてくれます。

3. グローバルロジックからのパーツ化

既存のクラスが少しずつ整理できたら、次はグローバルスコープのロジックから少しずつロジックを切り出してパーツ化していきます。やはり今回の改善活動のメインとなる作業です。

とは言え、この節で語れることはあまりなく、気づいたときにその時の工数で出来る分だけ切り出しを行って、上記の一元化先ディレクトリへ配置していく作業を延々と続けていくことになります。現在でも続けていますが、まだまだ終わりが見えません。

パーツ化の過程でアプリケーション全体で供給したい仕組みが新しく必要になれば、その場でアプリケーションの初期化部分に追加することで実現します。

あえて気をつけることを語るならば、切り出す際は当然グローバルな情報に依存しない疎結合な状態を目指すこと、テストを書くことです。それをしないとやっている意味が薄れてしまいます。

part_logic_from_globals.png

まとめ

いかがだったでしょうか。JUGEMは長い歴史の中でメンテナンス上多くの問題を抱えているコード環境でした。その背景にはアプリケーションアーキテクチャが貧弱だったことがあり、そこへアーキテクチャをもたらすべく私が行ってきた改善活動をまとめてみました。

今回ご紹介した範囲は改善しようと思い立ってから 約1年半という期間 で実現してきた内容で、普段の開発と並行してかなりのローペースで進めています。それでも以前よりもはるかに効率的に開発ができている感触があります。既存の仕組みを安心して流用できる、関心の分離が実現できている環境は以前とは比べ物にならないほど効率よく新しい価値を生み出せています。またこういった開発効率の改善がまた次の改善へとつながり、良い循環が回っていると感じます。今回はまだ仕掛りの改善などもあり、そこについては特に触れていませんが、現在のアーキテクチャは概ね以下の図のような状態になっています。(点線部分はこれから作ろうとしている箇所)

今回私が選択した方針は、別に優れた方針ではないと思っています。改善スピードが遅ければ改善した箇所もまた陳腐化していきますし、仕掛りで中途半端な改善状況は新しく入ってくる人には苦痛でしょう。だからといってずっと既存のアーキテクチャを見直さなければ現在の問題は永遠に続いていくことになります。むしろ時間が立つたびより苦しみが増すと思います。きっと他の歴史あるサービスもアーキテクチャに何かしらの問題を抱えていると思いますが、そういった環境から脱出しない限りエンジニアにとってもサービスにとっても不幸な循環は回り続けます。時代の変化に耐えられなくなったアーキテクチャという根の深い問題と向き合う時どういった方針を選択したとしても苦しみは伴うもので、結局のところ一番大事なのは現場のエンジニアの熱意だと思っています。今回の内容が同じような問題を抱えていらっしゃる方にとって少しでも参考になるものがありましたら幸いです。

architecture.png