GameWith Engineering Blog

GameWith のエンジニア、デザイナーが技術について日々発信していきます。

GameWithに雪とすっぴんちゃんが降るまでの意思決定のスピード。そして、おみくじへ・・・ #GameWith #TechWith

GameWithのエンジニアのtiwuです。

今回はクリスマスに雪が降る企画がリリースされた経緯と、正月キャンペーンの経緯を書きたいと思います!

クリスマス

実は去年の12/24,25にGameWithのトップページに雪とすっぴんちゃん(GameWith公式キャラクター)が降っていたのをみなさんご存知でしょうか?

f:id:tiwu_gamewith:20190117103408p:plain

この雪が降る企画は僕のSlackの何気ない一言から始まりました。

f:id:tiwu_gamewith:20190109110825p:plain

この投稿からわずか30分後、開発環境での実装が完了!

f:id:tiwu_gamewith:20190109110950p:plain

そして最初の投稿から7時間後に、本番リリースのOKが出ました!

f:id:tiwu_gamewith:20190109130024p:plain

盛り上がるSlack

f:id:tiwu_gamewith:20190109130637p:plain

f:id:tiwu_gamewith:20190109112739p:plain

f:id:tiwu_gamewith:20190109112801p:plain

f:id:tiwu_gamewith:20190109112817p:plain

そして雪すっぴんちゃん爆誕。

f:id:tiwu_gamewith:20190109130729p:plain

このように、エンジニア内で盛り上がるだけで終わらせず、ゲーム攻略チームやゲームレビューチームと連携し、わずか1日で意思決定されクリスマスにリリースできました!

素晴らしいスピード感だと思います!

お正月

みなさん、1/6(日) 23:59まで開催してた「おみくじ引いてお年玉ゲット!キャンペーン」は参加されたでしょうか?

このキャンペーンも何気ない会話から始まりました。

f:id:tiwu_gamewith:20190109130827p:plain

実は、3年前におみくじ機能は実装されていて、

f:id:tiwu_gamewith:20190109120330p:plain

terunumaさんの圧倒的スピードや、

f:id:tiwu_gamewith:20190109130910p:plain

FukiさんのGameWithならではのGIF作成や

f:id:tiwu_gamewith:20190109130952p:plain

ただおみくじ企画を復活させるだけでなく、キャンペーンを発案した企画サイドなど

GameWithのチーム力でキャンペーンを開始することができました!

キャンペーンは終わってしまいましたが、おみくじはこちらからひけるので、是非運試しをしてみてください!

最後に

GameWithの組織の雰囲気が少しでも伝わったら幸いです!

GameWithは、ゲームが大好きで、新しい技術をどんどん使っていきたいという方を大募集中! Wantedly でもよいので是非お気軽にお声がけください!

www.wantedly.com

GameWith新規事業への挑戦事例_攻略メディアの場合(2018年)

SEO狙いのタイトルでこんにちは。GameWith執行役員の阿部です。

現在、GameWithでは様々な事業を仕込んでおり、 僕は主にメディア周りを担当することが多いです。
その中で、2018年注力していた事業について、 どのように事業開発をし、どのような結果を得たのか共有しようと思います。

これから新規事業を作る、社内外の方の参考になれば幸いです。

攻略メディアが新たに注力した2つの事業

1.ゲーム攻略の短尺動画

1つ目はゲーム攻略の短尺動画です。
市場トレンドとしてアクションゲーム(荒野行動やフォートナイト)が流行る中で、どうしても攻略サイト「GameWith」(以下、「GameWith」)のような文字主体のメディアは相性が悪いです。

また市場にはYouTuberによるエンタメ寄りのゲーム実況動画はあるのですが、攻略情報を伝えることをメインとした短尺動画はプレイヤーのいない領域でした。
今回はこちらの事業内容について書こうと思います。

2.ゲーム攻略メディアの海外展開

2つ目はゲーム攻略メディアの海外展開です。 こちらの需要はGoogleトレンドなどで確認できていたので、 採算の合うオペレーションを組めるかどうかの挑戦でした。12月7日のプレスリリースで出した通り、一定の成果が出ています。
こちらについても、エモエピソード満載なのでまた別の機会に書こうと思っています。

gamewith.co.jp

短尺動画プロダクトでの挑戦!

どんなプロダクトを作ったのか?

ゲーム攻略を文字ではなく、短尺動画で解説したアプリです。
「いずれゲーム攻略は文字でなく、動画で見る世界が来る。」 という流れを想定し、 「Mipple」というアプリをリリースしました。

f:id:gamewith-tech:20181217191116p:plain
Mipple

当初の戦略は?(2017年12月頃)

このようなリーンキャンバスを想定していました。

f:id:gamewith-tech:20181217191051p:plain
リーンキャンバス
(モザイクばかりでごめんなさい)

キャンバスの詳細は割愛しますが、この他に「市場規模はあるか」、「このタイミングでやるべきか」という点にも着目し、問題定義をしました。
まず、市場の大きさは既存メディアの「GameWith」自体が証明していたので、市場規模はあるという結論になりました。(打倒「GameWith」と社内でも言っていました)
さらに、動画広告市場の急激な伸び(特にインフィード広告の盛り上がり)もあったので、「今、このプロダクトを作るべきだ!」という流れになりました。

webtan.impress.co.jp

戦略を考える中で、特に重要な仮説は「チャネル」と「提供価値」に位置づけをしていました。

「チャネル」と「提供価値」を検証しよう!(2018年1月頃)

そもそもなぜチャネルが重要?

「GameWith」に集まっているトラフィックから誘導することも可能ですが、 それでは「GameWith」の規模が成長の上限となってしまいます。

そもそも、メインのターゲットとして考えていた、アクションゲームのユーザーは攻略需要がほぼなく、検索をしないため、「GameWith」に訪れているユーザーはごく一部に限定されてしまいます。
なので「GameWith」とは別に、独自のチャネルハックは必ず見つけようと考えていました。

とても普通のアイディアだけど、勝算ありでは!?

チャネルハックの手段としては、ゲーム内からの導線をもらうなども考えましたが、 初期ユーザーの獲得は結局自前でやらないと、そもそもの交渉権がありません。
なので、まずはSNSでの拡散に注力しようと考えました。

