パルカワ2

最近はFlutterをやっています

ライブラリをつくったときの雑メモ

annotation processor 毎度忘れる。

  • ElementはVariableElementやTypeElementなどにcast出来たりするよ
  • ClassName.get(int.class)できない。
    • TypeName.INTなどがある
  • TypeNameを色々と渡すような実装にしたけど、auto/commonとかTypesUtils, ElementUtilsがあるのでElementを渡すようにしたほうがよかったかも???またはClassName???
  • google/auto/commonなど参考にするとよい
    • DeepLinkDispatchも使ってた
  • debugger でデバッグ出来るようにしておくとよい
  • ProcessingContext, Writer, Definition という役割にクラスを分けるとキレイぽい
    • Ormaがこんな感じだった
  • getAnnotaton().hoge() でClass型取ろうとしても取れない。今回つくったAnnotationExtendでやってるように取るとよい
  • processorではJava8つかうとよい streamが使えてシュッ
  • VariableElement#getConstantValue() は primitive型かStringの値しかとれない それら以外はnullになる
  • TypeElementとかはドキュメントよむ
  • 毎度読んでる気がする Aptを使ったAndroidライブラリの作り方 - Qiita
  • http://qiita.com/opengl-8080/items/beda51fe4f23750c33e9
  • JavaPoet 使い方メモ - Qiita
  • Observable<String>を作りたい場合はこうする ParameterizedTypeName.get(RxJavaTypes.Observable, JavaTypes.String)
  • ClassNameなどをRxJavaTypesやJavaTypesなどに定義しておくと使いまわせてまとめられて便利

新たなライブラリを導入するときに考える事

社内向けに書いたけど転載。

はじめに

開発をしていると判断していくことが数多くあります。世界中で公開されているライブラリの中から1つを選び、導入を決めるのもその1つです。

判断とはとても難しいもので、ほぼ確実に間違いは起きます。例えば、「実行速度が遅いが高速な開発には必要であろう」と判断して導入したが、実際運用してみるとやっぱり遅くてやいのやいの言われるとか。入れてみたいからという理由でライブラリを入れる判断をして、ある場所では使われてるけど、ある場所では使われておらずゴチャゴチャになってるとか。似たようなライブラリが3,4個導入されていて、どれが一番使うべきなのか判断出来ないとか。働き始めて5,6年の僕が失敗したな〜と思うだけでも色々あるわけです。

そこで僕が仮にポックリ逝ってしまったとしても、僕の失敗をみなさんが活かせていい感じに開発出来ると僕も生きた意味あると思うので、新たなライブラリを導入するときに考えていることを共有します。

⚠️ 注意 ⚠️

あくまでひさいちが考えてる事なので、書いてる事以外に重要なこともあるでしょうし、より良い方法考え続ける事でバンバン良くしていきましょう。(これだけ抑えておけば絶対破滅しないというわけではない)

ライブラリについて考える

ライブラリを導入するからにはライブラリについて考える。

メリット・デメリット

ライブラリのメリットとデメリットは何か?必ず複数個挙げる。 気をつける点として、メリットで「わかりやすくなる」をあげる場合があるが、これはあくまで個人の感想で事実ではない。メリットとデメリットには事実のみ書くべき。

理科系の作文技術 (中公新書 (624))

理科系の作文技術 (中公新書 (624))

ライブラリのサイズ

モバイルアプリはインストールする必要があるので、アプリサイズをなるべく小さくしたい気持ちがある。なので、ライブラリのサイズがあまりに大きいものは採用しない。

ライブラリ実行速度

多少気にする。必要があれば計測する。

ライブラリは課題をどう解決するのか

  • 画像表示ライブリではキャッシュやBitmap Poolやらスレッド数変更やらなんやらをどう実現出来るのか調べる
  • ORMだとSQLを書く必要がない等をどう実現するのか調べる

自分やチームは今どういう課題を抱えていてを考え、ライブラリはどう解決するのか調べる。

似たライブラリの比較する

似たライブラリといってもどう解決するのか?の部分は違っていたりするので、違いを理解する。

実行時エラーではなくコンパイルエラーになるか

具体的な例を出すとOrmaはSQLをつくるときにテーブル名を文字列で渡す必要がない。文字列でテーブル名を渡す場合、テーブル名がtypoしていたら実行時にエラーとなるが、Ormaはメソッド名なのでコンパイルエラーになる。

