PROMARI JOURNAL

OCP――共有先を一つ足したときの差分を追う

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

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

丸い共有ボタンの裏側を掘る連載の第5回。SOLID の2つ目の原則 OCP を、本物の SNS(Bluesky)の追加を通じて確かめます。名札カード1枚で済む変化と、共通処理のコードを変更することになる変化。差分を1行ずつ追いかけ、閉じる向きは変化の来やすさで選ぶことを、図22点で読み解きます。

PASS IT ON

ひとつの発見を、次の会話へ。

約束は、テストで守る

2ページ目では、Bluesky の名札カードを足しても、共通処理のコードは1行も変わりませんでした。けれど、「コードを変えていない」ことと、「今までのボタンが今までどおり動く」ことは、同じではありません。たとえば、足した名札カードのせいで、X のボタンの並び順がずれることもありえます。OCPの約束、つまり「足しても今までのものは変わらない」が守れているかを確かめる証拠になるのが、テストです。

図5-1 約束は、テストで守る
図5-1 約束は、テストで守る。実測(検証結果)。既存の63件の期待値を1つも書き換えずに通ったことが、「既存のコードを変えていない」ことの証拠になります。図5-1 約束は、テストで守る。実測(検証結果)。既存の63件の期待値を1つも書き換えずに通ったことが、「既存のコードを変えていない」ことの証拠になります。

テストとは、「この入力なら、この結果になるはず」という答えを先に書いておき、プログラムを動かして一致するかを機械で確かめる仕組みです。先に書いておく答えを期待値と呼びます。

今回の検証では、X や LINE の URL の作り方、ボタンの並び、クリックしたときの動きを確かめる Node のテスト63件が、期待値を1つも書き換えずにすべて通りました。これが「今までの振る舞いを変えていない」ことの証拠です。書き換えたのは、共有先の一覧をそのまま書いた「在庫表」のテスト3件だけでした。一覧に bluesky が増えたのだから、在庫表にも1行増えるのが正しい、という種類の修正です。新しく足したのは、3ページ目の textWithUrl を確かめるテスト1件です。

反対に、今までのテストの期待値を書き換えないと通らないとしたら、それは今までの振る舞いが変わってしまったという合図です。足しただけのつもりで、閉じていた共通処理に手が入ってしまったのかもしれません。

たとえば、Bluesky を足したら、X の URL を確かめるテストが落ちたとします。ここで X のテストの期待値を新しい URL に書き換えれば、テストは通ります。けれど、それは「X の URL が変わった」という事実を見えなくしただけです。本当に調べるべきなのは、「Bluesky を足しただけなのに、なぜ X の URL が変わったのか」のほうです。今までのテストは、足したものが今までのものに影響していないかを見張る役目です。落ちたときほど、期待値を簡単に書き換えないようにします。

期待値を読むときは、まず「前からある約束」と「今回増やした約束」を分けます。前者には、Xへ渡すURLや、コピーのボタンが記事URLを書き込むことがあります。後者には、textWithUrlが共有文とURLを一つにすることがあります。新しい約束のために、前からある約束を黙って弱める必要はありません。

たとえば、厳密なURL一致のテストが落ちたときに、「文字列ならよい」という緩いテストへ変えると、テストは緑へ戻るかもしれません。しかし、肝心のURLが欠けた段階1のような状態も通りやすくなります。追加した機能に合わせて確認を増やすことと、既存の確認を弱めることを、差分のレビューで区別します。

逆に、仕様として意図的に既存の結果を変える場合は、古い期待値を永久に守る必要はありません。そのときは『追加だけ』として扱わず、既存の利用者に何が変わるかを明記し、変更後の約束をテストへ書きます。OCPは正当な仕様変更を隠すための言葉ではなく、影響のある変更を見分けるための物差しです。

図で同じテストを変更前後へ当てているのは、同じ問いを続けて聞くためです。質問の内容を途中で変えれば、二つの結果は比べにくくなります。変える必要がある問いには理由を添え、変えなくてよい問いは残す。この扱い方をすると、テストの差分そのものが、設計の変化を説明する資料になります。

想定の外は、生成器が止める

差し込み口を用意したら、その口から想定外のものが入り込まないようにすることも大切です。このプラグインでは、それを生成器が受け持っています。3ページ目で見たとおり、名札カードの右側に書けるのは、用意された6つの名前だけでした。そこで、共通処理を直す前の生成器に、textWithUrl と書いた名札カードを読ませてみました。

