目次
■ソフトウェア設計とメンテナンス
2023.08.18 2024.03.05 約4分
この記事は、2023年8月24日開催のオフラインイベント 『ミノ駆動さんと語るエンジニア怪談〜技術的負債の呪いにどう立ち向かうのか』をレポート化したものです。 |
本日は三体の怨霊を連れて参りました。これから架空の人物の会話形式でお届けしますが、技術的負債は霊の仕業であり、人が悪いわけではありません。貶める意図はないのであしからず……。
まずはこちらの会話をご覧ください。
Aさん:既存のOOManagerクラスに新機能のロジックを書いておきました。
ぼく:ち、ちょっと。新機能なのにクラス追加しないんですか!? Bさん:え…クラス追加ですか?クラスって追加していいもんなんですか? Cさん:新しくクラスって要る?動くもの書けてるんだからそれでいいじゃん Dさん:クラス分けると一気に読み流せなくなるから俺はやらない(ドヤ顔 |
クラス追加を拒んだり恐れたりする霊、それが「クラス追加拒絶霊」です。
霊の性格はさまざま。
|
僕は「クラスを追加することに、何かよく分からない不安感や罪悪感を覚える」タイプの霊によく遭遇します。
重要なのは、カプセル化です。カプセル化は、データとそれに関わる処理を一緒にまとめて秘匿し、外部からは正しい操作方法(メソッド)だけを使えるようにする考え方です。これを怠ると「低機集」と呼ばれる問題が生じます。関連する処理が散乱し、追跡が難しくなります。つまり、影響範囲を調べるために必要な労力が増えてしまうのです。また、秘匿しないままだと、無断で変更されたり意図しない変更が加えられたりして、バグの可能性が高まります。カプセル化を考慮しない実装は、これらの問題を引き起こす結果につながります。クラスは、カプセル化を実現するための手段の一つです。こうした「クラス追加拒絶霊」が集まり出すと、神クラスが生み出されます。
神クラスの正体はカプセル化が崩壊した世界。通常、クラスは自身のメンバを知り、操作できますが、神クラスは巨大過ぎて自身のメンバがグローバルな特性を持つようになります。「グローバル変数は作っていない」と主張する人でも、実際には作っているようなもの。神クラスのメソッドは、グローバルなメソッドのような振る舞いをすることが多いです。あらゆる部分からアクセスできるため、カプセル化を無視した場合に起こる問題が発生しやすくなります。
「クラス追加拒絶霊」を除霊するためには、カプセル化の意義も含めてメンバーの設計スキル向上が肝要です。これは本を読んだだけでは絶対に身に付きません。実際に手を動かし訓練しましょう。かとじゅんさん、増田さんのような有識者が仰るように、手を動かすことでスキルアップに繋がります。
「カプセル化」の概念や言葉が通じない人には代わりに「セキュア設計」の観点で説明してみると良いでしょう。たとえば、カプセル化を使わずに外部から完全なアクセスができ、何でも自由に操作できる構造は、大切な情報を誰でも触れてしまったり、誰でも変更できたりする状態と同じです。みなさん Webサービスのセキュリティには気を使っているのに、アプリケーション内でどのデータをどのクラスがアクセスできるかについてあまり気を配っていないように思えることがあります。クラスを家に例えてみましょう。クラス内のデータと操作に対するアプローチは、家のセキュリティ対策に似ています。玄関を施錠したりドアホンを付けることと同じように、カプセル化はクラス内のデータや操作を外部から保護するための方法なんです。
それでも除霊できない場合もあるんですよね。
本人に成長する意欲のない場合は学習コストをかけても徒労に終わります。基本的に除霊不能ですが、封じることもできます。(まとめにて記述)
続いてこちらの会話をご覧ください。
Aさん:この追加仕様、どうやって実装する?
Bさん:どれどれ。あー、それは(既存の)この〇〇メソッド内でフラグを生やして分岐で切り替えるだけでいけるっしょ。 Cさん:あと、流用できそうなメソッド見つけたよ。仕様通りに動くように呼び出してパパっと実装終わらせようぜ。 |
ありあわせのロジックの流用や改造で動くものを作る霊、それが「流用霊」です。
既存ロジックにフラグと条件分岐を埋め込むことや「流用・応用・再利用」という言葉を非常に好んで話します。使えそうなロジックをgrepする能力に異常に長けているので、grep能力がさらに先鋭化すると、ネット上で使えそうなサンプルコードを見つけ、サンプルのコピペと継ぎ接ぎで動くものを作る「コピペ霊」に変化するケースも。
DRY原則のよくある誤解を例に見てみましょう。
あるECサイトがあります。通常割引価格を5%、夏季割引価格を5%に設定する際、「どちらも同じ5%だから、DRY原則を用いて再利用する」と、どうなるでしょうか。あとで 通常割引価格を5% から 3% に変更する際、割引価格のパーセンテージを共通化しているせいで、夏季割引価格も3%になってしまいます。
このように「割引率」が多目的に使われてしまうと、一方の仕様変更が別目的の仕様に影響を及ぼしてしまうわけです。本当に本当に誤解が多いのですが、DRY原則は、コードの重複を許さないのではなく、意図や目的の重複を許さない原則なのです。
僕は、単一責任原則とは、単一目的原則だと考えています。
通常、何かしらのフレームワークの上にアプリケーションを開発していきますが、アプリというのは目的特化のため、再利用できるものほとんどありません。共通化できるものは目的が同じロジックのみ。無理に共通化しようとすると爆発します。一方、フレームワークは極めて汎用的な要素が求められるため、しっかり再利用性を追いかけましょう。
もし「流用しよう」「再利用しよう」という声が聞こえてきても、それは流用霊の声です。惑わされぬようお気を付けください。開発対象がフレームワークならば、再利用性を追いかけてもOKですが、それ以外のアプリなどは基本的にNGだと覚えておきましょう。
こちらの会話をご覧ください。
Aさん:デザインパターンとか、書籍『リファクタリング』の方法でリファクタしてみたんだけど……
Bさん:どうした? Aさん:なんか逆に余計に複雑になっちゃった感じでさ。やった意味があったのか疑問で。 Bさん:偉い人が書いた本でも実務に使えないことはよくあるからね。うちらの開発には合わないんだよ。 Aさん:そっか、そうだよね。やめた方がいいかも。 |
設計やリファクタリングに興味を持ち始め、取り組んではみたものの、上手くいかず挫折してしまう霊、それが「挫折霊」です。「どうせ上手くいかない」「うちらには合わない」と囁き、挫折させてしまう霊も当てはまります。
|
まずは「変更容易性の高い構造」を知ることが大切。これを知らないと、負債もゴールも認知不能です。
|
挫折霊の除霊方法としておすすめなのは、手段に対応する目的がたったひとつになるよう設計することです。
例えば、ドライヤーは髪を乾かす目的のための手段です。自動車は目的地に早く移動するための手段です。つまり手段は目的によって作り出されます。目的はひとつです。
ダメな例は目的がいくつもあること。例えば電子レンジは食べ物を温めることが目的であって、猫を乾かすためのものではありません。
例えば、ECサイトの大きな目的は「商品売買」ですが、実はもっと細かく中目的に分解することができます。
たくさんある目的に対し、たった一つの商品モデルで対応しようとすると、モデルが巨大化かつ複雑化してしまいます。
これを解決するためには目的ごとに必要な解決要素を作りましょう。各目的に対応する特化型のモデルを作ることが大切です。
その手段は、どの目的を実現させるための手段なのかを考える。もし複数の目的であれば、それを分解する。それぞれ目的がたった一つになるようにし、それを設計やリファクタリングのゴールとして設定することが大事です。
ここまで三体の怨霊を紹介しましたが、怨霊の正体は「学習コスト」だと考えています。負債は当たり前に積み上がっていくもの。問題はそれが解消されないことです。
|
このように設計そのものの知識がなければ、重要性が理解できず、危険な状態を生んでしまいます。これを解決するためには、設計に関する学習コストを軸に開発戦略を組み立てることが重要です。そして重要なスポットには設計を積極的に行う人をアサインし、品質を求めるスポットとは別の箇所には学習コストが高い人をアサインすることが必要です。アーキテクチャレベルで設計を行い、重要なスポットとは分離して隔離することで、悪いコードの影響を最小限に抑えることが重要です。
『良いコード/悪いコードで学ぶ設計入門』ITエンジニア本大賞2023 大賞受賞
登壇及び受賞多数
|
「ミノ駆動と語るエンジニア怪談」ではミノ駆動さんへ直接質問することも可能です。イベント前に技術的負債について復習しておきましょう!
『良いコード/悪いコードで学ぶ設計入門』は、優れたコードを書き、開発力を向上させるためのベストセラーの設計入門書です。技術的負債の構造はどれも基本的には同じであり、変更容易性を重視した設計によって負債を克服することができます。安全に変更可能なクラス構造の方法を詳しく知りたい初級〜中級者の方向けです。 |
こちらも「変更容易性」にフォーカスした記事。「良い設計」が大切であることは理解できたけど、どう習得するの?という疑問にこたえます。コードの不吉な臭い(設計の良し悪し)を判断できる嗅覚を身に付けましょう。 |
エンジニアが直面する分岐の複雑化に対処するためには、interfaceの効果的な使用と発想の転換が必要です。本講演は、架空の防犯システム設計を事例に防犯システム設計を用いて interfaceの使用方法を紹介します。 |
スタートアップに入社や転職をして「なぜ対策しなかった?」「コードが酷すぎて読めない」と心の中に秘め、吐き出せない気持ちを抱えているエンジニアの方へ。技術的負債に対峙した場合、どうしたらよいか、CTO のめもりーさんがお答えします。スタートアップの経営学をさくっと知りたい方にもおすすめです。 |
なぜレガシーコードを許容してまでプロダクトを作るのか、エンジニアリングを進めるのか疑問に感じることも多いのではないでしょうか。本記事はレガシーコードや技術的負債が生まれる理由から、技術的負債を改善するために経営層に掛け合う方法を紹介しています。 |