PROMARI JOURNAL

ISP――コピーの代役に、いいねの保存まで求めない

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

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

丸い共有ボタンの裏側を掘る連載の第7回。SOLID の4つ目の原則 ISP を、飛べないペンギンの例から、プラグインの5つの小さな口(ポート)とテストの代役まで読み進めます。全部入りのインターフェースにすると、コピーの代役に何が要るのか。作業コピーでの実験と図15点で確かめます。

PASS IT ON

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

LSP・SRP とのつながり

最後に、ISPを、前回までに読んだ原則とつなげておきます。

前回のLSPは、「同じインターフェースを満たす実装へ取り替えても、利用側が頼っていた約束が崩れないこと」を求める原則でした。1ページ目のペンギンの fly や、3ページ目の全部入りの代役のように、使わない項目に「例外を投げるだけ」の中身を書くと、その実装は約束を守れていない実装になります。ISP は、利用側が要らない約束をインターフェースから外しておくことで、そうした守れない約束が生まれる余地を先に消します。LSP が取り替えたあとの約束を見張るのに対して、ISP は約束をどこまで求めるかを決める、という分担です。

連載2.1のSRPは、「変更を頼んでくる人(依頼主)ごとに、置き場所を分ける」原則でした。ISP は、同じ見方をインターフェースの側から当てたものと言えます。SRP は「誰が変更を頼むか」で置き場所を分け、ISP は「誰がその能力を使うか」で約束を分けます。4ページ目で、いいねの保存を知らせの口に入れなかったのは、いいねの保存を頼むのも、使うのも、クリックの処理ではないからでした。

3つの原則が見ているもの
原則見ているものこのプラグインでの当て方
SRP(2.1)変更を頼んでくる人名札カードの依頼主を SNS 各社にそろえる
LSP(2.3)取り替えたあとも約束が守られるか動きの種類ごとに、URL を開く・コピーするの条件を分ける
ISP(2.4)利用側が使わない能力を求められていないか外の世界の能力を5つの口に分け、いいねの保存は口に入れない

三つの原則を同じコピーの変更へ当ててみると、見る場所が違うことが分かります。SRPでは、誰の都合でその置き場所を変えるかを考えます。ISPでは、使う側にコピー以外の能力まで要求していないかを見ます。LSPでは、差し替えたコピーの部品が、書き込んでから完了する約束を守るかを確かめます。

小さく分けた口でも、中身が何もしなければLSPの問題は残ります。約束を守る全部入りの実装でも、コピーだけの利用側に無関係な変更を強いていればISPの問題は残ります。一つを守ればほかが自動で満たされるわけではありません。同じ図へ三枚の観点を重ねて、どの問題を解いている変更かをはっきりさせます。

ISP を確かめる3つの問い

ここまでの話を、コードを見直すときに使える3つの問いにまとめます。3ページ目の全部入りの形と、今のプラグインを、同じ問いで比べました。

ISP を確かめる3つの問い
問い全部入りの形(実験)今のプラグイン
代役に、使わない項目の中身を書いているかはい(コピーの代役に6項目)いいえ(コピーの代役は write と fallback だけ)
使わない能力の変更で、直すことになったかはい(loadLikes を足すとコピーの代役が止まる)いいえ(いいねの保存は口の外)
例外を投げるだけ・空の実装があるかはい(「この試験では使わない」)いいえ

3つとも「いいえ」なら、調べた範囲では、使わない能力による負担は見つかっていません。どれかが「はい」なら、5ページ目の判断の目安に進み、つなぐ手間と比べて分けるかを決めます。

ISP によくある3つの誤解

ISP を読むときに陥りやすい誤解を、3つ並べておきます。

ISP によくある誤解と、この記事での答え
よくある誤解この記事での答え
メソッドは1つずつに分けるほどよい分ける単位は、利用側が一緒に必要とし、一緒に変わる能力。NativeShareGateway は2項目のまま
分けた口をまとめ直すのは、いつも悪い利用側が一緒に使うものを束ねるのはよい(ShareGateways)。避けるのは、利用側が使わない能力まで必須にする形
ISP は、実装するクラスの話主役は利用側。使う側が何を求められているかで決める。実装する側の空のメソッドは、その結果として現れる合図

3つの誤解に共通しているのは、ISP を「インターフェースを小さくすること」だと読んでいることです。ISP が求めているのは、小さくすることそのものではなく、利用側が、使わない能力に頼らされないようにすることです。どこで分けるかは、実際に代役を書いたり、変更に巻き込まれたりした経験を数えて決めます。

レビューで「口が大きい」と言うときには、メソッドの数だけでなく、具体的な利用側を指してみてください。「この処理はwriteしか使わないのに、saveLikeも実装しなければ作れない」と言えば、何を外したいのかが伝わります。「八個あるから多い」だけでは、一緒に必要な八個なのか、無関係な仕事が混ざった八個なのかが分かりません。

分割案を見る側も、「分けた結果、どの変更に追従しなくて済むか」を聞くと評価しやすくなります。今回なら、いいねの読込機能を足しても、コピーの代役には項目を足さない、という具体的な答えがあります。効果を一つの将来の変更で説明できれば、ファイルが増える費用と比べて判断できます。

手を動かして確かめる

今回の練習は、手元のインターフェースで代役を1つ書いてみることです。インターフェースを1つと、それを使っている利用側を1つ選び、その利用側のテストのための代役を書きます。そして、代役のうち「使わない」「空」になった項目を数えます。例外を投げるだけの中身を探すなら、grep -rnE “not implemented|未実装” src test のように、手元のコードで使っている言い回しで検索すると見つけやすくなります。

図9-1 この回の宿題
図9-1 この回の宿題。確かめ方の提案。代役を1つ書くと、その利用側が本当に要る能力が見えます。使わない項目の数が、分けどきの目安です。図9-1 この回の宿題。確かめ方の提案。代役を1つ書くと、その利用側が本当に要る能力が見えます。使わない項目の数が、分けどきの目安です。

数えた数が多いなら、その利用側が一緒に必要とする能力だけを持つ、小さな口を作れないかを考えます。ただし、5ページ目の3つ目の問い(つなぐ手間)も忘れずに比べてください。宿題:代役を1つ書いて、使わない項目を数える。数えた結果は、このラベルからコメントに残せます。

練習では、最初に既存のテスト用ヘルパーを見ず、小さな代役を自分で一つ書いてみると、余分な要求に気づきやすくなります。型の検査が足りないと言った項目を並べ、その利用側が実際に使うものへ印を付けます。残った項目は削除を決めたものではなく、別の口へ分ける候補です。

次に、その候補のうち一つを変更したら、どこを直すことになるかを調べます。代役、実装、組み立ての三か所を見れば、口の広さによる負担と、分割のための負担を同じ紙で比較できます。最後に、分ける案でも今の動作を保てるかを、LSPの契約の観点で確認します。数えて終わらず、次の変更がどこに届くかまで描ければ、練習は十分に具体的です。

ISP の定義は、Robert C. Martin が The C++ Report に書いたThe Interface Segregation Principle(1996・Internet Archive に残る写し)から、短い言い直しはSolid Relevance(2020)から引きました。「どういうものか・守っていない例と守っている例・守らないとどうなるか・守るための方法」という読み進め方と、鳥とペンギンの例は、NakuRei さんの Zenn の本『SOLID原則完全に理解した!になるための本』のインターフェース分離の原則の章とSOLID原則とはの章を参考に、この連載の TypeScript で書き直しました。

まとめと、次回

第7回のまとめです。ISP は、利用側に、使わない能力まで求めないようにインターフェースを分ける原則でした。飛べないペンギンに fly を書かせるような「例外を投げるだけ」の実装は、インターフェースが大きすぎる合図です。プラグインの実物では、外の世界の能力が5つの小さな口に分かれていて、コピーの代役は write だけで書けました。全部入りの1つにすると、コピーの代役に使わない6つの中身が要り、いいねの変更にまで巻き込まれることを、作業コピーの実験で確かめました。

この回で確かめたこと
問い答え確かめ方
コピーの代役に何が要るかwrite(と、必要なら fallback)だけapplication.test.ts の代役・Node 63件が通る
全部入りにすると何が起きるか使わない6項目の中身が要り、いいねの変更で止まる作業コピーで tsc(TS2740・TS2741)
いいねの保存はどこにあるかプラグインの口の外(ページ側)promari-sns-share-like と setLikeState
どこまで分けるか一緒に必要とされ、一緒に変わる能力ごとNativeShareGateway は2項目のまま

分ける単位は、利用側が一緒に必要とする能力。使わない能力が代役や変更に現れたら分けどきで、分ける前には、つなぐ手間とも比べます。今回の実験で作った全部入りのインターフェースと、知らせの口への saveLike は、作業コピーで試しただけで、プラグインの本体には入れていません。

次回は連載2.5「DIP――ブラウザの機能を、ポートの向こうへ置く」です。今回は、ブラウザの機能を使うための口を、能力ごとに分けて見ました。次回は、そもそもなぜ内側のコードがブラウザの機能を直接呼ばず、口の向こうに置いているのかを、DIP(依存性逆転の原則)の目で確かめます。それでは、次回もお楽しみに!

連載の全体像は本編の連載目次へ。前回の2.3「LSP――Copyに「開くURL」を要求すると何が壊れるか」、2.1「SRP――一つの共有先の定義は、一つの理由で変わるか」とあわせて読むと、口の分け方が、どんな原則の上に立っているかが一続きで見えてきます。

プロマリでは、Webサイトの制作に加えて、共有や計測のような「裏側のしくみ」の設計・導入、それらを運用できる人材の育成に取り組んでいます。テストしやすい部品の分け方をチームでそろえたい方も、お気軽にご相談ください。

Web制作・計測・人材育成のご相談はこちら

COMMENTS
コメント…

この記事全体の感想・質問・設計へのコメント

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 課題・進め方をご相談
送信だけで契約やお申込みが確定することはありません。