Slide 1

Slide 1 text

チュートリアル実装の 『そこどうしてる?』 Poiboyではこうしてる! マッチングの裏側Night #1 2018/09/28 @imaizume

Slide 2

Slide 2 text

<2 INDEX • 自己紹介 • Poiboyについて • Poiboyのチュートリアルと実装解説 1.男女で画面のViewController分けるか問題 2.実装をライブラリでやるか自前でやるか問題 3.デバッグどう/どこまでやるか問題

Slide 3

Slide 3 text

<3 INDEX • 自己紹介 • Poiboyについて • Poiboyのチュートリアルと実装解説 1.男女で画面のViewController分けるか問題 2.実装をライブラリでやるか自前でやるか問題 3.デバッグどう/どこまでやるか問題

Slide 4

Slide 4 text

‣ 今泉 智博 @imaizume ‣ 2017年株式会社ミクシィ新卒入社 ‣ 現在株式会社 所属 ‣ iOS利用経験0から iOS版開発担当に ‣ (ほぼ)毎日健康COMP生活はもうすぐ1周年

Slide 5

Slide 5 text

<5 INDEX • 自己紹介 • Poiboyについて • Poiboyのチュートリアルと実装解説 1.男女で画面のViewController分けるか問題 2.実装をライブラリでやるか自前でやるか問題 3.デバッグどう/どこまでやるか問題

Slide 6

Slide 6 text

とは❓

Slide 7

Slide 7 text

Diverseが運営する カジュアルマッチングアプリ❤

Slide 8

Slide 8 text

最⼤の特徴 = ⼥性主導 女性からの「いいね = ポイ」でマッチング成立 男性はポイされた後に初めて返信できる ねらい マッチングアプリを初めて使う女性にも 安心して使ってほしい ポイ メッセージ

Slide 9

Slide 9 text

今⽇の内容: Poiboyチュートリアルの実装⽅針 実装で直面する疑問・課題とPoiboyでの実装例を紹介 3つのテーマで実装の「そこどうしてるの?」を解説 ウォークスルー 登録前/登録後 チュートリアル プロフィール 登録 今日話すところ Poiboyのチュートリアル構成 SNS認証 登録前チュートリアル プロフィール登録 登録後チュートリアル ウォークスルー 本使用

Slide 10

Slide 10 text

<10 INDEX • 自己紹介 • Poiboyについて • Poiboyのチュートリアルと実装解説 1.男女で画面のViewController分けるか問題 2.実装をライブラリでやるか自前でやるか問題 3.デバッグどう/どこまでやるか問題

Slide 11

Slide 11 text

テーマ1: チュートリアルの画⾯ (ViewController)を男⼥で分けるか問題

Slide 12

Slide 12 text

男⼥の画⾯どうやって分けてる?? • 男女でUI/ロジックが似ている画面をどうするか問題 • 男女ではなく登録経路で分かれることも… • プラットフォームで仕様が異なるケース(今回は割愛) ⽅針: A.共通化 / B.分離 Facebook (左) と Twitter (右) 男性 (左) と ⼥性 (右)

Slide 13

Slide 13 text

A. なるべく共通化する • 男女/登録経路で共通のVCを使用 • 内部Viewの表示切替え • 共通化が有効そうな場所 • ログイン画面 • プロフィール登録画面 • 見た目が似ているUI // 画像切り替え self.banner.image = isMale ? maleBannerImg : femaleBannerImg self.user.image = isMale ? maleUserImg : femaleUserImg self.example.image = isMale ? maleExampleImg : femaleExampleImg // 制約切り替え self.maleContraint.priority = isMale ? .defaultHigh : .defaultLow self.femaleContraint.priority = !isMale ? .defaultHigh : .defaultLow 男⼥共通のVC

Slide 14

Slide 14 text

B. なるべく分離する // MARK: ViewController出し分け if isMale { // 男性 let vc = MaleRegisterViewController() self.present(vc, animated: true) } else { // 女性 let vc = FemaleRegisterViewController() self.present(vc, animated: true) } • 男女/登録経路毎のVCを定義 • VC自体を表示制御 • 完全分離が有効そうな場所 • 性別に固有の体験 • Viewや状態数が多い • UIや仕様変更が見込まれる 男性VC ⼥性VC

Slide 15

Slide 15 text

共通化 VS 分離メリデメ A. 共通化 B. 分離 ✂ メリット • DRYな実装がしやすい • Viewの構築時間を短縮可 • ロジックの可読性が向上 • 画面単位の仕様変更に強い デメリット • VC内のロジックが複雑化 • コードでの状態変更 • UIのバグ発見・再現が困難 • WETな実装になることがある • ファイル数が増える • 同一変更でも複数箇所修正 場面毎に考えて方針を選んでも良いが 原則の方針は決めておきたい

