なるべくコードを書かないandroid開発
TRANSCRIPT
なるべくコードを書かないAndroid開発
株式会社ミクシィ・株式会社Diverse
@kikuchy
Who?
@kikuchy菊池 紘株式会社ミクシィ ‑‑(出向)‑‑> 株式会社DiverseAndroidの前はWebのフロントでJavaScriptとか書いてましたShibuya.apk, Roppongi.aar, Kotlin勉強会など
おわび
Kotlinの話が20分枠に収まりきりませんでした
許可いただければお話しします
資料を後ほど公開します & 懇親会でお声掛けください
想定リスナー
二人以上で開発していて
製品のコードの保守が大変だと感じている人
「私のことかも!?」
と思った方は挙手
( ´ ▽ )ノ
コードの保守は大変!!
保守のコスト
と聞いてどんなコストを想像しますか?
人件費
保守にかける時間
気持ち的な問題
たくさん書くとそれだけ負債が増える(›´ω‹ )
書かなければ良い!!!!!
人間が保守するコードを減らせば管理コストは減らせる
どうするか
コンパイル時にコードを自動生成すれば、生成したコードは管理の必要がない
ジェネレーターだけ管理していれば良い
( ´・ω・ )「でも新規開発じゃないと、フレームワーク変えるとか言語変えるとか無理じゃね」
大丈夫!\\ ٩( 'ω' )و //
aptだったら一部分から使い始められる!
チームに「コードを少なくする」ことに対して前向きになってもらおう!
apt1. aptとは2. 使い所3. できること4. 作ろう!
apt1. aptとは2. 使い所3. できること4. 作ろう!
1. aptとは
JSR269 =
Pluggable Annotation Processing API
Android界隈ではaptと呼ばれることが多いようなので 今スライドではaptと呼びます。
コンパイル時にアノテーションを見て何かしらの処理をする仕組
み。 ソースコードを生成することもできる。
apt1. aptとは2. 使い所3. できること4. 作ろう!
2. 使い所マッピングの手間を減らす
何かしらの変換・対応作業
例) ButterKnife R.id.* のViewをクラスのフィールドに対応させ
る
例) ormaDBの行をPOJOに、カラムをフィールドに対応さ
せる
「ライブラリにとって未知のフィールドやメソッド」へ
アクセスできる
2. 使い所クラッシュ(ランタイムエラー)の発生をコンパイル時に前
倒しする
例) R.java 文字列でlayoutファイル名やIDを指定しているとtypoの危険性が
クラッシュはユーザー体験にとって大きなマイナス
コンパイルエラーとして前倒しできればすぐミスに
気付ける
apt1. aptとは2. 使い所3. できること4. 作ろう!
3. できること作例
POJOを HashMap<String, String> に移し替えるPOJOにアノテーションをつけるだけでOKコンパイル時に生成されるコード
POJOの各フィールドを
指定のコンバーターでStringにコンバートし
指定のkey名でHashMapにputする
@ToQueryMap public class BbsCreateRequestBody { @QueryParam(name = "message", adapter = StringTypeAdapter.class) public String message;
@QueryParam(name = "category_code", adapter = EnumToStringTypeAdapter.class) public BbsCategory categoryCode;
@QueryParam(name = "title", adapter = StringTypeAdapter.class) public String title; }
Serializer<BbsCreateRequestBody> serialzer = new BbsCreateRequestBodySerializer() Map<String, String> serialized = serialzer.serialize(request);
あなたのコーディングにどう応用できそうでしょうか?
apt1. aptとは2. 使い所3. できること4. 作ろう!
4. 作ろう!
rejasupotaroさんの『Androidでaptのライブラリを作る時の高速道路』が詳しい
http://qiita.com/rejasupotaro/items/b9b89f88348222b46708
ここに書かれていない、覚えておくと便利なTipsをご紹介
(以降の話の前提)
Java Libraryの module を2つ追加
アプリから使うモジュールに、使いたいアノテーションを定義し
ておく
// RetentionをSOURCEにすると // コンパイル後はこのアノテーションが消えてくれる @Retention(RetentionPolicy.SOURCE)
// Targetを指定するとアノテーションできる場所を限定できる @Target(ElementType.TYPE) public @interface ExampleAnnotation {
// 値を持たせたかったらvalueなどを宣言する public int value(); }
コンパイル時に走るプロセッサを定義する
ソースコード以外も生成できますが、今回はソースコードを生成
// Google の AutoService を使うとメタデータの生成が楽 @AutoService(Processor.class) public class ExampleProcessor extends AbstractProcessor { Filer filer; Types typeUtils; Elements elementUtils; Messager messager;
// プロセッサ初期化時に呼ばれる // 便利なインスタンスが渡されるので取得しておく @Override public synchronized void init( ProcessingEnvironment processingEnv) { super.init(processingEnv); // Filer#createSourceFile にJavaソースコードをStringで渡すと // javaファイルを作ってくれる filer = processingEnv.getFiler(); // TypeMirror を取得したり 具体的なTypeを取得したりできる typeUtils = processingEnv.getTypeUtils(); // Java 構文の要素から子要素を取得したりできる elementUtils = processingEnv.getElementUtils(); // 警告やエラーメッセージの出力に便利 messager = processingEnv.getMessager(); }
// このプロセッサでサポートするアノテーションを決める @Override public Set<String> getSupportedAnnotationTypes() { Set<String> types = new HashSet<>(); // アノテーションの名前はFQCNでないといけない types.add(ExampleAnnotation.class.getCanonicalName()); return types; }
Overriveしない場合、このプロセッサにつけた
SupportedAnnotationTypes アノテーションに書かれた型がサポート
される
@SupportedAnnotationTypes("net.kikuchy.aptsample.ExampleAnnotation") @AutoService(Processor.class) public class ExampleProcessor extends AbstractProcessor {
ソースコードの生成と書き出しには square/javapoet を使うと楽 https://github.com/square/javapoet
// ソースコードを生成して Filter で書き出す処理を書く @Override public boolean process( // 今処理を要求されているアノテーション Set<? extends TypeElement> annotations, // ラウンドの情報 RoundEnvironment roundEnv) { // RoundEnvironment#getElementsAnnotatedWith を使うと // アノテーションがついた構文要素を取得できる for(Element elem : roundEnv. getElementsAnnotatedWith(ExampleAnnotation.class)) { // ソースコードの生成と書き出し ... } // 後続のプロセッサにアノテーションの処理を渡すか否か return false; }
注釈処理のラウンド
process が何度も呼ばれる(ラウンド)
生成したソースコードに対しても注釈処理が必要なため、何
度も呼ばれる
通常は2回 JavaFileObject#openWriter に2回書き込もうとすると2回目は例外が出る
Pluggable Annotation Processing API 使い方メモ http://qiita.com/opengl‑8080/items/beda51fe4f23750c33e9
ラウンド対策
try‑catch2回目に出る例外を握りつぶす
プロセッサのメンバに処理済みかどうか記録しておく
ButterKnifeなどがこれ
生成したコードを使う
一度コンパイルをかければ生成される
aptプラグインを使っていれば、生成後はAndroidStudioの補完機能でも呼び出せる
ButterKnifeのように生成コードを隠蔽する方法もある
クラスの動的ロードが必要なのでProguard設定が必要
// 生成されたViewBinderクラス類は動的ロードされている ButterKnife.bind(this);
aptの補足
aptを使ったAndroid向けライブラリButter KnifeDagger2DeepLink DispatcherPermissionsDispatcherOrmaIntentBuilderFragmentArgsAndroidAnnotationskvs‑schemeFlender
etc
Kotlin
保守コードの減量とKotlinの関係
そもそものコード行数が少なければ、保守コストも少なくて済む
Javaは冗長になりがち、短く書ける言語を使おう
Kotlinもプロダクトの一部分から使い始められる
Java Compatible!!
もうみなさんKotlinはご存知だと思いますので 少しだけマイナー気味で、コード短縮に効果のあることだけ紹介
します。
スコープ関数
apply と let を使うと便利なことが多いです
val intent = Intent(context, NextActivity::class.java).apply { // このスコープのthisは☝のIntent putExtra("hoge", "hogehoge") putExtra("fuga", "fugafuga") }
nullableVal?.let { // nullableValがnullだとこのスコープは実行されない // it (= nallableVal)がnonnullであることが保証される it.doSomething() }
業務でKotlinを書いている僕がKotlinを書く際に個人的に注意していること
http://qiita.com/magie‑pooh/items/b1179af28f5e0d50b62a
Class DelegationEffective Javaなどで言われている「継承より合成」を圧倒的簡単
さで実現
class CustomList<E>(private val base: ArrayList): List<E> by base { override fun add(elem: E) { print("${elem} is added!") base.add(elem) } }
KotlinのClass Delegationおさらい http://sssslide.com/speakerdeck.com/ntaro/kotlinfalseclass‑delegationosarai‑number‑kotlin‑sansan
Property DelegationAndroidでは頻発する遅延評価が簡単に
// in Activity private val hoge by lazy { intent.getStringExtra("hoge") }
// KotterKnife 使用 private val userName: EditText by bindView(R.id.user_name)
Delegated Properties で遊ぼう(スライド版) http://qiita.com/kikuchy/items/55ea0748a5850925349a
こういう話をした理由
むかーしむかし、あるところに、Activity1ファイルで4000行を超えるソースコードがありました。
4000行超え
つらい。
その他のActivityも2000行クラス新しい機能を入れようとしたらまず調査から
長すぎて読めない ‑> 既存ロジックを回避するようにコードを
足す ‑> さらに長くなるやばいコードの上にコードを足そうとすると、やばいコード
がどんどん増えて行く
割れ窓理論
アプリのリニューアルをする過程で、aptとKotlinを導入
Activityの平均行数がJavaで300行くらいkotlinで140行くらい
調査時間とかほとんどいらない
短く書く方法がある ‑> コードを短くしよう、という動機につ
ながる
割れ窓理論の解決法
短く綺麗なコードを保っている環境があれば良い
すべてのヤバいコードを生まれる前に消し去りたい
楽しく開発ができますように!
まとめ
保守するコードが少ないと楽です
コード減量のため導入しやすい方策がaptとKotlinこれをきっかけに、チーム全員がコードを少なくすることに
積極的になったら良いですね
Thank you!