僕は僕にどういう教育を授けたか

まえがき

会社の若い子に「情報系出身でもないのに一体どうやって勉強してきたんですか?」と聞かれたのでランチを食べながら「こんな本読んだ。これもタメになった。あ、これもタメになった」とKindleを広げながらリストアップした。思い返せばたくさん本を読んだ。その中には役に立ったものもあれば時間の無駄だったものもある。すると「あ、役に立った本だけ抽出したら有益かもしれないな」と思ったのでエントリにする。

僕は文章を簡潔に分かりやすくまとめる才能が致命的にないのでこのエントリもげっそりするほど長い*1が、2017年も暮れなのでここはひとつ日本酒でもかっ喰らいながら自分の人生を振り返ってみようと思う。

無理やり要点をまとめるならば、

を身につけたらどんなに低く見積もっても僕と同程度のプログラマをつくるレシピには充分だと思う。具体的な書籍名も挙げてあるので誰かの人生に勇気を与えられたらいいな。

 

僕について

あー超言いたくないので今まで隠してたんですが僕は英文学部出身*3なんですよ。チョムスキーとか読んでました。割と自由な学科だったので英文学と英語学に飽きてからは通訳の授業を取ったりしていた。

数学は1A2Bまでしかやっていない。生物と化学はちょっとだけ覚えている。物理はまともにやった記憶すらない。コンピュータサイエンスの教育は1秒も受けていない。

ピアノと耳コピが趣味でMIDIにハマったのがきっかけでそれを発表するためのサイトを始めた。そのうち第三者の作品投稿を募るようになってPerlCGIを書き始めた。どこかで買ってきた本*4を見ながら無料公開された掲示板CGIを元にコピペと改造を繰り返してサグラダファミリアを建築していた。

3年次に大学を中退。前述のプログラミングもどきをきっかけに知り合った大学の先輩が起業したのでその会社で働き始めた。

 

インフラ

会社での僕の業務は雑用全般だったのでクビになることを恐れて誰もやり手がいなかったLinuxサーバ管理をし始めた。当然すべて物理サーバ。当時使っていたのはRedHat 9。そして出たばかりのFedora Coreに乗り換えてyumコマンドで依存ライブラリも含めて一発でインストールできることに感動したのを覚えている。ここではいくつか重要な知識を身につけた。

この業務に5年間たずさわったが、ほぼ次の本を読めば同等の知識を獲得できる。 

TCP/IPの絵本 ネットワークっておもしろい!

TCP/IPの絵本 ネットワークっておもしろい!

 

右も左もわからない人がざっとインターネットプロトコルスイートについて雰囲気を知るのに良い。

 

ネットワークはなぜつながるのか 第2版 知っておきたいTCP/IP、LAN、光ファイバの基礎知識

ネットワークはなぜつながるのか 第2版 知っておきたいTCP/IP、LAN、光ファイバの基礎知識

 

ルーティングの基礎がちゃんとわかる。

 

マスタリングTCP/IP 入門編 第5版

マスタリングTCP/IP 入門編 第5版

 

マスタリングTCP/IPを入門編でも読めればTCPダンプも怖くない。

 

CentOS7で作るネットワークサーバ構築ガイド (Network server construction gu)

CentOS7で作るネットワークサーバ構築ガイド (Network server construction gu)

 

ここだけ、この本を手放しに推奨するということじゃなくて「自分の使ってるLinuxディストリビューションApache/Nginx, Postfix, Bind, Samba等々を『全部入りで』解説されてる本」で自分にあうものを1冊探して欲しい。僕は現在はもっぱらDebianばかり使っておりRedHat系を推奨するという意図はない。

 

プログラマ転身

インフラのかたわらで会社のサーバサイド開発を手伝うようになってちょっとずつプログラマとしての経験値を貯めていった。僕のおすすめのアプローチは「何かひとつ『これさえあればとりあえず安心して何か書ける』ようになるまでひとつの言語を集中して頑張ること」だ。僕の場合はそれはJavaだった。

