[ アーキテクチャ適応度関数 Part.1 ] 適応度関数の分類ついてまとめてみた

## はじめに
以下書籍を読んでいてアーキテクチャ適応関数という概念に出会った。
DDDやレイヤードアーキテクチャなど複雑で、維持が困難な設計思想に関心を持っているので
何かの役に立つと思い調べてみることにした。

https://www.oreilly.co.jp/books/9784814400065/

### 対象読者
- アーキテクチャの維持に困っている人
- CI / CDでアーキテクチャを管理したい人
- コードレビューの負担を軽減したい人

### 注意書き
この分野に関してはネット上に知見が少ないゆえ、私が間違った認識を持っている可能性があります。
上記を了承した上でご拝読お願いいたします。


## アーキテクチャ適応度関数
### アーキテクチャ適応度関数とは
オライリーではアーキテクチャ適応度関数を以下のように定義している

https://www.oreilly.com/library/view/untitled/9784873118567/ch02.xhtml#:~:text=%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%E3%81%AE%E9%81%A9%E5%BF%9C%E5%BA%A6%E9%96%A2%E6%95%B0%E3%81%AF%E3%80%81%E3%81%82%E3%82%8B%E3%82%A2%E3%83%BC%E3%82%AD%E3%83%86%E3%82%AF%E3%83%81%E3%83%A3%E7%89%B9%E6%80%A7%E3%81%8C,%E7%9A%84%E3%81%AA%E6%8C%87%E6%A8%99%E3%82%92%E4%B8%8E%E3%81%88%E3%82%8B%E3%80%82&text=%E3%81%93%E3%81%AE%E9%81%A9%E5%BF%9C%E5%BA%A6%E9%96%A2%E6%95%B0%E3%81%AF,%E3%82%84%E7%B5%84%E7%B9%94%E3%81%AB%E3%82%88%E3%81%A3%E3%81%A6%E5%A4%A7%E3%81%8D%E3%81%8F%E7%95%B0%E3%81%AA%E3%82%8B%E3%80%82　

上記やその他参考文献から私は以下のように解釈している。
`コーディング規約やアプリの弾力性、パフォーマンスのような設計や品質の指針がどの程度守られているかを評価するテスト`

類似の概念として**アーキテクチャテスト**が存在するが、
私はこれをアーキテクチャ適応度関数のサブカテゴリとして解釈している。

https://speakerdeck.com/kawanamiyuu/jjug-ccc-2019-spring

### メリット & デメリット
* **メリット**
    * コードレビューを半自動化できる
    * 設計思想の属人化を防止できる
    * リリースによる品質の低下を検知できる
* **デメリット**
    * やりすぎるとシステムの柔軟性を失う
    * やりすぎると開発者にストレスを与えてしまう。


## 適応度関数の分類
### 静的 or 動的
#### 静的
コンテキストに依存しない結果を検証する適応関数。
アーキテクチャテストなど、状況に依存しない結果を返すものがこれに該当すると思われる。
サンプルとして以下のような適応関数があげられる（未検証）
```java
public class ArchUnitTest {
    // CommandServiceではdaoを使用してはいけない
    @Test
    public void CommandServiceClassShouldNotUseDao() {
        JavaClasses javaClasses = new ClassFileImporter().importPackages("example");
        ArchRule rule = noClasses().that().resideInAPackage("..infra.dao..")
                            .should.onlyBeAccessed().byClassesThat().resideInAPackage("..service.command..");

        rule.check(javaClasses);
    }
}
``` 

#### 動的
コンテキストに基づいた検証結果を返却する適応度関数。
「同時接続ユーザーが`平常時平均+X`となったときユーザー単位のパフォーマンスが`Y％`以上低下しないことを確認する」
のように状況に応じた検証結果を返却する適応関数がこれに該当すると思われる。


### アトミック or ホリスティック
#### アトミック
単一のアーキテクチャ観点でのみ検証を行う適応関数。
たとえばアジリティの観点からコンポーネントのステートメント数を統制したい場合に使用できる
`いかなるコンポーネントも平均サイズから＜標準偏差に基づく閾値＞に収まっていルことを確認する適応関数`
などもアトミックなものに分類できると私は認識している。

#### ホリスティック
複合的なアーキテクチャ観点から検証を行う適応関数。
連動するアーキテクチャ特性について顕彰を行うことが多い。
例えば拡張性(Scalability)と弾力性(Elasticity)の関係を検証する適応関数がこれに該当する。
多数の同時接続ユーザーをサポートすると、急激なユーザーの増減に対応できなくなる場合があるように
拡張性のあるシステムが弾力性を兼ね備えてるとは限らない。
しかし弾力性のあるシステムは拡張性を兼ね備えている必要があるので
これを複合的に確認する関数はシステムの品質を維持していく上で非常に重要である。
このような連動・相反するアーキテクチャ特性の組み合わせがアーキテクチャに悪影響を与えていないこと
を確認する適応関数をホリステックなものに分類できると私は認識している。


### イベント式 or 継続式
<iframe width="560" height="315" src="https://www.youtube.com/embed/Zm8NSJ_Prd8?start=379" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen></iframe>

#### イベント式
PR作成時など、あらかじめ決められたイベントが発生した場合のみの実行される適応度関数。
これに該当する適応度関数は必ずプロダクション環境にデプロイ前に実行されなければならない。

プロダクションにチームの指針に合わないコードがデプロイされないメリットがある一方で
テストのため弾力性のような複雑なシナリオを検証するには、
テストケース・データの作成・維持が必要となり、非常に大きなコストがかかる。

#### 継続式
プロダクション環境で継続的に実施される適応度関数。
DataDogやCloudWatchのような監視ツールを用いて、アーキテクチャ特性を検証する。

テストデータを必要としないため、維持が容易なことがメリットとして挙げられる一方で
プロダクション環境に基準を満たしていないアーティファクトがデプロイされてしまうというトレードオフが存在する。
また将来的に発生するかもしれない事象に対してのテストを行うことができないこともデメリットであると考える。



## その他参考文献
### 記事
https://continuous-architecture.org/docs/practices/fitness-functions.html

https://www.thoughtworks.com/insights/articles/fitness-function-driven-development

https://product.10x.co.jp/entry/fitness-function-in-stailer

https://www.infoq.com/jp/news/2019/04/fitness-functions-architecture/