こんにちは、@IT編集部の西村賢です。IT系のオンラインメディアで編集・記者をしております。タイトルに「ど素人」と書くと、ちょっと嘘になるので「素人」と書きましたが、素人がWebアプリを作ってみた体験談と感想を書いてみたいと思います。「オレもプログラミングを勉強して何か作ってみたい!」と考えている人や、「自分でサーバを借りて何かやってみようと思っていたんだよね」という人の参考になれば幸いです。
去年の夏、Webアプリケーション開発フレームワークのRuby on Railsのことを調べていて「面白そうだな」と思い、ドキュメントに従ってサンプルアプリをいくつか作ってみました。作ったり壊したりしている間に、こう思いました。
「あれ? これなら自分が欲しかったサービスが作れちゃうんじゃないの?」
で、「Worklista」(ワークリスタ)という名前のWebサービスを作りました。3カ月ほど前から親しい友人や同業者の何人かに試用してもらっていて、2カ月ほど前に、ひっそりオープンしました。ソースコードは、GitHubのレポジトリに置いてあります。

開発環境もサーバも手軽に入手できる恵まれた時代
自分で作ったロゴがひどかったので、サイトロゴはパキスタンのデザイナーに発注して30ドルで作ってもらいました(クラウドソーシングのoDesk.comというサイトがスゴく便利です!)。それと、@ITの連載のネタとしてプロのRails開発者にリファクタリングを通してMVCの基本とは何かというのを実例で教えていただきました。その2点以外はゼロから1人で作りました。
月並みな言い方ですが、とても良い勉強になりました。
Railsの勉強を始めて約4カ月。週に4、5時間をかけて3週間ほどで基本機能は実装できました。その後もウジウジとデザインを変えたり、少しずつ機能を足したりで半年以上が経過しています。途中、すっかり存在すら忘れて放置していた期間もあります。
ドメインを取って、さくらインターネットのVPS(512MBの月額980円のもの)に、Ubuntu、Nginx × 2、Thin × 2、MySQL、Ruby on Railsという構成でデプロイして動かしています。Rails3+Ruby 1.9.2で、Git+Capistranoの楽ちんデプロイです。
私はプログラマではありませんし、Webアプリと呼べるほどのものを作ったのも今回が初めてです。さらに、「プログラマ35歳引退説」に従えば、すでに引退済みという三重苦みたいなところからのスタートでした。でも、考えようによっては、実に恵まれています。
オープンソースの良質な開発ツールやフレームワーク、そして解説書籍、解説ブログ、QAサイト(コミュニティ)、サンプル実装(あるいは本番実装すら)など情報が溢れかえる時代に生きています。勉強会やコミュニティも活発。そして月額1000円とか2000円で自由に使えるサーバだって手に入ります。自分で使ってみてよく分かりましたが、オープンソースの教育効果は絶大です。人が書いたソースコードや開発ツール自体の中身が見えることほど、勉強になることはありません。英語まで含めると、ソースコード例も含めてRails関連情報はネット上に溢れかえっています。例えばいま、RSSリーダー機能を実装しようかと考えています(フィードのほうじゃなくて、サブスクライブする側です)。そのために、Livedoor Readerの英語版のオープンソース版、Fastladderのソースコードを眺めたりしています。複数ユーザーがいるプラットフォームでRSS受信をどうモデル化するかって自明じゃないと思うんですが、自分が普段お世話になっているアプリが参考にできるなんてすごい時代です(日本語版のLivedoor Readerはコードベースが違うという話ですが)。
Worklistaというサービスで何ができるのか、そして何がしたいのかということと、Ruby on Railsで開発してみて分かったことを書いてみたいと思います。個人的な小さなプロジェクトですが、やってみないと分からないことってあるんだなと実感しました。
「これまでの仕事リスト」のCMSがほしかった
Worklistaは自分のために作ったようなサービスです。記事やブログという仕事のアウトプットを一覧でリスト表示することができます。以下の画面の通りです。

記事を書くと、その後の読者の反応が気になるわけですが、Worklistaに登録しておけば、はてブやTwitter上の反応を1カ所からたどれます。これは自分としては気に入って使っています。「あ、意外にブックマーク数が伸びてるな」とか「Twitterで良くクリックされてるな。どれどれ反応は……」といった具合です。
フリーライターの人だと、よく自分のサイトに「これまでに執筆した記事一覧」というのを載せていますよね。これまでに自分がどういう取材をしてきたか(あるいは取材を受けたか)、どういう媒体に寄稿やコメントをしたことがあるのか、あるいは、どこでどういう講演をしたか示すことで、仕事の依頼につなげようというセルフマーケティングの一種です。自分用のメモという側面もあるかもしれません。
こういう業績リストは、手書きのHTMLだと更新が滞りがちです。たとえブログエンジンを使ってエントリ化しているとしても、結構更新が面倒なものです。だから、そうした業績リストが楽に維持・管理できれば便利かもしれないと思ったのでした。
自分を売り込む際にも「こちらのURLで、これまでの仕事がご覧いただけます」とメールで送れます。タグを使えば「Ruby関連では、こういう記事を書いています」ともURLで示せます。こういう感じの記事を書いています、という履歴書的な意味合いで最大10個のアイテムを1つのタブにまとめることもできます。

例えば、過去に私がRuby関連で書いた記事は「ruby」タグをクリックして一覧できます
社名や媒体名ではなく個々の「人」に光を!
Worklistaでは、記事のURLを入れるとHTMLを取ってきて、タイトルや公開された日付を自動的に入れてくれます。対応するURLがある「仕事」であれば、「記事」でなくても構いません。Amazonの自著へのリンクでも良いですし、講演スライドや動画も一緒にリストアップしておけると思います。Amazon、SlideShare、YouTubeなどは書影やサムネイルを引っ張ってくる機能を付けるべきかな、などと考えています。

