5 年続く 「はてなブックマーク」 アプリを継続開発する技術

71
2016-02-19 / DroidKaigi 2016 5 年続く「はてなブックマーク」アプリ を継続開発する技術 信岡 裕也 NOBUOKA Yuya 株式会社はてな (Hatena Co., Ltd.)

Upload: yu-nobuoka

Post on 19-Jan-2017

12.917 views

Category:

Software


4 download

TRANSCRIPT

Page 1: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

2016-02-19 / DroidKaigi 2016

5 年続く「はてなブックマーク」アプリを継続開発する技術

信岡 裕也NOBUOKA Yuya

株式会社はてな (Hatena Co., Ltd.)

Page 2: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

自己紹介

● はてな id:nobuoka● Twitter @nobuoka● ソフトウェアエンジニア

モバイルアプリ (Android アプリ / UWP アプリ) Web サービス (Java / Scala / Perl / TypeScript)

● 経歴 2012 – 2014 年 : 主に 「B!」 サーバーサイド 2014 年 : 主に 「少年ジャンプルーキー」 2015 年 : 「B!」 Android アプリ開発

Page 3: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

背景

Page 4: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

「はてなブックマーク」 アプリの開発

● 「はてなブックマーク」 自社の web サービス ソーシャルブックマーク サービス自体は 10 年以上続いている

● 今月 2/4 に Android アプリ 「はてなブックマーク」 が 5 周年!

Page 5: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

「はてなブックマーク」 で web ページをブックマーク

Page 6: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

他の人がブックマークした web ページ一覧を閲覧できる

Page 7: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

現在の B! Android アプリ開発チーム

● 企画 (マネージャも) 2 人● デザイナー 1 人● エンジニア 2 (+1) 人

Cashlytics

Page 8: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

B! Android アプリの歩み

● 2011-02-04 最初のリリース API level 4+ 対応 最新の Android は 2.3 という時代

● 継続的に開発 (エンジニアが兼任で 1 〜 2 人程度)

● 2015 年からエンジニア 2 (+1) 人体制 大きな機能追加や変更ができるように

● 5 年続いてきて、この 1 年ほど特に開発が盛ん

Page 9: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

B! Android アプリの歩み

2015-01-01

Page 10: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

長く開発しているアプリで遭遇する問題

● コードの変更が意図せぬ影響を起こして期待する動作をしないようになる

● 機能追加、変更時に既存の設計では対応できない

● Android プラットフォームの変化への追従● などなど

Page 11: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

この発表の目指すところ

● 継続的にアプリ開発を行うには? チームでの取り組み、方針を紹介

● 話題としては 自動テスト、CI サーバー、ビルドシステム チーム体制、開発フロー アプリ設計、ライブラリ化

Page 12: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

第 1 部テスト・CI・自動化

Page 13: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

ソフトウェアテストの話

Page 14: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

ソフトウェアテスト

● テストを書いてますか? Instrumented tests Local unit tests (Gradle plugin 1.1 より)

● テストは我々の開発を助けてくれる バグの早期発見 (新規開発時もコード変更時も) テストしやすく → より良い設計

● Gradle によりテストが書きやすくなった → Gradle 導入後からテストを書くように

Getting Started with Testing | Android Developers

Page 16: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

B! アプリ開発とテスト

● コード品質を高める一つの手段としてテストを利用

● 標準のテストツールをベースに Testing Concepts (Android Developers) AndroidJUnitRunner、Espresso

● テスト用のビルドタイプ (“ttest”) を用意 Build config / ProGuard / テスト用コード

Page 17: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

目的を意識してテストを書く

● あらゆる状況・動作をテストすることは困難● 何をテストするのか不明確なままテストを書い

ても効果は薄い● 目的に応じて手段も変わってくる

Page 18: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

目的を意識してテストを書く

● 各 API level で問題なく動作するか?● 手動での動作確認では発見しづらい項目の検査

スクリーンビューの記録とか● 将来変更するときに見逃しそうな部分● 複雑な処理が期待通りに動くか?● 外部とのやりとり● など

