決める能力

会社でも役所でも国家でも人が集まるところには、人が集まること特有の事象というのが多くあります。その中でも特に「決める」ということは、一人で何かする場合にはありえない面倒な作業です。決裁とか承認とか呼ばれるものです。

決裁とか承認は、職務権限で誰が決裁するか決まっている場合もあれば、管轄としてどこが決定するか決まっている場合もあるかと思いますが、いずれにせよ、だいたいの仕事は決めるのは自分ではなくて、他の誰かに決めて貰わないといけません。自身の行動ですら、決めることを許されないのが組織にいてつらいところですね。

決裁権を持つ人、つまり、決める人が組織や仕事に与える影響は大きくて、何かするときには、この決める人が仕事のボトルネックになってしまうことが多いです。決まらなければ進まないし、誤ったことが決まってしまえば失敗します。決めるところにいる人の能力はよく見えますし、決める人の能力は影響が大きいです。だから、意思決定をする人には能力が高い人を置くことが一般的です。マネージャは平社員たちよりだいたい優秀ですし、経営者はマネージャたちよりだいたい優秀です。一方で、能力以上の権限をもってしまった人は、能力が足りていないことが分かるので、しんどそうにしていますね。例えば、何も決まらない会議を主催する人たちとか。

観察するに、決めるというのは単なる技能で、テクニカルなものに思えます。決めれなくてしんどそうな人は救えるし、ボトルネックの問題も解決できそうに見えるんですよね。

では、ここでいう「決める能力」というのは何なのかという話でして、ちょっと分解して考えてみようと思います。

意思の決定というぐらいだから、心の中で行われることです。心の中の動きを分解するのは難しいのですが、エイヤで「気持ち」と「思考」の2つに分けます。命名がよくないですが、2つは別のものを示しています。

気持ちの問題

大きいのは気持ちの問題です。決定には「責任」が伴うので、気持ち的に責任が持てない人は決められないですね。役職的に権限と責任があっても、気持ち的に責任を負えない人は決める能力がないと言えるでしょう。

ではどうやったら気持ちがつくかというと、慣れ、あるいは訓練によって気持ちはつちかわれます。リーダーシップと言ったらいいのか、俺の責任でやるんだ、みたいな気持ちは性格の問題ではなくて、経験から得るものなのだと思います。

例えば総理大臣は賛否両論ある中で重大な決断をしているかと思います。彼の判断が正しいのか間違っているのかはここでは議論しませんが、常人があの立場にたっても何かを決断することすら不可能でしょう。少なくとも私には無理で、何も決められないかと思います。なぜ常人にはできないような重大な決断が彼にできるかと言えば、高いレベルのことを決める能力を教育だったり経験によって会得しているからでしょう。

帝王学とでも呼べばいいでしょうか。一朝一夕で身につくものではないし、訓練と言っても外から与えられるものではなくて、内から芽生えたものを繰り返すことで習得するのだと思います。経営者や政治家のレベルは常人にはおそらくたどり着けません。

しかし、全員が、経営者や政治家になるわけではないので、帝王学のレベルは無用です。自分の役職の権限のことは自分の責任で決める程度ことは、身につけようと思えば誰でも身につく、ただの技能です。

当然ながら権限以上の責任はないのだから、責任の範囲なんて怖れるに足りない、大したことのないことです。十分にコントロールできることだということに、やってみて慣れていけばいい話な気がします。車の運転みたいなものです。やっているうちにいつの間にか責任が苦痛ではなくなってきて、自然と決定ができるようになります。

思考の問題

決めようという気持ちがないと決めれないので、気持ちは大事なのですが、いざ決めるときには、気持ちや余計な感情を排して、冷静に判断をしなければなりません。確からしい判断をするためは思考の能力が必要です。決めれらたところで、その判断が常に誤っているのでは、困ります。なるべく正しかろうことを決定しなければなりません。