SNSで動画付きの投稿をすると通常よりもエンゲージメントが高く、拡散されやすい。 という特性を活かして、ここをハックできないかと考えました。

特にTwitterを活用して、ゲーム専用のサブアカウントを作る文化があり、その層にうまくバイラルすることでアプリDL数が伸びると想定していました。

既に自社でも各ゲーム攻略のSNSアカウントがあり、そこそこフォロワーがついていました。フォロワーの増やし方についてもノウハウがあったので、バイラルの起点は作れるという予想でした。

検証にプロダクトはいらない

チャネルと提供価値の検証はプロダクトなしで進めました。
Twitterアカウントを作成し、攻略短尺動画を投稿してみました。ここで検証したかったのは、「①どれくらいのユーザーにリーチができるか②どういったコンテンツがエンゲージメント高いのか③動画1本あたりの作成コスト④ゲームのアプデから投稿までの時間がどのくらいか」でした。
それがこちらのアカウント。

twitter.com

最初は動画編集者もいないので、デザイナーに無理を言って動画を作ってもらっていました。
自社リソースを使い、且つ低コストで検証できたのでこの点はよかったと思います。

初投稿が5万再生以上!!

初めて投稿した短尺動画は、社内で保有する別アカウントからのRTでブーストがかかり、5万再生以上されました。
もしアプリDLリンクをつけたら、1%のユーザーがDLするとして、1投稿で500DL。
1日10投稿する体制を作ったら、1日5,000DLをSNSで獲得できる、
と、夢を見させていただきました\(^o^)/

その後も継続して動画投稿をした結果、想定以上にSNSで動画再生されることがわかり「チャネルはこれでいける!」と考え本格的にアプリを作る判断をしました。

競合優位性は想定通り!しかし難易度が高い(2018年3月頃)

競合優位性は即時性

攻略メディアを5年運用して一番重要だと感じていたのは「情報の即時性」でした。
攻略情報の需要はゲームのアプデや発売された瞬間がピークで、2週間ほどで消えてゆきます。そのためGameWithではゲームのアプデ10分後には情報が出せるオペレーションを組んでいます。

媒体が文字から動画に変わったとしてもこの点が一番重要だと考えていました。
つまり、ゲームアプデの30分後には動画を出せる体制を作ることを目標とし、そのため動画素材の撮影、動画編集は内製化する必要がありました。

例:↓こういった動画はアプデの瞬間が一番需要あります

動画素材の撮影は、既に社内に攻略メディアを運用している部があるので、そちらから提供してもらうことでコストをかけず、なおかつスピードを出すことができます。

短尺動画のプロダクトが世の中にたくさん出ているのに、広告単価の高いゲーム領域の短尺動画プロダクトがないのは、この作成コストの面が大きいのではと考えています。

動画制作オペレーションの構築に時間がかかる(2018年4-9月頃)

動画編集スタッフを採用し、社内で動画作成のフローを組んだのですが、なかなか"アプデ後30分以内に投稿する"フローが組めませんでした。正直何に時間がかかっているかも、最初わからない状態でした。
そこで動画制作のフローをカンバンで管理し、ボトルネックを特定し、、、と、この話は長くなりそうなので割愛します。製造業のお話ですが以下の本が参考になります。

ザ・ゴール ― 企業の究極の目的とは何か

ザ・ゴール ― 企業の究極の目的とは何か

結果、当初は動画編集1名で2日に1本しか動画投稿できていませんでしたが、1日4本且つアプデ後30分以内の投稿が可能となりました。投稿本数の最大化をしつつも、どんな動画がウケるのかを常に考え、検証サイクルを回していました。

爆速アプリ開発!(2018年8月〜)

MVP中のMVP

優秀なエンジニアが入社してくれたおかげで、β版のアプリはなんと1ヶ月で完成しました。正直、想定外の完成スピードでした。
スピード優先だったため、拡張性を捨てた作りになっているのですが、この判断は正解だったと思います。(詳しくはこちら↓)

tech.gamewith.co.jp

アプリを出すことで特に検証したかったのはADNWによるマネタイズの可能性でした。
攻略記事よりも攻略動画のほうが作成コストがかかるので、どれだけ記事よりも収益性が高いかの検証が必須でした。

アプリで検証したかったマネタイズの方向性

マネタイズの方向性は大きくADNWか純広告の2パターンあります。SNS上にADNWの動画広告を差し込むことはできないので、ADNWでマネタイズするならアプリに注力となります。
純広告の場合、アプリ内での再生回数にこだわる必要はなく、全SNSアカウント+アプリでの再生回数で値付けされます。(いわゆる分散型メディア的な立ち回り)

価格相場は1再生10円?動画メディアC Channel、KURASHIRU、DELISH KITCHEN広告比較 | The Startup

最終的にはどちらもやるべきですが、スタートアップの初期段階なので、まずはどちらのほうが可能性が広がるかを検証してみようと思いました。そのためにもβ版のアプリを出して、動画広告のeCPMがどのくらいの数値になるのか検証しました。

結論、ADNW動画広告のeCPMはとても良かったです。ここは想定以上に良い結果でした。

UXに一番重要な要素は

アプリを出してからいろいろな改修を重ねてみたのですが、結局ユーザー体験に一番影響を与えている要素は、デザインや機能ではなく投稿される動画の質、本数、即時性でした。

当たり前ですが、コンテンツ量が少ないアプリを開くはずもありませんでした。
ということで、再度動画の質、本数、即時性の最適化に注力することにしました。

改善、改善、で見落としていたもの(2018年9〜12月)

アプリを出して気づいた課題

ほとんどの仮説を外すことなく、ここまで進めて来ることができました。またアプリやコンテンツの質は、改善することでしっかり成果が出ていました。しかしアプリには想定と違っていた大きな課題が2つありました。

1つ目はSNSでの集客が思ったよりもできていないことでした。アプリを作る前にTwitter投稿でバイラルの検証をおこなっていたので、仮説通りのインプレッションは確保できていました。しかしツイートからのDL数(CVR)が極端に低かったのです。CVRまで事前に検証すべきだったという反省点がありました。

