| @技術/プログラミング

一個前の記事で書いた「記事の更新時に updated_at ではなく created_at が更新されてしまう」問題、原因はプログラム側にあるのではなく、MySQL の設定の問題だった。

mysql> desc entries;
+-----------------+--------------+------+-----+---------------------+-----------------------------+
| Field           | Type         | Null | Key | Default             | Extra                       |
+-----------------+--------------+------+-----+---------------------+-----------------------------+
| id              | int(11)      | NO   | PRI | NULL                | auto_increment              |
| user_id         | int(11)      | YES  |     | NULL                |                             |
| category_id     | int(11)      | YES  |     | NULL                |                             |
| slug            | varchar(255) | YES  |     | NULL                |                             |
| title           | varchar(255) | YES  |     | NULL                |                             |
| body            | text         | YES  |     | NULL                |                             |
| type            | text         | NO   |     | NULL                |                             |
| draft           | tinyint(1)   | YES  |     | 0                   |                             |
| created_at      | timestamp    | NO   |     | CURRENT_TIMESTAMP   | on update CURRENT_TIMESTAMP |
| updated_at      | timestamp    | NO   |     | 0000-00-00 00:00:00 |                             |
| frozen_tag_list | text         | YES  |     | NULL                |                             |
| markup          | varchar(255) | YES  |     | NULL                |                             |
+-----------------+--------------+------+-----+---------------------+-----------------------------+
12 rows in set (0.00 sec)

updated_atcreated_at の設定値が逆になってたのが原因。ALTER 文でカラムの情報を入れ替えておいた。

MySQL に流し込んだ Sqlite3 のデータを dump したやつの CREATE TABLE entries を見ると以下のようになってた。

CREATE TABLE `entries` (`id` integer PRIMARY KEY AUTO_INCREMENT, `user_id` integer, `category_id` integer, `slug` varchar(255), `title` varchar(255), `body` text, `type` text NOT NULL, `draft` boolean DEFAULT '0', `created_at` timestamp, `updated_at` timestamp, `frozen_tag_list` text, `markup` VARCHAR(255));

なんでこれが created_at に対して更新時に現在時間を上書きし、 updated_at は作成時のみ現在時刻が入るようになるのかは分からない。

それにしても日頃 MongoDB ばかり使っていて、データにおかしなことがあるのはほぼ間違いなくコードのせいだと思う癖がついていることが今回よくわかった。データベースのスキーマを見てみるまでに3日くらい時間がかかった。とほほ。

一方でデータベース内のデータ構造のことをあまり考えなくてよく、開発のみに集中すればよい MongoDB はやっぱり便利だなと思った。規模がでかくなったり高速な読み書きをさばかなければならない状況だと MongoDB にも色々問題があるのでしょうけどね。

| @技術/プログラミング

Jekyllを使いだしてから気がつくと一年経ってました。いろいろ便利に使えており気に入っております。

PygmentでコードをシンタックスハイライトしたりLSIで関連記事表示したりと結構手を入れてはいたんだけど、いわゆる世間の一般のブログにあるようなカテゴリ一覧表示機能と、カテゴリごとの記事アーカイブ機能がなくて、それを若干不便に思っておりました。

ググってみたところ、プログラマー向けなブログツールなだけあっていろんな方法が出てきました。以下そのまとめ。

カテゴリ一覧

JekyllのLiquid (テンプレート言語) には {{ "{{ sites.categories " }}}} みたいタグがあるんだけど、こいつが意図したとおりに動かない。普通のRuby使いの感覚からすると site.categories ってカテゴリを沢山持った配列になってそうな気がするんだけどこれが違う。

<ul>
{{ "{{ for category in sites.categories " }}}}
  <li>{{ "{{ category.name " }}}}</li>
{{ "{{ endfor " }}}}
</ul>

↑みたいな感じのコード書くと何も表示されない。 site.categoires はHashで、{ "カテゴリ名" => カテゴリ内の記事一覧 } みたいな構造になってる。LiquidでHashのキーを取りだす方法が分からず、どうにもこうにもいかなかったので他の人が作っているプラグインを利用することにした。

↑のファイルを JEKYLL_ROOT/_plugins にコピーする。(_plugins というディレクトリがなければ作る)。そんでテンプレートを変更する。↑のやつを↓みたいにする。

<ul>
{{ "{{ for category in sites.iterable.categories " }}}}
  <li>{{ "{{ category.name " }}}}</li>
{{ "{{ endfor " }}}}
</ul>

2行目のところが変更点です。これでカテゴリ一覧表示ができるようになる。

カテゴリごとの記事一覧