Java、なぜか今日では古くさくてイケてない言語の代名詞みたいに若い人に思われてそうだけど2017年現在ですら充分有力な選択肢ですぞ〜。

  • C++やRustを除くと最速の部類の実行性能を誇る
  • JVMGCのチューニングや運用実績も豊富
  • コアライブラリの代表的なデータ構造*6は種類も豊富だし実装も参考になる
  • ジェネリクス
  • 強力なスレッドサポートとconcurrentパッケージ
  • 昔でいうとAWTやSwing、いまならJavaFXとかでスタンドアロンGUIアプリケーションも書ける
  • AndroidJavaライクな言語で開発できる
  • 巷に開発者が多く、枯れた知見や強い静的型付けのおかげでチーム開発にも向いている
  • 別にやりたきゃFat Jarにして配布したりスクリプト処理だってできる

ちょっと最後は無理やりか!ほとんどのプログラミング言語は本質的にやろうと思えばなんだってできるね。

とにかく僕の場合はJavaだったわけだ。ジェネリックプログラミングやマルチスレッド処理、GUI開発の知見なんかは僕の現時点での最大の武器であるAndroid開発にも非常に役立った。 

いまからJavaを身につけるのは何がいいんだろうな…とりあえず

 Javaメモ目次(Hishidama's Java Memo)

の2つには大変お世話になった。Javaは「とりあえず使い始める」という点でちょっと分量が多いように感じられて*7初学者はウッ…となるかもしれないので何でも良いので本屋さんで簡単なのを買ってみるというのも手です。

 

改訂2版 パーフェクトJava

改訂2版 パーフェクトJava

 

これを手放しに推奨というわけではないけど何も知らない人は一旦ざっと俯瞰できる本を何か買ってください。始めた頃の僕みたいな実力だったらもっと入門的なものでも良いかもしれない。

 

EFFECTIVE JAVA 第2版 (The Java Series)

EFFECTIVE JAVA 第2版 (The Java Series)

 

これはJava書きのバイブル。Java 8, 9時代の内容を反映した3rd Editionも原著(英語)はすでに予約を開始してる。

 

新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES)

新装版 リファクタリング―既存のコードを安全に改善する― (OBJECT TECHNOLOGY SERIES)

 

僕はリファクタリングをチーム開発、使いやすいAPI設計、テストを書きやすい構造等々のすべての高品質なプログラミングの基礎だと考えており、この本は一歩前に進むために必読であった。Javaが題材なので手に取りやすい。

 

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

リーダブルコード ―より良いコードを書くためのシンプルで実践的なテクニック (Theory in practice)

 

言語に依らずシンプルで分かりやすいコードを書くためのテクニックが簡潔にまとまっている。新入社員には必ず薦めている。

 

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―

Java並行処理プログラミング ―その「基盤」と「最新API」を究める―

 

これ絶版なのが惜しくて惜しくてしょうがない。Javaが持つ強力なマルチスレッドプログラミングをjava.util.concurrentパッケージを使って安全に使うためのテクニックがすべて詰まっている。また「スレッドセーフとは何なのか」という観点から、単純にロックを安全に取る方法のみならずトラバースを安全に行うことに特化したアプローチなども学ぶことができる。

 

無職、そして東京へ

さて5年経って会社もIPOを目指すスタートアップからただの中小企業と化してしまったし僕も自分の人生に行き詰まりを感じて最初のスタートアップを退職した。*8

僕はちょっとだけ無職をしつつ自分が次になにをすべきか考えていたが、ふと「そういや大学3年まで取った単位もったいねえな。どっかに入り直すとして1回生からやり直すカネはないし引き継げたりせんかな」と思って中退した大学の教務課に行ったところ「確かに中退してるけど、キミ、5年以内なら無試験で復学できるね。ああ、来月末で5年だね。」と言われ、そのあまりのタイミングの良さに運命を感じて大学に戻ることにした。この時は手に職があったので知人経由で割のいいプログラミングのバイトを貰って働きつつ1年で卒業した。*9 

