読者です 読者をやめる 読者になる 読者になる

プログラミング 美徳の不幸

Ruby, Rails, JavaScriptなどのプログラミングまとめ、解説、備忘録。

計算機科学の初等知識はプログラミング学習に必要か

私は典型的な文系エンジニアなのでただひたすら目の前のTODO、壁を乗り越えるためにググってを繰り返してきました。従って計算機科学的なものはあまり分からず、具体的にはアルゴリズム、ネットワーク、ハード的なもの、機械語などはよくわかってません。

というのは、私は基本的にはウェブエンジニアで、たまにアプリも書いたり・・・というよくいるタイプなので、典型的にはネットワークはOSI参照モデルでいうところのアプリケーション層で提供されている実装を使っているだけだし、機械語どころか中級言語(つまりC)すらろくに使いません。

人が作ったものの上で、領域を決めてある程度パターン化されたものをプログラミングする上ではそこまで原理的な知識を持たなくてもなんとかなります。

で、ここまでがわりと世間によくある「習うより慣れろ」的な意見で、私も8割は同意なのですが、ドワンゴの川上会長はこういう発想に否定的でコンピュータの原理を知らないとダメと言っています。


コードを書く経営者ドワンゴ川上会長「プログラミングこそが基礎教養」 | Biz/Zine



実際僕も今まで現実的なタスクの中で、理論的なバックボーンがあれば・・・と思うことがけっこうあります。

■ グラフ、データモデリング木構造とか

カテゴリがネストする構造で、パンくずリストを作るとします。

" グルメ・レストラン > 東京レストラン > 東京和食・寿司 > 東京寿司 > 赤坂寿司 "

みたいなやつですね。
多くのウェブサービスではデータベースにMySQLとかのリレーショナルデータベースを使うので、これを一つ一つcategoriesみたいなテーブルに入れるとします。

categoriesには名前とparent_id(INT)として親のcategoryのidを持つという実装にしたとして、じゃあ赤坂の寿司のページを表示したとき(=赤坂の寿司のカテゴリのidが与えられた時)、前述のパンくずリストを作るのには何回問い合わせが必要か、というと階層分必要になりますよね?

本来ならidのリストさえわかれば一度のSELECT文でとってこれるので、parent_idだけ持つやり方はうまいやり方ではない。

こういうことを考えると、表現したいデータによって適切な保存方法、というか抽象化方法は違ってくるなというのがわかるし、例えばネストしたデータ構造を表したいならMongoDBとかのドキュメント指向DB使えばいいというのは知識としてわかってますが、工夫してMySQLでやる方法はないかとか考えるには知識があれば便利なのかなと思います。

ちなみにこの問題の答えはこれです。
http://mikehillyer.com/articles/managing-hierarchical-data-in-mysql/


システムコール

UNIXシステムコールは勉強しようと思わない限りなかなか情報に触れる機会が(少なくともそのへんのWebエンジニアとしては)ないと思いますが、軽く抑えておくだけで相当理解が捗ります。
重要なのはプロセス/スレッドとIO、プロセス間通信、ブロック、シグナルとかじゃないでしょうか。以前

Amazon.co.jp: 詳解UNIXプログラミング: W.リチャード スティーヴンス, W.Richard Stevens, 大木 敦雄: 本

という無駄に長い本を読んだ時にPostScriptとかモデムがどうとか古い内容も含んでいたしやはり無駄に長かったので、現実的にはこちらのほうがオススメです。

Amazon.co.jp: ふつうのLinuxプログラミング Linuxの仕組みから学べるgccプログラミングの王道: 青木 峰郎: 本

ちなみに今までIOとかブロックの概念を理解する必要に迫られたのはNode.jsを理解しようとしたとき、および高負荷なシステムを捌くためにどうするか工夫した(データベース問い合わせを減らすとか)ときです。後者はまぁそこまでシステムコール云々を理解しなくても分かるレベルですが、前者のほうはシングルスレッドでイベントドリブンとかを理解する上ではけっこう必須知識です。
けっこう忘れちゃったけど・・・。


node.js とは何か (2) - I am Bad at Math

構文解析

基本的にウェブで構文解析器といえばHTMLのパーサーですが、こういうのはほとんどライブラリがあるので実際にHTMLを解析するプログラムを書く機会はあまりありません。(たいていの人が書いてるのは解析された結果をいじくるプログラムです)

ところが稀にこの類のものを自作する必要があって、例えば

"[(xxx) hoge: 'fuga', piyo: 'test']"


"{ command: 'xxx', args: { hoge: 'fuga', piyo: 'test' }"

に変換する必要があるというような場合です。
これは意外と難しくて、現実的には任意の位置に改行が入ったりスペースが入ったり、引用句は二重引用符でも良かったりと、融通の利くものを作るのはけっこう大変。

で、基本は正規表現で処理するんですが、以前早稲田の情報系の友人にこの手のものは大規模になるなら構文解析器のプログラミングパターンがあるので、それを使ったほうが簡単と言われました。

ちなみにこれは正規表現だと

/^\[(\n|\s)*?(\(.+?\)(.|\n)*?)\]$/

というパターンなのですが、自分でもよくわからなくなってくるので保守性は悪いです。