Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

2,220 views

Published on

  • Be the first to comment

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

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

×