| @雑談

思うに、若いときは一番給料低くて、お金ないから、暮らせてたら節約する必要ない、どうせ今の若い人とか30歳までに死ぬから、それまでに貯金しても仕方ない、万が一長生きしても、相応に技術が高まってれば収入も上がるはずだから、健康を維持できれば取り返せる、ので、僕は今は特に貯金しようといった考えない。今けっこう本買って勉強したり書いてるコードも悪くないと思ってるから、これで若いときに貯金してなくてお金なくなって死ぬようなら理不尽だと思う。ハードモードすぎる。変に無理して節約しようとして精神が異常になるほうが損だと思う。

健康 - hitode909の日記

ヒトデさんの言うことは正しい。能力の高い人は高価な技術書を買って自己投資して将来荒稼ぎできるので週五日タクシーで山奥まで行ったり高級Tシャツ買ったりしても大丈夫だと思う。

残念ながら普通の人はそうはいかない。普通の人は将来自分が荒稼ぎできる自信がないので若い頃からちまちまお金を貯めるしかない。普通の人は無理して節約せず浪費したときの方が不安が高まって精神に異常を来してしまう。

僕は会社の若者に蓄財を説いたことがあるけど、この若者は有能だから僕のアドバイスは間違っていたかもしれないと思った。世の中には金を貯める必要がある人と貯める必要がない人の二通りがいる。

| @労働

RubyKaigi 、2010 年のに行ってすごく感化されて 2011 年も 2012 年の Sapporo も行きたかったけど結婚するといろいろあってそういうのは無理だった。当然のように今年も無理だった。恐らく自分は終生 RubyKaigi には行けないのだと思う。ああいうプログラミングのイベントに熱心に参加したり運営の方に回ったりする人は本当にすごいと思う。みんなそれぞれ家庭とか奨学金の返済とか住宅ローンとかあるんだろうけど、時間をやりくりしてコミュニティ活動を行っている。

受託の会社にいた頃、技術とかどうでも良くて言われたとおり作って金がもらえるならそれでいい、というような情熱がない感じの人だらけの職場がとても嫌だった。しかしいま自分が彼らのようになりつつあるように感じる。悪い感じにサラリーマン化している。このままでは新卒とか有能な若者にあっという間に追い越されて老いさらばえていくだけだと思う。それは分かっているけど 30 歳くらいになるといろいろ厳しい。

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

一月くらい前から Lokka の master ブランチを自分のブログ用のブランチに merge してサイトをデプロイすると謎の白画面が出るようになっていて困っていた。現象は極めて謎で、ローカルの開発環境(RACK_ENV='development')では見られず、本番(RACK_ENV='production')だけで発生した。HTTP ステータスコードは 1054 が返ってきたりする。なんか変な gem でも入れてしまったかなと休みの日に動作検証したりしていたんだけどついぞ分からなかった。

SQL 弱者なので気がついてなかったんだけど、2月15日の commit で Site モデルに新しいフィールドが追加されていた(Add default markup in admin/site/edit · 2243dc5 · lokka/lokka ※この機能便利すね)。なので bundle exec rake db:migrate しないといけなかったわけだった。ローカルで動いている開発環境(データベースは SQLite)では Migration なんて行ってないんだけどエラーは出なかった。本番は MySQL で動いていて、こちらでだけエラーが出るようだった。

しかしいざ migrate しようとすると失敗する。

bundle exec rake db:migrate
Upgrading Database...
rake aborted!
Invalid default value for 'updated_at'

のようなエラーが出る。updated_at のデフォルト値がおかしいらしい。このときのテーブルの構造を見てみると以下のような感じだった。

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   |     | 0000-00-00 00:00:00 |                             |
| updated_at      | timestamp    | NO   |     | CURRENT_TIMESTAMP   | on update CURRENT_TIMESTAMP |
| frozen_tag_list | text         | YES  |     | NULL                |                             |
| markup          | varchar(255) | YES  |     | NULL                |                             |
+-----------------+--------------+------+-----+---------------------+-----------------------------+

調べてみたところ MySQL の Mode が NO_ZERO_DATE になっている場合、MySQL は timestamp 型のフィールドのデフォルト値に 0000-00-00 00:00:00 みたいな値を設定することを許さないらしい。 mysql - Invalid default value for 'create_date' timestamp field - Stack Overflow

検証用に別にテーブルを用意して bundle exec rake db:setup してみたところ、以下のような構造のテーブルができた。

mysql> desc entries;
+-----------------+------------------+------+-----+---------+----------------+
| Field           | Type             | Null | Key | Default | Extra          |
+-----------------+------------------+------+-----+---------+----------------+
| id              | int(10) unsigned | 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    |                |
| markup          | varchar(255)     | YES  |     | NULL    |                |
| type            | varchar(50)      | NO   |     | NULL    |                |
| draft           | tinyint(1)       | YES  |     | 0       |                |
| created_at      | datetime         | YES  |     | NULL    |                |
| updated_at      | datetime         | YES  |     | NULL    |                |
| frozen_tag_list | text             | YES  |     | NULL    |                |
+-----------------+------------------+------+-----+---------+----------------+

