プログラミングの学び方

技術,プログラミング言語

最近、誰かの質問に誰かが答えるサイトで、プログラミングの初級から中級へのステップアップに悩んでいる感じの質問を立て続けに見つけました。プログラミングに限らず初級から中級へというのはなかなか難しいものです。
そんなわけで、その辺りを少し書いてみます。

プログラミング入門は世に溢れている

プログラミングを学ぶ方法といえば、昔は書籍を読んだりしました。今はWebサービスが色々あります。自分がたまたま知っている範囲でも以下の様なサービスがあり、一部は無料で学べます。他にもあるかもしれませんが、そういうサービスをリストアップする目的ではないので、ここでは割愛します。

論理思考の教材としてプログラミングを学びたい、といったことであればこれらのサービスのお題をもとに学習しておしまいで問題ないと思います。
ただ、プログラミングを職にしようとしている方でしたらこれでは不足しています。

これらのサービスのお題を全て見たわけではありませんが、典型的なものは以下の様なお題を元に、その様に動く簡単なプログラムを作ることかと思います。

以下の様に2つの数値を受け取り、その和を計算するプログラムを作成しなさい。
2 3

※数値と数値は半角空白で区切り、最後に改行が含まれているものとする

言語はなんでも良いのですが、とりあえずRubyで書くとこんな感じです。

s = gets.chomp.split(" ")
sum = s[0].to_i + s[1].to_i
puts sum

もちろん、以下でも構いません。

s = gets.chomp.split(" ")
puts s[0].to_i + s[1].to_i

あるいはこうでも良いでしょう。

s = gets.chomp.split(" ")
print "#{s[0].to_i + s[1].to_i}\n"

サービスでは正解として1例が紹介されるでしょうが、あまりに非効率なものでもない限りは結果が得られれば問題ありません。

おそらく、多くの学習サービスではこうしたコードを書いて、できた動いた、よかったね、で終わります。
最初に書いたように論理思考の訓練としてならこれでも別に構いません。ただ、職業プログラマを目指すのであれば、動くものができたで終わってはいけません。

お題はプログラミングの半分に過ぎない

上のようにお題を与えられ、それに対してその通りに動くプログラムを書くことは、最低条件であって、十分ではありません。職業プログラマにとっては。

実際のプログラミングでは、お題に沿った内容以外に以下の様なものを書く必要があります。

  • 与えられたパラメータの数は正しいか、値は適切かのチェック
  • チェックで引っかかったものに対する対処(例えば、正しい入力をする様に促す等)
  • 万が一問題が起きた時の対処
  • etc

職業プログラマにとって、与えられたお題に沿ったコードは全体の半分か、それ以下に過ぎません。ユーザの入力や、他システムからの入力が正しい時に正常に動くのは当然として、誤った値が入ってきた時に正しくエラーになるか、異常動作を引き起こしたり、最悪プログラムが止まったりしないか。そういうことを念頭に置いて、考えられる限りの対策を打ちます。

もちろん、遊びで作るプログラムであれば、滅多に起きないケースは無視して、止まってしまっても「ああ、止まったよ」と呟くだけで済みます。しかし、お金や命に関わる様なものであれば、そうはいきません。

さらに、テスト駆動開発という手法を取るのであれば、お題のプログラムを書くまえに、それをテストするためのプログラムを先に書きます。もちろん、1通りではなくて色々な入力パターンに沿って、いくつものてテストプログラムを書きます。
ますます、お題の動作をするだけのコードの比率は低下していきます。

お題を動かしたら改善しよう

職業プログラマを視野にプログラミングを学ぶのであれば、お題に沿って動くコードを書いて終わりではなく、その次にいろいろな改善を行いましょう。それはお題にないことなので、上記のサービスの中に回答例はないでしょう。
でも、そうやって改善できることがないか考え、そのための方法を調べ、実際に書いてみて、結果を確認するのがプログラミングを学ぶということです。

では、どんなことを考えたら良いのかという点のサンプルをいくつかあげてみます。

半角空白ではなくて半角の"+"で区切ろう

お題では半角空白で2つの数値を区切っていますが、試しに"+"で区切る様にしましょう。これはちょっと調べればすぐにできると思います。

s = gets.chomp.split('+')
puts s[0].to_i + s[1].to_i

結果出力を親切にしよう

例えば、2つの入力値を受け取って単に結果を出力するだけでは不親切ですよね。もうちょっと、親切に計算式を表示する様にしましょう。

また、上記のサービスではあまりコメントを書くことはないかもしれません。また、なるべく短く書く様になっているかもしれません。昔は短く書くことが美徳とされたこともありましたが、現在はわかりやすく書くことの方を優先すべきだと思います。
しかし、職業プログラマは適切なコメントを書く必要があります。自分はこれは義務だと考えています。他人にわかりやすくするのは義務ですし、他人には半年後の自分を含みます。

