帰りの電車でClean Codeを読んでいます。冒頭でインデントするとコードの品質が良くなるという話しがありました。生産現場における3Sを連想します。隅々まで気を配ることの大切さを教えてくれます。
- 作者: Robert C. Martin,花井志生
- 出版社/メーカー: アスキー・メディアワークス
- 発売日: 2009/05/28
- メディア: 大型本
- 購入: 27人 クリック: 914回
- この商品を含むブログ (83件) を見る
さて、今年、2回生向けのプログラミングの授業を演習だけ担当しています。Aクラス(要はできるクラス)担当です。本日、2回目がありました。Javaの復習でじゃんけんプログラムを作ってもらいました。
なかなか興味深い誤りを見つけました。さすがにAクラスということもあり、課題文を見るなりカチャカチャしてあっという間に仕様を満足するプログラムを書きあげてきました。うちの学生もなかなかのものです。
ただ。。。仕様は満足するものの指摘したくなる問題が2つほどありました。長くなりそうなので1つだけご紹介します。
じゃんけんは勝ちのパターンを列挙する必要があります。例えば、じゃんけんの手を1、2、3で表し2人対戦としたとき。。。
- プレイヤー1が「グー」でプレイヤー2が「チョキ」 または
- プレイヤー1が「チョキ」でプレイヤー2が「パー」 または
- プレイヤー1が「パー」でプレイヤー2が「グー」
のいずれかのときにプレイヤー1の勝利となります。
こうした条件をプログラムで記述するとif文で論理演算子(&&や||)を利用して記述するのが普通です。しかし、学生の中には、switch文とif文を組み合わせて記述したりif文を何階層にも渡って記述する子も見かけます。パッとひらめいたのでしょうね。。。恐らく。
答えは正しく表示されるので間違ってはいません。でもそうは書かないのです。非ネイティブの我々日本人が習いたての英単語や文法を組み合わせて作文するのと似ているような気がします。間違いではないけどそうは書かない、わけです。
こう(↓)は書いても、
if (hand1 == 1 && hand2 == 2 || hand1 == 2 && hand2 == 3 || hand1 == 3 && hand2 == 1) { System.out.println("プレイヤー1の勝ちです"); }
こう(↓)は書かないのです。
if (hand1 == 1) { if (hand2 == 2) { System.out.println("プレイヤー1の勝ちです"); } } if (hand1 == 2) { if (hand2 == 3) { System.out.println("プレイヤー1の勝ちです"); } } if (hand1 == 3) { if (hand2 == 1) { System.out.println("プレイヤー1の勝ちです"); } }
理由は条件判定する分岐が複数あり必要以上に複雑になっていること、要は、上記の例ですとプレイヤー1が勝つか負けるかを判定して2つの場合にわけるべきところを、悪い例では勝つ場合だけでも3つにわけています。場合わけが多くなることでプログラムの記述量は多くなりプログラムミスを起こす危険性が高まります。もちろんテストケースも増えます(追記:テストケースは増えませんね、パスが増えるの間違い)。
Clean Codeを帰りの電車で読みながら、この授業のことを思い返していました。「間違いではないけどそう書かない」ということをどう教えるか?とても大切なことだと思います。
コンピュータは処理速度は高速になり記憶容量も大容量になりました。それでも、必要十分にケチであることが求められます。ケチというよりは「わかりやすさ」「保守性」を重視します。プログラムは仕様に対して必要十分な量で記述されている必要があり決して動けばいいという「使い捨て」のものではありません(場合によってはそういうこともあるでしょうけど)。
プログラムの文法を学習したら、次は「普通に」効率の良いプログラムを書くこと、その教育をどうするか。。。他の教育機関ではどのように取り組まれているのでしょうか?とにかく一つ一つ「こういう理由でこうは書かない」ということを指摘するしか思いつきません。メトリクスのようなものがあればいいのですが。。。要求仕様に対してこのプログラムの複雑さは過剰です。75点です。といった具合に評価してくれるようなものです。でも要求仕様から仕様の複雑さを定量化しなければなりません。さらにその仕様を記述するプログラムの複雑さを数値化するとなるとこれまた頭を使わなければなりません。ちょっと関連研究、調べてみますか。。。