【読書メモ】Fundamentals of Software Architecture ~第三章 Modularity~
第三章は、Modularity(モジュラリティー)について。
MDN web docでModularityの定義をみると、以下のように説明されています。
システムのコンポーネントを分離して再結合できる程度を指しており、またソフトウェアパッケージを論理ユニットに分割することもあります。モジュラーシステムの利点は、部品を独立して考えることができることです。
この章では、モジュラリティーを理解するための三つの指標が提示されています。
cohesion(凝集度), coupling(結合度) それとconnascence(コナーセンス)です。
凝集度と結合度については、わかりやすい記事が既にあるので、ここでは飛ばします。
本記事では、残りのconnascenceについて詳しく触れていきます。
- connascenceとは
- Type of connascence
- 1. Connascence of Name (CoN)
- 2. Connascence of Type (CoT)
- 3. Connascence of Convention (CoC) / Connascence of Meaning (CoM)
- 4. Connascence of Algorithm (CoA)
- 5. Connascence of Position (CoP)
- 6. Connascence of Execution (CoE)
- 7. Connascence of Timing (CoT)
- 8. Connascence of Values (CoV)
- 9. Connascence of Identity (CoI)
- 3つの性質(Properties)
- 参考
- 英単語メモ
connascenceとは
凝集度と結合度は耳にすることも多いですが、connascenceは日本語だと情報がなかなか出てこないです。 connascenceは、Meilir Page-Jonesにより発明されたソフトウェア品質を測る指標だそうです。
coはtogather、
nascenceは'to be born' を意味するようです。
(ルネッサンス(Renaissance)は、re + nascence で復活の意味)
connascenceは複数のものが、同時に生まれるという意味になります。
では、ソフトウェア開発の文脈で、connascenceであるとはどういうことを指すのでしょうか。
connascenceの提唱者、Meilir Page-Jonesは、connascenceを以下のように定義しています。
two components are connascent if a change in one would require the other to be modified in order to maintain the overall correctness of the system.
二つのコンポーネントがconnascentである時、一方の変更が、システム全体の整合性を保つために、他方のコンポーネントの変更を要求する。
Type of connascence
次に、connascenceの種類について。全部で9種類存在するようです。
connascence.ioを元に、詳しく見ていきます。
1. Connascence of Name (CoN)
名前についての合意
function Aは、A()と呼び出す、という結合。
発見しやすく、リファクタもrenameで容易に可能。
2. Connascence of Type (CoT)
型についての合意 主に、静的型付け言語での話。例えば、以下のような例。
int age; age = 10.5 // TypeError
こちらも、静的型付け言語であれば発見しやすくリファクタも容易。
3. Connascence of Convention (CoC) / Connascence of Meaning (CoM)
意味についての合意
例えば、次のような関数はCoCによる結合を生み出す。
def get_user_role(username): user = database.get_user_object_for_username(username) if user.is_admin: return 2 elif user.is_manager: return 1 else: return 0
0, 1, 2のそれぞれの「意味」をget_user_roleを利用する側は知っている必要が出てしまう。 Enumとしてまとめることで、CoCの結合にすることができる。
4. Connascence of Algorithm (CoA)
アルゴリズムについての合意
複数のエンティティが同一のデータを扱う際にしばしば発生する。
例えば、次のようなコードは、エンコーディングがUTF-8である、という合意を元にしている。
def write_data_to_cache(data_string): with open('/path/to/cache', 'wb') as cache_file: cache_file.write(data_string.encode('utf8')) def read_data_from_cache(): with open('/path/to/cache', 'rb') as cache_file: return cache_file.read().decode('utf8')
また、サーバサイドとクライアントサイドの両方に実装される、 ハッシュアルゴリズムや、バリデーションロジックなどでも起きうる。
5. Connascence of Position (CoP)
位置についての合意
次のようなコードは、connascence of positionによって結合されている例だ。
def get_user_details(): # Returns a user's details as a list: # first_name, last_name, year_of_birth, is_admin return ["Thomas", "Richards", 1984, True] def launch_nukes(user): if user[3]: # actually launch the nukes else: raise PermissionDeniedError("User is not an administrator!") user = get_user_details() launch_nukes(user)
userというリストのうち、4つめの要素が権限を示すということを知らないといけない。 dictやエンティティにすることで、CoNの結合にすることができる。
6. Connascence of Execution (CoE)
実行順序への合意
例えば、リソースのロック/アンロックや、カプセル化されたステートマシンで起きうる。
以下のようなEmailSenderは、最後の2行が不正となる。
email = Email() email.setRecipient("foo@example.comp") email.setSender("me@mydomain.com") email.send() email.setSubject("Hello World")
このケースでは、実装箇所が近いため、発見は用意だが、 最後の2行が別スレッドで実行されるようなケース(high locality)では、発見が困難になる。
7. Connascence of Timing (CoT)
実行タイミングについての合意
例えば、複数スレッドで並行処理などで起きうる。
8. Connascence of Values (CoV)
値についての合意
例えば、以下のようなコードではArticleState.Draft
が初期状態である、という合意が元にある。
class ArticleState(Enum): Draft = 1 Published = 2 class Article(object): def __init__(self, contents): self.contents = contents self.state = ArticleState.Draft def publish(self): # do whatever is required to publish the article. self.state = ArticleState.Published
テストコードでArticleの状態をチェックする際など、Articleクラスの初期状態を知っていなければいけなくなる。 しかし、そうなるとArticleクラスの初期状態がDraftではなくなった場合、テストケースは壊れることになる。
以下のように、初期状態を示す値を持つことで、その問題を回避できる。
class ArticleState(Enum): Draft = 1 Published = 2 InitialState = Draft class Article(object): def __init__(self, contents): self.contents = contents self.state = ArticleState.InitialState
例えば、初期状態がDraftから、Preproductionになった際は、以下のように変更すればよい。
class ArticleState(Enum): Preproduction = 1 Draft = 2 Published = 3 InitialState = Preproduction
9. Connascence of Identity (CoI)
同一エンティティについての合意
一般的な例としては、2つの別々のコンポーネントが、共通のデータ構造(例えば分散キュー)を共有・更新する時など。
3つの性質(Properties)
また、connascenceは3つの性質で見ることができるようです。
- degree:より強いconnascencesは、より発見しづらく、リファクタリングしづらい。
- locality:より多くのエンティティと、connascentであるエンティティは、問題の影響が大きくなる。
- strength:Connascentな要素は、コード上で近い位置に存在する方がよい
1. Strength
Connascenceには、強度が存在し、コードはConnascenceが弱くなる方にリファクタするべきとされている。 CoNは、renameによって変更可能であるため結合が弱く、CoCはコード全体から変更を洗い出すことがより難しいため、結合は強くなる。 また、Static connascenceに比べ、Dynamic connascenceは実行時の挙動について知る必要があり、より強いconnascenceである。
2. locality
コンポーネント同士の近さ、を示す軸。 より強いconnascencesは、同一モジュール内などの近い関係では許容しやすく、 離れたコンポーネント間では、より弱いconnascencesであるべきである。
3. degree
connascenceが関与する影響度を示す軸。 結合が2つのコンポーネントに影響するのは、200のコンポーネントに影響するのかを見る。
参考
日本語での情報が少なく、あまり認知されていない(?)概念のように思われる。 以下、参考にしたリソースのメモ。
英単語メモ
■untangle (verb)
def: to separate pieces of string, hair, wire, etc. that have become twisted or have knots in them
def: to make something that is complicated or confusing easier to deal with or understand
■incarnation (noun)
def: a period of life in a particular form
def: a person who represents a particular quality, for example, in human form