• 検索結果がありません。

第1回 ソフトウェア工学とは

N/A
N/A
Protected

Academic year: 2021

シェア "第1回 ソフトウェア工学とは"

Copied!
34
0
0

読み込み中.... (全文を見る)

全文

(1)

ソフトウェア工学1

8回 コーディングとレビュー

2017年6月6日

中島 毅

(2)

授業内容

• コードを美しく書くことの意味

• 構造化プログラミングとレビュー

• 設計レビューとコードレビュー

• 静的解析ツール

(3)

世の中の開発は流用ベースが多い

初期製品開発(顧客

A向け)

シリーズ開発(顧客ニーズ追随)

機種分岐

XA-0

XA-1

XA-2

XA-3

XB-1

XB-2

市場ニーズの変化 テクノロジーの進歩 保守コストの増大

YA-0

次機種開発

YA-1

XB-3

YB-1

顧客(分野)A 顧客(分野) B

製品ライフサイクル

要求 分析 設計 製造 テス ト

開発ライフサイクル

企画

基幹業務(人事,資材,経理,・・)のシステム

FA, エレベータ,エアコン,エンジン制御,カーナビ・・・

分野別開発

(仕向地,

グレード)

(4)

読めないプログラムでは開発が回らない

完全流用

生産量の

90%以上が完全流用という開発プロジェクトがほとんど!

新規:

全く新しく作る部分

改造:

既存のプログラムを一部修正

して作る部分

完全流用: 製品に組み込まれているが,

一切修正せず利用する部分

5kL

100kL

1人しかアサイン

されない

開発量

生産量

知っている人が

少ない/いない

(5)

読めないプログラムでは開発が回らない

既存のコードが読めないと、改造や不具合の原因追求ができない

完全流用

欠陥は

主にここ

に出現

使い方のミス

(インタフェース)

にも欠陥あり

既にあった

欠陥の顕在

化もあり

流用する部分を知らないで,新規・改造

部分を作るのは容易でない

読めるプログラムを作ってほしい!(切なる願い)

改造

不具合の

原因追求

× どう改造してよいか?

× バグの原因はどこ?

設計書がない!

ソースコードが読めない!

品質悪化 & コスト増

(6)

授業内容

• コードを美しく書くことの意味

• 構造化プログラミングとレビュー

• コーディング規約

• 設計レビューとコードレビュー

• 静的解析ツール

(7)

よいプログラムを書くには

• 良いプログラムとは

– 欠陥がない

– 移植性がよい

– 性能がよい

– テストがしやすい

– シンプルである

(無駄がない)

– 自己説明的である

– 自己証明的である (見て正しいことがわかる)

基本作法

構造化プログラミング

(8)

構造化プログラミング

Edsger W. Dijkstra 登場!

・オランダの数学者 (チューリング賞受賞者)

・構造化プログラミング提唱者

プログラミングに,数学の証明の

考え方を導入すれば,プログラム

に欠陥が入らなくなる.

プログラムは、作るほど欠陥が入る。何とかならないか?

(9)

構造化プログラミング

(仕様の具体化)

•プログラミング=

仕様を段階的に具体化

していく過程

Structured programming とは

具体化

親処理

子処理

1

子処理

2

子処理

3

親処理

子処理

1

子処理

2

子処理

3

条件

具体化

親処理

子処理

1

条件

順次

分岐

反復

(ループ)初期化

•N階層はN+1階層へ

順次/分岐/反復

の3種類の制御構造

のいずれかを使って

仕様を分解

(10)

例:

生年月日と今日の日付から、年齢を計算するプログラム

今日が誕生日前

後か判定する

年齢を決定する

判定

=後

日の前後で判定する

現在月

>生月 =生月 <生月

判定

=前

現在日

>=生日 <生日

判定

=後

判定

=前

判定

==後

年齢=現在年

-生年

年齢=現在年

-生年-1

プログラミング時

(11)

// 年齢計算

int age(int byear, int bmonth, int bday, /* 生年月日 */

int cyear, int cmonth, int cday) /* 現在年月日 */

