Software Engineering Lecture s01
Menuこの授業では問題は全問提出とします。すべての問題を提出してください。その代わり出席はありません。
問題は、メールでSubjectを (s01 の 問題1.5ならば)
Subject: Report on Software Engineering Lecture 1.5として、問題毎に提出すること。
kono@ie.u-ryukyu.ac.jp まで送ること。番号のついてない問題はオプションです。
学籍番号をメールの中に記述すること。問題番号は正確に記述すること。出席しない場合でも、問題解答を送れば出席扱いとします。
提出期限は ura.ie.classes.software で知らせます。
ソフトウェアを作るということ
実際のプログラミングは、小さい例題をたくさん書けば良いと言うものではない。一人で書く短いものでも数百回も繰り返して実行されることがある。数人で書く数万行のプログラムが全世界で数億人に使われることもある。また、数百人で書いた巨大なプログラムがバグだらけで使い物にならない場合もある。自分がプログラミングに係わることはどういうことなのかを良く考えて、その時その時で最善の努力をしよう。また、プログラミングで学ぶべきことは多い。常に、
最新の技術から勉強する 自分の知識を最新のものとすることを心がけよう。必要になったら勉強するのではなく、自分が常になんらかの分野でトップランナーであることを心がけよう。
古い技術を一つ一つ勉強するよりも、最新の技術を勉強するのに必要な知識を勉強しておく方が良い。しかし、そのためには、基本をおろそかにしてはいけない。数学的手法、論理的な方法がプログラミングの基礎であることを忘れないようしよう。
プログラムの信頼性
まず、プログラムは動かなければならない。単に動けばよいのではなく、信頼性高く動く必要がある。信頼性とは、
要求された仕様を常に満たすこと例えば、
一部が壊れた時にも、悪い方向には動かないなども仕様になる。
仕様にそって必要な実装を行う。
それを動かすことにより結果が得られる。
プログラミングの数学的な意味
これらはつまり、やりたいことにたいして、何かを作って、動かしたことである。漫然とプログラムするのではなく、プログラムの意味を意識してプログラムしよう。プログラムの実行とは何か? どんなプログラムを作りたいのか? そのためには、記述すれば良いのか?
これらを整理して理解するためには、数学的手法を使う必要がある。
- プログラムが満たしてほしい性質 ... 論理的意味、代数的意味
- 論理 論理型プログラミング
- プログラムを動かす仕組み ... 操作的意味
- 写像、関数 関数型プログラミング
- プログラムの動いた履歴 ... 実行結果
- 集合 Specification Z
プログラミングの Life Cycle
プログラムは一度作れば終わりではなく、ユーザの要求仕様の変化、外部的な技術の進歩、バグ取りなどにより、様々な変更が加えられる。それらは、仕様実装テストの繰り返し(cycle)になる。このCycleをうまく廻すことが重要である。
gitやhg を使い、自動的にテストし、公開していく、Continuous Develeopmentというのが提案されている。
プログラムの拡張
機能拡張をしていく場合、既存のコードの変更を最小限にして、コードを付け加えていくのが望ましい。単調増加(Monotonic improvement)と呼ばれる。しかし、これは屋根に屋根を重ねていく方法で、コードの量が増えたり、基本部分の変更が、付け加えた変更部分全体に及んでしまうようになる。
機能拡張を想定したプログラミングにする必要があるつまり、基本部分を部品(Component)に分けて、変更は、その部品内で行うようにする。部品間の依存関係はできるだけ小さくする。
しかし、最初からあらゆる機能拡張を想定すると不要なコードが多くなってしまう。
拡張性を持つように変更を導入する必要があるプログラムの動作を保存しつつ、機能拡張などがやりやすいように構成を変えることを Refactoring という。
関数型プログラミング
メタプログラミング
集合
対象とするものの集まりを集合という。集合には二通りの表し方がある。- 集合の要素を全部示す (外延的定義 denotation)
{ 島袋哲,上原麻乃,金城尚治,比嘉陽一,前原崇章,三野敦史,宮城尚平 }
- 集合が満たす性質を示す (内包的定義 connotation)
{X | X は情報工学3年}
集合に対して簡単な演算を考えることができる。
- 集合演算 ... ∩ (Intersection), ∪(Union), - (Subtraction)
a ∈ A , a は集合A の要素
これを、Haskell / Agda では、
a : Aという風に書く。
写像、関数
何かの入力に対して決まった値を返すものが関数である。
可能な入力の集合を定義域、定義域に対する出力の集合を値域という。定義域Aから値域Bへの関数 f を以下のように書く。
f : A → Bつまり、A → B というのは集合であり、f は、その要素になる。
関数を集合と集合の対応と考える時には特に写像という言葉を用いることが多い。(その方がCの関数と混同しなくてすむし...)
二つの関数を持って来て、片方の値域と他方の定義域が適合していれば、関数の合成を作ることができる。
f : A → B g : B → Cこの二つの関数から AからCへの関数を作ることができる。
g ・ f : A → C
論理
論理は以下の要素から構成される
- 命題 (Q,P,R) ... T / F, 正しい / 間違っている, 真 / 偽
- 変数 (x,y,z) ... いろいろな値が割り当てられる名前
- 述語 p,q(x) ... 変数を含む命題
- 論理演算 ... ∧ (AND), ∨ (OR), ~ (NOT)その他、論理の記号(¬,∧,⇒,⇔)を使う。
空集合をF、空でない適当な集合をT、と見ることによって、集合演算と論理演算は対応づけることができる。
A∧B | A ∩ B |
A∨B | A ∪ B |
¬A | T - A |
集合を定義する論理式
集合を定義するのには、論理式を使うことが多い。
- {X | p(X)}
述語は、T/F を返す関数を使って定義することができる。したがって、集合は、T/F を返す関数を内包的に使って定義することができる。
具体的なプログラムに関して集合を使って意味を考える
もし入力が有限で、出力が一つだけなら、とても簡単になる。入力が無限だったりすると難しい。特にReal-timeプログラミング、並列プログラミングの意味は難しい。
- 仕様は論理式で表すのが容易である
- 実装は関数で表すのが容易である
- 実行結果は集合で表すのが容易である
しかし、この三つの道具は、実際には同等な力を持った道具であり、望むならば、論理だけ、関数だけ、集合だけ、ですべてを表現することもできる。しかし、適材適所を考えて使おう。