@ledsun blog

無味の味は佳境に入らざればすなわち知れず

ソフトウェア開発手法の歴史 1970 - 1990年代

1970年代~1990年代に発達したソフトウェア開発手法を振り返ります。 プログラマ向けです。

1970年代

構造化手法

1967年にEdsger Wybe Dijkstraが発表した論文「Structured Programming(構造プログラミング)」が元になります。 goto禁止論の親玉であり、おおざっぱに言うと「while文と関数を使え」です。例で示します。

after

関数とWhileが使うと、今時の言語と良く似たソースコードになります。*1

init()
main()

function main(){
  while(count > 10000){
    x = Math.GetRandomNumber(r)
    y = Math.GetRandomNumber(r)

    If((x*x+y*y) < rr) Then
      inCount = inCount + 1
    EndIf
    count = count + 1
    pi=4*inCount/count
  
    setcusor()
    TextWindow.Write("trial "+count+" ")
    TextWindow.WriteLine("PI="+pi)
  }
  Program.End()
}

function init(){
  r = 1000
  rr=r*r
  inCount=0
  count=0
}

function setcusor(){
  TextWindow.CursorLeft=0
  TextWindow.CursorTop=0
}

initとmainを順番に実行します。残りは関数定義です。このように処理の順序を分かりやすく書くことができます。

before

以前はループと関数へのジャンプが両方goto文で書かれていました。 ソースコードから制御構造を読み取りにくいです。

例えばGoto 文を使った繰り返し - 中学生のためのSmall Basic日記より*2

Goto init
main:

Loop:
  x = Math.GetRandomNumber(r)
  y = Math.GetRandomNumber(r)

  If((x*x+y*y) < rr) Then
    inCount = inCount + 1
  EndIf
  count = count + 1
  pi=4*inCount/count
  
  Goto setcusor
  label1:
  TextWindow.Write("trial "+count+" ")
  TextWindow.WriteLine("PI="+pi)
  If(count > 10000) Then
    Goto leaveLoop
Goto Loop
leaveLoop:
Program.End()

init:
r = 1000
rr=r*r
inCount=0
count=0
Goto main

setcusor:
TextWindow.CursorLeft=0
TextWindow.CursorTop=0
Goto label1

ソースコードをすべて読まないと制御の順序が分かりません。*3

制御構造設計

制御構造が一目で分かるようになり、制御構造を設計ができるようになりました。

  • どの処理を関数にする?
  • いつ関数を呼び出す?

を整理することが大事になり、プロセス中心アプローチ(POA:Process Oriented Approach)が生まれます。

プログラマに必要な技能は、goto文を使ってスパゲッティにならないようにコードを書く技能から、 制御構造の設計が必要になります。抽象度が一段上がります。

余談

それまでの設計はフローチャートを書いて制御構造を整理していました。

フローチャートの戻る矢印をGoto文で記述すると綺麗に対応します。

参考

1980年代

リレーショナルデータモデル理論

1970年にIBMのEdgar F. Coddが提唱しました。

アプリケーションのデータ保存には、アプリケーション毎に独自ファイル形式を定義していました。 SQLが登場したことにより標準的な方法、つまりDDL(Data Definition Language:データ定義言語)でデータを定義して、DML(Data Manipulation Language:データ操作言語)でデータを操作することができるようになりました。 これによりデータ操作がアプリケーションに依存しない汎用的な技能になります。

データ設計

データ設計の手法が発達します。

ファイルから関係モデルになり「テーブルの結合」という概念が登場します。 各テーブルには結合するためのキーと値を保持すればよく、全テーブルで値を持つ必要がなくなります。 つまり正規化によってデータをより少ないディスクスペースで保持できるようになります。

また制約を使えば、運用中に意図しないデータ変更を防げます。

  • どこでデータが生まれる?
  • どの機能がデータをで使う?
  • どのようなデータがありうるか?

を整理することが大事になり、DOA(データ中心アプローチ)が誕生します。

プログラマの技能もファイル操作からデータ設計へと、さらに抽象度が上がります。

支えた技術

  • メインフレーム
  • データベース

大きな会社は自社でメインフレームを持ち、専用の業務アプリケーションを使用するになりました。メインフレームとデータベース、さらにPC/AT互換機を提供するIBMがITの世界を席巻しました。