決める能力がない人には2つの種類がいまして、正しかろう答えは知っているが気持ち的に責任が怖いから決めたくないという人と、正しかろう答えが分からなくて決められない人がいます。前者の人は、前述の気持ちの問題でして、事故が怖いから車を運転したくないみたいなものなので、何度か乗ってみて事故なんてめったに起こらないことを知れば、運転できるようになります。

しかし、後者は、道に出れば事故を起こす状態です。何が正しいか分からないから、判断も確実に誤っている。事故を起こすから運転したくないように、何が正しいのか分からないから、決定をしたくない。これは気持ちの問題ではありません。決めさせてはならないでしょう。

ほとんどの問題は妥当な答えはあります。判断を誤らずに妥当なものを選択できるのは、思い切りの良さとかリーダーシップではなくて、思考能力の問題です。まれにトロッコ問題のような『答えは沈黙』的な場面で決断を下すこともないわけではないですが、そんなのはほとんどありません。

論理的推論によって得られた答えを、感情を排して選ぶことができる能力は、一種の論理的思考でしょうか。これも訓練でどうとでもなるし、リーダーシップなんかよりはずっと簡単に習得できるものだと思われます。

何だったら、答えを出すのは自分でなくてもいい。専門家に意見を求めてその中で妥当そうなものを、決める人は判断をすればいいだけです。ただし、専門職で自らの領域にたいして、答えは出せないなんていうの許されません。それは決めれないとかいう話ではなくて、単なる専門職としての業務遂行能力の問題かと思います。まあ社会は素人ばかりなので大した罪ではありません。


まとめますと、決定する人は上の2つができなくてはなりません。

  1. 何が正しいのかを判断する。
  2. 正しいと判断したことを、自らの責任で決める。

何も難しくないですね。決める立場の人がこれをできるようになって、何も決まらない会議とかがなくなればいいと願います。

やる順で仕上がりは決まる

仕事の出来栄えは、どのような順番でサブタスクをこなしていくか、考えていくかで大きく変わってくるように思います。もちろん、やる順番が唯一の説明変数ではありませんが、安定した仕事ができる経験豊かな人と、そうでない未熟な人、この二者の間では、明らかに手をつけていく順に違いがあります。

一般的に経験の浅い人たちは、どうやるのか想像がつきやすくて、簡単に手をつけやすいところから始める傾向があります。そして、手をつけ始めたところに夢中になってしまい、考慮していないところに大きな落とし穴があることに気づきません。後々になって問題が明らかになって、手戻りをしたり、いびつな状態で無理やり終わらぜなるを得なくなったりします。この結果、仕上がりは悪くなるのはよくあることです。

例えば、経験のない人が、設計をしてみたら、全体的には穴だらけなのに、一部はやたらと細かくなります。決まって、どこまで細かくしていいか分からないと言いながら、細かいところの議論に終始してしまいます。そもそも画面に必要な機能がふわふわしているのに、画面の絵を描いて意匠の議論が始まるなどよくあることかと思います。そして、追加要件があったときに(もとより未だ定まってないのだから追加要件ではないんだけど)無理やり画面に新しい要素を納めることになって、結果ダサくなります。

手をつけやすいところから始めるのは、何かやっていないと不安なのでとにかく進めたいと思っているからでしょう。実のところ手をつけやすいところを進めていっても、それは何かやっているフリをしているだけなのですが、なかなかこれは自分では気づかないものです。

正しいやり方というか、安定したやり方というか、老練なやり方は、簡単に手をつけやすいところからではなくて、不確実性が大きいところから解決していくものです。怪しげでリスクが高いところから潰していって、不確実性をすばやく収束させていくようにシニアな人は仕事を進めていきます。リスクを先にもってきて、後は流すだけとするのがきれいな仕事の進め方です。

不確実性が大きいところとは、利害関係者があったりして合意を取らないとひっくり返ったりする可能性があることであるとか、法務的あるいは技術的などの実現可能性に不安があったり、外部が行うので制御ができないことで不確実性が大きかったりするようなところですね。不確実性を測るのはできないので、どれが怪しいかは不安という野生の勘で決めていきます。

