【個人開発】プレゼントキャンペーンを開けるWebサービスをサーバレスで作ってみた

# まえがき
以前に[初心者3人でwebサービス(webアプリ)を作ったので、立ち上げからリリースまでを時系列に書いていく](https://qiita.com/yuno_miyako/items/d6595719ae7065927499)という記事を書かせていただきました。
今回は、前回の失敗を踏まえてサービス作りを考えて実装してみました。
それがTwitterでプレゼントキャンペーンを開ける「**プレキャン**」というサービスです！

![DvlzG2iVsAEa1yq.jpg](https://qiita-image-store.s3.amazonaws.com/0/234396/7ff85fa8-0d86-1c3d-9b1a-aff6f25e64cf.jpeg)

今回の記事は雑多な内容になりますので、目次から**気になるものだけ**をつまみ食いしてお読みください。各項目の内容は独立していますので、どこから読んでいただいても大丈夫です。

## 目次
１、[前回の反省点と、プレキャンを作ろうと思ったきっかけ](#前回の反省点とプレキャンを作ろうと思ったきっかけ)
２、[サービス内容](#サービス内容)
３、[試しにプレゼントキャンペーンに応募してみて](#試しにプレゼントキャンペーンに応募してみて)
４、[「RTしたらすぐくる」を実現する技術](#rtしたらすぐくるを実現する技術)
５、[TwitterAPI制限への対応](#twitterapi制限への対応)
６、[キャンペーン終了後に再抽選](#キャンペーン終了後に再抽選)
７、[dynamoDB + lambda開発で採用したプラクティス](#dynamodb--lambda開発で採用したプラクティス)
８、[システムの応用](#システムの応用)
９、[最後に](#最後に)

## 前回の反省点と、プレキャンを作ろうと思ったきっかけ
　前回作ったwebサービスはざっくりというと、**「宣伝してくれたらお返しをあげる」**というサービスでした。[初心者3人でwebサービス(webアプリ)を作ったので、立ち上げからリリースまでを時系列に書いていく](https://qiita.com/yuno_miyako/items/d6595719ae7065927499)は**20000Views**と多くの人に見ていただけたのですが、実際にwebサービスにアクセスしてくれたのは約2000人、登録してくれた人が約200人、そして**実際に投稿してくれた人は20人ほど**、という感じでした。。
　使っていただいた方の声では、「何ができるのか分かりにくい」「使いどきがわからない」「そもそもサービスそのものが悪い」等のご意見をいただき、初めてのwebサービス作りでしたが個人的には失敗だったと思っています。お返しとして用意できるのは画像や文章だけなので、それ欲しさでわざわざ宣伝したいとは思わないですよね。

　そこで私は考えました。じゃあ何が貰えたら人は宣伝をしてくれるだろうか？やっぱりもらって嬉しい**お金**が必要なのか。でも宣伝してくれた人全員にお金をあげることはできない。じゃあ**宣伝してくれた人のうち抽選で何人かにAmazonギフト券をあげることくらいならできる**んじゃないだろうか。

ということで生まれたのが**プレキャン**です。

## サービス内容
**「RTした人の中から抽選でn名に〇〇が当たる」を個人でも作れるサービス**です。このサービスの強みは主に次の４つです。

１、RTしたら**すぐに結果が届く**(本当にすぐです！）
２、Amazonギフト券の**送付まで全部自動**！
３、当選者、外れた人の**一覧が見れて安心**！（一言メッセージもつけられる！）
４、不正なアカウントの**排除**(捨て垢判定機能)

図: 当選者や外れた人の一覧
![IMG_2604.JPG](https://qiita-image-store.s3.amazonaws.com/0/234396/be42e421-479b-8a1c-1305-2565b13e5779.jpeg)
<img width="375" alt="IMG_2605.PNG" src="https://qiita-image-store.s3.amazonaws.com/0/234396/3b27932e-2e9c-f4e6-2dd2-731e76b7db04.png">

最近、企業がRTして応募完了タイプのプレゼントキャンペーンをやることが多くなりました。しかし個人がやるには敷居が高いので、ぜひともうちのシステムを使ってプレゼントキャンペーンを開いてもらえたらなーと思います。
興味がある人は以下のリンクから連絡いただければと思います！
https://adapp9.com

## 試しにプレゼントキャンペーンに応募してみて
**「RTしたらすぐ結果がくるプレゼントキャンペーン」**と説明してもイマイチ理解できない人も多いと思うので、聞くよりぜひ**体験**していただきたいです。下のツイートを**「フォローしていいね」**をしてみてください(RTよりもいいねの方が気軽でしょ？）。それだけで応募が完了して結果のDMが届くと思います。実際にAmazonギフト券が当たるかもしれないので、やらねば損です！！

<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr">いいねするだけでAmazonギフト券が当たる！とりあえずポチッといいねを押してみて！<br><br>応募方法<br>1⃣<a href="https://twitter.com/adapp999?ref_src=twsrc%5Etfw">@adapp999</a> をフォロー<br>2️⃣この投稿をRT or いいね<br>3️⃣すぐに結果がくる<br><br>締切:2019年01月15日19時まで<br>詳細URL(現在の当選者一覧など): <a href="https://t.co/YtSjSFrgzs">https://t.co/YtSjSFrgzs</a><a href="https://twitter.com/hashtag/adapp?src=hash&amp;ref_src=twsrc%5Etfw">#adapp</a> <a href="https://twitter.com/hashtag/%E3%83%97%E3%83%AC%E3%82%AD%E3%83%A3%E3%83%B3?src=hash&amp;ref_src=twsrc%5Etfw">#プレキャン</a> <a href="https://t.co/BdvA2dXCeC">pic.twitter.com/BdvA2dXCeC</a></p>&mdash; あどあっぷ公式@宣伝を気軽に (@adapp999) <a href="https://twitter.com/adapp999/status/1080055358041640960?ref_src=twsrc%5Etfw">2019年1月1日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>

ちなみにこのプレゼントキャンペーンの賞品の原資は自分で出しているのですが、すでに3000円くらい配っててつらいので、クラウドファンディングを始めました。どでかいキャンペーンをぶち上げたいので、共感してくださる方、ご協力していただけると幸いです😹

https://polca.jp/projects/xWRzjeyrenx

## 「RTしたらすぐくる」を実現する技術
　RTをするとすぐにDMが届く機能がこのサービスの目玉になっています。これを実現しているのは**Twitter Account Activity API**です。
　Twitter Account Activity APIとは、紐付けたアカウントの全てのアクティビティ(ツイートするとか、リツイートするとか、フォローするとか）の行為をするたびに登録したWebhook URLヘPOSTをしてくれる公式APIです。
　AWSの**API Gateway**と**Lambda**で受け入れ態勢を作れば、サーバレスで実装可能です。詳しい実装方法は[こちら](https://qiita.com/sakatukitukasa/items/426a5f434fb69d68586d)を参照してください。
　今回のサービスでは、RTやいいねのアクティビティをキャッチして「そのツイートがキャンペーンツイートか判定」「応募済みでないかチェック」「抽選」「結果の通知」などを行っています。

## TwitterAPI制限への対応
　企業が行なっているプレゼントキャンペーンのツイートを見ると、数万から数十万のRTがされているものを見つけることができます。このサービスは応募してくれた人全員に結果の通知をするため、一度に大量の応募があった際に**TwitterからAPI制限**を受けてしまいます。API制限になると結果の通知ができないので、「おいおい、応募したけど全く反応がないぞ」となってしまい**信頼を失ってしまいます**。
　そこで本サービスでは結果の通知がAPI制限で失敗した際には、**AWSのSQSというキューイングサービスを利用しています**。キューイングサービスとは、あのデータ構造でおなじみに**「キュー」をクラウドで実現しているサービス**です。時間のかかる処理や、失敗した処理を一旦このキューに投げておき、非同期で処理したりあとで処理したいときなどに使えます。
　なので、API制限で失敗したメッセージは一旦「送信先」と「メッセージ」をSQSに投げています。そして**10分おきにSQSを監視するLambda**がもし送信できていないメッセージが見つかったら時間をおいて再送信するようにしています。それも失敗したらまたSQSへ投げます。
　
## キャンペーン終了後に再抽選
　プレゼントキャンペーンには締め切りがあります。しかし思ったほど応募者が現れなかった時にはプレゼントが余ってしまうこともあります。余ったプレゼントは外れてしまった人たちから再抽選するのが道理でしょう。
　本サービスでは常に**DBを監視するLambda**を用意しておき、終了したキャンペーンを見つけたら再抽選を行う処理を用意しています。
　特に書くことがなくて申し訳ありませんが、全てDynamoDBとLambdaで実現しています。**AWS最高！**

## dynamoDB + lambda開発で採用したプラクティス
　本サービスを開発するにあたって使用しているのはAWSのDynamoDBとLambda（とAPIGatewayとS3）です。

DynamoDB : 2テーブル(応募者を管理するテーブルとキャンペーンを管理するテービル）
Lambda : 7つ

７つのLambdaは**共通して利用するロジックが多数あるため全てを１つのフォルダにまとめました**。７つの**lambdaを一気に更新するシェルスクリプト**を使うことで開発がとても楽になりました。

```sh
function_name="FUNCTION_NAME"
zip -r /tmp/${function_name}.zip *
aws lambda \
update-function-code \
--function-name ${function_name} \
--zip-file fileb:///tmp/${function_name}.zip \
--publish

これを７つ用意
```

また、DynamoDBとのやりとりが多かったので次のような構成で開発をしてみました。

<img width="1111" alt="スクリーンショット 2019-01-02 21.43.34.png" src="https://qiita-image-store.s3.amazonaws.com/0/234396/9a16abbd-7998-3aba-1702-fc90de05b266.png">

１、DynamoDB操作系の共通クラス(図の１段目)
DynamoDBはハッシュキーとレンジキーを使ったアクセスが基本なので、SQLのように複雑な問い合わせはしません。なので**DB操作はテーブルごとに共通化しやすい**です。~~python+boto3を使用して作った実際のコードが以下です。~~ (冗長になるため省略しました)

２、各テーブルのレポジトリ(図の２段目)
上記の共通クラスを継承して、共通クラスにはない特殊な問い合わせをここに書いています。

３、各テーブルのユースケース(図の３段目)
上記のレポジトリに依存しながら、ロジックをこのクラスに集約しました。各ファンクションが共通して利用できるのでとても**再利用性が高くなりました**。

## システムの応用
　このプレゼントキャンペーンのシステムは他にも**色々な応用が可能です**。
「RTしてくれた人全員に過去に書いた絵を送りつける」「いいねしてくれた人におみくじ結果を送る」などをテスト的にやらせてもらったのですが、それぞれ100人近く参加してもらえて、皆さんに楽しんでもらえました。
　プレゼントキャンペーン用に作ったシステムですが、色々な使い方ができるのは**カスタマイズを前提**にしたコーディングをしたからです。どうしてもベタ書きが多かったり、仕様が固まってしまうと考えていなかった使い方に対応できないシステムになってしまいがちです。**柔軟性を持たせたコーディング**をすることが(個人開発では)大事だなと思いました。

## 最後に
まとめますと、**「RTしたらすぐに結果がくるプレゼントキャンペーン」が作れるサービスを作りました！！**
プレゼントキャンペーンを開いてみると結構フォロワーも増えますので、興味ある人は以下のリンクから連絡くれたら嬉しいです。タイトルで有料と銘を打っていますが、最初のうちは無料でOKです。数が増えてくるとTwitter Account Activity APIの無料枠が終わってしまうので、そうなったらどうしても有料になってしまいますが。。

https://adapp9.com

 また、記事中に書きましたがデカい賞金のキャンペーンを開いてみたいのでクラウドファンディングで募集中です(乞食)

https://polca.jp/projects/xWRzjeyrenx