どうも、 try! Swift 2019 TOKYO で登壇したのにいまだにブログを書いてない @tobi462 です。
今回はすごく久しぶりに勉強会に参加してきたのでそのレポートです。 yj-meetup.connpass.com
Bonfire iOS は今回で5回目の開催で、今回は テスト がテーマということでした。
try! Swift でもProperty-based Testing / SwiftCheck で発表するくらい、テストの自動化に興味を持っているので、今回は絶対参加せねば・・・と思いブログ枠で参加させていただきました。
今回はキュレーターである @kumamo_tone さんのチョイスでYahoo!社内外のあわせて5名からの発表がありました。
テストは書かないと宣言していたアプリの現在
最初は @fromkk さんの発表でした。
メモ
- 振り返り
- 度重なる判断ミス
- アプリの開発うまくいってないかも
- Objective-Cでリニューアル
- テストは書かないという宣言
- MVCで突き進んだ
- これらをよい判断していれば
- 度重なる判断ミス
- やったこと
- アーキテクチャを VIPER に(新しい機能)
- 各レイヤを Protocol でつなぐ
- DI でオブジェクトを差し替えられるように
- チェッキング・テスティング
- チェッキング:すでに分かっていること(自明なこと)を検証
- テスティング;新しい情報を見つける(探検・発見・学習
- 今日はチェッキングで良いかも、という発表
- Xcodeの extension
- Swift Mock Generator
- 簡単にモックのコードを自動生成できる(Stub / Spy)
- サンプル1
- サンプル2
- delegate パターン
- UITableView とかも使われているパターンなので差し替えるだけで大丈夫
- クロージャのテスト
- Rxはテストしづらくて辛いかも(意見)
- delegate パターン
- タスクデー
- 2周間のうち1日を UX やバグ修正、リファクタリング
- 技術的負債を返す日
- 結果
- Swift:80%(90%以上かも)
- VIPER アーキテクチャでやってる
- テストコードが簡単に書けるようになった
- 課題
- Objective-Cのコードも残っている
- 古いコードにはテストが無いので不安
- 今後
- 品質向上委員会が発足中(有志で話し合う場所)
- E2Eテストの基盤構築
- QAの人たちも E2E テストが書けるようになったら。。
- 品質向上委員会が発足中(有志で話し合う場所)
- まとめ
- 判断ミスはあったが、タスクデーで負債返却
- アーキテクチャを刷新
- テストはチェッキングを集めに
- おまけ
- Bitrise
- Danger もつかってる
- UI テストも作っている(深夜で回している)
- TestSummaries -> S3 に画像をアップ
- Timers Meetup 1
- WWDC Pre Party やります!(仲間を集めましょう)
まとめ
実プロジェクトにおいて判断ミスによって苦しんだものの、タスクデーを使って技術的負債を返却していった結果、いろいろと改善したという発表でした。懇親会で本人ともお話させていただいたのですが、こうした実プロジェクトにおける失敗談(マイナス系の話)と、それに対してどういったアプローチをとったのかという話はとても貴重だと思いました。
個人的には Xcode extension の Swift Mock Generator を活用しているという話に興味を持ちました。前から気になっていたのですが触る機会がなかったので、今度ちゃんと試してみようと思います。
パフォーマンスチューニングとユニットテスト
続いて @shtnkgm さんの発表でした。
メモ
- ショッピング
- 2012〜
- 20万行
- ユニットテスト: 1800件(24%)
- 9名で開発している
- ロール
- 機能開発チーム
- 技術改善チーム
- パフォーマンス改善
- TOP画面
- アプリ起動から表示までの時間
- 平均 2.9秒 かかっていた
- 41%削減
- 動画:だいぶ早くなった
- ボトルネックの調査
- タイムプロファイラー
- Charls
- タブメニューに問題があった
- 動的に変更される
- フロー
- 複数の通信をしたあとにタブ表示(シーケンシャル)
- API通信の並列化+タブ表示も先に
- デメリット
- 複雑なコードになってしまう・・・
- 改修対象のクラスがすでに複雑
- TOP画面
- 現状
- 1700+ のFatVC
- ユニットテストなし
- どうした?
- 既存クラスを小さく切り出し
- ロジックを理解できる
- ユニットテストが書けるという単位
- 非同期通信とかも実装
- DI ができる構造に
- モックに差し替えることでテストしやすいように
- 例
- タブメニューの表示ロジックを整理
- 状態管理と通信クラスを分離
- Viewレイヤーのテスト
- 書きにくいけれど、不安があれば書く
- なぜテストしづらい?
- 出力が取得しづらい
- 表示完了をまつ必要がある
- TIPS
- アクセス修飾子を緩める
- 特定のViewクラスを取得する
- 表示完了の待機(waitUntil)
- ユニットテストが遅くならないように 1ms ごとに
- ユニットテストが通らない
- 手動テストだと大丈夫様な気がする
- Debug View Hierarchy
- タブが重なるような事象に陥っていた
- 原因
- サブビューの削除がうまく行ってなかった。
- StackView
- removeArrangedSubviews だとダメらしい
- removeFromSuperView を使うのが正しい
- 既存クラスを小さく切り出し
- 振り返り
- よかった
- ユニットテストを書きながらリファクタリングで、クリーンなコードに
- 手動テストの手戻りが少なかった
- 悪かった
- ログ送信が欠けててしまったことがあった
- ログ送信の前提条件を壊してしまった
- 送信データの取得が終わっていない状態でやってしまった。
- どうする?
- アサーションコード
- よかった
- まとめ
- パフォーマンス改善とリファクタリングはセットで
まとめ
アプリ起動からトップ画面の表示までのパフォーマンス(時間)を改善したという話でした。具体的にどういったフロー(手順)で改善を行ったのかが詳しく説明されていてとても良かったです。
話の本筋ではありませんが、removeArrangedSubviews
で正しく動かないというのは、まさに対称性のないAPIを用意した Apple に問題があるような気がしました・・・こんなの間違えたってしかたないレベルです。
なお失敗した点として、ログ送信が欠けてしまったという話がありました。個人的には、改修前のパターンでログ送信内容をキャプチャして記録しておき、改修後のもので同様のことをして比較する、みたいな方法でバグを検出するみたいなアプローチは出来たのではないかなぁと思いました。(もちろんリソース的なトレードオフもあったのかもしれません)
具体的な実務の話で、個人的にはとても面白い発表でした。
ポストモーテムやってみた
続いて @ktanaka117 さんの発表でした。
メモ
- ポストモーテムとは?
- 日本語では「検死」という意味
- 問題が収束して落ち着いた状態で、その事象を振り返る手法のこと
- 落ち着いた状態でやるのがポイント
- ルール
- 避難しない、責任追及しない
- 再発防止は仕組みで考える
- 事実と意見を分ける
- アイディアはやる・やらないにかかわらず
- 事例
- 一部のケースで購入できない事象が起こってしまった
- 解決のフロー
- とりあえず修正・リリース
- 最後にポストモーテムを入れてみた
- 事前に情報を集める必要がある
- GitHub Issue にラベルを付けた
- 同様の事象が過去にも発生していないか検証する、みたいな
- どうやってやる?
- ルールの説明
- 特定の個人を非難しない
- ポストモーテムの Issue を読み合わせ
- 原因考察
- ロジックが複雑かも
- 再発防止
- ロジックをきれいにリファクタリングできればなぁ
- 客観的な意見をもらえるので、建設的に振り返りが行える
- お疲れ様でした
- ルールの説明
- 気づき
- 曖昧な開発プロセスが明らかに
- なにをもってレビュー、テストしているの?
- 明文化されてなかった
- 人によって捉え方が違う状態
- エンジニアとして強くなるように
- 同じような間違いを繰り返さない
- 心理的に追い詰められる
- 視野は狭くなる
- 客観的に意見をディスカッションできることで、建設的に行える
- インシデント or バグ?
- 起こったときにどうするのか、というのも明確でなかったかもしれない
- 曖昧な開発プロセスが明らかに
- 注意すべき
- 避難しない・責任追及しない
- ちゃんとした改善にはつながらない
- テクニック
- 今回は慣れた人に司会をしてもらった
- 方向性に問題がありそうなら助言みたいな(スクラムマスターみたいな)
- 事実と水量と感情を切り分ける
- NVC
- 今回は慣れた人に司会をしてもらった
まとめ
テストや設計の話かと思いきや、今回は「ポストモーテム」という振り返りのテクニックの話でした。
個人的にこういう話はわりと好きで、建設的に議論・振り返りをするべきと言っても心理的に難しい部分を、こういった方法論で言語化・ルール化してうまくやるというのはとても良いと思いました。私もこういう失敗系には精神的にとても脆いタイプで、思考が反芻してまったく前向きな議論ができなくなるタイプなので、こういった振り返り方法はとても有効だと感じました。
ちなみにこれは余談ですが、この発表を聞いてふと思い出したのが GitLab の PostgresSQL データ消失の話です。やらかしてしまった彼(彼女かもしれませんが)は、そのあと「自分は今日、これ以上コマンドを叩くべきではない」と語ったそうです。人間、心理的に追い詰められた状態では冷静に考えられないので、そういった人間的制約を理解して、妥当なやり方を探るというのはとても大切だとあらためて思いました。
あなたがUIテストで評価したいのは何ですか?
次は @alligator_tama の発表でした。
メモ
- UIテスト
- 定義にブレはないだろうか?
- テスト
- 大量のキーワード、区別できますか?
- テスト
- テストに関わる用語も大量にある
- JSTQB で学べる
- テストピラミッド
- UI
- Service
- Unit
- UI テストをやりたい人?(質問)
- UIテストとは何か?
- XCUITest はすべてUIテスト?
- UIにフォーカスしたテスト?
- 評価したいのが画面・UIコンポーネントのみであればUIテスト?
- テストピラミッド
- 上の層に行くほど複雑さ・結合度が高い
- 定義
- UIをともなったテスト=UIテスト
- E2Eテスト
- ブロードスタックテスト
- システムテスト
- 総合テスト
- UIをともなったテスト=UIテスト
- 何をテストしたいのか?
- UIに対してテストをしたい(UI層のテスト)
- UIを伴うテストをしたい(E2Eテスト)
- XCUITest でなければ出来ないのか?
- コンポーネントが特定できればユニットテストでも出来る
- スクショを取りたい
- iOSSnapshotTestcase
- リファレンス画像と比較するタイプのライブラリ
- 全画面を取りたいみたいな感じであればこれをおすすめしてる
- 高速
- UnitTest なのでコンポーネントの差し替えも出来る
- View の変更の画像が載るので、PR とかで分かりやすい
- GitHub とかで差分の確認が出来る
- 様々な要因がテストしづらくする
- アプリ内部の状態変化
- launchArguments / launchEnvironment で設定できる(XCUITest)
- XCUIApplication のAPI
- launchArguments / launchEnvironment で設定できる(XCUITest)
- 外部システムとの連携
- 自分たちがコントロール出来ない
- モック・スタブ化
- OHHTTPStubs
- Embassy
- 注意点
- ユーザの操作からは遠ざかってしまう
- いったいどこをテストしたいのか?
- まとめ
- 容量用法を守って正しく使う
- 自分たちがやりたいテストは一体どこなのか?
- アプリ内部の状態変化
- UIテストはいつやる?
- ユニットテストからやっていく
- レガシーコードの改善のためにUIテストをやるってのはあり
- まとめ
- 言葉や定義はぶれがちなので軸を作る
- 基本をおさえた上でアレンジするのは問題ないと思う
- 効果的だと思うならやってみる、トライアンドエラーで改善すればいい
- 外部の人と話すときは、注意したほうがよいかもしれない。
まとめ
UIテストといった場合に何をテストしたいのか明確になっているのか、あるいはどこをテストしたいのか明確になっているのか、という話でした。
テストをせっかく書いたのに負債になってしまうというのはよく聞く話で、それは目的が明確になっておらず、テストを書くことが手段化してしまうというケースが多いかと思います。と、まぁこうやって言うのは簡単ですが、実際にそれをしっかりやるのは意外と難しいもので、自分が当事者の場合に客観的に状況を観るというのはとても難しかったりします。
今回の発表のようなそもそもの言葉の定義を考え直すことで、そういった客観的に状況をみるという訓練にもなるのではないかなと思いました。
Embedded frameworkを利用して既存プロジェクトでも爆速でTDD
最後の発表はヤフオク!の@shindyuさんの発表でした。
メモ
- TDD してますか?
- ヤフオクでは
- 2017から XP導入
- Swift:20万
- Objc:11万
- 改善するチームにいる
- TDD + ペアプロ
- Test 3500ケース以上
- ヤフオクでは
- XP
- ペアプロでチームの技術力向上
- コードレビューのストレスから解放
- TDDによる心理的安全
- TDD
- Red / Green / Refactor のリズムが大切
- ビルドやテスト実行時間が障壁になる
- ペアプロだと2倍かかっている
- どうやって解消した?
- Clean Architecture + Embedded Framework を採用
- 責務分割
- 最初は MVC でテストを誰でも書きやすい状況を作っていたが、課題解決のため
- 分割したモジュールを embedded framework に
- ビルド時間が短縮
- 差分ビルドも聞きやすくなる
- 結果
- Framework
- ビルド:18s
- 前テスト実行:1s
- Framework
- Clean Architecture + Embedded Framework を採用
- どうやってる?
- App / Domain で分割していた
- テストしやすいものを Domain においた(Presenter も含めた)
- 最近は Presenter から書くようになった
- やりかた
- Presenter のテストを書く
- Presenter のテストを通す
- ここまで Embedded Framework の中なのでとても早いサイクルで回せる
- UI / Presenter / Output をつなぐ
- UIEvent -> Presenter
- Output -> UI反映
- スキーマ切り替えのショートカットもある
- まとめ
- アーキテクチャ
- 爆速で TDD
- 開発効率も UP!
まとめ
TDDをより高速で回すために、Clean Architecture+Embedded Frameworkを採用したという話でした。
iOSアプリ開発においてビルドやテストの実行時間はつねに課題として挙げられますが、おそらく多くの方が試行錯誤している状況で、こういった具体的な数字を伴ったナレッジを聞くことができてとても勉強になりました。私はEmbedded Frameworkを活用した開発をしたことがないのですが、この発表を聞いてあらためて早く試してみたいという気持ちになりました。
ところでiOSアプリ開発ではユニットテスト実行のためにシミュレータの起動が必要である(=テストを実行するまでにワンテンポある)というのが課題だと思っており、その点をなんとか改善できないだろうかと思う今日このごろです。
懇親会
唐揚げが美味しかったです!
今回の勉強会のテーマではありませんが、最後の方でデザイナの方とお話する機会があり、デザイナがコードを書いたもののプログラマが納得いかない、といった実例を聞いたりして、こういった溝ってどうやったら埋まるんだろうなぁと改めて考えさせられたのがハイライトでした。
デザイナがせっかくコードを書いたのにエンジニアがクソコードと言ったという話を聞いたので、エンジニアが書く CSS なんてだいたいクソコードなんで安心してくださいって説明しておいた。(おぃ
— トビ@ペンギン村 - みんなで叶える物語 (@tobi462) March 26, 2019
え、これは冗談として言っただけなんだからね、勘違い(ry
おわりに
というわけで冒頭でも書いたとおり、久しぶりに技術系の勉強会に純粋な聴講者として参加したのですが、とても楽しかったです。私は自分の発表があると、どうも他の人の発表を集中して聞く余裕がなくなるので、しばらくはこうやって聴講者として参加してみるのもありかなと思ったりしました。
今回のイベントを企画および運営をしてくださったYahoo!の方々に感謝の意を示しつつ、まとめ記事を終わりにしたいと思います。
P.S.
なんだか久しぶりにイベントレポートを書いたせいか、全体的に文章が雑ですね(苦笑)