コードや仕様がシンプルであるか

  • 仕様が複雑すぎるとあとから見ると意味不明になる
  • コードが複雑すぎると読むのに時間がかかる

自分の場合、仕様が複雑だと理解すると便利!!って大体なるけど、数日後には忘れてる。またライブラリのコードは結局読むので、読みやすい・シンプルなものを選ぶのが後々楽な事が多い

メンテンスされてるか

数年間リリースされてないとかだと、ちょっと不安ですね。

いざとなったら自分が直せるか

無理そうなら複数人でメンテナンスされてるものを選ぶ

枯れているのか

それなりに他社でも事例があると安心ですね

導入後を考える

残念なことに導入して終わりではないので、先を見越して考えておく。ここが雑だとライブラリが優れていても途中で失敗したりする。

チームへどう広げるか

広げる事について考えている時にメリットやデメリットを話せないと説得力が無なので広がらない。だから、そのあたりは先に考えておく。

Fearless Change アジャイルに効く アイデアを組織に広めるための48のパターンは大げさだけど、活かせることがあるかもしれません。

Fearless Change アジャイルに効く アイデアを組織に広めるための48のパターン

Fearless Change アジャイルに効く アイデアを組織に広めるための48のパターン

どこから適用して、どこまで適用するのか

すでにあるプロダクトに新たなライブラリを導入する場合は考えます。 どこから始めて、どこで終わりとするのか見えてないと導入後いつの間にか負債となってしまう…

またこれを決める時にどういう実装になるのかを軽く実装して確認する。 無理なく、全員で進められるというのを大事にしている。

所感

こうして改めて文章にしてみるとライブラリについて考えるだけではなく、チームにどう広げるか等も考えている事に気づいた。そう思うとペパボの評価軸である「先を見通す力」「影響を広げる力」が主に必要で、なんならライブラリを導入のために何か作る必要があるのなら「作り上げる力」が必要になってくるのだなと思いました(Retrofit2導入時には、テスト用のクラスを作ったりしました)

追記:当たり前すぎて忘れてたけど、ライセンスも見てた。

Robolectric 3.3.2から3.4.2へのバージョンアップでやったこと

hisaichi5518.hatenablog.jp

Android Studio 3.0系ではAAPT2がデフォルトでONになっているので、Robolectric 3.3.2ではリソースまわりでエラーが出て動かないようだ。

AAPT2. We are continuing to stabilize AAPT2 which enables incremental resource processing. If your build fails due to resource processing issue, please send us a bug report. To temporarily disable AAPT, set android.enableAapt2=false in your gradle.properties file.
a. Roboelectric is currently not compatible with AAPT2
Android Studio Release Updates: Android Studio 3.0 Canary 5 is now available

AAPT2をfalseにするのも試したけど、テスト用のApplicationクラスを実行してくれなかったので、めんどくさくなって将来的に必要であろうということでバージョンアップした。
追記:テスト用のApplicationクラスを実行してくれなかったというのは僕の勘違いだった!!!!

  • バージョンをあげる
  • testOptionsの追加
  • Add-On Modules の名前変更
  • compileSdkVersion の変更
  • org.assertj.core.api.Java6Assertions.assertThatの利用をやめる
バージョンをあげる

はい

testCompile "org.robolectric:robolectric:3.4.2"
testOptionsの追加

Robolectricのドキュメントであるgetting startedに書かれてある通り、testOptionsを追加する必要がある。

android {
    testOptions {
        unitTests {
            includeAndroidResources = true
        }
    }
}
Add-On Modules の名前変更

ドキュメントはまだ更新されていないけど、Robolectric 3.4のRelease noteを見ると名前が変わっていたので変更した。一応、ドキュメント更新のプルリクを出しておいた。

