【Swift】Swiftで学ぶ結合度

<!-- textlint-disable -->
# 結合度とは
結合度とは、モジュール同士の関係の密接さを表す尺度です。
モジュールというのは、システムを構成する要素となるもの。具体例を出すと、検索機能や登録機能などのクラスや関数を指します。

つまり、結合度とは、**モジュールの影響範囲がどれだけ狭いかを測る尺度**です。

各機能において、どこで利用されて、どこで利用されていないかを判断できるよう整理・分割がどの程度されているかを表す尺度です。

## 凝集度との違い
凝集度は、モジュール内の評価に使われるのに対し、結合度はモジュール間の相互依存性の度合いに使われます。

高凝集を意図して強く関係していそうなロジックを 1 箇所にまとめ上げようとしたものの、結果として密結合に陥るケースは多く見られます。
そのため、それぞれの概念は分離し、疎結合にしなければなりません。（**疎結合高凝集**）

## 結合度の高い・低い
この結合度は、「結合度が高い」、「結合度が低い」といった言い方で使われます。
基本的に、

- 単一の機能をモジュールにしたか
- 複数の機能をモジュールにした場合、関係性や規則性があるか
- モジュールの入力、出力に共通性、独立性があるか

の 3 つを基準に強度が決定します。

モジュールの影響範囲が狭いと 1 つの事柄に特化していることになるので、

- 可読性
- 保守性

の点から、結合度は**低い方が望ましい**とされています。

# 結合度のレベル
結合度の高さには、レベルがあります。主に 6 つ存在しており、
1. 内容結合
1. 共通結合
1. 外部結合
1. 制御結合
1. スタンプ結合
1. データ結合

があります。
内容結合の方は「結合度が高い」とされており、データ結合の方が「結合度が低い」とされています。

## 内容結合
あるモジュールと別のモジュールが一部を共有するようなモジュールの結合を指します。
高水準言語を使用したモジュールには見られませんが、アセンブラ言語などを使用したモジュールではしばしば見られます。

```swift:内容結合
private func contentCoupling() -> Void {
    let user = UserData()
    let userId = user.findId(3)
    let output = user.getFirstName(id: userId) + user.getLastName(id: userId)
    print(output)
}

class UserData{
    func findId(_ id: Int) -> Int {
        return id
    }
    
    func getFirstName(id: Int) -> String {
        let firstNameList = ["佐藤", "田中", "高橋", "本田"]
        return firstNameList[id]
    }
    
    func getLastName(id: Int) -> String {
        let lastNameList = ["太郎", "二郎", "サブロー", "四郎"]
        return lastNameList[id]
    }
}
```
(ソースコードに自信がない・・・)

## 共通結合
共通結合とは、共通域に定義したデータを、いくつかのモジュールが共同使用するような結合を指します。
「共通域に定義したデータ」の具体的な物の中に**グローバル変数**があります。
あるモジュールでグローバル変数を変更すると、他のモジュールでも変更されてしまいます。
```swift:共通結合
var globalMember: Int = 5

private func add() {
    var privateMember1: Int = 2
    let sum = globalMember + privateMember1
    print("add: \(sum)")
}

private func add2() {
    var privateMember2: Int = 3
    globalMember += 10
    let sum = globalMember + privateMember2
    print("sum: \(sum)")
}

add() // add: 7
add2() // add2: 18
add() // add: 17
```
これはイメージがつきやすいかと思います。
可変なグローバル変数はいつ何処で変更されるのかわからないのが問題です。
エラーが出た時に容疑者が多いと特定するだけで時間がかかります・・・。


## 外部結合
外部宣言されたデータを共有したモジュール間の結合を指します。
要は、**`public` 変数**のことです。
```swift:外部結合
class SampleA {
    var sampleAPrivateMember: Int = 5
    private func add() {
        var privateMember1: Int = 2
        let sum = sampleAPrivateMember + privateMember1
        print("add: \(sum)")
    }
}

private func add2() {
    var privateMember2: Int = 3
    let sampleAMember = SampleA().sampleAPrivateMember + 5
    
    let sum = sampleAMember + privateMember2
    print("add2: \(sum)")
}
```
共通結合との違いは、不要なデータを共有するか否かです。
共通結合のように、不必要なデータも共有しないので、結合度は弱くなります。

## 制御結合
呼び出し側のモジュールが、呼び出されるモジュールの制御を支持するデータを、パラメータとして渡す結合を指します。
要は `if` 文を使って、実行する処理を外部のデータによって制御している状態をさします。
```swift:制御結合
func register(userData: Data) {
    
    if userData == "japan" {
        //国内ユーザーの登録
        return
    }
    // 海外ユーザーの登
}
```
呼び出し側が、呼び出されるモジュールの論理を知っている必要があり、相手をブラックボックス化できず、結合度が強くなります。
ただ、データの共有ということではないので、共通結合や外部結合より結合度は弱いと言えます。

## スタンプ結合
共通域にないデータ構造を、2 つのモジュールで受け渡しするような結合を指します。
```swift:スタンプ結合
func findUserEmail() {
    return UserData().findByUserName(User().name)
}
```
特別問題がなさそうなコードに見えますが、`User` インスタンスを渡しているため、`User` インスタンスに依存している状態です。
そのため、`User` クラスから `name` プロパティが削除されると、エラーが発生します。

## データ結合
モジュール間のインターフェースとして、型のデータ要素だけを、パラメータとして受け渡す結合を指します。
```swift:データ結合
private func findUserEmail(name: String, id: Int) {
    let user = User()
    user.addName(name)
    user.addIdFilter(id)
    return userData().findbyUser(user)
}
```
受け渡すのがデータ構造で、その一部だけを利用します。
そのため、相手モジュール(今回は `User()`)をブラックボックス化できるので、結合度は一番弱くなります。

# まとめ：参照透過性

https://twitter.com/Ktombow1110/status/1576583557593853959?s=20&t=OJWZ6CcTYpZQ1xO4P4iSrg

違います。

ある関数が、同じ入力に対して同じ作用、同じ出力を持つプログラムを指します。
具体例を挙げると、数学には参照透過性があります。
$y = 2 x + 3$という[一次関数](https://univ-juken.com/ichizi-kansu)は、入力$x = 1$に対して、出力$y = 5$を返します。
これは、どの値でも同じ処理、同じ出力を返します。

それに対し、プログラムはグローバル変数などによる副作用により、異なる処理や値を返す場合があります。
今回の記事「結合度」で紹介した結合度の高いメソッドなどがその例です。

参照透過性のメリットは、メソッド、変数について値を参照する必要がありません。
故に、「参照について透過的な性質」→「参照透過性」ということです。

# 参考文献

https://www.amazon.co.jp/dp/4798046140/ref=cm_sw_em_r_mt_dp_PTH1ZTA90681DPKCX5AK

https://www.amazon.co.jp/dp/4297127830/ref=cm_sw_em_r_mt_dp_D5YMR4KTVMYCYY49X6R7

https://note.com/cyberz_cto/n/n26f535d6c575

https://www.momoyama-usagi.com/entry/info-software09#2-3

## 参照透過性
https://qiita.com/Yametaro/items/1de3c2b76b8a4dc2d30d

https://ja.wikipedia.org/wiki/%E5%8F%82%E7%85%A7%E9%80%8F%E9%81%8E%E6%80%A7
<!-- textlint-enable -->