marp | size | theme | paginate | title |
---|---|---|---|---|
true |
14580 |
shin |
true |
SW設計論 |
単なる前提, ただし広い, ただし2回だけ
SW設計論13回 (楠本) 要求・見積・RFP SW開発論15回 (肥後) 要求・設計・実装・テスト
情報科学研究科の最大公約数を 幸いSW設計・工学周りは汎用的で役に立ちやすい
B3授業 (演習D・実験B) の経験から考える
・SWEBOK ・良い名前をつける ・コメントはない方が良い ・動くの先にある良いプログラム ・良いプログラムとは? ・"Don't call us, we'll call you" ・goto不要論からの学び ・できないことを増やす ・Complex vs Complicated ・分割統治 ・DRY・KISS・YAGNI
Software Engineering Body of Knowledge IEEEが作っているSEの知識体系
知識や概念の「体系化・構造化」が目的
例:節足動物門 > 昆虫綱 > コウチュウ目 > カブトムシ亜目 ...
内容は薄くて広い 構造付きの辞書とみなすと良い
Project Management BOK Data Management BOK 主にIT分野
1. SW要求
2. SW設計
3. SW構築
4. SWテスティング
5. SW保守
6. SW構成管理
7. SWエンジニアリング・マネージメント
8. SWエンジニアリングプロセス
9. SWエンジニアリングモデルおよび方法
10. SW品質
11. SWエンジニアリング専門技術者実践規律
12. SWエンジニアリング経済学
13. 計算基礎
14. 数学基礎
15. エンジニアリング基礎
2. SW設計
- SW設計の基礎
- SW設計における主要な問題
- 並行処理
- イベントに対する制御と処理
- データの永続化
- コンポーネントの分散化
- エラー・例外処理
- 対話と表示
- セキュリティ
- SW構造とアーキテクチャ
- UI設計
- SW設計品質の分析と評価
- SW設計のための表記
- ...
1. SW要求
2. SW設計
3. SW構築 // 今日はここ ★★★★
4. SWテスティング // 次回
5. SW保守
6. SW構成管理
7. SWエンジニアリング・マネージメント
8. SWエンジニアリングプロセス
9. SWエンジニアリングモデルおよび方法
10. SW品質
11. SWエンジニアリング専門技術者実践規律
12. SWエンジニアリング経済学
13. 計算基礎
14. 数学基礎
15. エンジニアリング基礎
・SWEBOK ・良い名前をつける ・コメントはない方が良い ・動くの先にある良いプログラム ・良いプログラムとは? ・"Don't call us, we'll call you" ・goto不要論からの学び ・できないことを増やす ・Complex vs Complicated ・分割統治 ・DRY・KISS・YAGNI
良いプログラミングの第一歩 簡単で効果あり
- return result; // 抽象的すぎて何も伝わらない
+ return count; // 具体的な名前を
- int delay = 1000; // delay WHAT?
+ int delayMs = 1000; // 単位をつけるべき
if (debug) {
String s = ..; // スコープが小さいならサボってもOK
print(s);
}
- getData(); // 抽象的すぎて何も伝わらない
+ getUserId(); // 具体的な名前を
- getAverage(); // 開発者の期待を裏切る名前
+ calculateAverage(); // 計算コストを要するという旨を伝える
get
よりも compute
calculate
retrieve
extract
名前をつけられない ≒ やりすぎ
他者のソースコードを読む git/builtin/clone.c
int cmd_clone(int argc, const char **argv, const char *prefix)
if (argc == 0)
usage_msg_opt(_("You must specify a repository to clone."),
builtin_clone_usage, builtin_clone_options);
$ git clone
fatal: You must specify a repository to clone.
usage: git clone [<options>] [--] <repo> [<dir>]
コメントを書くのを忘れていた 今後はできる限りコメントを書きたい
class User {
// constructor
public User() { ..
// find users by status
List<User> find(Status s) {
// initialize
String msg = "";
役に立たない ノイズにしかならない ファイルがでかくなる メンテも大変
F. Wen et al., Int'l Conf. Program Comprehension (ICPC) 2019.
- // ボタンを離した瞬間
- if (buttonState == LOW && lastButtonState == HIGH) {
+ if (hasButtonPressed()) {
void doSomething() {
- // setup
- ..
- // calculate
- ..
- // show
- ..
+ setup();
+ calculate();
+ show();
}
関数化は分割統治手法でもあり命名手法でもある
TODOコメント
// TODO: null時の処理を追加する
// FIXME: 処理が重いので最適化すべき
何もしないことの明記
while (offset < size && buf[offset++] != '\n') {
; // do nothing
}
複雑な命令の補足
// email matcher (e.g., [email protected])
Pattern.compile("^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$");
一時策であることの明記
// workaround for issue#30
・SWEBOK ・良い名前をつける ・コメントはない方が良い ・動くの先にある良いプログラム ・良いプログラムとは? ・"Don't call us, we'll call you" ・goto不要論からの学び ・できないことを増やす ・Complex vs Complicated ・分割統治 ・DRY・KISS・YAGNI
変数の宣言 int i
String s
var v
四則演算 sum+100
i++
total*rate
関数呼び出し print("err")
sort(arr)
str.lower()
繰り返し for(..)
while(..)
条件分岐 if(..)
switch(..)
チューリング完全 意図通りに動くプログラムは作れる
動くようになったら「良い」を考えるべき
Lv1+Lv2で動くプログラムは作れる
構造化・オブジェクト指向・関数型・宣言型
パラダイムの理解には様々な概念の理解が必要 - OOP:カプセル化・継承・移譲 - 関数型:参照透過性・冪等性・純粋性・副作用
Lv2は具体的で簡単, Lv3は抽象的で難しい
Lv2で満足してはいけない Lv3を習得すると劇的にプログラミングが上達する
LibやFWを使う際に開発者の気持ちがわかる 暗黙の了解がいたるところにある
理論を理解すれば実践が楽になるのと同じ 理論と実践の両方に取り組むべき
適切な名前・関数分割・浅いネスト等
コードだけ眺めていても分からない Web検索による断片的知識でも怪しい 手を動かさない時間が必要
非構造 → 構造 → OOP・関数型・宣言的 どういう背景・問題からその概念が生まれたのか?
比較するとわかることも多々ある 例)海外に行くと日本の車道の平らさがわかる
目的を満たすか?バグがないか? 計算リソースの無駄がないか?
読みやすいか?意図を汲み取れるか?
拡張時の作業は書き換えか?追加か?
main()
vs main()
+sub1()
+sub2()
+sub3()
・SWEBOK ・良い名前をつける ・コメントはない方が良い ・動くの先にある良いプログラム ・良いプログラムとは? ・"Don't call us, we'll call you" ・goto不要論からの学び ・できないことを増やす ・Complex vs Complicated ・分割統治 ・DRY・KISS・YAGNI
制御の主となるmain()を自分で書かない フレームワークはこの考えに基づく
普通の制御
[My source] // 我々のプログラムがLibを呼び出す
↓ call
[Library]
制御の反転
[Framework] // main関数はここ
↓ call
[My source] // 我々のプログラムはFWから呼ばれる
↓ call
[Library]
from flask import Flask
app = Flask(__name__)
@app.route("/")
def hello_world():
return "<p>Hello, World!</p>"
http://localhost:5000/
→ <p>Hello, World</p>
void setup() {
// 最初に一度だけ呼ばれる
}
void loop() {
// 無限に何度も呼ばれる
}
FWを利用する開発者はとても楽 共通の処理をFWに任せられる システム全体の制御を考えなくて良い 関心の分離が可能
できることに制限が生まれる かゆいところに手が届かない
FWに対する深い理解が必要 - いつcallback関数が呼ばれるか? - 開発者の気持ちを理解するべき
E.W. Dijkstra, Communications of the ACM, 1968
qsort:
PUSH {R0-R10,LR}
MOV R4,R0
MOV R5,R1
CMP R5,#1
BLE qsort_done # goto文
CMP R5,#2
BEQ qsort_check # goto文
..
qsort_check:
LDR R0,[R4]
LDR R1,[R4,#4]
CMP R0,R1
BLE qsort_done # goto文
..
qsort_done:
POP {R0-R10,PC}
ARMアセンブリ言語によるQSort
高い汎用性:分岐・繰返・関数の基本要素
使いやすい:CMP
JMP
のみ
プログラムの制御を自在に変更できる
無秩序の種 いわゆるスパゲッティコードの根源
天才なら制御できるかもしれないが常人には無理 天才は1年後自分のコードを理解できるか? 天才でも常人への説明責任がある
D.E. Knuth, RUNCIBLE -algebraic translation on a limited computer, Commn ACM, 1959
目的に特化している方が意図が明確
CMP
JMP
ではなく if()
や while()
→ 構造化プログラミングにつながる
var
ではなく int
や string
型なしよりも型あり
意図が明確になる 物事が単純になる 例外がなくなる 秩序が生まれる
SZZは~するものである
SZZは~する手法である
「もの」「こと」は汎用的で使いやすいが曖昧
~における~
~に関する~
「~のようなかたちです」
「そんな感じです」
グローバル変数はとても使いやすかったので 今後積極的に使っていきたい
変数・フィールドの可視性 (見える範囲) を下げる 変数・フィールドが及ぼしうる影響範囲を最小限に
変数の書き換えを禁止する
Rustはデフォルトで不変
let x = 5; // 不変(デフォルト)
let mut y = 5; // 可変
自分でやらずに誰かに任す バグを減らす一つの方法はコードを書かないこと
・SWEBOK ・良い名前をつける ・コメントはない方が良い ・動くの先にある良いプログラム ・良いプログラムとは? ・"Don't call us, we'll call you" ・goto不要論からの学び ・できないことを増やす ・Complex vs Complicated ・分割統治 ・DRY・KISS・YAGNI
https://www.gilkisongroup.com/investing-complicated-or-complex/
大きな問題に体当たりしてはいけない 小さく分解して一つずつ解決する 小さくテストできる 優先順位をつけるとベター
ComplexをComplicatedにする第一歩
プログラミング以外にも適用できる - パーティーの準備をする - 授業の準備をする - 研究する
1. 指定ディレクトリ内のファイルを探索する
2. 発見ファイルに外部ツールXを適用する (前処理)
3. ツールXの出力結果に処理Yを適用する (本処理)
4. その結果を指定ディレクトリに書き出す
$ analyze.py in-dir/ out-dir/
$ apply-x.py in-file out-file
$ apply-y.py in-file out-file # 最優先で取り組むべき
$ find in-dir -type f | xargs -i apply-x.py {} out-dir/{}
繰り返すとメンテが大変 変更の際に多くの書き換えが発生する テストもしにくくなる
...
print("[ERROR] Something happens")
...
print("[WARN] Something happens")
...
log(log.ERROR, "Something happens")
...
log(log.WARN, "Something happens")
複雑なほどバグが増, 可読性も低, メンテも大変 最小限にしておく
int times(n, m) {
int sum = 0;
for (int i = 0; i < n; i++) {
sum += m;
}
return sum;
}
n * m;
関数を切り出すときもKISSを考える 処理内容を一言で説明できる, かつ単純にする
未来のための拡張の余地を作らない 必要になったときに実装する
OOPでよく陥る 今必要でないならやらない
interface X {
...
}
public class Y implements X {
...
}
怠惰の理由にしないように
・SWEBOK ・良い名前をつける ・コメントはない方が良い ・動くの先にある良いプログラム ・良いプログラムとは? ・"Don't call us, we'll call you" ・goto不要論からの学び ・できないことを増やす ・Complex vs Complicated ・分割統治 ・DRY・KISS・YAGNI
人との対話という側面もある 「人」には他者だけでなく未来の自分を含む
人に伝わるコードを書こう それが結果的に自分を助ける
数学的素養だけでなく国語的素養 論理的思考力だけでなく言語能力 (叙情的・詩的な力は不要)
客観視能力も必要 相手がどう感じるかを類推する
題材はなんでもOK - 学部の演習・実験 - 研究用の実験スクリプト
1.可読性・保守性の問題点を3つ以上列挙せよ - リソース効率や機能不備は対象外 - 名前等の字面だけでなく構造的な問題も
2.問題点それぞれについて具体的な改善を考えよ
1と2をまとめたテキストをCLEに提出すること