1

「シンプル・プログラミング」
2013.11.02
XP寺子屋

XPJUG関西 / XP寺子屋
2

自己紹介
XPJUG関西 / XP寺子屋
3

・名前

丈善(たけぷ~)
: 西 丈善(たけぷ~)

・仕事

: 組み込み系

・業界歴

: 20年以上
年以上

関西、
・コミュニティ : XPJUG関西、PFP関西
関西
関西
・使用言語

: C, C++

・SNS

: Twitter takepu
FaceBook 西 丈善

・宣伝

: ▼アジャイルラジオ 毎週水曜日公開
http://www.agileradio.info/
開催決定!
▼XP祭り関西
祭 関西2014 2014年4月26開催決定!
年 月 開催決定
http://www.xpjug.jp
▼出張アジャイル社内研修(無料)受付中
出張アジャイル社内研修(無料)
アジャイル社内研修

XPJUG関西 / XP寺子屋
4

アジェンダ
XPJUG関西 / XP寺子屋
5

アジェンダ
•
•
•
•
•
•
•

「シンプル・プログラミング」講座
コードレビュー
休憩
練習
実習
ふりかえり
あとかたづけ

XPJUG関西 / XP寺子屋

-

50分
10分
5分
30分
90分
10分
10分
6

シンプル・プログラミング
?
て何
っ

XPJUG関西 / XP寺子屋
7

ようこそ「シンプル・プログラミング」の世界へ!

XPJUG関西 / XP寺子屋
8

早速質問。
「シンプル」とは、どういう
意味?
XPJUG関西 / XP寺子屋
9

XPJUG関西 / XP寺子屋

kotobankより引用。
10

続いて質問。
「シンプルなプログラム」
とは、どんなプログラム?
XPJUG関西 / XP寺子屋
11

●行数が少ない?
●関数の数が少ない?

XPJUG関西 / XP寺子屋
12

大切なのは、
「分かりやすい」事.
XPJUG関西 / XP寺子屋
13

どっちが簡単?

XPJUG関西 / XP寺子屋
14

シンプルなプログラムのメリット
•
•
•
•
•
•
•

間違いにくい
バグが混入しにくい
デバッグが簡単
他人が書いても分かりやすい
バグの発見が容易
仕様変更が容易
性能改善も用意

XPJUG関西 / XP寺子屋
15

シンプルなプログラムのデメリット
• 人に自慢できる複雑で難解なコードを書いて悦
に入る事ができない
• 複雑なコードを理解した時に得られる達成感が
得られない
• 残業できない
XPJUG関西 / XP寺子屋
16

シンプルなプログラム
と複雑なプログラム、
あなたはどちらを
選びますか?
XPJUG関西 / XP寺子屋
17

シンプル・プログラミング6つの原則
1.
2.
3.
4.
5.
6.

コメントの書き方
名前の付け方
コピペ禁止
1関数1機能
ボトムアップアプローチ
インクリメンタル開発

XPJUG関西 / XP寺子屋
18

1.コメントの書き方

?
てた
っ
て知
っ

XPJUG関西 / XP寺子屋
19

1.コメントの書き方
• 基本は、「コメントが不要なくらい分かり易いコード
を書く」.
• どうしても説明が必要な箇所にコメントを書く.
• コメントは、「処理」では無く、「やりたい事」を書く.

XPJUG関西 / XP寺子屋
20

悪い例
/******************/
/* バブルソート */
/******************/
#include <stdio.h>
#define MAX 10
void main( )
{
int data[MAX]={ 80,5,36,23,12,100,45,9,1,78 };
int n,i,w;
// 未整列データ数
for( n=MAX; n>1; n-- )
{
for( i=0; i<n-1; i++ )
{
// 次のデータが小さい
if ( data[i]>data[i+1] )
{
// 入れ替え—
w=data[i];
data[i]=data[i+1];
data[i+1]=w;
}
}
}
printf("¥nソート後¥n");
for( i=0; i<MAX; i++ )
{
printf("%d ",data[i]);
}
printf("¥n");
}

XPJUG関西 / XP寺子屋
21

改善例
/******************/
/* バブルソート */
/******************/
#include <stdio.h>
#define MAX 10

/******************/
/* バブルソート */
/******************/
#include <stdio.h>
#define MAX 10

