PHPで不要なソースコードを取り除く時の4つの心得

この記事はPHP Advent Calendar 2017 20日目の記事です
記事中のキーボードショートカットはMacのPhpStormのものです

そもそもどういう経緯でソースコードを取り除かなければならない状態が起こるのか

  • どんな会社でもメンバーが変わったり、昔関わっていたメンバーが会社を去っていたり、新チーム・新部署・新事業の立ち上げなどによってそのリポジトリやその範囲のソースコードに関わるメンバーの変更があったりするかと思います
  • そうすると、「長い間同じ人が同じリポジトリや同じ範囲で責任を持って開発を続ける」ことが出来なくなってしまうケースもあるかと思われます
  • その結果として、現在では使われていないソースコードや周りから浮いてしまっているコード、よくわからない仕様などが残されてしまっている、などという状況が起こり得ます
    • そもそもそういう状況が起きないことが理想ではありますが、事業展開・戦略上仕方がない部分が出てくるのは事業をやっている上で当然出てくることであり、その状況を解決するというアプローチは今回はやめておきましょう

何故私たちはソースコードを取り除かなければならないのか

  • ソフトウェアエンジニアの仕事はソフトウェアを開発することかと思います、新機能の追加、従来からある機能の改修などが多いことでしょう
  • しかし、ソフトウェアとは現実の状況・条件・要望を反映し、変化し続けるもの、という前提があるかと思います、その前提の通り、時には古くなったり不要になったソースコードを取り除くことが必要となる場面も出てくると思います
  • 自分はここ数ヶ月そのような状況に多く遭遇し、スキマ時間を使って多くのソースコードを取り除いてきました

それでは実際に自分がソースコードを取り除く時に気をつけていることを以下に書いていこうと思います

PHPで不要なソースコードを取り除く時の4つの心得

1. IDEを使う

  • IDE(IntelliJ, PhpStormなど)を絶対に使いましょう
    • IDEの静的解析が強力にサポートしてくれます
      • 何かミスがあればすぐにwarningが出てきます
    • IDEなしでコードの取り除きはかなりリスクがあることだと考えます
    • IDEの使い方はこの記事では詳細には述べません