カテゴリごとの記事一覧を表示する方法だけど、こういうのを発見した。

ここの generate_categories.rb を使えばカテゴリ内の記事一覧を作成できる。こんな感じ。

これもさっきのと同じように、JEKYLL_ROOT/_plugins にファイルをコピーする。そんでLiquidテンプレートを書き換えるんだけど詳細はプラグイン内の記事をご確認くだしあ。

| @技術/プログラミング

ポータルシットをLokkaに置き換えたくていろいろやってる。ポータルシットの過去記事をYAMLでエクスポートし、それをLokkaのDBに取り込む作業をやってる。TDD BootCampに参加したので、テストファーストしながらの作業。RSpecでテストコードを書き、ログが正しくインポートできることを確認する。テスト終了時 after(:all) フックで、取り込んだログを削除してる。コードはこんな感じ。ちなみにLokkaはDataMapperをORMに採用してるので以下はDataMapperでの話。

after(:all) do
  Category.all.destroy
  Entry.all.destroy
end

しかしこれでは AUTO INCREMENT の値がリセットされず、テストを繰り返す度に AUTO INCREMENT の値が増えていってうざかった。

DataMapperの機能で AUTO INCREMENT 値をリセットするのってないのかなと5秒くらい探してみたけど見つからなかったので、SQLを直接実行する方法を採用した。

ちなみにRDBMSに採用してるのはSQLite3。SQLiteでは UPDTE sqlite_sequence SET seq=0 WHERE name='テーブル名'; みたいなコードで AUTO INCREMENT 値を任意の値に設定できるみたい。

最終的な after(:all) フックはこんな感じ。

  after(:all) do
    Category.all.destroy
    Entry.all.destroy
    Entry.repository.adapter.execute('update sqlite_sequence set seq=0 where name="entries";')
  end

テスト実行後にはすべてのデータがデータベースから削除されて、AUTO INCREMENT の値もリセットされる。人畜無害なテストコード万歳。

| @読書

Ruby on Railsの生みの親、デイヴィッド・ハイネマイヤー・ハンソンの勤務先37シグナルズの本。CEOのジェイソン・フリードとデイヴィッドの共著です。とても共感しながら読むことが出来ました。個人的に響いた部分を箇条書き。

計画をやめる

  • 計画を予想に言い換える。誰にも未来のことを計画するなんて不可能。
  • 計画はあらかじめ立てるのではなく、やりながら立てる。やっていないと情報が集まってこない。

最適な規模

  • 無意味に拡張しない。規模の拡大はコストも増やす。
  • 働きすぎるのは馬鹿。ヒーローになるな。

自分たちが必要なものをつくる

  • 37シグナルズの Highrise は自分たちが必要性に駆られて作った。

まずつくる

  • アイディアは実行しなかったらアイディアのまま。
  • 金がないとか時間がないとか言い訳にならない。ベストな状態で始められることなんてない。本当に実現したいことだったら金や時間は自分で工面をつけるもの。

金を借りない

  • ウェブサービスとかは特に金が必要ない。
  • 他人の金が入ると感覚がおかしくなるし、長期的な視野を持てない。

なんでもまず自分たちでやる

  • 会社の規模はコンパクトに維持し続けるべき。
  • まずなんでも自分たちでやってみる。できなかったら人を雇う。

スタートアップという意識を捨てる

  • スタートアップには甘えがある。
  • 他人の金で好きなことをやるなんて幻想。
  • 最初から利益の出せる企業を目指すべき。
  • exitのことを考えるとユーザー本意のサービスが作れなくなる。

制約を利用する

  • 優れた作家は制約のもとで創作していた。シェイクスピア、ヘミングウェイ、カーヴァー。
  • 一度にサービスに携わる人間は一人か二人に限定し、機能は絞る。
  • 芯から作り、本質的でない細かい部分は後回しにする。

副産物

  • 企業は自分たちが気づかないうちに副産物を生産している。木工所はおがくずを売った。37signalsはGetting Realという本を副産物として売った。

すぐリリース

  • 不完全な状態でも最低限な条件をクリアしたらすぐにリリース。

会議をやるやつは馬鹿

  • 会議は時間の無駄。やっても7分。
  • 会議には準備が必要だが、十分に準備することは不可能。
  • 1時間の会議に10人が参加したら、10時間の生産性が犠牲になる。会議にそんな価値はない。
  • 会議は新たな会議を生み出すだけなので不毛。

一人で作業する時間をつくる

  • 電話とかメールとかシャットアウトする時間を作らないと生産性は上がらない。
  • せめて一日の前半か後半のどちらかは一人作業モードに設定すべき。
  • 連絡手段は電話やチャットなど即時対応式のもではなくなるべくメールにする。