void main( )
{
int data[MAX]={ 80,5,36,23,12,100,45,9,1,78 };
int n,i,w;

void main( )
{
int data[MAX]={ 80,5,36,23,12,100,45,9,1,78 };
int n,i,w;

// 未整列データ数
for( n=MAX; n>1; n-- )
{
for( i=0; i<n-1; i++ )
{
// 次のデータが小さい
if ( data[i]>data[i+1] )
{
// 入れ替え—
w=data[i];
data[i]=data[i+1];
data[i+1]=w;
}
}
}

バブルソートを
// バブルソートを行う
for( n=MAX; n>1; n-- )
{
for( i=0; i<n-1; i++ )
{
データを交換する
// データを交換する
if ( data[i]>data[i+1] )
{
w=data[i];
data[i]=data[i+1];
data[i+1]=w;
}
}
}
ソート結果 表示する
結果を
// ソート結果を表示する
printf("¥nソート後¥n");
for( i=0; i<MAX; i++ )
{
printf("%d ",data[i]);
}
printf("¥n");

printf("¥nソート後¥n");
for( i=0; i<MAX; i++ )
{
printf("%d ",data[i]);
}
printf("¥n");
}

XPJUG関西 / XP寺子屋

}
22

解説
/******************/
/* バブルソート */
/******************/
バブルソートを
// バブルソートを行う

/******************/
/* バブルソート */
/******************/
#include <stdio.h>
#define MAX 10

データを交換する
// データを交換する
ソート結果 表示する
結果を
// ソート結果を表示する

void main( )
{
int data[MAX]={ 80,5,36,23,12,100,45,9,1,78 };
int n,i,w;
バブルソートを
// バブルソートを行う
for( n=MAX; n>1; n-- )
{
for( i=0; i<n-1; i++ )
{
データを交換する
// データを交換する
if ( data[i]>data[i+1] )
{
w=data[i];
data[i]=data[i+1];
data[i+1]=w;
}
}
}

•コメントは「やりたい事」

ソート結果 表示する
結果を
// ソート結果を表示する
printf("¥nソート後¥n");
for( i=0; i<MAX; i++ )
{
printf("%d ",data[i]);
}
printf("¥n");

•コードは「実現方法」
}

XPJUG関西 / XP寺子屋
23

2.名前の付け方

にル
ール
があ
るの
?

XPJUG関西 / XP寺子屋
24

2.名前の付け方
• 一般的に、コーディング規約で命名規則が決まっ
ている.
• しかし、諸事情でコーディングルールが無かったり、
非オブジェクト指向言語では、分かりにくい名称
がはびこっている.
• 最近のオブジェクト指向言語で提唱されている命
名規則を使用することで、コードの可読性が向上
し、シンプルなプログラミングが可能となる.

XPJUG関西 / XP寺子屋
25

命名規則(1) 関数名
• 変数を取得する関数
– XXX getXXX( )

• 変数を設定する関数
– void getXXX( XXX 変数 )

• Booleanを返す関数
–
–
–
–
–
–
–

is + 形容詞,can + 動詞,has + 過去分詞,三単元動詞,三単元動詞 + 名詞.
boolean isEmpty() // JavaBeans でプロパティとして扱える(推奨)
boolean empty() // だめ!’空にする’という動詞的な意味に取れるため良くない.
boolean canGet()
boolean hasChanged()
boolean contains(Object)
boolean containsKey(Key)

XPJUG関西 / XP寺子屋
26

命名規則(2) 変数名
• Boolean 変数
–
–
–
–

形容詞,is + 形容詞,can + 動詞,has + 過去分詞,三単元動詞,三単元動詞 + 名詞.
boolean isEmpty
boolean dirty
boolean containsMoreElements

• 全て有意な名前を付ける
– Info, Data, Temp, Str, Bufという名前は極力使わない
– ループカウンタなどで用いる i, j, k も、適切な名前を付ける

XPJUG関西 / XP寺子屋
27

命名規則(3) 名前の対称性
•
•
•
•
•
•
•
•
•
•
•
•
•

add/remove
insert/delete
get/set
start/stop
begin/end
send/receive
first/last
get/release
put/get
up/down
show/hide
source/target
open/close
XPJUG関西 / XP寺子屋

•
•
•
•
•

source/destination
increment/decrement
lock/unlock
old/new
next/previous

クラス名,メソッド名を付ける際は,本頁
記載の英語の対称性に気を付ける.
28

悪い例
/****************/
/* 素因数分解 */
/****************/
#include <stdio.h>
#include <stdlib.h>
void FuncFactorization ( int argc, char *argv[] )
{
int n0,n; // 整数
int ns=2; // 素因数
int j;
// 乗数
n0=atoi(argv[1]);
// 因数分解
for( n=n0,ns=2; n>=ns; ns++ )
{
for( j=0; n%ns==0; j++ )
{
n /= ns;
}
if ( j==0 ) continue; // 1回も割り切れなかった
printf("素因数:%d 乗数:%d¥n",ns,j);
}
}