2. grep (全文検索)を使う

  • case 1
    • 消す対象のソースコードに含まれるfunction名や定数が使われている場所を把握します
      • 「command + B」で、そのfunctionや定数が使われている場所の一覧が出てきます
        • 使われている場所が大量に出てくるようであれば、恐らくそれは消すべきソースコードではないでしょう(消せるケースもあるでしょう)
      • また、functionはそのfunction名で必ずgrepし直しましょう、文字列でfunction名を定義して call_user_func などに渡して使われているケースがあります
        • このstringは前述した機能では出てこないと思われます(間違っているかも)
        • このPHPの仕様は個人的に最悪です、関数名を文字列で宣言してその関数をcall出来るのか意味がわかりません…(言い過ぎ
  • case 2

    • 例えば一旦取り除いたソースコードにmailのテンプレートのincludeをしている箇所があるとします
      • $this->getEmailTemplate("mail/2017/hogehoge_mail_temp.txt"); みたいな
    • このよう場合、頑張って「mail/2017/hogehoge_mail_temp.txt」も取り除きます
      • 「command + shift + O」でファイル検索の欄が出てきます
        • ファイル名のpathをコピペで入力してEnterを押せばそのファイルが出てきます
      • ディレクトリツリーの右上にある歯車をクリックし、「Autoscroll from Source」にチェックを入れておけば、開いているファイルに追従してディレクトリツリー側でもファイルにフォーカスが当たるので、あとは削除するだけです
        • Screen Shot 2017-12-08 at 13.09.57.png
  • case 3

    • namespaceで検索かける
      • あるクラスをファイルごと削除した時などに有効に働きます
        • PHPのnamespaceは\である程度の一意性を担保してくれているので、grepする時は便利です
      • 取り除いたnamespaceのクラスを使っている箇所が残っているかもしれません
    • 例えば Application\Hoge\Fuga\Hogehoge; というnamespaceを持ったclassを取り除く時は \Hoge\Fuga\\Fuga\ などでgrepすると良いでしょう

3. testも取り除く

  • 実装が取り除かれれば同時にtestも取り除かれなければなりません
    • この時、「ある実装を削除するとある実装を対象にしたテストが通らなくなる」という状況が起こるのが理想です
    • test failが起こらないのであれば、テストが上手く書けていないということになります(普通にテストを書いていればそんなことはあんまりないとは思いますが…)

4. 何故そのコードを取り除くのか?を記録する

  • 簡単でもいいので必ず取り除く理由を記録しましょう
  • 実装が行われたPRへのリンクを、ソースコード取り除きPRに貼りましょう
    • 後に、「この実装は何故取り除かれたのか」ということを調べる人が出てくるかもしれません、それは他人かもしれませんし数年後の自分かもしれません
    • 実装当時のドキュメントへのリンクなどをdescriptionなどに記載しておくといいと思います
    • 詳細な記述までしなくても大丈夫です、その先のドキュメントを頑張って調べるのは、「何故実装が取り除かれたのかを調べている人」の責務かと思います

実装の経緯を調べる時に便利な方法

  • 誰がいつこの行を編集したかが見たい場合
    • 行数が表示されている場所で、右クリック→「Annotate」を選択します
    • 誰がいつこの行をcommitしたかがサクッと表示されます

Screen Shot 2017-12-02 at 21.57.31.png

Screen Shot 2017-12-02 at 21.57.36.png

  • その行がmergeされたPRが見たい場合
    • shift2回→「github」とタイプし、「Open On GitHub」を選択するとGitHubが開きます
    • 開いたページの右上にあるBlameボタンを押すとcommitへのリンクが出てくるので、それをクリック
    • commitログの「#xxx」の部分をクリックします
    • commitがどのPRでmergeされたかのページに辿り着けます

Screen Shot 2017-12-02 at 21.45.59.png

Screen Shot 2017-12-02 at 22.53.06.png

Screen Shot 2017-12-02 at 21.49.00.png

Screen Shot 2017-12-02 at 21.49.08.png

Screen Shot 2017-12-02 at 21.49.23.png

コードを取り除くことを続けて

  • 実装とrefactoringが同時に出来る感性が磨かれます
  • 「新しい機能を追加するPRなのに、new linesよりdelete linesの方が多い」というPRを立てることが出来るようになります
    • こういうPR立てることが出来ると単純にかっこいいと思います
    • かっこいいと思ってやってます、自尊心は大事です

自分が過去にソースコードを取り除いたPRを参考までに

  • 会社のソースコードである関係上、行数だけですが…
    • Screen Shot 2017-12-02 at 22.18.59.png
    • Screen Shot 2017-12-02 at 22.19.16.png
    • Screen Shot 2017-12-02 at 22.17.27.png
    • Screen Shot 2017-12-02 at 22.18.01.png
    • Screen Shot 2017-12-02 at 22.18.25.png
  • 以下は「新機能実装時のPR」になります、かっこいい!!!(自尊心は大事です)
    • Screen Shot 2017-12-02 at 22.21.20.png

最後に

  • 自分は不要ソースコードの取り除きを「未来への投資」とも考えています、未来でjoinするメンバーが混乱しないこと、未来の自分が大量のソースコードを前に困ってしまわないこと、それらを実現するために今のうちからコツコツ取り除きを進めています
  • これらの考え方は以下のblogに影響されているのでもしよければ読んでみてください
  • 「自分はこうして取り除いています!」などの知見があればコメント欄へ投稿いただけると大変助かります
  • 自分はPHPをメインで扱っているためPHPアドベントカレンダーへの投稿になりましたが特にPHPに限った記事でもないかと思います
    • 丹念に調べ、テストでその取り除きを保証する、というごく単純な行為です
    • PHPでは特にstringで定義した関数名がcall出来るという点が一番気をつける点かと思います
  • スキマ時間を有効に使って、現在の仕様に対して必要十分なソースコードにしていきましょう