普通のプロジェクトマネジメントのやり方だと思いますが、これを体得するには経験を要します。不確実性に対する勘を得るにも経験がいりますし、不確実なものに立ち向かってコントロールするのは自然な心の動きに反するからです。自然にやれば、手をつけやすいところから始めたくなるのが常なので、それに反することを覚えるには訓練がいるのかなと思います。

では、シニアな人々が指導できるかというと、これも難しくて、老練な人でさえもジュニアたちと同じ罠にハマってしまってしまいます。

まず、順序のおかしい仕事でもやっているように見えちゃうんですね。3歩すすんで3歩下がるような手戻りをしていても、やっている人は6歩分仕事した気になるし、仕事をしているように見えます。手をつけやすいところから、思いついたことを思いついた順にこなしていっても、なんとなく仕事をしている気がするし、そう見える。頑張っているといって、そういうやり方を褒めちゃったりするわけです。具体的なものを尚早に求める態度を、スピード感がある勘違いしたりする。おっさんはそういう若い人が好きですよね。

また、細かいレベルの話をされたら、つられて細かいレベルの話をしてしまうものです。細かいレベルでも辻褄があってなかったら、それは正したくなる。大枠が穴だらけでも気づかない。本当は相手に引きずられずに、全体から見ていかなければならない。しかし、視点をスコープアウトさせて、見るレベルを上げる思考は、認知負荷が高くてストレスです。話を聞きながら、頭の中で抽象度を切り替えるなんて芸当はなかなかできないと思います。

そして、全体として誤っていたら、細かいところを考えたものは、心を鬼にしてすべて捨てしまわなければなりません。ちょっとでも時間を費やしたので、愛着が出ちゃっているから自らそれを捨てるのは難しいです。だから正しい考え方の順序というのを覚えていくわけです。しかし、自分のでさえためらうのに、他の人に一度した仕事を捨てさせるのは非常なストレスです。

指導、つまりコーチングをするのも、プレーヤーとしての思考ができるようになったら、自然にはできるようになるものではなくて、それなりに訓練がいるのかなと思います。どうやったらそんな人が生まれるんでしょうね。まだ考えはないです。

しかし、全員が老練であることはありえないし、老練な人だけで仕事をし続けるわけにもいかないので、コーチングができる人がいないと組織は育たないよなと思ったりします。

Clean Architecture と上流工程

Clean Architecture』を読んでいて、これを実現するには上流工程の順番で開発をすればいいのではと思いました。

https://blog.cleancoder.com/uncle-bob/images/2012-08-13-the-clean-architecture/CleanArchitecture.jpg

Clean Architecture とは上の図で説明されるソフトウェアコンポーネントの設計思想です。フレームワーク・データベース・画面などを「細かい話」として脇に追いやって、業務を中心に据えているところが特徴です。業務のモデルを表す Enterprise Business Rules が中心にあって、業務アプリケーションがする仕事を Application Business Rules として記述し、Interface Adapters が業務アプリケーションと細かい話を結びつけます。そして、Clean Architecture は、コンポーネント群のビルドの依存関係も、外側から内側にと、アプリケーションが業務に依存するようにせよと言っています。

さて、この Clean Architecture を実現するためにはどうしたらよいのでしょう。コンポーネント図を Clean Architecture に従って描いて、Clean Architecture を維持するようにコントロールをするのでしょうか。そのやり方でもよいのですけど、おそらくほとんどの人は Clean Architecture をやろうとおもったら、中心にあるコンポーネント、業務のモデルから順に考えて開発を進めるということをするんじゃないかなと思います。先に作ったものは、後に作ったものに依存されるので、自然の Clean Architecture のコンポーネントの依存関係になります。

また、Clean Architecture は細かい話を後回しにしようという開発のアプローチの方法でもあります。設計スタイルではなくて、低レベルな話からボトムアップに決めていくのではなくて、業務すなわちシステムの目的といった高レベルな話から決めていきましょうというアプローチの方法を述べているのだと思います。そのため、開発の順番で Architecture をコントロールするのが自然なのではと思うわけです。

