BeAct Co., Ltd.

BLOG
社員ブログ

大きなコードは「層」に分けよう

こんにちは! 今日もコーディングを楽しんでいますか?

コード……プログラミング言語だけでなく、スタイルシートやマークアップも含め、通常は「コード」を使って記述します。でも、なにか製品を作る場合、スタイルシートやマークアップのコードだけでも、たくさんの役割を持たせなければなりません。もし、すべての役割をこなすコードを、ひとつのファイルに書いていたとしたら、あとからのメンテナンスに大変苦労することでしょう。

原則として、コーディングは「小さく単純な役割を、完全に果たすもの」を、寄せ集めて作ります。でも、いざ実際にそれをやろうとすると、「どのくらい小さくしたら『単純』なのか?」「寄せ集めると言っても、どうやって寄せ集めればいいのか?」など、考えることが目白押しです。

こんかいは、そういった悩みに対して、「層」という考え方を使う方法を、一緒に学んでいきましょう。

こんかいのお題

「円グラフ(パイチャート)で、モバイル端末の所持率を表示させてちょうだい。あ、項目と割合はこれね」

という、Webアプリ製造の依頼が来たとします。データとして固定値が渡されたので、あえてズボラに実装することにしてみました。

See the Pen プログラムを層に分ける1 by isobeact (@rmzpacpm-the-builder) on CodePen.

いやはや、ズボラな割にCSS変数みたいな変なワザなどを使って、かえってコードが読みにくくなってしまっていますね。この静的なページを作るだけならば、これでもよかったのですが……。

顧客「サーバからJSONの値を取ってきて、それをもとにしてグラフを描けるようにしてよ」

……えっ? なんで今さら?! 開発現場は大混乱! どうしてこんな事になったのでしょう?

アプリケーションとは、舞台演劇だ!

最初に、この仕事の何がいけなかったのかを考えてみます。

製造側は、最初に「顧客は、このアプリのどこに『価値(つまり、お金になること)』を見出しているのか」を読み解くべきでした。そのために、「もしわからなければ、遠慮なく質問できる」よう、顧客との信頼関係を築くことも不可欠です。

比喩として、舞台演劇を用いてみましょう。みなさんが舞台演劇のプロデューサーだとして、外部、つまり顧客から企画を持ち込まれたときに一番気にしなければならないのは「この顧客は公演という企画を通じて、何を売りたいのか」であるはずです。そしてその企画での儲けを最大化するためには必要なのは、とにもかくにも売るべきものに対する知識です。

  • 彼らの事務所に所属する、特定の役者をバズらせるのでしょうか?
  • 彼らの開発した、新しいプロジェクションマッピング技術の宣伝でしょうか?
  • ソーシャルゲームとのコラボで、無料ガチャのコードをノベルティとして頒布するのでしょうか?
  • それとも? それとも……? 

上のリスト中、太字で書いた項目それぞれは、顧客にとっては等しく「お金儲け」の施策です。しかしプロデューサーであるみなさんにとって、それぞれの実現方法は全く異なるものであるのは、想像に難くありません。つまり、最初の段階では顧客とプロデューサーの目線は一致していないのです。

まず、この「目線の差がある」ことを認識していないと、製造側が「静的なパイチャート描画する」ことを目的として実装を終えてしまってから、実は顧客の要望は「動的にJSONを取得して描画する」だった……という事故は防げません。ゆえに、

顧客が売ろうとしている「価値」(お金になること)に対する知識

が、まず製造側に必要だったのです。

……と、口でいうのは簡単ですが、この情報収集は、一朝一夕でできることではありません。ゆえに、顧客と対話の機会を多く持ち、細やかな情報交換をスピーディーに行えるよう、ビジネスパートナーとしての信頼関係を構築してゆくことが大切になるのです。

もう一度「価値」について考えてみよう

お金儲けのために「何を」するのか=「関心事」を明らかにする