理由は考えれば当たり前ですが、わざわざアプリをDLしなくてもTwitterで流れてくる動画でユーザーが満足してしまうからです。

しかし、ツイートからのCVRは最適化できると思い、様々な検証を行いました。Twitterに投稿する動画は最初の数秒だけにする、ツイートの文言を最適化する、そもそも別のSNSを試すなど、、、また、アプリユーザーの獲得を諦め、分散型メディア化するという方向性も考えました。

もっとクリティカルな課題

上で述べた課題はいわゆる「チャネル」の課題です。他の方法を探せばもしかしたら、別の最適解が見つかったかもしれません。現にTikTok経由でのアプリDLがめちゃくちゃ発生したなど、細かいチャネルハックの話はあったりします。

ですが、それよりも大きな課題がありました。それは「ゲーム攻略は動画で見たほうがわかりやすい」という仮説が間違っていたことです。正確には「ゲーム攻略は動画で見たほうがわかりやすい場合もある」だという考え方に変化しました。

一部の需要しか満たせていなかった

例えば、スマブラをプレイしていて「プリンの即死コンボの手順を知りたい」と思った時には、動画で見たほうがわかりやすいです。しかし「隠しキャラ解放のやり方を知りたい」と思った時には、動画で見るよりも文字や画像で見たほうがわかりやすいです。

とても当たり前のことを言っているように思えますが、僕は後者の場合においても動画で解説したほうがわかりやすいし、それが当たり前になる未来がくると考えていました。

しかし、動画投稿を繰り返し、ユーザーの反応を見るうちに、反応が良い動画、悪い動画の違いがわかってきました。問題なのは文字媒体のメディアにおいて人気のコンテンツなのに、動画にすると人気が出ないコンテンツがあったことです。つまり動画が最適な媒体ではない場合があるということです。

最適なUXは?

作り手側の「動画広告でマネタイズしたい」という思惑を除いて、単純にUXを考えた場合、「動画で見たいコンテンツは動画で見れるし、文字で見たいコンテンツは文字で見れる」というプロダクトが最適だと考えました。

その場合、短尺動画単体のアプリとするのではなく、GameWithアプリの機能としてマージするのが最適だという判断をしました。「GameWith」アプリには文字情報での攻略もありますし、さらに動画情報での攻略を強化したら最高!という考えです。

もちろんUIの複雑化などデメリットはありますが、「ゲーム攻略を知りたければ、(動画、文字問わず)このアプリ見ればOK」という世界観を実現する近道だと考えました。
この結論を出したのが11月末でした。

※まだマージはできていません

ざっくり仮説と検証の結果

超ざっくり振り返ると以下のような結果です。

  • 顧客   →◯ PvPゲームユーザーはやっぱり増えている。
  • 課題   →× 動画で見たいもの、見なくて良いものがある
  • 価値提案 →◯ アプデ後30分以内の動画はやはり需要高い。即時性は重要。
  • チャネル →× TwitterからのDL率は低い。別のチャネルハック必要。
  • マネタイズ→◯ 動画広告のeCPMは想定以上に高い
  • 優位性  →◯ 即時性を出すためには、素材提供するチームが社内に必要。専属での採用はコストが重い

これらを検証するプロセスはもっと高速化できなかったのか?という反省はたくさんあります。特に「知ってる人に聞いたほうが早い」は、もっと意識すべきでした。たくさんのアドバイスをくれた皆様本当にありがとうございます。

副次的に良かったこと

「GameWith」アプリと別のリリースフローだったので、ABテストをばんばん回すことができました。そのため、「GameWith」アプリにマージした際に、最初から最適なUIで実装することが可能になります。
また動画広告のeCPMが高いことがわかったので、マージする優先度判断に役立ちました。(コスパが合うか判断しやすい)

素晴らしい仲間と学び

以上が今年の軌跡です。
感情面を抜きにして書いたので、とてもドライな文章になってしまいましたが、実際ここには書ききれない無数の施策があり、プロダクトの数値に一喜一憂する素晴らしいメンバーいます。

メンバーのキャリアストレッチ

このプロジェクトに参加したメンバーは全員急激なキャリアストレッチをしました。
デザイナーがディレクターを行い、エンジニアは自分の領域でない開発を行い、動画編集者は企画を行い、とてつもない負荷だったと思います。それでも、全員とてつもなく成長したと思います。きれい事ではなく、本当にそれぞれが人生の資産になったと思っています。

今後の予定

短尺動画単体のアプリはクローズしますが、短尺動画としてのチームは継続し、GameWithアプリから最高の攻略動画をユーザーに届ける予定です!ユーザーの需要に対して、網羅的に応えられるアプリを目指します!

さらに、動画投稿本数、質、アプリプロモーションも加速させ、攻略動画においても圧倒的No1のポジションを取ろうと思います。

新規事業を生み出すGameWith

GameWithではこれ以外にも、たくさんの新規事業を仕込んでいます。
収益は安定しつつ、会社としては挑戦していく、とても良い環境だと思います。もしゲーム領域に関する新規事業のアイディアがあればDMください。一緒に作りましょう!もしくは自身のキャリアを極限まで広げたい方お待ちしております!(僕もキャリアのスタートはデザイナーからでした)

最後に、このプロジェクトに関わった全てのみなさん。ありがとう。
心から感謝してます、愛してます。

twitter.com

LINE Messaging APIでモンストのマルチ募集が捗るチャットボットを作ってみた #GameWith #TechWith

f:id:gwchai:20181206165111p:plain

GameWith Advent Calendar 2018 9日目担当のiOSアプリエンジニアの chuymaster です。

先日、LINE DEVELOPER DAY 2018に参加してきて、クロージングセッションでの「今日のカンファレンスで聞いた内容で何かを作って欲しい」というメッセージを真に受けて、勢いでチャットボットを作った話を共有したいと思います。

サービスの背景

GameWithが取り扱っているゲーム攻略情報の中で、「モンスト」ことモンスターストライクが非常に人気で、多くのユーザーに見ていただいています。