Page 19: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

テストを自動で実行する

● 手動ではなかなかテストを実行しない テスト実行には時間がかかる・面倒 テストに落ちるのに気付くのが遅れる

● → 自動で実行されるように● Jenkins● Android SDK のエミュレータを利用● SDK セットアップ : sdk-manager-plugin

Page 20: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

テスト結果のフィードバック

● 自動で動いていても気づかなければ意味がない● 目に入る場所にフィードバックする

Slack のチャンネル GHE の pull request

Page 21: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

テスト結果のフィードバック

● Jenkins → Slack Jenkins Slack plugin

● Jenkins → GitHub curl コマンドで GitHub の API を叩く

● プラグイン等なくても Web API 等が提供されていれば戦える

Page 22: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

最近進めていること

● Jenkins の Pipeline plugin の利用 旧称 Workflow plugin ジョブの処理を Groovy の DSL で記述

→ 柔軟に書きやすく・管理しやすく Android エミュレータの起動・終了を Gradle タ

スクに→ ジョブを柔軟に・Jenkins への依存を小さく

● スクリーンショットによる表示のテスト

Page 23: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

テストを書いて変更しやすくし、品質を高めよう

●欠陥検出や品質を高めるための一つの手段 コードレビューなどと組み合わせて

●必要ならテスト用の build type を用意● 何を目的としてテストを書くのか意識する● 動かさないと腐っていくので

まずは自動化 目につくところにフィードバック

Page 24: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

リリースフローと自動化

Page 25: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

リリースの流れ

●週初めにリリース内容相談・決定 基本的にリリース可能なものからどんどん出す

● 機能が揃う → リリース用ブランチを切る リリース用ブランチでバージョン更新 自動テスト、パッケージ作成、チーム内への配布・動作確認

● Play Store へのアップロード・公開

Page 26: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

いつもの手順

● リリース用パッケージのビルド● チーム内に配布 (Beta by Crashlytics)

● GitHub Enterprise に “リリース” 作成● Google Play Store にアップロード・公開

Page 27: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

いつもの手順

Page 28: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

リリースフローが手動だと?

● 面倒 APK パッケージを作って Play Store にアッ

プロードするぐらいならいいけど● ミスが起こりがち

手順漏れ (clean、GHE のリリース作成等) アップロードすべきパッケージを間違う など

Page 29: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

自動化しよう!

Page 30: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術
Page 31: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

Gradle のタスク作成 & Jenkins 上で実行

● Gradle のタスク リリース用の APK パッケージ作成 GHE の “リリース” を作成 & アップロード 将来的には Google Play Store へも

● Jenkins 上で実行 将来的に Pipeline plugin を予定

● リリースフローの自動化がしやすそう

Page 32: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

リリースフローの自動化をしよう

● 面倒だと感じたら / ミスしそうだと感じたら● とりあえず Gradle のタスクを書こう

わりと手軽にいろいろできる がっつり時間を取るのは難しいので少しずつ

● さらに CI サーバー上で実行 手元にビルド環境が整ってない状況でもリ

リースできる

Page 33: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

テストや CI 関連のトーク

● Android CI: 2016 edition●僕がテスト書け書けおじさんになった経緯とそ

の過程でやったこと● Advanced Android Espresso●生まれ変わった UI Automator を使いこなす● Android Lint で正しさを学ぼう●怖くない gradle でのビルド環境設定と Bazel

Page 35: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

開発の流れ

● 企画・タスク管理 (Trello)

● デザイン・設計・コーディング やりとりは口頭・チャットツール (Slack)

● 東京・京都の遠隔、非同期コミュニケーション● コードレビュー (GHE)

● 自動テスト (Jenkins)

● チーム内へのパッケージ配布 (Beta by Crashlytics)

Page 36: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

B! アプリ開発と Git ブランチ

● Git flow

dev

master

release

feature

Page 37: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

B! アプリ開発とコードレビュー