参考

1990年代

オブジェクト指向

オブジェクト指向には三大要素があります。

中でも「多態」と呼ばれる、抽象クラス*4による実装の隠ぺいが大きな影響を与えました。*5

オブジェクト指向設計

オブジェクト指向設計が指すイメージは人によってまちまちですが、ここではデザインパターンを使った設計のことを指します。 *6

C言語のファイル操作関数はオブジェクト指向っぽく見えます。

FILE *fp;
char s[256];

fp = fopen("smpl.txt", "r");
fgets(s, 256, fp);
fclose(fp); 

↓と見比べると大変良く似ています。*7

f = new File("smpl.txt", "r");    
s = f.gets(256)  
f.close();

しかし、仕様の定義と実装の定義が分離されていません。関数仕様は別途文章で定義され、論理的には実装とは分離されていました。しかしソースコードで実装に依存しない仕様を表現することはできませんでした。

オブジェクト指向言語によって、仕様を表現する抽象クラス(またらインタフェース)が導入され、クラスの仕様と実装が分離できるようになりました。 そして実装を作る前にクラスの仕様の設計しソースコードとして表現できるようになりました。クラスの仕様を使った設計として

と言ったものが発達していきます。

プログラマは「クラスの仕様設計」というさらに抽象的な技能が必要になりました。

余談

当時、さらに抽象化したモデリングに取り組んだ人たちが居ました。

これらのパターンは当時の技術では実装を隠ぺいすることができませんでした。作るアプリケーション、使うミドルウェアによって考慮しなければいけない点に差があり過ぎたため、それほど普及しませんでした。10年後、システム構成パターンはAmazonがAWS上でアプリケーションの実装をELB、RDS、SQSなどの形で抽象化することで、CloudDesignPattern にまとめられることになります。書籍にしてたったの192ページです。

開発プロセス

この頃ウォーターフォールモデル*8開発プロセスが主流になります。

  1. 要件定義
  2. 設計
  3. 実装
  4. 単体試験
  5. 結合試験
  6. 受入試験

クラスの仕様設計を行うことでアプリケーションを複数のモジュールに分けることができます。 ここでデザインパターンなど実績のあるパターンを使うことで、実装してから仕様の不具合に気付くことが減ります。 各モジュールを同時に別の人が実装できるようになりました。

スケジュールが開発コストの大きな要因になるようになりました。 モジュールの依存関係を整理し、結合スケジュールに向けて最適なタイミングでモジュールを作り始めることで早く安く実装を進めることができます。

プロジェクトマネージメント手法が重視されるようになりました。

支えた技術

  • Java
  • Intel CPU
  • パーソナルコンピュータ

Intelが提供する安いx86 CPUによってパーソナルコンピュータ(AT互換機)が普及し、仕事で一人が一台のコンピュータを使うのが当たり前になりました。OSとOfficeを提供したMicrosoftが躍進しました。

参考

おわり

おしまい。上手く整理出来たら「2000 - 2010年代編」も書くかもしれません。

*1:これはJavaScript風の擬似コードです。

*2:当時はSmall Basicはありません。あくまで例です。

*3:ただしこれは悪い例として挙げられています。

*4:Javaの場合はInterfaceと思った方が分かりやすいと思います。ここでの抽象クラスは「実体化されない仕様を表すクラス」ぐらいの意味です。

*5:オブジェクト指向言語であるRubyではDucktypingをサポートしており多態はそれほど重視していません。実装は可能です。またJavaScriptオブジェクト指向言語ですが、プロトタイプベースであり仕様の継承を区別しません。このように現在のオブジェクト指向プログラミングでは必ずしも仕様の継承による「多態」を重視していません。現在の文脈では単に「オブジェクト指向」よりは「クラスベースのオブジェクト指向」と言った方が混乱を生まないと思います。ここでは当時の概念を尊重して単に「オブジェクト指向」と呼びます。

*6:GoFのカタログに載っているパターンしか使わない」という意味ではありません。GoFデザインパターンに代表される、仕様の継承を使ってクラスの関係を抽象化して整理した設計を意図しています。

*7:これも擬似コードです。

*8:この呼び方もいろいろあると思いますがもう勘弁してください。