Slide 16

Slide 16 text

Poiboyではこうしている! VC内ロジックの簡素化を重視 (以前は共通化したVCで条件分岐が増え 男女間の表示バグが多発していた) VC単位で分離するケースが増加 self.view1.hidden = false if isMale { // 男性 self.view2.hidden = false self.view.text = " " } else { // 女性 self.view2.hidden = true self.view.text = " " if isOk { self.view3.height = 80 } } 男⼥共通VC self.view1.hidden = false self.view2.hidden = false self.view.text = " " 男性⽤VC self.view1.hidden = false self.view2.hidden = true self.view.text = " " if isOk { self.view3.height = 80 } ⼥性⽤VC

Slide 17

Slide 17 text

UI上のバグの発⾒/再現性 片方に実装を忘れる → バグの発見・再現が容易 コードでの状態変更 → バグの発見・再現が困難 現在の課題: VCの名前に統一性がないため、新メンバーが把握に時間がかかる 画⾯遷移テストの書きやすさ /// 性別選択で女性を選択後に女性用ウォークスルー画面が表示される func testNavigationToFemaleWalkThrough() { let navigator = NavigatorMock() let isBetaUser = false let vc = GenderRegisterViewController( navigator: navigator, genderStore: GenderStoreStub(isFemale: true) ) ) vc.tapFemaleViewAction() XCTAssertTrue(navigator.viewControllerStack.first is FemaleWalkThroughViewController) }

Slide 18

Slide 18 text

具体例 (プロフィール登録画⾯) 男女共通に見えるが実は完全に別のVC • 画面上部のバナーパターンが増えても大丈夫だった • 前後のVCを増減しても影響が少なかった 男性登録画⾯ ⼥性登録画⾯ バナーが増えて もバグは出ない 女性側よりも 遅れて実装 制約の付け替え が不要に 細かい文言等の 違いも一目瞭然

Slide 19

Slide 19 text

<19 INDEX • 自己紹介 • Poiboyについて • Poiboyのチュートリアルと実装解説 1.男女で画面のViewController分けるか問題 2.実装をライブラリでやるか自前でやるか問題 3.デバッグどう/どこまでやるか問題

Slide 20

Slide 20 text

テーマ2: チュートリアルの実装 ライブラリを使うか⾃前で頑張るか問題

Slide 21

Slide 21 text

チュートリアル画⾯をどう作るか ?? • 登録後ユーザーが必ず表示する画面 • Poiboyではウォークスルーとコーチングの組合せ • 特にコーチングは自前実装そこそこ面倒 ウォークスルー コーチング ⽅針: A. ライブラリ / B. ⾃前

Slide 22

Slide 22 text

チュートリアル⽤ライブラリ • ライブラリもかなり充実 (調べて初めて知った) • 複雑なウォークスルーはRazzleDazzleがよさそう • UIがテンプレベースのため既視感が強い • 比較/詳解はtakatattaさんのスライドもご参考に • ephread/Instructions • aleksandrshoshiashvili/ AwesomeSpotlightView • ruipfcosta/SwiftyWalkthrough • teodorpatras/EasyTipView • ariok/BWWalkthrough • hyperoslo/Presentation • ealeksandrov/EAIntroView • MatthewYork/MYBlurIntroductionView • IFTTT/RazzleDazzle ウォークスルー コーチマーク

Slide 23

Slide 23 text

ライブラリ VS ⾃前メリデメ ライブラリへ完全依存したくないが完全自前も厳しい… A. ライブラリ B. 自前 メリット • 導入・メンテの工数少ない • OS/端末ごとの動作保証あり • 複雑な仕様やUIにも対応可 • アクション制御も自在 デメリット • アプリへの最適化に限度 • テンプレ的なUI/UX • デザイン次第で工数大 • メンテコストも大

Slide 24

Slide 24 text

Poiboyではこうしている! ライブラリ:自前 = 2:8 くらいのハイブリッド • ウォークスルー: 完全自前実装 • 仕様変更が多い • ボタン配置やUIも最適化したい • チュートリアル: 自前 + 一部吹出しにCMPopTipView • 指定の矩形をくり抜くカスタムViewで実装 • CMPopTipViewの吹出しを加えてコーチング • CMPopTipViewは画像等を含むことができない CMPopTipViewの吹き出し 画像の吹き出し

Slide 25

Slide 25 text

単純なコーチングの実装例 • コーチマークVCを定義、各ステップでpresent • UIBezierPathでマスクを切り抜き ベースのVC コーチングのVC チュートリアル var rects: [CGRect] = [self.rect1, self.rect2, self.rect3] self.setupMaskView(rects: &rects, isCircle: true) // 複数矩形の切り抜きにも対応できるよう配列で定義 let paths: [UIBezierPath] = rects.map { Helper.rectToSquarePath($0) } let maskLayer: CALayer = self.maskView.generateLayer(paths) self.maskView.layer.addSublayer(maskLayer) CGRect ↓ UIBezierPath この3つの合計で スコアが変動するよ タップして次へ self.present

Slide 26

Slide 26 text

複雑なコーチング (連続した動作制御) ステップ数少 →UIView.animateまたは Promiseをチェーン ステップ数多 →closureのスタックを用意 stack.popで実行する

Slide 27

Slide 27 text

複雑なコーチング (カードフリック) • チュートリアル用のViewにカードを重ねる • DataSourceから上2枚分のカードをコピーしDI • カードUIはカスタムView実装 • 動きも忠実で実際のデータなので使用感が出る DataSource CardView x2 CardContainerView view.animate self.showPopTip 上に重ねる アニメーション

Slide 28

Slide 28 text

本当はもっとこうしたい • VCの名称に一貫性がない(新人が覚えるの大変) • メンテ大変なので実装やステップを簡略化したい • 男女やプラットフォーム間の差をなくしたい • アニメーションを滑らかに (lottieの活用とか) • 現在CMPopTipViewはノーメンテ→EasyTipViewを推奨

Slide 29

Slide 29 text

<29 INDEX • 自己紹介 • Poiboyについて • Poiboyのチュートリアルと実装解説 1.男女で画面のViewController分けるか問題 2.実装をライブラリでやるか自前でやるか問題 3.デバッグどう/どこまでやるか問題

Slide 30

Slide 30 text

テーマ3: デバッグどう/どこまでやるか問題

Slide 31

Slide 31 text

チュートリアルのデバッグ⼤変問題 • 初日体験は大切なので重点的にデバッグしたい • でも全ての動作/表示のチェックは大変 • 特に登録条件(状態)が多いと大変 • (Poiboyは男女 x 登録導線で4パターン) ⽅針: A.⾃動(UI/Unitテスト) VS B. ⼿動(Beta)

Slide 32

Slide 32 text

Poiboyではこうしている! • XCUITestで登録完了までの一連スクショを自動撮影 • Firebase AuthのSMS認証にデバッグアカウントを作成 手動デバッグ中心だが作業負荷の軽減にチャレンジ中

Slide 33

Slide 33 text

XCUITestでの起動から登録までのスクショ撮影 XCUITestのスクショ自動撮影を利用 • エンジニアが全ケースを網羅できず • QAまで表示崩れを把握不可 これまで 改善後 XCUITestでの Facebookログイン • 正常系の表示確認を簡略化 • 対象端末を絞り手動確認も継続

Slide 34

Slide 34 text

Firebase Auth でSMS認証にデバッグ⽤ FacebookやTwitter認証はログインが面倒 • PoiboyではSMS認証に Firebase Authを使用 • 任意の電話/PIN番号を 登録可能 • 最大10件まで登録可能 • なので番号を専有して も大丈夫 • 入力がかなり楽になる

Slide 35

Slide 35 text

(おまけ) 電話番号の⾖知識 実在しないけど入力が簡単な電話番号は? 携帯電話番号の規格では “0X0-0000-XXXX”等の形式なら任意の番号で実在しない❗ 番号を追加する際はご注意を http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/number_shitei.html

Slide 36

Slide 36 text

本当はこうしたい • XCUITestが認証でコケる問題 • 他の正常系でのスクショ撮影 • XCUITestよりもFastlane? • レポートの定期的な書き出し • iOSSnapshotTestCaseで画像比較 できたらなお良し 性別選択で落ちた 認証が問題だった

Slide 37

Slide 37 text

まとめ: Poiboyではこうしてる! テーマ1: チュートリアルの画面分け なるべくVC単位で分離しバグを減らしている! テーマ2: チュートリアルの実装どうやるか 自前実装メインで最適なUIを実装している! テーマ3: デバッグどう/どこまでやるか問題 手動デバッグの負荷軽減にチャレンジ中!

Slide 38

Slide 38 text

参考資料 Poiboy iOS https://itunes.apple.com/jp/app/poiboy-ポイボーイ/id1028982003 導入画面を実装したよ @takattata https://speakerdeck.com/takattata/dao-ru-hua-mian-woshi-zhuang-sitayo 総務省|電気通信番号の利用・指定|電気通信番号指定状況 http://www.soumu.go.jp/main_sosiki/joho_tsusin/top/tel_number/ number_shitei.html