2019-05-20

ソフトウェアアーキテクチャとは何かを考える

最近,協力会社に開発を任せていてソフトウェアの中身が分からず,意図した動きにならない(レスポンスが遅いとか,画面が思ったように遷移しないとか)という話を聞いた。

また,「ソフトウェアを継ぎ足し続けた結果,肥大化・複雑化して,原因を追及しにくい不具合が発生して困っている。リファクタリングしたい」という話も聞いた。

どちらも,ソフトウェアアーキテクチャ(構造設計)ができていない,把握できていないのではないかと思う。また,現在のアーキテクチャがシステムの用途・目的に合っていないのではないかと思う。

ソフトウェア設計のプロセス的に言えば,要求分析や実現可能性の実験(フィージビリティ・スタディ)や機能要件・非機能要件を考慮したアーキテクチャ設計ができていないとかなんだろうが,一言で言えば「アーキテクト不在」という問題が一番大きい。

アーキテクト(=建築士)不在ということが,どういうことなのかを,住宅の設計の例で考えてみたいと思う。

建設転職ナビより転載

一級建築士について
一級建築士とは、国土交通大臣から認可を受けた国家資格です。家屋、学校や体育館、商業施設や病院など、ありとあらゆる建造物の設計をします。街や村など人々の生活を豊かにしていく、私達には欠かせない大切な仕事を担っています。 安全性を考慮して建物の設計図を書き、それを元に工事を進めていきます。

試験の受験資格の面でも、一級建築士の場合は実務経験がないと受験資格を得られないという決まりがあります。二級までは、建築学部などで履修科目を学んでいれば実務経験がなくても受験資格を得ることができます。十分な経験を積み、高い知識を持ちあわせている人だからこそ、一級建築士になれるのです。

一級建築士にできること
一級建築士は、一級というだけあり、建築できる建造物に制限がありません。
二級建築士までだと、建物の高さや面積により建築できる建造物に制限があります。 二級建築士は、主に戸建住宅などの小規模な建造物のみを設計・建築できます。 また、木造建築士においては、木造の建物かつ2階建てまでの建物しか取り扱うことができませんが、一級建築士の場合、高さや構造に制限がないため、学校や病院、商業施設など大規模な設計・建築に携わることができます。

【転載終わり】

ようするに,建築士の資格を持ったものが,さまざまが建物の設計図を書き,それに基づいて工事が進められる。自分は,「大改造!!劇的ビフォーアフター」というリフォーム番組が好きでよく見ている。この番組では,いろいろな悩みを持った依頼主が,さまざまな得意スキルを持った一級建築士に家のリフォームを一任し,依頼主の悩みを解決して家を新しくする様を見る番組だ。

建て直すわけではなく骨格は残すので,大元の家の骨組みは残すが,部屋割りや構造の補強など,建築士のアイデアで大改造を行う。

ソフトウェアで言えば,ソフトウェアアーキテクト(一級建築士)がユーザの悩み事や要望を聞いて,システムのアーキテクチャをリファクタリングすることになる。

リアル建築との違いがあるとすれば,「大改造!!劇的ビフォーアフター」の場合は,リフォームした家(リファクタリングが完了したシステム)を眺めて,その出来映えや使いやすくなったところをユーザと共有し共感することができることだ。一方,悲しいかなソフトウェアの方はリファクタリングが完了しても,ユーザとその出来映えを共有・共感することは難しい。

「すばらしいアーキテクチャに変わりましたね」という感想がユーザだけでなく,プロジェクトメンバからも口々に語られることは,おそらくない。リファクタリング後に,ソフトウェアの修正が楽になったとか,デグレードが発生しなくなったとか,派生製品を作るときの開発期間が短くなったという感想は聞けるかもしれないが,しばらく時間がたたないとそういった感想にはならない。

例えば,アーキテクチャを意識せず,または,設計当初はアーキテクチャの設計思想があったのに,その後の度重なる修正によりアーキテクチャが崩れてしまった場合,各ソフトウェアモジュール間の結合が強くなり,また凝集性が弱くなることで,テストケースが爆発的に増え,デグレードや欠陥の漏れが多くなる。

