ロコガイド テックブログ

「地域のくらしを、かしこく、たのしく」する、株式会社ロコガイドの社員がいろいろな記事を書いています。

「地域のくらしを、かしこく、たのしく」する、株式会社ロコガイドの社員がいろいろな記事を書いています。

技術的負債に立ち向かう ②ドキュメント編

f:id:ar_tama:20210422113054p:plain

こんにちは!RDCやFFKTの開催が楽しみで仕方ない@ar_tamaです。
前回の実装編に続き、開発者なら一度は直面したことのある「コードの技術的負債化」への考察を、今回は「ドキュメント」の観点から行います。

負債は生まれるべくして生まれる

どんなコードが負債の原因たるのかについては前回例示したとおりですが、それに該当せずとも「負債」が生まれる理由にはどんなものがあるでしょうか。

変わる要件にコードが追いつけない

真っ先に思いつくのが、「コードが書かれたタイミングと今とで要件に差異が生まれている」です。「当時は見越せなかった条件・制約が追加されている」といったこともありそうですね。これらの繰り返しによって、間に合わせのコードたちを継ぎ接ぎしたジェンガのようなコードが生まれるという状況です。
乱暴な物言いですが、正直これはどうしようもないと考えています。ウォーターフォールなエンタープライズアプリケーションの開発ならいざしらず、多くのプロダクト開発の現場は「どこに鉱脈があるか完璧にはわからない状態で日々あちこちを掘り進めている」ようなものですので、少しでも脈のありそうな線にピボットすることを止めてまでこれを防ぐのは難しいのです。
では、要件が変わりうるのはしょうがないとしても、なぜそれにコードがうまく追随できないのでしょうか?

経緯が語られないことこそが悪

コードというのは、言ってしまえば結果です。仕上がった画面と同じで、結果としてのコードの手前には、経緯となる要件や仕様*1の設計が脈々と連なっています。
結果だけを見て仕様を想像するというのは、形を大きく変えた伝言ゲームの最後から最初のお題を考えるようなものです。ある程度までは察せても、高い解像度は期待できません。
つまりこれが、「結果」だけを見て作り出された「経緯」を経て、新しい「結果」が再生産される……というジェンガ化必至のサイクルをもたらすわけです。

我々が負うべき義務

コードという成果物の手前には、例えば以下のような経緯があったはずです。

  • 産み出したい価値・体験
  • それにたどり着くためのいくつかの道筋と、選んだ道
  • 妥協したポイント
  • 未来に予想される変更ポイント

単純な機能追加であれば要件を満たすための最低限の手数で済ます、という選択肢も取れるでしょう。しかし大きな機能になればなるほど、盛大に風呂敷を広げた上で現実的なラインに落とし込む、という作業を機能仕様・技術仕様双方において行うことになります。先に述べたように、これらは正しく経緯を理解するための重要な情報となるはずです。
つまり我々は、 「変わり続ける要件のポイントを見極め、その時点で考えられる精一杯の範囲に風呂敷を広げた上で、その畳み方と畳んだ理由を後世に残す」 義務を負っているといえるでしょう。そして、この義務を果たすために、適切なドキュメントを後世に残し、そのポインタをコードに追加するというアクションが必要になります。

一方で、個人的には「そのままドキュメントになるコードを書く」という思想を好んでいます。しかし、残念ながらドキュメントたりうるコードを生み出すのは、ただ目の前の要件を満たすコードを生み出すことの何倍も大変ですし、たいていこういった部分はおろそかにされがちです*2。結局はそうした「結果のみ」が書かれたコードをメンテする機会のほうが多い、という理想とのギャップに向き合わねばなりません。

ドキュメントは誰が書くべき?

「ドキュメントはディレクターの役割でしょ」という声を耳にすることがあります。確かに機能仕様や思想の点では旗を振る人が書くべきというのも頷けますね。一方で、エンジニアにしか持ち得ない視点で語られるべきものごとというのも、同じくらい大事で、同じくらいたくさんあるのではないでしょうか。

  • 本来の想定とはことなるアーキテクチャで実装した場合の、その理由と差分
  • 将来予想される追加要件と、それへのアプローチ案・懸念

例えばこのような情報をアプリケーションコードとして表現するのは難しいはずです。個人開発ならともかく、集団でコードを書いているのであれば、いつでも同じ機能を自分が触れるとは限りませんし、知識を平準化するためにも、できるだけ多くの情報を何らかの形で残しておく必要があるはずです。

