Firebaseを使ってアプリをグロースさせていこう！

#はじめに
新卒入社時からスマホゲーム開発を行っておりましたが、今年よりiOS開発に転向したgiiiitaと申します！

今年からFirebaseを触る機会が多くなり年の締めくくりとして
今年学んだことのアウトプットとして[Firebase Advent Calendar 2018](https://qiita.com/advent-calendar/2018/firebase)の11日目を担当させていただきます！

#今回の記事について

Firebaseには、FireStoreやAuthentication,Functionsなどアプリ開発に必要な多くの機能が備わってますよね！

Firestoreにデータが入ったことをトリガーにAlgoliaにデータを流すfunctionを書くなど
Firebaseが提供するサービス間の連携が可能なのもFirebaseの強みの一つかと思います。

開発の助けとなる機能が目立つFirebaseですが、
実はアプリをグロースさせるためのサポートをしてくれるサービスもFirebaseが提供していることはご存知でしょうか？

そこで今回はFirebaseのグロースをサポートしてくれるサービスのうちの一つA/BTestingについて書いていこうと思います！

#A/B Testingとは？

Firebaseが提供するABTestを行うためのサービスです。
主な機能として以下4つが公式で挙げられております。
・製品の使用体験をテスト
・Notifications Composer を使用してユーザーに再度アプローチする方法
・新機能を安全にロールアウト
・予測に基づいてユーザーグループのターゲットを設定

個人的に気になっているのは
予測に基づいてユーザーグループのターゲットを設定です！
Predictionsでどれほどユーザの行動を予想する精度があるのか気になってます笑


**仕組みのイメージ**
<img width="739" alt="スクリーンショット 2018-12-11 11.49.36.png" src="https://qiita-image-store.s3.amazonaws.com/0/75593/144814b7-6f6c-7fb1-d531-fc6c9f58a039.png">


#Firebaseを使って考えられるABTestを行う方法

### FirebaseのA/BTestingだけを使用する

以前Qiitaにまとめてみましたので以下記事を参考していただけると幸いです。
※最近A/BTestingのUIとは異なる部分がありますのでご了承くださいmm
[目標指標に定義したAnalyticsEventを使用しFirebaseでA/BTestを行う手順(iOS向け)](https://qiita.com/giiiita/items/e2e5230aa786cd8d678e)

### FirebaseのRemoteConfig + 外部サービス(Repro等)
大まかな説明として、Firebase側で行うことは**RemoteConfigの設定**です。
RemoteConfigを設定しその値で外部サービスに通知する内容を分けるというものです。

### RemoteConfigの設定


![スクリーンショット 2018-12-11 8.21.13（2）.png](https://qiita-image-store.s3.amazonaws.com/0/75593/04f3a13c-1b67-e173-d593-a96c0b6cb093.png)

![スクリーンショット 2018-12-11 8.21.26（2）.png](https://qiita-image-store.s3.amazonaws.com/0/75593/dfe64388-61ac-3ad7-8db3-99591c462e58.png)

![スクリーンショット 2018-12-11 8.22.00（2）.png](https://qiita-image-store.s3.amazonaws.com/0/75593/350a9482-e5ed-e7fd-f4a6-b6aafc12e01b.png)

![スクリーンショット 2018-12-11 8.22.04（2）.png](https://qiita-image-store.s3.amazonaws.com/0/75593/0cb1ffa2-a541-bff0-569d-6a06b608d24a.png)

### 挙げた二つの方法の違い
考えられる違いを列挙してみました。
・テスト経過、結果の表示画面UI
・テストをサポートする機能


#ABTestを行う時にRemoteConfigで気をつけていること

### テスト対象のViewでRemoteConfigのfetchを行わないようにすること
なぜかというと
RemoteConfigから値を取得する初回はキャッシュがなく少し時間がかかるためです。

もう少し具体的に例を出して説明してみますと、
UserGroupAには赤色のボタン(試したいパターン)
UserGroupBには緑色のボタン(通常)

テスト対象のViewでfetchを行う場合
RemoteConfigの値の結果、ボタンを赤色に変える必要があった場合
ユーザがテスト対象のViewを表示し緑色のボタンが表示されていたが、ボタンの色を赤に変える必要があるためパッと赤色に切り替わってたように感じます。
これはremoteConfigのfetch完了後にボタンの色を切り替える以下のような実装になっているためです。

2回目からはキャッシュがあるのでパッと赤色に切り替わることないのですが、1回目の挙動はユーザに不信感を与えかねません。

```ViewController.swift
import UIKit
import FirebaseRemoteConfig
class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    override func viewDidLoad() {
        super.viewDidLoad()
        let remoteConfig = RemoteConfig.remoteConfig()
        let expirationDuration: TimeInterval = 3.0
        remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
            if status == .success {
                print("Config fetched!")
                remoteConfig.activateFetched()
                let isTestUser: Bool = remoteConfig["register_button_test"].boolValue
                if isTestUser {
                    self.button.backgroundColor = UIColor.red
                }
            } else {
                print("Error: \(error?.localizedDescription ?? "No error available.")")
            }
        }
    }
}
```

## 改善案
そこで、以下の改善案を提案します！

### RemoteConfigを事前にfetchしておく

```AppDelegate.swift
    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        FirebaseApp.configure()
        let remoteConfig = RemoteConfig.remoteConfig()
        let expirationDuration: TimeInterval = 3.0
        remoteConfig.fetch(withExpirationDuration: TimeInterval(expirationDuration)) { (status, error) -> Void in
            if status == .success {
                print("Config fetched!")
                remoteConfig.activateFetched()
            } else {
                print("Error: \(error?.localizedDescription ?? "No error available.")")
            }
        }
        return true
    }
```

keyを渡せば対応するRemoteConfigのvalueを返してくれるようにする

```FirebaseRemoteConfig.swift
import Foundation
import FirebaseRemoteConfig

enum FirebaseRemoteConfigBoolParameter: String {
    case registerButtonTest = "register_button_test"
    
    var defaultValue: Bool {
        switch self {
        case .registerButtonTest: return false
        }
    }
}

class FirebaseRemoteConfigBoolParameterStore {
    func value(forKey param: FirebaseRemoteConfigBoolParameter) -> Bool {
        let remoteConfig = RemoteConfig.remoteConfig()
        remoteConfig.setDefaults([param.rawValue: param.defaultValue as NSObject])
        return remoteConfig[param.rawValue].boolValue
    }
}
```

テスト対象のViewで適切なkeyを渡してボタンの色を切り替える

```ViewController.swift
import UIKit
import FirebaseRemoteConfig
class ViewController: UIViewController {

    @IBOutlet weak var button: UIButton!
    override func viewDidLoad() {
        let isTestUser: Bool = FirebaseRemoteConfigBoolParameterStore().value(forKey: .registerButtonTest)
        if isTestUser {
            self.button.backgroundColor = UIColor.red
        }
    }
}
```

簡単なプロジェクトではありますが、一様サンプルのせておきます！
[A/BTesting](https://github.com/yotsu12/ABTesting)


#おわりに

Firebaseが提供数アプリのグロースをサポートするサービスA/BTestingについて今回この場を借りて記事にさせていただきました。

仮説を検証する際に迅速にテストを行う環境としてFirebaseのA/BTestingを用いることは良いと思いますが、ABTestを行うことはあくまで手段でありコンテンツのどこをどのようにテストしどの数値を伸ばしたいのかを決めることが重要だと思っております！

また、各社のグロース施策で成功、失敗談があればぜひ聞きたいな〜とも思ってたりします！

最後に僕自身もまだまだ勉強中ではありますが、参考になったサイトと本を共有させていただきます！
[Hacking Growth　グロースハック完全読本](https://www.amazon.co.jp/Hacking-Growth-%E3%82%B0%E3%83%AD%E3%83%BC%E3%82%B9%E3%83%8F%E3%83%83%E3%82%AF%E5%AE%8C%E5%85%A8%E8%AA%AD%E6%9C%AC-%E3%82%B7%E3%83%A7%E3%83%BC%E3%83%B3%E3%83%BB%E3%82%A8%E3%83%AA%E3%82%B9-ebook/dp/B07HXKFQWQ/ref=sr_1_2?s=digital-text&ie=UTF8&qid=1544502915&sr=1-2&keywords=%E3%82%B0%E3%83%AD%E3%83%BC%E3%82%B9%E3%83%8F%E3%83%83%E3%82%AF)

[growthhackers.com](https://growthhackers.com/)

[VASILY GROWTH HACK BLOG](http://growthhack.vasily.jp/)