😼

再利用しやすいコードの設計について最近考えていること

2023/12/02に公開

概要

再利用しやすいコードを書きたい人に対して、再利用の性質と再利用しやすいコードの設計方法について説明します。

対象

  • Webアプリケーション開発の設計に興味を持っている人
  • X年前に仕事でWebアプリケーション開発をはじめた頃の自分

自分について

  • 業務でWebアプリケーション開発
  • 主にPHP、Symfonyのサーバーサイド開発
  • 目下の興味は「要件の変更をソフトウェアの設計・構造によって、いかに迅速・最小労力で実現できるか」

TODO:ここに図

ソフトウェア設計で意識していること

ソフトウェア設計に関する問題は、常に"要件の変更"に関する問題である

  • 要件はソフトウェアの存在理由のようなもの
    • 140字でテキストを投稿したり、音声通話したりする機能要件
    • セキュリティ、プライバシー、パフォーマンスのような非機能要件

ソフトウェア設計の良し悪しは"要件の変更"に対して、どれだけ少ない労力(時間・作業量)で対応できるか

再利用の性質

対象とするWebアプリケーションの設計

次のようなよくあるレイヤー構成のWebアプリケーションを対象に説明します。

このようなレイヤー構成では、概ね次のような順で処理を呼び出します。

  • プレゼンテーション層(UI、コントローラ)
  • ビジネスロジック層(サービスクラス、ドメインモデルクラス)
  • データアクセス層(リポジトリクラス等)
  • リソース(データベース、ファイル、外部API等)

再利用の性質

再利用性は次のような形になっていると良い設計と考えています。

  • レイヤーの上に行くほど、再利用性は低くなる(プレゼンテーション側:UI)
  • レイヤーの下に行くほど、再利用性は高くなる(データアクセス側:DB)

これは変更の頻度やコードの安定性と対称になっています。

  • レイヤーの上に行くほど変更量が多く、コードの安定性は低い(プレゼンテーション側:UI)
  • レイヤーの下に行くほど変更量は少なく、コードの安定性は高い(データアクセス側:DB)

再利用しやすいコードの設計方法

PHPやその他の言語ではメソッド・関数等が公開されていれば物理的には再利用できます。
(ソフトウェアエンジニアの言う「できなくはないです」の意味合い)

しかし、実際に再利用しやすいかはコードの設計次第です。
そこで次のような方針を考えました。

できるだけ少ない労力で機能を実現したいなら、できるだけ大きい粒度でコードを再利用できること

再利用の粒度

ブログアプリケーションで「記事を検索する」機能について考えます。
(雑な例ですが許して何卒)

  • SearchText::validate($rawSearchText);
  • SearchText::convert($rawSearchText);
  • SearchParameter::create($searchText);
  • ArticleRepository::findAll($params);

と細かいコードだけがある場合と、これらのコードを適切に呼び出して検索してくれる

  • ArticleSearch::search($searchCondition);

がある場合、どちらが開発者にとって開発がしやすいでしょうか。
例えば「特定のキーワードを含む記事をユーザーにメールでお知らせする」機能を実装する場合、

searchCondition = UserRecommendSearchCondition::create(user)
articles = ArticleSearch::search(searchCondition)
UserNotification::send(UserNotificationMails::create(user, articles)

と利用できます。
「記事を検索する」機能はユースケースに出てくる操作としても一般的でちょうどいい粒度の機能と感じます。

ただし、大きい粒度のコードをたった一つ部品だけで構成すると内部のコードを再利用できないので、再利用性が低くなってしまいます。
そこで内部もまた更に分解し、より小さい粒度のコードで構成します。

再利用の粒度の決め方

この粒度の決め方は抽象度によって決めると良いと考えています。

「記事を検索する」機能は想像するにユーザの「読みたい記事を探す」ユースケースを具体化したものです。

「読みたい記事を探す」ユースケースの具体化の別パターンでは例えば「(機械学習などの技術によって)記事をレコメンドする」ことも考えられます。

「記事を検索する」ことを具体化すると、例えば「DBや全文検索エンジンで取得する」となります。

このように処理を抽象化・具体化しながら適切な粒度を探求します。
抽象度をレイヤー表現したものを抽象化レイヤーといいます。

設計時には適切な粒度を「要件の変更が発生したら、その粒度のままで再利用できるか?」を問いながら探します。
他の開発者にも抽象化レイヤーを眺めてもらい、理解しやすいか(認知負荷が低いか)を確認するとなおよろしです。

再利用しやすいビジネスロジック層の命名

現時点の自分の考えでは、プレゼンテーション層(Controller,UI)から呼び出されるビジネスロジック層の再利用できる命名(クラス名・メソッド名)は

「〇〇を××する」形式、主語のない目的語+動詞の組み合わせ

のような形で、ビジネス動詞(ユーザーが行う作業・操作・業務活動)で表現するとわかりやすいと考えています。

  • 記事を作成する
  • 記事を検索する
  • 記事を公開する
  • コンテンツをダウンロードする
  • 広告掲載費を請求する
  • 商品を購入する

主語を抜いたのは主語はプレゼンテーション層(を操作する人)で、プレゼンテーション層は状況によって変わるからです。

  • Webアプリケーションのフロントエンド
  • スマホアプリ
  • 外部システム
  • タイマー(ジョブスケジューラ、cron)

まとめ

再利用の性質と再利用しやすいコードの設計方法について説明しました。

  • できるだけ少ない労力で機能を実現したいなら、できるだけ大きい粒度でコードを再利用できること
  • ビジネスロジック層では「〇〇を××する」形式、「(主語のない)目的語+動詞の組み合わせ」で表現してみてはいかが?

Discussion