この間に後に嫁さんになる女性とコミケで出会った。向こうは同人誌を作る側、こちらは同人誌を買う側である*10。奇しくも冬コミ初日の今日これを書いているのは感慨深いな。大学卒業後よめさんを追いかけて東京で職を探した。

 

ネイティブアプリ開発

ウェブの会社に拾ってもらってここで技術者としての基礎を全て叩き直された。京都時代にちょっと触ってたAndroid開発を本格的にやるようになった。ネイティブアプリ開発にはいくつかコツがあることを知った。

スレッド間通信

ネイティブアプリ開発のコツというとライフサイクルコールバックとか非同期処理とか貧弱なネットワークやハードウェアリソースなんかが挙げられると思うけど、最も大切かつ既存のほとんどすべてのGUIフレームワークに共通する仕組みがある。それがイベントループとメッセージパッシング機構でありこれらは取りも直さずスレッド間のメッセージのやり取りために存在している。

イベントループ

あるスレッドに関連付けられイベントやメッセージを待ち受けてる人。AndroidではLooperがこれに相当する。MessageQueueというその名の通り届いたメッセージをキューに積んで処理したりする。

メッセージ

スレッド間でやり取りされるメッセージ。AndroidではMessageというそのままの名前。

ハンドラ

イベントループにメッセージを届けたり処理を記述するための仕組み。AndroidではHandlerというこれまたそのままの名前のクラスがある。

 

なんでこれらの知識が必要かというと、こういった仕組みはGUIフレームワークに普遍的な考え方であり何かトラブルが起こった時の調査の取っ掛かりになるばかりか、まったく新しいGUI開発に従事した際にも充分に応用が効くようになるからだ。ここに挙げたものはiOSにもまったく同じものがあるしJava Swingにもあったし未来に生まれる次世代のスマホOSでも同じものが提供されるであろうことが想像に難くない。

ここまで分かるようになってくると、UIスレッドというのがそういう名前が付いただけのシングルスレッドであることも分かるし、反対にメッセージループの機構が単に別スレッドからUI部品を更新するためだけのものではなく任意のスレッド間の柔軟なメッセージングに使えることが分かる。

ちょっと脱線したけどAndroid開発の参考書籍をいくつか。

いきなり書籍じゃないけど「Androidの入門書なにがいいか?」って一番困る質問なんだよね…すでに僕はAndroid入門者じゃないので当時の気持ちが思い出せない…

ただこのトレーニングコースは無料で簡潔かつ本質的であり、今なお色褪せぬAndroid開発の極意をごく短期間で身につけることができる。

どうしてもIDEのインストールから手取り足取りやりたいひとはAmazonで適当に検索して評判の良さそうなものをなんでも1冊手にとって見ればいいと思います。

 

黒帯エンジニアが教えるプロの技術 Android開発の教科書(ヤフー黒帯シリーズ)

黒帯エンジニアが教えるプロの技術 Android開発の教科書(ヤフー黒帯シリーズ)

 

ヤフー黒帯本。Androidに限らずiOSもそうだと思うが公式の方法と現場で使われているデファクトスタンダードの乖離が初学者の挫折ポイントだったりすると思うので、最近の知見をサッと1冊で詰め込めるのはおいしい。

 

Androidを支える技術〈I〉──60fpsを達成するモダンなGUIシステム (WEB+DB PRESS plus)

Androidを支える技術〈I〉──60fpsを達成するモダンなGUIシステム (WEB+DB PRESS plus)

 

Androidの内部に切り込んだ世界でもこれ以上の書籍はないと思われる名著。I巻はGUIにフォーカスを置いている。前述のHandlerのような話題もはるかに深く掘り下げられている。

 

Androidを支える技術〈II〉──真のマルチタスクに挑んだモバイルOSの心臓部 (WEB+DB PRESS plus)
 

II巻はActivity(iOSのViewControllerに相当)に関する内容。普段何気なく利用しているActivityが誰によってどのように生成/破棄されているのかと言ったライフサイクルの心臓部の解説がある。

 