ソフトウェアモジュール間の結合度が小さく,凝集が強いということは,責務が明確で他のモジュールとの関係性が小さいということだから,修正が他のモジュールに与える影響は小さくなり,また,どこに影響が及ぶかが分かり易い。(凝集が強く,責務が明確なので,その機能に責任を持っているモジュールがどこなのかがすぐに分かる)

ソフトウェアのアーキテクチャが度重なる修正により崩れていくと,納期を急ぐあまり,自分の責務ではない機能をソフトウェアモジュールに入れ込んでしまったりして,テストが終わらなくなる。納期を急いでいるため時間切れとなり,テストされていない箇所が残り後に不具合となって現れる。

ソフトウェアは見えないだけに,悪い状態もよくなったことも,分かりにくい。だから,まずは「アーキテクチャとは何か」についてイメージだけでも押さえてもらいたいと思う。




まず,実際の住宅の構造(アーキテクチャ)にいろいろな種類があることを理解しよう。住宅の構造だけでも,木造在来工法や2×4工法,軽量鉄骨を使った鉄骨軸組工法,ユニット工法などさまざまな工法がある。

それぞれの工法には特徴があって,コストや施工の早さや,間取りの柔軟性等々,ユーザの要求や懐事情によって基本構造(アーキテクチャ)も変わる。

リアル住宅の場合も完成してしまうと,構造(アーキテクチャ)がどうなっているかは外からは分かりにくい。(丸太組工法などは例外)

例えば3階建てにしたいとか,地下室が欲しいとか,間取りにこだわりがあるとか,地震に強くしたいとかいったユーザの要望によって,建築士は構造(アーキテクチャ)を選択する。

別荘に丸太組工法のログハウスを提案することはあっても,普段生活をするための住宅に丸太組工法を提案することはあまりないだろう。

問題は,ソフトウェアの場合は,丸太組工法しか知らないソフトウェアエンジニアが丸太組工法で一般住宅や雑居ビルを作ってしまうケースがあるということである。


また,よくありがちなのは,狭い敷地に雑居ビルがひしめき合っているようなソフトウェアの作りにしてしまうケースや,老舗の旅館に別館や新館を建てまして迷路のようになってしまうケースだ。

収容できるお客は増えるのだが,泊まり客へのサービスはしにくいし,メインテナンスもたいへんだ。
雑居ビルもごちゃごちゃしていて,ビルメインテナンスがしにくい。

そういうソフトウェアになってしまうのは,設計を開始する際に建築士が要求に対して適切な設計図(アーキテクチャ)を作成していないからではないだろうか。

ただ,そういった場合であっても「大改造!!劇的ビフォーアフター」のように,リファクタリングをすることは不可能ではない。

ユーザの困りごとやシステムに対する要求,シリーズ製品のラインナップ等々を調査した上で,何をどう変更するのかを考える。

その際に,何に困っているのか,どんなシステム要求があるのか,ソフトウェアが動くプラットフォームの性能などの情報がないと,適切な工法を選ぶことができない。

【この後『C/C++による組み込みソフトウェア開発技法 オブジェクト指向を取り入れた理論と実践』から適宜参照。ソフトウェアアーキテクチャを基本から学びたい方は是非読んで欲しい。】

ソフトウェアのアーキテクチャを考える上で,構造化設計の基本を押さえておく必要がある。言わば,設計士の資格を得るための基礎知識といったところ。

構造化設計では、モジュールごとに固有の機能が割り当てられているソフトウェア構造であるほど、開発や修正が容易となる。

ソフトウェア構造が適切に分割されているか判定するために、エドワード・ヨードンとラリー・コンスタンチンが,著書“Structured Design”において、モジュールの結合度(Coupling)と呼ばれる基準を考案した。

左図にモジュールの結合度と特徴を示す。ソフトウェア内のモジュール間の結合度が低いほど、独立した機能と処理を担当するソフトウェア構造を持っていることを示す。

多くのモジュールが結合度の小さいデータ結合になっていればよいが,実際にはそうはなっていない。

モジュールの結合度と,後述するモジュールの凝集度は意識してソフトウェアを設計しなければ,なかなかそうはならない。ようするに,ソフトウェアアーキテクチャを「高凝集」「疎結合」なモジュールで構築しようという設計思想がなければ自然にはそうならない。まれに,直感で修正しやすいソフトウェアを作ろうとして「高凝集」「疎結合」なモジュールを作れるソフトウェアエンジニアもいるかもしれないが少数だろう。

