マイコン入門 モジュール分割手法を使ったシステム構築の考え方

マイコン
この記事は約7分で読めます。

C言語学習編を終えた皆さんは「こんなものが作りたい!」と思っているものがあっても「で、結局どうやって作り始めればいいの?」と感じてはいないでしょうか。

ソフトウェアシステムとは言語的な知識だけでは作ることはできません。言語知識以外にソフトウェアシステムを構築する技術も必要となります。

本章ではソフトウェアシステムをどのような考え方で作り上げていくのかを解説します。次章移行にて、その作り上げていく流れを具体的に体験していただきます。

スポンサー

モジュール分割によるソフトウェアシステム構築方法

マイコン入門編ではより実践的なソフトウェア開発を学びます。C言語入門編のヘッダファイルとソースファイルの書き方と分け方の章にて機能分割の解説を行いました。その続編と捉えてください。

システム設計を行うとは

当たり前のことですが、ソフトウェアシステムは規模が大きくなるほど作り上げるのが困難になっていきます。それは建築において犬小屋を作るのと豪邸を建てるのでは難しさが違うのと同じです。

ソフトウェアの世界でも、巨大なシステムを犬小屋のように行き当たりばったりで作っていくと規模が大きくなるにつれてシステム構成が破綻に向かいます。それを防ぐためにはしっかりと全体を見極めて、システムを設計する技術が必要となります。それがモジュール分割技法です。

ソフトウェア開発におけるモジュールとは

我々の身近に存在するあらゆる製品は様々な部品から構成されています。例えば自動車ではエンジン、タイヤ、フロントガラス、ミラー、ボディー、ブレーキ、ミッション・・・など様々な部品同士を結合して大きな一つの自動車を作り上げています。

各部品を独立して作り、出来上がった部品同士を結合することでひとつの大きな製品を作ることはモノづくりの世界で当然のように行われてきたことです。

ソフトウェアにおいても作成工程は同じです。目的のシステムを作るためにシステムに必要な部品を設計し、部品同士を組み合わせることでより大きなシステムを構築していきます。この部品のことをモジュールと呼びます。

ソフトウェアの世界も部品を組み合わせてモノづくりを行う。プログラムを部品というイメージで捉えられることが大事!

機能とモジュールの関係

システムを設計する際に機能という単位でシステムを捉える視点で見るとよいでしょう。抽出した機能はモジュールというソフトウェア部品として具現化します。

このように作りたいと思い描いたシステムを少しずつプログラムという形に近づけていきます。

システム規模にもよりますが、基本的にはこのモジュールという部品に対してソースファイルとヘッダファイルを1つずつ配置します。そしてモジュール同士で関数を呼び出しあう形でシステムを構築します。

ソフトウェアシステムのモジュール構成

作成したいシステム全体のモジュール構成ですが、ビルのようにくみ上げるのが一般的です。組み込み開発の世界で最も基本的なのが、次の3階層構造のモジュール構成です。

モジュールはこのように階層建てにし、上位モジュールから下位モジュールに対して関数呼び出しを行うことを想定して構築します。

数千~数万ステップ程度のシステム規模であれば、おおよそこの構成で対応可能です。数十万ステップなどの規模になると更に階層を分離して4階建て、5階建てといったモジュール構成にすることもあります。各階層の主な位置づけは次のものになります。

アプリケーション層

システム全体を統括するソフトウェアモジュールを配置する。対象システムそのものを表現する階層。ユーザーからの操作に従い、デバイスドライバ層のモジュールへ指示・要求を行うことでシステム全体の挙動を決定する。

デバイスドライバ層

ハードウェアを制御するためのソフトウェアモジュールを配置する。下層にいるハードウェアに対してレジスタを経由して指示出しを行う。基本的には1つのモジュールで1つの種類のハードウェアを制御するが、場合によっては1つのモジュールが複数のハードウェアを制御する場合もある。

ハードウェア層

対象システムを構成するハードウェアモジュールを示す。ボードに搭載された周辺機器などのハードウェアが配置される。デバイスドライバのソフトウェアからの指示に従い反応する。