しかし、業務を中心に考えていくのは、普通の上流工程やりかたと同じではないかとも思うわけです。

  1. 要件定義をしようとしたら、すなわち、それらが満足されたら問題が解決するのだという一覧を作ろうとしたら、まずは問題を分析して問題を理解することを試みますよね。業務アプリケーションならば、ビジネスモデルはどうなっていて、どういう登場人物がいて、彼らは何をやりとりしているのかみたいなことを読み解くことからするんじゃないかな?

  2. 問題を理解したら、次は解決策を考えます。一般には新しく機能を作るのが開発での解決策になるかと思います。新しい機能で考慮しなければならない使い方や無視してもよい使い方を勘定して機能の要件を決めます。

  3. 次は DB のスキーマを決めたり、I/F の仕様を決めたりしますね。こららを世間では基本設計というのかな。

1, 2, 3 の結果を、それぞれコード化したのが、Enterprise Business Rules, Application Business Rules, Interface Adapters に対応するのではないのだろうか。つまり、上流工程の進め方と Clean Architecture に類似性が見られます。もしかしたら、要件定義から基本設計にオーバラップして、決まっているところから結果をコードに表現していくみたいなことができるかもしれません。ただし、手戻りもするだろうし、作るのに夢中になって、何を実現べきかを考えるのが疎かになりそう。

いずれにせよ、今回気づいたのは、開発の進め方と Architecture は関連するもので、開発の進め方に応じて Architecture を決めたらいいということです。

オブジェクト指向は失敗だった

オブジェクト指向プログラミングは失敗だった――以前から思っていました。

okuranagaimo.blogspot.com

オブジェクト指向プログラミング (OOP) が人類にとって早すぎたか、人類には OOP が向いていなかった。世の中の Java で作られたプログラムのほとんどは、Java に付属する OOP っぽい機能を使うことで余計に複雑になっているように思います。ここでいう複雑さとは、頭が整理されていない状態、頭が構造化されていない状態のことです。例えば、インスタンスなんて作らずに全部 static メソッドでベタ書きされた方がよっぽどわかりやすいのに、それができてしまうからという理由で要らぬ副作用、すなわちオブジェクトの状態の変化が入りこんで、おかしなことになっている様子に出会ったことは何度となくあります。

おそらく原始的で単純な OOP で作られたプログラムはそこまで問題ではない。データ構造があって、その操作がメソッドになっている―― 例えば toString() みたいなデータ構造を変換する操作をデータ構造に集めることはおかしなことではなくて、toString() みたいな共通化された I/F が問題をシンプルにするのは疑いようのないことだと思います。そのデータ構造を文字列化したものが欲しいときに、toString() メソッドを呼ぶだけで済んだら、話は簡単になりませんか。

問題はそもそもデータ構造だけでは世界は表現できないことと、「継承」という要らぬものが導入されたことだと思います。

オブジェクト指向プログラミングでは、現実世界の森羅万象をプログラムに表現できるなんて言説をどこかでみたことがあります。しかし、それは無理です。クラスという表現の形式は、現実世界をモデル化するには十分な表現力をもっていない。そもそもプログラムとは何かを「する」ためにあるものです。何かをすることを私たちはしばしば処理といいますが、処理すらクラスで表現すると難しくなります。

ただのサブルーチン(関数)だけの方がクラスよりよっぽど処理の表現として優れています。処理をクラスで表現しようとするから、-er みたいな名前のクラスができて、処理だけするクラスの中にフィールド変数が現れて、処理の中でそれを触ったりすることが行われる。単一責任の原則にしたがって、1個の処理だけする -er みたいなクラスとは、要するに関数オブジェクトです。こんなもの作るなら、ただの関数の方がよい。

