プログラミング学習課題の紹介 - CodeKata

# はじめに
プログラミング初学者、特に一つ目のプログラミング言語を学習する際のあるあるに、「何を作ったらいいのか分からない」問題があると思います。とりあえず入門書は読んだ、が、その次に何をしたら良いか分からない、というやつです。これは学習者にとってだけではなく、教える側、課題を考える立場になって困っている方も多いのではないでしょうか。

社内勉強会でモブプログラミングをやってみた際、その書籍で勧められていた課題サイトがなかなか良かったので、簡単な補足付きで紹介します。

## CodeKata
http://codekata.com

コードカタと読み、カタは日本語の型（空手などの）から来ているとのこと。
海外では評判が良いサイトのようですが、日本語の情報はあまりなく、私も書籍を読むまで知りませんでした。

こちらにある課題の中から、今回は`Kata 4: Data Munging`を紹介します。

## Kata 4: Data Munging
http://codekata.com/kata/kata04-data-munging/

この課題は3つのパートに分かれています。

<dl>
  <dt>Part1: Weather Data</dt>
  <dd>一か月分の気象データが表現されたテキストファイルから、最高温度と最低温度の差が最小である日付を出力する。</dd>
  <dt>Part2: Soccer League Table</dt>
  <dd>2001/2の英国プレミアリーグの結果が表現されたテキストファイルから、得点数と失点数の差が最小であるチーム名を出力する。</dd>
  <dt>Part3: DRY Fusion</dt>
  <dd>Part1&2で作成した2つのプログラムから共通したコードを取り除き、より小さな2つのプログラムと共通機能にする。</dd>
</dl>

### Part1: Weather Data, Part2: Soccer League Table
扱うテキストファイルは以下のようなフォーマットになっています。

```weather.dat
  Dy MxT   MnT   AvT   HDDay  AvDP 1HrP TPcpn WxType PDir AvSp Dir MxS SkyC MxR MnR AvSLP

   1  88    59    74          53.8       0.00 F       280  9.6 270  17  1.6  93 23 1004.5
   2  79    63    71          46.5       0.00         330  8.7 340  23  3.3  70 28 1004.5
   3  77    55    66          39.6       0.00         350  5.0 350   9  2.8  59 24 1016.8
   4  77    59    68          51.1       0.00         110  9.1 130  12  8.6  62 40 1021.1
   5  90    66    78          68.3       0.00 TFH     220  8.3 260  12  6.9  84 55 1014.4
   6  81    61    71          63.7       0.00 RFH     030  6.2 030  13  9.7  93 60 1012.7
   7  73    57    65          53.0       0.00 RF      050  9.5 050  17  5.3  90 48 1021.8
   8  75    54    65          50.0       0.00 FH      160  4.2 150  10  2.6  93 41 1026.3
   9  86    32*   59       6  61.5       0.00         240  7.6 220  12  6.0  78 46 1018.6
  10  84    64    74          57.5       0.00 F       210  6.6 050   9  3.4  84 40 1019.0
  11  91    59    75          66.3       0.00 H       250  7.1 230  12  2.5  93 45 1012.6
  12  88    73    81          68.7       0.00 RTH     250  8.1 270  21  7.9  94 51 1007.0
  13  70    59    65          55.0       0.00 H       150  3.0 150   8 10.0  83 59 1012.6
  14  61    59    60       5  55.9       0.00 RF      060  6.7 080   9 10.0  93 87 1008.6
  15  64    55    60       5  54.9       0.00 F       040  4.3 200   7  9.6  96 70 1006.1
  16  79    59    69          56.7       0.00 F       250  7.6 240  21  7.8  87 44 1007.0
  17  81    57    69          51.7       0.00 T       260  9.1 270  29* 5.2  90 34 1012.5
  18  82    52    67          52.6       0.00         230  4.0 190  12  5.0  93 34 1021.3
  19  81    61    71          58.9       0.00 H       250  5.2 230  12  5.3  87 44 1028.5
  20  84    57    71          58.9       0.00 FH      150  6.3 160  13  3.6  90 43 1032.5
  21  86    59    73          57.7       0.00 F       240  6.1 250  12  1.0  87 35 1030.7
  22  90    64    77          61.1       0.00 H       250  6.4 230   9  0.2  78 38 1026.4
  23  90    68    79          63.1       0.00 H       240  8.3 230  12  0.2  68 42 1021.3
  24  90    77    84          67.5       0.00 H       350  8.5 010  14  6.9  74 48 1018.2
  25  90    72    81          61.3       0.00         190  4.9 230   9  5.6  81 29 1019.6
  26  97*   64    81          70.4       0.00 H       050  5.1 200  12  4.0 107 45 1014.9
  27  91    72    82          69.7       0.00 RTH     250 12.1 230  17  7.1  90 47 1009.0
  28  84    68    76          65.6       0.00 RTFH    280  7.6 340  16  7.0 100 51 1011.0
  29  88    66    77          59.7       0.00         040  5.4 020   9  5.3  84 33 1020.6
  30  90    45    68          63.6       0.00 H       240  6.0 220  17  4.8 200 41 1022.7
  mo  82.9  60.5  71.7    16  58.8       0.00              6.9          5.3

```
いわゆる固定長データというやつですね。
これを読み込み、データとして扱おうとする場合、以下のようなポイントが考えられます。
* そもそものファイルの読み方
* 横方向の区切り（以後「フィールド」と呼ぶことにします）をどうするか
* フィールドごとのデータをどう扱うか。数字に`*`がついていることもある？
* ヘッダや空行、合計行？をどう処理するか