# 2つの数値を取得(半角空白で区切られている前提)
s = gets.chomp.split(" ")

# 数値に変換
num1 = s[0].to_i
num2 = s[1].to_i

#結果を出力
print "#{num1} + #{num2} = #{num1 + num2}

文字を入力された場合に対応しよう

親切にするだけでなく、エラーに強いプログラムを作ることも大切です。

ユーザはこちらの思惑通りになんか入力してくれません。数値を入れろとメッセージを書いても、平気で文字を入力したりします。悪意がなくても、入力間違いはあるものです。

お題のプログラムに「a b」と入力してみると、なんの問題もなく動きはしますが、0という結果が表示されます。実際になんらかのプログラムでこんなことをして0とか表示されたら大問題なので、文字を入れたら数字を入れろと文句メッセージを表示するのが職業プログラマとしては当然でしょう。

言語や使っている命令によってはエラーになることもあります。例えばType missmatchみたいなエラーメッセージが出るかと思います。
そういうエラーが出たら、なぜそれが出たのかを確認し、対処方法を確認します。

チェックの仕方は色々あるかと思います。例えば、入力文字列を正規表現でチェックする、なんてところが定番でしょうか。何をいっているかわからないと言う方は「正規表現」を調べて、それを使いたい言語でどう利用するか調べてください。

あるいは、例外処理という仕組みを使う手もあります。実際のプログラミングでは多用するので、最初から慣れておくのも良いと思います。

上記の方法はそれぞれ宿題として、ここでは以下の様にチェックすることにします。

  • to_iメソッドに文字を与えると0を返す
  • 元の文字が0でないのにto_iが0を返したらおかしい

その方針をもとにプログラムを変更すると、例えばこんなものになります。

# 2つの数値を取得(半角空白で区切られている前提)
s = gets.chomp.split(" ")

# 数値チェック
value_check_ok = true

num1 = s[0].to_i
if s[0] != '0' && num1 == 0 then
    puts "1つ目の値が数値ではありません。数値を入力してください"
    value_check_ok = false
end

num2 = s[1].to_i
if s[1] != '0' && num2 == 0 then
    puts "2つ目の値が数値ではありません。数値を入力してください"
    value_check_ok = false
end

#結果を出力
puts num1 + num2 if value_check_ok

なお、上のコードにはロジック上の不備があり、入力する値によっては意図しない結果になります。どういう場合にそうなるか考えて、対策してみてください。

入力値が1つしかない場合に対応しよう

お題は入力時に半角空白区切りで2つの数字を並べる前提になっています。でも、ユーザは1つしか入力しないかもしれません。その場合に対応しましょう。
1つしか入力値を書かないと、最初のプログラムだとしれっとそのまま最初の数値だけ出力するでしょう。上の文字入力をエラーにするバージョンでは2つ目の値が数値ではありません、と言われるでしょう。他の言語や、違う方法で対応した場合はエラーになるかもしれません。

そうならないように、2つの数値を入力しなかったら2つ入れるようにメッセージを出す様にしましょう。
これも色々方法があると思いますが、ここでは以下の様にしてみました。

# 2つの数値を取得(半角空白で区切られている前提)
s = gets.chomp.split(" ")

value_check_ok = true

# 入力値が2つあるか確認(3つ以上もエラー)
if s.length != 2 then
    puts "数値を2つ入力してください。"
    value_check_ok = false
else
    # 数値チェック
    num1 = s[0].to_i
    if s[0] != '0' && num1 == 0 then
        puts "1つ目の値が数値ではありません。数値を入力してください"
        value_check_ok = false
    end
    
    num2 = s[1].to_i
    if s[1] != '0' && num2 == 0 then
        puts "2つ目の値が数値ではありません。数値を入力してください"
        value_check_ok = false
    end
end

#結果を出力
puts num1 + num2 if value_check_ok

お題のプログラムは最初の一歩に過ぎない

色々と改善内容を想定して幾つかのプログラムを掲載しました。元の簡単なプログラムからだいぶ違ったものになっているかと思います。でも、できることは(当たり前ですが)変わりません。変わらないのですが、現実のプログラムにはお題以外に書くべきことが色々あることが理解できれば幸いです。もちろん、現実のプログラムはこんなものではありません。

プログラミングの学習という面で大切なのは、単にお題に沿って動くものを作るだけではなく、こうしたら使いやすい、こうしたらエラーに強くなる、ということを自分で考え、試してみて、確認することです。
そうして色々試してみることで、こういう時にどうしたら良いか、こうしたいのだけど何が必要なのかという引き出しが増えていきます。その引き出しが多くなれば、実際の職業プログラミングで課題に直面した時に対応しやすくなります。

職業プログラマを目指す方は、プログラミング入門をやってみるだけに留まらず、それについてどうしたら良くなるか、そのために必要なことは何か、それを実現するのはどうするのか、ということを意識して、お題の先にあるものを実際にたくさん作ってみてください。