だから,多くのソフトウェアエンジニアは,ソフトウェアモジュール同士の関係が「高凝集」「疎結合」とはどんなことかを頭に入れておいて,できるだけモジュール間の結合を疎に,役割や責務を集約するようにしようと常に考えておく必要がある。

下記に上記のモジュール結合度のタイプ6種類を示す。







理想的には①データ結合,②スタンプ結合,③制御結合ですべてのソフトウェアモジュールが構成されているのがよいが,特にC言語で作っていると④外部結合や⑤共有結合や⑥内容結合になってしまう傾向がある。

C++のようなオブジェクト指向言語を使えば,言語仕様からして④外部結合,⑤共有結合,⑥内容結合は作りにくくなる。

次にモジュールの凝集度について説明する。

ソフトウェアの凝集度(Cohesion)は、エドワード・ヨードンとラリー・コンスタンチン、ウェイン・スティーブンス、グレンフォード・メイヤーズらによって考案されたソフトウェア機能の固有性の尺度で,凝集度が高いモジュールは、明確な責任を持ち、シンプルで独立性の高い機能を実装していることを示す。

この指標はオブジェクト指向設計の目標と一致する。
一般的に凝集度が高いソフトウェアほど保守性や拡張性が高く、再利用も容易な傾向がある。

ソフトウェアの新人技術者の教育をやっていると,機能の実現を関数を積み重ねることで作り上げていき,システムの規模が大きくなっても,そのやり方を続ける者が多い。

システムの規模が大きくなったときは,機能の実現というよりも,責務の分割という視点で設計した方が圧倒的に保守性,拡張性,再利用性が高いという実感がある。

ソフトウェアエンジニアはどこかの時点でその考え方のシフトが必要なんだと思う。そのことを『リアルタイムOSから出発して組込みソフトエンジニアを極める』に書いたつもり。

さて,ソフトウェアの凝集度(Cohesion)について見てみよう。



①暗号的凝集/偶発的凝集(Coincidental Cohesion)
  • 互いに関連のない複数の機能を含むモジュールの凝集度を指す。
  • たまたまタイマイベントによってメッセージ表示とファイル書き込みの処理が開始するため1つの関数内に両方を実装した場合などに、このような構造が現れる。
  • 機能同士はタイミングも、処理内容も、種別もまったく関連がない。そのため修正や機能追加の影響範囲が広いうえに可読性が低く、保守や修正が困難なソフトウェア構造。
②論理的凝集(Logical Cohesion)
  • 実際の内容は異なるが、同じカテゴリに属する処理を集めたモジュールの凝集度。
  • たとえばLCD表示を処理する関数に、アイコンの制御とメッセージ表示と背景画像の描画処理を実装している場合などが該当する。
  • ひとたび論理的凝集状態にあるモジュールを実装すると、関連する機能を追加する場合に分離が難しくなる。
  • LCD制御の処理やデータがすでに集まっている関数がある場合に新たに時計表示を追加しようとすると、既存処理を利用するには同じ関数内に実装せざるをえないことなる。
  • このため機能は膨れあがり、次第に修正と保守が困難になる。

③時間的凝集(Temporal Cohesion)
  • 同じタイミングで実行される処理を集めたモジュールの凝集度。
  • カーナビゲーションシステムで目的地に到着したタイミングでメッセージ表示と音声再生と画像更新を実行するために、一つの関数にこれらの処理を実装した場合などに発生する。
  • 機能的関連がないため共通化や修正が難しい。

④手続き的凝集(Procedural Cohesion)
  • 一連の処理を実行するために必要な機能を集めたモジュールの凝集度。
  • 内蔵チップを初期化する機能として、初期化開始処理・初期化完了待ち処理・初期値のデータ設定処理などを1つのモジュールに実装した場合などに発生する。
  • ひとまとまりの処理として実行されるだけで、機能同士の関連が弱いため、ある箇所を修正すると次の処理にも影響が及ぶ結果となり保守性が低下する。

⑤通信的凝集(Communicational Cohesion)
  • 同じデータを扱う処理を集めた凝集度。
  • 処理に順序性がなくデータの共通性によって結びついているため、データ構造の変更が複数の箇所に影響する可能性がある。
  • クラスによっては最適な設計の結果が通信的凝集の状態になる場合もある。