そこそこの解決策

  • 完璧な解決を求めようとしない。そこそこの手段で済む問題にはそこそこの解決策を。問題があれば後から良くすればいい。

タスクは分割する

  • 長大なタスクリストは気が滅入るだけ。
  • 100のタスクを10ずつに分解すれば心理的に楽になる。

はまったら人に見てもらう

  • 意固地になって無駄に時間を費やすとコストに見合わなくなる。
  • はまったら他の人に冷静な視点でレビューしてもらう。

寝る

  • 睡眠不足は創造性を損なうし、士気が低下する。間違いも犯しやすくなり、他人に不寛容になる。いいことは一つもない。

真似ない

  • コピペコードは理解が伴わないから、いつまで経ってもオリジナル作者にかなわない。

社員が一緒の国に住んでる必要はない(デイヴィッドは入社当初はまだデンマークにいたらしいです)とか他にも面白いところもあるんだけど、英語がしゃべれないとこの辺は僕らには当てはまらないですよね。あと会議を極力しないってのは理想だと思うけど、受託開発というかホームページ制作みたいなお客さんがいる仕事してたら打ち合わせはしないといけないわけで、なかなか難しいでしょう。

でも電話や会議などは確かに生産性を損ねていると思う。電話なんていきなり日常業務に割り込んでくるわけだから。電話は予約制にして欲しい。何日の何時に電話したいのでお願いしますみたいな感じでメールしろや。

雑談の排除とかも大事ですよね。僕はなるべく仕事中は雑談しないようにしてる。だからといって生産性が高いかと問われれば疑問なんだけど。でも雑談とか会議とか打ち合わせとかやって仕事した気になってる人は多いと思う。例えばこの本では人の雇い方のパートで、仕切り屋を雇うなみたいなことが書いてある。仕切り屋は会議好きで、自分の仕事を作り出すために会議を開きたがる。まったく何の価値も生み出さないのに、会議に参加することで会社に貢献しているふりをするわけですね。こういうのは本当に最悪。

37シグナルズの発想は、ピュアに作り手だけで会社を動かそうという風に読めました。広告とか営業とか意味ないというか、頼りにしないという考え方。本当に良いものを作って自分たちのファンになってもらえたらサービスを使ってもらえるようになる。特にウェブサービスとかはそうですよね。広告とかPRとかは金ばかりかかって効果がないということに気づかないと。有名な雑誌や新聞に取材してもらうことも否定していますが、折角ユーザーと直接結びつけるのがウェビサービスを提供する企業のメリットなんだから、そこにいちいち旧メディアや広告屋を介在させる必要はないですよね。またセールスマンを省きサポートも極力エンジニアが行うことで顧客の要望が直に作り手のところに伝わる(とはいえ本書では逆に顧客の要望には応えすぎるなとも書かれてはいます。その辺は買って読んでみてください)。

シンプルに、極力自分たちで会社を動かそうとすることで、大企業が抱えるいろんな問題が回避できるというのがこの本のエッセンスでしょう。Railsはお触り程度のことしかやってないですが、CakePHP(RailsのPHP移植版)越しにそのすさまじさというかすごさは実感しています。こういうすごいフレームワークがあるいまは、本書で掲げられていることは単なる理想や夢物語ではなく十分実行可能なものであると感じます。自分たちだけでなにかをやることが十分に可能。

とにかくなにかつくってみよう、と思わせられる本でした。Ruby on Railsの勉強を本格的に始めてみたいと思います。

| @技術/プログラミング

CakePHP、ちょこっと使ってみるだけのつもりだったんだけど、結構深くつきあってしまった。三つほどCakePHPでサイトつくりました。一つは社内用のウェブアプリケーションで、一つはまだ正式リリース前のものだけど、最後の一個はページビュー5000/日くらいあるサイトで実際に動いてます。ついこの前まで無職だったのに。スゲー。

PHPで素人がつくったサイトは危ないみたいな記事がこの前(というか定期的に)はてブでホッテントリに入ってた(る)けど、セキュリティのこととか分からない初心者こそCakePHPとかでサイトつくった方が楽だし安全だと思った。難しいことはフレームワークがやってくれるので。Bakeすればものの数分でウェブアプリケーションが出来てしまう。もちろんどんなフレームワークにも脆弱性がないわけじゃないだろうから100%安心というわけじゃないけど、少なくとも素人が自分でなんかやるよりも安全だと感じる。

