blog.hamadu.net

2017/12/23 - 社会人(プロ)になっても続ける趣味としての競技プログラミング

Tags: poem

この記事は「競プロ!!」 競技プログラミング Advent Calendar 2017 の23日目の記事として書かれた。

 私はプロのWebエンジニアとして、趣味で競技プログラミングを続けている。

 競技プログラミングは学生のスポーツである、とよく言われる。JOI,IOI(情報オリンピック) は高校生向けだし、ICPC(国際大学対抗プログラミングコンテスト) はその名の通り大学/大学院生が対象だ。また、多くの企業主催のコンテストは本戦への参加条件に「学生」「既卒未就業」であることを課している。

 最近は企業主催コンテストの増加に現れているように、競技プログラマを積極採用している企業が増えている。大変喜ばしいことだ。今年のICPCではグーグルやヤフーを始めとした名だたる企業がスポンサーとして参加した。一方、私はというとそんな企業に採用されることはなく、現在はベンチャー企業の一員として Rails 製のWebアプリケーションを書いたり、Android アプリを書いたり、自社サービスの運用を助けるシステムを書いたりしてる。そこに競技プログラミングで培ったスキルが活かせる余地は殆ど無いが、良い意味で、競技と仕事のプログラミングの住み分けができていると自負している。なので、私は現状に概ね満足している。ということで、本稿は chokudai氏の去年の記事 「競技プログラマは競プロのコンテストを開いてる会社に就職しろ!」 とは異なり、一人のWebエンジニアの視点から競技プログラミングを続けることについてのHowとWhyを述べていく。

どうやってるのか?

 競技プログラミングにお金はかからない。コンピュータとインターネット接続料金は必要だが、これらが無い生活は元々考えられないため無視できるだろう。が、時間のかかる趣味である。社会人になり自由な時間が減った後もモチベーションを高く保つには工夫が必要だと考えている。

記録をつける

 記録をつけることによって、定期的に過去問に取り組む動機づけをしている。私はこのような スプレッドシート を作って運用している。専用のWebアプリを書くことも考えたが、運用が楽であることが大事なのでここに行き着いた。

comp

 解いてない問題を探すのは別のサービスを使うことにして、このスプレッドシートは解いたことを忘れないために付けている。各プラットフォームごとにシートを用意して、項目を埋める。意味は以下の通り。

  • 理解: 解法を理解するのに時間がかかった問題にマーク
  • 方針: 方針を見出すのに時間がかかった問題にマーク
  • 発想: 解法の発想が難しい(思いつけば簡単)な問題にマーク
  • 実装: 実装に手間取った問題にマーク
  • 解けず: 解けなかった問題にマーク

解いた日付に Cmd+; を入力することで日付を入れるようになっている。これは複数回解いた場合右の列に伸びていく。最近まで「同じ問題を2度解くのは意味が無い」と思っていたが、過去に解説を呼んで理解したはずの問題を再度やってみたら解けず、考えを改めた。

 また、試験運用中だが「発想漏れ」のシートもある。これはコンテスト本番に参加したときに、思い至らなかった考えを列挙している。これは順位表を確認するなど、問題そのものではなくコンテストにおける戦略も含む。

コンテストに参加する

 コンテストに参加する事自体もモチベーションの維持を助けてくれる。向上心を保つため、定期的に悔しい思いをする必要がある。現在は週1回、時間帯の合う AtCoder にしか参加していないがこれで十分だ。ただし、解けなかった問題の復習は必ず行うようにする。

 コンテストの日程を把握するには、Competitive Programming Contests Calendar 等のサービスが役に立つ。

なぜやっているのか?

 身も蓋もない話、Webエンジニアのキャリアにおいて短期的に見れば競技プログラミングに時間を突っ込むのは損だといえる。その時間を使って新しいソフトウェアの使い方について調べたり、アプリを書いたり、またそのことについてブログ記事を書いたりするほうが有益だろう。対外的にも評価されやすい[要出典]。だが、私はWebエンジニアのキャリアに役立たずとも、競技プログラミングに一定の時間を割く価値があると思っている。以下はその理由である。

技術の根っこを追うのに役立つ

 コンピュータ技術の発展の歴史は抽象化の歴史と言われる。Webにおいてはその進化のスピードが著しい。特に下位レイヤに依存する、アプリケーション寄り、特にフロントエンド周りの技術は陳腐化しやすい。ソフトウェアの使い方だけ覚えても、学んだ部分の大半はそれが新しいものと置き換わったときに無意味になる。したがって、大事なのはそのソフトウェアの技術の根っこを追うことである。こうしたことを正しく理解するには、ソースコードを読んだり、論文に当たったりする必要が出てくる。競技プログラミングは、これらを理解するための下地になる。

 例えば React の裏側には仮想DOMの考えがあり、Reactにおける仮想DOMの実装の根幹を成しているのは 木の更新アルゴリズム である。もう一例挙げると、全文検索エンジンの Groonga は、そのテーブルの構造にパトリシアトライを選ぶことができる。パトリシアトライはコンテストでも出題されたことがある

 余談だが、量子コンピュータが実用化されることで、既存のコンピュータアーキテクチャが根本から陳腐化し、その上に乗っていた技術が全て無と化すことがあるかもしれない。現在低レイヤ技術を学んでいる身として、恐怖はもちろんある。だが、変革を目のあたりにするのが楽しみでもある。こういう気の持ちようで居られるのも、技術を深掘って学んでいるからこそだと思う。技術の興亡の歴史全てを理解するには、人生は短すぎる。どうせ学ぶなら、より根幹的な部分に手を付けたい。

問題解決について学べる

 よりメタな視点に立ってみよう。問題解決そのものの方法論について競技プログラミングを通じて学ぶことができる。ここでいう問題とは、数学や競技プログラミングに限らない。私は身近な人の課題を解決するのが好きだ。問題を解くと達成感に浸れるし、人から感謝されるし、場合によっては給料に反映されたりもする。私が勤めているベンチャー企業では、解くべき問題が溢れている。よく「問題を解くのではなく、発見できるようになれ」と言われるが、問題を見つけることと、それを解くことは別の軸だと思う。

 問題を解くには、まずそれを正しく理解する必要がある。何が問題なのか?問われていること自体は大したことではなく、別の問題が潜んでいるのかもしれない。まずは解決策を列挙してみよう。策の列挙が終わったら、それぞれについてそもそも現実的な解か、そうだとしたらどの程度時間がかかるか見積もろう。有効な解が思いつかず、筋の悪い解を延々と捏ねてドツボにはまることもある。そういうときは、問題に戻って別の視点で考えてみる。

 ここまでくると、このプロセスはいつも競プロでやってることだと気づく。そう、私たちは問題に取り組むための力を持っている。それをどう磨き、使うか。身近な人を助けるのか、それとも、より世界を良くしていくソフトウェアを書くのか。この世は競技プログラミング以外でも、解かれる問題たちが私たちを待っている。

まとめ

 この記事が、社会人で競技プログラミングをする人たちのエールになれば幸いである。私はプロのWebエンジニアとして、趣味である競技プログラミングを続けていこうと思う。