ソフトウェア構造の基本概念
ソフトウェアの開発に興味を持って学習してみたいと考える人にとって、ソフトウェア構造の基礎概念を把握しておくことは重要です。
ソフトウェア開発は分野やスコープが多様で、分野やスコープによって異なる技術や前提知識に基づいた解説がなされることが多くあります。この記事では、そうした分野やスコープに依存しない本質的なソフトウェアの基本概念について説明してみたいと思います。
■ソフトウェア構造の基礎概念の概要
ソフトウェアの基本要素は、データと処理手続きです。そして、データを入れるための空間と、処理手続きを行うための実行単位があります。
このうち、処理手続きを記述したものが、プログラムになります。一般的にソフトウェア開発はプログラミングという言葉で表現されますし、その成果物として目に見える形で存在するのはプログラムですので、どうしても処理手続きにばかり焦点が当たってしまいます。
しかし、ソフトウェアの構造をしっかりと理解するためには、プログラムで表現される処理だけでなく、その処理手続きを行うための実行単位、そして、ソフトウェアで扱うデータと、データを入れるための空間という4つの要素を把握する必要があります。
今からソフトウェアを設計するのであれば、実行単位は何処にいくつ必要で、実行単位間でどうデータをやり取りするのかを考える必要があります。また、データ格納空間もどこにいくつ必要で、データ格納空間をどの実行単位がどのように読み書きするのかを考える必要もあります。
既存のソフトウェアやプラットフォーム、フレームワークを扱っている場合は、実行単位、実行単位間のやり取り、データ格納空間、実行単位との関係を把握することが重要です。
■計算処理ソフトウェアの例
ここで簡単なソフトウェアの例を示しながら説明していきます。
例として、売上の合計値を計算するソフトウェア、というものを考えてみます。
図1に売上の合計を算出するソフトウェアの例を示します。左上の画面イメージのように、入力された複数の売上を示すデータ1~データ3の合計を、データ4として計算することがこのソフトウェアの目的になります。
図の右上にプログラムの例を示しました。処理手続き1に記載しているように、内部に持っているデータaに対して、データ1~データ3を順番に加算していくことで合計値を求めます。そして、最後にデータaをデータ4にコピーすれば、目的を達成できます。
このプログラムを考える時、処理手続きとデータに焦点があたり、実行単位や格納空間はあまり意識されません。プログラム上でも、これらは表現されていません。
しかし実際にソフトウェアとしてこのプログラムが動作する際には、図1の下のように、処理手続きを実行する実行単位1が存在しなければなりません。また、データ1~3の格納空間(入力)、内部のデータaの格納空間A、データ4の格納空間(結果)といった、格納空間が存在しなければなりません。
このように整理すると、単に合計値を算出するという非常にシンプルなソフトウェアであっても、ソフトウェア構造を明確に理解していないと、プログラムが何を行っているのかの理解が難しいことが分かります。
■操作と表示を伴うシンプルなソフトウェア構造
このソフトウェア構造の図を見ていると、気がつくことがあるはずです。入力となるデータ1~3はどこから入力されて、データ4はどこに出力するのでしょうか。
売上の合計を計算するプログラムが欲しいと考えた人は、プログラムの中にデータ1~3を書いて、プログラムの中にデータ4があれば良いと考えているでしょうか。そんなことは無いはずです。
おそらく、キーボードやマウスの操作でデータ1~3を入力し、その結果をディスプレイで表示したいと考えるはずです。
図2に、操作処理手続きと表示処理手続きを加えたソフトウェアの構造を示します。先ほどの処理手続き1の前に、キーボードやマウスからデータ1~3を操作する処理手続きを加え、処理手続き1の後にディスプレイへデータ1~4を表示する処理手続きを加えました。これで、図1の左上に示した画面イメージでのデータ入力と結果の表示が出来るでしょう。
このソフトウェア構造では、実行単位1が、操作処理手続き、処理手続き1、表示処理手続きを一連の処理手続きとして実行します。処理手続き1が3つのデータの合計を求めるだけの非常に短い時間で終わる処理手続きであるため、特にこのソフトウェア構造でも困る事はありません。
しかし、処理手続きの部分に機能を追加したり、膨大な売上データの集計処理が出来るように拡張していくと、問題が生じます。
まず、処理手続き1の部分に時間がかかると、マウスやキーボード操作を行ってから、データ1~3が画面表示に反映されるまでの時間が長くなり操作に違和感が出てきます。また、データ1~データ3に関係のない操作を行おうとしても、実行単位1が処理手続き1を実施しているため、終了するまで他の処理手続きを一切行う事ができません。
より細かい点で言えば、一度データ1~データ4を画面表示した後、他のウィンドウがその上に移動したり、ディスプレイが省電力のためにOFFになった場合、再度、表示処理手続きが実行される時まで、データが画面から消えてしまう事になります。
■操作と表示を伴うソフトウェア構造の改善
これらの問題を解消するために、通常の操作と表示を伴うソフトウェアは、図3のように実行単位を複数に分けます。一般的には表示を行うための実行単位と、操作を行うための実行単位を独立させます。
それ以外のデータ集計などの処理手続きを行う実行単位はこの図では実行単位1のみを描いていますが、機能追加していく中で、他の処理手続きの完了を待たずに並列に実行した方が良い処理があれば、適宜、実行単位を増やすことも考えます。
図2と図3のソフトウェア構造を理解するための比喩として、ハンバーガーチェーン店をイメージしてもらうと分かりやすいと思います。実行単位が店員で、データ1~3が顧客からの注文で、商品がデータ4だと思ってください。
図2の場合、一人の店員が、顧客からの注文の受付を行い、その注文に従ってハンバーガーを作ったりポテトを揚げて、出来上がったら商品を顧客に受け渡します。次の顧客は、前の顧客が商品を受け取るまで待たされることになります。
図3の場合、3人の店員がいて、1人目の店員は顧客からの注文を受けて2人目の店員に連絡することを繰り返します。これにより次の顧客の注文をすぐに受け付けることができます。2人目の店員は注文に従って順番にハンバーガーを作ったりポテトを揚げていきます。3人目の店員は、一人の顧客が注文した商品が出来上がったら、それをまとめて顧客に渡します。
客が少ない店舗であれば図2でも問題ありませんが、客が多くなったり、一度に大量の注文をする顧客がいる場合は、図3のような役割分担をさせるやり方が良いでしょう。
■データの格納空間の具体化
実際のソフトウェア設計では、こうした形でソフトウェア構造における実行単位や格納空間を整理しつつ、これらを具体的にどこに配置するかを考えることになります。
この際には、各データの扱われかたの理解が不可欠になります。データの格納先は、メモリ、ファイル、データベースなどがあります。
まず、入力となるデータ1~3は、計算が終わった後も表計算ソフトのように残しておく必要があるのか、電卓アプリのようにその場で消えてしまっても良いのでしょうか。前者であればデータ1~3はファイルなどに保存すべきデータになりますが、後者であればファイルへの保存は考える必要がありませんのでメモリ上に格納しておくだけで済みます。
残しておく必要があるデータの場合、データ1~3は一人の人が操作できれば良いのでしょうか、複数人で共同で操作する必要があるのでしょうか。複数人で操作する必要があるなら、ファイルの形であれ、データベースの形であれ、どこか共有のサーバ上に保存しておくことが必要です
複数人が操作する場合でも、誰かが操作している時に他の人が操作する必要が無い場合は、1つのファイルで保存しておく形で良いでしょう。しかし、多数の人が操作するのであれば、担当者ごとにファイルを分割して保存しておくか、同時操作可能な形でデータベースサーバに保存しておくことも考えられます。
また、通常はファイルやデータベースに格納するデータであっても、処理を行う時にはメモリ上にもそのデータのコピーを持っておくことになります。このため、そのメモリ上のデータとファイルやデータベース上のデータを同期させるタイミングなどを、別途、具体的に設計する必要があります。
■処理手続きの実行単位の具体化
各データに対する格納場所の整理がある程度進んだら、処理手続きの実行単位の配置についての検討を進めることができます。
通常、操作と表示は、ユーザの手元にあるパソコンやスマートフォン側で担うしかありません。問題は処理手続き1のような操作や表示と切り離すことができる部分です。
データが全てパソコンやスマホの中に配置されるのであれば、通常は処理手続き1もパソコンやスマホの中に配置することになります。
データがサーバに置かれる場合でも、ファイルの形で共有されて、一度に1人の人しか操作しないのであれば、基本的には処理手続き1もパソコンやスマホの中に配置してよいでしょう。
データを複数の人が同時に操作する場合、データベースサーバにデータを保存することを選択することになるでしょう。その場合、処理手続き1はユーザの手元のパソコンやスマホの中に配置することも不可能ではありませんが、多くの場合サーバ側に配置することになります。
合計値を求めるという程度の一般的な処理手続きであれば、データベースサーバ側の機能で、処理手続き1を行う事もできます。より複雑で特殊な処理手続きであれば、別途、集計処理をサーバ側で行わせることを考える事になります。この場合、入力となるデータが更新される都度、集計処理を行うか、例えば夜間に定期的に集計処理を行うといったことを検討することになります。
■さいごに
ここまでの整理が出来たら、ようやく詳細な設計に入る事ができます。ここから先の詳細な設計については、専門用語が多くなるため、この記事の末尾に補足として書き足しておきます。
売上の合計値を計算するソフトウェアは、その中心となる計算処理は、単に足し算を繰り返すに過ぎません。しかし、実際のソフトウェアを開発するとすれば、こうした観点で全体を考えていく必要があります。
ソフトウェア開発に関する技術や手法は、日進月歩で進化しており、次々に新しいものが登場しています。そうした新しい技術についてインターネットや周囲の人から見聞きすると、どんどん新しい技術を取り込んでいかなければ時代に取り残されてしまうように感じるかもしれません。
しかし、進化の速いソフトウェア開発の世界でも、基本となる概念と、それに基づいた設計開発技術というものは大きく変化するわけではありません。この記事に書いたように、基本的には実行単位と格納空間の上で、処理手続きがデータを加工するということが、ソフトウェアの本質です。
新しいように見える技術の殆どは、特定の分野やスコープ、目的や立場に沿って、それを効率よく開発したり、低コストで実現したり、より高速に処理したり、膨大な量のデータを扱ったりすることができる、というものに過ぎません。
重要なことは、ソフトウェアの基本概念をしっかり理解した上で、それを中心に技術的な知識を身に着けていくことです。そして、ソフトウェアの分野やスコープ、開発者の目的や立場を広く把握し、様々なソフトウェア技術やミドルウェアや開発手法が、どういった観点から有用であるかを理解できるようにしていくことです。
そうすれば、日進月歩で進化するソフトウェア技術や開発手法の情報の洪水に惑わされることなく、自分の目的のソフトウェアの実現に最適な技術や手法を理解することができるようになるはずです。
【補足】
■格納空間の詳細化
データの格納空間や処理手続きの実行単位の物理的な配置場所が整理出来たら、それぞれの詳細な構造を考えていくことになります。
ここからはより専門的な用語が多くなりますが、ざっと概説をしておきます。個々の用語は一般的な専門用語ですので、インターネットで調べると解説記事が多く出てきますので、ここでは詳細は書きません。
データ格納空間内の構造は、リレーショナルデータベースならテーブル設計になります。非リレーショナルデータベースでも、データのカラムや個々のオブジェクトのキーなどを設計していくことになるでしょう。
ファイルの場合は、まずファイル名やファイルの分割単位などの設計と、個々のファイルフォーマットや内部要素の設計が必要になります。
メモリの場合、構造体やオブジェクト、コレクションなどの構造の設計と、それをグローバル変数、ローカル変数、ヒープ領域のどこに配置するかも考える事になります。必要があればプロセス間での共有方法も検討します。
■実行単位の詳細化
処理手続きの実行単位については、通常のプログラムはプロセスを基本単位として考えます。
一つのプロセスの中のメモリ空間を共有しながら、複数の実行単位を持たせるためにはスレッドを使用します。
また、別々の異なる処理手続きを複数のプロセスで実現することは一般的ですが、1つの処理手続きをプロセスに分割して順次実行させることもあります。これは、シェルスクリプトやバッチ処理という形で処理を実行させる場合が代表例です。
■連携方法の詳細化
連携しあう処理手続きが別の実行単位に分かれている場合、別の実行単位に処理手続きを開始させるために連絡を行う必要がある場合があります。スレッド間通信やプロセス間通信、あるいはネットワーク越しの通信などを行って、連絡を取る事になります。
処理手続きとデータの格納先が分かれている場合も同様に、共有メモリアクセス、ファイルアクセス、通信を介してのデータアクセスなどを行う必要があります。
このように整理すると、プログラミングについて勉強する中で出てくる、データベース、ファイル、メモリ、プロセス、スレッド、シェルスクリプトやバッチ処理、共有メモリ、プロセス間通信、ネットワーク通信などが、どのような位置づけにあるのかが理解できるようになるはずです。
そして、これらは全て、処理手続きとデータ、実行単位と格納空間の4つの要素に基づくソフトウェア構造として把握することができます。
サポートも大変ありがたいですし、コメントや引用、ツイッターでのリポストをいただくことでも、大変励みになります。よろしくおねがいします!