継承も同じことで、処理をする部品(メソッド)を共有したかったら、関数を別に切り出して共有すればいいだけだ。クラスである必要がない。また、階層構造のモデルで、問題を表現しきるのが難しいというのはリレーショナルデータベースを使ってたら知っているはずなのに、どうしてオブジェクトの関係を階層構造で表現したいと思うのでしょう。継承なんていらない。処理だけ欲しければ関数の方がいい。

動的に処理を切り替えたければ関数を切り替えればよい。デザインパターンっぽいものは、要するに処理を関数オブジェクト化してクラスとして切り出したら、切り替えられて便利だよねってだけのはなしです。つまり、出来の悪い関数プログラミングです。関数を値として渡せたらそれで十分だ。でも、それも下手に使われるよりはベタ書きの方がずっといい。

処理と呼ぶものは関数で事足りる。クラスはデータ型とその操作のための I/F としての役割で十分だ。

プログラミングというのはただやりたいことを順序立てて書くだけのもので、それ以外のことを考えないようにしたい。処理をオブジェクトで表現するにはどうしたらよいのだろうとか共通化するにはどうしたらよいのだろうなんて無駄なことを考えなければならない OOP は、不完全な枠組みだったと思います。

static メソッドでよいのでは?

static おじさんと呼ばれる人がいたそうだ、あるいはいるそうです。インスタンスの生成を嫌がって、何でも static メソッド にしてしまう人のことです。static メソッドと呼ぶよりも関数と呼んだ方がよいかもしれません。

インスタンスの生成を嫌がるのは、気持ちはわかります。メモリ管理が GC 任せで、速度にどう影響するかわからないのが嫌なのでしょう。現在では、細かいメモリ管理が本当に必要な場合はほとんどないので、ほとんどの場合インスタンスの生成なんて無視してよいでしょう。しかし、ひとつひとつの処理に対してコスト感覚を持つこと自体はよいことです。問題があるとすれば、その感覚が誤っていることでしょう。

ただ、おそらく static おじさんと嘲笑されたのは、コスト感覚の誤りからよりも、未知のものがわからない、覚える気がない態度からでしょう。いつか私も Java おじさんとか Linux おじさんとか言われるのかなと思うと、笑ってられません。

でも、static おじさんがどうだとか言っていた人は、本当にオブジェクト指向を分かっていたのかと疑問に思ったりもします。

役割駆動設計で巨大クラスを爆殺する - Qiita

この記事にある、コンテキストに対応する役割を振る舞うのに必要な最小限のフィールド、メソッドが定義された動名詞のクラスとは、関数オブジェクトのことではないでしょうか?関数オブジェクトとは、関数をオブジェクトにしたもので、引数に渡したりできる関数のことです。SOLID 原則の最初の一つ「Single Responsibility Principle 単一責任原則」に従っていくとクラスは、ただの関数オブジェクトになってしまうと思います。『Clean Architecture』の単一責任原則の章には下の絵が書いていました。たった一つの仕事しかしない 〇〇er は、〇〇関数と変わりありません。

f:id:fjkz:20181013155919p:plain

関数オブジェクトであれば、わざわざオブジェクトにしなくても、static メソッドでほとんど同じことが表現できます。むしろ static メソッドを使った方が、記法としてシンプルです。引用元の記事を書いた人も、Robert Martin も、static おじさん叩きなんてしてないことは念のためいっておきますが、オブジェクト指向を分かっていると思われる彼らが一周回ってたどり着いたのは、static メソッドと同じものではないでしょうか?

関数オブジェクトだと、引数に値として渡したりできる利点はありますが、コールバック関数をむやみに使う設計はあまりよい設計とは言えません。業務モデルにはほとんど使わないでしょう。また、Java 8 からは static メソッドであっても、値として渡せます。 だったら、もう関数オブジェクトを作らずに、static メソッドでよい。

データ型の表現には、インスタンスを作るクラスを引き続き使う必要があります。しかし、手続きを表現するには static メソッドでよいのです。つまり、static おじさんが正しかったのです。