アイテムの追加画面
もし、Worklistaが広く利用されれば、これから誰かに仕事を依頼しようという側の人(プロデューサーや編集者、広報担当者、PR関連の人など)が、実際にその人の仕事のアウトプットを一覧できるサイトになるのではないかと思います。記者という仕事をしていると、「どういうジャンルを取材されているのですか?」という質問を、広報部やPR代理店の人に良く聞かれます。その答えがURL一発で分かるというわけです。もしかしたら、「うちの製品・サービスについて記事を書いている人を探したい」というニーズもあるかもしれません。
個展を開くような“写真家”ではなく、コンスタントに質の高い写真を撮る商業カメラマンっていますよね。あるいはイラストレータ、Webデザイナーにも、そうした人がいくらでもいます。世間一般の誰もが名前を知っているわけではないけれども、良い仕事をしているプロというのはいます。組織に属しているかどうかは別として、そういうプロの1人1人に光を当てたい、というのがWorklistaを作った私の動機です。
今のところ、コンテンツの多くは雑誌やWebサイトなどの媒体に強く紐付いています。それはそれでパッケージ商品としては良いのですが、それを生んだチームの個々のメンバーや個々の人間を軸としたコンテンツのまとめ方があってもいいのじゃないかと思うんですね。
日本の媒体に載る記事って署名がないことが多いですよね。あったとしてもクリッカブルじゃないことがほとんどです。クリッカブルで記事一覧が出るとしても、それは、その媒体上の記事一覧であって、その人の仕事一覧ではありません。
時代が変わりつつある予感があります。誰もが言ってることですが、コンテンツの信頼度や質を判断する指標として、これまでは放送局や出版社といった企業名、そして番組名、雑誌名が重要なシグナルの役割を果たしてきました。今後は、それに加えて「誰のコンテンツか」がシグナルになるように思います。
例えば、私は日経新聞のIT関連記事をことさら読もうとは思いませんが、井上理さんの署名があるものは全部読みたいなと思います。もし井上記者にWorklistaを使ってもらえれば、そこに「井上記者のRSS」ができます。ですので、井上様、これをご覧のようでしたら、是非サービスを使ってみてくださいませ!
もう1人、例を挙げると、元CNET記者の鳴海淳義さんがいます。以下を見てみてください。見覚えのある記事もあるでしょうし、彼が非常に優秀な記者だったことが分かります。