ファイルの読み方など、どのようなコードを書くかすぐに浮かばないレベルならば、これを書いてみるだけでも良いエクササイズになるでしょう。

実際に書いてみると分かりますが、目的は「最高温度と最低温度の差が最小である日付を探す」ことなので、実は無視できるデータも多く、要件を満たすだけならそこまで難しくはありません。

`Part2: Soccer League Table`もほぼ同じなので、Part1ができればすんなり書けると思います。

### Part3: DRY Fusion
この課題はここからが面白いところです。
2つのプログラムから重複する処理を共通化せよ、ということですが、どの部分を共通化するかで頭を悩ませることになります。

共通化のポイントを整理するために、このプログラムの処理をやや俯瞰的に見てみると
1. ファイルを開く
1. すべての行を読み込む
1. 1行ごとにデータを解析する
1. 特定の条件を満たす行データを抽出する
1. 抽出した行データに対して何らかの処理をする

といったステップが見えてきます。これらのどこを共通化するのかを考え、実際にプログラムに落としていくわけですが、人によって違いも出てきそうであり、なかなかに面白い課題です。

### Part3を終えた後に
CodeKataの課題には明確な正解がありません。重要なことは正解に辿りつくことではなく、その過程で学ぶことだとされています。

Part3の共通化についても、2つのケースだけに着目すれば、共通化は難しくないでしょう。そこでさらに、以下のような視点を追加すると選択肢はより広がり、工夫の余地が出てきます。
* データフォーマットと抽出条件が異なる、3種類目のファイルを扱うとしたら？今の共通処理はそのまま使える？
* 新しいファイルに対応する場合、どこに変更が必要なプログラム構造とすべきか
* 抽出条件に合う行が複数になる可能性を考慮するか？
* ヘッダやフッタの行数がファイルによって異なる場合はどうする？
* etc...

最終的には、どこまで汎用的に構えておくべきなのか？という、実際のシステム開発においてもよく直面するような命題に繋がってきます。

章末にある`Kata Questions`にも、興味深い問いがあります。

#### Kata Questions（機械翻訳）
* オリジナル・プログラムを書く際に行った設計上の決定が、共通コードを因数分解することをどの程度容易にしたのか、あるいは困難にしたのか。
* 2つ目のプログラムの書き方は、1つ目のプログラムの書き方に影響されましたか？
* できるだけ多くの共通コードを因数分解することは、常に良いことなのでしょうか？この要求のために、プログラムの読みやすさは損なわれましたか？保守性はどうですか？


# まとめ
実際にやってみて良かったプログラミング課題として、CodeKataの`Kata 4: Data Munging`を紹介しました。このような課題を探している方は試してみてはいかがでしょうか。

前述の通り明確な正解がありませんので、複数人でそれぞれ考え、共有し、議論することで真の学習効果を得られると思います。私たちの社内勉強会ではJavaを使ってやりましたが、参加者のレベルごとにクラスやメソッドの設計は異なったものとなり、得るものの多い勉強会になりました。