● 社内の文化としてコードレビューは定着● 継続して開発するためにも重要

他人が見て意図がわかるか? 将来、変更が難しくなってしまわないか?

● レビューされやすいように依頼側も気を付ける 適切な規模 (数百行程度) 変更の目的を明確に (複数の変更を混ぜない)

Page 38: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

dev

Dev ブランチにマージする段階でレビュー完了しているように

Page 39: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

dev

規模が大きくなるなら分ける

Page 40: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

リファクタリング

● 長く開発を続けていると & 続けていくにはリファクタリングが必要 機能追加・変更時に設計を変える必要 レガシーコード改善

● リファクタリングする際の問題 機能追加・変更前に必要なリファクタリングを見極

めづらい 他の変更とコンフリクトする

Page 41: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

B! アプリ開発とリファクタリング

● リファクタリングと機能追加は分ける 混ざるとレビューできない

● 機能開発時に必要になった箇所をリファクタリングとして切りだす 不必要なリファクタリングは行わない これはヤバい、という場所はリファクタリングする

●小さな単位でリファクタリング レビューしやすい 早く dev ブランチに取り込みコンフリクトを避ける

Page 42: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

dev

開発中にリファクタリングが必要になったらブランチを新たに切って先にレビュー

Refactoring

feature

Page 43: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

Preview 版と大規模な新機能開発

● 大規模な新機能開発 dev ブランチでリファクタリングすると feature ブランチと

コンフリクトしがち● どんどん dev ブランチにマージ?

開発中の状態でリリースされると困る!!!● Preview 版 (product flavor) でのみ機能を有効に

これ自体がバグの原因になりうるので注意 規模が大きい場合は有効

● 開発中の状態で動作確認してもらうのもやりやすい

Page 44: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

Preview 版専用画面

Page 45: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

メンテナンスしやすいコードを生み出す体制

● コードレビューしよう 依頼側はレビューしやすいように気を付ける

●必要なリファクタリングはどんどんやる リファクタリングと機能開発は分ける

● 開発用にプレビュー版などを作るといいかも Product flavor

Page 46: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

第 3 部設計・実装

Page 47: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

継続して開発するために必要なこと

●古い API level の対応 Android Support Library 自前で実装

● 将来にわたってメンテナンスしやすい設計・実装 クラスの役割を明確に、クラス間の結合度を小さく 処理は共通化する Activity、Fragment を肥大化させない 複雑な処理はライブラリを作るなどして隠す 意図がわかるように (コメントやアノテーションなど)

Page 48: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

Android Support Library の互換機能

● B! アプリは現状 API level 10+ 対応● v7 appcompat library などが重宝●誰もが使っている機能

Fragment、AppCompatActivity、など● あまり使われてなさそうな便利機能

Drawable tinting など

Page 49: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

古い API level をサポートする自前の実装

● Support Library の実装を参考に●例えば ProgressBar の色変更

“android:progressTint” 的なもの ProgressBar のサブクラスを作って対応

●例えば影の実装 : “Build.VERSION.SDK_INT” で分岐 API level 21 以降で elevation それ未満では Drawable

●古い API level では諦めて何もしない場合も

Page 50: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

アノテーションによるサポート

● Annotations Support Library を使おう!● @Nullable/@NonNull● 各種リソース (@StringRes など)● @MainThread / @WorkerThread

整理されてない古いコードで便利

Page 51: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

Activity・Fragment を肥大化させない

Page 52: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

Activity や Fragment は肥大化しがち

● 各コールバックメソッドでいろいろな処理● View 操作を直接行いがち

setContentView メソッドや findViewById メソッドなどの存在

View 操作のためのクラスの準備が面倒● どこに書けばいいか迷うもの● 特定の Activity/Fragment でのみ必要な処理

Page 53: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

さらには同じような処理が分散

● Activity/Fragment 内に書かれた処理が別の場所でも必要になったら?

● 分離しづらいとそのままコピペされるなど●同じような処理が複数の Activity/Fragment

に存在!!!!●メンテナンスしづらい

