リスト１

public class SetScorer

{

private int[] games = {0, 0};



public void gameWon(int i){

games[i-1]++;

}



public String getSetScore(){

if ( games[0] < 6 && games[1] < 6) {

if(games[0] > games[1]){

return "Player1 leads " + games[0] + " - " + games[1];

} else if (games[1] > games[0]) {

return "Player2 leads " + games[1] + " - " + games[0];

} else {

return "Set is tied at " + games[1];

}

}

if (games[0] == 6 && games[1] < 5) {

return "Player1 wins the set " + games[0] + " - " +

games[1];

}

if (games[1] == 6 && games[0] < 5) {

return "Player2 wins the set " + games[1] + " - " +

games[0];

}

if (games[0] == 6 && games[1] == 5) {

return "Player1 leads 6 - 5";

}

if (games[1] == 6 && games[0] == 5) {

return "Player2 leads 6 - 5";

}

if (games[0] == 6 && games[1] == 6) {

return "Set is tied at 6 games";

}

if (games[0] == 7) {

return "Player1 wins the set 7 - " + games[1];

}

return "Player2 wins the set 7 - " + games[0];

}



}



リスト２

public class SetScorer {

private int[] gamesWon = {0, 0};



public void gameWon(int player){

gamesWon[player-1]++;

}



public String getSetScore(){

int leader = gamesWon[0] > gamesWon[1] ? 1 : 2;

int leadersGames = gamesWon[leader - 1];

int opponentsGames = gamesWon[leader == 1 ? 1 : 0];

String setScoreMessage = null;

if ((gamesWon[0] < 6 && gamesWon[1] < 6)

|| (leadersGames == 6 && opponentsGames == 5)) {

setScoreMessage = "Player" + leader + " leads " +

leadersGames + " - " + opponentsGames;

} else if (gamesWon[0] == gamesWon[1]) {

setScoreMessage = "Set is tied at " +

leadersGames;

} else if (( leadersGames - opponentsGames >= 2)

|| leadersGames == 7) {

setScoreMessage = "Player" + leader +

" wins the set " + leadersGames + " - " +

opponentsGames;

}

return setScoreMessage;

}

}



★

1. レイアウトへの配慮がない

2. 変数の扱い方の問題

3. 直感的表現の消失

4. 読者層が想定外

★

リスト３

public class SetScorer

{

private int[] gamesWon = {0, 0};



public void gameWon(int player){

gamesWon[player-1]++;

}



public String getSetScore(){



// どっちが優勢か

int leader = gamesWon[0] > gamesWon[1] ? 0 : 1;

int leadersGames = gamesWon[leader];

int opponentsGames = gamesWon[leader == 0 ? 1 : 0];



String scoreMessage = null;

if ((leadersGames < 6) || (leadersGames == 6 && opponentsGames == 5)) {

// 試合途中

scoreMessage = "Player" + (leader + 1) + " leads "

+ leadersGames + " - " + opponentsGames;

} else if (leadersGames == opponentsGames) {

// 同点

scoreMessage = "Set is tied at " + leadersGames;

} else if ((leadersGames - opponentsGames >= 2) || leadersGames == 7) {

// 試合終了

scoreMessage = "Player" + (leader + 1) + " wins the set "

+ leadersGames + " - " + opponentsGames;

}



return scoreMessage;

}

}



