なぜソフトウェアアーキテクチャ設計が重要か:車載開発における品質要求と設計の考え方
はじめに
車載ソフトウェア開発に関して、ソフトウェアアーキテクチャ設計の重要性と難しさについて、日頃から感じていることについて記述します。
Automotive SPICE v4.0 のソフトウェアアーキテクチャの仕様化に関する記述
Automotive SPICE v4.0 の 「SWE.2 ソフトウェアアーキテクチャ設計」 では、ソフトウェアアーキテクチャの仕様化に関して以下の2個の基本プラクティス(BP)が規定されています。

ソフトウェアアーキテクチャ設計とは
ソフトウェアアーキテクチャ設計は、エンジニアが実施すべき重要な作業であり、具体的には製品に必要な品質をバランスよく実装するために、すべての品質特性を考慮し、ソフトウェア全体をどんな構成にするか、どのようなメカニズムで動作させるかを設計する作業です。 ソフトウェアに対する要求には大別して以下の2つのカテゴリーがあります。
- 機能要求 :ソフトウェアが実現するべき機能(振る舞い)を規定したものです
- 非機能要求:包括的な用語であり、具体的には機能以外の品質要求や制約事項等が該当します
非機能要求は機能以外のすべて要求を包含すると考えれば、概ね 「非機能要求=品質要求」 と考えても良いでしょう。 一般的に、非機能要求という言葉はあまり使われていませんが、Automotive SPICE では、あえて非機能要求という言葉を使っています。 非機能要求に関しては、以下の記事も参考にしてください。
ISO/IEC 25010:System and software quality models では品質を以下の8個の品質特性で定義しています。

一般的に、ソフトウェア開発プロジェクトでエンジニアがまず最初に着目するのは、どんな機能(機能要求)を開発するかという事だと思います。 機能要求はソフトウェアに要求する機能やサービスなので、利害関係者は明確に要求し、エンジニアは優先的に要求内容を確認すると思います。 しかしながら、品質要求は抽象的な記述や省略されるケースもあるため、この場合はエンジニアが善意をもって開発する製品(ソフトウェア)に実装すべき品質要求定義し、利害関係者と合意しておく必要があります。
車載ソフトウェア開発におけるアーキテクチャ設計に対する課題
ソフトウェア工学では、開発要求を総合的に分析して、ソフトウェア全体の構造(静的側面)や動作/アルゴリズム(動的側面)を決定して、ソフトウェアアーキテクチャ設計書を作成し、そのソフトウェアアーキテクチャの上で要求された機能を実現していくことが求められています。 SDV時代になってソフトウェア規模は巨大化しており、高品質ソフトウェアを開発するためのソフトウェアアーキテクチャの重要性は増大しています。 しかしながら、車載ソフトウェア開発では、母体とするソフトウェア全体に対するアーキテクチャ仕様書がないケースが見受けられます(システム制御仕様書がソフトウェアアーキテクチャ設計書代わりに参照されているケースもあります)。 信頼できるソフトウエアアーキテクチャ仕様書がない環境では、開発者は要求機能毎に個別ソフトウェアを設計するスタイルにならざるをえないというのが、車載ソフトウェア開発の現状課題のひとつではないでしょうか?。 Automotive SPICEの要求に答えるために、無理やりソフトウェアを構造化しているような取り組みも見受けられます。 ソフトウェアアーキテクチャ設計に関しては、以下の記事も参考にしてください。
以下にアーキテクチャ設計事例(課題のあるアーキテクチャ設計事例と改善事例)を紹介します。
ソフトウェアアーキテクチャ設計の事例紹介1(動的側面)
-
要求機能
- ECU は空き状態で起動信号を受信したら機器1、2、3を起動する
- すべての機器の起動が成功した場合は緑ランプ点灯し、運用中状態にする
- 起動失敗機器がある場合、障害表示と赤ランプ点灯し、運用中状態にする
-
要求通りソフトウェア実装した、よくある事例
- 要求機能の順序通りにソフトウェア動作を設計する
- 複数機器をシーケンシャル起動する制御方式を採用する

-
筆者見解
- この処理方式では3つの機器に対して順次起動するので、各機器に起動信号送信から応答信号を受信するまで、ECUでは計3回の機器起動待ち時間が発生するので、信号A 受信からランプ点灯までのレスポンスタイムが長くなるというデメリットがあります
- 要求機能に記載内容をそのまま上図のように単一タスクで実装すれば、ソフトウェアアーキテクチャを意識せず、要求機能を簡単にソフトウェアで実現できます
- ECUは、この単一タスク実行中(3回の機器起動待ち時間を含めて)は、他の処理を実行できません(タスク実行中のため、他の信号受信等のタスクはすべて待ち合わせになります)
- プロトタイプや PoC(Proof of Concept:概念実証) 開発では、正常機能の動作確認優先で、開発コスト削減/期間短縮のために動的側面を考慮しないケースでは、この処理方式でも問題ないでしょう
-
性能品質を考慮したソフトウェアアーキテクチャ設計の事例
- 信号A 受信からランプ点灯までのレスポンスタイムを短縮する
- 複数機器をパラレル起動する(機器起動待の発生箇所を1回にして待ち期間を短縮)
- パラレル制御を実現するアーキテクチャ(例:状態遷移モデル)を採用する
- 各機器からの起動完了信号をランダム受診時の処理を考慮する
- 起動 NG 受信、起動完了信号タイムアウトした時の処理を考慮する

