はじめに
この記事は 食べログアドベントカレンダー2024 の19日目の記事です🎅🎄
こんにちは。食べログ開発本部 ウェブ開発1部の相馬です。新卒で入社してから今年で2年目になります。
入社してチームに配属されてからは、システムの細かい改修や問い合わせがあった機能の調査をしていました。ここ最近、システムの移行作業やPoC用のテスト画面の作成といった、配属直後よりも規模が少し大きい案件を担当するようになりました。
そのような状況で、私自身の課題として浮き彫りになったのが「設計」です。設計は、エンジニアとして活躍するために必要なスキルの1つであることは皆さんもご存じでしょう。この記事では、設計の重要性や良い設計がもたらすメリットについて私の体験を通じてお伝えします。
それは設計ではないと知る
私が設計の重要性に気づいたのは、テスト画面を作成していたときです。この画面は「入力 -> 認証 -> 確認 -> 登録 -> 完了」と進むものでした。研修以来のゼロベースの開発に「よっしゃ!やってやるぞ!」と意気込んで実装を進め、動作確認も完了したので、チームに自信満々でコードを見せました。
しかし、返ってきたのは「直しましょう」という言葉と、数時間の会議室予約の通知でした。
会議室ではホワイトボードを使って図を用いながら、私がどのような意図でコードを書いたのかを説明しました。「入力画面のアクションがこれで〜」「パラメータを渡すために〇〇メソッドが必要で〜」などと話しました。しかし、チームメンバーから「それで設計は?」と質問され、私は内心で『今話していたことが設計ではないのか?』と戸惑いました。そんな私に、メンバーが設計について教えてくれました。
設計を知る
何をしたくて作るのか
「今回の画面は何のために作るのか?」と問われ、私は「入力フォームで〇〇を選択してもらって、確認した後に登録して…」と長々と答えました。しかし、結論は「ユーザーに入力してもらった情報を登録して保持すること」とシンプルなものでした。それだけ?と驚きましたが、実際にやりたいことはそれだけでした。
「何をしたいのか(要望)」を把握できていない状態で作るのはコードを書くというよりもモノを作るということにおいて不足していてはいけないことでした。 要望を認識せずして、要望を満たしたものなんて作れるはずがなかったのです。
要望を叶えるためには何が必要なのか
要望を把握したら、それを実現するためにどんな業務が必要なのか問われました。業務の例としては、「利用できるユーザーの判定」「情報の入力」「入力内容の成否判定」などがあります。これらを細分化し、「入力内容の表示」や「利用できるユーザーの判定」を深掘りしました。
入力内容の表示
- 入力された内容の保持
- ユーザーに見やすいフォーマットへの変換
利用できるユーザーの判定
- ログイン状態の確認
- アカウント設定の確認
- 利用可能なユーザーとしての登録確認
洗い出してみると「当たり前」と感じることばかりでしたが、次のステップで自分のコードが設計できていなかったことに気付きました。
役割分担
洗い出した業務を「アカウント情報」「入力データ」「登録処理」などにグループ化し、model, controller, view, usecaseに割り当てました。例えば、登録する処理はmodelへ、画面遷移に関連した処理はcontrollerへといった具合です。これにより、どこにどのメソッドを配置するかが見えてきました。しかし、実際のコードと比較すると配置が全く異なっており、設計の根本的な理解不足を痛感しました。
悲しみのリストラクチャリング
私の実装は、動作するだけのコードであることが発覚し、見直されることになりました。それも単なるコードのリファクタリング(整理)ではなく、リストラクチャリング(再構築)が必要でした。結果的に、チームメンバーがコードを修正してくれましたが、その間に自分のコードを改めて見返しました。
私の実装には、やたらと多くのことを行うメソッド、処理が肥大化しているコントローラーのアクション、様々な箇所で行われているsave、他のクラスを頻繁に呼び出すユースケースなど、問題点が次々と浮き彫りになりました。
業務の洗い出しをした際、「当たり前のこと」と感じていた内容が、実際には役割分担ができていないためにどのファイルやメソッドがどんな役割を持っているのかが混乱している状態でした。
別人のようになったコードとの再会
チームメンバーが再構築したコードは、自分が実装していた面影が残りつつ以前とはまるで別物になっていました。
処理が簡潔になったメソッド、すっきりとしたコントローラーのアクション、モデルにまとめられた登録処理、そして適切にクラスを呼び出しているユースケースなど、見やすく整ったコードに感動しました。うまく表現できませんが、そのコードは非常に落ち着いているように感じました。
設計ができているとこんなに綺麗なコードになるのかと感じつつも、私はまだ良い設計の凄さを実感できていませんでした。
訪れた素敵な仕様変更
再構築が完了した直後に、テスト画面の仕様変更依頼がありました。もともと「入力 -> 認証 -> 確認 -> 登録 -> 完了」だった画面遷移を「入力 -> 確認 -> 認証 -> 登録 -> 完了」に変更するという内容です。最初に依頼内容を見たときは、「画面移動には多くの処理を移動する必要があって大変そうだ」と気が重くなりました。実際、チームメンバーも少し時間がかかりそうだと感じていました。
せっかく綺麗に再構築してもらったコードを壊さないように、各ファイルやメソッドの役割を把握し、修正後も役割分担が保たれるようにどう修正するかを考え始めました。
すると、あることに気づきました。「あれ?このファイルにあるこの辺のメソッドをこっちに移動するだけじゃん」と。そんな簡単なことがあるのかと疑いながらコードを何度も確認しましたが、本当に数個のメソッドを移動するだけで対応できるようでした。実際に修正してみると、あら不思議、実装と簡単な動作確認までが30分で完了しました。最初に想定した時間よりも大幅に短く作業が終わりました。
この経験を通じて、設計がしっかりしていることの素晴らしさを実感しました。短時間で仕様変更に対応できること、しかもほぼ他の人が作ったコードで可能であること。これが良い設計なのかと、脳裏に電流が走ったように感じました。もし自分が作ったコードのままだったらここまで簡単に対応できなかったでしょう。
教訓と今後の展望
教訓
一連の体験を通じて、自分が設計を全くできていなかったこと、そしてしっかりとした設計がどれほどありがたいかを実感しました。特に、役割分担の重要性を強く感じました。もちろん、根本的な要望やそれを満たすための業務を考えることも不可欠です。しかし、「このファイルはどういう処理をまとめたものなのか」「このメソッドは何をしているのか」が明確だったからこそ、素早く仕様変更に対応できました。
今回の経験はテスト画面でのことでしたが、もっと大きなシステムでファイルやメソッドが多数ある場合、「設計ができている」ということはさらに大きな価値を持ちます。修正箇所の特定や修正作業が迅速に終わる設計は運用・保守に優れており、エンジニアにとって安心できるシステムになると私は考えています。修正作業が早く終わるというのは実装についてだけでなく、テストも含まれています。再構築後に実装した画面の全体のテスト設計をしていると、各リクエストやメソッドに対してのテストケースはそれほど多くないことに気がつきました。最初に自分が書いたコードでテストしようとすると、テストケースが10個以上増える場合がありました。設計ができていると、実装だけでなくその後のテストまで楽にできてしまいます。
また、設計において要望の把握や業務の洗い出しを行いましたが、シンプルな答えが出せないときは目的が定まっていないか、前の段階が間違っている可能性があると学びました。実装があやふやであれば設計ができていない証拠であり、設計が不十分な場合は要望の把握や作業の洗い出しが不十分であることが考えられます。メソッドが多くの処理をしているときは、メソッドの役割が具体的に決まっていないからです。「これはどうして?」「これは何?」と問われたときにシンプルに説明できるように考える必要があると学びました。
今後の展望
今回、要望の把握や業務の洗い出し、役割分担といった内容に取り組みましたが、これらは設計の一部に過ぎません。良い設計をするためには、まだ多くの要素が必要です。それでも、今回の経験は良い設計に向けた第一歩となったと感じています。この経験を通じて、設計を意識するようになりました。
「このメソッド名は具体性がない」と感じたときに、「やろうとしていること」や「役割分担」を見直すことができるようになったのもこれまでの取り組みのおかげです。
今回の経験を通じて、次に何に注力すべきかが明確になったことは大きな利点でした。それまでは、自分にはエンジニアとして不足している点が多いと感じていましたが、具体的にどうすればよいのかが不明瞭な状態でした。しかし今では、役割分担された設計ができるようになるという具体的な目標を持つことができました。もちろん、役割分担された設計をするためには、要望の把握や業務の洗い出しが必要です。今回の経験は、自分が考える良い設計とは何か、どうすれば役割分担された設計ができるのか、と考える機会になり、エンジニアとして成長する足がかりになったと感じています。
私の上司から「特定のスキルを習得するためには、おおよそ1,000時間の練習が必要である」という話を聞きました。「1,000時間の法則」と言われているようですが、そう考えるとまだまだ道は長いですね。
まだ良い設計はできませんが、私の設計したコードが私のように素晴らしい設計と仕様変更に出会う誰かの助けとなるように、努力を続けていきたいです。
まとめ
- 要望の把握や業務の洗い出しが設計の基盤となる
- 役割分担が明確な設計は、迅速な仕様変更や保守性の向上に直結する
- 設計がしっかりしていると、他者のコードでも対応が容易になる
- 動作するだけのコードではなく、目的に沿った設計が必要
- 設計について最低1,000時間考えろ
さいごに
設計ができるようになるためには学び考え続ける必要がありますが、最初から1人で設計ができる人はいません。私はチームのメンバーに相談することもありますが、最近はAIにも相談しています。「こんな感じの設計を考えているが、もっと良い案はあるか」「こういったものは一般的か」といったざっくりとした設計について確認したり、〇〇の考えをまとめるのに適した図の表現はないかを尋ねたりします。コードを書く時にもAIに聞いて解決することがあり、とても助かっています。便利なものはどんどん活用し、時代に合ったエンジニアになっていきたいです。そのためにも、まずは設計について学んでいきます。
明日は@takayukiさんの「Sansanさんとの合同勉強会の報告」です。ぜひご覧ください。