スポンサー

モジュール同士をつなぐインターフェース

モジュールはソフトウェアにおける部品です。部品はお互いを結合しあってより大きな部品になり、全てが結合されてひとつの製品になります。

インターフェースとは

モジュール同士を結合するジョイント部分をインターフェース(I/F)と呼びます。ソフトウェアの世界でのインターフェースの実体は関数のことです。

インターフェースという関数をモジュールで定義し、もう片方のモジュールからインターフェースを呼び出します。これがソフトウェア世界のモジュール結合になります。

「それってただの関数呼び出しじゃないの?」そう思われた方、その通りです。関数を呼び出す側と呼び出される側が異なるモジュールの場合、その関数のことをインターフェースと呼ぶのです。

インターフェースという関数仕様をしっかりと定義することは多人数開発や大規模開発では非常に重要なものです。モジュールは複数の人でソフトウェアを作り出すうえでの仕事分担の境界線であり、インターフェースはモジュール同士が連携する手段なのです 。

インターフェース設計の難しさ

インターフェースとは関数ですが、関数の仕様とは関数名、引数、戻り値、処理概要で構成されます。プログラムにおいてこの設計パターンは無限にあるため、自由度が高く様々な形として作りだすことができます。

しかし、この自由度こそがソフトウェア設計の難しい部分でもあります。

技術レベルに差がある2人がいた時に、同一モジュールの設計をしても全く異なるインターフェースになることは珍しくありません。技術者によってインターフェース設計の良し悪しが露骨に浮き出てきます。

初めから上手に設計できる人はいません。設計を何度も経験することで少しずつ形の良い設計を学んでいくのです。本サイトで経験を積んでいきましょう。

設計の経験を多く積むことで、より良いモジュール設計ができるようになれ!

スポンサー

Q&A:モジュールに関するよくある質問

モジュールという単位でソースファイルとヘッダファイルを1つずつ作ればいいということでしょうか?

本サイトで学ばれている方はまずはこの考え方であっています。ただし、これはあくまでも基本形と考えてください。

大規模な開発ですと1つのモジュールの中に複数のソースファイルとヘッダファイルを管理させることも珍しくありません。システム規模により様々な形態で開発を行うことになります。

インターフェースは関数であるということですが、モジュールで定義した関数は全てインターフェースということですか?

それは少し違います。

インターフェースとは他のモジュールとジョイントするための関数です。モジュールの中にはそのモジュール内からしか呼ばれない非公開の関数もあるのです。

インターフェースは他のモジュールから呼ばれる性質上、一度定義すると関数仕様を変更することが難しくなります。例えば、「引数を1つ追加したい」となった場合に他モジュール側の関数呼び出し箇所の修正が必要となります。

大規模開発では他モジュールが自分以外の担当者であることが普通のため、簡単に修正できないこともあります。そのため、インターフェースの関数仕様は将来性なども含めて引数や戻り値の構成などをしっかりと吟味して決定する必要があります。

階層建てのモジュールにおいて上位モジュールから下位モジュールのインターフェースを呼び出すとされています。下位モジュールから上位モジュールのインターフェースを呼んではダメなんでしょうか?

はい、呼ばないように設計します。

C言語という言語的な観点から言えばもちろん関数を呼び出すこと自体は可能です。

しかし、ソフトウェア構造的にはよくない設計になるのです。モジュールにはモジュール結合度と呼ばれるソフトウェア品質の基準があり、モジュール結合度は小さいほど良い設計とされます。結合度が小さいほどモジュールという部品の独立性が高いことを示します。

下位モジュールから上位モジュールの関数を呼び出すと2つのモジュール結合度が高くなります。理由は関数を呼ぶという行為はリンカによってモジュールが結合されるからです。

上位モジュールと下位モジュールがお互いの関数を呼ぶということは、お互いが相手を掴み合うことと同じです。このようにするとモジュールの切り離しが困難となり悪い設計になるということです。

よって、上位モジュールからのみ下位モジュールのインターフェースを呼び出すことで、切り離したい時は上位モジュールを自由に引きはがすことができるのです。