メンバページ: Go
美人プログラミングスタイル by Java
Beauty Oriented Programming Style by Java
このページは、「美人」を目指すプログラミングスタイルについての話を掲載していきます。
- A: 美人プログラムスタイルって、なんですか
- G: 中身は別にして、眺めるだけで幸せになるプログラムじゃ
- A: ははぁ、アルゴリズムやクラス構造などの中身でなく外見重視なんですね
- G: 昔から七難を隠すというじゃろ、色白美人は」と
- A: え、つまり、バグが7個あると言うんですか
- G: こらこら、言葉尻を突くんじゃないのじゃ。それじゃ行くぞ
| 1日目 | 美人プログラムとは |
| 2日目 | 原則の1. かわいく |
| 3日目 | 原則の2. かんたん |
| 午前 | 簡単に書く編 |
| 午後 | 分かりやすく書く編 |
| 4日目 | 原則の3. きれい |
| 5日目 | 原則の4. バランスよく |
| 6日目 | そしてエレガントに |
| 7日目 | まとめ、参考文献 |
1日目 --- 美人プログラムとは
ここではプログラミングスタイルについて書いていきます。
技法よりもスタイル中心
プログラミング技法については、多くの文献で紹介、解説されていますが、 プログラミングスタイルについてあまり紹介されていません。また同様な 名前の文献でも技法が中心に書かれていることが多いようです。
そこでここでは、アルゴリズムやクラス構造などの技法にはあまり触れずに、表面的な外見的なスタイルに拘って 書いていきたいと思います。例えて言えば、お化粧の仕方を中心にする予定です。
- A 君: お化粧の仕方ですか。薄化粧ですか厚化粧ですか。
- G 君: うむ、これは最後の方に書く予定にしておるが、やはりバランスなんじゃ。
- A 君: え、久しぶりにまともなことを。厚化粧に限ると言うものと思っていたのに
プログラミングスタイルとは?
プログラミングスタイルとは、クラス設計やモジュール分割から、インデントの 制御までの細かいコーディング規約までを決めて、その結果として、プログラムの 外見的見栄え=スタイルとなります。
これはまたプログラミング書法の結果として、出てくるものです。
自然言語の世界では、文法規則があり、さらに書き方が あります。同様にプログラミング言語の世界でも構文規則があるだけでなく、 同様に書き方=スタイルがあります。
自然言語では小学生のことから学んできましたが、プログラムについては それほど多くの時間を使って学んできていません。しかし、自然言語の書き方の 考えを流用することにより、その学習期間を短縮することは可能です。
例えば、文法は正しくとも一つ一つの文が長く分かりにくい文章があります。 これは書き方がなっていないことを意味しています。プログラムでも同様のこと がありますが、これは自然言語と同じような規則「文章は簡潔に言いたいことだけ を書く」がそのまま使えます。
- A 君: 自然言語の下手な例がここには豊富にあるような気が・・・
- G 君: いや、ここは自然言語じゃなくて、Web 言語じゃ。
- A 君: また、はぐらかす・・・
美人プログラミングスタイルとは?
プログラミングスタイルで、人々を「外見」「スタイル」だけで魅了する ものを「美人プログラミングスタイル」と言います。
美人であるかどうかの判断は個々人によって異なる場合がありますが、 ここではなるべく最大公約数を取って書いていきます。しかし作者の好みが 多く入る可能性があります。
- A 君: なんだか八方美人のような気がしますが、最大公約数って言うのは
- G 君: うーん、好みを思いっきり出すと講師ができなくなる危険性が・・・
- A 君: それは止めましょう。八頭美人にしましょう。SD(スーパーデフォルメ)でなく
募集:美人プログラミングスタイル
皆様の美人プログラミングスタイルを募集します。 断片的でまとまっていないものでも結構です。 ここで紹介させていただきたいと思います。 公開用の名前(本名でもペンネームでも結構です)をメイルに 書いてもらえれば嬉しいです。(デフォルトは匿名にさせていただきます。)
- A 君: ということで本文でも募集していますが、ここでも募集します。
- G 君: ここはどんな過激な化粧でもいい。美人フィルタ(または美人リファクタリング)があれば便利じゃ
- A 君: 待って(い)ます!!!
See you again !!
2日目 --- 原則の1. かわいく
プログラムはかわいく、小さく
今日はプログラムを「かわいく」作ることを目指します。
「かわいく」とはどういうことでしょうか。一言で言えば、「小さい」ということです。これは物理的に小さいということと 機能的に小さいということを意味しています。
かわいく作ることの利点は、プログラムが見やすくなる(読解性・了解性が向上する)ことです。 これで他人からも「読まれる」「読むことが苦痛にならない」プログラムになります。プログラムの作者自身でさえ、 読み直すときに読みやすくなります。
逆にかわいくないプログラムとはどういうものでしょうか。Java プログラムで一つのメソッドが100行を超えれば、半分ぐらいの人がかわいくないと感じるでしょう。 1000行を超えれば、100%近くの人が大きすぎると感じるでしょう。
- A 君: 1000行はすごいですね。逆に感心しますが。
- G 君: まだまだじゃ、寒心レベルじゃ。1メソッド1万行を超えて、やっと神になれるんじゃ。
- A 君: 1ステートメントメソッドだけでプログラムを作るのはどうでしょう。
- G 君: おぉ、その意気や良し。但し if 文はもっての他じゃ。
それぞれの比率を「不快指数」または「違和感指数」と呼ぶようにします。つまり100行を超えれば不快指数は50%を超えると上記では言っています。
- A 君: やはり梅雨時になると不快指数はあがるんでしょうか
- G 君: 卒業式シーズンになるときも不快指数は上がるようじゃ。
- G 君: わしなんかついつい指が勝手にプログラムをかわいく作ってしまうもんじゃが。神にはなれん。
実務的にはどれくらいの大きさまででしょうか?
メソッド当たりの平均ステートメント数について、Java のオープンソースや実開発物件を多数計測したことがあります。この平均値は10行もなく、6,7行になります。
これは流行のフレームワークを使うとゲッター関数やセッター関数の定義が多く、その多くは1ステートメントで実装されます。 その結果、平均値を下げているためです。このような傾向がありますので、実務的な計測では、平均値だけでなく、分散も測定する必要があります。
例えば、閾値を全体の10%にするのであれば、60行当たりになります。注意:平均値が0の打ち切りに近い値になっていますので、 正規分布を仮定をせずに実測しています。但し、「標本調査」しただけで全数調査していません。
計測して分かるものとしては、フレームワークによって、大きさの平均と分散は大きく異なりますので、Java プログラムとひとくくりにしない方がいいでしょう。
もう一つの傍証として、メトリクスツールで警告を出すデフォルトの閾値があります。例えば、 JMA (Java Metrics Analyzer)ではデフォルトの閾値は50行になっています。ちなみに他の閾値のデフォルトは以下のようになっています。
- ファイル当たり、500行の命令行数
注意: 命令行数---コメントを除いた行数(宣言文は入る) - クラス当たり、300行のステートメント数、25行以上の平均ステートメント数
- メソッド当たり、50行のステートメント数、30個のメッセージ送信数
- A 君: 大体50行ぐらいなんでしょうか
- G 君: まぁ、違和感を持たれない限界じゃのう。
- A 君: 昔、キャラクターディスプレイを使っていたときは画面一杯20行程度はどうでしょう
- G 君: ほんの少し前、ラインプリンタを使っていたときは66行じゃ。横は80桁じゃ。大きすぎるが。
プログラム断片の個数を少なくする
プログラムの断片、例えばパッケージ、ファイル、クラス、メソッド、宣言などの断片の個数を多くしすぎないことも重要です。 例えば、1パッケージに100個のファイル(クラス)があれば、それは多すぎるでしょう。 プログラム作者も含めて誰もがすべての名前を覚えられないでしょう。
大きさのときと同様にJMA (Java Metrics Analyzer)のデフォルトの閾値を以下に示します。
- ファイル当たり、4個のクラス
- クラス当たり、50個の公開インスタンスメソッド数、1個の公開属性数
- メソッド当たり、20個のローカル変数、15個の分岐、10個の繰り返し
パッケージ当たりのファイル数の項目がありませんので、それを追加します。
- パッケージ当たり、30個のファイル
この数値の根拠はファイル一覧が1画面で収まる範囲にしています。この意味で50では多すぎるという意味です。
プログラムを小さく少なくする
プログラムを小さくして、かつプログラム断片の個数を少なくすることを同時にするにはどうしたら、いいでしょうか。
これは、プログラム断片の管理を階層化して、その階層化の個数を増加させることです。例えば、2万行のプログラムを50行に分割して、 一つのグループの個数を20個以内にするには、グルーピングの階層を3階層にすることで可能になります。
Java では、パッケージとクラスにおいて階層化が行えます。パッケージは階層化のためには最適です。クラスはネストクラスによる実装になりますが、 階層化するという機能としては弱く、その目的のために使うのはよくはないと思います。
構文的に可能なグルーピング 階層化パッケージ - ファイル/公開クラス - クラス - ネストクラス - メソッド 望ましいグルーピング 階層化パッケージ - ファイル/公開クラス - メソッド
- A 君: 結局は普通の文章を書くのと同じなんですね。章- 節 - 段落 - 文 の枠組みと。
- G 君: そうじゃ。節は階層化されているのが一般的じゃし。上の方へは「部」「巻」があるしの。
- A 君: 「続」とかいうことで無理やり継続させているものもありますが
今日はプログラムを小さく、個数を少なくすることと、その閾値について書いてきました。 明日はプログラムをかんたんに書くことを勧めるようにします。
See you again !!
3日目 --- 原則の2. かんたん
今日はプログラムを「かんたん」に書くことを目指します。プログラムも普通の文章と同じように簡単に書くことにより、 その読解性を向上させます。
プログラムを簡単に書く方法を示します。このための方法の一つに、昨日の「小さく」書くこともその一つです。 今日はそれに続く方法を示します。
簡単に書く編
定型的に書く --- パターン
プログラムを「定型的」に書くことが、結局は簡単に書くことに繋がります。これは、定型的に書くということは定型的な 「パターン」を使って書くことになります。自然にいいパターンは「簡単」なものになることからです。
- A 君: いわゆる「いつものパターン」ということですね。
- G 君: そうじゃ、文章でもそうじゃが、プログラムでもそうなんじゃ。
- A 君: ここもワンパターンですしね。
次に制御構造のパターンを取り上げてみます。
制御構造のパターン化 --- 構造化プログラミング
プログラムの制御構造をパターン化することでプログラムの制御構造を簡単化します。
プログラムの制御構造を少ない種類の簡単なパターンで記述します。これは(狭義の)構造化プログラミングになります。 この構造化プログラミングは、goto 文による制御構造の乱立を戒めています。
プログラムの制御構造のパターンの例を以下に記述してみます。
- 順次制御
これはプログラムの制御を順に実行されます。プログラムを上から下へ読むだけでその流れがつかめます。 - 分岐制御
条件によって、プログラム断片の実行を制御します。これは条件が真のときに実行する、偽のときに実行する、 両者のときに別々のプログラム断片の実行を制御します。 言語に依存しますが、if, unless などがあります。 - 繰り返し制御
繰り返しの条件で制御することにより、プログラム断片の繰り返しの制御を行います。条件判断の場所によって、 前判断、後判断、途中判断があります。言語に依存しますが for, while, repeat, until, dotimes, dolist, for-enum などがあります。
繰り返し制御のパターンの例を上記に示しましたが、パターンを多くすることが目的ではありません。 逆に少なくすることを目的としています。効率をある程度悪くしても、パターン化することを推奨します。
ある言語では繰り返し制御をマクロ定義できるものがあります。確かに繰り返し構造に名前付けする機会が与えられ、 プログラムの自己記述性が向上しますが、やりすぎると第三者は頭を悩ます元になります。マクロ定義がそうであったのと同じようにです。
例えば、以下のある繰り返し構造の中から飛び出して繰り返し構造があるプログラムを考えます。
飛び出し多重繰り返しの例 --------------------------------------- loop1: // <--+ ...1... // | loop2: // <--|--+ ...2... // | | loop3: // <--|--|-------+ ...3... // | | | if (c1) goto loop1; else if (c2) goto loop2; // ---+--+ | ...4... // | goto loop3; // --------------+
これは構造が分離できませんので読解性が悪くなっています。構造を分離するために以下のように構造化してみます。
内包多重繰り返しの例
---------------------------------------
mainloop: // <-------+
call loop3(); // |
innerloop: // <--+ |
if (c1) { // | |
call loop1(); // | |
goto innerloop; // ---+ |
} else if (c2) { // | |
call loop2(); // | |
goto innerloop; // ---+ |
} // |
...4... // |
goto mainloop; // --------+
loop1(){
...1...
call loop2();
return;
}
loop2(){
...2...
call loop3();
return;
}
loop3(){
...3...
return;
}
構造が分離され、いわゆる「プログラムを上から下へ流れるように読解できる」ようになります。
単一機能 --- 1関数1機能
プログラムを複雑化する原因の一つは、1つのプログラム断片(メソッド、関数、クラス、パッケージ)に複数の機能を記述してしまう ことがあります。
そこでプログラミングの原則として、「1関数1機能」があります。つまり、一つのところには一つの機能だけを書くというものがあります。
名前に "and" や "or" が入っているものは複数の機能が含まれている危険性があります。同じように名前が長すぎると複数の機能が入っている危険性があります。
- G 君: and や or の名前を使っているメソッド名を見つけるのが、手じゃ。
- G 君: 他人のプログラムに「いちゃもん」をつける時に「アラ」を探す最初の入口なんじゃ。
- A 君: そうだったんですか。名前でばれないように気をつけないと・・・
独自性を出さない --- 標準使用
世の中の標準的なプログラムイディオム、スタイルを用いるようにします。
プログラムは文学作品ではありません。プログラム断片レベルで独自性、独創性、芸術性を出すことに開発コストを掛けるのではなく、 標準のものを使用することを勧めます。開発コストを掛けるところはここではなく、設計の方が効率がいいでしょう。
- A 君: プログラムは文芸作品ではないのですか。
- G 君: そうじゃが、どこにコストを掛けるかのコスト問題じゃ。概要レベルの設計に全生命をかけるんじゃ。
- G 君: それよりも力を入れるのが、名前じゃ、名前付け、ネーミングじゃ。名前が大切じゃ。全生命よりも大事じゃ。
- A 君: それにしては G って安易なネーミングのようですが。
今日の午前中は、プログラムを簡単に書く方法として、パターンの使用や単一機能、独自性の禁止について書いてきました。 今日の午後はプログラムを分かりやすく書く Tips を紹介する予定です。
分かりやすく書く編
今日の午後はプログラムの分かりやすさを出す Tips を紹介します。Tips の以下のものを紹介する予定です。
ネーミングこそ命
ネーミングは、プログラムの読解性を向上させる大きな「鍵」です。
まずは各プログラミング言語でのネーミングの慣習は踏襲するべきです。以下に Java プログラムの例を見ていきましょう。
-
Java のネーミングの慣習
- クラス名はキャピタライズする(単語単位に先頭の文字を大文字にする)
例. Book, MovingObject
クラス名は原則的には名詞句にする - インタフェース名はクラス名に準じ、"I"を先頭に付けることもある。また"IF"を後尾に付ける場合もある。
例. IDataAccess, IThreadRunning
実装クラスの名前に "Impl" または "Imple"を後尾に付ける場合もある。 - 定数は大文字にする
例. MAX_MEMBER, MAGIC_NUMBER - メソッド名や他の名前の先頭は小文字にし、後はクラス名と同じにする
例. get, movingByOthers - 複数の単語による名前はキャピタライズして接続する
例. movingObjectOnTheRoad
但し、定数のときは"_"アンダーバーで接続する。 - 述語関数(boolean を返す関数)のときは、"is" を先頭に付ける
- 型変換のときは"to"を中置する
- フィールド変数の参照、いわゆるゲッタ、セッタ、アクセッサは "get", "set", "access" を先頭に付ける
ネーミングは原則として Java Language Specification, Section 6.8: Naming Conventions に従いましょう。
このネーミング規則を遵守するだけでなく、プログラムを分かりやすくするために さらに工夫を行ないます。
ネーミングはそれ自体、プログラムの意味論を与える大きな材料になります。 いい名前を付けることがプログラムを分かりやすくし、逆に悪いネーミングはプログラムそのものの価値を半減させます。
いいネーミングとは、意味論が簡潔に表現されていることです。これをするための 方法を以下に示します。
- 短い名前にする
単語3個は既に長すぎる - 英語表記かつ一般的な単語にする
一般的な用語:ポケット英和辞書でも載っている単語 - 情報のある名前にする
情報の少ない名前の例. data, inf(o), val(ue), var, fun(c), flag, state, delegate
但し、一時的なエクステントかつ限定されたスコープであれば、慣例的に i などを使用する場合もある - 母音を省略しない、発音しやすい名前にする
- 名前のタイプを先頭の数文字で表現する、いわゆるハンガリアン記法は行なわない
- 意味論と名前を一致させる
上記のものは、どちらかというと「やってはいけない」ネーミング方法の逆を 言っているだけで、「エクセレント」「エレガント」なネーミングではないかも 知れません。しかし、これらを遵守するだけで分かりやすいプログラムになります。
- A 君: 名前は自分の名前(A 君)も含めて安易になりがちですね
- G 君: それではいかん。韻を踏んで発音もエレガントな名前にするべきじゃ
- A 君: 例えば?
- G 君: ToneTingKann なんかがいいのう。Javava もいいかのう。
宣言と使用は近くに
例えば、変数のタイプ(クラス)とスコープの宣言の位置が実際の変数の使用の位置 が離れていることは望ましくありません。タイプが存在する言語ではもちろんですが、 タイプがない言語においてもスコープを明示的にするためにも、宣言と使用はなるべく 近くにある方が望ましいと言えます。これにより、タイプやスコープの情報が直ぐに分 かるようになります。
以下に例を示します。
int i; for (i = 0; i < MAX; i ++) // 宣言で使用が別のブロックになっている ↓ for (int i = 0; i < MAX; i ++) // 宣言と使用が同じブロックにある
- A 君: 近ければいいということですね
- G 君: {int i; for (i = 0 のように明示的にブロックを作って使っておったもんじゃ、C では。
- A 君: 嘘?
- G 君: ほっほっほ
異体同名の禁止
同じ名前を文脈によって異なる意味論で使用することは、読者に混乱を招きます。
Body body = man.getBody(); HelthCheck(body.weight); ... body = machine.getContents(); MesureWeight(body.weight); ↓ Body manBody = man.getBody(); HelthCheck(body.weight); ... Body machineContents = machine.getContents(); MesureWeight(machineContents.weight);
それぞれ、折角、ネーミングの機会を与えられているのですから、有効に利用する べきでしょう。多くの場合、コンパイラにより空間効率は悪くはならないでしょう。
手動最適化の禁止
最近のコンパイラは最適化を多くやってくれていますので、手動による最適化を行 なうことでプログラムを分かりにくくすることは避けましょう。
例えば、定数項の計算はそのままにすることにより、計算過程も残すことにより、 読解性を向上させます。
HoursInYear = 365 * 24; // または DAYS_A_YEAR * HOURS_A_DAY
この定数項はもちろんコンパイル時に計算され、コンパイルコードに埋め込まれます。
他のいくつかの最適化について述べます。
- インライン展開
コンパイラに任せる。コンパイラによっては、インラインするサイズを指定できる。 - ループの最適化
ループの分割などの最適化もコンパイラに任せる。 CPU によって、最適な分割数や方法も異なる。for (int i = 0; i < MAX; i ++) ... ↓ for (int i =0; i < MAX / 4; i ++) ..., for (int i = MAX / 4; i < MAX / 4 * 2; i ++) ..., ...
のようにはしないようにしましょう - ループ内不変の取り出し → 行なう
これはコンパイル時では「不変性が保証できない」ことが多いので、不変変数は外側へ取り出す必要がある
手動最適化によって、プログラムが見にくくなっていないかどうかに注意を払ってください。そしてその最適化はコンパイラが 行なってくれているかどうかを確認することもいいことです。
トリッキーに書かない
トリッキーに書くとは、プログラムとして正しく動作し、かつ少ないコードで高速で動作させるために各種の技法を使って書くことです。
しかし、一般的にはプログラムが直感的に見にくくなることが多いです。
以下にトリッキーなプログラミングの例を示します。
if (x = f(y = z)) {
これが何をしているか、直ぐにわかりません。 代入文と引数渡し、条件判断を同時に行なっているため、わかりにくくなっています。
これは以下の方がわかりすいものになります。
y = z;
x = f(y);
if (x) {
- A 君: わかりやすいですか
- G 君: 結局、1機能1文じゃ。同時に一杯は駄目じゃ、それだけじゃ。
See you again !!
4日目 --- 原則の3. きれい
今日はプログラムをきれいに書くことをやっていきましょう。
全体のスタイル
全体のスタイルはプログラムのプロポーションの決め手
他人のプログラムを読むときに、まず目に入るのが全体のスタイルの外見です。 そして、その外見からそのプログラムを評価を行ないます。これは人間の場合でも同じかも知れません。
この意味で外見をきれいにすることは重要です。例えば、1行の文字数は外見に大きく影響を与えます。太りすぎはもちろん駄目ですが、 やせすぎもよくありません。別の例では文字の密度があります。文字だらけにする、逆にすかすかにするかです。これも外見です。
- A 君: めりはりのあるプロポーションの方がいい?
- G 君: プログラムの話じゃが、いわゆる「階段の踊り場」に相当するものは必要じゃが、それ以外はのう。
- A 君: それと色白の方が言い?それとも色黒?
- G 君: 中間、中庸じゃ。白すぎず、黒すぎずじゃ。
それでは、どれくらいのものがいいでしょうか。また、どのような項目があるでしょうか。それを以下にまとめてみます。
- 1行は80文字以内 (ASCII 文字換算で)
このために、各エディタに80文字を越えないように設定すると便利です。Eclipse についてはここを参照。
強制改行のタイミングを統一する必要があります。例えば、演算子の直前(または直後)に統一する。 - 1行の複文はしない
- トークンの区切りには空白文字
例. x = x + 1 - 空行を入れて、1画面の文字密度を調整
但し、1画面の情報量が減少するので、入れすぎには注意
インデンテーション
インデンテーションはきれいに見せる技術 --- 統一することが重要
プログラムの字下げをどの程度にするか、つまりインデントをどこにするかは、プログラミングスタイルの中心的な役割を持っているものになります。
このインデンテーションを統一することがまず重要です。通常のエディタにはオートインデント機能が付いていますので、 ユーザが制御するのは「改行」するタイミングです。インデントそのものは、そのエディタのインデントの設定を変更することになります。
インデンテーションの流派を見ていきましょう。
- カーニハン&リッチー派
関数内部は「傾斜」させ、関数そのものは改行後に開き括弧が来る
例.void main () { if (test()) { ... } ... } - 純粋傾斜派
すべての括弧は開き括弧の前に改行をいれずに傾斜させる
例.void main () { if (test()) { ... } ... } - WhiteSmith派、Delphi 派
すべての開き括弧の前に改行を入れる
例.void main () { if (test()) { ... } ... }
ここでは改行の位置だけに注目して、改行後の空白文字数には触れていません。
統一することが重要であり、どの流派にするかはあまり問題ではありません。
これと同じように改行後の空白文字数をいくつにするかがあります。ハードタブは8文字の空白文字と同じ見栄えになりますので、 ソフトタブは8の約数にすることが多いです。つまりは、2文字か4文字、または8文字になります。このうち、4文字と2文字が多くあります。 4文字は横長になりますので、PC の画面的には合っているでしょう。2文字は縦長になりますので、プログラムコメントを多用するとき には有効でしょう。またレビューのときなどに2タブに変換して横に情報を入れることもあります。最後に8文字は大きすぎます。
ここも統一することが重要です。
- A 君: ここは宗教戦争と同じようになるところですね
- G 君: まぁ、Java であれば、JDK に合わすか、Swing に合わすかなど、合わせるものを決めればいいだけじゃ。
- A 君: 同じことでしょ。どれに合わせるかで哲学論争、宗教戦争へ行くんでしょ。
コメント
コメントはプログラムと同じぐらい重要
コメントはプログラムの読解性のために重要です。クヌースも「文芸プログラム」でそれを含んだ重要性を示唆しています。
この美人プログラミングスタイルでも、コメントもプログラム本体と同様に作品として、見栄えのあるものにしなければなりません。 もちろん、コメントの内容こそが重要ですが、ここでは見栄えのみを言及します。
ドキュメンテーションコメントの書き方
プログラムの断片(クラス、メソッド、関数、文)のドキュメントとして記述することを目的としています。Java であれば、このコメントをもとにして javadoc コマンドにより、このプログラム断片に対する HTML の説明書が生成されます。
Javadoc ではコメント中の単語の意味論として、引数 @param, 値 @returns などが用意されています。
ここでは上記の @属性を使用し、さらに「目立たない程度に HTML タグを入れて、気にならない程度に目立たせる」 ことを行ないます。ネオン街の灯りは目立ちませんが、田舎の電信柱の裸電球の灯りは目立ちますのでこれを目指します。
プログラムコメントの書き方
プログラムコメントは、プログラムのステートメントまたは複数のステートメントに対するコメントを記述します。
コメントの量
コメントは多すぎず、少なすぎずの量がいいでしょう。例えば、JMA のデフォルトでは 全体の 10% 以下であるとコメントが少ない という警告が出ます。 多すぎると感じたら、そのコメントは多すぎます。それはリンク経由で別の箇所にまとめるようにしましょう。
コメントに経過は書くか?---必要なときがあり、その場合は書く
一般的にはコメントには結果のみを記述をします。しかし、結果に通常と違い違和感のあるコードであるときで、 かつ納得の行く説明ができないときは、その経過を記述するようにして、このようなプログラムになったかを第三者 (往々にして将来の自分自身)に知らせるようにしましょう。
コメント禁止事項
- 嘘は書かない、嘘になってしまったら直ちに変更する
一つでも嘘があるとすべてのコメントに疑いの目が向けられる - 情報量の少ないコメントは書かない
情報量のないコメントは不要であるばかいでなく、有害になります。
例.void foo(int x) // 引数 x は整数で foo は値を返さない
コメントの発展
- 実行可能なコメント --- アサーション
関数やメソッドに、守られるべき条件を記述します
チェックプログラムの明示化→アサーションであることを示します
事前条件、事後条件などのアサーションを記述します
言語レベルで用意されていなければ、ライブラリを作ることはいいことでしょう - 文芸的プログラミング by クヌース
プログラムとドキュメントの一体化
WEB 言語により両者をワンストップで記述
- A 君: コメントですか、ここに妙に力を入れている人がいますね
- G 君: ちょっと肩に力が入りすぎて、プログラムが少なすぎて見つからないということもある
- A 君: 腹八分目ということでしょう
See you again !!
5日目 原則の4. バランスよく
まずは標語から
バランスこそが命
人にしろ、プログラムにしろ、美人に見えるためにはバランスが重要です。
バランスには、今までに書いてきたものがあります。プログラムとコメントのバランス、1行の文字数のバランス、 関数の大きさ、ファイルの大きさなど、結局はバランスよくということを訴えてきました。
このバランス感覚が「経験」に基づくもので形成されています。ここではそれを明示的な情報として示 すように努力してきました。しかしまだ頭の中に経験としてあるだけ(暗黙知)で、 言葉に表現していないことがあるかも知れません。この意味では「徒弟制度」が必要かも知れません。
- A 君: だんだん怪しくなってきましたね、催眠商法のような
- G 君: 暗黙知あたりがちょっと、まぁ徒弟制度はいいと思うんじゃが
- A 君: 師匠にもよりますが
- G 君: 弟子にもよるが
全体のバランスを考えて
個々のバランスと全体のバランスの両方とも重要です。
リズム感のあるプログラムに
万遍だらりとしたプログラムは読んでいても退屈です。起承転結があるプログラムが望ましいです。 そのためにはプログラム断片を小さくすることにより、ネーミング機会を増加させ、その名前によって、 リズム感を醸し出し、「読ませる」プログラムにします。
バランスの流行に乗って
「プログラムは他人に読ませるもの」から考えれば、バランスの取り方も世間の流行に合わせることが必要になります。
自分のスタイルが世の中で奇異と見られると、それだけでプログラムは読まれません。
中庸プログラミングを目指す
ちょうどよい長さのちょうどよい断片個数からなるプログラムが優れたプログラムに結局はなります。
- A 君: 言うのは楽なんですが、時間がないときにやるのが大変・・・
- G 君: 違〜う、無意識にやるのがコツじゃ、指が勝手に動いて作っていくんじゃ
- A 君: なんだか、怪しげな
バランスの悪いプログラムの見本、さらに障害の発生原因の見本
次にバランスの悪い、バランスの崩れたプログラムの例を見ていきましょう。これが障害の原因になること、 性能のネックの原因になる可能性が高いでしょう。 「アンチイディオムを収集して反面教師として使う」ように しています。
コピー&ペースト手法(またの名をサンプルリファレンス手法)
リファレンスとする既に存在するコードを「コピー&貼り付け」してコードを複製し、それの一部仕様を変更する手法です。 サンプルプログラムをリファレンスにするという意味で「サンプルリファレンス手法」または単に「サンプル手法」を呼んでいる人もいます。
この手法では類似コードが各地に散りまかれることになりますから、見た目に良くありません。 どこかで見かけた似たコードを何回も読まされることになります。
また、この手法では参照するプログラムの動作を理解せずにコピーして使用していることが多いため、 障害発生時の修正のコストが増大し、また修正漏れが発生する可能性が高くなります。 さらに仕様変更時の変更のコストが増大し、修正のときと同じように変更漏れの可能性があります。
差分化機能の未使用
オブジェクト指向プログラムで、差分化されていないプログラムには違和感を感じます。継承、インタフェース、コンポジショ、 デリゲーションなどを使用しての差分化をしていくようにしましょう。自然なオブジェクト指向機能の使用になります。
最後に上記の2点も加えて、障害の原因になる「バランスの悪いプログラム」の原因となったものを項目だけになりますが紹介します。
- コピー&ペースト手法(またの名をサンプルリファレンス手法)
- 差分化機能の未使用
- 大きすぎるメソッド、クラス
- 不要なオブジェクトの生成
- 多すぎるグローバル変数
- 繰り返し処理の中からの不変関数の呼び出し
- ハードコーディング
- 不適切な動的なメモリ確保
- コンパイラの警告無視
- 不要な GC の呼び出し
- 不適切な他言語インタフェースの使用
See you again !!
6日目 --- そしてエレガントに
エレガントなプログラムとは?
将来の拡張・変更を見越して、そのための仕掛けを作っておこう
将来の変更点: ホットスポット (効率だけから考えれば無駄になる)
その実装は、インタフェース、クラス、メソッド、インスタンス変数などで行う
例.ファクトリーパターンを始めとするデザインパターン。
ホットスポット → デザインパターン
実行を最初からテストできるように書こう
アサーション
事前アサーション、事後アサーション、ループ不変アサーション
テストケースをプログラムの前に作成しよう
テストファースト
芸術作品としてのプログラムを書こう
例. クヌースの The art シリーズ
ノープログラミング・プログラミング
プログラムをしないことがよいプログラムです。
- A 君: 最初の方はまだわかりますが、後の方は観念みたいですが
- G 君: ・・・ 無言の言じゃ
究極のプログラム
究極のプログラムを収集していきます。
問題は、究極のプログラムの合成は(たぶん)究極のプログラムではないことでしょう。
See you again !!
7日目 --- まとめ、参考文献
ここでは、いままでに出てきました美人プログラミングのための標語を一括掲載します。
- いままでに出てきた標語をまとめてみます。
- プログラムはかわいく、小さく
- プログラム断片の個数を少なくする
- プログラムを小さく少なくする
- 定型的に書く --- パターン
- 制御構造のパターン化 --- 構造化プログラミング
- 単一機能 --- 1関数1機能
- 独自性を出さない --- 標準使用
- ネーミングこそ命
- 宣言と使用は近くに
- 異体同名の禁止
- 手動最適化の禁止
- トリッキーに書かない
- 全体のスタイルはプログラムのプロポーションの決め手
1行80文字以内、複文禁止、中間の文字密度 - インデンテーションはきれいに見せる技術 --- 統一することが重要
- コメントはプログラムと同じぐらい重要
- ドキュメンテーションコメントは目立たない程度に HTML タグを入れて、気にならない程度に目立たせる
- コメントの量は少なすぎず、多すぎず。10% 以上。
- コメントに経過が必要なときがあり、その場合は書く
- コメントに嘘は書かない
- コメントに情報量の少ないものは書かない
- バランスこそが命
- 全体のバランスを考えて
- リズム感のあるプログラムに
- バランスの流行に乗って
- プログラムは他人に読ませるもの
- 中庸プログラミングを目指す
- アンチイディオムを収集して反面教師として使う
- 将来の拡張・変更を見越して、そのための仕掛けを作っておこう
- 実行を最初からテストできるように書こう
- 芸術作品としてのプログラムを書こう
- ノープログラミング・プログラミング
- 究極のプログラム
次に参考文献を示します。
-
プログラミング書法
- カーニハン、“プログラム書法”, 共立出版、 ISBN: 4320020855、第2版 (1982/06)
- 林晴比古, “Cによるプログラミング・スタイルブック”, ソフトバンク、ISBN: 4-89052-137-2(1990)
- ドナルド・E・クヌース, “The Art of Computer Programming
Volume1 Fundamental Algorithms Third Edition"
日本語版 ASCII Addison Wesley Programming Series, アスキー, ISBN: 475614411X , 1 巻 (2004/02/18) - Niklaus Wirth、”アルゴリズムとデータ構造“、近代科学社、ISBN: 4764901625、(1990/09)
- 有澤誠編、“クヌース先生のプログラム論”, 共立出版、ISBN: 4-320-02546-6, (1991)
- ドナルド・E・クヌース, “文芸的プログラミング”, Ascii software science—Programming paradim, アスキー, ISBN: 4756101909, (1994/03)
- カーニハン、リッチー、“プログラミング言語 C 第2版”, 共立出版、ISBN: 4-320-02483-4(1989).
- プログラミングの禁じ手Web版 C言語編、http://www.cmagazine.jp/src/kinjite/c/index.html
- Cプログラミング診断室、http://www.pro.or.jp/~fuji/mybooks/cdiag/index.html#mokuji8
- オープンソース: 例. SUN JDK, Jakarta TOMCAT
技法(art)
プログラミング思想
プログラミング言語
プログラミング技法(テクニック Tips)
オープンソース --- 優れたソースコードは、プログラミング書法のいいガイドである
みなさんも上記の標語を思い浮かべて、エレガントなプログラムを作成していきましょう。
See you again !!