created_atupdated_atdatetime 型になるらしい。なので以下のような ALTER 文を実行した。

mysql> alter table entries modify column created_at datetime, modify column updated_at datetime;
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      | datetime     | YES  |     | NULL    |                |
| updated_at      | datetime     | YES  |     | NULL    |                |
| frozen_tag_list | text         | YES  |     | NULL    |                |
| markup          | varchar(255) | YES  |     | NULL    |                |
+-----------------+--------------+------+-----+---------+----------------+

これで最新のコードをデプロイしても真っ白画面になることはなくなった。以前遭遇した更新時に created_at の値が更新されてしまう問題 もフィールドの型が timestamp だったのが原因なのだと思う。SQLite から MySQL への移行は一筋縄では行かないことが分かった。

DataMapper はソースコード内の記述内容から動的に Migration を行えるけど、ActiveRecord みたいに $APP_ROOT/db/ ディレクトリに Migration ファイルを作ってくれたりしないので DB スキーマの変更が必要なことに気がつきにくい。便利だけど不便な感じがする。Rails で $APP_ROOT/db/ 以下にアホみたいにファイルが出来ていくの嫌だと思っていたけど、スキーマ変更に気がつかずコードをデプロイしてウェブアプリケーション停止みたいな自体は防げると思った。

ブログ書こうと思ってパソコン開いて「ついでに最新版の変更を取り込むか」とかやるとデプロイできなくなったりして書きたかった記事が書けず残念な感じになる。はてなブログでブログ書いてて画面が真っ白になったらひとでくんさんに不具合報告して直してもらえば良いので楽だと思う。

| @散財

一昨年、会社を変わったときに Happy Hacking Keyboard Professional 2 を買った んだけど、貧乏性のためなかなか会社に持っていって使うという気にならず、会社では3年前に買った HHK Lite2 を使い、Pro の方は家で使っていた。

しかしよくよく考えると家でコードを書く時間よりも会社でコードを書く時間の方が圧倒的に長いわけで、一番長くコードを書く時間を一番良いキーボードととともに過ごした方がよいのではないかと考えを改めて HHK Pro を会社で使うことにした。

連休明けの火曜から HHK Pro でコードを書いていて一週間が終わったところだけど、会社で毎日8時間以上使うことで初めて良さが分かったような気がする。Lite に比べてしっかりしている。Lite はカチャカチャとうるさいけど Pro は激しくキーを叩いても静かだ。それなのに押したときの反発は Lite の方が重く、Pro の方が軽い。Lite はカチャカチャしていておもちゃのようで、音を聞くだけで疲れる。

キー配列に関しても、HHK Pro はただの US 配列とは異なっていて、チルダキーの位置や Control キーの位置が一般的な US 配列よりも利用しやすい位置に置いてある。正直プログラミングしやすい。

HHK Pro を使うことで困ることと言ったら、それ以外のキーボードを利用したくなくなることだと思う。家でも職場でも HHK Pro が使いたくなる。自分の場合は HHK Pro を二つも買えるような財力はないので、そもそも HHK Pro を買ってしまったのが失敗だったのかも知れない。毎日 Amazon を開いてため息をつきながら HHK Pro をカートに入れたり戻したりしている。

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

Lokka で Syntax Highlight するプラグイン(morygonzalez/lokka-pygmentize · GitHub)、これまで Ajax で Syntax Highlight させてたんだけど、HTTP リクエストが増えていけてないと感じたのでサーバーサイドでハイライトが完結するように変更した。Railscasts の #272 Markdown with Redcarpet - RailsCasts を参考にして、プラグインの中で Entry クラスを再オープンした。こんな感じ。

class Entry
  def body
    doc  = Nokogiri::HTML(self.long_body)
    doc.search("//pre").each do |pre|
      code = pre.css("code")[0]
      pre.replace Pygments.highlight(
        code.text.rstrip,
        :lexer   => code[:class],
        :options => { :encoding => 'utf-8' }
      )
    end
    doc.to_s
  end
end

前の実装はだいぶいけてなかったと思うので随分マシになったと思う。あと この Pull Request でレンダリングエンジンに Redcarpet が追加されたので、GitHub と同じように

```ruby

```

みたいな感じの書き方でコードがハイライトされるようになった。便利。

追記1

ちゃんと動いてなかった…。夜直します…

追記2 2013/02/04 0:45

最終的にオープンした Entry クラスのコードは以下のようになった。

class Entry
  alias_method :original_long_body, :body
  def highlighted_long_body
    syntax_highlight(self.original_long_body)
  end
  alias_method :body, :highlighted_long_body

  alias_method :original_short_body, :short_body
  def highlighted_short_body
    syntax_highlight(self.original_short_body)
  end
  alias_method :short_body, :highlighted_short_body

  def syntax_highlight(body)
    doc = Nokogiri::HTML(body)
    doc.search("//pre").each do |pre|
      code  = pre.css("code")[0]
      lexer = if pre[:class].present?
                pre[:class]
              elsif code.present? && code[:class].present?
                code[:class]
              else
                nil
              end
      begin
        pre.replace Pygments.highlight(
          code.text.rstrip,
          :lexer   => lexer,
          :options => { :encoding => 'utf-8' }
        ) if code
      rescue MentosError
        next
      end
    end
    doc.to_s
  end