と、Worklistaにはそれなりに思い入れがあったりするのですが、それは置いておき、「初めてのRails開発」の体験談を書いてみます。
分かったこと1:Railsは想像以上に分かりやすかった
Railsによる開発の流れ自体は、想像以上に分かりやすくてシンプルでした。ドキュメント通りに動かしたり、知っていることをやっている限りは非常にストレートです。動かすだけなら、難しいところはありませんでした。ただし、Ruby on Railsに触れるより前に、3年ほど細々とRubyやC(時々ClojureやHaskell)の勉強を続けていましたから、いきなりRailsに取り組んで作り始めたわけではありません。
最初に『Head First Rails ―頭とからだで覚えるRailsの基本』という本を眺めて概念的なところが分かった後は、オンラインの解説や人のソースコードなどを読み漁りつつ、実践あるのみという感じです。初期化コードをboot.rbに書いて「それは……、斬新ですね……」と、Rails開発者に絶句されたりしつつ(ふつう、boot.rbはRailsフレームワークの初期化のコードが入っているので、ユーザーがいじるものではありません)、だんだんと全体像の理解が進んでいくという感じでした。
Webアプリなので当然かもしれませんが、Railsで機能を追加していく作業は、HTMLやCSSを書く延長上にあるという感じすらあるなと思いました。ノートに手書きした「なんちゃってUML」を元に、モデルを追加し、マイグレーションを書いてアクションを定義し、ルーティングを設定する。画面で確認してHTMLを調整する。「あ、このへんにこういう機能がほしいな」と思ったら、まずHTMLを書き換えてボタンを作ってしまい、対応するアクションを作る。ボタン名が違うなーと思ったら、またHTMLをいじる。何だかWebページ制作のようです。あ、テストはモデル以外は全然書いていません……。
モデルが全部で4つしかないシンプルなアプリだからということもあるかと思いますが、むしろ時間がかかるのはCSSやHTMLです。CSSを使ってナビゲーションバーをどうやって作るのが正しいのかとか、CSSの擬似クラスの挙動ってどうだっけと調べたりします。ロゴ画像へのリンクをCSSで指定するときにマイナスの値でオフセットを設定しているサイトがあるのはなぜだろうか……? というように、HTMLやCSSで悩んだりゴニョゴニョしている時間が長かったように思います(後にjQueryを使うようになってからは、CSSの悩みの半分は吹っ飛びましたけど)。そして、Web開発者が共通に嘆く「IE! なぜお前だけこうなる!」という気持ちが良く理解できるようになりました。
分かったこと2:Webアプリは想像以上に複雑だった
私はIT系の記者・ライターとして、Webアプリやサービスのレビュー記事を書くことがあります。表層的とはいえ、技術トレンドもそれなりに追いかけています。ですから、Webアプリがどう振る舞うべきかということについては、それなりに分かっているつもりです。外から観察できるWebアプリについては結構知っているつもりでいたわけです。
これはWebアプリに限らないと思いますが、外から見ているのと、中身を作るのとでは大違いです。実際にやってみて分かったのは、Webアプリというものが非常に複雑な構築物だということです。複雑というか、膨大な量の技術の上に成り立っています。その1つ1つについて、それなりに調べながら作っていると、個々のトピックは難しくはなくても、「知らなければならないこと」の量が多くて途方に暮れそうです。
非常に長いですが、以下に引用の形であれこれ書いておきます。長いですので雰囲気だけ感じ取って読み飛ばして下さい。
例えば、インジェクション、XSSやCSRFといったセキュリティ対策。Rails3では、デフォルトでテンプレートに埋め込む文字列はエスケープされますが、だからといってインジェクションのことを分かっていなくても良いということではありませんよね。CSRFについても、Railsはトークンを自動で生成してくれたりしますが、なぜそれが必要で、どう使うべきなのかということも、理解するには30分ぐらいはかかります。逆に、Railsなどのフレームワークなしに、素のPHPやPerlでCSRF対策をやるなどということを考えれば、わずか30分で先人のベストプラクティスを生かせるのは物凄いショートカットだなと思いました。いわゆる高速道路っぽいです。
アプリケーションサーバを設定するにしても、ThinなのかMongrelなのかPassengerなのか、どれを使うべきか、調べだすとキリがありません。格安VPSではメモリが貴重なので、私はThinを選びましたが、ThinをNginxの背後に複数並べるとき、そのコネクションにUnixソケットを使うべきか、TCPソケットを使うべきか、そのメリット・デメリットとは何か? というようなことで、また30分ほど調べたりします。
認証プラグインのDeviseがBasic認証と相性が悪いと思って調べてみたら、Nginxのリバースプロキシ設定で明示的にBasic認証のパスワードがアプリケーションサーバに渡らないようにしないとダメだった、などというハマりポイントもありました。そういうことで、すぐに30分ぐらい経過します。
認証プラグインのDeviseの暗号方式や、ハッシュやソルトの保存方式についても、あれこれ調べていると時間がかかります。デフォルトで本当に大丈夫なのかと思えるのに、やっぱり1時間ぐらい時間を使います。
Ubuntuって、ファイアーウォールの設定にiptablesだけじゃなくて、ufwというのが使えるんですね。で、ツールの使い方を調べたり、ポートの設定を考えたりで1時間。
ストレージはMySQL一択でしたが、MySQLのエンジン選びも私には自明ではありませんでした。バックアップ方法と合わせて調べだすと、すぐに2時間ぐらい経過していました。
MySQLのRubyライブラリと日本語のエンコーディング周りの設定も、「そういうことなのか」と理解して設定が終わるまでに2時間ぐらいかかりました。
DBのインデックスってなんだったっけ? どうして速くなるんだっけ? ということで、B-Treeの図が載っているMySQL解説本なんかも読んだりします。
「よし、じゃあcronでDBのバックアップタスクを書くかな。書式はこうだっけ? あ、エラーだ。どれどれ、man……、おお、Debianのcrondはsendmailで有名なPaul Vixieさんのやつが入っているのか。どうも書式がキモイな。うん、よし、そうそう、これでオッケー。げ、動かない……。え、cronって環境変数をシステムとは別に自分で設定するのか。そうだっけ、ママン。え、cronってRailsではwheneverというgemを使ってDSLで管理すると楽なの? おお、なるほど」とか言っていると、このへんだけでまた3時間ぐらいかかります。
ActionMailerとPostfixのTSL設定でハマって8時間ぐらい悩みました。インフルエンザで高熱を出して会社を休んだのをいいことに、延々とやりました。そもそもSMTPでTSLをどう使うべきかを良く理解していなかったので、そうした基礎から調べると非常に時間がかかります。こういうのって、外からWebサービスを眺めていたときには「メールってローカルのMTAを25番で叩いてテキスト流しこむだけでしょ?」としか思っていませんでした。でも実際にはフレームワークの都合もあるし、設定は意外にストレートではありません。いえ、実際には必要だった設定は、たった1行で、後からサーバ管理者の友人に聞けば「一体Postfixの何につまずくの?」とバカにされたりもしたのですが、設定している最中はあちこちのドキュメントを読んだり、Postfix側、Rails側の設定を変えたりで五里霧中といった感じでした。
長い文字列を画面に表示するとき、適当な長さでカットしたいものです。Railsには標準でtruncateというヘルパー関数がありますが、どうも表示結果がガタガタする。それもそのはずで、日本語とASCII文字では、同じ1文字でも表示幅が違います。じゃあ、ほかのサービスはどうやってこの問題に対処してるのだろうか、といろいろと見て回ってみると、文字種による表示幅を考慮したtruncateをしているサービスがあるじゃないですか。なるほど! というわけで、私も全角文字は2文字としてカウントするtruncstrというヘルパーを定義。こういう細かなところでも、1時間ぐらいかかります。
途中からJavaScriptライブラリを変更しました。Prototype.jsを消して、jQueryを使い始めましたが、APIを眺めている間に、なぜか気づくとPrototype.jsやjQueryのコードを読み始めていて、なるほどなぁとか言ってるうちに、また2、3時間ぐらいがあっという間に過ぎます。jQueryを使ってAjax化してみたら、もっと早くやれば良かったと思うほど簡単だったのはいいのですが、いざ開発ブランチをマージしてサーバにデプロイしてみると、なぜかサーバ上ではデータロード中のアイコンがクルクル回り続けて画面がアップデートされません。調べてみると、rails.jsというJavaScriptライブラリのラッパーがあるのですが、この中のajax:successがコールバックで呼ばれていませんでした。怪しいと思ったのは、コントローラのrender :partialのオプション指定、jQueryのUJSドライバのバグ、Nginxのプロキシキャッシュの設定、Keep-aliveのタイムアウト設定などですが、私のスキルと時間コストの感覚に照らすと、この問題を特定して解決できる気がしなくて気が滅入りました。結局、この問題の原因は、Ubuntu(=Debian)のNginxのパッケージが古くてバグがあったことでした。バージョン0.8.32より前のNginxは、HTTPレスポンスで201 Createdを返すときに、Content-Lengthヘッダを付けてくれません。このため、HTTP1.1をしゃべるモダンなブラウザは、keep-aliveのときにDOMの描画アップデートを保留して「待ち」の状態に入ってしまうのですね。このことを調べて理解するのに3時間ぐらいかかりました。keep-aliveの挙動ということで、HTTP1.1の基礎が分かっていなかったのだということを悟って、RFCを1時間ぐらい眺めたりもします。
Railsと直接は関係ありませんが、ソースコード管理ツールのGitも簡単ではありません。2冊ほど入門書を読みましたが、たぶん素振り不足なんでしょうね、いまだに操作が分からなくなるときがあります。「あれ? あっちのブランチのファイルをチェックアウトせずに一時的に参照するときってどうするんだっけ?」とか「マージを取り消すときって、HEADをチェックアウトしてから、追加されたファイルを消去……、あれ? 消去するときのコマンドってなんだっけ? 確か-fを付けないと実行できないやつで、えーと……」とか「一連のコミットをcherry-pickするにはどうするの? え、最近のバージョンは範囲指定できるの?」というように、検索しまくっています。git stashに名前が付けられることを昨日始めて知った、というようなことも続いています。GitHubの公開レポジトリにソースコードを置いたはいいけれど、DBのパスワードを間違ってコミットして世界中に公開してしまった!(注:実際には誰も見ていない。誰でも見れるというだけですね) どうすればいいんだ!! ということも起こりました。で、「ああ、やっぱりみんな良くパスワードをGitHubで公開しちゃうのでFAQなんだね」というのを調べたりで、またまた30分。開発ブランチに秘密情報を持っていると、masterにマージできないので、めんどくさいんだけど、これって普通どうするの? というようなことで、まだまだまだまだ悩みます。
デプロイツールのCapistranoって、すごく便利そうじゃない! と思って、あれこれ調べて設定するだけで、これまた2、3時間ほどかかります。
ほんのちょっとしたことでもつまずきます。ブラウザで画像アップロードを受け付けて、モデルのオブジェクトに画像を付加するためのプラグイン「Paperclip」を使っているのですが、このPaperclipが試作アプリでは問題なかったのに、Worklistaに組み込むと、最初はうまく動きませんでした。ImageMagickの問題かと思って手動でビルドしてみたりと頑張ってみました。ところが、ImageMagickを最新版にしても動きません。実は、モデルに書いたPaperclipのオプション文字列で、単数形と複数形を間違えていただけだったのでした。どうしてミスに気付かなかったのか、そもそもImageMagickの問題だなどと見当違いのアタリを付けたのかを考えると、やっぱりRuby/Railsが良く分かってないからカンが働かなかったんだろうなという感じです。ともかくこのときは、3時間ぐらいムダにしました。
認証プラグインの「Devise」で招待コードを実装するために、どこに何を書けばいいのかと、Deviseのドキュメントやメーリングリストを漁るのにまた2時間ぐらいかかります。Deviseは凄まじく便利ですが、持ち込まれる構造的な複雑さが初心者にはつらいですね。
複数のRubyやgemをバージョン別に管理できるrvmをいじったついでに、zshの設定に凝りだしてしまということも起こります。どうせならプロンプトにGitのステータス出したいよね、みんなやってるしね。と、適当にそれっぽいブログを検索して、なるほどなるほどとか言いながらコードをコピペ。でも動かない……。ええい! もうこの際、zshのマニュアルをダウンロードして読むか! と、これでまた貴重な朝の2時間が消えたりします。
ついでにEmacsのGitモードを試してみて1時間……。そういえば、EmacsのRails開発環境だと、実はRails Reloadedじゃなくて、Rinariがいいらしいので入れ替えよう、ということでまた1時間。なんだよ、Emacsっていつからido-modeなんていう便利なものがあったんだ! これはすごすぎる! ん? あれ、なんかキーバインドが難しいな……、よし、ちょっくら練習するか! で、また1時間です。
……このへんは盆栽みたいなものですね。ツールをあれこれ調整するのは枝ぶりを調整する盆栽のようです。それ自体が楽しいのですよね。zshやEmacs、Screenのカスタマイズは、無限に時間を潰せます。いい加減20年も使ったし、Emacsを捨てたいと思い、TextMateを一生懸命頑張ってみたり、Redcarを入れてみたりということもやりますから、ツールに親しむのも時間がかかります。GNU Screenの挙動が気に入らず、パッチを作ったこともあります。本末転倒気味ですが、そういうものですよね。
zshとRails開発は関係があるような無関係のような感じではありますが(たぶん無関係)、何が言いたいかというと、周辺のツールやミドルウェア、プラグインまで含めると、Webアプリの開発で知らなければならないことというのは非常に多く、ともかく時間が必要ということです。
さらに追い打ちをかけるように、「テストを書かなきゃRuby開発者じゃないよね」という声が聞こえてきます。それで、RSpec、Cucumber、Capybara、Seleniumと、テスティングフレームワークだけで、またいろいろな知識が必要とされます(Seleniumに感動しました!)。いえ、実際にはどれもまあ使うだけかもしれません。しかし、手を動かして「なるほど」という程度に理解するだけでも結構時間がかかります。「個人プロジェクトならテストなんて書かなくていいんですよ、ジャンジャンやっちゃえば」という意見もいただきましたが、見よう見まねでDSLを書けばそれなりに動いてしまうのがRailsです。ドキュメントを眺めながら書けばいいんですよね、といいつつ、やっぱりRSpecやCucumberの本を買ってきて読み始めたりして、また何時間もかかったりするわけです。リファクタリング関連の本も、理論ぽいもの、実践ぽいものとで2冊ほど読みました。
最近、だんだんとjQueryのコードが増えてきたので、JavaScriptの本を何冊か買い込んできて勉強したりもしています。jQueryの本もサラサラと2冊ほど読みました。jQueryのAPIはシンプルかつ対称性もあって難しいところはありませんが、例えば、jQueryを書くときの重要ポイントとして、DOMのトラバースを想像して効率を考えないと、レスポンスが重たくなりやすいというようなことは指摘されるまで分かりませんでした。実は今のところ、iPadでWorklistaを操作すると、とてつもなくモッサリとしか動作しません。あるいは.bind()と.live()の使い分けを調べていると、ブラウザ上のイベントの伝播のタイミングや規則というものの理解が足りていなかったことが分かったりします。調べだすと面白いなーとは思うのですが、本当に時間がかかります。
Omniauthという認証ライブラリでFacebookとTwitterのログインに対応しましたが、FacebookのAPIのドキュメントを眺めたり、テストしたり、ということですぐに2時間ぐらい経ってしまいます。Facebookのデベロッパーページは、何というか、阿鼻叫喚ですね。10月1日が楽しみ?
Facebookのユーザーアイコンは正方形じゃないケースがあります。あれ? じゃあみんなどうやってアイコンを流用してるの? と、いろいろと調べてみると、どうも正方形以外の写真だと、正方形の切り抜き位置をユーザーに選ばせるんですね。こういうのも自分のアイコンを変えながら調べたりすると1時間ぐらいかかります。
ユーザーのアイコンはFacebookやTwitterがCDN上に持っている画像をURLとして直接埋め込む方式にしました。そのURLは実際にはそれぞれのAPIを叩いた結果、302 Movedで転送された先です。ということは、転送先URLを直接叩くのは微妙にアンドキュメンテッドな使い方っぽいです。ある時、ファイル名の命名ルールが変わるかもしれませんし、ユーザーがアイコンを変えるとどうなるのかよく分かりません。かといってGraph APIを毎回叩くのは遅いし、API制限に引っかかりそうです。API制限を調べてみると、公式には何も書いてありませんが、どうも1分間に600回というようなことがまことしやかに言われています。いずれにしてもアイコン表示の全てで、毎回Graph APIを叩く選択肢は、ちょっとないのかな、と思いました。さらに、よくよく調べてみるとCDN上の画像はユーザーが明示的に消しても何年も消えないまま残ることがあるようなんですね。プライバシー上の懸念がある一方、CDN上のオブジェクトをポイントするサードパティーアプリがあると考えると、この仕様は合理的にも思えます。いや、Facebook自身、あまりに巨大すぎてFacebook上の更新済みオブジェクトのポインタを張り替えることが非現実的なのかもしれません。そもそも302で転送されているというのは、301とは違いますよね。いや待てよ、HTTPのステータスコードの301と302はどう違うのか? と言い始めると、RFCやWikipedia、関連ブログエントリを読み出して、またまたこれは大変に時間がかかります。というように、単なるFacebook連携だけでも、調べ出すと、いろいろ難しい話があるんだなという感じで、そうこう言ってる間に3時間ぐらいかかっています。
というように、いくらRailsがムダを省いてくれる高速道路(高速鉄道?)のようだとはいっても、前提として必要な知識量が膨大だなというのが感想です。知識もそうですが、振り返って考えると、「どういう仕組みで実現されていて、どうやって、なぜそれをやる必要があるのか」というメンタルモデルが脳内で形作られるのに時間がかかるのかもしれません。Gitが典型です。あるいはテストに関する諸々の概念(フィクスチャ、モック、スタブ)もそうです。だから、後から振り返ってみると、なぜそんなにそのツールやライブラリを理解するのに時間がかかったのか分からない、ということが多くあります。
Worklistaを作っていく中で否応なく学んだ技術的トピックやノウハウの数々は、自分でも信じたくないぐらいの分量になっているように思います。仕事と家庭を持つサラリーマンが片手間にやるには厳しい感じです。平日の朝5時に起きて、そこから2時間、子どもが起きてくるまでが勝負という感じです。
もちろん、次にRailsで同じようなものを作るのであれば、ずっと速く作れるだろうなという風には感じていて、それは良かったと思っています。実際、隣の部署が困っている問題に対して、シンプルなWebアプリを1つ作ってみました。特定のWebページをスクレイプした結果を元にTwitter APIを叩き、その統計情報を日々データベースに蓄積していき、Google Chart APIに数字を投げて可視化する、というようなカンタンなWebアプリです。そういうことは朝の2、3時間でできるようになりました。
分かったこと3:完成度を8割から9割に上げるのは大変
どんな仕事でも「完成度を8割から9割に上げるのはとても大変」ということはよく言われますが、それを身を持って実感しました。
ユーザーが入力したURLを元に、HTMLをフェッチしてくるという処理には、RubyのNET::HTTPを抽象化したライブラリ「open-uri」を使っています。今のところHTMLをパースするまでもないので、正規表現でtitleタグを切り出しているだけです。これはirb(インタラクティブなRubyの実行環境、いわゆるREPLですね)でちょこちょこ試せば1分で書ける処理です。
1分で書ける処理でも、ちゃんとやろうと思うと、いろいろと問題があるものです。
まず、タイムアウト処理が難しい。いえ、タイムアウト処理を書くこと自体は簡単です。でもopen-uriなどが依存しているCライブラリのlibcurlがブロックしていて、実は状況によってはタイムアウトさせることができません。つまり、Cレベルで何か対策するしかないんですね。名前解決が“刺さる”状況では、open-uriやNet::HTTPだけでなく、かなり多くのネットワーク関連ライブラリでタイムアウト処理がうまくいかないようです。調べてみると、CRubyには、それを解決するためのresolv-confという差し替え用ライブラリがあることが分かりました。ところが、このresolv-confを使うと、今度はActionMailerがエラーを吐くようになりました。
ここで私は途方に暮れました。原因を調べるために必要なスキルが欠けています。あるいは、調べるのに必要と思われるコストと、実現したいことが見合わないのですね。
文字コード問題も結構大変です。
open-uriで文字列としてHTMLを読み込んだ場合、そのStringオブジェクトはexternal_encodingの設定に従いますが、それは困ります。UTF-8以外にも、Shift_JISやEUCで書かれたWebページは普通に存在しています。それで、いったん一律8ビットASCIIとして読み込み、HTMLやXML文書に書かれたcharsetを見てエンコーディングを変えるようにしてみました。ところが世の中にはcharsetで嘘をつくWebサイトというのがあるんですね。
エンコーディングの判定で信じるべき情報には優先順位というのがあって、それはWeb開発者の常識ですよと、後になって教わりました。ついでに言うと、他人のサービスのAPIを叩くときには、HTTPヘッダにメールアドレスなど連絡先を入れておくのがマナーということも、プロの方に教わりました。
charsetに指定するエンコーディング名として、歴史的経緯からx-sjisというものが残存しています。遠い昔にそういうものがあった気がしますが、これのために文字化けが起こりました。RubyはEncoding::name_listという組み込み定数に、Rubyで扱えるエンコーディング名が“全部入り”という感じ入っています。携帯電話キャリアのものも入っているので安心していたのですが、x-sjisは入っていません(規格上は存在していないので当然ですよね)。なので、x-sjisは明示的にShift_JISとして認識させるコードを書き足す必要がありました。うぐぐ、という感じです。
さらに、最近のHTMLではASCII文字に入っていない、Unicodeのクオーテーションや記号類が使われます(「»」が典型です)。これらがエスケープされて実体参照(»)となってしまう挙動も、「文字化けしてますよ」と指摘されたことを受けて、明示的に変える必要がありました。
これはまだやっていませんが、記事の本文の冒頭を引っ張ってきてデータベースに入れたいと思っています。調べてみると、Webページの中でどこが本文かを推定するのは、かなり難しいことであるのが分かりました。本文抽出処理は、終わりなき精度向上の道が待っているヒューリスティクスの世界。サイト個別のプラグインによるアプローチが必要なのだと知りました(一番単純で有効なのは、最も多くの句読点を含む最初のdivタグを本文だと推定する方法らしいです)。
手元で書いて動くコードは1分でできるのに、例外処理をして9割の完成度に上げるのには、とてつもなく時間がかかる場合がある、ということかと思います。
しかも、あまり楽しくありません。
Webアプリにサービス(人に喜んでもらう)としての価値があるとしたら、こういう細かいことを積み上げていく“積分値”こそサービスなのかなという気もしていますけど。
分かったこと4:アプリ作りは思った以上に楽しい
実際にRailsアプリを作ってみて分かったことの4つ目は、「アプリ作りは思った以上に楽しい」ということです。これには2つの側面があります。実現方法を考えるのが楽しいという面と、ユーザー体験やシナリオを考えるのが楽しいというサービス開発面があります。
Worklistaでは、各アイテムに対して、はてブ数やTwitter上のクリック数をAPI経由で取ってきて、準リアルタイムに反映しています。この機能を実現しようとしたとき、こう思いました。
「まさかテンプレート(ビュー)をレンダリングするたびに、はてなのAPIを叩いていいわけがない。相手がもし図書館だったらタイホされちゃう……」。
では更新の戦略はどうあるべきか? はてブ数の伸びが速いときには頻繁にAPIを叩き、数字の伸びが鈍ってきたらAPIアクセスの頻度を下げる、ということにしました。まず初期更新間隔を180秒とし、この間に5%の伸びが観測できなければ更新間隔の秒数を4倍ずつ増やすようにしています。どうも追随性が悪いので5%という数字を3%ぐらいに変えてみようと思っています(5%というのは「ひとまず消費税率にしておくか」と適当に決めた数字です)。
こういうことって、経験を積んだ人には、「ああ、そういうときはですね」というように、どうすべきかすぐに分かるのでしょうね。
APIアクセスはユーザーのアクションとは同期させずに、バックグラウンド処理としましたが、このとき、キューを使った非同期処理の仕組みを何で実現するかもまた、選択肢がさまざまです。
AmazonRDSのようなサービスを使うのか、MySQLでキューが実現できるQ4Mを選ぶのか、Redisと組み合わせて使えてWeb UIまである高機能なResqueを使うのか、はたまたRailsで標準的に使われるプラグインのdelayed_jobを使うのか、などといったことです。結局、実装をシンプルに保つことを何よりも最優先すべきという判断から、cronでrakeタスクを叩くようにしました。一番つまらないアプローチですが、選択肢を並べて、いろいろと調べたり検討する作業というのは楽しいものだなと思いました。
ここにあるのは、システムを構築する楽しさで、レゴブロックのような喜びです。誰に文句を言われるわけでもなく、自分が思った通りにブロックを積み上げる子どもが感じる喜びだと思います。
実装をどうするかということよりも楽しいのは、「ここに、誰でもコメントを付けられるようにするべきだろうか? それは何文字であるべきか? どういうユースケースにしたいのか? コメントと呼んでいるものは本当は何なのか? 誰が、何のためにコメントを付けるのか?」といったことを考えることです。
やってみて良く分かりましたが、単純な機能1つ取っても、何も自明じゃないんですね。例えば「登録アイテムにタグを付ける」といっても、それは「特定ユーザーのもの」(つまり私が登録したrubyというタグがあるアイテム)と「全ユーザー」(rubyとタグが付いた全ユーザーのアイテム)の2つがあるべきで、そのナビゲーションやURLがどうあるべきか、ということも考えなくてはいけません。
そうしたものを確定させていくのは楽しい作業です。なぜ楽しいのか、いま、この文章を書きながら、その理由が豁然とひらめきました。
何を決めるにしても会議がないんですよ!
Worklistaでは自分の記事を登録するようになっていますが、実は他人の記事を引っ張ってきてコメントや批評、キュレーション的な解説を付けられるようにするべきではないか、と思っています。はてなブックマークと同じく、一種のソーシャルブックマーク機能です。はてなブックマークと違って、
- 文字を多く書けるようにする
- コメントにコメントを付けられるようにする
- 各コメントには「同意!」「同意しかねる!」ボタンを付ける
- 登録アイテムの多くは情報の発信者自身
- Twitter、Facebookと連携することで顔が見えるやり取りができる
ということをやると面白いのではないか?
英語圏でいえば、RedditやDiggといったソーシャルアグリゲーションかもしれませんし、キュレーションプラットフォームかもしれません。Worklistaは、記事を書く人をユーザーとして想定していますが、テーマを持って記事を書いている人は、良きキュレーターでもあるだろというのが私の仮説です。
「じゃあ最低限の機能でいいからキュレーション機能を付けてみよう」
そう思ったある朝、タブを1つ追加してキュレーション機能を実装してみました。ところが、「サービスの軸がぶれませんか」と友人の1人に言われました。すぐに考え直し、結局、キュレーション機能は実装後12時間で削ってしまいました。
この決定には、上司の承認も、関係部署の合意の取り付けも必要がなかったのです。実験的に実装し、実際に触ってみて「意外にいいじゃん! でも、これは別サービスとして切り出すべきかも……」ということが分かりました。オレオレWebアプリ開発って素晴らしいですね。もちろん、ユーザーがほとんどいないからできることではありますけど。
分かったこと5:Webアプリはプログラミングとしては退屈な面も
Webアプリを書く前から、少しずつプログラミングを勉強しています。新しい言語や概念、アルゴリズム、データ構造、テクニック、ソフトウェア開発にまつわるもろもろを学ぶというのは、知的好奇心を満たしてくれる楽しいアクティビティです。
一方、Webアプリは複雑で大きな世界ですが、全体像が分かってくるにつれて、プログラミングという感覚がどんどんなくなっていきました。Railsぐらい抽象度が高いと、ソースコードは“動く詳細設計書”という感じです。「こういう機能を作りたい」というのを最短時間で実現できるのは素晴らしいことですが、そこには「よっしゃ動いた!」というプログラミングの喜びは、あまりありません。WorklistaというのがトリビアルなWebアプリだからということもあるかと思いますが。
フレームワークに乗っかってシンプルなものを作る作業は、実はプログラミングとしては退屈なのかもしれないな、と思えました。日々解決するべき問題というのも、ライブラリのAPIを調べたり、ライブラリの整合性を取ったり、外部APIの調査をしたりと、あまりプログラミングと関係がありません。何かを考えて作るというよりも、次々に現れるツールの使い方を学ぶことで精一杯という感じがします。Railsで学んだことには、ポータブルな知識もあると思いますが、それでも別言語、別フレームワークとなれば、また学び直しかと思うと、開発者の方々が自分が取り組んでいる言語に過剰に思い入れを持つのも分かる気がしました。スイッチングコストが大きいのですね。
プラグインを作るとか、Railsというフレームワークの中身に踏み込むということをすれば楽しいのかもしれません。
分かったこと6:世の中のWeb APIの充実度
TwitterのAPIにしろFacebookのAPIにしろ、あるいはGoogleが買収したCAPTCHAサービスのreCaptchaにしろ、実に簡単に実装できるように工夫されています。薄々は知っていましたが、これは新鮮な発見でした。
使ってもらってなんぼだから当たり前といえば当たり前ですが、人気サービスのAPIは、これ以上はないというほど使うのが簡単です。ドキュメント、APIの実験ツール、ライブラリの提供具合と、凄まじい充実ぶりです。Google Font APIという新し目のものも使ってみましたが、実装するだけなら、検索してドキュメントを眺める時間を入れても10分程度で対応が完了という感じです。
最初、CAPTCHAを実装しようと思ったとき、私はCのライブラリかImageMagickのスクリプトがあるだろうと当たりを付けました。ところが、思ったよりもそういうものは少ないし、洗練されていないんですね。何故だろうかと不思議に思ったのですが、今やWebサービスとしてAPIで実装する時代なんですね。
分かったこと7:セキュリティは非常に難しい
FacebookでOAuth認証をすると、コールバックで、こちら側のサーバの任意のエンドポイントに対して、認可トークンを付加した形でHTTPで叩いてくれます。ところが、RailsのOAuthプラグインの「Omniauth」を使うと、標準では、このコールバックのプロトコルとしてHTTPSではなく、HTTPが使われます。
OAuthで認証・認可したユーザー(のブラウザ)は、このコールバックのURLでリダイレクトされて、Worklistaのサーバを叩きます。このとき、URLに含まれるパスの情報は、HTTPだとリクエストヘッダに平文で含まれるわけですから、ユーザーの認可トークンが盗聴される可能性があります。トークンがあれば、そのユーザーが認可した権限に基づいてFacebookのAPIが叩けます。これはマズイのではないか、と思いました。
公衆無線LANだと暗号方式にもよるでしょうけど、HTTPだと同一セグメントにいる人々のトークンやセッションは盗聴できますよね。オフィスなどのLANはスイッチングハブなのでパケットの盗聴は直接はできませんが、それでも同一セグメントに「arp spoofing」とググれるだけの知識と悪意のある人がいるかもしれません。平文で流れるトラフィックの盗聴は簡単です。
セッション・ハイジャックというのは、HTTPでクッキーをやり取りしている限り、本質的に防ぎようがないように思うのですが、違うのでしょうか? 改めて調べてみると、日本の大手ECサイトやSNSサービスですら、全然ハイジャックが楽勝でできるように見えるのですよね……。それどころか、mixiを見て驚いたのですが、ログイン画面ですら、HTTP POSTでパスワードをユーザーに投げさせているではありませんか。
えっ!? ガラケー対策? それにしても、ユーザーに平文でパスワードを投げさせるのは、ひどくないですか? なぜPCブラウザからのアクセスでSSLを標準にしないのか分かりません。明らかに危険だと思うのですが、大きな問題になったと聞いたことがありません。
私はFacebookから飛んでくる認可トークンを「HTTPSで守らないと!」と思い、年額2900円のSSL証明書(ちなみに、RapidSSLです。大丈夫です)を取得し、NginxをSSLモジュール付きでリビルドし、HTTPS通信時のブラウザの警告を消すためにFacebookのCDN上の画像をローカルファイルにキャッシュするように一部コードを追加したりしました。でも、もしかしてこれらの作業は、YAGNI(You Ain’t gonna Need It)だったのではないかと思い始めています。すでに友人が何人も登録してくれているのだし、守るべきものは守ろうとは思います。でも、何千万人もユーザーがいるサービスですら、パスワードやセッション情報を守っていないのであれば、登録ユーザー数が40人しかいなくてパブリックな情報しか預かっていない私のサービスで、しかもFacebookのプロフィールが少し読める程度の認可トークンのためにSSLなんて使う必要があったのかどうか、と思わなくもありません。
ともあれ、セキュリティは本当に難しいですね。調べても調べても分からないことが多いです。
分かったこと8:本当にRailsを学ぶべき人は誰か
私はWeb(インターネット)には輝かしい未来があると思っています。だから動向がとても気になっています。Webベンチャーが好きで、よく記事も書きます(シリコンバレーのWebベンチャーを取材して記事を書いたりもしています)。そういう私にとって、Worklistaは習作です。自分で手を動かしてやってみれば、技術やサービスについて記事を書くときにも、より良いものが書けるだろうということです。
習作なのですが、同時に本気だったりもします。
プロじゃなくても、簡単なWebサービスは作れるということが私には分かりました。多分、やればやるほど上達もするだろうとも思っています。Railsで簡単なWebアプリを作ってみた結果、もっと多くの“非エンジニア”が実装スキルを学ぶべきではないかという気がしてきています。
ITは、ほかの産業と違って、既存の経済活動に作用してレバレッジを効かせることが価値であるという特性があります。どうITを既存業務に作用させるか、どうやってITなしで不可能なことを実現するかが価値です。だからこそSEの皆さんは“業務知識”を蓄えるわけですよね。その逆のアプローチとして「もう現場のキミがいちばん分かってるんだし、キミが書いちゃえば?」というアプローチも、もっとあってもいいのではないかと思います。
医療、会計、法律、教育、出版、旅行、ファッション……、いろんな産業がありますが、各分野で本当にイノベーションを起こすべき人々は、今からでもプログラミングを学ぶべきじゃないかと思います。30歳でも40歳でも遅くないと思います。1、2年ぐらい取り組んでみる価値があると思います。本番で使うプロダクトコードを書かないにしても、ITによって何が可能となるかが分かれば、それを適用すべき問題を抱えている人というのは世の中に多くいるはずだからです。
セキュリティ対策のこと、SQLのチューニングのこと、クラウドを上手に使うというスケーラビリティのこと、あるいは、きちんとテストがあって一定品質のコードで維持・構築していくというメンテナビリティのことなどを除けば、プロじゃなくても簡単なRailsアプリは、比較的すぐに作れるようになると、私は思います。少なくともプロに依頼するために、何がどうやって実現できるのかを知っておくのはとても良いことでしょう。そのハードルは極めて低くなってきています。もちろん、「1週間で分かる!」という類のタイトルの書籍がばらまく幻想のように簡単ではありませんが、例えば外国語を学ぶのよりは簡単で、1000時間程度の取り組みでも十分に意味があると思います。
ITは既存産業に作用します。この話を私に当てはめると、「IT+ネットメディア」です。
ITとメディアの接点に、新しい価値を生み出せるものがあるという直観があります(ちなみに私が在籍する会社の社名はITmediaです!)。英語圏を見ていると、HuffingtonPostやQuora、StackOverflow、Ardvark、AsqAny、TechMeme、Redditなど、メディアとサービスの中間と言うべき領域で、新しいプラットフォームが次々に出てきています。自動処理や統計処理というITと、編集者・ライター・読者という人間の重なる領域です。日本でもNAVERまとめや、ザ・インタビューズなど、いろいろとサービスが出始めています。
そういうものを横目で見ていて、いろいろとアイデアを思い付くわけです。「ザ・インタビューズ」を見ていて、「ちくしょう、オレだって、そういうプラットフォームを作ってみたい!」と思うわけです。
思うだけではダメで、試行錯誤しながら「やってみる」ことが重要だと思っています。やってみないと分からない。それなら、いつまでも会議室で次世代メディアのあり方を議論していてもしょうがない。サービスの作り方の見当が付かないようでは、何が実現可能で、どうやって外注するべきかも分かりません。それが私の問題意識でした。WordPressを適当にカスタマイズすることがネットメディアなのか? まさか! という気持ちです。
だから、自分1人だけであっても、まずはやってみようと思って最短距離を走れそうなRuby on Railsを選んだのでした。1人の人間が限られた時間でWebアプリを作るというとき、Ruby on Railsはベストの選択だと思います。過去に、PHPでWebコミュニティを作ろうと1カ月ほど頑張った経験があります。XOOPSベースです。簡単なCRUDアプリの追加が必要なだけだったのですが、目に見えてコードはスパゲティになりました。DBのスキーマも破綻しそうなことが明らかに思えて、すぐに行き詰まりました。反省から学びつつ前進できるとはいえ、どうして良いのか分からないことが多いんですね。その点、Railsは「Webアプリ設計、かくあるべし」というベストプラクティス集として1本のレールがあるので、初心者に優しいと思います。今なら素のPHPでも何とかできる気がしますが、それはRailsがMVCやDBのテーブル設計の基本を“教えてくれた”からです。Railsは「Webアプリ開発者養成ギブスだ」というのは本当だと思います。教えてくれたという意味では、Rubyがオブジェクト指向を教えてくれたということも感じています。
ともあれ、Webアプリを作る上で、どの程度の工数でどういう機能が実装可能かということは、Worklistaを作ってみたことで、ずいぶん分かったように思います。
分かったこと9:サービス作りに関心がない開発者も多い
ITを活かすべき現場の人々は、その分野における深い洞察や、将来へのビジョン、そしてパッションを持っていることでしょう。それは貴重な資源だと思います。
Worklistaを作る過程で、多くのRails開発のプロに会ってきましたが、いちばん驚いたのは「特に作りたいサービスはない」という人が多いことでした。正確に言うと、作りたいのはイケてるライブラリや、開発者向けツールであることが少なくないのですね。開発コミュニティへの貢献が楽しくて、やりがいのあることだという印象です。これはこれで素晴らしいことだと思います。傍目にもオープンソース活動は楽しそうで、できることなら、私もあれこれのプロジェクトに対してパッチを書いてみたいと思い始めています。
私が熱っぽく今後のネットメディアはどうなるだろうかという話なんかをしたところで、Rails開発者と呼ばれる人たちの多くは乗ってこないんですよね。そりゃあ、そうです。それが仕事ではないですし、特別注視しているわけでもありませんから。
だからこそ、現場主導の開発には大きな価値が生まれる可能性があるのではないかと思うのです。人間誰しも自分の心配事でこそ必死になれるものです。私は何か新しいネットメディアのあり方がないだろうかと考え続けています。有り体に言って、このまま同じことを続けていても、オレ(たち)は食えなくなるのではないかと思っています。個人としても、企業に属する中堅社員としても現状に危機感を持っています。
Ruby on Railsを本当に使ってアイデアを形にすべきなのは、開発を効率化したいWeb開発者ではなく、既存産業をITで変革したいと思っている人々なのではないだろうか。Railsに触れてみて、少しそんなこと考えるようになりました。
ずいぶんいろいろと偉そうに分かった風なことを書いてきましたが、「RubyやRailsをやってみたい!」と思っている人の参考になれば嬉しいです。