とはいえ、フレームワークで万事オッケーなわけでもなかったりする。ちょこちょこっとカスタマイズするみたいのがフレームワークは難しい。特にCakePHPは規約がすごく重視されるから、データベースへのクエリでちょっと変わったことしようとすると結構難しくなる。というかはまる。サイト内検索をつくろうとして結構苦労した。土台が出来上がるまでは速いんだけど、そこからブラッシュアップさせていくときに結構停滞してしまう。それでも自分で一からつくるよりはかなり迅速に作れるんだけど、規約に縛られるのが窮屈に感じることもないではないですね。

で、タイトルの件なんだけど、真面目にエロサイトを作ってみた【プログラマ編】|ASTRODEO という記事がおもしろかった。はてブで1200以上ブックマークされますが1ゲットは僕です。すごいでしょ。いや僕は全然すごくないですね。書いてある内容がすごい。

確かにエロとかスクレイピングとかまぁきわどい内容ではありますが、僕はCakePHPでこんだけのことをやったということに素直に驚いた。

例えばCakePHPには hasAndBelongsToMany というのがある。ブログ記事があったとして、これが一つのカテゴリーを持つ場合は、 Post テーブルと Category テーブルを結びつけてやるだけでOKなんだけど( Post は一つの Category に所属し、 Category は複数の Post を持つ)、 Tag のような複数持てるし複数に所属する概念のモデルが存在する場合、 hasAndBelongsToMany じゃないとデータの整合性というか組み合わせをきちんと保つことが出来ない。

で、自分はこういうのの組み合わせは手が空いてる人に頼んで人力でやってもらったんだけど、このエロサイトの場合は、動画と動画の関連性の判定をプログラムにやらせてる。150件そこそこのデータの整合性を保つのも大変なのに、10000件とかそれ以上のデータを、しかも自動処理で関連づけるってまじすげーと思った次第です。

エロコンテンツなのに年齢確認がないとか著作権がらみの問題とかスクレイピングでよそのサイトに負荷かけるとかいろいろあるけど、僕は率直にこういうサイトをつくったのはスゲーなと思いました。こんなことまで出来るんだー、っていう素直な驚き。読んでて楽しかったしわくわくした。

今後もCakePHPを使い続ける分からんけど、自分もなんかおもしろいもんつくってみたいなーってすごく触発されました。

蛇足

はてブのコメント欄に「技術的には大したことない」みたいなコメント書いてる人が何人かいるけど、ほんとに大したことないんですかね。データベースを保存用と参照用で分けたり、スクレイピングしてきたデータの保存処理とか結構難しいと思うんだけど。これをすごいって感じるのはピヨピヨプログラマーだけなのかな?

| @技術/プログラミング

はてなダイアリーとかはカテゴリーごとにフィードを生成してて便利だと思ったので真似してみました。たとえば category.php?k=映画 にアクセスしたら、映画のフィードだけにアクセスできる。もう金輪際、僕のチラシの裏的雑記で精神的苦痛を被ることはありません! =-o 読みたいカテゴリーのフィードを選択して時間を有効活用してください。

| @技術/プログラミング

P_BLOGをわさわさいじって、Tagを付けられるようにしました。いや正確には前からTag付けられるようになってたんだけど、P_BLOGのTagは「CategoryをTagっぽく使う」っていうコンセプトなので、WordPressとか他のブログツールのTagの概念とちょっと違った。もともとP_BLOGにはTagはなくて、SafariStandのhetimaさんのハックを取り入れてCategoryをTag代わりに使えるようになっていたわけでした。

Tagはいっぱい付けといた方がいいとは思うんだけど、いままでTagをいっぱい付けまくったので数が260個ちかくになってしまって、こうなると逆に目当ての情報にたどり着くのが難しくなった。そういうわけでTagとは別にCategoryによって記事を大まかに分類しておくと便利だなーと思って、ちょちょっといじってみました。

データベースの `p_blog_log` テーブルのこれまでTagとして使っていた `category` フィールドを `tag` という名前にしてしまい、新たに `category` フィールドを作ってphpMyAdminでテキトーに記事にカテゴリーを割り振りました。その後P_BLOG本体のカテゴリーにまつわる部分をごにょごにょと改造して、TagとCategoryの機能を明確に分けました。要するにコピペして変数名や関数名を書き換えただけなんですけどね。

P_BLOGの後継プロジェクトのLoggix含め世の中には優れたブログツールが沢山ありますが、「自分で欲しい機能をどんどん拡張できる」のはオレオレ仕様のこのP_BLOGだけなわけでして、もう開発は終了していますがオレオレ仕様でどんどん進化して行っております :-) なんかもう主客転倒で、P_BLOGをいじる片手間でブログ書いてるような感じです :-P