バイバイレガシー
2018年現在、まだまだレガシーコードに苦しんでいる現場が多いと思います。しかし、それをなんとかリファクタリングやマイグレーションしたいと思っている会社やエンジニアも多いはずです。
それをなんとかしよう!予算も人も確保ができた!となったとき、読んでもらいたい事をまとめてみます。個人的な僕の経験で、という注釈が付きますが、いくつかのプロジェクトで成功した一つの事例を紹介します。
Laravelは魔法のステッキではない
どうやらLaravelっていうのがいいらしいぞ!とフレームワーク選定してみたはいいけど、それだけではレガシーな技術的負債が解決されていくわけではありません。Dependency InjectionやTDD、DDDのレイヤードアーキテクチャ、リポジトリパターンなど、メンテナンス性にすぐれ、リグレッションも起きづらく、疎結合で読みやすいシステムを作る手法はたくさんありますが、それらがすべてLaravelを使うことでまるで魔法のように実現でき、解決できるわけではないです。
街をクールにドライブするのに、モダンなスポーツカーを買って運転しても、乗っている人がひげもじゃ&髪ボーボー、よれよれのランニングシャツにモモヒキならちっともクールではないのです。
いざ、脱却手順
では、Laravelを採用してレガシーから脱却するためにすることを説明していきます。
Readable codeを読む
もう手垢のついた説明でしょうが、リーダブルコードはやはり良書です。Laravel本家のTOPにもあるように、Laravelも「美しいコード」にはこだわって書かれています。
読むだけではなくプロジェクトの標準コーディング規約として取り入れてもいいと思います。
PHPStormを入れる
EclipseもVimもいいエディタです。しかし、PHP書くならPHPStormの採用を強く進めます。利点はいくつもありますが、個人的にはメソッドファンクションの呼び出し元へJUMPできることでLaravelのコアの部分まで潜っていきやすく、より理解が深めやすいことをあげます。
PHPStormで設定してほしいこと
PHP CodeSniffer / PHP MessDetectorは必需品です。
コーディング基準として、今後PHPは PSR1 / PSR2に沿って書くのがいいでしょう。上記2ツールは「基準に沿っているか」のチェックをリアルタイムで行い、エディタ上に警告を出してくれます。(まぁ、PHPStormのフォーマッタを使えば、自動で基準にあわせた変換をしてくれます。)
newを禁止する
Dependency Injectionについて教育するコストを考えたら、とりあえず「このプロジェクトではnew禁止です」って言っちゃうことでいろいろ解決します。
「どうやってインスタンス作るんですか」となるので、コンストラクタインジェクションの書き方を共有します。習うより慣れろ、じゃないですけど、これでひとまず疎結合になります。イコール、モックを使ったテストが書けるようになりました。
Facadeも禁止する
Laravelの特徴として上げる方も多いFacade、依存性の注入もでき、動的ファンクションを静的呼び出しのように呼べるすぐれものですが、一旦禁止しちゃいます。
Dependency Injectionの理解もなくFacadeを見たとき、一見static関数かな?と思うでしょう。実際僕のいた現場で、理解されないまま「Facadeを使ってます」とstatic functionを見せられたことがありました。
また、レイヤードアーキテクチャを徹底させたいからでもあります。
どこでもnewできなくなり、Facadeも使えない。インスタンスはコンストラクタでインジェクションするしかない。
今までどおり、コントローラとかモデルでなんでもしちゃうようなコードを書こうとすると、あっという間にコンストラクタがどえらいことになってしまい、Pull Requestで容易に見つけられます。
まぁ、Logファサードくらいは許容してもいいのかな、と思います。
インラインコメントを禁止する
コメントを打ちたくなったら別メソッドにする季節、を徹底させるためです。PHPDocで十分理解できる程度の大きさで書くべきです。
というか、よく見かける書いてあることをそのまま日本語でかいちゃうやーつ
// 計算する
$result = $this->calculate($price);
みたいなコメントは、Readableに書かれていればそもそも必要がありません。
型宣言(タイプヒント)を記述する
newできなくなったことで、必然的にコンストラクタでは型宣言を記述するはずです。コンストラクタだけではなく、各メソッドの引数にも型を指定するクセをこの際つけるといいと思います。
PHPUnitテストを書く
これが一番インパクトが大きいと思います。エンジニアはもちろん、プロダクトや管理部門からも「その工数がもったいない」「コストがない」という話があがるかもしれません。
でも、そんなもん__「うるせー」です。
僕らの作っているシステムはwebシステムです。リリースしてからどんどん成長していくシステムで、成長とともにデグレの率があがり、テスト工数もかかるって意味がわかりません。
今のコストと工数と、あとから指数関数的にふくれあがるコストと工数と「危険性」__。
天秤にかけるまでもないです。
エンジニアも、
- レイヤーわけされていて
- 1メソッドがひと目で分かるくらい短い
PHPUnitなら書きやすいと思います。
- newをつかわず、疎結合な実装
になっているので、mockeryでモックも作りやすく、レイヤー単位でテストが記述できます。
終わりに
結構ドラスティックな制約ですが、TDDとはー!DIとはー!と言う前にこれらの事をまず徹底してやってみることをおすすめします。自然にQiitaや各種勉強会などで語られているモダンな設計・実装に近づくことができるのではないかな、と思います。
僕の経験では、このベースが浸透したあかつきに、「なぜ?」をきちんと理解していくというプロセスを持ち、最終的にそれこそTDDであったり、抽象化クラスのDIでリポジトリパターンを実装したりにつなげていけました。
最後になりますが、もちろんこれがベストプラクティスではないし、もっと別のアプローチもあると思います。あくまで一例として参考にしていただければ幸いです。