Shell共通処理を変更する前の生成器に、textWithUrl を書いた名札カードを読ませた結果
$ python3 tools/config.py --config config/share_config.example.toml --generate
❌ シェア設定が不正です: bluesky.toml: params は「SNS 側の項目名 = hashtagsCsv / site / text / title / url / via」の形にしてください

1行目が実行したコマンド、2行目が生成器の返事です。「bluesky.toml の params は、hashtagsCsv / site / text / title / url / via のどれかで書いてください」と、書ける名前の一覧を示して止まりました。一覧に無い名前を書いても、黙ってそのまま動いてしまうことはありません。口の外から入ろうとする変化は、作り直しの時点で機械が止める。だから、名札カードという差し込み口を安心して用意しておけるのです。止まったということは、「その変化は名札カードだけでは足せない」という知らせでもあります。

生成器が止まる場面では、エラーの位置も手がかりです。記事の例では、値の名前を受け付ける段階で止まっています。つまり、ブラウザでクリックするより前に、書ける値の範囲から外れていることが分かります。ここで無理に検査を外すと、問題を後ろへ運ぶだけになるかもしれません。

ただし、生成器が通したから相手のSNSでも必ず動く、という意味にはなりません。生成器が知っているのは、定義した書式や値の名前などです。外部の投稿画面が今日も同じ項目を受け取るかまでは、その検査だけでは分かりません。図の門を一つ通ったら、次は何を確認するかを考えます。

このように差し込み口には、使い方だけでなく、どこまで確かめるかの境界もあります。追加する人がその境界を知っていれば、検査の成功を過大評価せずに済みます。説明書に『生成できたあとに、この共有先のURLを確認する』まで書ければ、口を開けた人から次の利用者へ、確認の手順も引き継げます。

差し込み口を開けておくことの代償

それなら、あらゆる変化に差し込み口を用意しておけばよいのでしょうか。そうはいきません。差し込み口を1つ用意するたびに、それを持ち続けるための手間が増えるからです。

図5.2-1 口を開けておくことの代償
図5.2-1 口を開けておくことの代償。考え方。口を1つ開けるたびに、決まりと検査と手順が1つずつ増えます。よく来る変化のためだけに開けます。図5.2-1 口を開けておくことの代償。考え方。口を1つ開けるたびに、決まりと検査と手順が1つずつ増えます。よく来る変化のためだけに開けます。

名札カードという差し込み口のために、このプラグインが抱えている手間は3つあります。1つ目は、名札カードの書き方の決まりと、決まりを守れているかを調べる検査です。2つ目は、名札カードを読んでブラウザ用の JavaScript ファイルを作り直す生成器と、その作り直しの手順です。名札カードを足しても、作り直しを忘れるとボタンは出ません。3つ目は、共有先の情報が、名札カードと共通処理の2か所に分かれて置かれることです。「Bluesky のボタンはどう動くのか」を調べるとき、名札カードと共通処理の両方を見る必要があります。

名札カードは、新しい SNS というよく来る変化のためのものなので、この手間に見合っています。けれど、めったに来ない変化のためにまで差し込み口を用意すると、手間だけが残ります。差し込み口は、よく来る変化のためだけに開けるのが、手間との釣り合いの取り方です。

天秤の図では、差し込み口を保つおもりを一度だけ払う費用として読まないでください。新しい値が増えれば説明書と検査を更新し、生成の手順が変われば利用者へ知らせます。差し込み口は、作ったあとも使い方を保ち続けるものです。一度の実装が短かったことだけで、維持の手間まで小さいとは言えません。

反対側には、追加するたびに共通処理を読み直す手間、既存の分岐へ触る危険、似たコードを重ねる負担があります。何度も来る同じ種類の依頼なら、口を用意した費用を繰り返し回収できます。数字を正確に予測できなくても、最近の変更を数件並べれば、どちらの手間が繰り返されているかは話せます。

まだ例が一つしかないときは、将来のための大きな仕組みを作る前に、変更箇所を分かりやすく寄せるだけでもよいでしょう。次の依頼が来たときに比較できるよう、何が足りなかったかを残します。今すぐ差し込み口を作ることだけが、拡張へ備える方法ではありません。判断の材料を残すことも準備になります。

新しい口は、いつ開けるか

では、3ページ目で Bluesky のために足した textWithUrl は、プラグインの本体に入れるべきでしょうか。実は、今回の変更は、まだ本体には入れていません。この記事のために、作業用のコピーで試しただけです。本体に入れるかどうかは、次の3つの問いを順にたどって決めます。