-
筆者見解
- 3つの機器を同時に起動して、一番起動時間の長くかかる機器からの応答を待ってランプ点灯できるので、ECU 待ち時間は、最大1/3 に短縮できるという大きなメリットがあります(ECU 自体の処理時間は起動待ち時間に比べて非常に短いため無視している)
- 3つの機器に対して処理を並行実施して応答待ちする必要があるため、これらの信号受信を並行処理するためにソフトウェアアーキテクチャが複雑になります
- ECUが起動待ち状態でも、他の信号受信やタイムアウト等発生時のタスクが実行可能です。
- 商用ソフトウェア開発では、エンドユーザの使い勝手や「性能を重視する必要があるので、レスポンスタイム短縮という品質(性能効率性)の実装は非常に重要です
ソフトウェアアーキテクチャ設計の事例紹介2(静的側面)
-
要求機能例
- 信号 A を受信したら、処理 1、処理 2、処理 3 を実施する
- 信号 B を受信したら、処理 4、処理 5、処理 6 を実施する
- 信号 C を受信したら、処理 7、処理 8 を実施する
-
ソフトウェアを単純構造化した、よくある事例
- 信号A、信号B、信号C 受信時のタスクを個別に順次作成する
- 各処理のかたまりを関数にして、「タスク群」と「関数群」に分離する

-
筆者見解
- タスク群と関数群に分離して、見かけ上はソフトウェアを構造化しているように見えますが、実質的にはタスク中に各処理 BOX を、関数形式で埋め込んだだけです
- タスクで制御するデータと関数で制御するデータは、階層化されていません(すべての関数はタスク固有なので、タスクと関数でデータを階層化する必要性もありません)
- すべての関数はタスク固有処理となるため、ソフトウェア部品としての再利用性はありません
- 同じような処理が、複数の関数に存在してしまうことで、機能追加/変更時に影響範囲が発散する可能性が高いため、保守性に課題があります
- プロトタイプ開発/PoC 開発でのソフトウェアアーキテクチャを考慮しないケースでは、このような構造化でも問題ないでしょう
-
再利用性やデータ構造化を考慮したソフトウェアアーキテクチャ設計の事例
- 信号 A、B、C を受信時の処理1~8を総合的に分析し、共通処理/機能を抽出し、それらを4個の共通関数(W、X、Y、Z) にまとめ、定義する
- 共通関数で処理できない固有部分はタスク側で処理する
- 受信信号毎の処理差分を、関数側で制御できるように、タスク群と関数群間のインタフェース(共通関数の入出力パラメータ)を定義する
- タスク側で制御するデータと関数側で制御するデータを分離(階層化)する

-
筆者見解
- タスク固有部から関数CALL時に、固有情報を入力パラメータとして引き渡すことで、共通関数化しているため、タスクと関数が階層化(構造化)されています。
- タスク制御するデータと関数制御するデータは分離(構造化)されています
- 共通関数は独立したソフトウェア部品として、再利用性が高くなっています
- 個別タスク側の機能追加/変更と、共通関数側の機能追加/変更が、独立して実施できるので機能追加/変更の影響範囲が局所化され、保守性が高まっています
- 商用ソフトウェアでは、将来の機能追加/変更時の響範囲が局所化や保守性を重視し、個々の要求毎に逐次ソフトウェアを開発するのではなく、類似する要求を総合的に分析し、どのようなソフトウェアアーキテクチャにすべきかを決定する必要があります
ソフトウェアアーキテクチャ設計における留意点
個々の要求機能毎に逐次ソフトウェアを開発するのではなく、要求の集合ととらえて俯瞰し、どのようなソフトウェアアーキテクチャにすべきか決定する必要があります。 参考までに、静的側面のアーキテクチャとして、AUTOSAR のレイヤー構造図とアプリケーションソフトウェアの構造図の事例を紹介します。

さいごに
Automotive SPICEのSWE.2は、ソフトウェア工学をマスターしたエンジニアがソフトウェアを開発する際に、当然実施しているはずの活動や成果物を要求しているだけです。
-
ソフトウェア要求に基づいて、適切なソフトウェアアーキテクチャを採用している
- ソフトウェア全体の構造(ソフトウェア構成図 etc.)を設計する(静的側面)
- 外部インタフェース、コンポーネント間インタフェースを設計している(静的側面)
- ソフトウェア全体構造上での、ソフトウェア動作(シーケンスチャート、状態遷移図/遷移表 etc.)を設計している(動的側面)
- 上記のソフトウェアアーキテクチャ設計を文書化している
運用実績のある既存ソフトウェアを母体として機能変更/追加する場合、あまりソフトウェアアーキテクチャを意識しなくても詳細設計を実施できることもありますが、既存ソフトウェアアーキテクチャが理解不十分だと、機能変更/追加に対する適切な追加/変更箇所の特定や影響範囲分析は困難です。 また、Automotive SPICEの要求に答えるためだけに、ソフトウェア工学に基づかないアーキテクチャ設計(=名ばかりのアーキテクチャ設計)を作成しても、利用価値がありません(誰も参照しない)。 ソフトウェア工学に基づいた、信頼できるソフトウェアアーキテクチャ設計書を整備・更新しておくことは、追加/変更箇所の特定や影響範囲分析やソフトウェアの保守作業を効率化し、設計品質向上に大きく貢献します。 ソフトウェアアーキテクチャ設計の重要性を認識し、要求された機能だけに着目するのではなく、他の機能要求や実現すべき品質要求もバランス良く考慮した上で、アーキテクチャを重視したソフトウェア開発を心がけてください。
(海農 公宏)