XPJUG関西 / XP寺子屋
29

改善例
/****************/
/* 素因数分解 */
/****************/
#include <stdio.h>
#include <stdlib.h>
void FuncFactorization ( int argc, char *argv[] )
{
int n0,n; // 整数
int ns=2; // 素因数
// 乗数
int j;

/****************/
/* 素因数分解 */
/****************/
#include <stdio.h>
#include <stdlib.h>
void DoFuncFactorization ( int argc, char *argv[] )
{
int num;
// 整数
int num_div; // 割り算した整数
int prime = 2; // 素因数
int multiple; // 乗数

n0=atoi(argv[1]);
num=atoi(argv[1]); // 整数を入力
// 因数分解
for( n=n0,ns=2; n>=ns; ns++ )
{
for( j=0; n%ns==0; j++ )
{
n /= ns;
}
if ( j==0 ) continue; // 1回も割り切れなかった
printf("素因数:%d 乗数:%d¥n",ns,j);
}

// 素因数分解
for( num_div=num,prime=2; num_div>=prime; prime++ )
{
for( multiple=0; num_div%prime==0; multiple++ )
{
num_div /= prime;
}
if ( multiple==0 ) continue; // 1回も割り切れなかった
printf("素因数:%d 乗数:%d¥n",prime,multiple);
}

}
}

XPJUG関西 / XP寺子屋
30

3.コピペ禁止

!
幅Up
大
生産性
で
コピペ
?
のでは
な

XPJUG関西 / XP寺子屋
31

3.コピペ禁止

ダメ、絶対!
XPJUG関西 / XP寺子屋
32

「コピペ禁止」の理由
• コピペすると、同じコードが重複して存在することになる。
• ある場所でバグが発生すると、重複するコードすべて変更
する必要がある。うっかり修正が漏れると、バグが発生。
• 更にややこしいのは、「関数A」では修正必要だが、「関数
B」では変更してはならない場合。それが簡単に気付ける
かどうか想像して欲しい。

• コピペはバグの温床と知るべし。

XPJUG関西 / XP寺子屋
悪い例
//----------------------------------------int FuncA( int *array, int array_cnt )
{
int idx;
for( idx=0; idx<array_cnt; idx++ )
{
printf( "%d ", array[idx] );
}
printf( "¥n" );
}
//----------------------------------------int FuncB( int *array1, int array_cnt1,
int *array2, int array_cnt2 )
{
int idx;
int *array;
int array_cnt;
array
= array1;
array_cnt = array_cnt1;
for( idx=0; idx<array_cnt; idx++ )
{
printf( "%d ", array[idx] );
}
printf( "¥n" );
array
= array2;
array_cnt = array_cnt2;
for( idx=0; idx<array_cnt; idx++ )
{
printf( "%d ", array[idx] );
}
printf( "¥n" );
}

XPJUG関西 / XP寺子屋

33
改善例
//----------------------------------------int FuncA( int *array, int array_cnt )
{
int idx;
for( idx=0; idx<array_cnt; idx++ )
{
printf( "%d ", array[idx] );
}
printf( "¥n" );
}
//----------------------------------------int FuncB( int *array1, int array_cnt1,
int *array2, int array_cnt2 )
{
int idx;
int *array;
int array_cnt;
array
= array1;
array_cnt = array_cnt1;
for( idx=0; idx<array_cnt; idx++ )
{
printf( "%d ", array[idx] );
}
printf( "¥n" );
array
= array2;
array_cnt = array_cnt2;
for( idx=0; idx<array_cnt; idx++ )
{
printf( "%d ", array[idx] );
}
printf( "¥n" );
}

XPJUG関西 / XP寺子屋

//---------------------------------------------------------void arrayPrint( int array, int array_cnt )
{
int idx;
for( idx=0; idx<array_cnt; idx++ )
{
printf( "%d ", array[idx] );
}
printf( "¥n" );
}
//---------------------------------------------------------int FuncA( int *array, int array_cnt )
{
arrayPrint( array, array_cnt );
}
//---------------------------------------------------------int FuncB( int *array1, int array_cnt1,
int *array2, int array_cnt2 )
{
arrayPrint( array1, array_cnt1 );
arrayPrint( array2, array_cnt2 );
}

小さい関数を作る事で、再利用性が
向上します。

34
35

4.1関数1機能

に
イイの
コ
がカッ
方
複雑な
関数は

XPJUG関西 / XP寺子屋
36

4.1関数1機能
• シンプル(=簡単)にコードを書くためには、複
雑なコードを書いてはダメ。
• 関数は「小さい機能をまとめる」のはNG。
• 「小さい関数をたくさん作る」方がシンプル。