図5.3-1 新しい口は、いつ開けるか
図5.3-1 新しい口は、いつ開けるか。判断の目安(提案)。来ていない変化のために口を開けません。同じ種類の変化が重なりそうになったときに開けます。図5.3-1 新しい口は、いつ開けるか。判断の目安(提案)。来ていない変化のために口を開けません。同じ種類の変化が重なりそうになったときに開けます。

1つ目は、その変化の依頼が、いま実際に来ているか。2つ目は、同じ種類の変化が、ほかにも来そうか。たとえば Bluesky のように「URL を本文に含めて渡す」SNS が、ほかにもあるか。3つ目は、差し込み口を持つ手間よりも、次から書き換えずに済む利点のほうが大きいか。「まだ来ていない変化のために、先回りして仕組みを作り込まない」という考え方には、YAGNIという名前があります。Bluesky を足してほしいという依頼が実際に来て、同じような SNS がほかにも出てきたら、そのときに本体へ入れます。

SOLID の入門書でも、同じ考え方がよく勧められています。差し込み口(抽象化)は、最初から全部の場所に作る必要はありません。種類が増えそうかをいつも意識しておき、実際に増えたときに作れば十分です。すべてに差し込み口を用意するのは、やりすぎになります。

このプラグインの差し込み口

最後に、このプラグインに今ある差し込み口を、まとめて見ておきます。名札カードのほかにも、共通処理を書き換えずに足せる場所が3つあります。

図5.4-1 このプラグインの差し込み口
図5.4-1 このプラグインの差し込み口。現在のしくみ。口はどれも、よく来る変化の側に1つずつ開けてあります。共通処理の中身は、どの口から足しても変わりません。図5.4-1 このプラグインの差し込み口。現在のしくみ。口はどれも、よく来る変化の側に1つずつ開けてあります。共通処理の中身は、どの口から足しても変わりません。
このプラグインの4つの差し込み口
差し込み口置き場所足せるもの
名札カードdestinations/*.toml新しい SNS
サイトの設定config/share_config.toml並び・言い回し・色の上書き
部品の差し替えcomposition/(DI コンテナ)コピーなどの実装の取り替え
知らせ(イベント)document に届く promari-sns-share計測の受け手

名札カードは、新しい SNS を足す場所です。サイトの設定は、ボタンの並び順や、ボタンに出す文字、色を、サイトごとに変える場所です。部品の差し替えは、たとえば「URL をコピーする」処理の中身を、別の作りに入れ替える場所です。どの部品を使うかを composition フォルダの1か所でまとめて決めているので、そこを変えるだけで入れ替えられます。この仕組みを DI コンテナと呼びます。

知らせ(イベント)は、ボタンが押されるたびに promari-sns-share という名前の知らせを出す仕組みです。アクセス解析などのプログラムは、その知らせを受け取って、どのボタンが押されたかを記録できます。4つとも、よく来る変化に備えて1つずつ用意してあります。部品の差し替えは、連載2.5で詳しく読みます。

四つの差し込み口は、全部を一度に使う必要はありません。共有先を増やすなら名札カード、サイトの並びを変えるなら設定、コピーの実装を試験用へ替えるなら組み立て、計測の受け手を増やすなら知らせ、というように依頼の種類から入口を選びます。図の地図を、実際の作業の行き先案内として使ってください。

入口を間違えると、別の仕組みを無理に広げることになります。たとえば計測の項目を増やしたいだけなのに、各SNSの名札カードへ計測処理を書く必要はありません。逆に、SNSのURLの仕様変更を、計測イベントの受け手で書き換えようとすると、どこで共有先を決めているのかが見えにくくなります。依頼と入口が対応しているかが、最初の確認です。

どの入口でも、受け取る側の約束はあります。知らせを受け取る側なら、渡される情報の意味を守り、コピーの代役なら、成功したと返す条件を守ります。入口から差し込めることだけでは、正しく動くことまでは決まりません。ここから次回のLSPへ、話がつながります。

考えてみる:差し込み口を増やしすぎると、何が困るの?

差し込み口ごとに、書き方の決まり・検査・作り直しの手順が増え、読む人が覚えることも増えます。しかも、使われない差し込み口も、決まりを変えるたびに合わせて直す必要があり、手間だけが続きます。差し込み口の数は、実際に来そうな変化の数に合わせるのがちょうどよく、それより多く用意するのは、将来の自分に手間を前払いするようなものです。

COMMENTS
コメント…

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

PASS IT ON

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

この記事を書いた人

Takaomi Murasaki

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

公開記事 11 件

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

FROM INSIGHT TO IMPACT

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

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

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

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

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

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

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

ご相談後の流れ

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