科学と家事とプログラミング (python を中心に)

python 温度計測 湿度計測 DS18B20 USB9097

超構造化(02) 構造化定理、構造化の恩恵、構造化チャート

構造化定理

全てのアルゴリズムは順次/選択/反復の組み合わせで表現できる。これを構造化定理と呼 ぶ。処理の流れを、if/else や for (と、それらの派生形)に限定することで、階層的な部分/ 全体関係を導入して、分かりやすいプログラムを実現する。構造化の考えを一歩すすめて、

  • if 節と else 節の同形性を保つ
  • むやみに変数を書き換えない

といった指針(ローカルルール)を導入すると、より分かりやすくなる...という話をしたいのだが、 そのまえに、まずは教科書的な説明から始めよう。

三種の制御構造

f:id:sken20k:20180124235526j:plain

入口も出口も一つだけ!

構造化定理は、順次/選択/反復という三種の制御構造を定める。 フローチャート的には上の図のように表現される。 三種の制御構造に共通する特徴は何か?答えはもちろん、「入口も出口も一つだけ」という事。 なんでもない事のようだけれど、こういう特徴があってはじめて「入れ子」を構成できるようになる。 少し硬い言葉を使えば、「階層的に部分全体関係を構築するための前提条件」。 箱の上下に配置したマルポチは視覚的な工夫である。

マルポチに注目すると、箱が入れ子を構築する様子を、ちょっとだけ想像しやすくなると思う (フローチャートを使う時に、マルポチを付ける事を勧めているわけではない)。 順次/選択/反復という名称は、動的(時間的,命令的)であり、処理の進行を制御する様子(動き)を表現している。 それに対して、直列/分岐/円環という名称は、静的(空間的,宣言的)であり、記述されたプログラムの形(見た目)を表現している。 どちらが正しいということもないが、異なる二つの見方がある事は知っておいて損は無い。 branch や loop には、動詞と名詞の両方の意味があるが、ここでは名詞として、つまり構造あるいは形状の意味で使っている。 直列という性質は、制御構造が共通に備えた原初的(基本的)なものとして捉えることもできる。 その場合、基本要素として連結できる箱(枠だけ)を定義して、その中身の特殊化として、選択と反復の2つを用意すればよい。

構造化の恩恵

構造化を適用したプログラムの特徴を列挙してみよう。 「構造化を上手に使えば実現できる(かもしれない)」といった観点から、 概念の重複を恐れずに列挙するなら、

まず、形式的な特徴は、

  • 三種の制御構造の組み合わせ(入れ子構造)で構築する。
  • 処理の流れとソースの順番が、ある水準で一致する。
  • 処理の流れを、もつれのない構造に射影できる。

次に、意味的な特徴(見たり書いたりする上で人が受ける恩恵)は、

  • 規模に比例した時間で把握できる。
  • ある種の予測が働きやすい。
    • if 節を見れば else 節について、ある程度の予測がつく
  • 階層的/段階的な把握を可能にする。
    • 入れ子の詳細に立ち入らずに理解できる(かもしれない)
    • 上下の階層のことを忘れて、注目している階層に集中できる(かもしれない)
    • 機能群が満たすべき完全性や直行性は上位階層で担保し、下位層は個々の役割に 専念する。キーワードは切り分け/独立性)
  • 人がもつ空間優位の認識能力を活用できる。
  • プログラムの正しさや品質を、その形から(ある程度)判断できる。
  • 変数の値の時間的推移(変化)を追跡する作業から解放される。

代表的な捉え方は、上のリストでカバーできていると思うが、どうだろう。

構造化チャート

NSチャートと PAD

構造化チャートの例として、 NS チャートと PAD を紹介したい。 NS チャートは、処理の流れを空間に写像する様をよくあらわしている。ある種の美しさ、完成度の高さを感じる。残念ながら、少しの加筆修正に対して全面的な書き直しを要求するため、手書きのラフスケッチには適さない。専用ツールを用意するという選択肢もあるが、専用ツールが必要という時点で適用場面が制限される。そういう意味で、無条件に勧めるわけにはいかない。 PADは、処理を(直線的ではなく)平面的に展開できる記法である。NSチャートと違って、手書きのラフスケッチにも適している。どの階層(水準)に注目すべきか?という観点でコードに検討を加える際、ネストが平面的に(横方向に)展開される特徴は大変重宝する。特に機能追加の検討やデバッグの場面で、対象となる階層を識別する際、威力を発揮する。 f:id:sken20k:20180203221645j:plain

チャートの出番は減った?

学生の頃は、プログラムを設計する時に PAD を使っていたが、最近めっきり使わなくなった。そもそもフローチャートや構造化チャートを描く必要性を感じない。手続き的な計算モデルから、(純)関数的な計算モデルに移行して、さらにオブジェクト指向的な手法を適用すると、設計図としてのフローチャートや構造化チャートの重要性が相対的に低くなる。フローチャートや構造化チャートは、手続き的な計算モデルの枠組みの中で処理の流れを空間化して把握するための道具であって、計算モデルが異なれば出番はなくなる。 もう少し言うと、職業としてのプログラミングにおいて、いわゆるアルゴリズムっぽいものを直接設計/実装する機会は極端に減っている事も背景にあるかと思う。ソートなどの基本アルゴリズムは標準のライブラリーを使えば十分な事が多いし、各種リストやハッシュなどの基本データ構造も処理系に用意されている場合が多い。その結果として、アプリケーションの多くは、写像やディシジョン・テーブルのような静的な設計で収まるものが大半を占めることになる。いわゆる動的なアプリケーションは状態機械でモデル化することが多い(これについては別途)。チャートに対して否定的な事を書いているが、設計結果を他の人と共有するには、チャートは効果的なツールだと思う。フローチャートにしても、それを全否定しているわけではなく、ロケットの打ち上げシーケンスが途中で中止になった時の復帰手順など、目の前の状況だけで次にやるべき事を判断するためのャートは不可欠と思う。もっとも、そういうチャートを設計する時には、漏れや無駄を避けるうえでも構造化チャートを利用することを勧める。