職業プログラミングと競技プログラミングの違い

技術

Paizaのスキルチェックをやっていますが、どうにも競技プログラミング的です。それはそれでスキルアップに使えると思いますが、ただ競技プログラミングをしていても職業プログラミングのスキルは上がらないのではないかと感じています。

競技プログラミングとは

自分は競技プログラミングをやったことがありません。その立場で書いて良いのかわかりません。競技プログラミングについてはWebで調べれば色々情報があります。ここではその詳細は割愛しますが、自分の理解としてはこんな感じで捉えています。

私見・競技プログラミングとは

・より早く与えられた要求を満足するプログラムを正確に記述することを競う(Wikipediaより)
・コードの実行時間、メモリ使用量、プログラムの短さ、などで評価される
・国内外でいくつかの大会がある
・大会によっては就職へとつながることもある(らしい)

一方で、各種のソフトウェア開発のための普通のプログラミングが職業プログラミングです。そんな言葉はないですが、ここでは競技プログラミングとの対比のためにそう呼びます。

競技プログラミングの説明をしているサイトで、以下のようなことが書いてありました。

  • 楽しく学べる、達成感がある
  • スキルが早く身につく
  • 仕事のオファーが来る

確かに達成感とかあると思うし、モチベーションの維持につながると思います。また、オファーが来ることもあるのでしょう。ただ、スキルが早く身につくかというと…。

競技プログラミングでよくあるコードのテンプレートというものがあります。そこに出てくる部分はスキルアップするでしょう。また、問題を素早く読み解くスキルも上がるかも知れません。でも、おそらくいくつかの類型で処理できますよね?早晩、頭打ちしそうな気がします。やってないで語るのも烏滸がましいですけど。

何より、競技プログラミングで求められるスキルは職業プログラミングでのそれの一部にすぎません。正直、それより重要なスキルが山ほどあるよ、と感じます。それが自分が職業プログラマのスキルアップ手段としての競技プログラミングに否定的な最大の理由です。

Paizaのスキルチェック

Paizaのスキルチェックをやっていますが、競技プログラミングに近い様に感じます。お題に沿って回答をした後スコアが計算されます。そしてそれをもとにランキングというものが出てきて、あなたは○位です、とか表示されます。ただ、このスコアというのは時間内に正解すれば100点なので、ランキングの優劣は最終的に回答にかかった時間で決まります。要は早く解いたものがランキング上位になります。
ランキングはお題ごとに発表されるので、個人のランキング的なものはスキルチェックによってつけられるレーティングが該当するかと思います。ただ、こちらは順位が出るわけではなく、この人のレーティングは2000です、みたいに表示されるだけです。求人側にはランキング的なものを閲覧できるのかも知れません。Paizaの場合そのレーティングによって予想年収というものが表示されます。レーティングがちょっと違うと年収が微妙に上がる様です。ただ、きつい様ですが自分ならランクDは採用の検討もしませんし、Cは眺めてみるくらい。最低でもBは必要と思います。

Paizaは転職サイトでもあり、求人側担当者が登録メンバのスキルチェックで書いたプログラムを見ることができるらしいです。実際にプログラムまで見る人もいればみない人もいるでしょうし、どれくらいの人がプログラムを見て、その内容を参考にして採用するかどうかの資料にするのかは全くわかりません。あるいは、全然見ていないかも知れません。担当者は人事担当であって、技術者ではないケースが多いと思いますので。おそらくですが、プログラムよりは登録されている履歴書的な部分が一番重視されるのではないかと想像しています。

自分の場合、Paizaのランキングで上位を取ることに意義を見出せないのと、自分が担当者ならランキングで上位を取るための書くスピード優先、処理効率優先のプログラムよりも、ある程度実践に即したプログラムを見たいので、それなりにコメントも入れるし、処理もある程度見やすさベースで分割します。流石に、エラーチェックまでは書いているとキリがないのでしていませんけど。

なぜ競技プログラミングでは職業プログラミングのスキルが上がらないのか

もちろん、全く上がらないということはありません。お題を与えられてその求めるところを認識してプログラムを書くこと自体はスキルアップにつながると思います。ただ、競技プログラミングと職業プログラミングでは重視する観点が違います。

競技プログラミング

・(競技内容によると思いますが)書く速さとか、プログラムの速さ、メモリ効率等が重要
・保守性や可読性は重要ではない
・基本は個人が書いて使い捨てのプログラム

職業プログラミング