具体的すぎてわからない

具体化という言葉を会社員をしていますとよく聞きます。特に企画の仕事では良く耳にします。再建策に具体性がないみたいな批判も経済ニュースではよく見ます。どうも、具体的なのは良きことで、抽象的なことは悪しきことみたいです。具体化していくのが仕事だ!といった話もしばしば聞きます。

それは間違ってはいないでしょう。抽象概念に金を払う人はいないですから、仕事でやっている以上何かしらの実体にせざる得ません。抽象概念を操っているように思える数学者でさえ、紙に書かれたものにしなければ仕事とは認められません。

仕事ならば、放っておいても勝手に話を具体化し始めます。すぐにタスクのブレークダウンを始めるし、気の早い人だったら何か「成果物」をつくり始めます。何か不安なのか、取り憑かれたように具体化が行われます。具体化とは難しくないし、それで仕事が進んでいるように見えるからでしょう。

しかし、急速に具体化が進むのは必ずしも正しいとは思わない。具体的な何かが出てきたら、枝葉末節のどうでもいい議論が始まりませんか。そもそもの目的が妥当なのかだとかを決着せずに、各論を議論して何の意味があるのでしょう。また、急に具体的な話が出てきても、何の話をしているのかさっぱりわからないのは、私だけでしょうか。

目的が不在なのは失敗プロジェクトの典型です。具体化――仕事を進めるのは、作業者が仕事をしているフリをするためにしているもので、それは仕事であって仕事でない。まして、仕事でない仕事を見て満足しているのは、マネジメントの仕事でない。

すぐに各論に飛びついて具体化を急ぐよりも、抽象的な状態で話を整理しながら、少しずつ抽象度を下げていった方がよいと思う。

イメージとしては、金属の焼きなましです。 *1 金属は急激に冷却すると、内部の組織に結晶ができて固くなるが、それぞれの結晶は勝手気ままに結晶化しているので、全体としてはひずみができます。焼きなましとは、ゆっくり金属を冷却して、ひずみがない材質をつくる方法です。各論に飛びついてすぐに具体化が始まって、全体としての整合性がない状態と焼入れは似てませんか。これを防ぎたかったら、具体化したいという欲望を抑えてゆっくり抽象度を下げていくべきでしょう。あるいは、具体化が急すぎると感じたら、手もどりをさせるか。手もどりは、焼もどしに似てますね。

抽象度を自在に移動して、適当な抽象度で議論をするのは、高度な知性で、習得したいとは私も思ってますが、なかなか困難です。それでもあえてコツをあげますと、抽象度が高いのとぼんやりふんわりしているのは違うので、抽象的であってもフォーマルに言語化をしてその抽象度でのあいまいさはないようにすることでしょう。例として適当かあやしいのものの、例えば数式モデルはいろんなものを取っ払って抽象化されていても、それ自体はよく定義されたあいまいさのないものです。具体化と同じぐらい明確化というのを企業ではよく耳にしますが、抽象も明確化はできて、そうしろと言っているのでしょう。

具体化は人間の思考のくせみたいなものであいまいなものでも自然と具体化は進みますが、抽象度を保ったまま言語化するのは頭に負担がかかる疲れる仕事です。それでも、ここを踏ん張って行うのが大事なのかなと思います。それができたら、抽象度を落としても、具体的な議論であってもどうでもいいということにはならないはずです。

結合の種類と結合度

先日に発見したモジュールの結合の定義を自身でも気に入ったので、よく知られている結合の種類をこの定義に当てはめてみようと思います。

モジュールの結合にはいくつかの種類がありまして、以下のものが知られています。

  • 内部結合 content coupling
  • 共通結合 common coupling
  • 外部結合 external coupling
  • 制御結合 control coupling
  • スタンプ結合 stamp coupling (data-structured coupling)
  • データ結合 data coupling

名前が変だし、それぞれの関係性も分かりづらいので、この分類はあまり好きではないのですが、他のもっと良い分類をしらないので、とりあえずこれを使います。

