DroidKaigi 2017のまとめ

# DroidKaigi 2017

AndroidカンファレンスのDroidKaigi 2017に行ってきました。
Android主体のカンファレンスですが、モバイル系エンジニアが多数集まって互いの知見をやりとりするため、Android以外のエンジニアにもとても役に立つカンファレンスです。

開催セッション
https://droidkaigi.github.io/2017/timetable.html

## まとめ
自分が参加したセッションのまとめです。

### モデリング
■  [How to apply DDD to Android Application Development](http://y-anz-m.blogspot.jp/2017/03/droidkaigi-2017_9.html) by あんざいゆき（@yanzm）さん


DDDはドメイン駆動設計です。
ドメインはアプリの利用場面といったところでしょうか。
アプリを作る前にそのドメインをよく知っている人（ドメインエキスパート）と開発者との間で、
ドメインベースのモデリングを行ってから実装を行うと変更に強いコードになる。
なぜなら、同じドメインで利用するアプリであれば、実装する機能はドメインエキスパートが指摘したモデリングに沿ったものになるから想定外の実装は少なくなるので。ただ、ドメインエキスパートと開発者は知識・経験が異なっていて、認識を一致させることが難しいため、お互いに理解しやすいユビキタス言語的なものを設ける必要がある。

ユビキタス言語で気をつけることは、同じ言葉でも利用場面によって異なる意味になるものがある。
そのような利用場面のコンテキスト（抽象的な言葉ですが、ここでは使われる言葉の意味が同じになる範囲）一覧を書き出して、コンテキストマップを作り、言葉を区別していくことが重要。

概念詳細は、エリック・エヴァンスの"ドメイン駆動設計"と"実践ドメイン駆動設計"という本を読んでくださいとのこと

後半はアプリでよく使われるアーキテクチャとドメイン駆動で設計したモデリングをどう結びつけるかという話でした。最近よく聞くドメイン層というのが、上記のドメインベースのモデリング（ビジネスロジックといったほうが分かりやすいかも）部分で同じドメインで利用するアプリであればそのモデリングは流用できそうということですね。

### DB

■ [Android ORMの選び方](http://gfx.hatenablog.com/entry/2017/03/10/141908) by gfxさん

ORM（Object-Relational Mapping）はDBのモデル定義をオブジェクト指向的な実装に変換するといったところでしょうか。Android ORMの一つであるormaの開発者の方が様々なORMを比較して利点と欠点を比較していました。
比較点としては
・使いやすさ：ライブラリの読込部分やDBハンドラの定義とか扱いやすいか
・モデル定義のされ方：アノテーションベースとかアクセッサを自動生成するとか
・クエリー方法：型安全か、Typoが起きにくいか
・アソシエーション：モデル間のリレーションシップを扱いやすいか
・PubSub：データ更新の通知
・マイグレーション：スキーマ変更時に自動で更新できるか、バージョニングされるか

AndroidはORMがたくさんあるんだなーと思いました。あとPubSubというかデータ更新通知が重視されるのはReactive-Programmingの影響かなと思いました。

■ [オフラインファーストなアプリケーション開発](https://speakerdeck.com/zaki50/ohurainhuasutonaapurikesiyonkai-fa) by zaki50さん

API指向のため外部からデータを取ってくるアプリが多くなっていますが、一方でオフラインで利用できるというのも非常に重要です。通信環境が悪いところはレスポンス遅くなるとかUXに深く関わるからです。
オフラインで困ることは、結局のところ外部からデータが取得できないということです。
Realmはモバイル利用で設計されたDBで、オフラインも一つの正常系として動作するように設計されているようです。
・オンライン時はアプリでデータが必要な時にローカルDBをDBサーバと同期させる
・オフライン時はアプリはローカルDBのデータを取得できる
・オンライン復帰時はまたローカルDBをDBサーバと同期させる

オフライン時のデータ取得処理をアプリで実装している人は多いと思いますが、Realmを使うとそれを隠蔽できます。また、APIとの通信もRealmを使うと直接データをやりとりできるので、JSONなどを使ったエンドポント間通信を実装しなくても済むとのこと。
さらに、Realm Mobile Platformを使うと、複数デバイス間のDBを同期できるとのこと。
なかなか良いと思いました。

ただ一つ気になるのは、上記のAndroid ORMの選び方でも話があったのですが、マイグレーションの実装が分かりにくいというところでした。確かにデータの自動同期がされるDBにおいてスキーマ変更によるマイグレーションの影響がどうなるか考えますよね。セッションの最後の質問で出ていたのですが、基本的にマイグレーションではスキーマの追加しか扱えないようです。削除ができないとのこと。古いデータとか残り続けるのだろうか・・

### リファクタリング
■ [Don't reset --hard: Strategies for Tackling Large Refactors](https://speakerdeck.com/sienatime/dont-reset-hard-strategies-for-tackling-large-refactors) by Siena Aguayoさん

この方法はアーキテクチャを置き換えるものではなく、スムーズにリファクタの目的を達成するための方法とのこと

1. まず修正する部分の目星をつけるため、コードをよく見る。（Code Smellsと言ってますね）

* 肥大化しているコードはあるか（行数の多いメソッド、大きいクラス、長いパラメータリストなど）
* オブジェクト指向がうまく利用されていないか（switch分岐を多用、テンポラリ変数多い、継承している機能を使ってないなど）
* 変更を阻害する要因はあるか（一つの機能修正のためにあちこち修正する必要がある、一つの修正で複数のクラスに影響を与える、複数の継承元を持って作られたクラスなど）
* 不要なコードはあるか（重複しているコード、使ってないコード、無駄なコメントなど）
* 不適切なカップリング（自身のデータでなく、別のオブジェクトのデータを多くアクセスしている、内部変数と外部クラスのメソッドで構成されているクラス、単に機能を中継しているだけのクラスなど）

2. 一度にできるだけ最小限の修正を行う
3. コンパイルできるようになったらテストを走らせてみる。テストをパスしなかったら違う修正を試す。
4. 退屈な作業になりがちだけどスキップしないで繰り返しテストを行なっていく

目星もつける→修正→テストを繰り返していくのが重要。後半は実際にアプリコードでそれを実践した例を説明。
他のユースケースとして、

* コンポーネントの置き換え　
　どの程度違いがあるか、簡単に移行できるかを目星つける
　修正では古いクラス・メソッドと新しいクラス・メソッドについて1対1で置き換えながら実施。
　もしクラッシュが起きるようであれば変更直前までもどしてやり直す

* ライブラリのアップデート
　大規模な変更があるかを確認
　新旧ライブラリを共存できるのであれば、利用している部分を少しづつ変更することはできるが、そうでない場合はライブラリの切替にかける時間を最小限にして危険な状態を短くする

などあるとのこと。

■ [大規模アプリのリノベーション](https://speakerdeck.com/funnelbit/droidkaigi-2017-renovation) by 北村 涼さん

はてなブックマークアプリのリファクタリングについて説明されてました。
・リファクタリングに専念する時間がほしい
・アプリの機能を全体的に確認したい（ドメイン知識と言ってますね）
まとめの最初の方でDDDのことを書きましたけど、そこで言ってたドメインが出ましたね。
ユビキタス言語としては画面キャプチャや画面遷移図を作成し、開発者メンバーとデザイナーで共有して再モデリングした感じですね。アーキテクチャはMVVMでライブラリも変えて一新したそうです。
また設計ドキュメントを残して実装方法を共有しているのも特徴的だなと思いました。

リファクタの方法も少しづつ変更して1〜2週間でリリースを繰り返して様子を見たとのことです。
リファクタしていることを明確にするために細かい見積もりを作って、全体に対する実施状況を把握できるようにしたのはいいなと思いました。

### デバッグ
■ [エラーと戦うためのデバッグ法](https://speakerdeck.com/ymnder/eratozhan-utamefalsedebatugufa) by 山﨑亮さん

私はiOSアプリ開発しているのですが、デバッグ作業で見るところは同じなので今回の話は色々ためになりました。
AndroidではStethoというツールで、Chrome Dev toolsを使って色々できるようです。
・View Hierarchy
・Network Inspection
・Database Inspection
・Console
・dumpapp
と色々機能があるようです。
iOSでもほしいなと思って探したらPonnyDebuggerというのがありました。ただ今も使えるのかどうかわからないのであとで試そうかなと思ってます。
他にも
chuck
Android-debug-Database
layout-inspector
theme editor
などのツール説明がありました。

■ [Building my own debugging tool on overlay](https://speakerdeck.com/keithyokoma/build-my-own-debugging-tool-on-overlay) by KeithYokomaさん

WindowManagerを使って、画面上に常に表示されるViewを実装する話です。
・WindowManagerのレイヤーはたくさんあり、レイヤーによっては制限事項ある。
・Viewを更新し続けるため、ServiceでViewを作成する。
・表示するViewはActivityでないのでServiceでLifeCycleを自分で管理する必要ある。
・LifeCycleとView更新を実装したOverlayViewManagerを作成した。
・マニフェストにブロードキャストインテントを受信できるようにする。
・ServiceをOSに止められないようにVisibleProcessにするよう工夫する。
　ただメモリ使いすぎだとkillされるので、メモリ利用に気をつける。
・アプリのActivityと連携するのにIntentやEventBusやDIスコープを使う。

### テスト
■ [How to remodel current testing environment](https://speakerdeck.com/jmatsu/how-to-remodel-current-testing-environment) by red_fat_darumaさん

モデル：何かの物や事の知り得た機能や性質を抽象化して、同じような機能や性質を持つ構造や外観
モデリング：特定の機能や性質を持つ構造や外観を作ること

既存環境のテストモデリングを見直して（Remodeling）、新しいモデル（目的モデル）を構築してテストの信頼性向上と負債（欠落したテストの補完、不要なテストの削除）の返上を目指すやり方

Remodelingのステップ

1. 現存のテストの理解
　・非機能要件のテストは曖昧なものが多いので見直す
　・モデリングには二つの側面
　　運用的側面（ポリシー・ストラテジ・要件保証・オートメーション）
　　技術的側面（言語・フレームワーク・実行環境、テストサイズ、テスト段階（ユニットテスト、UIテスト、パフォーマンステスト、シナリオテスト、正常系テスト）、Mockable/Injectable）
　*Mockable:スタブなどパラメータを自由に差し替えられるもの（Test Double思想）
　*Injectable：テスト用クラスに差し替えられるもの

2. 目的モデルの選定
　・保証すべき要件からボトムアップで決定していく
　　例えば仕様で条件分岐がはっきりしていればBDD(振舞駆動開発)の方が適しているが、Mockableでないとテストが難しい

3. 目的モデルの構築
　・必要に応じてリファクタリングも行う

### デザイン
■ 2つのアプリ、1つの設計のデザイン指針 by meycoさん
スタディサプリというアプリで行なっている、一つのソースコードで複数のアプリを提供するメリットを説明していました。

メリットとしては、
・メンテナンスをアプリごとに分けて行わなくすむ
・機能が一緒なので構造を把握しやすい
・ユーザレビューを集めやすい

またこのアプリはグローバルで展開しており、やはり一つのソースコードで提供しているため、
・任意の国ですぐリリース可能
というメリットがあるそうです。

またグローバル展開の特徴として
・地域によって通信事情が悪い国もあるので、オフライン利用を強化。
・ユーザテストをどこで行うか。
・営業部隊と開発で良好な関係を築く。
・課金まわりは国によって異なる。課金できなかった場合の動線やプロモ動線も気をつけること。
・扱う機種が異なる。安価な機種ではストレージのデータ容量が少ない。

ここからがデザインの話になるのですが
このアプリは元はQuipperというアプリだったのですが、アプリ同士でブランド統合したことにより
デザインの基本ガイドライン作成してアプリ同士の整合性を取るようにしたようです。
またマーケティングなどの他のプロダクトメンバーも確認している。

ガイドラインとしては
・色の名前、利用する場所
・ボタンの色、大きさなどのデザイン
・画面についてはInfoGraphicで説明
ただデザインはプラットフォーム間で同一にするには工数かかる。特にフォント関係。
これはデザイナーだけでは気づかないので、エンジニアを入れて検討すればよかった。
またデザインによってはアプリのパフォーマンスを損なうこともあるので、OSに沿ったデザインというのはある。
またUIについては過剰に丁寧にやってもUX的にあまり意味がないことも多々あるのでバランスが必要

■ [エンジニアが武器にするMaterial Design](https://speakerdeck.com/seto_hi/enziniagawu-qi-nisurumaterial-design) by 瀬戸優之さん

マテリアルデザインは理論的なデザインなのでエンジニアに分かりやすい。

アプリのデザインについて、エンジニアがデザインに関わると色々捗るそうです。
特に実際に実装できるデザイン設計ができるため、手戻りがなく工数削減できる。
またデザイン設計に関わっているため、実装を並行でできる。
またデザイナーとエンジニアの多視点で判断できる。
しかし、エンジニアに負荷はかかるのでバランスは必要。
エンジニアはマテリアルデザインで指定する部分だけ確認し、それ以上のデザイン部分はデザイナーに任せる。最終決定権はデザイナー。
デザイナーにOS世界観を持ったアプリデザイナーの能力は必要。

マテリアルデザインとは
https://material.io/jp/guidelines/
・現実世界ベースで分かりやすい
・リファレンスがしっかりしている
・リファレンスでそこそこのUIは作れる。それ以上はデザイナーのセンス必要。
・学習順序は、マテリアルデザイン→コンポーネント→パターン→レイアウト→モーション→学習と情報提供

UXではデザインの他にRAILモデルも考え、そこもガイドラインに載せる
https://developers.google.com/web/fundamentals/performance/rail?hl=ja

ノハナではマテリアルデザインの普及について下記のことを実施している。
・社内マテリアルデザイン勉強会
　概念、世界、Viewコンポーネント説明

・社内アニメーション勉強会
　何が可能か、どのくらい工数かかるかを共有

デザイン指示について、
・なぜその指示なのかの意図を確認し、NGなら代案を示す。

### 言語
■ [解剖 Kotlin ~バイトコードを読み解く~](https://speakerdeck.com/sys1yagi/jie-pou-kotlin-baitokodowodu-mijie-ku) by sys1yagiさん

Javaとの違いは
・null安全
　null許容（?）が入っているというところは、nullが入っているくる可能性があるところ
　実装的にnullを想定していないのでは、そもそもnull許容しないように変えていく必要ある
・関数型
　引数や変数に関数を代入できる。これにより高階関数をかける
・ラムダ式
　関数型実装を式として記載できる
・拡張関数
　既存のクラスに対して新しい関数を追加。冗長な処理をまとめたりできる。実際のクラスでは必要な機能を後から追加可能。
・プロパティ
　フィールドとアクセッサを自動生成

印象としては、テンプレ的なコードを隠蔽して書くコード量を減らしたり、ラムダや拡張関数などでコードを見やすくしたりして、プログラミングしやすくしているJavaという感じです。

### データバインディング
■ [Data Bindingで実現するMVVM Architecture](https://speakerdeck.com/star_zero/databindingteshi-xian-surumvvm-architecture) by Kenji Abeさん

有用な設計原則にUIのプレゼンテーション層とその他の機能をうまく分けるというのがある。
プレゼンテーション層とドメインロジック（Model）が分かれていると理解しやすい。
このプレゼンテーション層について、ViewとViewのロジック（ViewModel）を分離したものがMVVM。ViewはViewModelと双方向データバインディングで連携、ViewModelとModelは戻り値なしの呼び出しと通知でやりとりする。

データバインディングでは、単にプロパティの値を連動させるだけなく、カスタムセッターで拡張できる。ViewについてはイベントによってはViewModelのメソッドを直接呼ぶこともある。
変更通知でデータバインディングを使えないパターン、例えばダイアログや画面遷移ではEventBusやRxJavaを利用する方法あり。

モデルではドメイン（ビジネスロジック）/DB・API（リポジトリ）、他を扱う
ViewModelへの通知は、
・リポジトリから非同期でEntity取得するとき
　成功と失敗を通知する
・もしViewModelのEntityがViewとデータバインディングされているのであれば、そのEntityにリポジトリのプロパティ変更を通知

ViewがViewModelのインスタンスを保持している

以上