PROMARI JOURNAL

DIP――ブラウザの機能を、ポートの向こうへ置く

作成: / 公開: / 内容更新:

執筆:tamito0201 / 掲載・運営:プロマリ

丸い共有ボタンの裏側を掘る連載の第8回。SOLID の5つ目の原則 DIP を、「コピー」のボタン1つから確かめます。コピーを頼むコードはブラウザを知らず、約束(ポート)だけを知る。実行時の呼び出しは外へ、import は内へ。import の向きを数え、DI・DI コンテナ・ファクトリの役目を読み、わざと境界を破って何が止めるかまで、図16点で読み解…

PASS IT ON

ひとつの発見を、次の会話へ。
自然光の差す部屋で、机の横の白い壁のコンセントに紫のプラグが差さり、コードの先の真鍮のデスクランプが灯っている写真風のイメージ

こんにちは、プロマリの紫です。連載「丸いボタンの裏側」の第8回、第2章の5回目です。SOLID は、変更に強いコードを書くための5つの原則を、頭文字でまとめた呼び名でした。第2章では、その5つを1つずつ、この共有ボタンのコードに当てて確かめてきました。今回は最後の原則、DIPです。テーマはコピーを頼むコードは、ブラウザのことをどこまで知っていればよいかということ。「コピー」のボタン1つを入口に、コードの矢印の向きを数え、わざと境界を破って何が止めるのかまで確かめます。

点線の付いた用語は、その言葉を押すと詳しい説明が開きます。意味、身近なたとえ、この実装での使い方を順に読めます。キーボードではTabで用語へ移動し、EnterまたはSpaceで開き、Escapeで本文へ戻れます。各ページで最初に出る用語から参照できるようにしました。

この記事は連載「丸いボタンの裏側」の第8回(2.5)です。前回の2.4「ISP――コピーの代役に、いいねの保存まで求めない」で、能力ごとに小さく分けたインターフェースを先に読むと、今回の話がつながりやすくなります。連載全体の地図は、本編5ページ目の連載の目次からどうぞ。

この回は6ページあります。1ページ目で DIP の意味と、このプラグインの層の地図を確かめます。2ページ目では、プラグインを離れて、ボタンとデータベースの短い例で「逆転」の正体をつかみます。3ページ目でプラグインの実物に戻り、コピーの差し込み口と import の向きを数え、4ページ目で、実装を選んで渡す組み立て役(DI・DI コンテナ・ファクトリ)を読みます。5ページ目ではわざと境界を破って、何が止めるかを実測し、6ページ目で、何にでも差し込み口を挟まないための目安と宿題に進みます。図は16点です。ここで示す件数や出力は、すべて実際に手元で動かして測ったものです。

コピーを頼む側は、ブラウザを知らない

共有欄には、SNS のボタンと並んで「URLをコピー」というボタンがあります。押すと、いま読んでいる記事の URL がクリップボードに入り、設定の例どおりなら「URLをコピーしました」と小さな知らせが出ます。やっていることは、それだけです。

けれど、このボタンの裏では、ブラウザに用意されたnavigator.clipboardという機能を呼んでいます。ブラウザによっては使えないことがあり、ページの状態によっては書き込みを断られることもあります。テストを動かす Node には、そもそもクリップボードがありません。コピーという単純な操作ほど、外の事情に振り回されやすいのです。

図1-1 コピーを頼む側は、壁の向こうを知らない
図1-1 コピーを頼む側は、壁の向こうを知らない。説明。家電がコンセントの形に合わせて作られるように、コピーを頼む側は差し込み口(ポート)の形だけを知り、壁の向こうのブラウザを知りません。図1-1 コピーを頼む側は、壁の向こうを知らない。説明。家電がコンセントの形に合わせて作られるように、コピーを頼む側は差し込み口(ポート)の形だけを知り、壁の向こうのブラウザを知りません。

そこで、このプラグインでは、コピーを頼むコードに、ブラウザの機能を直接呼ばせていません。代わりに、「文字列を書き込み、成功か失敗を返す」という約束だけを用意し、それを通して頼みます。約束の名前は ClipboardGateway です。身近なもので言えば、壁のコンセントです。家電は、壁の向こうの発電所や配線を知りません。知っているのは、コンセントの形だけです。発電所のほうも、その形に合わせて電気を届けます。この連載では、この差し込み口にあたる約束を、ポートと呼びます。

このコンセントのたとえが、この回でずっと使う、ただ1つのたとえです。コピーを頼むコード(家電)は、ポート(コンセント)の形だけを知っています。ブラウザ用の実装も、テスト用の代役も、壁の向こうで、そのポートの形に合わせて作られています。だから、テストのときは代役を差し込むだけで、コピーを頼むコードを1行も変えずに動かせます。

Martin が書いた、2つの文

DIP を言葉にしたのは、SOLID の原則を広めた人として知られる Robert C. Martin です。1996年6月、C++ Report という雑誌の連載コラムで、次の2つの文にまとめました。