Some Robolectric sub-projects have been renamed. build.gradle files will need to updated accordingly. [issue #3186]:

robolectric-annotations -> annotations
robolectric-junit -> junit
robolectric-processor -> processor
robolectric-resources -> resources
robolectric-sandbox -> sandbox
robolectric-utils -> utils
shadows-core -> framework
shadows-httpclient -> httpclient
shadows-maps -> maps
shadows-multidex -> multidex
shadows-play-services -> playservices
shadows-support-v4 -> supportv4

Rename projects. by xian · Pull Request #3186 · robolectric/robolectric · GitHub

compileSdkVersion の変更

compileSdkVersion が25未満だとShortcutManagerがないと怒られるのでバージョンを25以上にする必要がある。

org.assertj.core.api.Java6Assertions.assertThatの利用をやめる

Robolectric now requires JDK8.

とのことで依存からなくなったようなので、org.assertj.core.api.Assertions.assertThatに変更

アプリをAndroid Studio 3.0 beta 4に対応したのでやったこと

まだマージする気はないけど、対応しておくかと思ったのでやってみた。
結構色々と変わっているようだけど、ビルド出来るところまではすぐ出来た。しかしRobolectricまわりでテストが死んでる…(まだ調べてない)追記:Robolectricがエラーになるのを調べたので書いた

  • gradleの更新
  • maven.google.com を追加
  • deploygateのプラグインを更新
  • gradle pluginの更新
  • retrolambda を削除
  • provided を利用してた箇所を annotationProcessorに変更
gradleの更新
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wr
index 4d0f7f7e7..01ed591b3 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Thu Jan 19 11:13:41 JST 2017
+#Tue Sep 05 17:23:15 JST 2017
 distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-4.1-all.zip
maven.google.com を追加

google()を buildscript と allprojects 両方に指定する必要があった。

deploygateのプラグインを更新

古いプラグインは対応していないようなので1.1.3に更新した
https://docs.deploygate.com/v1.1/docs/gradle-plugin

gradle pluginの更新
diff --git a/build.gradle b/build.gradle
index 156d515ea..ccc0c96f1 100644
--- a/build.gradle
+++ b/build.gradle
@@ -16,7 +16,7 @@ buildscript {
         maven { url 'https://jitpack.io' }
     }
     dependencies {
-        classpath 'com.android.tools.build:gradle:2.3.3'
+        classpath 'com.android.tools.build:gradle:3.0.0-beta4'
         classpath 'com.deploygate:gradle:1.1.3'
retrolambda を削除

Android Studio 3.0から一部Java8の文法に対応しているようなので削除

Use Java 8 language features | Android Studio

provided を利用してた箇所を annotationProcessorに変更

icepickとlombokがprovided使ってたので修正
ただLombokがannotationProcessorのみだとエラーになるので、compileOnly も加えた

https://developer.android.com/studio/build/gradle-plugin-3-0-0-migration.html#annotationProcessor_config

diff --git a/app/build.gradle b/app/build.gradle
index cb74189ff..a62e509c0 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -260,7 +260,7 @@ dependencies {

     compile 'frankiesardo:icepick:3.2.0'

-    provided 'frankiesardo:icepick-processor:3.2.0'
+    annotationProcessor 'frankiesardo:icepick-processor:3.2.0'

@@ -347,7 +347,8 @@ dependencies {
         transitive = true;
     }

-    provided 'org.projectlombok:lombok:1.16.18'
+    compileOnly "org.projectlombok:lombok:1.16.18"
+    annotationProcessor "org.projectlombok:lombok:1.16.18"
 }

AndroidエミュレータでのAuto Backup for Appsを検証する

  • Settings > Backup & Reset でバックアップを有効にする
  • バックアップ用にGoogleアカウントにログインしている必要がある
  • adb shell bmgr run
  • データを保存するような動作をする
  • adb shell bmgr backupnow
  • App infoからデータをクリアする
  • adb shell bmgr restore

Auto Backup for Apps | Android Developers

コマンドを実行するとTransport errorというのが出ていて???ってなってたけど、バックアップが有効になってなかった事とバックアップアカウントが設定されていないのが原因だった。

Retrofit2+RxJava2 で リクエストするときに subscribeOn を指定する必要がないようにする

こういう風にRetrofit2を利用してた。

new Retrofit.Builder()
    .client(clientBuilder.build())
    .baseUrl(...)
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
    .build();

APIを叩くコードを書くたびsubscribeOnを指定していてめんどくさかったので調べたらcreateWithSchedulerを利用すればどうにか出来ると知った。

new Retrofit.Builder()
    .client(clientBuilder.build())
    .baseUrl(...)
    .addConverterFactory(GsonConverterFactory.create())
    .addCallAdapterFactory(RxJava2CallAdapterFactory.createWithScheduler(Schedulers.io()))
    .build();

便利