seri::diary

日常

やりたいことを最初にやる,あるいは効率の良いプログラミングの勉強法について

去年は数ⅡB辺りを勉強したので今年は線形代数を勉強している。サラスの方法や余因子展開を使って行列式を求めたり、行列をあれこれ変形してrankを求めて一次方程式の解が求まるかどうかを日々検討しているのである。

しかし、勉強を始めたもともとの動機は、別の本を読んでたら出てきた「固有値」とか「固有ベクトル」という言葉の意味ってなんだっけ?という疑問であった。だから線形代数の本を買ってきて固有ベクトルの章だけ読めばよい。最初はそう思っていた。ところが、固有ベクトルの章だけ読んでもそれ以前の前提知識(特に行列式の意味や正則な行列の性質)がなければ理解できない内容だった。なので諦めて最初から参考書籍を読み問題集を解いているのである。

ちなみに読んでる本はこれ。とても分かりやすい。

プログラミングのための線形代数

プログラミングのための線形代数

問題集はこれ。学部生向けの模様。

新版 演習線形代数 ((新版演習数学ライブラリ))

新版 演習線形代数 ((新版演習数学ライブラリ))

線形代数のように順番に勉強しないといけないということは結構ある。多分資格の勉強とかも大体そうだろうと思う。しかし、新しいITスキルを習得しようとする時はどうだろうか?なぜこんなことを突然言い出したのかと言えば、今日図書館で線形代数の勉強をしていた時にふと思いついたからである。

かつての自分がやっていた「間違ったプログラミングの勉強法」

例えば、新しい言語を勉強する時に初心者用の入門書を買ってきて、頭から最後まで全部読んでからコードを書き始めるだろうか。実際、自分は一度だけやったことがある。webサービスを作りたくて,phpの入門書を買ってきて最初のページから写経し始めたのである。

ただ今振り返れば、phpを覚えてから7年ぐらい経っても未だに一度も使ったことがない関数やクラスのsampleコードを必死に写経していたのはかなり無駄だったなと感じる。もちろん、「こういうのがあるのか」というのを知っておくことは重要である。問題なのは、肝心のウェブサービスを作る上では不必要な知識だったということである。

実際に自分がphpwebサービスを作るために自分はどうしたか?入門書の最後の方に「応用課題」として掲載されていた掲示板だのSNSだののサンプルコードをコピペしまくって改造したのである。そうしなければwebサービスは作れなかった。その章に行き着くまでに多くのコードを書いたが、それだけでは足りなかったのである。echo "Hello, php!"; から始まり mysql_connect('localhost', 'root', 'pAssw0rd') or die('データベース接続エラー');みたいなことをやるscriptをいくら書いてもwebサービスを作ることはできなかったのである。

何が足りなかったのか?

いや、足りなかったというよりそもそも努力の仕方が間違っていた。webサービスを作りたければ、まずコピペでもなんでもいいから完成させてみることが重要だった。そうすれば自ずと何が必要か分かってくる。実際、自分のプログラミングのスキルや技術の知見は掲示板っぽい何かの実装を通じて大きく広がった。最終的にはさくらのVPSを借りてCentOSの使い方も調べてドメインまで取って、今見たらどうしようもなく意味の分からないみたいな掲示板もどきサービスを公開するところまで行った訳だが、プログラミングは覚えたので次はLinuxについてじっくり勉強してから。。などとやっていたらおそらく一生公開できなかったと思う。

それがなぜ公開にこぎつけられたかと言えば、まずやってみて、足りないと感じるものだけを補うように途中から方向転換したからだと思っている。それが結局は効率が良かった。勉強と言えばまず基礎をガッチリ固めて次に応用問題を。。という、高校までのスタイルにどっぷり浸かっていた自分は、当初プログラミングに対しても同じスタンスで挑んだが、プログラミングは学問ではない。道具なのだ。金槌を使えるようになるためにまず金槌の歴史の勉強から始める必要があるだろうか?全くないとは言い切れないが、大抵の人は金槌をまず握ってみるだろう。何なら叩いても良さそうなものを叩いてみるはずである。

プログラミングも多分同じだと思う。まず今必要なことをその言語でやってみる。次にそれで分かった足りないことを知るために書籍に立ち返って必要な部分を集中的に勉強する。結局、これが効率がよい勉強の仕方ではないかと自分では思っている。

自分がEffective Javaを読んだのはjavaを書くようになって1年近く経った後、Effective Rubyを読んだのもrubyを書くようになって2年以上経った後だったが、逆に初心者の頃だったら、何に役に立つのか分からずに多くの学びは得られなかったと思う。

新しいアプローチによる学習例

今でも新しいことを勉強するときはこのアプローチでやっていることが多い。
今年に入ってからはデータ分析の業務でpythonを結構書くようになったが(去年もNNの実装で使ったが)、何も考えずにまず brew install pyenv して pyenv install anaconda3 してjupyter notebookをinstallしてpandasでBigQueryのデータをいじり始めた。ハマりまくったが結局やりたいことはできた。*1
たまたま別件で調べ物をしていて見つけた某大学のシステムプログラミングの講義資料が面白くなってしまい全部写経して、まだ作ったことがなかったwebサーバーを書いた。Cを集中的に書いていた時はCがどういう風にメモリを管理するかロクに知らなかったので構造体を使ったコードを書いたら至る所でSEGVの嵐で泣きたくなったが、お陰様で低レイヤーの技術とアセンブラに興味が沸いて今では社内輪読会でパタヘネを読んでいる。

このアプローチの応用で、自分がまだやれたことがないと思うのが「自分が一番難しいと思うこと」からやってみる、というものである。これまでは「多分実現可能っぽくて(周りがやってたりするので)一番やりたいこと」から手を付ける、という感じではあったのだが、それだとどうしても自分のスキル面での成長が止まってしまうと危惧しており、逆に「実現可能か全然分からないけど自分の中で一番難しいと思うこと」から手を付けてみたいと考えるようになった。

実際には時間的な制約でできなかったり、あまりに壮大過ぎて結構本気でどこから手をつけていいか分からないというものだったりするのだが*2、少しずつ課題を切り崩して、何とかとっかかりを見つけていきたいものである。

併せて読みたい(というかこれ読めば上記の文は読まなくてよい)

luccafort.hatenablog.com

*1:のちにpyenvとanacondaは自分には不要とわかり使わなくなった。とりあえずpython機械学習したーいという人には最初からpyton3をbrewで入れる方法を勧めている

*2:具体例を挙げると「HDFSより使いやすいインターフェースを備えた分散ファイルシステム」「でかすぎるjobは勝手にクラスタ内のnodeにバラまいて分散処理してくれるworker」「一度に大量のtopicを並列readできるQueue Store」「ぼくがかんがえた最強のBaaS」「Cコンパイラ」「sparkのRDDよりさらに抽象化された分散プログラミングモデル」