2014年 導入してよかったもの等
先日、"2014年買ってよかったもの" などというエントリ書ける人間たいしたもんだ、日々記録やアウトプットをしていてえらい、みたいな話をして、自分は思い出せないからまあいいかと思ったんだけど、それで終わらすと何も始まらず終わるので頑張って思い出しました。一応、WEB 系エンジニアのような仕事するにあたって導入してよかったもの等です。
空気のような存在になったもの
導入してあたりまえのように使われたものたち (ゆえに忘れていた)。
アプリケーションをつくる英語 (電子書籍版)
アプリケーションに関する英語について書かれているもので、英語っぽいものを書くのに役立ちました。読むじゃなく書く。クラスやメソッドなどの名前をつけるときや、英語でやりとりされているリポジトリにコミットするとか、そういうときに利用されています。これの PDF 版と辞書 (Dictionary.app) とを常に開いてあります。ローカルにデータあるとやっぱり速いし、外でちょっと調べたいときとかにオフラインで利用できると便利です。それからアプケーションで利用される英語、というコンテキストでまず探せるので、英語力ない者としてはありがたいです。
普通に使うようになったもの
IntelliJ IDEA
型がある言語で IDE つかうとはかどりそうという目論見から導入されました。不慣れなライブラリを使いはじめるときに、どういうインタフェース持ってるのかとか、どういう定義されてるのか見にいったりとかそういうときに便利です。クラス名とか package 変えるみたいな変更のときにリファクタリングと称して一括名前変更できるのが一番便利です (このためだけに起動する価値あり)。慣れてきたら普段使いのエディタで書いてしまうけど、天才ではないので本来ならばそのままツールの支援を得て書くべきだと思います。REPL がある環境だと、数行のコードの単位で試してフィードバックが得られるため、オッこれは Rails みたいにやってけるぞ、みたいになってエディタとコンソールで書いてくような習慣が抜けないです。
ちなみに Rails っぽく型のある言語導入してくのには Skinny Framework が良い気がします。オフィシャルに Skinny framework's concept is Scala on Rails
ですゆえ。モデルまわりのつかいごこちは驚きが少ない感じがあってよいです。静的型付言語、外からくる値に対して型をつけてくところがダルい印象なので、Skinny ORM (scalikejdbc) の TypeBinder とかにおもてなしを感じます。
意外と使わなかったもの
最近出てきたチャットツール各種
Slack とか。きちんとプロジェクトで利用しはじめたらまたちょっと違ったかもしれないけど、仲間内で使う分にはやっぱ IRC だね、みたいな感じで移行に至らない感じでした。チャンネルにいる人間の倍くらい IRC bot がいたり、ログが保存されて一応検索できる仕組みとか WEB インタフェースやら API があるなど IRC まわりの環境がそこそこ発達しているという背景もあったので、周辺のツールたちに嫌気がささない限りは IRC 使い続けそうな気がします。
peco
最初は嬉々として使ってたけど一度使う習慣なくなったら存在を忘れたうえに、もともと使ってた zaw も使わなくなってた。ちゃんと使ったら便利だと思います。シェルのヒストリ絞り込みで生きていく、みたいになっています。
感想
保守的。
エディタ から dayone
やりたいこと
- エディタで書いたテキストを Day One に追加したい
前提
- Mac
- ビム
- あんまりむずかしいことはわからない
今回の対応
エティタのプラグインとか、ラッパースクリプトさがしたりしたけど、エディタのバッファを dayone
コマンドにわたすのでいいか~ となりました。
:w !dayone new
(わ びっくりだよね ニュー と内的発話です。)
準備
- http://dayoneapp.com/tools/ から dayone-cli.pkg をダウンロードして
dayone
コマンドを使えるようにする (dayone
コマンドは位置情報などを付加しない点について留意する必要があります)
毎日のメモを一箇所にまとめたいのでオススメされていた Day One をつかいます
背景
毎日のメモをひとところにまとめたい。
要件
希望
- コンソールからの入力が可能であること
- オフラインで編集可能であること
- 人間が読める形式で保存されること
- エクスポート処理など特別な処理をしないでデータにアクセスできること
- 特殊なファイル形式でないこと(テキストファイルを希望)
その他
- お金を払ってもよい
Day One
オススメされていた。完璧な感じではないけど、いい感じな気はする。
気に入った:
- こぎれいな iPhone アプリがある
- CLI がある (http://dayoneapp.com/tools/)
howm
テキストエディタにプラグインする自分用 wiki っぽいメモ機能。
気に入った:
- エディタと相性がよい
- けっこう機能が充実している
- テキストフォーマット
気に入らない(または問題点):
その他:
データの同期については Dropbox などのサービスが存在しているため、テキストデータを扱うならさほど困難でないと考える(データを扱う単位によってはマージの難しさがある)。
- http://wadap.hatenablog.com/entry/20081026/1225019930
- https://sites.google.com/site/fudist/Home/qfixhowm/file-share
howm と似たような位置にあって、もっとシンプルな方式の ChangeLog メモという選択肢もみてみたが、これもモバイル端末との相性があまりよくない(MHODiA というアプリがある: https://itunes.apple.com/jp/app/id431691790)。
Evernote とそのクライアントたち
今 PostEver という iPhone アプリをつかっている(https://itunes.apple.com/jp/app/id422023962)。1日の入力を1つのノートにどんどん追記していく(日毎に1つのノートになる)。
PostEver のノートに Mac からの入力があいのりできるならそれでよかった(現状簡単にきれいにできない)。
気に入った:
雑感
観点としては以下について重点を置いていたように思われる:
- データをどこにどうやって置くか
- 複数の端末で同期可能な箇所にあること(プライベートでさえあれば手段は問わない)
- どのように見えるか
- 日毎にまとまっているのが好ましい
Evernote の1アカウントをもって一箇所とみなす、という雑な運用でもよかったかもしれないという迷いがある。見せかたの問題だったのかもしれない。
Dropbox について
サードパーティのクライアントを認証すると $HOME/Dropbox/アプリ
みたいなディレクトリを作られてつらい気持ちになるが、 落ち着いて $HOME/Dropbox/Apps
にリネームすればよさそう。Day One が Dropbox で同期されているディレクトリがわからなくなってしまうので、一旦終了させてから起動して、ディレクトリを教えてあげれば認識する。
iPhone アプリのほうは、どういう仕組みになっているかわからないが、とりあえず上記手順ののちインストールして同期設定を行った。
複数端末で同期するということについて
データの扱いについて、同時更新の問題があるため以下のような対応になるのかなと思う:
- データの単位について、
- 1端末から1ファイル(データ)単位で更新する
- 1更新で1ファイル(データ)を追加する
- ロックはあまり現実的でない
Day One では、1更新で1ファイルを追加し、編集の際は衝突した事実はのこるものの基本後勝ちというルールっぽい。同時更新すると以下のようにコンフリクトしたファイルがつくられる。
ls -1 ~/Dropbox/Apps/Day\ One/Journal.dayone/entries FF04BE2FE3304849B025ABAF87150748 (Watanabe Mayu's conflicted copy).doentry FF04BE2FE3304849B025ABAF87150748.doentry
もしコンフリクトした場合は https://dayone.zendesk.com/hc/communities/public/questions/200028729--Conflicted-copy-on-Dropbox-sm- の、ファイル消して作りなおす、というのがオフィシャルな回答っぽい。
ファイル名が UUID (version 4) のハイフン抜きにしたもので、中身の XML(plist) が適切であればクライアントが何であってもよさそうなので、別ファイルにしてあげてもよいかもしれない。
テキストのメタデータについて
テキストデータでメモ行為をしようとすると、メモ本文とは別に管理のためのメタデータをどこに持つか問題が常につきまとう気がしていて、今自分の認識では、本文にちかいところに決まったフォーマットで入っているほうがあつかいやすそうという感じです。ChangeLog 形式とか XML でメタデータ持つのがわかりやすくて処理しやすくてよさそう。
メタデータファイルとかインデックスファイルを別に持つというのはキャッシュ用途でなければ端末間の同期とかの都合でめんどくさそうという印象。
総括
そういうわけで、メモ行為について、しばらく Day One つかって生活してみます。
DbCharmer commit:b02576644d982f895365e796ba75b825f7104210 時点の README.rdoc のざっくり読み下し
"DbCharmer" は、シンプルでパワフルな ActiveRecord のプラグインです。ActiveRecord が複数のデータベースや複数のデータベースサーバで動作できるよう拡張します。
このライブラリが ActiveRecord に追加する主な機能は以下のとおり:
- AR model のコネクションをシンプルに管理 (switch_connection_to メソッド)
- AR model をデータベースを分割したコネクションに
- クエリをどこにむかわせるか簡単に選べる機能 (
Model.on_*
メソッド群) - 自動でマスタ・スレーブにクエリをむかわせる (参照はスレーブに、更新はマスタで)
- 複数のデータベースのマイグレーションをフレキシブルに
- 複数のシャーディング方法でシンプルなシャーディング機能を利用できる (value, range, mapping table)
詳細は、 http://dbcharmer.net を見てください。
導入
DbCharmer の導入には2つのアプローチがあります:
gem として導入するなら、Gemfile に以下を追加してください:
gem 'db-charmer', :require => 'db_charmer'
Rails のプラグインとして導入するなら以下のコマンドで:
./script/plugin install git://github.com/kovyrin/db-charmer.git
注意: DbCharmer を Rails じゃないプロジェクトで使うなら、コネクションを管理するメソッドを使う前に、DbCharmer.env
に適切な値を設定する必要があります。適切な値は、database.yml
のトップレベルのセクション名です。
簡単な ActiveRecord のコネクションの管理
このプラグインで追加される機能として switch_connection_to
というメソッドがありますが、これはいろんな種類の DB コネクションの指定を受け付け、モデルでその指定を使います。以下をサポートしています:
- 文字列とシンボル: database.yml にある接続設定のブロックを指定
- ActiveRecord のモデル (モデルに対してコネクションを設定する)
- デーテベースのコネクション (
Model.connection
) - nil: デフォルトのコネクションにリセットする
サンプルコード:
class Foo < ActiveRecord::Model; end Foo.switch_connection_to(:blah) Foo.switch_connection_to('foo') Foo.switch_connection_to(Bar) Foo.switch_connection_to(Baz.connection) Foo.switch_connection_to(nil)
サンプルの database.yml
の設定:
production: blah: adapter: mysql username: blah host: blah.local database: blah foo: adapter: mysql username: foo host: foo.local database: foo
switch_connection_to
メソッドは第二引数にオプション引数として should_exist = true
な引数をとります。このオプションは文字列またはシンボルを引数にメソッドが呼ばれたとき、そのコネクションの設定が database.yml
にあるかどうか見ます。この should_exist が true ならば、例外をあげるし、false ならばエラーは無視され、コネクションの変更は起きません。
これは、development モードやテストのときに、複数のデータベースをローカルに作りたくない、ひとつのデータベースに全部テーブルを作りたい、とかいうときにつかえます。
警告: 全てのコネクションのスイッチの呼び出しは、呼んだクラスだけでコネクションをスイッチします。switch_connection_to
の呼び出しと、コネクションのスイッチを継承元のクラスでやってはいけません (たとえば ActiveRecord::Base クラスのコネクションをスイッチすると、全てのモデルが新しいコネクションになってしまいます。そういうことがしたいときには、普通に establish_connection
を使いましょう)。
複数データベースのマイグレーション
複数のデータベースを使うアプリケーションでも、便利なスキーママイグレーションの仕組みが必要でしょう。
Rails ユーザのみなさんは既に Rails の migration という仕組みを持っています。DbCharmer でも、Rails の migration で可能なかぎりシームレスに複数データベースを扱えるようにしています。
複数のデータベースを操作するのに、以下の2つの方法が使えます:
- マイグレーションファイル全体でコネクションを変更する方法: マイグレーション全体を指定のデータベースにスイッチする
- ブロックでコネクションを変更する方法: マイグレーションの一部を指定のデータベースにスイッチする
マイグレーションファイルの例(全体でコネクションを変更する場合):
class MultiDbTest < ActiveRecord::Migration db_magic :connection => :second_db def self.up create_table :test_table, :force => true do |t| t.string :test_string t.timestamps end end def self.down drop_table :test_table end end
マイグレーションファイルの例(ブロックでコネクションを変更する場合):
class MultiDbTest < ActiveRecord::Migration def self.up on_db :second_db do create_table :test_table, :force => true do |t| t.string :test_string t.timestamps end end end def self.down on_db :second_db { drop_table :test_table } end end
マイグレーションファイルの例(全体でコネクションを変更し、同じテーブルの操作を複数コネクションに):
(注: :connection と :connections は、コネクションの配列を指定することができる)
class MultiDbTest < ActiveRecord::Migration db_magic :connections => [:second_db, :default] def self.up create_table :test_table, :force => true do |t| t.string :test_string t.timestamps end end def self.down drop_table :test_table end end
デフォルトのマイグレーションのコネクションについて
DbCharmer 1.6.10 以降では、ActiveRecord::Migration.db_magic
の呼び出しと、マイグレーションでのデフォルトのコネクションの設定(特定のコネクションの変更しない限りこれが使われる)ができるようになりました。マイグレーションでデフォルトの ActiveRecord のコネクションが使いたい場合は db_magic :connection => :default
を使ってください。
不正なコネクション名の扱いについて
どの環境でもデフォルトでは、on_db
と db_magic
の宣言は指定したコネクションが database.yml に存在しない場合失敗します。production 環境以外でひとつのデータベースを使うなどしているときに、こうなるのを無視させることができます(テストコード用のデータベースとかでとくに便利です)。
この振る舞いは、Rails の initializers で DbCharmer.connections_should_exist
の設定をすることでで制御できます。
警告: もしテスト環境でデータベースのコネクションを分けてマスタ・スレーブのサポートをしたいなら、transactional fixtures のサポートをオフにする必要があります。そうしないと、データを使ったテストでいろいろ問題に遭遇することになるでしょう。
モデルをマスタ・スレーブ環境で使う
マスタ・スレーブレプリケーションは、今日の中規模から大規模なデータベースアプリケーションでの、もっともポピュラーなスケールアウト手法です。いくつかの Rails プラグインが、モデルでスレーブサーバを使えるようにしていますが、それらは大きなアプリケーションで使った感じではあまりフレキシブルではありません。
ActsAsReadonlyable プラグインをしばらく使ってきましたが、たくさんの変更を加えながら使っていました。しかし、このプラグインが作者に放置されたので、我々はマスタ・スレーブのためのコードをプラグインにまとめリリースすることに決めました(Rails 2.2以降向け)。DbCharmer は、以下の機能を Rails のモデルに追加します:
全ての参照をスレーブ(たち)に自動スイッチ
モデルを作ったら、db_magic :slave => :blah
か db_magic :slaves => [ :foo, :bar ]
のコマンドをモデルで使うことができます。そうすることで、find, count, exist などの参照系の操作をスレーブ(または複数のスレーブなら、それらをラウンドロビン)に切り替えるモードになります。例は以下のとおり:
class Foo < ActiveRecord::Base db_magic :slave => :slave01 end class Bar < ActiveRecord::Base db_magic :slaves => [ :slave01, :slave02 ] end
デフォルトコネクション切り替え
もし、一組のマスタ・スレーブ(あるいは単純にひとつより多いデータベース)がある環境ならば、いくつかのモデルでデフォルトのコネクションを変更したいかもしれません。db_magic :connection => :foo
をモデルに書くことでそうすることができます。例:
class Foo < ActiveRecord::Base db_magic :connection => :foo end
マスタ・スレーブ構成 (つまりメインのコネクション + スレーブのコネクション) で分割されているモデルの例:
class Bar < ActiveRecord::Base db_magic :connection => :bar, :slave => :bar_slave end
クエリごとのコネクション管理
マスタで select のクエリを走らせたいというケースがあると思います。たとえば、ちょうどデータを追加して、それを読み出す必要があって、でもそれがスレーブに反映されたかどうかわからない、というようなときです。こういうようなときのために、設定する方法を ActiveRecord モデルに追加しています:
1) on_master
- これは block スタイルと proxy スタイルの2種類の書き方があります。
block スタイルでは、コードブロックのコネクションを強制的にスイッチさせることができます:
User.on_master do user = User.find_by_login('foo') user.update_attributes!(:activated => true) end
proxy スタイルは、あるクエリをマスタに向けることができます:
Comment.on_master.last(:limit => 5) User.on_master.find_by_activation_code(code) User.on_master.exists?(:login => login, :password => password)
2) on_slave
- これはマスタを強制的に使うようにしたあとなどに、強制的にスレーブに使うようにさせるメソッドです。スレーブが複数あれば、ランダムでひとつが選ばれます。このメソッドも block と proxy のスタイルがあります。
3) on_db(connection)
- これは前出の2つのメソッドを可能にするものです。これはモデルのコネクションを、コードのブロックや1つの文で、ある DB に切り替えるのに使います(2つの形式があります)。これは switch_connection_to
と同じ類の値を受け付けます。例:
Comment.on_db(:olap).count Post.on_db(:foo).find(:first)
development と test 環境のデフォルトでは、存在しないコネクションを on_db
の呼び出しを使うと、クエリはひとつのデータベースに全てのクエリを送ります。production の on_db
では、存在しない名前は受け付けません。
この振る舞いは、 DbCharmer.connections_should_exist
を Rails の初期化で設定することによって制御できます。
強制的なスレーブ参照
いくつかの場面で、デフォルトで、全ての参照がスレーブにむかうモードが使われるには重大すぎるモデルがありますが、それらをスレーブにむかわせるモードに切り替えたいと思うことがたまにあります。
たとえば、User
モデルがあるとします。ユーザは古いアカウント情報を見たくないので、スレーブ参照での遅延は避けたいです。しかしあるケースでは(たとえば、ログアウト状態でのプロフィールページの表示、などなど)、全ての参照をスレーブに向けるよう切り替えるというのは合理的です。
このユースケースのために、DbCharmer の 1.7.0 から、強制的にスレーブを参照する機能が追加されました。これは、いくつかの小さな別々の機能から成りますが、組み合わせによりパワフルなものになっています:
1) ActiveRecord の db_magic
メソッドの :force_slave_reads => false
オプション。
このオプションはモデルで自動でスレーブ参照するのを無効にします。なので、on_slave
あるいは、その他のスレーブ参照できるようにするメソッドを必要に応じて呼ぶ必要があります。例:
class User < ActiveRecord::Base db_magic :slave => slave01, :force_slave_reads => false end
2) ActionController の force_slave_reads
クラスメソッド。
このメソッドは、コントローラごと(引数なしで呼ばれたとき)、あるいは、アクションごと (:only
と :except
パラメータを渡して呼んだとき) 、強制的にスレーブを参照します。
これは、スレーブ参照によるラグがいくらか許容できるアクションで、スレーブが設定されているモデルの参照先をスレーブに向わせる、というようなときに使えます。例:
class ProfilesController < Application force_slave_reads :except => [ :login, :logout ] ... end
3) ActionController の force_slave_reads! というインスタンスメソッド、このメソッドで、アクション内、あるいは、コントローラのフィルタで、一時的に参照先を強制的にスレーブに向かわせられます。
このメソッドは同じアクションをログインしているユーザとログインしていないユーザに呼ばれるときに使えます。before_filter
でユーザ認証して、認証していないユーザ向けには force_slave_reads!
メソッドを呼びます。
class ProfilesController < Application before_filter do force_slave_reads! unless current_user end ... end
注意: このメソッドを使う前に、DbCharmer の ActionController サポートを有効にする必要があります。
DbCharmer.enable_controller_magic!
を、プロジェクトの初期化コードで呼ぶ必要があります。
4) DbCharmer.force_slave_reads
メソッドは、ブロック内のコードで強制的にスレーブ参照をするのに使われます。これは、とても細かい粒度でのスレーブ参照を強制する機能です。例:
DbCharmer.force_slave_reads do ... total_users = User.count ... end
注意: 今のところ、この機能はベータで、使う場合は注意が必要です。テストしているものの、現実世界のアプリケーションでは想定外の問題が起こる可能性があります。
関連のコネクションの管理
ActiveRecord モデルはそれぞれ互いに関連を持っていて、それぞれがデータベースのコネクションを持っているため、User.posts.count
のようなメソッドチェーンなんかで、コネクションの管理をするのが少し難しいです。 posts の count を別のデータベースでやりたいならば、あるひとつのクラスだけコネクションを変更して、以下の様にメソッドを呼びます:
Post.on_db(:olap) { User.posts.count }
これはあまり良い書き方ではないようなので、関連をうまく扱えるように on_*
メソッド群を準備しました。こんなかんじで使えます:
@user.posts.on_db(:olap).count @user.posts.on_slave.find(:title => 'Hello, world!')
注意: ActiveRecord の関連は、結果のオブジェクトあるいはコレクションのプロキシとして実装されているため、チェインしたメソッド以外もコネクションの切り替えを使えます:
@post.user.on_slave # post の author を返す @photo.owner.on_slave # photo の owner を返す
DbCharmer の 1.4 以降では、has_many と HABTM 関連のコネクション切り替えで prefix 記法を使えます:
@user.on_db(:foo).posts @user.on_slave.posts
named scope のサポート
DbCharmer ユーザの named scope でのコネクションの切り替えを簡単にするため、スコープでも on_*
メソッドをサポートするようにしました。
以下のスコープチェーンは全部やってることは同じです(クエリは :foo データベースコネクションで実行されます):
Post.on_db(:foo).published.with_comments.spam_marked.count Post.published.on_db(:foo).with_comments.spam_marked.count Post.published.with_comments.on_db(:foo).spam_marked.count Post.published.with_comments.spam_marked.on_db(:foo).count
関連のサポートもしているので、以下のようにも使えます:
@user.on_db(:archive).posts.published.all @user.posts.on_db(:olap).published.count @user.posts.published.on_db(:foo).first
一括したコネクションの管理
たくさんのテーブルを使ってコードを書きたい、そして、それらを別のデータベースを使うようにしたいというときがあります。
こんなふうにできます:
DbCharmer.with_remapped_databases(:logs => :big_logs_slave) { ... }
デフォルトが :logs
のどのモデル (たとえば db_charmer :connection => :logs
などと書いているモデル)も、このブロック内ではコネクションを :big_logs_slave
に変えます。
これは、他のどの DbCharmer のメソッドより優先度が低いです。なので、Model.on_db(:foo).find(...)
などは、指定されたデータベースを使いつづけ、そうでないものはリマップされます。
一度に、いくつでもリマップの指定をできます。また、DbCharmer でコネクションを指定していないどのモデルにマッチするデータベース名として :master
を使えます。
ノート: DbCharmer は モデルで alias_method_chain
を使って動いています。注意して、必要な箇所にだけパッチしています。
しかし、with_remapped_databases
とデフォルトのデータベース(:master
) のリマップを使いたいなら ActiveRecord::Base
の全てのサブクラスにパッチするしかありません。
これはひどい問題も、大きなパフォーマンスの影響もおこさないはずです(よくできてる)。
シンプルなシャーディングのサポート
DbCharmer の 1.6.0 から、ActiveRecord の拡張としてシンプルなデータベースシャーディングをサポートしています。
この機能は本番環境でもテストされているとはいえ、この機能の基本をちゃんと理解せずにアプリケーションで使うのはオススメしません。
現時点では4つのシャーディング方法をサポートしています:
1) "range" - とてもシンプルなシャーディング方法で、事前に定義したプライマリキーの範囲でテーブル分割を行い、その小さく分割したテーブルを別のデータベースやデータベースサーバに配置することができます。
こんなとき便利: 非常に大きいテーブルがだんだん大きくなっていくようなとき。テーブルをいくつかのサーバにのせることで複雑なシャーディングの仕組みなしでシンプルさを保ちたいとき。
2) "hash_map" - けっこうシンプルなシャーディング方法で、事前に定義しておいたいくつかのキーでテーブル分割を行います(プライマリキーでなくてよい)。
たとえば、どの州をどのデータベース(あるいはデータベースサーバ)に保存するか定義しておいてアメリカの住所のリストを州ごとにシャーディングするとかできます。
3) "db_block_map" - これはとても複雑なシャーディング方法で、テーブルを小さなブロックのセットに分けて、さらに、シャーディングしたデータベースなりデータベースサーバなりにそれを割り当てます。
ブロックを追加したいときはいつでも、ブロックは自動かつシャーディング間でバランスをとってデータベースに割り当てられます。
この方法は、1000万から10億レコードの巨大なテーブルをスケールするのに使え、比較的簡単にシャーディングしなおせる一番よい方法です。
4) "db_block_group_map" - これは "db_block_map" とよく似た方法で、一点だけが異なります。それは、この方法は
データベースのセット(テーブルのグループ)を各サーバに持てて、各グループがシャーディングとして扱われるところです。
このアプローチはアプリケーションをスケールするまえに事前にシャーディングしておくのに使えます。
ひとつのサーバから簡単にはじめられます。10, 20, 50 に分割したデータベースを持っておき、ひとつのマシンで対応できなくなったら、それらのデータベースを別のサーバに移します。
どうやってシャーディングしたらよいか?
シャーディングの拡張を有効にするには、すこし準備が必要です:
1) シャーディングのコネクションを定義した Rails のイニシャライザを作る (スクリプトやアプリケーションの初期化のときのコード)。それぞれのコネクションに名前と、シャーディング方法と、初期化のためのそのオプションを指定します。
2) シャーディングを使いたいモデルにシャーディングのコネクションを明示する
3) シャーディングしたいモデルを操作する前にシャーディングを明示する
より詳細は、以下のドキュメントをご覧ください。
シャーディング(分割)コネクション
シャーディングコネクションはシンプルな抽象化で、クラスタのためのシャーディングパラメータを一箇所で指定し、このひとところで設定したものをモデルで使えるようにすることができます。
いくつかのシャーディングのコネクションの初期化の例は以下のとおりです:
1) range ベースのシャーディングコネクションの例:
TEXTS_SHARDING_RANGES = { 0...100 => :shard1, 100..200 => :shard2, :default => :shard3 } DbCharmer::Sharding.register_connection( :name => :texts, :method => :range, :ranges => TEXTS_SHARDING_RANGES )
2) ハッシュマップのシャーディングコネクションの例:
SHARDING_MAP = { 'US' => :us_users, 'CA' => :ca_users, :default => :other_users } DbCharmer::Sharding.register_connection( :name => :users, :method => :hash_map, :map => SHARDING_MAP )
3) データベースブロックマップのシャーディングコネクションの例:
DbCharmer::Sharding.register_connection( :name => :social, :method => :db_block_map, :block_size => 10000, # ブロックごとのキーの数 :map_table => :event_shards_map, # シャーディングブロックをマップするテーブル :shards_table => :event_shards_info, # シャーディングコネクション情報のテーブル :connection => :social_shard_info # マップでどのコネクションを使うか )
シャーディングコネクションの定義をしたら、モデルでそれを使えるようになります:
class Text < ActiveRecord::Base db_magic :sharded => { :key => :id, :sharded_connection => :texts } end class Event < ActiveRecord::Base set_table_name :timeline_events db_magic :sharded => { :key => :to_uid, :sharded_connection => :social } end
シャーディングしたモデルでのコネクションの切り替えについて
シャーディングしたモデルを操作するとき、必要があればいつでも、どの分割先を使うか指定することができます。
シャーディングしていない環境での DbCharmer のつかいかたと似た方法で、クエリごとに接続を管理できるメソッドを用意しています:
Event.shard_for(10).find(:conditions => { :to_uid => 123 }, :limit => 5) Text.shard_for(123).find_by_id(123)
その他に、range と hash_map のシャーディングの方法で、デフォルトの分割先に切り替えることができるメソッドがあります:
Text.on_default_shard.create(:body => 'hello', :user_id => 123)
そして最後に、システム内の各シャーディングで、コードを実行するメソッドがあります(現在のところ、db_block_map と db_block_group_map でのみサポートされています):
Event.on_each_shard { |event| event.delete_all }
自分のシャーディング方法の定義
DbCharmer は、ユーザ定義のシャーディング方法が可能です。自分のシャーディング案を実装するには、いくつかやることがあります:
1) DbCharmer::Sharding::Method::YourOwnName
という名前をつけてクラスをつくる
2) 最低でも、コンストラクタ initialize(config)
と、判別するためのインスタンスメソッド shard_for_key(key)
、これは database.yml
ファイルか、rails connection アダプタのコネクションパラメータのハッシュからコネクション名を返すようなメソッドになるでしょう。
3) 以下のようにして、あなたのシャーディングコネクションを登録します:
DbCharmer::Sharding.register_connection( :name => :some_name, :method => :your_own_name, # あなたの定義したシャーディング方法を小文字にしたシンボルで渡します ... ほかにパラメータが必要ならそれも ... )
4) 他の標準のシャーディングコネクションと同様に、あなたの定義したシャーディングコネクションを使います
自分で定義したシャーディングで、デフォルトの分割先をサポートする方法
もし、on_default_shard
メソッドを自分の定義したシャーディングモデルで使いたいなら、2つやることがあります:
1) support_default_shard?
というインスタンスメソッドをシャーディングクラスに実装します。これは、デフォルト分割先の指定をサポートするなら true を、そうでないなら false を返します。
2) shard_for_key
メソッドで、:default
のシンボルをキーとしてサポートするよう実装します。
自分で定義したシャーディング方法で、シャーディング列挙をサポートするには
シャーディング列挙を自分で定義したシャーディングのモデルでサポートするには、shard_connections
というインスタンスメソッドを追加する必要があります。このメソッドは、シャーディングコネクション名か、コネクションの接続で使われる設定の配列を返す必要があります。
ドキュメントと質問について
このライブラリについてのよりくわしい情報については、われわれのサイト http://dbcharmer.net を参照してください。DbCharmer の内部の詳細について知りたいときは、ソースコードをチェックアウトしてください。プラグインのコードは、だいたい100%のカバレッジがあります。test-project ディレクトリに全てのユニットテストと、実際に使うときのテストが入っています。
このプロジェクトについて何か質問があるときは、作者が使っている DbCharmer ユーザーズグループのメーリングリストにコンタクトすることができます:
- グループ情報: http://groups.google.com/group/db-charmer
- このページを購読するか、db-charmer-subscribe@googlegroups.com までメールしてください
動作する Ruby と Rails について
この gem ライブラリは、いくつかの Ruby のバージョンと、Rails 2.3, 3.0, 3.1, 3.2 で CI しています。
CI は TravisCI.org (https://travis-ci.org/kovyrin/db-charmer) でまわしています。
ビルドステータスは https://travis-ci.org/kovyrin/db-charmer を見てください(原文では現在のステータスについてのバッジみたいな画像が表示されています)
今、以下の組み合わせでビルドしています:
くわえて、この gem は Scribd.com の本番でも使われています (世界で最も大規模な Rails で作られたサイトのひとつです)。 REE + Rails 2.2, 2.3 あるいは Sinatra と Rack アプリケーションで使われています。
1.8.0 から、3.2.8 に対応しましたが、3.2.4 はオフィシャルにサポートしてないので注意してください。たぶん動くと思いますが、対応していないバージョンについてバグレポートはうけつけません。
作者について
このプラグインは Scribd.com 社内で使うために作られ、さらにそれ以外のみなさんに使ってもらうために公開されました。コードのほとんどは Oleksiy Kovyrin によって書かれ、MIT ライセンスで公開されています。詳細については LICENSE ファイルを参照してください。
その他のコントリビュータは以下のとおりです(アルファベット順):
- Allen Madsen
- Andrew Geweke
- Ashley Martens
- Cauê Guerra
- David Dai
- Dmytro Shteflyuk
- Eric Lindvall
- Eugene Pimenov
- Jonathan Viney
- Gregory Man
- Michael Birk
- Tyler McMullen
付記
- 原文は https://github.com/kovyrin/db-charmer/blob/73b72bf1aeb9e7f04bf982830050de861e4f291c/README.rdoc です
- 直訳できずにバッサリいっているため解釈が誤っている箇所がたくさんあると思います(指摘してくれる親切なかたがいたらうれしいです)
- Sharding まわりがとくにあやしい
- 明日は Octopus の README 読む予定
Rails のパンくずリストのオススメを教えてください
背景
パンくずリストというのを用意してみたところ、センスがなく、これは自前でやるものでなくてライブラリでやったほうがいいと思いました。
要件
つかいやすく、見た目があまりダサくないく、かつ、つくりがあまりダサくない、というものがよいです。
自分が見付けられたもの
ruby-toolbox.com でさらっと見てみたところ、以下の5つがよさそうかな、と思いました。
- Breadcrumbs On Rails
- Crummy
- Breadcrumble
- Loaf
- Gretel
Breadcrumbs On Rails
定番のようで、一番人気っぽい。コントローラでリンク名とパスを配列に詰めてゆき、ビューでそれを表示するタイプ
- ActionController::Base#add_breadcrumb にリンク名とパスを渡しリストを作る。同名のクラスメソッドがあり、before_filter を使いマクロ的に定義する機能を提供する
- 表示のためのヘルパを定義しており、パンくずリストのセパレータ(» がデフォルト)や、span やら li などのタグ指定ができたりする
- 幾種類かのリンク名やパスの指定が可能であり、シンボルや Proc オブジェクトをわたせばコントローラのインスタンスのコンテキストで評価される
Crummy
Breadcrumbs On Rails とアプローチは同じで作りもだいたい同じ。マクロ的に before_filter を宣言するクラスメソッドのつくりがちょっと違う。
- ActionController::Base#add_crumb にリンク名とパスを渡しリストをつくる。ActionController::Base.add_crumb がインスタンスのコンテキストを手にいれるのがすこしへたくそな印象
- 表示のためのヘルパは、表示用のクラス(Crummy::StandardRenderer というレンダラ)に処理させる方式で、will_paginate っぽい
Breadcrumble
シンプルな Breadcrumbs On Rails。日本の方が作ってる様子。
- ActionController::Base#add_breadcrumb で(以下略)。マクロ的クラスメソッドがシンプルすぎるかもしれない。collection な URL の named_path の指定はできたい気もする
- 表示のためのヘルパは、表示用のパーシャルを使う方式で、kaminari っぽい。今はできないが、kaminari みたいに theme オプションを受け付けたりできそう
Gretel
config/initializers 以下に Ruby のファイルを置く設定ファイル方式。
- config/initializers/breadcrumbs.rb に、パンくずリストのテキストとリンクを名前をつけて設定していく。設定は parent の設定を指定することが可能で、これで階層を表現する。
- 表示のためのヘルパに、設定ファイルでつけた名前で設定を呼ぶ(
<% breadcrumb :issue, @issue %>
のように。設定では表示するリンクのリソースを指定することが可能) - 標準ではヘルパが content_tag などのメソッドで HTML を生成するが、リストにアクセスするメソッドがあるので、オプション指定でどうにもならないときは ERB などで表示の変更が可能
結論
Gretel が一番よいかなという気がする。パンくずリストの表示という、あまりメインの処理と関係ない(関係ないことはないが)処理のことを考えなくてすむのはありがたい。
なんとなく予想してたけど、Gretel ではわりと view で表示を制御する形になるので(どうあるべきか、は判断しかねる)同じ view をつかいまわすような画面が多いとあつかいづらいかもしれない(helper でラップすればよさそうではある)。また、コントローラでパンくずリストについてあまり意識しなくて済むとはいえ、全く意識しなくていいわけではない。とはいえコントローラの before_filter でなんかいろいろつめてくのもどうなんだろうといつも思うので Gretel でしばらく生きていきます。
Gretel で不都合があれば Breadcrumbs On Rails か Breadcrumble を使う、としたい。
何かオススメがあったら誰かおしえてください。
Evernote をコンソールから扱いたい
背景
Evernote がすごい便利な気がしてきたので活用したいと思いました。
結論
Ruby で書かれている evernote-editor というのが良さそうだった。
良さそうと思ったけど Evernote からとってきてエディタで読み込んだときにデータ構造がちゃんと markdown にできてない気がする…(あとで確認する)。 → 最初から markdown で作ったノートなら大丈夫そうだが、そうでないノートだとデータがこわれる(保存しなくても markdown にパースしてそれを保存しようとするため)。
evernote-editor の使いかた
Rubygems にあるので、gem つかえる環境ならば以下で導入できる。
gem install evernote-editor
すると、evned
というコマンドが追加される。
title という名前のノートを作りたいときは以下のようにする。
evned title
初回起動時は、developer token と編集に使いたいエディタを尋ねられる。
- developer token については https://www.evernote.com/api/DeveloperToken.action からとってくる
- エディタについては
which $EDITOR
したものがデフォルトで使われる - 設定は ~/.evned に YAML 形式で書き込まれる
編集するときは -e
オプションをつける。ノートの候補が複数ある場合は、いくつか候補があるため選択せよといったプロンプトがでるので、自分が編集したいものを選ぶ。
evned -e title
タグをつけるとか Evernote のサンドボックス環境で実行するとかのオプションがある(README 見たらすぐわかる)。
その他の選択肢
他に探した感じでは、 Evernote をコンソールから(Vim から)扱う方法は以下の2つの選択肢があった。
前者の evervim はエディタ(Vim)に Evernote にポストする機能を付加するもので、+python で vim をコンパイルする必要がある。自分が Emacs を使っているならばこのようなアプローチでもかまわないと思う可能性があるが、自分としては、エディタにはテキスト編集以外の機能を盛り込みたくないので今回はパスした。タイトルとかタグとか全部含めてエディタの中で書けるのは良いなと思った。
後者の geeknote は、python で書かれた Evernote クライアントで、テキスト編集部分を任意のエディタで編集することができる。いままではこれを使っていたが、新規ノートを作るときにエディタが使えず微妙に不便だった。ドキュメントをちゃんと読んでいなくて見つけられなかったのかもしれない。ぱっとみの印象では、インタラクティブにコマンドを実行するというより、バッチスタイルで使うのに便利なインタフェースに見えた。
ちなみに Windows 環境では以下が使えるようだった(未確認)。
find_by!
欲しい。
以下のようなイメージ。Rails 4 の all とか take の雰囲気わかってないのでイメージ。
module MyFinderMethods def find_by(*args) where(*args).first end def find_by!(*args) where(*args).first! end end class ActiveRecord::Relation include MyFinderMethods end class ActiveRecord::Base class << self delegate :find_by, :find_by!, to: :scoped end end
find_by どうでもいいけど find_by! 欲しい。