・必ずしもプログラムの実行速度やメモリ効率等が最優先ではない
・保守性や可読性も重要
・基本は何人かで分担して書くことが多く、ある程度の期間使われる、そのため提供期間中は不具合修正や機能改善を行うことが多い(もちろん、売り切りもあるでしょう)

私見ですが以上のように観点が違います。
競技プログラミングをそれとして楽しむのは構わないし、無意味とは言いません。ただ、いくら競技プログラミングをこなしても、職業プログラミングで必要な部分を伸ばすことはできません。それはそれ、これはこれと切り分けて、職業プログラミングに必要なスキルは別にスキルアップする必要があります。
そもそも、職業プログラミングだって分野や状況によって重視する部分は変わってきます。つまりは、その時その時の求められるものに最適なものを提供するために幅広い知識が必要になります。

プログラムの比較

という話をぐだぐだ書いてもわかりにくいので、一例を挙げてみます。実際の例はもっと複雑みたいですが、PaizaのDランクぐらいを想定した超簡単なサンプルで考えてみます。

正の数値i,j,kの3つが与えられます。iとjの和s1とjとkの和s2を比較して、大きいほうを出力してください。

ただし、i,j,kは1以上100未満とし、3つの数値は単一の半角スペースで区切られるものとします。数値は順不同です。また入力の末尾には改行がつきます。出力は数字のみ出力します。

これだとランクD以上C未満になってしまうかな。
例えば、"1 2 3″が与えられると2つの和は3と5なので5を出力。また、"6 8 4″なら14と12なので14になります。Paizaではこの2つの入力例と出力例が与えられて事前確認できるようになっているので、試してからコード提出の流れかと思います。実際にはこれを含め10個程度のサンプルが用意されていて、提出コードを実行してチェックすることになります。上記の制約条件があるので、0以下の数や文字が入力として与えられることはありません。

使うプログラミング言語はPaizaでは自分で選択できます。競技プログラミングも人気の言語とかあるので、選べるのでしょう。いくつかのサイトを調べてみましたが、おすすめとしてあげられているのはC++, Python, Java, C#, JavaScriptなどでした。多少の順番の違いと入れ替わりがありますが、左記とRubyくらいです。
AtCoderというサービスでは1位のC++が圧倒的で2位のPythonに5倍近い差があるとか。それでも3位についたJavaの倍あるというので、この2つが二強のようです。C++は解説が多く、テンプレとかも豊富であり、Pythonは書きやすいからでしょうか。

競技プログラミングでは

そんなわけで、上記のお題でPython3系で書いてみます。サービスによって評価基準は違うのかと思いますが、こんな感じかなというのを挙げてみます。競技プログラミングを学んでいるわけではないので、それっぽくなかったらご指摘いただけるとありがたいです。

items = input().split()
print(max(int(items[0]) + int(items[1]), 
                    int(items[1]) + int(items[2])))

見にくいので改行入れてます。これで仕様は満たしているので余計なことはしなくて良いのですが、これでは個人的には許せないので、Paizaのスキルチェックではもうちょっと足して以下のようなコードを提出しています。意味があるかはわかりませんけど。

# 半角空白区切の数値3つを取得
items = input().split()
n1 = int(items[0])
n2 = int(items[1])
n3 = int(items[2])

# 2つの和を計算
s1 = n1 + n2
s2 = n2 + n3

# 判定結果を出力
print(max(s1, s2))

正直、これでもだいぶモヤモヤしています。妥協の産物としてこれくらいは最低書くべきかと思って書いていますが、スキルチェック的にはおそらく意味がないし、競技プログラミング的には無意味どころか害悪かも知れません。
実際問題、職業プログラミングとしても最初のコードに適切なコードをつければ、この程度のロジックなら十分です。あくまで説明のためのものですので、ご承知おきください。

職業プログラミングでは

さて、上記のコードで実際ちゃんと結果は得られるし、入力値の制約条件もあるので問題が発生することはないでしょう。ただ、実際のソフトウェアではこれで良しとはできません。自分がこのコードをレビューしたら叩きまくります。入力元が何らかのシステムでもらえるデータが確実に保証されているのであればこれでも良いかも知れませんが、相手が人間なら絶対思った通りに入力なんてしてくれません。

実際入力が空行だったりすると、こんなエラーが出ます。

Traceback (most recent call last):
  File "Main.py", line 3, in <module>
    n1 = int(items[0])
IndexError: list index out of range

入力が2つしかなかったり、あるいは半角スペースではなくて全角スペースや他の記号を使っても同様なエラーが出ます。2〜5行目で数値が3つあることを前提にしているので当然です。

