Realmは、SQLiteやCoreDataから置き換わるモバイルデータベースです。

Eight AndroidアプリでのRealm導入事例

Eight AndroidアプリでのRealm導入事例

山本純平さん @ Sansan株式会社

Sansan株式会社のAndroidエンジニアである山本純平さんによる、Android版のEightにRealmを導入した際の知見について話していただきました。

永続化されないプロパティのオーバーライドを利用して、擬似的にRealmオブジェクトにポリモーフィックな振る舞いを持たせる工夫や、データのデバッグに便利なstetho-realmなどのツール、JVM上でのテストを可能にするPowerMockの活用について詳しく解説されています。

実際のプロダクトにおける開発の話なので、非常に実践的な内容となっています。Realmの導入、およびRealm使った開発を進めるにあたって、参考にしてください。


Eight、Sansan株式会社の紹介

名刺管理ツールです。スマートフォンで撮影した名刺データをクラウドソーシングを活用して、手入力によりデータ化します。最近のアップデートにより、名刺管理だけでなくビジネスネットワーキングツールとしての機能を備えるようになり、フィードの投稿や、自分に関連する会社のニュースの閲覧などができるようになりました。

Sansan株式会社では、技術顧問として、まつもとゆきひろ氏、堤修一氏、山﨑誠氏、あんざいゆき氏、岸川克己氏に協力していただいています。
Slackによるサポートや、GitHub上でのコードレビューなどを受けることができます。
さらに、山﨑誠氏、あんざいゆき氏にはAndroidに関するレクチャーを月2回お願いして実施しています。
内容は、「Lintの警告とその対処方法」「Master of Fragment」「いかにViewがレイアウトされるか」「Retrofit + RxJavaハンズオン」「BLEの実装について」などがあります。

Realm導入のメリット

Realmを導入する前は、ORMも使用せずにSQLiteを直接利用していました。DAOパターンなどを使用していたが、直接コードにSQLを書いているところもあり、SQLの生成のコードが読みづらく、メンテナンスに難がありました。
そこにRealmを導入することで、これらの問題の解決を図りました。
Realmを導入することによるメリットは、高速である、APIが簡単で使いやすい、導入が簡単、(SQLiteを利用していたときに比べて)ソースコードの記述量が圧倒的に少なくなる、サポートの手厚さなどがありました。導入にあたって苦労した点などは意外にもほとんどありませんでした。

工夫した点

サーバから受信したフィードのデータの保存にRealmを利用しています。Realmのモデルオブジェクトには継承によってポリモーフィックな振る舞いを持たせることができない制限があります。
しかし@Ignore指定のプロパティのgetterをオーバーライドして、カスタムのメソッドを定義するというテクニックにより、擬似的にポリモーフィックな振る舞いを持たせ、データ構造の管理をやりやすくしています。

public interface FeedItemDetail {
}
public class CardUpdateDetail extends RealmObject implements FeedItemDetail {
    @PrimaryKey
    private String postId;
}
public class FeedItem extends RealmObject {
    private int kind;
    @Ignore
    private FeedItemDetail feedItemDetail;
    
    public FeedItemDetail getFeedItemDetail() {
        /* ... */
        switch (kind) {
            case FEED_ITEM_KIND_CARD_UPDATE:
                (this.feedItemDetail = realm.where(CardUpdateDetail.class))
            case FEED_ITEM_KIND_SHARED_LINK:
                (this.feedItemDetail = realm.where(SharedLinkDetail.class))
            /* ... */
        }
        
        return feedItemDetail;
    }
}

Realmのデバッグツール(stetho-realm)

stetho-realmを利用すると、Chromeのインスペクタを利用してRealmのデータを閲覧することができます。デバイス内のデータをリアルタイムに見てデバッグすることができる非常に画期的なツールです。Eightの開発では積極的にこのツールを活用しました。

Realmのテスト(PowerMock)

テストについて、Realmオブジェクトがfinalクラスに指定されているため、Mockitoなどを用いてMock化することができないという問題がありました。
この問題についてはPowerMockというライブラリを利用することで解決しました。PowerMockfinalクラスやStaticメソッド、Privateメソッドなど、およそJavaの制限によりMock化できなさそうなものをMockできてしまう強力なライブラリです。クラスローダを差し替えることによって実現しています。

Eightの開発ではPowerMockを利用することで、Realmを使用しているコードもJVM上でテストすることができるようになりました。

RunWith(RobolectricGradleTestRunner.class)
@Config(constants = BuildConfig.class, sdk = 21)
@PowerMockIgnore({"org.mockito.*", "org.robolectric.*", "android.*"})
@PrepareForTest({Realm.class})
public class ExampleUnitTest {
    @Rule
    private PowerMockRule rule = new PowerMockRule();
    
    @Test
    public void mockRealm() throws Exception {
        final Realm mockRealm = PowerMockito.mock(Realm.class);
        
        PowerMockito.when(mockRealm.isAutoRefresh()).thenReturn(true);
        
        assertThat(mockRealm.isAutoRefresh(), is(true));
    }
}