Open8

保守性を犠牲にしないための最小限のスタイルガイドを考えたい

dondakeshimodondakeshimo

Why

t_wadaさんの超有名なスライドの「質とスピード」では、内部品質を高めることと、開発速度はトレードオフではないと主張している。
https://speakerdeck.com/twada/quality-and-speed-2020-autumn-edition

自分としてもこの主張は概ね納得できることであり、ソフトウェアの保守性はそのまま開発速度に直結すると考えている。短期開発の場合はその限りではないと言われているが、短期開発と中期開発の閾値は1ヶ月と非常に短いことには留意すべきである。

では、スピードとトレードオフになるものは内部品質ではなく、学習、教育である。先述の資料でも、設計スキルを磨くためには自分で書いたコードを長期にわたってメンテナンスすることが重要だと説かれていた。しかし、スタートアップではエンジニアの育成に時間をかけている余裕はない。また、優秀なエンジニアを揃えられる企業も少ないので、必然的に保守性の担保が難しくなっていく。

保守性の高いコードを学習するためには、たくさんのアーキテクチャパターンや設計論を学び、たくさんのコード、長い業務経験が必要になる。一方で、我々が実際にチームとしてコードを書く時に、あるいはレビューを行うときに議論の基にすべきは「ぼくのかんがえたさいきょうのせっけい」よりも、チーム内でコンセンサスの取れた規約やスタイルガイドである。

未熟なエンジニア(自分も含めて)が、改修を加えるためにコードベース中を駆け回らなければならないような、リファクタリングするときにフルスクラッチで描き成すことが最も安価な選択肢になるような、袋小路に追い詰められないようにできる最低限のスタイルガイドをこのスクラップで考えたい。

dondakeshimodondakeshimo

DDD

全体設計

できれば以下のことを考える。

  • サブドメインの抽出 (特にコアドメイン)
  • サブドメインに基づいた境界づけられたコンテキストの設計

モノリスでの実装から始まると思うが、可能な限り上記の設計方針に従って、モジュラーモノリスとして実装していく。
サブドメインの抽出をしていなかった場合もなんとなく境界づけられたコンテキストはできている状態だと思うので、整理してドキュメント化し、全体像が見えるようにする。

ユビキタス言語

  • 概念に適切な名前をつける
    • ドメインエキスパートと相談した上で決める (エンジニアだけで決めない)
  • ソースコードでは必ずユビキタス言語に基づいた命名を行う
  • 可能ならコードから用語集を作成する
    • 直近は無理でも将来的に用語集がコードから作れるように意識してコードのコメントなどを記載する
dondakeshimodondakeshimo

アーキテクチャ

コアドメインの実装には Ports & Adapters を推奨する。
汎用サブドメインや支援サブドメインについてはMVCフレームワークなど簡単に実装できるもので問題ない。

dondakeshimodondakeshimo

開発プロセス

アジャイル

会話することと、ルールのドキュメントかが重要。

ブランチ戦略

定義してあることが重要。

レビュープロセスがある場合はレビューのガイドラインもあると良い。

CI/CD

1日に複数回のメインラインへのマージを行えるようにすること。

CI/CDのために

  • 最初から自動テストを記載すること
  • メインラインへの変更に対して自動テストを都度実行し、失敗すれば即時修正できること
    • または、メインラインへの変更反映前にチェックを実施し、失敗すればメインラインへの反映を止められること
dondakeshimodondakeshimo

ドキュメンテーション

無駄なものは書かない

時間がないので不要な労力は使わない。

プロダクト/プロジェクト

  • 背景や目的
  • 必要なリンク集

開発プロセスの定義

  • アジャイルな開発フローの定義
    • 完了の定義
    • チケットの切り方や担当の振り方
    • 会議体
  • ブランチ戦略の定義
  • テスト戦略の定義

README

  • コードベースの背景や目的
  • 上位文書への誘導
  • 開発環境の構築方法
  • 開発におけるルール
dondakeshimodondakeshimo

コアドメインの実装

命名

適当な命名は許容しない。ユビキタス言語を最優先に、適切な名前をつけられるまできちんと検討する。

OOP

オブジェクト指向プログラミングを徹底する。手続的な処理は極力なくし、データと振る舞いをセットで記述する。
カプセル化を行うために、基本的にデータの公開範囲は狭くする。

CQS (Tell, Don't ask)

コマンドとクエリを分けて実装する。

イミュータブル

可能な限りデータは変更不可にする。

永続化

永続化層にロジックを持たせたくないので、シンプルに保つ。ESまでできるなら SaveLoad があれば十分。すべてのドメインモデルに対して、永続化層との連携ができる必要がないので、ある程度大きな塊でアクセスできれば良い(結果としてその塊を集約ルートとして扱うことになる)。

Repositoryパターンの使用をよく見るが、すべてのドメインモデルに対してRepositoryを用意する必要はないので注意する。Aggregate RootのみがRepositoryを所持するようにする。

UI

利口なUIにならないようにする。

ログ

ルールを決めるのが重要。以下は参考

  • 大量のログを出さない
  • Debug logレベルのものを出さない
  • 構造化する

コメント

WhyとWhatに集中する。Howに関してはコードの再説明は書かない。コードより大きな粒度でのHowについては記載する価値がある場合もある。

プログラミング言語には大抵標準的なコメント記載方法があるので、それに従う。

インターフェースコメントは特に重要なのでしっかりと記載する。

dondakeshimodondakeshimo

セキュリティ

最小権限の原則

必要な権限しか与えない。

ライブラリのアップデート

ライブラリを順次アップデートできるようにしておく。dependabotなど最初から入れられるなら入れてしまう。