f:id:gwchai:20181205165616p:plain
モンスト攻略

モンストには、「マルチプレイ」というモードがあって、最大4人で集まってゲームをするとクエストがクリアしやすくなったり、報酬がたくさんもらえたりします。

GameWithアプリでは、プレイヤーが集まりやすいように、「自動マルチ募集掲示板」機能を提供しています。クリアしたいクエストに、欲しい条件のプレイヤーに一緒にマルチしてもらえる掲示板です。

f:id:gwchai:20181205170741p:plain:w300
GameWithアプリ「自動マルチ募集掲示板」

GameWithユーザーが抱える課題

さて、そんな便利なマルチ自動掲示板ですが、実は一つ手間があります。

それは、募集のとき、募集メッセージをLINEからコピペする必要があることです。

f:id:gwchai:20181205172636p:plain:w300
マルチ募集画面

募集する手順は

  1. モンストでクリアしたいクエストのLINEでのマルチ募集を選ぶ
  2. LINEで友達を探す
  3. 友達に募集メッセージを送る(LINEチャットボットに送ることが多いらしいです)
  4. 送ったメッセージをコピーする
  5. GameWithアプリの募集画面を開く
  6. メッセージをペーストする
  7. 条件を決めて募集を始める

・・・長い!

募集メッセージを保存しておいたり、LINEを経由しない裏技的なことをしてマルチ募集の手間を減らすこともできますが、 公式の手順で、自然な流れで、「本当の友達とマルチする」みたいに募集したいというユーザーが多いはずです。

f:id:gwchai:20181205180859p:plain:w300
私はLINEデリマをいつもマルチに誘っていますw

そこで、LINEを通すことは仕方ないのなら、その後の手間をなくそう!という発想が、今回のチャットボットを作成する経緯になります。

どんなチャットボット?

「マルチ募集をワンタップでできる」チャットボットです。

このチャットボットにマルチ募集メッセージを送ると、GameWithアプリで募集するURLを返信してくれます。

そのURLをタップするだけでGameWithアプリで募集の必要な項目を埋めてくれて、コピペ要らずに募集開始ができるようになります。

f:id:gwchai:20181205184026p:plain:w300
マルチ募集お手伝いチャットボット(画面は開発中のものです)

デモ動画

さっそくデモ動画を見ましょう!

f:id:gwchai:20181206130223g:plain
チャットボットでマルチ募集

ポチポチタップするだけで募集ができて、サクサク感が伝わるんじゃないかと思います!

それでは、実装の説明をしていきます。

チャットボットの準備

まずは、公式のチャットボットサンプルでのセットアップです。 私はPythonが少し書けるので、Pythonのサンプルを選び、こちらの記事を参考に開発を始めました。

qiita.com

LINE@のアカウント作成、Herokuの環境作成は上記の記事で詳しく説明しているので割愛します。