⑥逐次的凝集(Sequential Cohesion)
  • 同じデータを扱う処理を、順序性を持たせて集約したモジュールの凝集度。
  • ある処理の出力が次の処理の入力となり、処理を分離してもソフトウェアの構造が単純化されない(またはかえって複雑となる)ような機能を持つ状態を指す。
⑦機能的凝集(Functional Cohesion)
  • 1つの関数やモジュールが単一の役割と目的を持っており、固有の機能を実装する状態の凝集度。
  • クラス設計においても独立したシンプルなクラスとすることができます。
  • すべてのモジュールを機能的凝集度で実装することはできないが、可能な限りこのレベルに近づけるように検討すべき。
次に,すでに機能の積み重ねで作ってしまい大規模・複雑化してしまったシステム,バグが多く混在する未熟な組込みシステムから,システムの中で価値の高いコア資産を分離する(高凝集,疎結合にする)イメージを示す。

2005年のESEC専門セミナーで講演した内容からの抜粋。







あくまでもイメージであり,実際のソフトウェアのリファクタリングはそんなに簡単ではないが,まずはどうなっていればいいかというイメージを持つことが重要だ。

ソフトウェアシステムのソフトウェア開発に携わるソフトウェアエンジニアは,まず,ソフトウェアのモジュールを作成する際には「高凝集」「疎結合」とすべきであることを常に認識しておく。作成したモジュールが結合の分類,凝集の分類のどれに当たるのかを把握しておくとよいだろう。

そしてソフトウェアシステムのアーキテクチャを考えるアーキテクトは,システムに対する要求や条件,実現の可能性等を考慮して,どのような構造(アーキテクチャ)にするのが最適であるかを考える。その際には,今回対象の製品だけでなく,製品群で共通に使用するコアとなる資産が何になるのかを意識した方がよい。コア資産となるソフトウェアモジュールほど,高凝集,疎結合であった方が再利用性が高くなり,保守もしやすい。

リアル建築士のように,ソフトウェアのアーキテクトも必要な知識やスキルがあるかどうかを検定して一級,二級といったソフトウェアアーキテクトの資格を作った方がいいのかもしれない。

アーキテクト不在のソフトウェアシステムは恐ろしいので,ソフトウェア開発には少なくとも一人はアーキテクトを含めるようにした方がよいだろう。

「ソフトウェアアーキテクトなんかいない」という組織やプロジェクトではどうすればいいのか。それは,外部の協力会社のアーキテクトをプロジェクトに引き入れたり,メンターとなってくれるコンサルタントに支援を要請する。

ちなみに,ソフトウェアアーキテクトの素養のある人は,ソフトウェアエンジニア20人に1人くらいの割合だろうと言われている。みんながみんな一級建築士になれるわけではないのは,リアル建築と同じだ。

ちなみに,実感として,ソフトウェアアーキテクトの素養のある人が,その能力を適正に評価されているようには思えない。ソフトウェアの構造(アーキテクチャ)が良い,美しいことは,外側からはよく分からないからだろう。

「大改造!!劇的ビフォーアフター」のように依頼者が涙を流して,アーキテクトに感謝してくれるといったシーンが,ソフトウェアの世界では期待できない。

そこがソフトウェアアーキテクトの悲しいところだ。

ソフトウェアもリファクタリングは可能と書いたが,現実にはすでに出来上がってしまったソフトウェアシステムを静的な構造として解析すると(どのクラス,どのモジュールがお互いを呼び出している関係)左図の左のようになっていたりして,リファクタリングはそう簡単ではない。

全体的なリファクタリングは諦めて,後継機種を開発するときに着手しようという結果になることも多い。

本来ならば,上から下へといった呼び出し関係(上図の右)となるような,レイヤードアーキテクチャになっていた方が,保守性が高まるが,そういうアーキテクチャにしようという意図なく開発していたら,そうそう,作り直すのは簡単ではない。

最初の問題提起に戻ると,ソフトウェア開発する際に「アーキテクト不在」では何事もうまくいかず,失敗プロジェクトになってしまう可能性が高まる。

0 件のコメント: