OCP――共有先を一つ足したときの差分を追う
作成: / 公開: / 内容更新:
執筆:tamito0201 / 掲載・運営:プロマリ
丸い共有ボタンの裏側を掘る連載の第5回。SOLID の2つ目の原則 OCP を、本物の SNS(Bluesky)の追加を通じて確かめます。名札カード1枚で済む変化と、共通処理のコードを変更することになる変化。差分を1行ずつ追いかけ、閉じる向きは変化の来やすさで選ぶことを、図22点で読み解きます。
SRP が線を引き、OCP が足し方を決める
前回のSRPと、今回のOCPは、別々の原則に見えて、実はひと続きになっています。
SRP は、「変更を頼んでくる人(依頼主)ごとに、置き場所を分ける」という原則でした。このプラグインでは、SNS 各社の都合で変わる情報は名札カードへ、サイトの運営者の都合で変わる情報は設定ファイルへ、と分けています。
OCP は、そうして分けた置き場所に、足すための差し込み口を用意します。置き場所が分かれているから、「新しい SNS を足したい」という依頼は、名札カードの置き場所に1枚足すだけで済み、設定ファイルや共通処理には触れずに終わります。SRP で線を引いたから、OCP で「その置き場所に足すだけ」が成り立つのです。
OCP を確かめる4つの問い
ここまでの話を、コードの変更を見直すときに使える4つの問いにまとめます。同じ4つの問いで、段階1(新しい SNS)と段階3(新しい動き)を採点してみました。
問いは次の4つです。新しいファイルを足しただけか。共通処理の変更は0行か。今までのテストの期待値はそのままか。足し方が説明書などで決まっているか。4つとも「はい」なら、その変化に対しては閉じています。図7-1 のとおり、段階1は4つとも「はい」でした。段階3は「はい」が1つだけで、差し込み口の無い変化だと分かります。
差し込み口の無い変化が来ること自体は、悪いことではありません。大事なのは、その変化がどのくらいの頻度で来るのかを見て、差し込み口を用意するかどうかを決めることです。
OCP によくある3つの誤解
OCP を読むときに陥りやすい誤解を、3つ並べておきます。
| よくある誤解 | この記事での答え |
|---|---|
| 既存のコードを一行も変えてはいけない | 閉じるのは、選んだ種類の変化に対してだけ。想定の外の変化が来たら、共通処理を変更してよい |
| あらゆる変化に差し込み口を作るべき | 口を開けるたびに代償が増える。よく来る変化のためだけに開ける |
| 設定ファイルにすれば OCP になる | 設定で選べるのは、共通処理が用意した値だけ。Bluesky の例のように、用意の外の値は設定では足せない |
3つの誤解に共通しているのは、OCP を「変更しないこと」だと読んでいることです。OCP が求めているのは、変更しないことではなく、よく来る変化に対して、変更せずに足せる形を選んでおくことです。どの変化を選ぶかは、実際に来た変化を数えて決めます。
もう1つ付け加えると、OCP は、コードを書く前に一度だけ当てはめて終わりのものではありません。最初に選んだ備え方が、あとから来た変化と合わなくなることもあります。Bluesky のような SNS が次々に現れて、「タイトル+URL」の依頼が何度も来るようになったら、そのときは注文票に textWithUrl を足して、備え方を選び直します。どの変化に備えるかは、実際に来た変化を見ながら、少しずつ育てていくものなのです。
手を動かして確かめる
今回の練習は、最近足した機能の差分を、2つに分けてみることです。手元のリポジトリで、最近足した機能を1つ選んでください。次のコマンドで、足す前と足した後のあいだに、どのファイルが何行変わったかを一覧にできます。<足す前> と <足した後> には、それぞれの時点のコミット(変更の記録)の名前を入れます。
$ git diff --stat <足す前>..<足した後>一覧に並んだファイルを、「新しく足したファイル」と「今あるファイルを直したもの」の2つのかごに分けます。直したファイルのうち、在庫表のように「増えたら1行足すのが正しい」ものは、別に数えておきます。残った「直した」ファイルが、その変化に対して閉じていなかった場所です。
この記事で加えた変更の差分も、同じように数えました。
段階1は、新しいファイル1枚と、設定の1行だけでした。共通処理の変更は0です。段階2と在庫表の修正まで合わせると、8ファイル・18行の追加・6行の削除になり、その中に共通処理(ドメイン層)の変更が3ファイル入りました。どこまでが名札カードで足せる範囲で、どこからが共通処理を直す範囲なのかが、数で見えます。宿題:最近足した機能の差分を、「足した」と「直した」に分けて数える。数えた結果は、このラベルからコメントに残せます。
OCP をプラグインの形として説明し直した記事は、Robert C. Martin のThe Open Closed Principle(2014)です。Meyer の1988年の定義も、この記事に引用されています。Bluesky の投稿画面の入口は、公式ドキュメントのAction Intent Linksで読めます。「触らないはずのコードに手が入るとき」は、連載1.2でも別の角度から扱いました。if で分ける例をランクごとのクラスに置き換える流れと、「種類が増えたときに抽象化すればよい」という考え方は、NakuRei さんの『SOLID原則完全に理解した!になるための本』のオープン・クローズドの原則の章を参考にしました。
まとめと、次回
第5回のまとめです。OCP は、機能を足すことには開いていて、すでに動いているコードの書き換えには閉じている、という形を目指す原則でした。「閉じている」は「もう触れない」ではなく、「ほかのコードが安心して頼れるほど、使い方が変わらない」という意味です。Bluesky を実際に足してみると、名札カード1枚で済む変化と、共通処理のコードを書き換えることになる変化があることが、数で分かりました。
| 問い | 答え | 確かめ方 |
|---|---|---|
| 何に対して閉じているか | 新しい SNS(今ある動き・今ある値) | Bluesky を足して web/src 0行 |
| 閉じていない変化は何か | 新しい値・新しい動き | 注文票の3ファイル・動きの分岐8か所 |
| 閉じていると言える証拠は | 既存のテストの期待値を書き換えずに通ること | Node 63件がそのまま通った |
| 新しい口はいつ開けるか | 同じ種類の変化が重なりそうになったとき | 3つの問いを順にたどる |
閉じる向きは、変化の来やすさで選ぶ。よく来る変化には差し込み口を用意し、めったに来ない変化は、来たときに直します。前回の SRP で依頼主ごとに置き場所を分けたから、OCP で「その置き場所に足すだけ」が成り立ちました。
ここで大事なのは、今回の検証で加えた変更を、プラグインの本体にはまだ入れていないことです。Bluesky を足してほしいという依頼が実際に来て、同じような SNS がほかにも出てきたとき、この記事の差分は、そのまま「差し込み口を広げるときの設計図」になります。差分を数えておいたおかげで、広げるとどれだけ直すことになるのかが、もう分かっているからです。
次回は連載2.3「LSP――Copyに「開くURL」を要求すると何が壊れるか」です。今回は、動きの種類(開く・コピー・端末の共有)で分岐する8か所を、差し込み口の無い場所として見ました。次回は、その3つの動きを「同じ共有先」として取り替えられるかを、LSP(リスコフの置換原則)の目で確かめます。コピーのボタンに「開く URL」を求めると、何が壊れるのか。一緒に見ていきましょう。それでは、次回もお楽しみに!
連載の全体像は本編の連載目次へ。前回の2.1「SRP――一つの共有先の定義は、一つの理由で変わるか」、1.2「共有先が増えても触らないコードを決める」とあわせて読むと、名札カードという差し込み口が、どんな原則の上に立っているかが一続きで見えてきます。
プロマリでは、Webサイトの制作に加えて、共有や計測のような「裏側のしくみ」の設計・導入、それらを運用できる人材の育成に取り組んでいます。機能を足しやすい作りをチームでそろえたい方も、お気軽にご相談ください。
記事で追った差分を、実際のリポジトリで確かめるための資料です。











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