Androidを支える技術の別冊「詳説 Binder」。すいませんこれ怒られるかもしれないけどまだ読んでなくて正月休みに読む予定なんだけど、AndroidにはBinderというプロセス間通信の仕組みがあって普通にIDEの参照ジャンプで辿っていくだけだとこのBinderの層でプッツリと途絶えてその先を見つけられないのだ。

ここを読むにはAndroidのなかみ InsideAndroidという書籍*11の解説とかを見ると助けになるんだけど、著者の有野さんも

と仰っているしdex.fmでご本人が熱弁しておられた様子をお聞きしても名著であることを確信したのでここで紹介した。

 

アルゴリズムとデータ構造

たぶんここまで来るだけでモバイルアプリ開発者としてなんとなく食っていくには充分だと思うんだけど外資に転職したくて勉強したアルゴリズムとデータ構造について理解を深めるにつれ「これは順番が逆だった!これを知ってからプログラミングをやるべきだった」という思いに強く駆られたので紹介しないといけない。

 

アルゴリズム

アルゴリズムはある問題を解くためのアプローチだ。数列を昇順に並べ替えるアルゴリズム木構造から目的のデータを素早く探すためのアルゴリズム等がある。

 

データ構造

アルゴリズムを実装する際に効率的に処理するためにデータの集まりを都合の良い状態に整えたもの。整列済みの配列は立派なデータ構造だし、平衡二分木もB+木も赤黒木もデータ構造である。

 

で、普段こんなの使わんでしょ?と思いきや全然そんなことなくて、自分で実装することはほとんどないかも知れないけど普段のプラグラミングやサービス開発でよく使うものでこれらアルゴリズムとデータ構造の恩恵を受けていないものは存在しないほど身近で重要なものだったりする。

普段使ってるRDBMSファイルシステムはB+木のお陰で挿入も削除も検索も高速だし、全文検索エンジンはトライ木の一種のサフィックス木で実装されてるかもしれない。

身近なプログラミングでダントツに重要なデータ構造としてHashMap(Dictionary)があると思うけど、普段これがどうやって実装されてるか*12考えたことがあるだろうか?

このあと紹介する参考書籍とかを読めば分かるけど、HashMapはキーのハッシュ値をモジュロ演算して固定長配列*13に割り当てて、ハッシュ値の衝突は連結リストの後ろにつなげていくだけで実現されている。それぞれは非常にシンプルなデータ構造とシンプルなアルゴリズムを工夫してこのようなベンリなデータ構造を作ってるわけである*14

またAndroidにはキーが任意の型Tではなくint固定の代わりにメモリ効率が良いとされているSparseArrayというデータ構造があるが、これは内部では2分探索木が使われている。つまりエントリが爆発的に増えればおそらく挿入時にはSparseArrayの方が有利だし検索時にはHashMapの方が有利であることを示唆している*15

こういう知識はいざ自分で新しい何かを生み出せばならないときに強力な持ち駒として力を発揮するはずだ。

 

この本は何個か読んだ中でも比較的とっつきやすかった。使い慣れたJavaだし。

 

なっとく!アルゴリズム

なっとく!アルゴリズム

 

この本はアルゴリズム本の中で特別読みやすかった。図もたっぷりで軽妙な語り口。それでいて動的計画法のナップザック問題あたりまでもカバーする骨太さ。言語はPythonだが読めないということはまずないだろう。

 

アルゴリズムクイックリファレンス 第2版

アルゴリズムクイックリファレンス 第2版

 

僕が読んだ中で最も広範かつ深くアルゴリズムについて学べる本。いきなり「アルゴリズムの数学」と題して計算量とは、最良・最悪・平均性能とは何なのかみっちりと解説してくれる。その後他のアルゴリズム本にもあるような整列、探索、グラフに始まりAI、ネットワークフローの深きまでがっつり入っていく。これをマスターすれば怖いものなし。僕はマスターしていない!

 

AtCoder代表のchokudaiさんによるTopCoderSRMに挑むための訓練本。やや難易度が高いけど実際のプログラミングコンテストに挑むための力をつけることができる。外資企業の面接で間違いなく力を発揮する。

 

UNIX/Linux