モジュール A の モジュール B に対する結合度 C_{AB} を以下の式で定義します。

C_{AB} =  - \sum_{h  \in H_{AB}} \log  \big( 1 - P_h \big)

ここで、 H_{AB}AB に対して持つ仮定の集合、P_h は仮定 h が成立しなくなる確率です。

それぞれの結合の種類が、この結合度の値にどう影響するのか考察していきましょう。

内部結合 content coupling

あるモジュールと別のモジュールは、普通はインターフェースによって接しています。Java の interface だけでなくて、関数やクラス/メソッドといった、インターフェースを定義して外部に公開できる機能がプログラミング言語には用意されています。普通の人は、この機能を使って他のモジュールと自身のモジュールを結合させます。

しかし、インターフェースという概念すら理解していない人は、それを無視して、リフレクションで private な変数を取ってきて、使ったりします。こういう他のモジュールの内部に結合するような種類を内部結合と呼びます。

インターフェースは変更をすれば、呼び出し側も変更しなければならないので、あまり頻繁に変更しようとは思いません。しかし、内部は仕事をしていれば変更されます。モジュールの内部が変更されないという仮定は高い確率で成立しなくなるので、モジュール間の結合度 C は非常に大きくなります。

プログラミング言語の機能で普通すればできないようになっているので、意図して汚く脆弱に作ろうとでもしないかぎり、内部結合をつくってしまうことはないと思いますが、決してそんなことはしてはいけません。

共通結合 common coupling

いわゆるグローバル変数を共有している状態です。グローバル変数を使うときは、他のモジュールがこちらの意図どおりにグローバル変数を書き換えている/いないことを仮定しています。この仮定は壊れやすいので、グローバル変数を共有しているモジュールの結合度は高いです。

もし、グローバル変数が immutable であれば、意図しない書き換えが起こる可能性は低いので、疎結合は保たれます。例えば、設定変数はグローバルに持っていてもよいでしょう。

外部結合 external coupling

2つのモジュールが、ファイルやプロトコルといったもので結合している状態です。モジュールというかシステム/サービスの結合の話のようです。これだけ毛色が異なります。

なお、出典によって、例えば 『ずっと受けたかったソフトウェア設計の授業 』と wikipedia 、意味が違うのですが、wikipedia の方を採用しました。原典に当たるほどでもないし、正しいとかないので。

制御結合 control coupling

あるモジュールが他のモジュールの動きを制御している状態です。例えば、クラスに○○モードみたいな名前の変数があって、それを変えると動きが変わるような場合です。

制御する方は制御される方がどう動くのか知りすぎた状態になるので、この2つのモジュールの結合度はやや高くなります。抽象化が十分でなくて、中身が漏れているイメージですね。制御用の変数が増えて、変な if 文が追加されていきそうなのが、想像できます。この場合は、制御する方もされる方も不安定な I/F に依存していることになります。

インターフェースを抽象化して、ポリモーフィズムなどを使って、知り過ぎない状態にするのが解決方法です。

スタンプ結合 stamp coupling (data-structured coupling)

なぜスタンプなのかはよく分かりません。データ構造で結合している状態とは、引数や返り値に独自に定義したクラスなどを使って、それで2つのモジュールが通信している状態などです。必ずしも悪いわけではないが、不必要な型で結合するのは、要らない仮定を持ち込むことになります。仮定の数が多ければ結合度が高まります。

1つのフィールドしか要らないのに、データ構造を丸々渡してしまうのは、良くないでしょう。例えば、 this を引数に渡すのは乱暴さを感じませんか?

また、引数には複数の値が渡せますし、返り値としても Python などは多値を返せます。意味もなく型を共有せずに、基本的な型だけのインターフェースの方が、使いやすくなることもあるということは知っておいた方がよいでしょう。

データ結合 data coupling

必要なデータだけを交換して結合している状態です。要らない仮定がなくて、仕様が安定している状態なので、結合度が低いです。