Martin の DIP(1996)の2つの文と、この記事での言い換え
原文この記事での言い換え
A. HIGH LEVEL MODULES SHOULD NOT DEPEND UPON LOW LEVEL MODULES. BOTH SHOULD DEPEND UPON ABSTRACTIONS.大事な判断をするコード(上位)は、具体的な道具(下位)に頼らない。どちらも、あいだに置いた約束に頼る
B. ABSTRACTIONS SHOULD NOT DEPEND UPON DETAILS. DETAILS SHOULD DEPEND UPON ABSTRACTIONS.約束が道具の細かい都合に合わせるのではなく、道具のほうが約束に合わせる

ここで言う「上位」は、偉いという意味ではありません。コピーを頼む、共有の手順を決める、といったアプリケーションの方針を持つコードのことです。「下位」は、その方針を実際に動かす細かい道具、たとえばブラウザのクリップボードの機能です。そして「抽象」は、何をするかだけを決めて、どうやるかを決めていない部品を指します。「依存」は、あるコードが別のコードの名前を知っていて、それが無いと動かない関係のことです。

2つの文をまとめると、こうなります。方針のコードも、道具のコードも、あいだに置いた約束のほうを向く。方針のコードが道具を直接知る形をやめ、両方が約束を知る形にそろえる。これが DIP の中身です。

原典の例も「コピー」だった

面白いことに、Martin がこのコラムで最初に使った例も「コピー」でした。キーボードから打った文字を、プリンタへ書き出すプログラムです。Copy という関数が、ReadKeyboard でキーボードから1文字読み、WritePrinter でプリンタへ書く。とても素直な作りです。

困るのは、書き出す先をディスクのファイルにも広げたくなったときです。Copy の中に「プリンタならこちら、ディスクならこちら」という if 文を足すことになり、出力先が増えるたびに、Copy は細かい道具を次々に知っていきます。Martin は、この Copy こそが「文字を読み取って書き出す」という、いちばん再利用したい方針を持っているのに、具体的な機器に縛られて使い回せない、と指摘しました。そして、Reader(読むもの)と Writer(書くもの)という抽象を挟み、Copy はその2つだけを知る形に直して見せました。

このプラグインのコピーのボタンも、同じ形をしています。コピーを頼むコード(方針)は、ClipboardGateway(書くもの)という抽象だけを知り、ブラウザのクリップボード(機器)は、壁の向こうに置かれています。30年前のプリンタが、いまはブラウザに替わっただけです。

おさらい:このプラグインの四つの層

先に進む前に、このプラグインのブラウザ側のコードが、どう分かれているかを確かめておきます。連載の本編でも紹介したとおり、コードは役割ごとのレイヤーに分かれています。表示と操作を受け持つ presentation、共有の手順を受け持つ application、判断と約束を置く domain、ブラウザの機能を実際に呼ぶ infrastructure の四つです。そのほかに、起動するときに部品をつなぐ組み立て役として composition があります。

図1.3-1 四つの層と、組み立て役
図1.3-1 四つの層と、組み立て役。現在のしくみ。import の矢印は、すべて domain へ集まります。domain は、ほかの層を知りません。図1.3-1 四つの層と、組み立て役。現在のしくみ。import の矢印は、すべて domain へ集まります。domain は、ほかの層を知りません。

地図のいちばん大事なところは、矢印の集まり方です。application は domain を知り、infrastructure も domain を知っています。けれど、domain はほかのどの層も知りません。import の矢印は、すべて domain に向かって集まります。コピーの約束(ClipboardGateway)が置かれているのも、この domain の中の gateway というフォルダです。点線の矢印は、組み立て役が起動するときにつなぐ線で、コードの import とは別のものです。この地図を手元に置きながら、次のページへ進みましょう。

考えてみる:方針のコードが、ブラウザを直接呼んでも、今のところ動いているなら困らないのでは?

動いているあいだは困りません。困るのは、変えたくなったときと、試したくなったときです。ブラウザの機能は、ブラウザの種類や権限、テストの環境によって振る舞いが変わります。方針のコードがブラウザを直接呼んでいると、そのたびに方針のコードを開くことになり、テストではブラウザの代わりを差し込む口がありません。5ページ目で、実際に直接呼ぶ形に書き換えて、テストの何件が落ちるかを数えます。

COMMENTS
コメント…

このページ(1ページ目)の感想・質問・設計へのコメント

PASS IT ON

この気づきを、誰かにも。

この記事を書いた人

Takaomi Murasaki

Promari SNS Shareの開発を通して、Webの仕組みや設計の選び方を紹介しています。動く実装と、その判断に至るまでを記事に残しています。

公開記事 10 件

プロフィールを見る
THANK YOU FOR READING.すべての記事へ ↗

FROM INSIGHT TO IMPACT

「できたらいいな」を、
動く仕組みに。

記事で見つけたヒントを、あなたの事業へ。
新しいサービスも、手間のかかる業務も。
いまの課題から、つくるべきものを一緒に考えます。

開発・AI・研修の実績を見る

まだ、仕様書はいりません。

「何から始める?」から、ご一緒に。

課題がまとまっていなくても大丈夫。テーマを選ぶと相談文をご用意します。
連絡先の必須入力は、お名前とメールアドレスだけ。

まずは課題の整理から相談する

ご相談後の流れ

  1. 01 内容を確認
  2. 02 メールでご連絡
  3. 03 課題・進め方をご相談
送信だけで契約やお申込みが確定することはありません。