何がいけなかったのかを、ひと通り嘆いたところで、顧客がこのアプリによって売ろうとしている価値への知識を、顧客の快諾のもと、整理してゆくことになりました。何回かのやり取りを経て、以下のような知識を、顧客と共有できました。

  • 大前提として、動的なデータを用いた円グラフを描画したい。
  • 特定のURLにアクセスすることで、JSON形式で、以下の情報が配列として返ってくる。
    • その項目の内部名(英数字の組み合わせ)。
    • 見出しの文字列。
    • パイチャートを占めるパーセント数。
  • 表示順は配列の順そのまま。パーセントの多寡は気にしなくて良い。
  • 合計で100パーセントに満たない場合、余りは「その他」として扱う。
    • 「その他」は、上記の内部名、見出しの文字列だけを送る。
    • 「その他」のデータは、必ずJSON配列の最後になる。

つまり、これができれば「価値」を生み出せる……お互いの共通認識が定まりました。こうした知識を「関心事(かんしんじ・かんしんごと)」と呼びます。

関心事を実装に落とし込む前に

さあ、ここからが本題です。この知識をWebアプリで体現するには、実装側は少なくとも以下のことができなくてはなりません。

  • サーバと通信する
    • 通信に失敗したときは、その旨をエンドユーザーに伝える
  • 通信結果を、JSONとして評価する
    • JSONとして不正なデータなら、その旨をエンドユーザーに伝える
    • JSONとして有効でも、パーセント数の合計が100を超えた場合は「不変条件違反」として、その旨をエンドユーザーに伝える
  • パーセントの数字を、パイチャートの角度として計算し直す
  • パイチャートを描画する
  • 見出し文字列と、%記号を付けたパーセント数を、項目ごとに描画する

数はともかく、通信と描画など、畑違いな機能を連携させてこなさなければなりませんね。これを素朴に実装しようとすると、巨大なひとつのプログラムとなり、最初にお話したとおりメンテナンスに大変苦労することになります。

そこで、また舞台演劇の比喩で考えてみましょう。

役割と「層」

大道具担当に俳優をやらせるのは、俳優に大道具を担当させるのと同じくらい非効率です。また小道具担当が都合がつかなくなったからといって、勝手に台本を書き換えてしまうなんて、もっての外です。担当者は担当以外の作業をしてはならない……つまり役割分担とは「やるべき作業の範囲(ドメイン)」を決めることと言い換えられます。

実際の舞台演劇ではどのような表現になっているのかはともかく、あくまでも例として、このような役割分担の図を書いてみました。

企画モノの舞台演劇の役割分担(想像図)

内側から、赤、黄色、緑の、三重の範囲が設定されていることがわかると思います。各範囲の中央上部にそれぞれ、「舞台」「進行」「企画」と記載していますが、これがこんかい重要になってくる「層」です。各「層」は、演劇の外部とのやり取りの「具体性」の高さで分けられており、中心にゆくに従って、「お芝居をする」という具体性よりも「お金儲けをする」という抽象性が高くなっています。

層と依存

図にはたくさんの矢印がありますね。この矢印は「依存(いぞん)」の向きを示しています。例えば図の左側、俳優から演出や舞台監督に向かって矢印が伸びているのは、「俳優は、演出や舞台監督に依存している」という意味です。また矢印に添えられた説明は「どのような形での依存か」を表しており、例えば俳優から演出や舞台監督への矢印は「指導を受ける」と書かれているので、全体としては「俳優は、演出や舞台監督によって、指導を受ける」という意味になります。

実線の矢印は、具体的な依存を表します。図の中央の、顧客とプロデューサーとの関係では、顧客はプロデューサーに対し、「価値」に対する具体的な情報や知識を、直接共有するという対象として依存するというわけです。基本的に、この矢印は「外から中の層へ」または「同じ層どうしに」伸びています。

一方で点線の矢印は、抽象的・仮想的な依存を表します。図では、プロデューサーは顧客の「価値を生み出したい」という意向の実現に対し、依存している状態であることを示しています。