XPJUG関西 / XP寺子屋
37

悪い例
/********************************/
/* ファイルの内容を1行づつ表示 */
/********************************/
#include <stdio.h>
int main(void)
{
FILE *fp;
char *fname = "test.txt";
char str[100];
fp = fopen( fname, "r" );
if( fp == NULL )
{
printf( "%sファイルが開けません¥n", fname );
return -1;
}
printf( "¥n-- fgets() --¥n" );
while( fgets( str, 100, fp ) != NULL )
{
printf( "%s", str );
}
fclose( fp );
return 0;
}

XPJUG関西 / XP寺子屋
38

改善例
/********************************/
/* ファイルの内容を1行づつ表示 */
/********************************/
#include <stdio.h>
int main(void)
{
FILE *fp;
char *fname = "test.txt";
char str[100];
fp = fopen( fname, "r" );
if( fp == NULL )
{
printf( "%sファイルが開けません¥n", fname );
return -1;
}
printf( "¥n-- fgets() --¥n" );
while( fgets( str, 100, fp ) != NULL )
{
printf( "%s", str );
}
fclose( fp );
return 0;
}

XPJUG関西 / XP寺子屋

/********************************/
/* ファイルの内容を1行づつ表示 */
/********************************/
#include <stdio.h>
//------------------------------int main()
{
FILE *fp = NULL;
fp = openFile( "test.txt" ) ;
if( fp == NULL )
{
printf( "%sファイルが開けません¥n", fname );
return -1;
}
displayFile( fp );
closeFile( fp );
return 0;
}
//------------------------------FILE* openFile( char * fname)
{
return fopen( fname, "r" );
}
//------------------------------void displayFile( FILE* fp )
{
char str[100];
printf( "¥n-- fgets() --¥n" );
while( fgets( str, 100, fp ) != NULL )
{
printf( "%s", str );
}
}
//------------------------------void closeFile( FILE *fp )
{
fclose( fp );
}
39

5.ボトムアップアプローチ

ょ!?
が普通でし
の
上から書く

XPJUG関西 / XP寺子屋
40

5.ボトムアップアプローチ
• 下(下層)の関数から書く。
• 作った関数単体でテストする。
• テストがパスすれば、その関数の1つ上位関数
を作り、以降これを繰り返す。

XPJUG関西 / XP寺子屋
41

ボトムアップアプローチのメリット
• 下位関数から開発するので、コンパイルが通
しやすい。
• 足元からしっかり開発するので、バグが混入し
にくい。
• 呼び出す関数を考慮しなくて済むので、開発
中の関数にのみ集中できる。

XPJUG関西 / XP寺子屋
42

悪い例
/********************************/
/* ファイルの内容を1行づつ表示 */
/********************************/
#include <stdio.h>
//------------------------------int main()
{
FILE *fp = NULL;

①

fp = openFile( "test.txt" ) ;
if( fp == NULL )
{
printf( "%sファイルが開けません¥n", fname );
return -1;
}
displayFile( fp );
closeFile( fp );
return 0;
}
//------------------------------FILE* openFile( char * fname)
{
return fopen( fname, "r" );
}

②

//------------------------------void displayFile( FILE* fp )
{
char str[100];
printf( "¥n-- fgets() --¥n" );
while( fgets( str, 100, fp ) != NULL )
{
printf( "%s", str );
}
}
//------------------------------void closeFile( FILE *fp )
{
fclose( fp );
}

XPJUG関西 / XP寺子屋

③

④

①~④の順に開発する
43

改善例
/********************************/
/* ファイルの内容を1行づつ表示 */
/********************************/
#include <stdio.h>

/********************************/
/* ファイルの内容を1行づつ表示 */
/********************************/
#include <stdio.h>

//------------------------------int main()
{
FILE *fp = NULL;

//------------------------------int main()
{
FILE *fp = NULL;

①

fp = openFile( "test.txt" ) ;
if( fp == NULL )
{
printf( "%sファイルが開けません¥n", fname );
return -1;
}
displayFile( fp );
closeFile( fp );
return 0;
}
//------------------------------FILE* openFile( char * fname)
{
return fopen( fname, "r" );
}

④

fp = openFile( "test.txt" ) ;
if( fp == NULL )
{
printf( "%sファイルが開けません¥n", fname );
return -1;
}
displayFile( fp );
closeFile( fp );
return 0;
}

②

//------------------------------FILE* openFile( char * fname)
{
return fopen( fname, "r" );
}

③