また、”1 2 a”みたいに数値でないものを紛れ込ませると、ちょっと違うエラーが出ます。

Traceback (most recent call last):
  File "Main.py", line 5, in <module>
    n3 = int(items[2])
ValueError: invalid literal for int() with base 10: 'a'

数値を与えることを前提としたものになっているので、これも当たり前です。競技プログラミングでは入力の制約条件から外れるデータなんて与えられないでしょうし、そのための制約条件です。
ただ、実際のソフトウェアではデータの入力条件を保証するのはプログラマ側です。それをどこでいつどれくらいやるかというあたりが肝になってきます。足りなければ問題があるし、そうかといってあちこちでチェックしまくるのも効率が悪いです。

とりあえず、入力が空だったり足りなかったら数値を3つ入れろと文句を言う様にしましょう。4つ以上あるのは目を瞑ることにします。

# 標準入力から1行取得
line = input()
if line == "":
    print("数値を半角スペースで区切って3つ入力してください")
    exit()

# 入力を3つの数値に分解する
items = line.split()
if len(items) < 3:
    print("数値を半角スペースで区切って3つ入力してください")
    exit()
    
# 3つの数値を文字列から変換する    
n1 = int(items[0])
n2 = int(items[1])
n3 = int(items[2])

# 2つの和を計算
s1 = n1 + n2
s2 = n2 + n3

# 判定結果を出力
print(max(s1, s2))

次に、数値ではなくて文字を入れた場合("1 2 a"とか)もエラーにならない様にしましょう。

# 標準入力から1行取得
line = input()
if line == "":
    print("数値を半角スペースで区切って3つ入力してください")
    exit()

# 入力を3つの数値に分解する
items = line.split()
if len(items) < 3:
    print("数値を半角スペースで区切って3つ入力してください")
    exit()
    
# 3つの数値を文字列から変換する
try:
    n1 = int(items[0])
    n2 = int(items[1])
    n3 = int(items[2])
except ValueError:
    print("数値を指定してください:%s"% line)
    exit()

# 2つの和を計算
s1 = n1 + n2
s2 = n2 + n3

# 判定結果を出力
print(max(s1, s2))

一般的にプログラマの仕事はプログラムを書くことと思われています。しかし、実際にはプログラムを書くのは仕事の半分かそれ未満です。プログラムの設計書を書いたり、テストのためのデータを用意したり、実際にテストしてみたり。そういうこともプログラマの仕事の一環なので、すごく広義では「プログラムを書く」の中に入ると言えるのですが、新人さんとかが最初に遭遇するギャップの一つです。
また、そのプログラムにしたって、実際にやりたい業務のコア部分の行数1に対して、そのための準備とか、チェックとか、前処理、後始末のそれ以外の行数が2倍どころか、5倍とか10倍とかになります。その競技プログラミングでは省みられない地味な部分がなければ成り立ちません。

自分が採用する立場になったら、この程度のプログラムは最低でも書けないとお断りするかと思います。新卒とか未経験ならこれからの教育次第という部分ではありますが、中途とか業務委託先のメンバーとか派遣できてもらう「経験者枠」だったら少なくとも保留です。

競技プログラミングについて説明しているサイトを見てみましたが、結局、普通の受験テクニックみたいなことが言われてました。やれ過去問をたくさん解けとか、テンプレを用意しておいてお題に沿ったものをすぐに使える様にしておくとか。もちろん、実際のソフトウェア開発でもそういうパターンはあって、その引き出しを多く持つことは重要です。
ただ、それにしても競技プログラミングのプログラミングスキルはとても偏った狭い範囲に見えるし、問題を読み解いてロジックを考えることと、ユーザが利用するソフトウェアの設計作業とは大きくかけ離れています。いきなり設計の仕事はしないまでも、エラーや妥当性のチェックもしないのが当然の世界と、それが必須の世界の差はとても大きい様に感じます。

まとめ

別に競技プログラミングを否定しないし、それはそれで面白いものだとは思います。頭の体操としては推奨しますし、とある言語を学ぶ際に活用するのもモチベーションを保つのに良いかと思います。

ただ、書く速さ、プログラム自体の速さや効率ばかりが必ずしも重要なわけではありません。そして、職業プログラミングで必要な知識、経験、スキルは競技プログラミングだけでは得られません。競技プログラミングを嗜むのは構いませんが、そちらではあまり重視されなくても職業プログラミングで必要なことを疎かにしないでください、という話です。

技術プログラミング言語

Posted by woinary