はいさい!オースティンやいびーん!
概要
今日の記事は、リファクタリングについてお話しします。
特に、エンジニアがなぜリファクタリングをしないのかについて触れたいです。なぜできないか、というべきでしょうか。
そして最後に、リファクタリングの文化を根付かせるためにどのような対策を取ればいいかの話題でまとめます。
背景
筆者が複数の日系企業で働いてきましたが、健全なリファクタリング文化を育んでいる会社は一社も出会っておりません。
リファクタリングをしないせいで身の回りの動きがどんどん取れなくなっていく、つまり開発の効率が悪化する一方で徐々にコードベースがわからなくなってくるという悪循環をいくつかのプロジェクトで見てきました。
なぜリファクタリングを敬遠するのか、どんな課題があるのか、ずっと疑問に思っています。
リファクタリングとは
リファクタリングは、ソースコードを見直して再編することです。つまり、以前書いて動いているソースコードを、動作を変えずに修正する、編集することです。
ソースコードを部屋に、プログラマーを住人に例えると、住人が自分の部屋で身動きが取れて気持ちよく生活できるように定期的に掃除をするのと全く同じことです。
部屋を片付けないと、臭いし、不快だし、暗い時にあれこれぶつかって転んで怪我するかもしれん。ソースコードをリファクタリングしないのはそれと一緒なのです。
リファクタリングの目的
リファクタリングは以下の目的で行われます。
- パフォーマンス向上
- 保守性を高める
- コード量を減らす
- コードの簡略化
- コードの可読性向上
- DRY(同じようなコードのコピぺをまとめる)
- 未到達コードの削除
- 拡張性を高める
リファクタリングの戦略パターン
リファクタリングといってもいくつかのパターンがあります。患者さんの症状によって処方が変わるのと同様に、ソースコードの状態によって部分的に掃除すればいいか、大掃除が必要かの判断も変わってくるのです。
抽出パターン
煩雑になっているコードを取り出して新しいメソッド・関数にまとめるパターンです。
あるある話で、関数名と実際にやっていることが全く合わないようになることがあるでしょう。
そうなった時に、やっぱりここのロジックは分けるべきだよねと思ったら、それは抽出パターンのリファクタリング。
このパターンの大きなメリットは、影響範囲を抑えながら、ソースコードの可読性を一気に高められることです。
変数名は非常に大事でdoStuff
というような変数名とcheckUserAgeInput
とuploadUserInput
を比較すると、コードを読む人に伝わる情報量が違うでしょう。
簡略化パターン
読者はみんなこんな経験があるのだと思います。
この部品は一体何をしているのだ
NewCompanyFormComponent
と名ばかりで、実際には、使われていないけど飼っている猫を登録するロジックまでなぜか入っているような部品。
ここで問わないといけないのは、ソースコードの妥当性ではなく、 この部品は本来、何をしているべきだろうか? ということです。
部品でなくともクラスでもそうです。
実際に担っている役割、担うべき役割を定めたら、要らないコードを裁けます。
簡略化パターンで大切なのは、リファクタリングをする人がソースコードがどうあるべきかの像をしっかりと頭の中に抑えていることです。
簡略化によって何百行も消えるようなPRを筆者は出したことが何回かあります。このコードは必要かどうか、本当にこんなに複雑でないといけないのか、リファクタリングをするものにはその判断が求められます。
部分的に簡略化する程度から、完全に部品・クラスごと作り替えるほどの変更まで、全部このパターンに入りますが、そのスペクトラムの中でどこまでリファクタリングするべきか、判断が非常に難しい。
以下の基準で判断します。
- ソースコードはどれほど重要?ほとんど使われていない画面か?
- テストケースは作れているのか?
- 影響範囲は把握できるのか?
プロの職人なら、部品をみて、一瞬でどこまでやるべきかの判断ができます。
抽象化・DRYパターン
コピぺプログラマーは世の中に存在します。
様々な理由でコピぺプログラミングは今もあるし明日も続きます。
コピぺプログラミングを、筆者も場合によってします。
ただ、コピぺプログラミングは非常にリスクが高いし、保守性の面で言うと自分の利き手の指を折るのと同じくらいの打撃になってきます。
コピぺしたコードにバグが見つかった場合、どうするかというと、ソースコード全部追って上書きするのです。
重大なバグが出た時に、すぐに直せないのはこのパターンの開発負債です。
ここで、責任ある職人なら、部屋を散らかしたことを忘れずに、期限が過ぎたあと、急いでコピぺしたところを抽象化したクラス、共有できる関数にまとめていきます。
これが抽象化・DRYパターンのリファクタリングです。
残念ながら、いつまでも「忙しすぎるから」という決まり文句で治らず、重大なバグが出てすぐに対応できない事故が起きるまで反省をしない人が多いと感じます。それでも反省しないプログラマーも、おそらく因果関係が繋がっていないのでしょうか。
事前・事後リファクタリングパターン
これは筆者が独自に作ったパターンです。
新機能開発で、古いソースコードをいじることがあるのですが、必要な変更を加えることが簡単にできるように、そこにあるコードのリアーキテクチャが必要な場合があります。
例えば、複数のモーダルをタブで制御していて、そのタブは全て条件分岐で表示するか否かを制御しているとしたら、そこにさらにタブと画面を三つ増やしたら、条件分岐が半端ないことになると知った時に、どうしますか?
事前リファクタリングの場合、ここでこのモジュールの設計を見直すべく、条件分岐で画面表示をしていたロジックを全部ルーターに持ってきて、パスを分けるようにする、と言う判断にたどり着くのかもしれません。そもそもモーダルで表示するべきでないとデザインチームと相談するかもしれません。
今後の開発がしやすいように、そこにあるものの設計を見直す、それが事前リファクタリングです。
事前リファクタリングの大きなメリットは、テストコストを増やさずに技術負債を新規開発とともに解消していけることです。また、工数見積もりにもりやすいです。「事前リファクタリングで3人日使ったら、実際の作業が5人日減る」と言うふうに説明すると、マネジメントも納得してくれます。
事前リファクタリングとセットでくるのは、事後リファクタリングです。
下記のTDDのリファクタリングフェーズと似ています。
新機能開発が終わった後、日を改めてそこで作ったものを見直して拡張性と保守性を意識した設計にすることです。
事後リファクタリングのコストは少ないけれど、効果は大きいし、職人として自分の作ったものを真剣に見直す習慣をつけるのが非常に役に立つと思います。
TDD(テスト駆動開発)
テスト駆動開発は、簡単にいうと、仕様を先に決めて、テストを作ってから実際の開発に入るという考え方です。
赤信号、青信号、リファクタリングという段階に開発を分けるのです。
赤信号フェーズは、先にテストを作るフェーズ。機能を実装していないので確実に失敗するから、「赤信号」と言われています。
青信号フェーズは、上記のテストが通るようにとりあえず開発するフェーズです。ここで設計は深く考えず、まず「できるか」で試行錯誤的に開発してもいいです。いわゆるプロトタイプを作るフェーズです。
リファクタリングフェーズは、テストを満たしながらも、新機能の拡張性、保守性を考えて設計を見直す段階。ここが非常に重要です。
多くの日系企業は青信号フェーズしかないと見受けています。
なぜリファクタリングをしないのか
ここまでリファクタリングについて紹介し、リファクタリングの戦略も紹介してきました。
部分的にリファクタリングするパターン、大幅な作り替えをするパターン、様々あります。メリットもいっぱいあります。
大体、慢性的にリファクタリングができていないコードベースは、以下のような症状を出しています。
- しょっちゅうバグが起きる
- バグ調査に時間がかかる
- 開発の効率が致命的に悪化している
- エンジニアの不満が続出
- パフォーマンスが悪い=UXが悪い
- 誰も直せないバグがある=バグ修正に思いの他時間がかかる
では、なぜリファクタリングをしない開発チームが世の中に溢れているのか?
以下の理由を思い付きます。
純粋に、そこまで興味がない
プログラマーはみんなそれぞれにレベルがあります。職人は自分で腕を鍛えていくのですが、どこまでいくのかというのは本人次第です。
いくら仕事でも、リファクタリング、可読性、コードの品質に純粋に興味がない人が中にいるのだと思います。
そのようなエンジニアはおそらく、プログラミングを愛していないのか、それか向上心が薄いかと思います。
こういうエンジニアは少ないと思いたいのですが、世の中には残念ながらいます。
ご満悦なエンジニアと言うべきでしょうか。
- これだけできているのだからいいだろう
- マネジメントに時間を与えてもらったからしょうがないだろう
- このライブラリーを入れたのは自分じゃないんだから
- 根本的に直すの、自分の仕事じゃないし
上記のようなコメントはああしてかくと格好悪く見えるけど、本気でそうと諦めている人の気持ちもわからなくもないです。
ただ、いつまでも自分の仕事とせず、他人任せでは、一人前の開発者にはなれないのでは、と思います。
リファクタリングについて単純に知らない
コンピューターサイエンス専門の人でも、リファクタリングについて学校で習った人がいるのでしょうか?
リファクタリングについて知る機会がなければ、その作業がもたらすメリットを思いつきもしないのかもしれません。
リファクタリングの文化を習慣づけるためには、研修がこの場合必要です。
変更したら壊れることを極端に恐れている
ここの枠に入るエンジニアは非常に多い。
大体、手動・自動テストのシステムがきちんとできていないことも多いです。
そもそも、変更したら壊れやすくなるほど脆くなっているのは、リファクタリングをしてこなかったからで、今更変更することを躊躇したら問題は治らないだろう、と言うのが正論です。
ただ、自身が持てない人には大胆なリファクタリングはできっこないです。
その気持ちもわからなくもないです。
今筆者が働いているプロジェクトは、恐ろしいバグを直すのが本当にしんどいほどストレスがかかります。
それを背負いたくないというのも人間かなと思います。
ただ、それでは前に進めません。
レグレッションを防ぐシステムがない
上記の問題につながるのですが、本来であれば、アプリケーションの品質を担保するためになんらかの制度がないといけないのですが、多くの場合、それがないのです。
そこで、エンジニアのコードレビュー、エンジニア個人の確認に頼ってしまう運営が出来上がっているのです。
その場合、リファクタリングをして壊したら、そのリファクタリングをしたエンジニア個人に岩のように重い責任が両肩にがっと乗ってしまうんです。
筆者も、自分がリファクタリングしたコードがバグを最近生んだので、本当に悲しいです。自分の責任に直結してしまうようになっているので、よくした部分よりはるかに評価が落ちます。嫌なことです。
エンジニアの技量が足りない
これは読むのが嫌な人もいるかと思いますが、アプリケーションを作り始めた時のシステム的欲求と、成長して拡張した後の欲求が変わります。
アプリケーションの成長で、簡単になっていくようなケースは存在しません。
当初のメンバーの技量が足りていたとしても、成長した後の今直面している問題に対して対抗できなくなっていることがあります。
リファクタリングどころか、バグフィックスも何も徐々にできなくなっていきます。
新しいアイデアで設計を見直して拡張性に耐えられるようにアプリケーションを改修する必要がありますが、そもそもこの問題を作ったチームにそんなことができるのでしょうか?
ここまでくると、本当に技量的に直せないという事実を認めざるを得ない時があります。
技量が足りていないことを認めないから、リファクタリングに前向きになれず、その妥当性も理解できないかと思います。
諦めているか
本当にソースコードを変えたい、よくしたいが、どこかで折れて諦めてしまった人もいるかと思います。
プライド
自分のコードをリファクタリングされたら、ちっとも面白くないと思います。
自分の非を認めるようなものです。
謙遜でオープンであるべきとよく言われますが、それが簡単ではないと、筆者も読者もお分かりでしょう。
指摘に寛容でない人がたくさんいるとなかなかリファクタリングしやすい空気が生まません。
保守の経験がない
もう一つのパターンとしてあるのは、長く一つのアプリケーションを保守した経験がない人です。
長らく一つのアプリケーションと付き合っていると、いやでもリファクタリングの必要性に気が付きます。
小さいプロトタイプに近いプロジェクトばかり手掛けている人なら、設計を見直す機会もなければ求められることもないでしょう。
また、長く運用しているプロジェクトでも、新規開発しかしないプログラマーもいます。
組織によっては新規開発とバグ修正のチームを分けていることがありますが、こういう制度だと保守性の悪いカードをばんないばんない出していても、臭い排気ガスを出している大型トラックの乗り手と同じようにその臭いを嗅ぐことなく突っ走り続けるでしょう。
そのような組織で働いていると、成長するきっかけはなかなか訪れないでしょう。
上司の理解がない
もう一つよく聞く話です。
経営側がリファクタリングをやらせてくれない
短期的に利益を出して成長最優先で開発を進めているからリファクタリングの工数を与えてもらえない、もしくはそもそも工数見積すらしておらずいつもギリギリで開発をしている、とか。
この意見に同情できなくもないですが、プログラマーを整備士に例えてみましょう。
整備士が車検をやっている時に、ブレーキの不具合に気づいたとします。
お客様にブレーキを修理すると言った時に、「いやいや、普通にブレーキ効いてるよ?安く済ましてくれ」と言われたら、整備士はどうするべきだと思いますか?
経営側に「ここをリファクタリングしないとこれが壊れる」と言った時に、「いや使えてるしそこは時間とお金の無駄、仕事しろ」と言われたら、あからさまに危険度が伝わっていないので 説得する 必要があります。
先ほどの整備士はどうしたと思いますか?「はいわかりました、直さずに安く車検を通します」とは絶対に言わないでしょう。そう言って通してしまい、重大事故が起きた時に「だってお客様はわかってくれんかったさ」と言ったところで責任を問われることには変わらないでしょう。
経営は重大事故が起きた時に「しょうがない、いつも急かしてて悪かったね」と言ってくれるほど甘いでしょうか。
自分が作ったコードは自分の責任。充分な工数を与えてもらえなかった時、危険度をめげずに説明したでしょうか?
仕様が定かでない
動作を変えずに行うことがリファクタリングの大前提です。
じゃあ、動作がそもそもバグっているのか、それで正しいのか、わからない。
ソースコードを読んでもメモがないしコードの可読性は100年も外で野晒しの新聞と同じ状態と一緒でわからない。
こうなることはしょっちゅうあります。
ここでエンジニア同士で仕様を議論すると拉致が開かない。
マネジメントに仕様がどうあるべきかをまとめてもらう必要があります。
しかし、それができていないところだと、リファクタリングもできないのです。
リファクタリングの文化を根付かせるためにはどうしたらいいか?
マネジメントと話すことかと思います。要するに、組織改革が必要なので、組織改革は一人の力では起こせません。
本当に組織を変えたいのであれば、影響力を持っている仲間を増やしていくしかないのです。
そこで、文化を変えたいあなたに求められるのは、
- 現実的な計画を作成すること
- 計画を実施した場合のメリットを説明すること
- 実施しなかった時のリスクを十分に理解してもらうこと
上記の三つかと思います。
マネジメントがむしろ、アプリケーションのバグと深刻さについて関心を持っているケースが多い。
彼らもアプリケーションが会社の財産であることを理解しているはずです。
アプリケーションの成長に連れて求められる開発の体制も変わるので、その変革を起こすべき時になったら、マネジメントは協力的になるかと思います。
マネジメントを味方につけてからは、他のエンジニアを巻き込んで、空気を変えていく動きを起こしていけばいいとも思います。
改革を起こすからには必ず反発を受けます。快く思わない人もいます。ただ、中には共感してくれる人もいるので、そこから徐々にやっていけばいいかと思います。
長い道のりですよ。筆者は応援しています。
味方が見つからない時は、退職した方がいい
そこまで会社のこと、自分の仕事のことを大切しているあなた。
周りから反発しかなく、アプリケーションをよくしたいという味方がどうしても現れなかった場合、どうしますか?
僕は、そのあなたを評価しない企業にそれ以上時間を無駄にするべきではないと思います。
その熱量、やる気を評価するところは必ずあるので、今問題を抱えている会社に解決する気がないことがわかったら、お別れの時かと思います。
いくら一人で吠えても、孤立するばかりです。それは正しくないことだと思います。
まとめ
いいアプリケーションを作るためにはいい開発文化が必要です。
変化は、マイケルジャクソンが言うように、鏡に写っている自分から始めるものです。
自分の書くコードに求める品質を高めれば、人は気付きます。嫌がる人もいます。
でも、リファクタリングの習慣をつければ確実により強い職人になります。
そこに尽きるかと思います。
リファクタリング運動を広めてうまく行った人、うまくいかなかった人、ぜひコメントにてお話をお聞かせください!