「書いた途端に陳腐化するのでドキュメントには意味がない」という意見もたびたび目にしますが、大事なのは「その時どんな議論がされ、それはどのように着地したのか」がアーカイブされるということなのですから、陳腐化上等!と言いたいところです。「機能Aを作ろう」と誰かが思い立ったとき、仮に過去に「機能Aの実装を試みた経緯」「機能Aを撤廃した理由」があれば、同じ轍を踏まずに最短で成功へとたどり着けるはずです。経験から学ぶのではなく、歴史から学ぶ努力をすべきではないでしょうか。

負債を作らないためには

不確実な未来に向かって突き進んでいる以上、これだけ気を配ったとしても資産の負債化リスクは0にはできないでしょう。しかし、その進行をできるだけ遅らせたり、たとえ負債化しても早々に手を打ったりできれば、チームの生産性を高いまま保つこともできなくないはずです。
負債化するということは、それだけ不確実性の高さと戦っていることの証左でもあります。ポジティブに捉え、深刻化するまえに倒してしまいましょう。

どんどんドキュメントを書こう

「ドキュメント」と言ったときにアレルギー反応が出てしまう一番の原因は、その堅苦しさにあると考えています。体裁とか、読みやすさとか、そういったものは一旦後回しにして、気張らずに、まずは1行のコードコメントから始めてみましょう。それだけで数日後、はたまた数年後の自分や誰かの命が救われるはずです。
もちろんドキュメントを書くということは、ある程度のメンテナンスコストとのトレードオフになるため、はじめは「経緯の補強」の一点のみに絞って書くとよいでしょう。
また、前述の「コードがドキュメントになる」を目指して実装するのもよいですね。コードを読めば「なぜそのロジックになったかがわかる」「ロジックをどのように拡張したらいいかわかる」状態は一種の理想です。

ただし、たとえこれらの試みが行われても、アクセス可能な状態になっていなければそれは十分とは言えません。たとえばドキュメント置き場を決めたり、関連情報にアクセスしやすくしたりすることで初めて機能し始めるでしょう。ロコガイドでは、仕様書はGoogle Document、技術仕様等はGitHub issueとしてまとめられることが多いため、相互にリンクしつつ、更にコードコメントにそれらを引用することで文脈の補完を図っています。

みんなで同じ方向を向いて、実践&実践

チームでコードをメンテナンスするとき、一番難しいのがそれぞれの思想の統一です。はじめの一歩としては、lintやGoodcheckなどを活用し、コード自体へのある程度の方向づけを行う(考えなくても済むようにする)ことで、コードレビューにおいてチームが本質的な課題に目を向けられるようにするのがよいでしょう。 その手前の思想的な部分は、輪読会等を通しての補強がおすすめです。チームでは実際にクリーンアーキテクチャ実践DDDを輪読しましたが、さっそく「自分たちのコードベースにはどのように適用していったらいいか」「チームで思想を更に一歩進んだ形で共有するにはどうしたらいいか」などの議論がなされており、非常に有益だと感じています。

一番難しいのが、両者をつなぐ部分である「設計をどのように実装へ落とし込むか」の共有(あるいは強制)です。この部分には正解がなく、正解の定義もプロダクトやチームのフェーズによって変わりうるので、様々な角度からのレビューを入れ洗練させる過程が必要です。そのため、はじめに思想的なゴールをチームで共有した上で、実践(設計〜実装〜レビューのサイクル)を通してすり合わせていくほかないと考えています。

ロコガイドでは、前回でも軽く触れたように、今まさに新しいアーキテクチャへの移行を始めているところです。現在はひとまずの方針を示し、メンバーそれぞれが実践に当たっている段階ですが、これもフェーズに合わせて柔軟に形を変え、負債になりにくい=価値を高く保てる資産を、最速で積み上げていけたらと思っています。

これらはなかなか一朝一夕に結果の見える取り組みではありませんが、結局のところ、こういったところに一番感度の高い人が旗を振ってやっていくべきでしょうし、それがテックリードやアーキテクトと呼ばれる人々の大事な職務のひとつだと私は考えています。こういうことを粘り強く推進していける人材でありたいですし、そういった人々が増えてほしいなとも思っていますし、そういった人々の参画を心待ちにしています

*1:システムだけにとどまらない

*2:返済を検討しないとならない負債が生じているということは、これが達成されていないということでもありますね