end

Lokka、結構メタプログラミングが多くて、Entry クラスのインスタンスの body メソッドは単なるゲッターではなく、 index アクションのときと show アクションのときで別々にエイリアスが設定されていて、index アクションのときは Entry#short_body 、show アクションのときは Entry#long_body が呼ばれるようになっていた。アラウンドエイリアス使って力業で解決したけど他のプラグインが同じように振る舞ったら破滅を招きそうな気がする…。それにしても『メタプログラミング Ruby』読んでなかったらどうすればいいか皆目検討付かなかっただろうなー。

| @散財

指定暴力団清貧会会長なので2012年の消費活動を振り返ろうと思います。買って良かったものベスト3をご覧ください。

3位 無印良品の肌着

天然素材にこだわったぬくもりクルーネック長袖シャツ 紳士・M・杢カーキ

3年くらい前からヒートテックを着て冬を過ごしていた。しかしヒートテックは窮屈だしちくちくしていて着心地がよくなく、さらにすぐ伸びてだらだらになってしまうので正直微妙だと思っていた。今年は偶然無印良品で見かけたこの肌着が安くなっていたので試しに買ってみたら、大変暖かくて良かった。気に入ったのでもう一枚買って二枚でローテーションを組んでいる。ユニクロのヒートテックとの違いは、生地の厚みと柔らかさにある。ユニクロのヒートテックは生地が薄くて締め付けられる感覚があるけど、この無印良品の肌着は生地に厚みがあり、締め付けはゆるく、心地よく着られる。暖かさもヒートテックよりも暖かいと思う。氷点下の阿蘇でもこの肌着と厚手のラガーシャツとナイロンパーカーの三枚で外出できた。買ってよかったと思う。

2位 携帯ウォシュレット

痔瘻になって手術後とかシートン法の輪ゴムをつけてる間とか、肛門周辺が阿鼻叫喚になっているときはウォシュレットがないとつらい。自宅は古い賃貸住宅なのでウォシュレットがついてなくて、痔瘻になった後は半泣きになりながら血だらけの肛門を拭いていた。そんなときに伊藤直也さんのブログを読んで携帯ウォシュレットなるものの存在を知り、すぐさま注文した。最初は半信半疑だったんだけど、普通に使える。手で水が当たる部分を調整できる分、便器に備え付けてあるやつよりも便利かもしれない。水の強さ調節もできるし、満タン時は23秒間放水できる。ただ便器備え付けのやつと違って温水ではなく水しか出せないので冬場はつらい。でもこいつがなければ俺の肛門は崩壊してたと思う。買ってよかったと思う。

1位 ソニーの Bluetooth ヘッドホン

これは嫁さんに買ってもらった。Bluetooth なのがとてもすばらしい。ワイヤレスヘッドホン、初めて買ったけど想像以上に良かった。実は二年くらい前から Kleer という規格のヘッドホンを狙ってはいた。当時は Bluetooth は音質の劣化がひどく実用に耐えないという意見を目にすることが多かった。Kleer は Bluetooth の後継規格で、まだ普及がいまいちなため出力側に送信機をつけないといけなかった。TH-WR700 という TDK 製のを買おうかと思ったのだけど、せっかく無線のヘッドホンを導入するのに送信機を取り付けなければならないというのが気にくわなかった。Mac につないで使うのならそれでもよいかもだけど、外で iPhone で使うときにヘッドホンジャックに送信機をつけるなんてあり得ないと思った。 MDR-1RBT は Bluetooth の Version 3.0 という規格に対応していて、よく知らないんだけど音質がいいらしい。また無線接続時は再生される周波数の帯域が20Hz-20000Hzまで落ち込むらしいんだけど、Sony が開発したナントカという技術によって劣化した音質を頑張ってなかなかよいとこまで復元するらしい。どうしても Bluetooth の音質に不満がある場合は、付属のケーブルを使うことで兄弟製品の MDR-1R と同じ音質で再生できるらしい。これも良い。自分は高音難聴でどうせ8000Hz以上の音は聞こえないので自分にとっての可聴域はカバーされているし、音質面で MDR-1RBT には全く不満がない。音質重視のヘッドホンだけどマイクとかついていて、電話のヘッドセットとしても使えるし、充電が micro USB でできるのも良い。ヘッドホンがオーディオの世界に閉じこもるのやめてデジタルガジェットの方に歩み寄ってきた感がある。買ってよかったと思う。

以上、2012年買って良かったものベスト3でした。

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

一個前の記事で書いた「記事の更新時に 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 にも色々問題があるのでしょうけどね。