{

enum question {yes, no} afterBirthday; int result; // 今日が誕生日前後か判定する // 年齢を決定する return result; } // 年齢計算

int age(int byear, int bmonth, int bday, /* 生年月日 */

int cyear, int cmonth, int cday) /* 現在年月日 */

{

enum question {yes, no} afterBirthday; int result; // 今日が誕生日前後か判定する // 年齢を決定する return result; }

コーディング

Cプログラム)

• シンプルである

• 自己説明的である

• 自己証明的である

// 年齢計算

int age(int byear, int bmonth, int bday, /* 生年月日 */

int cyear, int cmonth, int cday) /* 現在年月日 */

{

enum question {yes, no} afterBirthday; int result;

// 今日が誕生日前後か判定する

if (cmonth > bmonth) { afterBirthday = yes; }

else if (cmonth == bmonth) {

// 日の前後で判定する } else { afterBirthday = no; } // 年齢を決定する return result; } // 年齢計算

int age(int byear, int bmonth, int bday, /* 生年月日 */

int cyear, int cmonth, int cday) /* 現在年月日 */

{

enum question {yes, no} afterBirthday; int result;

// 今日が誕生日前後か判定する

if (cmonth > bmonth) { afterBirthday = yes; }

else if (cmonth == bmonth) {

// 日の前後で判定する if (cday >= bday) afterBirthday = yes; else afterBirthday = no; } else { afterBirthday = no; } // 年齢を決定する return result; } // 年齢計算

int age(int byear, int bmonth, int bday, /* 生年月日 */

int cyear, int cmonth, int cday) /* 現在年月日 */

{

enum question {yes, no} afterBirthday; int result;

// 今日が誕生日前後か判定する

if (cmonth > bmonth) { afterBirthday = yes; }

else if (cmonth == bmonth) {

// 日の前後で判定する if (cday >= bday) afterBirthday = yes; else afterBirthday = no; } else { afterBirthday = no; } // 年齢を決定する if (afterBirthday == yes) result = cyear - byear; else

result = cyear - byear - 1; return result;

}

プログラミング時

// 年齢計算

int age(int byear, int bmonth, int bday, /* 生年月日 */

int cyear, int cmonth, int cday) /* 現在年月日 */

{

(12)

構造化プログラミングとレビュー

(証明過程)

プログラムの正当性は

N階層とN+1階層を比較して確認

補題1・補題2・補題3

⇒命題A

数学的

帰納法

数え上げ

n=1のとき成立

nのとき成立するとして

n+1を証明

親処理

子処理

1

子処理

2

子処理

3

親処理

子処理

1

子処理

2

子処理

3

条件

親処理

子処理

1

条件

順次

分岐

反復

(ループ)初期化

補題1

|補題2|補題3

⇒命題A

命題

A

命題

A

補題1

補題2

補題3

命題

A

補題1

補題2

補題3

比較 比較 比較

(13)

// 年齢計算

int age(int byear, int bmonth, int bday, /* 生年月日 */

int cyear, int cmonth, int cday) /* 現在年月日 */

{

enum question {yes, no} afterBirthday; int result;

// 今日が誕生日前後か判定する

if (cmonth > bmonth) { afterBirthday = yes; }

else if (cmonth == bmonth) {

// 日の前後で判定する if (cday >= bday) afterBirthday = yes; else afterBirthday = no; } else { afterBirthday = no; } // 年齢を決定する if (afterBirthday == yes) result = cyear - byear; else

result = cyear - byear - 1; return result; }

コーディング

Cプログラム)

• シンプルである

• 自己説明的である

• 自己証明的である

⇒コードレビュー

がやりやすい!

レビュー時

(14)

int age(int AY, int AM, int AD, int BY, int BM, int BD) {

int X, Y;

X=0;Y=BY-AY;

if (BM>AM)X=1;

if (BM==AM&&BD>=AD)X=1;

if (X==0) Y-=1;

return Y;

}

参考: 等価なプログラム

変数名が記号になっている

変数とそれを使った式の意味は?

インデントや改行がない

構造はどうなっている?

if文がelse項を持たない

場合分けがどこを通る?

計算の順番がまとまっていない

どの計算結果がどこで使われる?

読んで理解できない,正しさを確かめられない

何が悪いか

(15)

コーディング規約

プログラム自体を説明的にしよう!

•ヘッダコメント

•変数コメント(引数/内部変数)

•ブロックコメント

コメントを書こう!

•画面に収まる範囲の大きさにモジュールを作る

•統一的でわかりやすい関数名/変数名を使う

•統一的な制御構造を使う

•統一的なレイアウト(空行、空白、改ア行)

コーディング規約

読みやすさの追求

(16)

コメント例

/*******************************************

*** Designer

: 中島 毅

*** Date

: 2003.6.1

*** Purpose

: 三角形の種別を判定するプログラム

*******************************************/

#include <stdio.h>

enum Result {ordinalTriangle=0, isoscelesTriangle=1,

equilateralTriangle=2};

int main()

{

float x, y, z;

/* 三角形の3辺 */

enum Result myResult; /* 判定結果 */

extern enum Result checkTriangle(int, int, int);

//データ読み込み

fprintf(stderr, "x = "); (void)scanf("%f", &x);

fprintf(stderr, "y = "); (void)scanf("%f", &y);

fprintf(stderr, "x = "); (void)scanf("%f", &z);

ヘッダコメント

(作成者、日付、内容等)

変数コメント

(引数/内部変数)

(17)

授業内容

• コードを美しく書くことの意味

• 構造化プログラミングとレビュー

• コーディング規約

• 設計レビューとコードレビュー

• 静的解析ツール

(18)

ユーザ 分析者

設計者

プログラマ

テスタ

検討

確認

伝達

伝達

検討

確認

要求分析/企画

設計

コーディング

テスト

要求

仕様

設計

仕様

設計レビューとは

工程を設定する

正しさを確かめ,伝えるために

ドキュメントを作成し,

確認する

ソフトウェアの品質を保証するための

人手による検証活動

18

ソース

コード

検討

確認

(19)

実際、設計レビューってどうやっている?

会議形式のレビュー

レビューしてもらう人: 説明する

レビューする人:

質問する、指摘する

書面レビュー

書類をまわす、赤を入れる

誰が?

自分(セルフレビュー)

仲間内(ピアレビュー)

利害関係者(公式レビュー)

(20)

コードに含まれる欠陥の種別をあげよ

• 今までに出会ったことのあるバグを思い浮かべよう。

• 手強かったのはどんなバグか?

(21)

コードに含まれる欠陥の種類(単体レベル)

カテゴリ

種別

シンボル

シンボル取り違え

演算

演算子の取り違え

演算順序間違い

型変換誤り

初期化抜け

精度誤り

配列

配列領域からの逸脱参照

メモリ

不正領域(

Null、不定値)への書き込み

メモリリーク(開放不正)

条件式

異なる型の比較

演算子の順序誤り

精度の異なる値の比較

比較演算子の選択誤り

ループ終了時の処理の誤り

ループ脱出条件の誤り

ループ変数の変更誤り

条件組合せ 複合条件式の組合せ誤り

複数条件ブロックの組合せ誤り

設計誤り

アルゴリズムとデータ構造の不正

条件処理抜け

例外処理抜け

(22)

コードレビュー

チェック

リスト

視点1: 機能仕様満足 視点2: アルゴリズムの出来 視点3: インタフェースミス 視点4: プログラムミス レビュー結果 報告書

フィードバック

コーディング

規約

① 守るべきこと

② 確認の視点

③フィードバック(改善)

ソースコード

プログラム 仕様書

プログラム仕様

を満たすこと

コーディング規約

を満たすこと

ソースコードの正しさを検査するために、人が読んで確認

する設計レビュー

レビューのポイント

22

(23)

コードレビューの流れ、利点/欠点

利点

– あらゆる種類の欠陥を見つけることが可能

– 一般に、欠陥を見つけるコストは、テストに比べて安価

欠点

– 人間が実施するので、レビューアの能力とやる気に、パ

フォーマンス(欠陥検出率、検出効率)が左右される

ソースコードレビューの流れ

セルフ

レビュー

ピアレビュー

公式レビュー

作成者自身

開発チーム内

関係者(設計者、テスタ、品質保

証者など)

ポカミス除去の観点

実装の適切さの観点

品質保証の観点

(24)

コードレビューの種類

ウォークスルー法

チェックリスト法

(インスペクション)

実施

方法

プログラムを机上で実行すること

でプログラムの動作を追いながら

欠陥を見つける(机上実行)

ルールとチェックリスト(CL)を

用いて、着眼点ごとに欠陥を見

つける

実施

形態

• 主に、ピアレビューで使用

• 複数人での実施が推奨

• 通常、個別に事前レビュー実施

• 主に、公式レビューで使用

• 参加者の役割が決っている

• (例)開発者、モデレータ他

利点

• コードでありがちな欠陥を検出に

向いている(CLの効用)

• 基準(ルールとCL)があるので、

品質保証として意味をもつ。

• コードの実装が仕様を満足して

いることを確認しやすい。

• プログラム仕様やコードの実装

の意味を伝えるのに向いている

(技能とノウハウの伝達)

(25)

仕様:

このプログラムは、3つの数字を端末より読み込む。この3つの値は、そ

れぞれ三角形の3辺の長さを表すものとする。プログラムは、三角形が不

等辺三角形・二等辺三角形・正三角形のうちのどれであるかを決めるメッ

セージを出力する。三角形でないケースについてもその旨を出力する。

コードレビューの体験

チェックリスト

C-1 プログラムは仕様を満たしているか?

C-2 コーディング規約にあっていないものがあるか?

C-3 プログラム自体にエラーはあるか?

コーディング規約(抜粋)

R-1 main関数は引数がないときvoidを記述する。

R-2 代入の型が違う場合には、明示的にキャスト(強制型変換)する。

R-3 if/while/forの後は必ずブロック{}にする。

(26)

/************************************************* *** Designer : 中島 *** Date : 2003.6.1 *** Purpose : 三角形判定プログラム *************************************************/ #include <stdio.h>

enum Result {ordinalTriangle=0, isoscelesTriangle=1, equilateralTriangle=2};

/************************************************ *** Function Name : checkTriangle

*** Designer : 中島 *** Date : 2003.6.1 *** Function: 3辺の長さから不等辺三角形・二等辺三角形・ 正三角形のいずれかを判定する *** Return : ordinalTriangle -- 不等辺三角形 isoscelesTriangle -- 二等辺三角形 equilateralTriangle -- 正三角形 ************************************************/ enum Result

checkTriangle(int x, int y, int z) {

enum Result myResult; // 正三角形のチェック if (x == y && y == z) myResult = equilateralTriangle; // 二等辺三角形のチェック if (x == y || y==z || z == x) myResult = isoscelesTriangle; return myResult; } /************************************************ *** Function Name : checkTriangle

*** Designer : 中島 *** Date : 2003.6.1 *** Function: 3辺の長さから不等辺三角形・二等辺三角形・ 正三角形,三角形不成立のいずれかを判定する ************************************************/ int main() { float x, y, z; /* 三角形の3辺 */ enum Result myResult;

//データ読み込み

fprintf(stderr, "x = "); (void)scanf("%f", &x); fprintf(stderr, "y = "); (void)scanf("%f", &y); fprintf(stderr, "x = "); (void)scanf("%f", &z); // 三角形判定

myResult = checkTriangle(x, y, z); // 出力

if (myResult == ordinalTriangle)

printf("Result = 不等辺三角形¥n"); else (myResult == isoscelesTriangle)

printf("Result = 正三角形¥n"); else { printf("Result = 二等辺三角形¥n"); } return 0; }

(27)

授業内容

• コードを美しく書くことの意味

• 構造化プログラミングとレビュー

• コーディング規約

• コードレビュー

• 静的解析ツール

(28)

コードレビューの支援ツール: 静的解析

静的解析ツール

プログラムを実行することなく,危険なコード部分を見つけ、警告を出すツール

ソース

コード

静的解析

ツール

①警告

②メトリクス

レポート

解析

コンパイル

直後

修正

プログラマ

不具合を含むコードの

重大問題を早期発見!

(29)

静的解析ツールの機能: 警告出力

・ 不具合に直結するコード

・ 保守性の悪いコード

危険なコードに警告を出す

早い段階で見つけ修正

できればコスト効果大!

// ネットワークノードの接続

long NwDrawer::GNAtoINL(GNetwkArc* pGNA,IltLink* pINL, double fromID,double toID) { IltObject* fromINE; IltObject* toINE; // 始点と終点の決定 if (fromID >= 0) { fromINE = SearchNetworkElement(fromID); } //終点IDが正常値である場合 if (toID >= 0) { toINE = SearchNetworkElement(toID); } // どちらかのIDが異常な場合

if ( (fromINE == NULL) || (toINE == NULL) ) { return -1; fromID >= 0 なら fromINE 初期化 toID >= 0 ならtoINE 初期化

S:¥QAC¥PROJECT¥source¥GNWtoTGO

Drawer.cpp(248) ++ WARNING ++:

<=5=(4201)

変数

'fromINE'は、設定されていない可

能性があるのに、アクセスされています。

S:¥QAC¥PROJECT¥source¥GNWtoTGO

Drawer.cpp(248) ++ WARNING ++:

<=5=(4201)

変数

'toINE'は、設定されていない可能

性があるのに、アクセスされています。

警告例

初期化忘れの例

(30)

静的解析ツールで検出できる欠陥

C/C++言語 → splint, cppcheck, QA C/QA C++, Klocwork, Coverity

Java言語

→ jlint, checkstyle, Klocwork Insight, Jtest

 初期化忘れ

 危険な型変換

• 型不一致の代入

• 関数の引数、戻り値の型不一致

 誤りがちな構文

• あいまいな実行評価順序

• 危険なポインタ演算

• 条件式内の代入

 メモリ操作ミス

• メモリ領域(配列)の範囲オーバー

• メモリ解放忘れ

 処理系依存(移植性の問題)

下線は

OSS,他は商用

30

(31)

静的解析ツールの機能: メトリクス出力

保守性:

プログラム行数

, McCabe (分岐の数+1)

テスト可能性:

静的経路数(すべての実行パスの数)

例)

1モジュール

100行、

McCabe

10以上は、理解困難/欠陥率の増加が顕著

例)

1モジュール

200経路以上は、単体試験でのテスト網羅性を確保しにくい

早めに悪いプログラム構造をチェック

コード品質のメトリクスを計算する

品質メトリクスが悪い

コード部分を指摘

QAC基準 値 経路複雑度(1関数あたり) 10 GOTO数(1関数あたり) 0 コード行数(1関数あたり) 100 ネストの深さ(1関数あたり) 7

メトリクス基準値例

モジュール別

メトリクス値

(32)

例題: 人間のレビュー

VS 静的解析ツール

#include <stdio.h>

#include <math.h>

int myRoot(double x)

{

int y;

if (x > 0) {

y = sqrt(x);

}

return y;

}

int main(void)

{

int i;

double *x = (double*)malloc(sizeof(double)*100);

while (i <= 100) {

x[i] = myRoot((double)i);

i++;

}

return 0;

}

• いくつプログラムの欠陥らしきものを見つけられますか?

32

(33)

コードに含まれる欠陥と検出手段

コードに含まれる誤り

検出手段

カテゴリ

種別

コンパイラ

テスト

レビュー

静的解析

シンボル

シンボル取り違え

演算

演算子の取り違え

演算順序間違い

型変換誤り

初期化抜け

精度誤り

配列

配列領域からの逸脱参照

メモリ

不正領域(

Null、不定値)への書き込み

メモリーリーク(開放不正)

条件式

異なる型の比較

演算子の順序誤り

精度の異なる値の比較

比較演算子の選択誤り

ループ終了時の処理の誤り

ループ脱出条件の誤り

ループ変数の変更誤り

条件組合せ 複合条件式の組合せ誤り

複数条件ブロックの組合せ誤り

設計誤り

アルゴリズムとデータ構造の不正

条件処理抜け

例外処理抜け

変数の物理値域と物理値域の不整合

(34)

まとめ

• コードは資産、人に読んでもらうことを意識する。

• 良いコードを書くには:

– 構造化プログラミング

– コーディング規約

• コードレビューは、ソフト開発における重要な活動

– 守るべきこと、確認の視点、フィードバック

– ウォークスルー法とチェックリスト法

– 静的解析ツールを使う

SEは、コードを書かなくても、良いコードの意味、レ

ビューを大切さを知っておく必要がある。

参照

関連したドキュメント

⼝部における線量率の実測値は11 mSv/h程度であることから、25 mSv/h 程度まで上昇する可能性

現状では、3次元CAD等を利用して機器配置設計・配 管設計を行い、床面のコンクリート打設時期までにファ

data-set-name BOOLEAN 参照 DataSet true(レポート内に収容). data-reference BOOLEAN データ項目情報

八王子市の一部 (中央自動車道以北で国道16号線以西の区域) 、青梅市、あきる野市、日の出町、檜原村及び奥多摩町 3 管理の目標.

J2/3 ・当初のタンク設置の施工計画と土木基礎の施工計画のミスマッチ

今回のスマートメーター導入の期待効果の一つには、デマンドレスポンス による

・ごみの焼却により発生する熱は、ボイラ設備 により回収し、発電に利用するとともに、場

プレフィルターエレメント汚れ、取付状態確認 プレフィルターハウジング破損等点検 電動弁・減圧弁作動確認 流量調整弁作動確認