個人のPCレベルだとWindowsがまだ世界で90%ものシェア*16を持っててまさに圧倒的という言う他ないんだけど、ことサーバ環境においては7割近くがUNIX系OS*17という調査もあるようで元インフラ出身の僕の肌感覚とも近い。それにiOSDarwinというUNIXだしAndroidLinuxをベースにしていることを考えるとUNIX/Linux力は非常に重要だと思う。

ここでUNIX/Linux力といった場合単純にコマンドを扱えるよりもうちょっと踏み込んだ点を指していて、具体的には次のようなことだ。

  • 入出力
  • ファイル(inodeとか)
  • プロセスのフォークやシグナル
  • pthreadと同期
  • プロセス間通信(名前付きパイプとかUNIXドメインソケットとか)

で、これらは普通にコマンドを利用してるぐらいでは中々身につけるのは難しくて、やっぱりglibc越しにシステムコールを呼ぶようなプログラムを書かないといけない。

かつて一回だけ本番環境のMySQLが原因不明のタイミング*18でネイティブクラッシュを繰り返して生きた心地がしなかったんだけどstraceコマンドでシステムコールトレースをつぶさに追ったところRDSのホスト名が長すぎて名前解決キャッシュのテーブルの最大バイト長を超えて書き込もうとしてセグメンテーション違反を起こしていたのを突き止めたことがある*19

 

詳解UNIXプログラミング 第3版

詳解UNIXプログラミング 第3版

 

上に挙げたようなことをすべて身につけることができる本。900ページぐらいあってめっちゃムズイけどCを書いてコンパイルしてっていうのは実は生まれて初めてだったので楽しかった。全部やるのは無理だった。

 

詳解UNIXプログラミングのLinux版かつテーマをグッとしぼった感じの本。初学者はこちらの方がずっとオススメ。grep等のよくあるコマンドを自分で実装してみることができる。

 

教養

直接なにか利益を受けるつもりで学んだものではないんだけど回り回って血となり肉となった知識がいくつかあって、その中のひとつが関数型プログラミングだ。

特にHaskellモナドを学んで将来確定する計算結果をパイプライン処理するというような考え方はAndroid開発時にRxJavaを見た時にすんなり理解できる助けになってくれたりして大いに役立った。また昔は特に苦手だった再帰も、スタックフレームを消費する末尾呼び出しとアキュムレータを用いた最適化可能な末尾再帰を使い分けることができるようになったりと得るものが多かった。再帰的な考え方は再帰的なデータ構造やアルゴリズムを考える時に脳の体操になるので非常に役立つ。

 

すごいHaskellたのしく学ぼう!

すごいHaskellたのしく学ぼう!

 

たぶんHaskellの入門書で圧倒的に一番分かりやすい。Haskellの機能をシュールな絵とともにのらりくらりと解説してくれるんだけど、Functor, Apprecative, Monoidとステップを踏んで最終的にMonadを作るところまで学ぶことができる。

 

ScalaをBetter JavaというよりはかなりHaskellっぽく使うための様々なアプローチが紹介されている。随所に練習問題があって難しいが素晴らしい本。

 

Land of Lisp

Land of Lisp

 

スポンジボブのようなシュールな絵でLispの歴史の解説に始まり最終的にCommon Lispを使ってちょっとしたゲームまで作ってしまう面白い本。S式という連結リストと関数だけというかなり割り切った言語設計とカッコだらけの見た目でかなりぎょっとするが、再帰を使って連結リストに関数適用していくという関数型プログラミングの醍醐味のようなものを学ぶことができる。

 

フロントエンド開発

むしろ僕が教えていただきたい…僕のフロントエンドの知識はjQueryprototype.jsで停まっている化石状態だ。

ただ来春の僕のミッションに素早いプロトタイピングが加わるのでReact Nativeでクライアントサイドを、Cloud Functionsでバックエンドを書いていこうかなと思っているので双方に共通する技術スタックとしてTypeScriptを速習予定だ。

 

TypeScript実践マスター

TypeScript実践マスター

 