//------------------------------void displayFile( FILE* fp )
{
char str[100];
printf( "¥n-- fgets() --¥n" );
while( fgets( str, 100, fp ) != NULL )
{
printf( "%s", str );
}
}

③

//------------------------------void displayFile( FILE* fp )
{
char str[100];
printf( "¥n-- fgets() --¥n" );
while( fgets( str, 100, fp ) != NULL )
{
printf( "%s", str );
}
}

②

//------------------------------void closeFile( FILE *fp )
{
fclose( fp );
}

④

//------------------------------void closeFile( FILE *fp )
{
fclose( fp );
}

①

XPJUG関西 / XP寺子屋

①~③は最下層なのでどの順に開発しても良い
44

ポイント
• この方法を実現するためには、xUnitなどのテ
スト環境が必要。
• テスト環境が無ければ、main( )から開発中の
関数を呼び出せばOK。関数を追加する度に
main( ) を変更する。最後にmain( )を実装す
る。

XPJUG関西 / XP寺子屋
45

6.インクリメンタル開発

手戻
りは
悪!

XPJUG関西 / XP寺子屋
46

6.インクリメンタル開発
インクリメンタル(機能を順次追加する)に開発する。
①手短な設計 → ②テスト → ③コード → ④リファクタリング
これを、関数単位に実施する。
①手短な設計
– 関数の仕様を考える
• ②テスト
– 関数のテストパターンを考える
– xUnitのテストコードを書く
• ③コード
– テストがパスする様、製品コードを書く
• ④リファクタリング
– コードを見直し、必要であれば修正する。
•
•
•
•

XPJUG関西 / XP寺子屋
47

悪い例
/********************************/
/* ファイルの内容を1行づつ表示 */
/********************************/
#include <stdio.h>
//------------------------------int main()
{
FILE *fp = NULL;

①

fp = openFile( "test.txt" ) ;
if( fp == NULL )
{
printf( "%sファイルが開けません¥n", fname );
return -1;
}
displayFile( fp );
closeFile( fp );
return 0;
}
//------------------------------FILE* openFile( char * fname)
{
return fopen( fname, "r" );
}

•①~④の順に開発する
•一気にテストを実施
•バグってたら修正

②

//------------------------------void displayFile( FILE* fp )
{
char str[100];
printf( "¥n-- fgets() --¥n" );
while( fgets( str, 100, fp ) != NULL )
{
printf( "%s", str );
}
}

③

//------------------------------void closeFile( FILE *fp )
{
fclose( fp );
}

④

XPJUG関西 / XP寺子屋

•手短な設計

•「リファクタリング」しない
改善例
/********************************/
/* ファイルの内容を1行づつ表示 */
/********************************/
#include <stdio.h>
//------------------------------int main()
{
FILE *fp = NULL;

•①開発
④

fp = openFile( "test.txt" ) ;
if( fp == NULL )
{
printf( "%sファイルが開けません¥n", fname );
return -1;
}
displayFile( fp );
closeFile( fp );
return 0;
}
//------------------------------FILE* openFile( char * fname)
{
return fopen( fname, "r" );
}

③

•テストパターン検討
•①開発
•main( )から①を呼び出しテスト
•①リファクタリング
•②開発
•手短な設計

//------------------------------void displayFile( FILE* fp )
{
char str[100];
printf( "¥n-- fgets() --¥n" );
while( fgets( str, 100, fp ) != NULL )
{
printf( "%s", str );
}
}

②

//------------------------------void closeFile( FILE *fp )
{
fclose( fp );
}

①

XPJUG関西 / XP寺子屋

•手短な設計

•テストパターン検討
•②開発
•main( )から②を呼び出しテスト
•②リファクタリング

48
49

「シンプル・プログラミング
6つの原則」
をご紹介しました。
XPJUG関西 / XP寺子屋
50

シンプル・プログラミング6つの原則
1.
2.
3.
4.
5.
6.

コメントの書き方
名前の付け方
コピペ禁止
1関数1機能
ボトムアップアプローチ
インクリメンタル開発

XPJUG関西 / XP寺子屋
51

しかし、開発状況により
「6つの原則」を守れない
場合があります。
XPJUG関西 / XP寺子屋
52

•新しい考え方を導入する時間が無い
•メモリ空き容量が少なく、関数をまとめる必要
がある
•高速化のため、変数名を短くする必要がある
などなど。

XPJUG関西 / XP寺子屋
53

大切なのは、
「分かりやすい」事.
XPJUG関西 / XP寺子屋
54

最後までお付き合い頂き、ありがとうございます。
XPJUG関西 / XP寺子屋

XP寺子屋第9回「シンプル・プログラミング」