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

  • 1,079 views
Uploaded on

 

  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
No Downloads

Views

Total Views
1,079
On Slideshare
0
From Embeds
0
Number of Embeds
4

Actions

Shares
Downloads
4
Comments
0
Likes
3

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. 1 「シンプル・プログラミング」 2013.11.02 XP寺子屋 XPJUG関西 / XP寺子屋
  • 2. 2 自己紹介 XPJUG関西 / XP寺子屋
  • 3. 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. 4 アジェンダ XPJUG関西 / XP寺子屋
  • 5. 5 アジェンダ • • • • • • • 「シンプル・プログラミング」講座 コードレビュー 休憩 練習 実習 ふりかえり あとかたづけ XPJUG関西 / XP寺子屋 - 50分 10分 5分 30分 90分 10分 10分
  • 6. 6 シンプル・プログラミング ? て何 っ XPJUG関西 / XP寺子屋
  • 7. 7 ようこそ「シンプル・プログラミング」の世界へ! XPJUG関西 / XP寺子屋
  • 8. 8 早速質問。 「シンプル」とは、どういう 意味? XPJUG関西 / XP寺子屋
  • 9. 9 XPJUG関西 / XP寺子屋 kotobankより引用。
  • 10. 10 続いて質問。 「シンプルなプログラム」 とは、どんなプログラム? XPJUG関西 / XP寺子屋
  • 11. 11 ●行数が少ない? ●関数の数が少ない? XPJUG関西 / XP寺子屋
  • 12. 12 大切なのは、 「分かりやすい」事. XPJUG関西 / XP寺子屋
  • 13. 13 どっちが簡単? XPJUG関西 / XP寺子屋
  • 14. 14 シンプルなプログラムのメリット • • • • • • • 間違いにくい バグが混入しにくい デバッグが簡単 他人が書いても分かりやすい バグの発見が容易 仕様変更が容易 性能改善も用意 XPJUG関西 / XP寺子屋
  • 15. 15 シンプルなプログラムのデメリット • 人に自慢できる複雑で難解なコードを書いて悦 に入る事ができない • 複雑なコードを理解した時に得られる達成感が 得られない • 残業できない XPJUG関西 / XP寺子屋
  • 16. 16 シンプルなプログラム と複雑なプログラム、 あなたはどちらを 選びますか? XPJUG関西 / XP寺子屋
  • 17. 17 シンプル・プログラミング6つの原則 1. 2. 3. 4. 5. 6. コメントの書き方 名前の付け方 コピペ禁止 1関数1機能 ボトムアップアプローチ インクリメンタル開発 XPJUG関西 / XP寺子屋
  • 18. 18 1.コメントの書き方 ? てた っ て知 っ XPJUG関西 / XP寺子屋
  • 19. 19 1.コメントの書き方 • 基本は、「コメントが不要なくらい分かり易いコード を書く」. • どうしても説明が必要な箇所にコメントを書く. • コメントは、「処理」では無く、「やりたい事」を書く. XPJUG関西 / XP寺子屋
  • 20. 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. 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. 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. 23 2.名前の付け方 にル ール があ るの ? XPJUG関西 / XP寺子屋
  • 24. 24 2.名前の付け方 • 一般的に、コーディング規約で命名規則が決まっ ている. • しかし、諸事情でコーディングルールが無かったり、 非オブジェクト指向言語では、分かりにくい名称 がはびこっている. • 最近のオブジェクト指向言語で提唱されている命 名規則を使用することで、コードの可読性が向上 し、シンプルなプログラミングが可能となる. XPJUG関西 / XP寺子屋
  • 25. 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. 26 命名規則(2) 変数名 • Boolean 変数 – – – – 形容詞,is + 形容詞,can + 動詞,has + 過去分詞,三単元動詞,三単元動詞 + 名詞. boolean isEmpty boolean dirty boolean containsMoreElements • 全て有意な名前を付ける – Info, Data, Temp, Str, Bufという名前は極力使わない – ループカウンタなどで用いる i, j, k も、適切な名前を付ける XPJUG関西 / XP寺子屋
  • 27. 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. 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. 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. 30 3.コピペ禁止 ! 幅Up 大 生産性 で コピペ ? のでは な XPJUG関西 / XP寺子屋
  • 31. 31 3.コピペ禁止 ダメ、絶対! XPJUG関西 / XP寺子屋
  • 32. 32 「コピペ禁止」の理由 • コピペすると、同じコードが重複して存在することになる。 • ある場所でバグが発生すると、重複するコードすべて変更 する必要がある。うっかり修正が漏れると、バグが発生。 • 更にややこしいのは、「関数A」では修正必要だが、「関数 B」では変更してはならない場合。それが簡単に気付ける かどうか想像して欲しい。 • コピペはバグの温床と知るべし。 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寺子屋 33
  • 34. 改善例 //----------------------------------------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. 35 4.1関数1機能 に イイの コ がカッ 方 複雑な 関数は XPJUG関西 / XP寺子屋
  • 36. 36 4.1関数1機能 • シンプル(=簡単)にコードを書くためには、複 雑なコードを書いてはダメ。 • 関数は「小さい機能をまとめる」のはNG。 • 「小さい関数をたくさん作る」方がシンプル。 XPJUG関西 / XP寺子屋
  • 37. 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. 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. 39 5.ボトムアップアプローチ ょ!? が普通でし の 上から書く XPJUG関西 / XP寺子屋
  • 40. 40 5.ボトムアップアプローチ • 下(下層)の関数から書く。 • 作った関数単体でテストする。 • テストがパスすれば、その関数の1つ上位関数 を作り、以降これを繰り返す。 XPJUG関西 / XP寺子屋
  • 41. 41 ボトムアップアプローチのメリット • 下位関数から開発するので、コンパイルが通 しやすい。 • 足元からしっかり開発するので、バグが混入し にくい。 • 呼び出す関数を考慮しなくて済むので、開発 中の関数にのみ集中できる。 XPJUG関西 / XP寺子屋
  • 42. 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. 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. 44 ポイント • この方法を実現するためには、xUnitなどのテ スト環境が必要。 • テスト環境が無ければ、main( )から開発中の 関数を呼び出せばOK。関数を追加する度に main( ) を変更する。最後にmain( )を実装す る。 XPJUG関西 / XP寺子屋
  • 45. 45 6.インクリメンタル開発 手戻 りは 悪! XPJUG関西 / XP寺子屋
  • 46. 46 6.インクリメンタル開発 インクリメンタル(機能を順次追加する)に開発する。 ①手短な設計 → ②テスト → ③コード → ④リファクタリング これを、関数単位に実施する。 ①手短な設計 – 関数の仕様を考える • ②テスト – 関数のテストパターンを考える – xUnitのテストコードを書く • ③コード – テストがパスする様、製品コードを書く • ④リファクタリング – コードを見直し、必要であれば修正する。 • • • • XPJUG関西 / XP寺子屋
  • 47. 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寺子屋 •手短な設計 •「リファクタリング」しない
  • 48. 改善例 /********************************/ /* ファイルの内容を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. 49 「シンプル・プログラミング 6つの原則」 をご紹介しました。 XPJUG関西 / XP寺子屋
  • 50. 50 シンプル・プログラミング6つの原則 1. 2. 3. 4. 5. 6. コメントの書き方 名前の付け方 コピペ禁止 1関数1機能 ボトムアップアプローチ インクリメンタル開発 XPJUG関西 / XP寺子屋
  • 51. 51 しかし、開発状況により 「6つの原則」を守れない 場合があります。 XPJUG関西 / XP寺子屋
  • 52. 52 •新しい考え方を導入する時間が無い •メモリ空き容量が少なく、関数をまとめる必要 がある •高速化のため、変数名を短くする必要がある などなど。 XPJUG関西 / XP寺子屋
  • 53. 53 大切なのは、 「分かりやすい」事. XPJUG関西 / XP寺子屋
  • 54. 54 最後までお付き合い頂き、ありがとうございます。 XPJUG関西 / XP寺子屋