＠IT の「 キミのコードが汚い理由 」という記事を読んだ（ yasuhoの隠れ家 さん経由）。この記事には、テニスのスコアをつけるための２つの Java コード紹介がされている。「幼稚なスタイル」で書かれたとされる「リスト１」と、それを「クリーン」に書き直したとされる「リスト２」である。記事の中では、これらは単なる「前フリ」程度の扱いなのだが、「 読者指向プログラミング 」ということを考える上で、おもしろい題材なので、少し細かく見てみようと思う。元記事の趣旨に対しては「重箱の隅」的な指摘になるかと思うが、それは承知の上で、別のテーマとして読んでいただきたい。まず、元のソースコードは画像で公開されているので、テキストにしたものを以下に示しておこう。yasuhoの隠れ家さんも指摘されているように、リスト１の方が分かりやすいと感じる人も多いのではないだろうか。確かに、リスト２は数式的には「整理」はされているのだが、読みやすくはないように思える。いくつか、その原因を考えてみた。空行挿入、改行位置、インデントなど、レイアウトについての配慮が甘く、全体的に、目で追いにくい書き方になっている。もっとも、これは Web 掲載上の都合かもしれない。リスト２では、リスト１より変数が多くなっている。ここでは「優勢なプレイヤー」と「劣勢なプレイヤー」の勝ち数を明確にする意図があり、それ自体は悪いことではない。しかし、せっかく配列の内容を leaderGames、opponentGames という変数に入れ直しているのに、その後も元の配列を参照し続けているので、逆効果になっている部分がある。例えば、「gameWon[0] < 6 && gameWon[1] < 6」は単に「leaderGames < 6」でいいし、「gamesWon[0] == gamesWon[1]」も「leaderGames == opponentGames」でいい。また、２人のプレイヤーを数値で区別しているのだが、「0 と 1 で区別する場合」と「1 と 2 で区別する場合」が混在していて分かりにくい。そもそも、プレイヤーが２人しかいないのに、配列にする必要があるだろうか？ このあたりは、リスト１の書き方に引きずられている印象だ（比較しやすいように意図的にそうしているのかもしれないが）。更に細かいことを言えば、"set" で始まる変数名があるが、これは一見、関数（setter）のように見えるので、避けたほうがいいだろう。「幼稚なスタイル」のコードは、幼稚であるが故に読者にとって「直感的」であることも多い。逆に、コードを「整理」すると、その代償として、素直な表現が失われてしまうことがあるのだ。例えば、リスト１の if 文は処理としては冗長なのだが、条件が馬鹿正直に書かれているので、逆に分かりやすい。また、return しているメッセージの文字列も、リスト１ではやはり馬鹿正直に書かれているため、「文」として意味を取りやすい。コード内の文字列は、往々にして、そこで何が行われているのかを伝えてくれる。いわば「コメント的な効果」を持っているのだ。リスト２のメッセージは変数で分断されている箇所が多く、この効果が薄れている。もちろん、私もリスト１のような「幼稚な」書き方が良いなどと言うつもりはない。効率や汎用性、あるいは「他の角度から見た読みやすさ」のために、こうした直感的な表現が犠牲になることは、宿命だろう。しかし、そうした表現の効果について、知っておくということは必要である。「読者指向プログラミング」のテクニックのひとつになりうるからだ（※）これは読者側の問題になるのだが、英語が苦手な読者にとって、変数名が直感的に理解できないという問題もある。個人的には、"leader" や "opponent" といった単語が「優勢なプレイヤー」とその「対戦相手」であると理解するために、変数に代入している式を解読する必要があった。つまり、変数名が「a」や「b」でも同じだったわけだ。多くのプログラミング言語で、ソースコードはアルファベットと数字と記号で書くことになっている。このため、日本人向けのコードには、より多くのコメントが必要になる（漢字という「表意文字」の効果は絶大である）。しかし、リスト２の作者は日本の読者を想定していなかっただろう。こうした点を考慮しながら、リスト２を修正してみよう。といっても、全ての問題を同時に解決することはできない。全体のバランスを考えた「落とし所」を見極めることが必要だ。読みやすさという点において、いくらか良くなっていると思うが、どうだろうか。もちろん、コードの書き方に「正解」はない。私が自分でゼロから書いたとしたら、また違ったコードになるだろう。「読者指向プログラミング」について考えるには、適度な題材である。プログラマの方は、自分ならどう書くか、実際にやってみてはいかがだろうか。