Page 54: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

具体例

● Web ページ一覧のリスト項目のコンテキストメニュー 「あとで読む」 → 非ログイン状態の場合、ログイン画面に遷移し、ロ

グインして戻ってきた場合は 「あとで読む」 の HTTP リクエストを送信

● Activity/Fragment と密な部分 コンテキストメニュータップ時の処理

(onContextMenuItemSelected)

onActivityResult メソッド

Page 55: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術
Page 56: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

Activity や Fragment から処理を分離

Activity/Fragment

View / UI の処理

コールバックメソッド

ライフサイクルに応じた状態管理

その他何らかの処理

何らかの処理をするクラス

ユーザー入力

Page 57: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

Activity や Fragment から処理を分離

Activity/Fragment

View / UI の処理

コールバックメソッドライフサイクルに応じた状態管理

その他何らかの処理

ユーザー入力

(外に出した部分の設計しなおしも大事)

Page 58: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

コールバックメソッドからのメソッド呼び出し

● onCreate、onStart、onStop など●メソッド呼び出しを求められることが多い

広告とか● 問題

明示的に呼ぶ必要があるのは面倒 呼び忘れしやすい

Page 59: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

CallbacksAppComponents

● 自作ライブラリ Activity や Fragment のベースクラスを提供 各コールバックメソッドの呼び出しを受け付けるイン

ターフェイスを実装したオブジェクトを登録できる 登録しておけばベースクラスで勝手に呼んでくれる

● 各コールバックメソッドで種々の処理をする必要があるために Activity/Fragment から処理を分離しにくい問題を解決

Page 60: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

ベースクラスがコールバックメソッドを呼ぶ

Activity/Fragment

View / UI の処理

コールバックメソッド

ライフサイクルに応じた状態管理

その他何らかの処理

ユーザー入力

ベースクラス

Page 61: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

https://github.com/nobuoka/CallbacksAppComponents

Page 62: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

複雑な処理をライブラリにする

Page 63: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

複雑な仕様には複雑な処理を書く必要

● どんどん複雑になるページ一覧のリストの処理 リストをセクション分けする リストの項目を動的に追加していく リストの最後に何かを表示 (広告とか次ページ読

み込みボタンとか) 記事一覧のリストの途中 (10 件目とか) に 「お

すすめユーザー」 などを表示 → 厳しい!!!!

Page 64: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術
Page 65: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

複雑な処理をライブラリにする

● 複雑な機能は 2 つに分けて考える 機能に特化した部分 (扱うクラス・データ内容等)

汎用的で複雑な部分 → ライブラリ化● 複雑な処理はライブラリに押し込んでしまう● アプリケーションコードでは単にライブラリを使うだけ

Page 66: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

ComponentsRecyclerAdapter

●先の複雑なリストを実現するために作ったライブラリ● 複数の item view type の使用を容易に● 表示のためのデータ構造をコンポーネントの木構造に

コンポーネントでセクション分けしたり ベースのリストの途中に別のコンポーネントを指

し込むコンポーネント

Page 67: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

Components-RecyclerAdapter

ViewHolderFactory

Binder

Component

ViewHodleronCreateViewHolder

onBindViewHolderRetrieve item / item view type

Create

Component Component

Pass view holder and item

Domain model

Page 68: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

https://github.com/nobuoka/ComponentsRecyclerAdapter

Page 69: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

メンテナンスしやすいコードを書こう

● アノテーションと lint を活用● ドキュメントコメント● 設計を考える

Actvity/Fragment を肥大化させない 複雑な処理はライブラリにする などなど

Page 70: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

まとめ

Page 71: 5 年続く 「はてなブックマーク」 アプリを継続開発する技術

まとめ

● 継続して開発を続けるには?● コード変更を行いやすく・コード品質を高める

ソフトウェアテスト (自動化・フィードバック重要) リファクタリング (機能開発とは分ける) コードレビュー アプリケーションの設計・実装

● さらに、自動化 Gradle のタスクを書くところから始めよう