とりあえずこれはパラパラ読んでみたが初学者には良さそうだった。

 

数学

数学の出来なさがかなり僕のコンプレックスになっており自分なりに少しずつ努力している。僕はビッグオー記法のO(logN)の意味が最初わからなくて指数対数からやり直したレベルだ…こちらは完全に教養として本当に少しずつ進めているので進展があったら共有したい。

このエントリで拝見した高専の数学は良さそうである。

 

やっていき

いや〜長すぎてもう誰も読んでないと思うので最後にちょっと好きなことを書きます。

自分がこれだけ路傍の石ころみたいな状態からプログラマになってこうしてなんとか食ってこれたのは、やっぱり諦めなかったからだと思う。僕は常にいまの自分が許せなかった。いまの自分の不甲斐なさが悔しかったのだ。これは裏を返せば自分の可能性を信じているわけだ。まだやれるはず、まだ道は続いているはずだと信じている。

ちゃんと教育を受けた人が大学で4年、修士で2年、博士で3年だとしてざっと10年。僕はこのような専門教育は受けていないがかれこれ12年自分で自分にコンピュータサイエンスを教え続けてきた。努力を積み重ねれば彼らに追いつくのも不可能とは限らないのだ。毎日は1㍉1㍉の積み重ねだが12年経って振り返った時に「気付かないうちに随分登ったなあ」と小高い丘から目を細めながら過去の自分を見下ろせればそれで良い。

22歳からでも、いや30歳からでも遅すぎるということはないのだ。自分が今日より若い日は今後一生ないのだと思うと何歳からはじめても今日が最善の日だ。やっていこう!

 

情熱プログラマー ソフトウェア開発者の幸せな生き方

情熱プログラマー ソフトウェア開発者の幸せな生き方

 

技術書以外はめったに読まないんだけどとても好きな本。オフショアでの衝撃的な経験や生きるためにコードを書くということ、採用に対する考え方、エンジニアとしての幸せなど示唆に富んだ本。

 

最後に

2017年は本当にお世話になりました。来年はちょっと今まで目を背けつづけてきた機械学習にチャレンジせねばと思っています。どうか良いお年を。

*1:マジで長くて1万字を超えちゃって笑ってしまった

*2:身も蓋もないけどコレはホント。しかし運は待つのではなく無理やりつかみ取りに行くのです。

*3:だから英語に苦手意識がないんですね〜。けどこの時の英語力はハナクソみたいなもんだったのでその後のトレーニングの方が大事。

*4:これはもはや記憶にない。何でも良かったのだ。

*5:29ビットマスクのグローバルIPをやりくりしていた

*6:List, Set, Hash, Dequeなんでもいいんだけど、Arrayを元にしたものやLinkedな実装など用途に応じて自在に使い分けできる。僕はアルゴリズムとデータ構造を学んでからJavaのコアライブラリの凄さを見直した。

*7:リテラルも弱いし配列やコレクションもRubyPythonとかより使いにくくてとっつきづらいよね…

*8:僕を引っ張ってくれた恩人の先輩もそれからほどなく共同創業者に株式を売り払って東京に出ていった

*9:思えばこのとき2年かかってもいいから理学部情報学科にでも編入試験を受ければよかったな〜。でも学士を取れてよかった。

*10:「ここここのあとののの飲みにいきませんか」みたいなことを言った。通報も逮捕もされなくてよかった。

*11:こっちは読んだ!

*12:もっというとどうやってO(1)の検索を実現しているか

*13:ホントは然るべきタイミングでリサイズしないといけない。卜部先生のブログに詳しい。

*14:これを理解するとどうしてMapが挿入順序を持たないか簡単に分かるだろう

*15:ただし一般的なアプリで現実的なデータ量では2分探索木でもO(1)に近い性能が出ると思われる。参考サイト

*16:https://news.mynavi.jp/article/20170904-a057/

*17:https://w3techs.com/technologies/overview/operating_system/all

*18:後にレプリケーションのタイミングと判明

*19:これは --skip-name-resolve オプションを付けていればそもそも起きなかったミスではあるが…