具体的な依存と抽象的な依存が循環することで、プロデューサーと顧客との情報共有のサイクルが常に回り続けるという状態を示しています。

具体的な依存どうしの循環は避けよう

上図にはたくさんの矢印がありますが、実線と点線の矢印が向き合う事はあっても、実線の矢印どうしが向き合うことはありません。仮に「俳優と舞台監督が互いに、実線の矢印で向き合っている状態」を現実世界に置き換えれば、

  • 俳優は、舞台監督に依存している→厳しい指導を受けるのだろうから、わかる。
  • 舞台監督は、俳優に依存している→なにか弱みでも握られてるの???

が、同時に起きていることになってしまいます。もし実線の矢印を向かい合わせたくなったときは、役割分担に矛盾が起きているサインかも知れません。いちど、関心事を洗い直すことをおすすめします。

アプリケーションをモデル化してみよう

では、舞台演劇の例で頭がほぐれた頃合いだと思いますので、いよいよ本題のWebアプリの関心事を図に起こしてみます。

舞台演劇の例に寄せた模式図

この図で大幅に簡略化していますが、いわゆる「ヘキサゴナルアーキテクチャ」や「オニオンアーキテクチャ」と呼ばれるものと、目指すところは同じです。

簡略化されているとはいえ、この図のすべてをここで解説するには複雑すぎるため、「層」に絞って解説してみましょう。

ドメイン層

一番内側にあり、「関心事を表現するデータ構造と、その操作」をまとめた層です。操作と言ってもあくまでデータレベルの話であり、どのように取得するのかはこの層では関知しません。「ビジネスロジック」と言い換えると、ピンと来る人もいるかも知れませんね。

アプリケーション層

ドメイン層の情報をもとに、「この業務はなにをしたいのか」を実現する仕組みを配置する層です。具体的には、外部からの信号を関心事に変換し、また外部に送り返すという挙動が主になります。慣れてくると、アプリケーション層をもとに関心事を分析できるようになってきます!

プレゼンテーション層

エンドユーザーや外部データといった「システムの外側」と対話し、それをもとにアプリケーション層やドメイン層に対して「データ操作のお願い」をする層です。ここに複雑なデータロジックを作り込まないことで、画面や通信手段の交換が手早くでき、顧客のニーズに素早く応える事ができます。

実際にコード化してみよう

というわけで、実際にコード化してみました。層の分割や依存方向が制作時にわかりやすいように、コードは「ESモジュール」単位で分割し、フロントエンドフレームワークである Vue を利用しました。

すでにお伝えしたとおり、依存は外側から内側、プレゼンテーション層→アプリケーション層→ドメイン層の方向に作ります。

エンドユーザーから外部データへの流れは:

  • 【プレゼンテーション層】ユーザーインターフェース
    • 【アプリケーション層】ユースケース
      • 【ドメイン層】値オブジェクト、エンティティ、集約、リポジトリ抽象
    • 【アプリケーション層】リポジトリ
  • 【プレゼンテーション層】インフラストラクチャ

そして、外部データからエンドユーザへの流れは:

  • 【プレゼンテーション層】インフラストラクチャ
    • 【アプリケーション層】リポジトリ
      • 【ドメイン層】値オブジェクト、エンティティ、集約、リポジトリ抽象
    • 【アプリケーション層】ストア
  • 【プレゼンテーション層】ユーザーインターフェース

と、依存の方向と処理の順番は、まったく無関係であることに注意する必要があります。

まとめ

こんかいの記事は「設計」に踏み込んだため、初~中級者の方には難しく感じられたかもしれません。とりあえず覚えていただきたいことは、

  • システムの外側とやり取りする層を作るよ!(プレゼンテーション層)
  • お金儲けするためのデータ構造の層を作るよ!(ドメイン層)
  • 上の2つを橋渡しする層を作るよ!(アプリケーション層)

の3つの層にコードを分類することで、大きくて複雑なコードをできるだけわかりやすく作ってみませんか?……といったところです。

今回のお話は、以上です。それでは、よきコーディングライフを!