文系大学生がマッチングアプリをリリースしてみた

## アプリの概要

文系大学生が一人で**マッチングアプリ**を開発、リリースしてみました。（文系ですがプログラミングはバリバリにやってました。流石に未経験からいきなりマッチングアプリは無理です）

ダンスを学びたい人とダンスを教えたい人をマッチングさせるiOSアプリです。サービス名は**Dancy**です。名前は響きがいいので適当に決めました。
[詳細はこちら](https://apps.apple.com/jp/app/dancy/id1468729980)

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">Apple Storeで <a href="https://twitter.com/hashtag/dancy?src=hash&amp;ref_src=twsrc%5Etfw">#dancy</a> と検索！！<a href="https://twitter.com/hashtag/%E3%83%80%E3%83%B3%E3%82%B9?src=hash&amp;ref_src=twsrc%5Etfw">#ダンス</a> <a href="https://twitter.com/hashtag/%E3%83%80%E3%83%B3%E3%82%B5%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#ダンサー</a> <a href="https://twitter.com/hashtag/%E3%83%9E%E3%83%83%E3%83%81%E3%83%B3%E3%82%B0%E3%82%A2%E3%83%97%E3%83%AA?src=hash&amp;ref_src=twsrc%5Etfw">#マッチングアプリ</a> <a href="https://twitter.com/hashtag/dance?src=hash&amp;ref_src=twsrc%5Etfw">#dance</a> <a href="https://twitter.com/hashtag/dancer?src=hash&amp;ref_src=twsrc%5Etfw">#dancer</a> <a href="https://t.co/dNbJ0KILm3">pic.twitter.com/dNbJ0KILm3</a></p>&mdash; dancy -ダンスマッチングアプリ- (@dancy_matching) <a href="https://twitter.com/dancy_matching/status/1141614864898465792?ref_src=twsrc%5Etfw">2019年6月20日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

## 作ったきっかけ
元々自分はダンスをやったことはありません。クラブに行った時に少し踊る程度です。

ちょうどオンラインサロンでつよつよなポートフォリオを沢山見て「自分もなんか作りたいな」と思っていた時、ダンサーの友達から

「ダンサーのマッチングアプリあったら面白いんじゃね？　作れる？」

と言われたのでノリで作ってみることにしました。

友達から聞いた話によると、ダンサーを目指す人は経済的に不安定だったり、アルバイトで食いつなぐ人も非常に多い世界だそうです。**界隈で知名度のあるダンサーであっても月収が10万円代前半**というのも珍しくないそうです。

**「ダンサーがダンス一本で生活できる社会にする」**
**「日本でもっと広くダンスが受け入れられるようにする」**

という2つの目標を掲げて事業がスタートしました。お金もないのでとりあえず私がCTOになって開発を進めました。ポシャってもポートフォリオになりますしね。

## 開発フロー

エンジニアは他にいないので自分で作るしかありませんでした。

* 仕様の策定　2日
* AWSの設定とサーバーサイドの実装 2日
* 大まかなクライアントサイドの画面構築 3日
* デザインの作り込みと機能追加、課金処理 7日
* デバッグとストアへの申請 7日
* (＋α ユーザーの反応をもとに機能追加 7日)

途中で試験期間によって１週間休んでいますので、**開始から1ヶ月半**が経って今に至ります。当時やっていた長期インターンを辞め、毎日ファミレスにこもって開発していました。ユーザーからの反応に関しては後述します。

一応自分はエンジニアで、友達が代表兼マーケターなのですが、代表が就活で忙しいのでマーケティングにも口を出しながら動いてます。

## アプリの構成
フロントエンドはSwift（5.0）、サーバーサイドはAWSのLambdaを用いてNode.js(8.10.0)で書きました。Swift4のつもりで書いていたらいつの間にか5に設定されていました。ほとんど変わりませんけどね。

API Gateway + Lambda + DynamoDBという典型的なサーバーレスの構成です。
![AWS.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240900/b538579c-2ca9-ca44-e82b-d2e47309f672.png)

* 確認メールの送信のためにSES（Symple Email Service）
* 画像アップロードのためにS3
* 定期的なバックアップのためにAWS BackupとCloud Watch
* ユーザーアクセス管理のためにIAM

などを用いました。

### 使用したライブラリ

* Alamofire
* SwiftyJSON
* Stripe
* AWSCore
* AWSS3
* Cosmos

**Cosmos**は評価制度に使われるような星の画像を簡単に表現できるSwiftのライブラリです。下の図のように評価4.3などの中途半端な状態も表現することができます。

![cosmos.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240900/291c24cb-e8f2-7c6d-790e-b8a1d36c9b18.png)

## アプリ作成で大変だったこと、苦労したこと

#### 1.講師と生徒で処理を分ける必要がある
マイページ、レッスン一覧、トーク画面などほとんどの画面は講師と生徒で共通していますが、処理は当然分ける必要があります。正しく処理をしないとトーク画面で自分と相手の発言が入れ替わってしまうという現象が起こります。

コーディング量は倍にはなりませんが、デバッグするのが結構大変でした。**三項演算子**のありがたみを初めて実感しました。


#### 2.課金処理では絶対にミスができない
課金処理には**Stripe**を使いました。手数料も3.6%と割安で本番環境の手続きや実装も比較的楽にできました。課金が絡む以上、絶対に失敗はできません。DynamoDBではトランザクション処理が可能なので、レッスンテーブルと講師テーブルを同時に更新するときは非常に助かりました。

Stripeの公式ドキュメントの記述通りに書くと、入力されたセキュリティコードが誤っていても成功のレスポンスが返ってくるという問題があり、その部分を書き換えるのに苦労しました。

#### 3.ログインしていないユーザーも見れるコンテンツを作る
最初に会員登録を要求すれば便利なのですが、アップルの審査やファーストインプレッションのことを考えるとログイン前に講師の一覧画面を見られる方がいいという結論に落ち着きました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240900/fb6a2a15-7a25-c17e-01a2-555b21ab0baa.png"  width=50%>


ログインしていない状態でコンテンツを見せると思わぬnilが発生するので注意が必要です。


#### 4. キャンセルが発生するので処理が面倒
このアプリではレッスンにかかるお金は全てアプリ上で支払い、生徒と講師の間でお金の手渡しがないように設計しています。

ここでネックとなるのがキャンセル料です。Dancyでは講師がダンスのスタジオを予約した後、生徒都合でキャンセルを行なった場合、レッスン開始48時間前以降であればキャンセル料を発生させています。

しかし48時間以上前に生徒がキャンセルしても、スタジオ代のキャンセル料を講師が払う必要があります。そこでトーク画面にスタジオ代の請求を行う画面を設け、お互いの合意の上でキャンセル料を生徒に負担してもらう仕組みを作成しました。

レッスンの状態を以下の7つに分けて保存しています。

* 1.講師の承認待ち（リクエストしただけ）
* 2.承認済み（レッスン終了時刻より前）
* 3.決済待ち（レッスン終了時刻を過ぎている）
* 4.先生の直前キャンセル
* 5.生徒の直前キャンセル
* 6.レッスン開始４８時間より前のキャンセル
* 7.トラブルにより運営の判断で解決

キャンセルがなければ結構楽なんですが、キャンセルが入るだけで場合分けが面倒くさくなりますね。

男女のマッチングアプリなら勝手に会ってくれって感じですが、ダンスのマッチングはアフターフォローが必須です。

#### 5.DynamoDBには予約語が多くて面倒
DynamoDBには予約語が多くて面倒でした。属性名が予約語の場合、DynamoDBではエラーが出ないのですが、Lambdaの実行時にエラーが出ます。

name,regionなどプロフィールで使いたかった属性名が予約語に入っていたのでやり直しに。

* 属性名の置き換え
* 属性名を変更する

の2つの方法があったのですが、DynamoDBはスキーマレスなので属性名を変更して対応。その分フロントエンドを書き換える必要があって大変でした。

## DynamoDBの設定をミスって1万円請求された
DynamoDBの料金体系には「オンデマンド」と「プロビジョニング」の２種類があります。

プロビジョニングでは、アプリケーションに必要と予想される 1 秒あたりの読み込みと書き込みの回数を指定します。Auto Scaling を使用すれば、指定した利用率に応じてテーブルのキャパシティーが自動的に調整されます。

反対にオンデマンドではテーブルに対して実行された読み込みと書き込みの数に応じて課金がなされます。

１秒間に何回もアクセスされることがないデバッグ段階では、オンデマンドにしておくのがベストです。自分は何も設定がわからず、プロビジョンドのオートスケールを選び、最小のRCU,WCUを40などと設定していたので、1万円近い請求を食らいました。

DynamoDBのストリームからのストリーム読み込みリクエスト250 万回までは無料枠があるので、デバッグの段階ではオンデマンドにしておくのが良いでしょう。


## アップルの審査を通す時に気をつけたこと

マッチングアプリは審査を通すのがとても大変で、20回以上リジェクトされたなんて話を聞いていました。最初はダメ元で申請したのですが、**一発で通ってしまいました**。
本当はなぜリジェクトされたのかをまとめるつもりだったのに...。

最初に申請したところ、以下の3つの質問をアップルからされました。

* 悪質なユーザーをどのように排除するの？
* 決済はどのように行われるの？
* 講師と生徒は実際に会うのか？

英語と日本語をの双方で回答を送ったら、審査が通っていました。ちょっと拍子抜けです。

具体的に気をつけたのは以下のことです

* 問い合わせ機能を作り、アップルには24時間以内に必ず対応をとると約束
* 決済にはStripeを使うことをアップルへの説明で明示する
* 利用規約と悪質ユーザーへの対処法について目立つところに明示
* 使い方ガイドや利用規約を登録する前から見えるようにしておく

男女のマッチングアプリに比べれば、比較的審査は緩いのでしょう。悪質なユーザーの通報ボタンがまだないのに、審査に通ったのでビックリです。（すぐにアップデートで追加しました）

## ユーザーからの反応まとめ

* とりあえず発想が面白い
* **すごい**（多数）
* 面白そうだから今度一緒に飲み行こう（fromダンス関係の人）

ダンサーの友達がストーリーで拡散してくれました。インスタの拡散力は素晴らしいですね。

* ログアウトすると自分のプロフィールが消えてしまうので何とかして欲しい
* **お気に入り機能が欲しい**
* ログインがどこからかわかりにくい
* 生徒の自己紹介を見たい
* 自分以外の講師のプロフィールを見て参考にしたい
* **自己紹介を全く書いていない生徒からレッスンリクエストがきて怖い**

リリースしてみると思わぬ反応が飛んでくることがあって勉強になります。**マッチングアプリって普通はログアウトしない**ものなんですが、講師も生徒も両方やりたいとか、他の講師のプロフィール見たさにログアウトする人が沢山居て驚きました。

当初は「気になった講師がいればすぐにチャットするからお気に入り機能なんていらない」と思っていましたが、実際使ってみるとチャットするのって勇気がいるんですよね。Wantedlyで「話を聞きたい」ボタンを押すのをためらうのと同じです。要望に合わせて**ブックマーク機能**をつけました。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/240900/a0b67862-58d9-0ff3-2383-124a759c8683.png" width=50%>

また、講師にとってはどこの馬の骨ともわからない人からのメッセージは怖いもの。写真と表示名を設定しないとトークができないように修正をし、生徒のプロフィール画面を新設しました。

## まとめと所感
AWSを本格的に使うのは初めてでしたが、使ってみると何とかなるものです。通常のインプットより、アウトプットからのインプットからの方が効率が良いというのを強く実感しました。

今まではUdemyをみながら一部を写経してポートフォリオを作ることがほとんどでしたが、今回で公式ドキュメントを丁寧に読む癖がつきました。

トーク画面では双方向通信とか入れてみたかったんですが、開発コストを考えてひとまず断念しました。そのうち**Realm**とかも入れて検索を高速化したいと思います。

３週間ほぼ誰とも話さず家にこもって開発していると頭がおかしくなりそうでした。久しぶりに人に会った時にろくに会話ができずに困りましたね。

半年前にリリースしたアプリは

* ナビゲーションコントローラーの使い方もわからず
* オートレイアウトも使えず
* Firebaseで単純な配列をscanするだけ
* 色合いもめちゃくちゃ
* Fat ViewController 

だったので、この半年でずいぶん成長したなあと感じます。

## 最後に


ダンスに特化したマッチングアプリは恐らく日本で初めてです。人脈の広い知り合いが、有名なダンサーをどんどん勧誘しているので、是非使ってみてください。

[詳細はこちら](https://apps.apple.com/jp/app/dancy/id1468729980)

技術的な詳しいアウトプットについては別記事にまとめる予定です。

## 追記
Android版をリリースしました。是非使ってみてください！
[Google Playへ](https://play.google.com/store/apps/details?id=dev.tanaka.dancy)