やらなイカ?

たぶん、iOS/Androidアプリの開発・テスト関係。

Realm Tech Talk with JP Simard 1 に行ってきました #realm_jp

iOS/Androidで使用できるDBMS(+ORM)であるRealmのイベント、Realm Tech Talk with JP Simard #1(於 freee株式会社さん)に行ってきました。

Tech Talk with JP Simard from Realm

Realmのメンバー、JP SimardさんによるRealmの紹介。

Realmの特徴

  • オープンソース(ASL 2.0)である。なお、現時点でDBのCore部分はまだクローズドだが、オープンにする方向で進めている。
  • iOS/Androidで同じように使用できる。リリースタイミングのずれはあるが*1、双方、同じ機能を提供する。

既存DBMS(およびORM)との比較

  • iOSのCore DataはSQLiteのORM(Object Relational Mapper)で、古く、遅い。学習コストも高い。
  • SQLiteは早いが、ORMでなくSQLクエリで操作する必要がある。スレッドセーフでない。
  • ほか、FMDB(SQLiteのラッパー)などもあるが、総じて遅い。またAndroid向けには選択肢が少ない。
  • ベンチマーク
    • 単純なinsertは、生のSQLiteが早い(178k件/sec)が、Realmはそれに次ぐ(94k件/sec)。FMDB(47k件/sec)、Core Data(18k件/sec)
    • レコード数カウントは、Realm(30.9回/sec)、SQLite(13.6回/sec)、Core Data(1.0回/sec)。なお、数値はDBに200kレコード入っている状態のクエリ実行回数
    • 抽出クエリは、Realm(31回/sec)、SQLite(14回/sec)、Core Data(2回/sec)

モデルの定義

RLMObjectを継承したValue Objectを定義する。

@interface Employee : RLMObject
@property NSString *name;
@property float salary;
@end

RLM_ARRAY_TYPE(Employee)

@interface Company : RLMObject
@property NSString *name;
@property RLMArray<Employee> *employees
@end

これで、Employeeテーブルと、Employeeの配列(内部的にはrelation)を持ったCompanyテーブルができる。Swiftではデフォルト値の定義も可能。 (コードはその場でメモした擬似コードなので注意)

使いかた

Add(insert)はこんな感じで可能。

let employees = List<Employee>()
let company = Company()

Realm.write{     //transaction
    defaultRealm.add(company);
}

GCDから使う場合

dispatch_async(queue){
    realm.beginTransaction()
    ...
    realm.commitWriteTransaction()
}

(※コードはイメージです)

抽出クエリは、#filter()をチェインしていく形式で記述。

マルチスレッドでRealmを使っても、ちゃんと捌いてくれる。ただし、クエリで取り出したインスタンスはそのスレッドでしか使用できない。別スレッドでは再取得する必要があるので注意。

Notifications

例えばinsertされたタイミングで指定メソッドの呼び出しを登録できる。何がinsertされたかは(今は)わからない。

注意点

  • NSDataは、秒単位までしか保持されない。これはAndroidとの整合性のため。ミリ秒以上の精度はNSTimeintervalを使う。
  • KVOは未サポート

Work In Progress

  • multi process
  • fine-grain notifications(Notificationで操作されたオブジェクトも通知できる)
  • async queries
  • cascading deletes(リレーションのレコードを連鎖で削除する)
  • nullable types(現状はNullを入れられない)
  • sync
  • open source core

質疑応答

理解できたものだけ。

  • Realmのファイルは、iOS/Androidで共通フォーマットなのでファイルコピーで共有できる
  • desktop appで、Realm Browserというのがある。CUIツールは無い
  • coreは、TightDB(旧社名?)
  • in memoryで利用するには、begin transactionのとき指定できる
  • arrayのcountをクエリで取ることはできない(カウントを格納するプロパティを設けるなどのwork around)

realm-javaを使ってみての発表

Chatwork 宮下さんの発表。ChatworkのAndroid版で実際に使用したお話。

Android のORMはそもそも選択肢が少ない。

  • greenDAO: 早いけど準備が面倒
  • ActiveAndroid: insertが遅い(Chatworkさんの事例での話で、大量にinsertが発生すると厳しい)
    • Benchmark: 619件の処理(insert?)で、ActiveAndroidでは1551ms、Realmは414ms。

realm-javaでのモデル定義例

class xxx extends RealmObject{
    @primaryKey private long id;
}
  • RealmObjectはvalue objectでなくてはならず、ロジックは持てない。toString(), equals()とかもオーバーライドできない。
  • Realmのobjectは、スレッド単位でしか利用できない。別スレッドで扱うならqueryしなおす
  • 日本語ドキュメントのバージョンは0.72、最新は0.79.1。かなり変更があるので、最新情報にあたるほうがいい。
  • ButterKnifeと干渉するところがあったが、Gradleの定義で回避できた

所感

iOS/Androidで共用できるシリアライズ機構としては、Dropboxが公開しているmx3も気になっているのですが、こちらはライブラリでなく実装サンプルであり、ORMも含めて考えるとRealmの有望さを感じました。

モデルがvalue objectに限定されることは不便に思いますが、ロジック付きのラッパーを作ればいいので致命的ではなさそう。

最近、DBMSを使う系のアプリを作っていないのですが、止まっている電エースアプリAndroid版ででも使ってみたい。

懇親会では、freeeさんの会社およびプロダクト*2の話をたくさん聞けて、それもまた色々参考になりました。

freeeさん、岸川さん、通訳を買って出てくださった北さん、そしてJPさん、ありがとうございました。

*1:iOSがやや先行するみたい

*2:クラウド会計をユーザとして使いたいと思っていたので