ただし、記事で紹介された flask-echo というオウム返しするだけのサンプルを使うと、 LINEのチャットボットは何ができるかイマイチわからないので、flask-kitchensink (https://github.com/line/line-bot-sdk-python/tree/master/examples/flask-kitchensink)を使いました。

f:id:gwchai:20181205170713p:plain:w300
flask-kitchensinkボット

実装

ボット返信の大まかな流れは

  1. 送信者から受け取った、マルチ募集メッセージをサーバーに一時的に保存する
  2. メッセージファイルのURLを、GameWithアプリで処理するURLスキーマ gamewith:// のパラメータにくっつける
  3. 送信者に返信する

パラメータを受け取った後の処理はアプリ側の責任になります。

  1. URLスキーマを解析する
  2. メッセージファイルのデータを取得する
  3. 取得したデータを文字列に変換する
  4. マルチ募集画面を開いて、文字列を入力ボックスにセットする

アプリ側の実装は詳細を割愛します。以下、サーバー側の実装を説明します。

1. 送信者から受け取ったメッセージをサーバーに一時的に保存する

嬉しいことに、flask-kitchensink のサンプルでは既に画像を一時的に保存する処理が実装されているので、それを活用します。

もらったテキストをファイルに保存して、URLを返すメソッドを作りました。

def write_message_to_file(text):
    ext = 'txt'
    with tempfile.NamedTemporaryFile(dir=static_tmp_path, prefix=ext + '-', delete=False) as tf:
        tf.write(text.encode())
        tempfile_path = tf.name

    dist_path = tempfile_path + '.' + ext
    dist_name = os.path.basename(dist_path)
    os.rename(tempfile_path, dist_path)

    message_url = (request.host_url + os.path.join('static', 'tmp', dist_name)).replace("\\","/")
    return message_url

2. 保存したファイルのURLを、GameWithアプリで処理するURLスキーマ gamewith:// のパラメータにくっつけて返信する

ここは単純に文字列を結合するだけです。URLスキーマと処理するパラメータは予めアプリ側と合意を得る必要があります。

def get_monst_reply_message(message_url):
    message = "このURLをタップして、GameWithアプリですぐマルチ募集を始めよう!(*'▽')\n"
    gamewith_app_prefix = "gamewith://line?message_url="
    return message + gamewith_app_prefix + message_url

3. 送信者に返信する

linebotのSDKを使って返信します。サンプルからコピペするだけで良いです。

def handle_text_message(event):
    #-------
    # サンプル中略
    #-------
    elif "https://static.monster-strike.com/line" in text:
        message_url = write_message_to_file(text)
        reply = get_monst_reply_message(message_url)
        line_bot_api.reply_message(
            event.reply_token,
            TextSendMessage(text=reply)
        )

今後の課題

価値の検証

ユーザーが使って本当に喜ぶかどうかを検証する必要があります。まず社内の攻略チームの方々にお願いして、使ってフィードバックをもらおうと考えています。

全体的なユーザーフローの設計

チャットボット自体は便利ですが、歓迎メッセージや使い方の説明をちゃんと案内してあげないとユーザーが離脱してしまいます。 価値検証できたら、ユーザーフローやサポートを含めた設計をします。

本番稼働に向けた開発

まだプロトタイプ段階なので、Herokuの無料プランでチャットボットを稼働させていますが、 本番稼働に向けて、安全性・安定性・メンテナンス性を考慮した開発が必要になります。 この辺りのサーバーサイド開発はほぼ経験がないので、他のサーバーエンジニアからいろいろ学ぼうと考えています。

最後に

私はiOSアプリエンジニアですが、今回はサーバーのコーディング、社内でまだ使ったことのないLINE Messaging APIという未知の領域に挑戦しました。 GameWithは、会社のミッションである「ゲームをより楽しめる世界を創る」ことに繋がる挑戦を積極的に応援しているからこそ、実施できたと思います。

そんなGameWithは、ゲームが大好きで、新しい技術をどんどん使っていきたいという方を大募集中! Wantedly でもよいので是非お気軽にお声がけください!

www.wantedly.com

AndroidのプロジェクトにCIを導入した話 #GameWith #TechWith

はじめまして、GameWithのエンジニアのソンです。 今回はGameWith本体アプリのAndroidプロジェクトにCIを導入した話をします。

まずはどうしてCIを導入しようと思うのを説明させていただきます。 PullRequestを作る時に、人為的なミスでそもそもBuildやUnitTestが通らないことたまにあります。この問題はCIの導入でReviewする前に必要ない人力が省けます。

また、複数人のプロジェクトにはある程度のCode Styleを制限しないとCodeの可読性がすぐ悪くなります。

 

ゴール

f:id:w_sun:20181204153724p:plain

  1. CircleCI 2を導入
  2. UnitTestを行う
  3. APKをビルド
  4. Danger経由で、GithubにKtlintからのエラーメッセージをコメント
  5. 3.で生成したAPKをDeployGateにアップロード

Circle CI 2を導入

社内のGithubアカウントは既にCircleCiと連携してますので、新しいプロジェクトに導入するのは難しくないです。

導入したいプロジェクトの「Set Up Project」を押すと、そこには簡単なconfig.ymlの例文があります。チュートリアルに沿ってプロジェクトに配置すると、最初の構築が終わります。次はconfig.ymlにどんどんJob(実行させたいタスク)を追加する感じです。

一応CircleCIは複数のJobを同時に実行することができるので、ここはUnitTestBuildKtlintと三つのJobに分けまして、平行で走らせます。

また、各JobでGradleの初期化を行うと時間がかかりますので、CircleCiのworkspaceを使って、初期化したものを各Jobに提供してます。

UnitTestを行う

  unitTest:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run:
          name: Run UnitTest
          command: ./gradlew testProductDebugUnitTest
      - store_artifacts:
          path: app/build/reports
          destination: reports
      - store_test_results:
          path: app/build/test-results

store_artifactsstore_test_resultsはテスト項目の結果を保存するMethodです。Jobが実行した後にArtifactsで見れます。

f:id:w_sun:20181204153805p:plain

APKをビルド

 normalBuild:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run:
          name: Build
          command: ./gradlew assembleQualityAssuranceDebug
      - persist_to_workspace:
          root: ~/
          paths: code/app/build/outputs/apk/qualityAssurance/debug/

最後のpersist_to_workspaceは生成したAPKをDeployGateにアップロードできるように、workspaceに保留する。

ktlintの実行

  ktlint:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run: ./gradlew ktlintProductReleaseCheck
      - persist_to_workspace:
                root: ~/
                paths: code/app/build/reports/ktlint/

ktlintはGradle pluginsのKtlint Gradleを使ってます (https://github.com/JLLeitschuh/ktlint-gradle

OutputはCHECKSTYLEに設定する、この後はDangerから読み込んでGithubにコメントする。

dangerの実行

  danger:
    working_directory: ~/code
    environment:
      - LANG: C.UTF-8
    docker:
      - image: ruby:2.1
    steps:
      - attach_workspace:
          at: ~/
      - run: gem update --system 2.4.8
      - run: gem install bundler
      - restore_cache:
          key: gem-cache-{{ .Branch }}-{{ checksum "Gemfile" }}
      - run: bundle install --path vendor/bundle
      - save_cache:
          key: gem-cache-{{ .Branch }}-{{ checksum "Gemfile" }}
          paths:
            - vendor/bundle
      - run: bundle exec danger --verbose

DangerはRuby版を使ってます。(https://danger.systems/ruby/)

Dangerfiledanger-checkstyle_formatdanger-lgtmくらい簡単なものしか入れてないです。

  • エラーになる時

f:id:w_sun:20181204160901p:plain

  • 成功する時

f:id:w_sun:20181204160913p:plain

DeployGateにアップロード

 deploy:
    <<: *defaults
    steps:
      - attach_workspace:
          at: ~/
      - run:
          name: Deploy APK
          command: curl -F "token=${DEPLOY_GATE_API_KEY}" -F "file=app-qualityAssurance-debug.apk" -F "message=$(git log --oneline -1)" https://deploygate.com/api/users/

リリースする前にQA版のAPKを使って自動テストを実行してるので、そこの手動生成の手間が省略できます。

以上で簡単なCI導入の手順でした。導入してよかったと思ったところがいくつあります。

  1. Ktlintの導入によって、書き方のミスが防げるようになりました。基本的に人工でチェックするのは不可能ので、非常に助かります。
  2. QAテスト向けのAPKを手動でビルドして、DeployGateにアップロードする手間も省略できました。
  3. 開発する時にDebugBuildすることは多いですが、実際ReleaseBuildの時にBuildが通らないこともたまにあります、これもCIによって事前にわかります。

また、この記事を書いてる途中で気づきましたけど、DangerさんがKtlintを対応してくれました。また試してみます。 :thinking_face:

終わりに

GameWith は、ゲームの楽しさをもっと世界に伝えていきたいエンジニアを大募集中です。 Wantedly でもよいので是非お気軽にお声がけください!

www.wantedly.com

AWS Session Manager を Mac の Terminal から利用する #GameWith #TechWith

GameWith Advent Calendar 2018 6 日目担当の @serima です。

最近のマイブームはソードアート・オンライン アリシゼーションです。 SAO シリーズで一番好きなエピソードは「ファントム・バレット」で、気付いたら何度も視聴しています。

Session Manager とは

GameWith ではリモートワーク環境の実現のために AWS Session Manager を利用しています。

AWS Session Manager を利用すると、踏み台サーバが不要になります。 踏み台サーバが不要になるということは、鍵の管理から解放されるということです。

前提として以下を満たしていると、EC2 インスタンスにシェルアクセスが可能になります。

  • シェルアクセスを受け付ける EC2 インスタンスに AWS Systems Manager エージェントがインストールされている
  • EC2 インスタンスの IAM ロールに AWS 管理ポリシー AmazonEC2RoleforSSM が割り当てられている

また、弊社のセキュリティポリシー上 IAM User に MFA 設定(二段階認証)がされていない場合は AWS Session Manager を利用してシェルアクセスができないようになっています。

Session Manager 自体について、詳しくは本家の記事をご覧ください。

このポストでは 「Session Manager の導入が済んでいる状態で、どのように Terminal からシェルアクセスを行うか」についてフォーカスしたいと思います。

aws.amazon.com

Terminal からのシェルアクセス

AWS Console 上から Session Manager を利用する際は当然すでに MFA での認証は済んでいる(Console へのログイン時に確認コードが求められ、それもパスしている)状態なので問題なく利用できます。

しかし、Terminal から aws ssm コマンドを利用して Session Manager に接続しようとすると認証エラーが出てしまいます。(二段階認証ができてないので当然ですね。)

前提

手順

基本的にはこちらの記事(AWS CLI 経由で MFA を使用してアクセスを認証する)を参照していただければ問題ないと思います。

--serial-number には MFA デバイスの ARN を指定、--token-code には二段階認証のコード(6桁の数字)を指定して以下のようにコマンドを叩くと、アクセスキーとトークンが手に入ります。

% aws sts get-session-token --serial-number arn:aws:iam::000000000:mfa/username --token-code 000000 --output json
{
    "Credentials": {
        "SecretAccessKey": "XXXXXXXXXXXXXXXXX",
        "SessionToken": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
        "Expiration": "2018-10-15T21:39:58Z",
        "AccessKeyId": "XXXXXXXXXXXXX"
    }
}

取得できた SecretAccessKeySessionTokenAccessKeyId をここでは ~/.aws/credentials に以下のように追記しています。 これらのキーやトークンは一時的なもののため、期限が切れたら(デフォルトでは12時間)再設定する必要があります。

[mfa]
output = json
region = ap-northeast-1
aws_access_key_id = XXXXXXXXXXXXX
aws_secret_access_key = XXXXXXXXXXXXXXXXX
aws_session_token = XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

その後

% aws ssm start-session --target i-someinstanceid --profile mfa

と、することで Terminal から指定したインスタンスに接続ができます。 ログイン時のユーザは ssm-user ですが sudo で昇格が可能です。(パスワードなし)

ubuntu ユーザになってからは [tab] キーでの補完が効くようになりました。

f:id:serimaryo:20181130231632p:plain

Session Manager で接続中にネットワーク切断した際の挙動

Terminal からの接続テストを行っている際に、ちょっとした実験を行いました。そちらは別記事として投稿してありますので、興味があれば、ぜひご覧ください。

qiita.com

終わりに

Session Manager は割と最近リリースされたものなのですが、インフラエンジニアの方がすかさず検証をして本運用まで導いてくれました。

GameWith では現在のところ AWS を利用していますが、最近は GCP の活用も本格的に始めています。

そのような環境下で、適材適所でクラウドベンダーを選択できるようなインフラエンジニアを募集しています!

www.wantedly.com

参考記事

Mac のプレビューで Slack カスタム絵文字を効率的に作る #GameWith #TechWith

GameWith Advent Calendar 2018 5 日目担当の id:syque です。三度の飯より Slack のカスタム絵文字を作るのが好きです。

弊社エンジニアチームでのコミュニケーションは Slack で行われているのですが、カスタム絵文字も人が増えるにつれ順調に増加し、本日 2018/12/5 時点では 583 emoji が登録されていました。

f:id:syque:20181204124715p:plain
大丈夫? だめだ...ダメです。ダメらしい🤢


何やら危なげな絵文字が登録されていますが、実際のSlack上の利用例を見てもなかなかにカオスです。


f:id:syque:20181204155220p:plain:w300
リンクをシェアするときにさりげなく parrot gif


f:id:syque:20181204155354p:plain:w250
明日から本気出す。


f:id:syque:20181204161258p:plain:w450
ポケモンにはポケモンの絵文字でリアクション。


f:id:syque:20181204155735p:plain:w350
港区。GameWithは港区にあります。なんだこれは。てぇてぇ。


うまくコミュニケーションできてるのかできてないのかよく分からない感もありますが...概ねメッセージに添えたりリアクションに用いたりとで表現の幅を広げるのに活用できているかと思います。

本題

本題です。カスタム絵文字を作成するためには当然素材が必要なわけですが、巷のトレンドもそうですが自社組織・携わる業界ならではのニュースやトレンド、ミームなどがありそこで出回っている事象をカスタム絵文字にしたい! という欲求も出てくるかと思います。

そういった時に加工が必要であればAdobeなど各種画像編集ツールを使って...とやるところですが、エンジニアだと会社のMacにインストールされていないということもままあり得ます。ですがちょっとした切り抜きやサイズ・色味調整であればOS標準機能やMacのプレビューでも問題なく行えたりします。今回はいくつか紹介します。

領域のスクリーンショットを取る

OS標準機能として、⌘ + Shift + 4 で領域を選択してのスクリーンショットが保存できます。デスクトップに保存されます。

f:id:syque:20181204174528p:plain

例としていらすとやさんの塩水ウニの画像を選択して取得してみます。

f:id:syque:20181204174812p:plain:w100

このように取得できます。(もちろんダウンロードできるものはした方が早い)

サイズ変更 & 切り抜き、クロップ

プレビューの機能です。⌘ + Shift + A または 表示 -> マークアップツールバーを表示 でツールバーを表示し、中央付近にあるサイズ変更のボタンをクリックします。

f:id:syque:20181205100322p:plain

サイズ変更のダイアログが表示されるので、任意のサイズに変更します。

f:id:syque:20181205100916p:plain:w250

Slack のカスタム絵文字のサイズは 128x128px と決まっているので、これに合わせてリサイズしたりなどが主な用途になるかと思います。

またサイズ変更するにあたって不要な部分などを切り取りたい場合があるかと思います。 こうした場合に領域を選択して、⌘ + Delete で切り取り、⌘ + K でクロップ(切り抜き)が行えます。(後述のテクニックでも紹介しますが、⌘ + C コピーや ⌘ + X カットもできます) 領域を選択する際に Shift を押しながらドラッグすることで枠の比率を維持することができますので、例えば絵文字向けに正方形に切り抜きたい場合に有効です。(この操作はスクリーンショットの領域切り抜きの際にも利用可能です。) また選択中の枠はドラッグやカーソルキーで動かすこともできますので、境界のピクセルに合わせる際などに有用です。

f:id:syque:20181205104025p:plain:w300

f:id:syque:20181205104322p:plain:w300

綺麗に正方形に切り取ることができました。これを 128x128px にリサイズすれば絵文字に登録できます。

人物などを切り抜き

背景色を自動選択しての切り抜きができます。マークアップツールバーの左から二番目にある色選択ツールのアイコンをクリックします。

f:id:syque:20181205102453p:plain

画像の背景部分をクリックし、任意の方向にドラッグします。これにより色の選択範囲を調整できます。 参考画像だとシンプルな背景色なので分かりにくいですが、木の葉など似た色味を選択してくれるのでうまく範囲選択できれば綺麗に人物などを切り取ることができます。

f:id:syque:20181205102930p:plain:w350

f:id:syque:20181205103357p:plain:w350

このような形に切り取れます。写真とかだと背景が複雑なことも多いので、ある程度切り取って残りは選択ツール(矩形や丸など)で不要な部分やゴミを切り取っていくと良いです。 この例だと輪郭に白い線が残っていたり、スカーフの白い部分まで消えてしまっていたりするので調整が必要です。⌘ + Z でUndoが可能なので切り抜く前の状態に戻し、下の余白を切り取ってから領域選択をもう少し深めに実行してみます。

f:id:syque:20181205105411p:plain:w350

先ほどよりはかなりマシになりました。(あまり変わらない? スカーフは直った...)まだ白い線が残っていたりはしますが、絵文字に使う用途であれば 128px まで縮小されるので、多少のゴミや輪郭は無視してもそれほど見栄えには関わりません。あくまでプレビューを使って気軽に...という範囲なのでこのくらいの気持ちで作ってしまいましょう。

(応用) 複数の画像を重ねる

応用として、複数の画像を重ねるというものをやってみます。 例として、先程切り取った人物の画像にウニの画像を重ねてみます。

二つの画像をそれぞれプレビューで開きます。

f:id:syque:20181205111137p:plain:w350

ウニのプレビュー画面で ⌘ + A で全選択し、⌘ + C でコピーします。その後、人物のプレビューで ⌘ + P でペーストします。

f:id:syque:20181205111359p:plain:w350

ウニの画像がペーストされます。この画像はドラッグで移動、角の丸をドラッグでサイズ変更ができるので配置したい場所まで移動&リサイズします。

f:id:syque:20181205111500p:plain:w350

画像を重ねることができました。透過部分は重ねた時にもきちんと透過するので、前述の切り抜き処理と組み合わせるとかなりクリエイティブの幅が広がります。


登録してみる

せっかく作ったので絵文字に登録してみます。アメデオアヴォガドロがウニを持っているのでそのままの名称で登録します。

f:id:syque:20181205112319p:plain:w350

無事に登録し、Slack で使うことができるようになりました。

f:id:syque:20181205112709p:plain:w350

この発言の後にチャンネルの会話の流れが止まってしまった気がしますが、そんな日もあります。ハイコンテクストな会話を重ねることでチームメンバーのコミュニケーションを高めていくことができるのです。 *1


終わりに

非デザイナーでもMacのプレビューでこのような感じに絵文字が作れます。自分で作った絵文字をメッセージやリアクションに使うと愛着も湧くしコミュニケーションもより活発になること受け合いです。*2

今回紹介した以外にも Mac のプレビューの使い方や絵文字の作成ツール(アニメーションGIFにしたり)などもありますので、皆さまこれを機に良いSlack絵文字ライフを送って頂ければ幸いです。

*1: 言い訳

*2: ハメを外しすぎて業務に支障が出ないようには注意しましょう 👀

HTML5 Conference 2018に参加してきました! #html5j #GameWith #TechWith

GameWith Advent Calendar 2018 4日目担当の GameWithのエンジニアの tiwu です。

先日開催されたHTML5 Conference 2018に参加してきました!

f:id:tiwu_gamewith:20181201155309j:plain
お疲れ様でした!

HTML5 Conferenceに参加するのは3度目で、毎回刺激をもらっています。

今回も見たいセッションがたくさんあったのですが、厳選に厳選を重ね以下のセッションを見ました。

  • 光を超えるためのパフォーマンスチューニング/アーキテクチャ
  • カンファレンススポンサーによるライトニングトーク大会
  • 「それ、AMPで作りませんか?」--- RichでResponsiveかつPWAなAMPの作り方
  • Web Components のリアル
  • Web プラットフォーム再考 ~PWA のもたらす未来の光と影 ~
  • HTTP の今と未来 ー BBR, HTTP/2, QUIC の基礎から 5G 試験ネットワークでのブラウザベース評価試験まで
  • スペシャルセッション

各セッション簡単にですが概要と感想を書いていきたいと思います。

光を超えるためのパフォーマンスチューニング/アーキテクチャ

  • 賽の河原でdivを積む
  • この世界の光の速度はとても遅く、世界中の人とリアルタイムにゲームするにはまだ耐えられない(格ゲーなど致命的
  • 60fpsをwebで目指す= 16msの壁を超える必要がある
  • フロントから見たらサーバーというものはデータをシンクするシステム
  • ローカルキャッシュ > CDN Edgeキャッシュ > サーバーキャッシュ > クエリ叩く
  • しかしキャッシュの設計は難しい
  • 高速化は目的ではなく結果に過ぎない=高速化ができるキレイなアーキの証明
  • コードの綺麗さと速度は両立する
  • つまりみんな綺麗なコードを書こう

SWでHTMLキャッシュをしてサイトを作ったことがあるのですが、あれは本当に光を超える・・・

ただキャッシュ破棄戦略とかが難しい・・・

ここの戦略の難しさは綺麗なコードによる綺麗なアーキが繋がってくるんですね・・・!

資料

カンファレンススポンサーによるライトニングトーク大会

印象に残っているのは新人研修でSlackを作ったLTで、サイバーエージェントさんの新人研修のレベルの高さとそれを超える新卒の技術力を感じました。

ほかチームが機能を沢山開発している中で、開発フローや開発体制などに力をいれ、賞を取ったそうです。

※ビデオチャット?の時に美肌加工する機能などあったらしいです(うろ覚えです

最後に苦労した点を聞かれた際に「他チームが機能を作っている中、開発フローなどに力を入れたため、他チームと比べて遅れている、進捗が悪いなど不安になった」と言っていました。

しかし、メンターに相談して不安を取り除いてもらい自信もって開発を進めることができたそうです。

新人研修の内容、新人、メンター全て合わさって素晴らしい新人研修ができていると実感しました。

「それ、AMPで作りませんか?」--- RichでResponsiveかつPWAなAMPの作り方

  • AMPは3年経って、LP以外にサイト全体をAMPで構築する事例も増えてきた
  • 便利なAMPコンポーネントもたくさんできた
  • AMPは簡単にレスポンシブにでき、一休さんのサイトはとてもいい事例
  • AMPとPWAは相性がいい(文字をひっくり返すとAMP <=> PWAになることからもわかる...w)
  • ただ、URLがGoogleドメインになるのは課題として感じており現在対応中(Signed Exchangeを利用)
  • さらに、AMPでJSが使えるようになる!(WorkerDOMを利用)

ついにAMPでJSが動くそうです(震え声)

サイト全体をAMPで構築し、ほぼ光の速度のサイトを作れるのは夢がありますね!

登壇者によるタイムライン

Web Components のリアル

  • IEを無視すれば今すぐにでもいける(2020年にWin7のサポートが切れるからそこまで待つ説)
  • Custom Elements,Shadow DOM,HTML Template,ES Modulesの組み合わせの技術
  • Custom Elements独自タグを作り、コールバックを定義できる
  • Shadow DOMはDOMをスタイルごと隠す
    • slotで小要素を表示する
  • プロジェクトをまたぐコンポーネントを作る時に便利(ロゴなど)
  • ライブラリに依存しないコンポーネントを作る時に便利(Vue,Reactなど)
  • マイクロフロントエンドの実現
    • コンポーネント内にVueやReactを隠蔽できる
    • ボタンはVueが得意なチームが、カルーセルはReactが得意なチームが作るといった分離ができる
  • Web Componentsは標準の仕様なので使えるなら使ったほうがいい
  • 現実的に作るなら、バニラ,lit-html,lit-element,Vueなどを利用したほうがいい
  • lit-elementが作る時は便利

以前Polymer使ってWebComponentsを作ったことがあるのですが今はlit-elementが主流?ぽいんですね

AMPのコンポーネントもWebComponentsベースらしいです。

今後はJSフレームワークではなく、コンポーネントによるサイト構築が主流になるのかも。

資料

Web プラットフォーム再考 ~PWA のもたらす未来の光と影 ~

  • PWA + ○○ が来ている(Web VRなど)
  • WebなのにPWAのせいで使いづらくなることがある
    • スタンドアローンモードは検索バーが消えるので、検索したい時にブラウザにアプリ切り替えをする必要がある
    • 別のページを開くとき、前のページを上書きして開くので前のページに戻れない
  • PWAで夢を見るな、現実を見ろ

僕も作ったサイトにAdd to homescreen入れたのですが、完全にUXの向上など無視してました・・・。

HTTP の今と未来 ー BBR, HTTP/2, QUIC の基礎から 5G 試験ネットワークでのブラウザベース評価試験まで

  • 5Gが来たが、5Gで何ができるのかが課題になっている
  • この前HTTP/3が出た(HTTP over QUIC)
  • ネットワーク技術の変化を知らないWeb開発者はやばい
  • Softbank X WebDinoJapanが世界初の調査結果を公表
  • Web開発者と共に、5Gネットワークの使い方を創っていきたい
  • 5G IoT Studioという場所を提供している
  • 5GだとHTTP/2のほうが遅い
  • ただまだまだ5Gは調査不足

ネットワーク技術の変化を知らないWeb開発者はやばい

この一文にすべてが込められていました。

資料

スペシャルセッション

LT大会とクイズ大会でした!

1000万以上をAMPにした話

  • WeblioをAMP対応
  • 段階的にAMPにしていった
  • 通常のサイトにAMPコンポーネントを使っている

PureJS

  • Haskellライクな関数型

CSSアンチパターン

  • ビルドプロセスから考えることが必要
  • コンポーネント化されているのにCSSだけグローバルになっていた・・・
  • ビルド後のJSはDRYだがCSSはDRYになってない

Preload,Preconnect

  • とりあえず入れるだけでも負担にならない先読みの仕様
  • APIもフェッチできる

Vivliostyle

  • css組版
  • ブラウザの印刷機能を利用しPDF出力する
  • 利用者が増えてきた

Passive Event

  • Chromeの絵を書く人
  • スクロールにEventを貼ると、スクロールがカクつく
  • heightが変わったりする可能性があるので処理が終わるのを待っているため
  • addEventListenerに{passive: true}を渡すと、処理が終わるまでにスクロールするのでなめらかになる

最後に

以前参加したHTML5 ConferenceはAMPやPWAやWeb Componentsは紹介するセッションが多くありましたが

今回は使ってみてどうだったか、などといった事例のセッションが多かった気がします!

GameWithは、ゲームが大好きで、フロントエンドが大好きな方、新しいWeb技術に興味がある方を大募集中! Wantedly でもよいので是非お気軽にお声がけください!

www.wantedly.com