ホーム ブログ ページ 19

良い催しは事前の準備から。第21回基本方針発表会&新春決起パーティ開催!

0

「基本方針発表会」、「新春決起パーティ」とは

アピリッツでは、1月に「基本方針発表会」、7月に「基本方針中間報告会」といった、全社員を集めて会社や各部の来期の方針や現況報告を伝える催しがあります。 発表会後は、美味しいお酒やお食事を頂きながら歓談できるパーティも…!

今回は1月なので、「新春決起パーティ」という名のパーティが催されました。

それではさっそく当日の様子についてご紹介していきます!

いい催しは事前の準備から

催しといっても、事前の準備が必要です。その準備次第で、いい催しになるかどうか決まるほど大事な部分でもありますよね!
今回は、19卒の面々が会場で様々な準備を行っていました!

クイズ大会で使用するビニールプールを膨らませていますね!

出欠確認や案内のために、事前に打ち合わせをしているようです。

P-Review’19の総括動画を流すようですが、音量や映り方のチェック作業をしています。放映は一度のみなので、明るさ調整など細かい指示を行っていました!

事前に案内版を作成し、早めに入り口で待機しているようです。

こういった事前の準備があるからこそ、スムーズに発表会が行われるのですね!

「第21期 基本方針発表会」の様子

事前準備のおかげで、無事に基本方針発表会が始まりました!
社長、そして執行役員の順に今後の方針が発表されていきます。まずは社長より…..

今回のテーマは「アピリッツの歴史」についてでした!2000年7月の創業から今年で20年になるということで、様々な歴史があり社員が自分の会社について知るとてもいい機会となったと思います。

続いては、執行役員の方々から各事業部の方針発表についてお話しをいただきました。

会社の今後に関わる重要なお話がたくさんありました!
和田社長、そして執行役員の堂々と発表する姿が、とても輝いていました♪

最後に第20期下期社員表彰!!今回は会社の業績に大きな貢献を残した社員を各事業部から選出しました。

今回は10名が選ばれました!!おめでとうございます!!!

受賞者の方々には賞状と金一封が授与されました。表彰が終わると新春決起パーティーに移ります。後ろのパーティー会場にみなさん移動します。

「新春決起パーティ」の様子

基本方針発表会の後は、社員同士で歓談できるパーティが始まります。
和田社長による乾杯の音頭と共に、皆さん大きく盛り上がりをみせました。

食事を楽しみながら部署やチームの垣根をこえて話ができる貴重な機会でもあります。

お酒が入ると話しやすいのか、皆さんいつも以上に話が盛り上がっていました!

今年はパーティーのビュッフェとは別にシュラスコを発注したそうで、すぐに行列ができていました….!

パーティーの中で内定者紹介も行われました!

19卒社員 頑張ってます

19卒のメンバーが、出し物としてクイズ大会を開催しました!
参加者はもれなく賞品を受け取れる優しい設計となっており、企画者やるな…という内容でした。

なんと景品にswitch liteも!!大変盛り上がりました。

なかにはこのような賞品も…!事前の準備で用意したビニールプールは、お菓子を入れるためのものだったんですね……!!

事前の準備もあってクイズ大会はスムーズに進行。出題内容もバラエティに富んだユニークなものばかりと、観戦している皆さんも含めとても盛り上がりました!

19卒の皆さん、本当にお疲れ様でした!!

いかがでしたでしょうか。


アピリッツでは定期的にこのような催しを行い、会社や各部の方針を明確に示すことで上層部との齟齬がなくなること。また、パーティでは部署や役職関係なく、誰とでもコミュニケーションを深めることができます♪


2020年も、「セカイに愛されるインターネットサービス」をお届けできるよう、第21期の基本方針のもと各自の目標に向けてがんばりましょう!

株式会社Appiritsでは一緒に働く仲間を募集しています!
アピリッツが気になった方は コチラの採用情報 もチェックしてみてくださいね。

【成果発表会】「”かんたん”な効率化でコストダウン!」ゲームデザインで今すぐマネしたいテンプレ化(動画付き)

今回は社内の成果発表会「P-Review ’19」にて発表した、デザイナ 復本 文人さんの発表を動画で紹介します。

復本 文人
2019年3月ゲームデザイン部デザイナにアルバイトとして入社。
入社後は「関ケ原演義」「幕末演義」担当する。 前職は郵便局職員 兼ストリートアーティスト。

「テンプレ化」と「データ整理」による作業の効率化

動画概要

復本氏は、2019年2月より当社に移管したソーシャルカードゲーム「演義シリーズ」の 2タイトル「関ケ原演義」「幕末演義」のデザイン業務を、1人で担当している新人デザイナです。

「演義シリーズ」3作がアピリッツに運営移管する前は、イラストを除くデザイナ業務だけで約5人/月かけており、運用する上で大きな負担になっていました。 前任者、ベテランデザイナの橘氏は、3作のデザイナ業務を少人数でこなせるようにPhotoshopの「アートボード」にてカードイラストを「テンプレ化」する仕組みをつくりました。

前任者を目標に「どうすれば3作を1人で担当できるのか」を日々意識し、さらなる効率化を目指したところ、3度の運営移管で混沌としてしまっていたハードディスクドライブの「データ整理」をすることで作業時間を大幅に短縮できそうな事に気づき、それを実施した事で3タイトル分を受け持つことができる作業効率まで到達することができました。

さらに、効率化したことでできた空き時間で外注していた新規イラストの一部内製化を提案。毎月の運用コストを節約させることにも繋がりました。 大好きなこのゲームをいつまでもユーザに遊んでほしい。その為には日々の業務を効率化して行く事が重要かもしれません。

毎日同じ仕事を続けるだけでなく、スタッフひとりひとりが「効率化」について考えていくと良いではないでしょうか。

「経験も知識もない新人デザイナが、1人で3つの演義タイトルを受け持てる」仕組みを作る!

担当したデザイン「疾風 幕末演義」を前に笑顔の復本氏
日本の夜明けは近い。疾風の如く幕末を駆け抜け、新時代の魁となれ!大人気アプリ「関ヶ原演義」の続編。「演義シリーズ」第2弾!

意識をすることで、効果的な効率化の方法を見つけられるんですね。すごいです!!
アイコの仕事も効率化できるかな?

発表資料

Preview発表用6-3

【成果発表会】「効果的な広告を打つ試み」小手先プロモーション

今回は社内の成果発表会「P-Review ’19」にて発表した、プランナ 栗山 春樹さんの資料を紹介します。
※記載内容はすべて個人の意見・研究内容であり、会社の見解ではございません。

栗山 春樹
2019年4月アピゲー部プランナとして入社
入社後は自社開発ゲーム「ゴエティア」を担当

PR19-H-kuriyama-3.pdf栗山さん-3

テーマ説明

(※挨拶省略)

早速ですが、こんなことに悩んだことはありませんか?

ゲームの「オモシロサ」には自信があるけど知名度がない……
広告を打ちたいけどお金が無い……
広告の効果に半信半疑だからお金をかけたくない……
  Etc……

特に広告とお金の心配って結構あると思うんですよ。
そこで僕は考えました。タダで効果的な宣伝を打てばいいんじゃないかと…
なので今回はこのテーマはこちらです。

「どうやって、タダで効果的な宣伝を打つか」

ただ、皆さんのほうが僕より何倍も経験があるため、新卒の自分の考えた方法はここで話しても説得力がないですよね。
なので今回は、海外のインディーズゲームから例をお借りしたいと思います。

インディーズというものが何か、わからない方もいるかと思うのでわかりやすく説明します。

インディーズとは

・日本でいうところの同人ゲーム
・開発は小規模で特定の企業には属しておらず、大手パブリッシャーとの契約は無い
・プロダクトアウト思考で基本的にマーケティングで何を作るかよりも先に製品を作っちゃう
・「Indiepocalypse」という過当競争が続いていており、インディーでも生き残っていけないという状態が続いている

ざっというとこの人たちは、製品以外何もない状態で戦っているという訳です。
そんな大変な状態の中でもゲームのヒット作品って結構生まれてるんです。

PLAYERUNKNOWN’S BATTLEGROUNDS/Goat Simulator/Guacamelee!/DESCENDERS

こういう人たちはどうして成功しているのか?どういう風に宣伝を打っているのか?
というのを気になって調べたのでそれを皆さんに共有していこうと思います。

友達にLINEでゲームを宣伝する

友達にゲームを宣伝するってことはわかりやすく”あなたのゲームの魅力”を伝えることだと思うんですよ
海外のインディーゲームの例を紹介します。

About a BlobGucameleee!は同じ開発会社が作ったものなんですけど、ざっくり見てください。

❖About a Blob
・スライムが主人公の横スクロールパズルゲーム!
・障害物を乗り越え、仲間を救い出しましょう
・24個のステージ
・沢山の実績とチャレンジを用意しました!

❖Guacamelee!
・決して戦闘が絶えることが無いアクションゲーム!
・2つの異なる世界、「死」と「生」の世界をボタン一つで行き来しましょう!
・魅力的な過去を持つボス、特殊な敵が大量に登場します。
・ニワトリ……沢山のニワトリが登場します。

About a Blobの広告は抽象的で、売りがちょっとわかりにくくないですか?
ゲームの売りが分からないから興味が湧きにくいと思います。

2つ目のGucameleee!は何を売りにしているのか、このゲームの面白さは何かを明確に伝えることができてると思います。

だからAbout a Blobに比べてGucameleee!は売り上げ差で言うと10倍くらい売り上げが違ったんです!
この事例から分かるのはゲームの面白さを明確に伝えることってめちゃくちゃ大事ということです。

特に勘違いされやすいのが、開発が考えるゲームの魅力とユーザーにとっての魅力って全然違ってHooker(引き)Kicker(掴み)っていうとらえ方をしてる海外の方が多いんですけど、まず広告で重要なのは引きをアピールすることが大事だと思うんですよ。

引きの大枠をとらえると直感的に理解・想像しやすいもの、次に他のゲームとあなたのゲームで明確に差別化できている点、そして既にゲームをリリースをしている場合はあなたのゲームをユーザーがどういう風に評価してくれているのかというのを理解して広告打つのが重要だと思います。

うちのゲーム、ゴエティアで参考の例を出してみます。

ゴエティア -千の魔神と無限の塔-

A.ひとりで遊ぶことはもちろん、多人数のプレイヤーで協力しながら同時に遊ぶこともできるマルチバトルRPGです。

B.好きなキャラクターも限界まで育成出来るマルチバトルRPGです。育成次第ではどんなに強い敵でも一撃で倒せます。

Aは実際にプレスリリースとかゲームの公式サイトに打ってある広告で、Bは僕が考えた広告です。

正直な話自分で言うのもなんですが、AよりもBのほうがもっと面白そうじゃないですか?
なぜならこのゲームの一番の面白さををより明確に伝えることができている
さらにそれに対して、ほんとに育成次第ではどんなに強い敵でも一撃で倒せるという他のゲームにはない面白さをしっかり提供できているんですよ

自分のゲームの面白さを明確に伝えるっていうことはすごく重要なことだと思います。

好きなキャラクターも限界まで育成出来るマルチバトルRPGです。育成次第ではどんなに強い敵でも一撃で倒せます。

貴族を仲間にする

皆さんPUBG(PLAYERUNKNOWN’S BATTLEGROUNDS)ってご存知ですか?

関連画像
PLAYERUNKNOWN’S BATTLEGROUNDS

今でこそインディーとは言えない規模に成長しましたが、はじめはすごい小規模な開発チームから始まり、広告費もほとんどなかったんです。

このゲームがやったすごいことはAlpha1~リリースまで全てストリーミングを許可したんです。
ここで重要だったのが、Alpha~Closed betaは会社側が招待しないと参加できなかったんです。
ですが、ストリーマーが参加したいと言ったらすぐにキーを渡していました。

この結果どうなったかというと・・・

Closed betaへ招待された方達は「自分は特別な存在なんじゃないか」と思いゲームに対して貢献してくれるロイヤルユーザーになったんです。

さらにAlpha~リリースまで、運営はユーザーの意見をちゃんと聞いてどんどんゲームが良くなっていってるのを生放送し、このゲームはどんどん向上していくんだなっていうことがユーザーに伝わ運営への信頼に繋がりました。

なので、ストリーマーがたくさんいて運営側も信頼されているということで、リリース前から既にゲームを遊びたいというユーザーが大勢いました。

インフルエンサーを味方にする

あなたのゲームを広告してくれる有名人を味方にすることってものすごく重要なんです。
何をするかというとインフルエンサーに特権を与えてそれを話題にしてもらうんです。

継続的に”あなたにしか与えていない特権”を提供することにより、その人を単純にゲームを広告しているという意識から、「私たちがこのゲームを面白くする役割を担っているんだな」という当事者意識をしっかり持ってもらうことができます。

さらにそれだけではなく、これに対して重要なのがインフルエンサー側にもしっかりとメリットを提示することで、あなたのゲームの面白さを伝えることで視聴者数が増えますよとか他にない特典を得ることができますよっていうのが重要です。

そういう人を味方にするのはどういうことかというと、勝手に宣伝してくれるんですよ
例えば声優さんなら「私のキャラクターこんなのが出ましたよ」とか、絵師さんだったらそのキャラクターの絵をいっぱい書いてくれたりとか、そういう風に勝手に宣伝してくれるのでまず損はないかと思います。

そして、友達ができる
これはほんとの友達というよりも、ビジネスパートナーができるということです。
一緒に作品を作っていくという上で、今後の作品も手伝ってくれるビジネスパートナーができるというのは非常に大きい点かと思います。
これらを用いて具体的に何をするのかというと僕はこんなことを思いつきました……。

声優さんにリリース前のキャラクターを先に渡す!!

この画像には alt 属性が指定されておらず、ファイル名は image-6.png です
(左から)コスプレイヤー:立花 はる(ふとんちゃん)様/声優:山根 絢様/声優:相沢 舞様

うちのゴエクロで生放送をしてくれている声優さんがいるので、その人達に新しいキャラが出る時は先に渡してそのキャラクターに対してツイートしてもらうとか……
生放送でこういう使い方があるんですよねっていうのを言ってもらうとか……
公式のアカウントよりも声優さんの方がフォロワー数が多いのでインプレッション数が稼げます。

そして、声優さんや絵師さんって絶対に1回は自分の書いたものを宣伝してくれるんですよ。
最初渡した時にまず宣伝してくれると思うので1回
さらにリリースされたタイミングでもう1回と、運が良ければ2回宣伝してくれるので効果はあると思います。

ユーザーと仲良くする。

Descendersという例を紹介します。
Discrdっていう海外のチャットツールでユーザーと運営が積極的にコミュニケーションをとりあったんです。

運営はユーザーのゲームに対するフィードバックに実際にテキストで答えて、さらにそのDiscrdに参加してる人に限定的な特権を与えました。

その結果何が起こったかというと、ユーザーに対するコミュニティが活性化して、新しいユーザーが一番最初に触れるコミュニティが盛り上がっているように見えたんです。

「今何が欲しいのか」」「どこが面白いのか」 ユーザーのニーズを正確に把握できるようになり、ユーザーが求めている提供ができる”良いゲーム”ということで、口コミからもゲームは広がっていきました。

ユーザーと仲良くすることは重要だよっていうことです。

ユーザーとの距離をなるべく近くする

・運営とユーザーがコミュニケーションを取れる場所を設けて、運営側からユーザーに問いかける
運営が「今何が欲しいですか」「今このゲームのあなたが楽しんでいるところは何ですか」と問いかけ、さらにそれに対して・・・

・ユーザーの意見を聞いていることをアピールする
一方的に答えをもらうのではなく、ちゃんと僕たちはあなたの話を聞いているんですよっていう感じで双方でコミュニケーションをとっていくことが重要だと思います。

実際にはこんなことが行われている

・日常的なことをキャラクターになりきって呟く
「今日は暑いですね~」とかキャラクターになりきってTwitterでtweetした。

・Twitterでゲームに興味があると呟いてる人にDMする
ここまでやるとすごいんですけどTwitterとかで「ゲームに興味があるよ」って呟いてる人がいたら「今僕たちのゲームはこんな特権与えますよ」とか「今このリンクから押せば10連ガチャ一回無料で引けますよ」みたいなことをDMしてユーザーを勧誘していた。

・ユーザーの絵をゲーム内のスタンプにした
ユーザーが実際に二次創作で描いてくれた絵を「これはすごく素晴らしいデザインなんでぜひともゲーム内に入れたい」と言ってゲーム内のスタンプにした。

派手なことのやり方3条

派手なことでとりあえず皆に周知してもらうっていう戦略をとりたがる人は多いと思います。
GoatSimulatorっていうのが、めちゃくちゃ派手な広告を打ったんですよ。

その広告のプロデューサが「この3か条をとりあえず守りましょう」と言いました。

1.ゲームを遊んでいる人にしか理解できないコンテンツは使わない
そのゲーム内でめちゃくちゃ価値のあるものを大量に配りますよって言ったところで結局あなたのゲームをやってないユーザーには効果がないんです。

2.ゲームと関係なさすぎることはあまり意味がない
実際の例になるんですけど、FPSを作っているのに「ネックレスを配りますよ」とかはたしかにTwitter内でRe tweetされると思いますが、それは”ネックレスが欲しい人”であってゲームに対して興味を持ってくれるユーザーではないのであんまり意味がないことです。

3.詐欺と思わせるようなことはやらない(騙す)
Twitterにて、「このtweetが1万リツイートいけば箱が開いて中から特別なものが出ますよ」と言い、いざ開いたら期待外れなものを出してしまったんです。
それに対してユーザーは騙されたと思い、ゲームを遊んでないのにゲームに対する悪い印象が定着しちゃったんですよ。

そういうことは絶対にやらない。

まとめ

皆さん、このプレゼンなにか新しい発見はありましたか?

……正直なにもないと思います。
だって考えたらこれ、めちゃくちゃ普通のことなんです。

ユーザーと触れ合ったり、声優さんと仲良くしたり、宣伝を打つ文言を考えるなんて、ユーザー視点からするとめちゃくちゃ普通のことなんですよね。

ですが、これはどのゲーム会社でも、なかなかできることではないと思います。
だってユーザーに毎回DMを送ったり、お問い合わせに丁寧に返したりするのって正直面倒くさいことで、とにかく大変なんですよね。
ですがそういう大変で地道なことを、しっかりやってるところのゲームが結局売れるんですよね。

僕が調べた海外のプレゼンターが毎回言ってました「別に僕の言ったことは面白いことじゃない、めちゃくちゃ当然なことだけど、そういう当然なことをやろう」ざっくりいうとゲームを売りたいんだったらどんなに大変でもやらなきゃいけないよ!!っていうことです。

僕は今回発表したような方向で、効果的な広告を打つ試みをしていきたいと思ってます。

ご清聴ありがとうございました。

ポーズを頼むと箱ティッシュを持ち出したり、謎のサービス精神がある栗山氏。

当然なことだけど、そういう地道なことが大切なんですね……。
アイコも地道に頑張るぞー!

アピリッツのクリスマスの様子をお届け!

0

こんにちは!皆さんクリスマスはどのようにお過ごしでしたでしょうか。

アピリッツではクリスマスが近づくとオフィスにクリスマスツリーが登場します!

玄関とオフィスの中にもツリーがあるのでご来社頂いたお客様や社員のみなさんにクリスマス気分を味わってもらえます!

クリスマス当日は社長自ら近くのケーキ屋さんに行ってお菓子を買って社員全員に配っていました。

写真には入りきらなかったのですが全部で32箱(笑)

店員さんがとても喜んでいました♪(笑)

ちなみにアピリッツのオフィスは原宿(明治神宮前)のため、帰りに表参道、原宿の綺麗なイルミネーションを見ることができます!

来年のクリスマスはサンタ(社長)から何が届くでしょう………♪

毎年冬が来るのが楽しみですね!
株式会社Appiritsでは一緒に働く仲間を募集しています! アピリッツが気になった方はコチラの採用情報もチェックしてみてください。

【成果発表会】「自分の魅せたいものを作る」Live2Dの表現と技術共有

今回は社内の成果発表会「P-Review ’19」にて発表した、デザイナ 森田 彩加さんの資料を紹介します。
途中でSpineについてなど、正確とは言いづらい情報が記載されていますが、そのままの掲載とさせていただきます。ご留意くださいませ。

森田 彩加
2019年4月コンテンツデザイン部(現:ゲームデザイン部)にデザイナとして入社
入社後は主にLive2Dを利用したキャラモーション作成やUIデザインなどを担当

Live2Dの表現方法

テーマ選定理由

(※挨拶省略)

テーマ選定理由なんですが、私はこの会社に入って初めてLive2Dを触りました。

ですが、社内にLive2Dの知識を持っている人が少ないなというのを感じ、簡単でもいいのでLive2Dのことを少しでも知って欲しいと思い、このテーマを上げさせていただきました。

もう一つの理由は、Live2Dには沢山の表現方法があり、発想次第でかなり自由に作ることができます!
ですが、自由度が高いゆえに指定されたものがない限り、何をどう見せたいかわからなくなってしまうことがあります。

そうならないために、今回参考として表現方法をいくつかご紹介したいと思います。

Live2Dって?

まずLive2Dとは、株式会社「Live2D」が作成しているPC用ソフトウェアのことを指します。

正式名称は「Live2D Cubism」という名前です。

2Dの、一枚絵のイラストをPhotoshopなどのイラストツールで頭や腕などのパーツ分けを行い、それを立体的に動かす技術です。
Live2Dにはモデルを作成するモードと、そのモデルにアニメーションをつけるモードがあります。

用語説明


まずメッシュ、アートメッシュというのは3Dでもよく見るポリゴンのようなものがあります。

そしてLive2D特有のもので、デフォーマというものがあります。簡単に説明すると、複数のパーツをデフォーマと呼ばれるフォルダに入れて、そのフォルダごと動かす事ができるツールです。

こちらのメッシュ、アートメッシュ画像にそのまま動きをつけることもできるのですが、そうすると動きに制限がついてしまい、後々困ることにもなったりもします。
なので、基本的にはデフォーマを使って動きを付けていきます。
※アートメッシュのにそのまま動きをつけたほうがいい場合もあるため、場合によります。

続いてLive2Dのパラメータというものがあります。これはモデルの動きの幅を規定するものです。


パラメータに点を打ち、パーツやデフォーマを設定することでモデルを動かすことができます。

Live2Dにはデフォルトで既に入っているパラメータがあるのですが、動かしたいパーツ名のパラメータがない場合があります。
その場合、腕や足はデフォルトにもともとないので新しく作るという方法がとれます。

2Dアニメーション作成ツール

ここでLive2D以外の2Dアニメーション作成ツールをご紹介します。

こちらのSpriteStudioはアピリッツでも2Dキャラを扱うときなどに使われています。

もうひとつのSpineなんですが現在海外向けのものしかなくて国内でも少しだけ使われている例もありますがそこまで浸透してはいません。

それでは本題のLive2Dでどんなものが作れるのかの説明に移ろうと思います。

表現方法の紹介

大まかに三つを紹介いたします。

①全身立ち絵を動かす
一番多くみられるのは一つのモーションをつけ、それをループさせて作成することが多いです。

②アニメのような演出
Live2D表でカメラワークなどを使ってアニメのように見せる演出があります。
例えば最近のゲームにて、カットインやガチャ演出などに多く使われています。

③Vtuberモデル
FaceRigというソフトを使い、自分の顔にカメラで対応されたモデルをVtuberとして使っています。ほぼ顔をメインとしたモデルとなっています。

3つ紹介致しましたが、制作する上での相違点も併せて紹介します!

制作相違点

3つとも2Dイラストをパーツ分けする点は同じです。

ただ①全身立ち絵を動かす③Vtuberモデルはパラメータのつけ方が似ています。
違う点はアニメーションの制作があるかないかになっています。

②アニメのような演出はこの2つとは全く違う作り方をしております。
これに関しては私もまだあまり研究ができていないのですがアニメのように魅せるためのパラメータ等、その他差分など作成する必要があります。

①~③は流用できる部分はあるのですがは、一つのモデルを作ったからと言って全部の表現ができる訳ではないというのが注意点です。

おおまかにどのような表現を先に作るかを決めることで、より動きに違和感のないモデルが作成できます。

最近のLive2D作成ポイント

続いて最近私が作ったLive2D作成のポイントをご紹介致します!
ここからはLive2Dを少し触ったことがある方向けです。

「AIチャットボットAiCHO」アイコちゃんのLive2Dモデルを作成いたしました。

■『心にひびくAIチャットボット AiCHO』とは
アピリッツでは、「接客・応対品質の向上」「顧客との対話」「業務の自動化」を目的としたチャットボットとして『心にひびくAIチャットボット AiCHO』(以下AiCHO、読みアイチョ)を開発しております。

今回はVtuberモデルということでFaceRig対応をしたモデルとなっています。
ポイントとして2つご紹介いたします。

顔の角度XY

顔の角度XYは簡単に言えば顔の上下左右のことです。

顔の角度は、パラメータに8つの点を打ちます。
正面を真ん中として、その他に8つの角度から見え方を作成するという形になっています。

ただ初めてのLive2Dでの作成で、最初からどの角度から見てもおかしくないようにするのはとても難しいと思います。

私のやり方は好きなアニメから「この角度良いな」みたいな角度を持ってきて、その角度を理想として真似をするような形で作成しました。
理由は既に世に出ているものなら、たくさんの人が見ている・評価しているものが多いので良いものを作る近道になると考えました。

特に顔周りは目線が集まりやすいところなので、これでもか!というくらい丁寧に作ることが大切です。

FaceRig対応

まずFaceRigというのは、主にVtuberなどに使われているソフトでウェブカムというカメラを使い2Dや3Dのキャラになりきれるソフトのことです。

気を付けた点は4つあります。

①自分で動きを付けるのではなく人に適応した動きをする

FaceRigは作成者がアニメーションで動かすのではなく、カメラでに映る人に対して動くのでチェックをしつつ調整を重ねることに気を付けました。

②FaceRigに対応するLive2Dパラメータ

Live2Dのパラメータは初期からあるパラメータもありますが、FaceRigにデータを持って行った時に対応しないものや自分の予想と違う動きになるものがあります。

■FaceRigでウェブカム対応が無い
通常通りに体の動きを「体の回転XY」に付けてしまうと反応しない。
正確には体の回転Xには対応しているが、マウス操作やショートカットキーを使用しなければならない。

■対応策
顔に追従するように、顔のパラメータ「角度XY」に体の動きを入れると良い。

③何を一番に魅せたいのか

簡単に言えばどの部位を一番見てほしいかです。
アイコちゃんの場合、FaceRigで動くということで顔に重点を置き、目のハイライトや口の動きに気を付けました。
胸などの女性的な部分よりも表情でかわいらしさを表現したかったため、あえて胸揺れは付けていない方を採用しました。

胸揺れなし(採用)
胸揺れあり

色気の強いキャラ、またはそういう作風なら顔にプラスして胸や足に重点を置いてもいいと思います。

④プロジェクトに沿った可動域を考える

キャラの可動域は制作時間などの制限がない限りどこまででもつけられます!!

ですが、やりすぎてしまってここはいらないと言われるのも悲しいので、一番最初に何に重点を置くか考えておくことはとても大切です。

今回伝えたかった事

色々な表現が、アプローチができるLive2Dってほんとにすごい!!

しかしその点を踏まえながらもまだ新しいソフトなので、まだまだ研究が必要です。
色々なものを見て、自分から表現の幅を広げていくことが大事だと思っています。

今回表現方法を3つご紹介しましたが、まだまだたくさんの表現があり、新しい表現や技術などはネットで調べたりするほうが多く出てきたりします。

そちらも参考にし、研究段階の足掛かりとして表現の種類・魅せたいポイントを決めて、その中でより魅力的な見せ方を考えることが大事だと思っています。

そうすることで、自由度の高いLive2Dでも自分の魅せたいものを作ることができます!

自分の表現したいものを追求できるLive2Dってすごい・・・
アイコもアイコを動かせるようになりたいです~!

お仕事中の森田さん(Appirits公式Facebookより)

「興味を発信することで知識が集まる」小さな活動から意識を変えるミニカンファレンスの仕組み

山田アイコ、社内のイベントを発信します!

今回は、自社ゲーム開発をしているアピゲー部のグループマネージャー『吉田 啓紀』さんから、4月より開催しているミニカンファレンスについてお話を伺ってみました。

吉田さん、今日は宜しくお願いします!

インタビューを通してミニカンファレンスの活動を周知していただけると伺いました。是非、宜しくお願いします!

仕事中の吉田氏

吉田 啓紀
2012年にWebのエンジニアとして入社
現在は、アピゲー部のグループマネージャーとして新作ゲームのディレクションと、
いくつかの既存ゲーム運営メンバーのマネージメント業務を行っている。
業務の傍ら、2019年4月より『ミニカンファレンス』を発足。

『定期的』にアウトプットする場を作りたい

まず、ミニカンファレンスを始めたきっかけや目的を教えてください。

社員の中でもっとアウトプットする場がほしいという話がもともとあったんですよ。

後は、部署が結構増えてきて部署間での情報共有が難しくなってきたなと、僕自身も感じていました。

アウトプットする場が、社内に少なかったということでしょうか?

少ないというよりは「あったけれど定常化はされていない」状態でした。
今までは突発的なもので『LT会』とか皆で技術書読もうみたいな『読書会』はありましたが、なかなか続けてやる題材がなかったんです。

開催者も「思いついた時にやる」みたいな感じだったのでほんとにまばらでした。

良い会なのにもったいないですね、そこで定期的な会を作りたいと……。

はい、いつ開催されるか分からない会に向けて目標を建てるのって難しいと思うんです。

前に開催したもので『LT』って名前を使っちゃったし、それなら名前を新しくして定期的にやる会を作ろうと思って始めたのが”ミニカンファレス”です。

ハニカミながらインタビューに答える吉田氏

なるほど!
定期的に発表があった方が、みんなが目標建てしやすくなっていいですね。

そうですね。
「今期あったことをミニカンファレンスまでに整理して発表ができれば」という話も最近ぽつぽつと耳にしていて、良い目標作りのきっかけになっているんじゃないかと思っています。

新技術を導入し、他のタイトルにも取り入れる

ミニカンファレンスでの印象深いエピソードはありますか?

直近だと、「発表した内容がもう明日から使えるね」と話がまとまって、プロジェクトにそのまま入れることになりました。

すごく早いですね!その新作ゲームにはどのように取り入れましたか?

発表した人自身がもうゲームに実装しているものだったんですが、「じゃあそれを他のプロジェクトにも入れよう」とすぐに決まりました。

どんなゲームなのでしょうか。良ければ宣伝していきませんか?

実装元は『ゴエティアクロス』というタイトルで、それとは別に新しく開発しているタイトルに取り入れようということになりました。
開発中のゲームについてはまだ詳しくお知らせできませんが、来年にはユーザーの皆様にお届けできるかと思います。

私もゲスト出演している『悪魔少女✕マルチプレイRPG ゴエティアクロス』。
是非、プレイしてみてくださいね!

アウトプットする事で得られる変化

ミニカンファレンスが会社に与えた変化はありましたか?

社員側が『定期的にアウトプットの場がある』ことを認識するようになったことで、目標設定として「次のキーワードを何か自分で研究してみて、それをミニカンファレンスで発表します。」と声が聞こえてきた事に関しては、すごくいい変化に感じました。

以前からあるブログ(DoRubyなど)ではアウトプットを目標として設定できなかったのでしょうか?

設定してる部署もあればしてないところもありました。ブログっていうのは結局「見る人は見るけど、見ない人は見ない」ものなので難しいと思います。

あと実際に人が前に立って発表することと、システムに書いて打ち込んで媒体として出すっていうのは、結構”行為”として違うなっていう風に思っていて、どちらも学んだことをまとめるっていう意味では同じなのかもしれないですけど、やっぱり個人的には前に出て発表するっていうのをもうちょっとやってもらいたいなと。

真剣な表情で語る吉田氏

吉田さんが考える最終的なゴールはどこですか?

社内のカンファレンスにも出てもらって発表して「俺たちすげえじゃん」みたいなとこまでいけるとゴールかなっという風に思っています。

明確で解りやすいゴール設定ですね!
ちなみに初回のミニカンファレンスでの反応はいかがでしたか?

まあ、「良かったね」という感じでした。マイナスな印象はなく、発表することに対して前向きな人が結構多かったです。

何か課題など出てきましたか?

発表する人が固定化されてきちゃうかなってところですね。
もうちょっといろんな人に発表してもらえればいいんですけど……。

特にどんな人に発表してほしいと思っていますか?

社内ではいろんな技術使っていて、実は業界的に見るとすごいことをやってるんだけど、その場に技術を持ったまま留まっちゃってる「もったいない」状態の人がいるんじゃないかと気づきました。

その人達にいきなり社外に向けて発表してくださいっていうのは、ハードルも高いですし、そんな恥ずかしいことできないってなると思うんです。
なので、その人達にはこのミニカンファレンスを最初の踏み台としてやってもらえたらと思ってます。

吉田さん自身は最初のミニカンファレンスでどんな発表をなさいましたか?

自分はエンジニアの発表をしようと思っていたんですけどせっかくなので、誰もあんまり触れていない広告の話をしました。
そこそこ興味持って見てもらえたと思います。

広告回りをやってる人があまりいないっていうところで布教活動にも使いたくて発表しました。

同じものに興味ある人が集まるきっかけにも使えるんですね

そうですね、広告回りでいうと興味はあるけど具体的に何やってるか知らないっていう状態の人が結構多いので、その辺の共有にも使えます。

ミニカンファレンスを実際に行って吉田さんにとって良かったことはなんですか?

皆色々やってくれてるんですけど、なかなかそれを引っ張り出すことができないなと思っていました。

ミニカンファレンスを開催したことで「あ、そういうこと考えてるんだ!とか、そういうことやってたんだ!」っていう普段見ててもわからない所を引き出せたいいきっかけになってくれました。

一つの手段としてそういう場を設けられたのは良かったと思っています。

メンバーの体験を満面の笑みで喜ぶ吉田氏

発信してもらってより理解しあえたんですね

発信することで逆に周りからも興味や知識が集まって仕事に活かせたり、見る側としてもメリットが大きいと思います。

ありがとうございます。
最後に、今後はミニカンファレンスをどの様にしていきたいとお考えでしょうか?

最初にも言いましたが、いろんな人に自分の興味あるものや取り組んでいることをもっと発信して共有してもらいたい。

他の部署と連携してミニカンファレンスの様子をYouTube配信などもしましたけど、そんな風に一緒に協力してやっていけたらよりよくなっていくんじゃないかと思っています。

発表したスライドを前にいい笑顔を見せる吉田氏

社内で定期的な情報共有の場を作り、社員全体の知識レベルを上げる取り組みはとても重要ですね。
もちろん私達CTO室も共に盛り上げますよ!

アピリッツが気になった方は コチラの採用情報 もチェックしてみてくださいね。

どうしようもないけどやれるだけのことはやってどうにかしよう

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

がんばろう

貴方はプロジェクトにアサインされ、サーバーの負荷試験を依頼された

「頑張るぞ! ガルバンゾ!」

ここにコードがあった。それは見るからに不味そうなスパゲッティであった

「お? おお……」

ここにスケジュールがあった。それはスパゲッティが腐るまでに時間がない事を示していた

「おお……。お、おお……」

それは即ち、根本解決をするだけの時間的猶予がない事を示していた

「おおあああああっ、うっ、うぐぅっ」

貴方の使命は、せめて足掻く事であった

「……」

現状整理から始めよう

 コードがスパゲッティになる理由は幾らかあれど、そんな事を調査していても始まらない。
 やるべき事は罪を償わせる事ではない。罪を代わりに償う事だ。
 まずは一つ一つ現状を整理し、問題解決には何をすべきか考える事である。

 現状を調査した結果、まずはとても良い事が分かった。

テストを書く文化がある

 これが何を意味するかというと、コードの振る舞いがテストによって保証されているという事だった。
 コードが中でどんなに破茶滅茶な事をしていても、テストが通りさえすればそのコードは少なくとも挙動としては正しい。
 即ち、中を書き換えてもテストが通りさえすればその正当性は保証される。最後にQAなどを通す必要はあるが、これから行う改修に対しての強力な道しるべとなる。

使用している監視ツールはデータベースの重みを調査するものと、サーバーそのものの重みを監視する二つを利用していた

 確かにこれで重い部分がある程度は分かる。ある程度ではあるが。
 これではコード全体の重みは一部見逃される恐れがある。レスポンスの遅さとは、データベースのクエリ以上にコードそのものの重みが原因となる場合があるからだ。
 ただ、それは誰かに何かを依頼する事もなく調査、解決出来る。
 そしてその監視ツールがある事自体はとても有用である、というか無ければ負荷試験は出来ない。

最も問題であるコードは1APIの中で何度も同じデータを参照する事があった

 マスタデータやユーザーデータを、そのコードが呼ばれる度に参照、計算して返していた。
 1回の呼び出しでユーザーデータが多数変更され、また都度都度必要となるマスタデータは変わる。それが1APIの間で何度も発生する。
 そしてまた、これを根本的に解決する事ーー例えば1回の呼び出しに纏めるーーといった事などは影響範囲や再度掛かるQAへのコストなども鑑みると時間の都合上不可能。
 出来るのは1回1回で掛かるコストを出来る限り減らす事、それが最善だった。

改善方針をまず固めて共有しよう

 見ての通り改善すべき事はデータベース上の重みとしてもコードとしてもはっきりしている。
 ただ、改善するものの規模が大きいのならば、見切り発車で改善を決めるのではなく、一旦共有して見落としが無いかなどを第三者の目からも含めて判定した方が良い。

「ここの重みを削れれば、取り敢えず重みは60%位になります」
「60%でもまだ重いな……他の部分は?」
「まだ調査していないです。ただ、ここのコードの重みとしては、このAPIの負荷の割合を見てもデータベースの重みではなく別の部分である事ははっきりしているのと、今のツールでは調査しきれない部分もあるので先にやってしまおうと思います」
「……まあ、良いか。で、どうやって削る?」
「基本的に1API間でユーザーデータを使い回す、1スレッドで同じマスタデータを使い回す、という感じですね」
「どうやって使い回す?」
「ユーザーデータに関してはのユーザーのインスタンスが1APIで使い回されているので、そこにインスタンス変数として保持しまおうかと。
 マスタデータもメモ化してしまいます。
 まあ、要するにユーザーデータ、マスタデータ共にスレッドのメモリにキャッシュします」
「……メモリに負荷が掛かるだろうけどそこ辺りは」
「幸いそちらはまだ余裕があります」
「オーケー」

改修したが想定までは減らなかった

「まあ、そう簡単に減らせたら苦労しないよなー……」
 確かに、無駄なデータ検索量は減った。幸いマスタをメモリに持たせる施策も、強いメモリ負荷もなく実現出来た。
 しかしながらAPIの重みを見ると、データベース起因ではない不明な重みが大半を占める事となっていた。
 これは即ち、コード自体に問題があるという事だ(掛けている負荷が適切であれば)。

 アプリケーションに対するプロファイリングツールを導入し確認してみると、膨大な配列から必要なデータを参照してくる部分に大きな問題があった。
 既存の部分だけではなく、自身が改善したユーザーデータやマスタデータを使い回す処理でも、その引っ張ってきたデータから目的のデータを探り当てる処理で重みが発生してしまっていた。
「データをDBからメモリ上にデータを乗せるだけではまだ駄目か……」
 こうなると、その検索処理などをどうにかするしかない。
 コードを読み込み、どのようにデータが扱われているかを確認していく。
・ある条件に当てはまるユーザーデータは、特殊な条件の場合にしか参照されない事が分かり、基本的に検索から抜いても良い事が判明した。
・同じマスタの中でも種類が膨大にあり、複雑な検索条件でもメモ化の形を工夫すれば配列検索の回数を減らせる事が分かった(マスタを分けろよという愚痴は心の奥底に仕舞った)。
 そんな事からユーザーデータやマスタデータを分類分けしていくと、何とかなりそうな目星がついてきた。

※ruby_on_railsだとindex_byやgroup_byがとても有用。単純にデータ検索をするにしても配列からfindを仕掛けるよりもハッシュにしてキーが存在するかを判定した方が確実に早いです。
サンプルに以下。

1.

array = (1..1000).to_a
begin
  now = Time.now
  1000.times do |n|
    array.include?(n + 1)
  end
  p Time.now - now
end
=> 0.0051824

2.

hash = (1..1000).each_with_object({}){|n, res| res[n] = true}
begin
  now = Time.now
  1000.times do |n|
    !!hash[n + 1]
  end
  p Time.now - now
end
=> 0.0001501

かなり改善された

「ここまで改善出来ました!」
「これなら耐えうるな、で、コードは?」
「こうなりました!」
「……複雑だな……」
「……そうなんです。まあ、テストコードがあったので振る舞いは保証されています」
「そうだな、そうか(テストコードの網羅率って100%だったかな……)」

 根本原因を解決出来ずに上部だけで対応しようとすると、そうなります。
 できる事はスパゲッティを美味しく作り直す事ではなく、防腐剤を振りかける事、ただそれだけだったのですから。
 しかしながら、そうしなければいけない時もあるのです。きっと。

美味しいスパゲッティの作り方

  1. 厚切りの芽を抜いたニンニクと唐辛子をたっぷりのオリーブオイルで常温から弱火で炒めましょう
  2. ニンニクはきつね色になったら取り出しましょう。唐辛子も焦げる前に取り出しましょう
  3. 好きなキノコを好きなだけ入れて塩を振って炒めましょう
  4. 塩をきつめに入れた熱湯で茹で上げたスパゲッティを和えましょう
  5. 皿に盛り付けてから取っておいたニンニクと唐辛子と、あればパセリを意識高めに散らしましょう
  6. 食べよう

カスタマーサポートの極意 2019 #3 レポート

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

セミナー概要

・カスタマーサクセスを意識したカスタマーサポートの方法
・顧客から高い満足度を得続けるカスタマーサポートの方法
・カスタマーサポートに適したサービスの選定方法

登壇者

  • 弁護士ドットコム:三浦陽菜様「クラウドサインの新しいカスタマーサポートの方法」
  • ベルフェイス:森本真伍様

クラウドサインの新しいカスタマーサポートの方法

  • クラウドサインとは
    • クラウド型電子契約サービス
  • リレーションの現状
    • チャットサポートの目標
      • 速さ
      • 満足度
    • 体制と測定方法
      • 3人体制
      • チャットの最後の満足度を聞く
    • 結果
      • 初回連絡60秒以内(満足する結果)
      • 満足度90%以上(満足する結果)
  • 満足度とチャーンの結果
    • 満足度が低い顧客が解約しているわけではない
    • 解約している顧客はサポートに問い合わせがない
  • サポートの意味は?
    • 関係を築き続けることが大事
  • 関係を築き続けるには?
    • CX(カスタマーエクスペリエンス)の向上が大事
  • CXとは?
    • 顧客に手間を取らせない(1回の連絡も手間)
  • 手間を取らせない方法
    • 1.疑問が生まれない
    • 2.疑問を自分で解決できる
    • 3.疑問は聞けば分かる
  • 「疑問を自分で解決できる」の現状
    • ヘルプセンターで解決できる
  • 問題点
    • 存在の認知度が低い
    • チャットの方がラク
  • 問題点の解決策
    • elevio
  • elevioについて
    • 開発せずにツールチップ(はてなマーク)を設定可能
    • intercomと連携できる
    • elevioからアドバイスをいただける
  • elevioをを使った今後の予定
    • データ収集
  • まとめ
    • ユーザーに努力をさせないこと
    • 爆速で解決できること

ベルフェイスのカスタマーサポート

  • ベルフェイスとは
    • インサイドセールスサービス
  • カスタマーサポートの極意とは
    • 個に頼る
  • KPIの達成状況
    • チャットの初動時間:60s以内(コツは画面と音)
    • 満足度:95%以上
    • (こちらからのアンケートなどに対しての)回答率:40%
  • KPIと行動指針
    • カスタマーファースト
    • オーナーシップ
    • ハイスピード
    • 改善
    • 細部を大事に
    • メンバー内協力
  • 具体的な対策
    • よかったことの共有
    • 満足度が低い対応への改善検討(メンバー全員で)
    • チャット対応のポイントを共有(docbase)
  • 課題
    • 数値を正しくとる
  • まとめ
    • 行動指針をCS向きにする

Search Engineerring Tech Talk 2019 Spring レポート

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Search Engineering Tech Talk 2019 Spring レポート

Search Engineering Tech Talk とは

検索技術勉強会の目的は、「検索」/「検索システム」にまつわる技術や手法に関して共有できる場を提供すること

登壇者

  • ナビタイム 小式澤 篤 :「安心な移動」のためのPOI(Point-of-Interest; 地点)検索
  • 菅谷 信介 :社内ドキュメント検索システム構築のノウハウ
  • @818uuu :料理動画アプリ「クラシル」の検索について

「安心な移動」のためのPOI(Point-of-Interest; 地点)検索

  • POIとは
    • point of interest
    • 移動の目的地となる場所
    • 緯度軽度や名前や住所などの情報
  • POIの特徴
    • 短文か単語が多い
    • 文章が少ない
    • 要素が多い
  • 経路探索におけるPOI検索の立ち位置
    • 目的地検索ができなければ、そのあとのナビゲーションができない
  • 安全な移動のためのPOI検索
    • ほとんどの人が上位5位を選択している
    • キーワードとの一致率が大事
  • 問題点1
    • いろんな県のものが出てくる
      • ホテル椿山での検索でホテル椿山東京以外のホテル
      • ディズニーでの検索で東京ディズニーランド以外のもの
      • スカイツリーも同様
  • 対策1
    • 人気なもの(有名度)が高いものを優先して上位に表示 →大方解決
  • 問題点2
    • チェーン店などでの検索で、人気の店舗が上位されてしまう
    • 「コンビニ」での検索で、「セブンイレブン 新宿駅」が表示されるなど
  • 対策2
    • 距離が近いものも優先して上位に表示 →大方解決
  • まとめ
    • 並び順優先順位
  1. 有名度
  2. 適合率
  3. 距離
  4. 再現率

社内ドキュメント検索システム構築のノウハウ

  • 企業内検索とは
    • 企業内の情報を検索する(ファイルサーバーやウェブウェイトなど)
  • fessとは
    • オープンソースの全文検索システム
    • elasticsearchを使っている
  • 企業内検索を構築する際のよくある課題
    • クロール対象が大規模
    • セキュア
    • 業務システムとの連携
    • ファイルが様々
  • 大規模化について
    • ドキュメント数は数千万くらい
    • クラスタにして分散検索
    • クロールする際の工夫
    • 更新ファイルリストを生成し、更新されたもののみをクロールする(全件だと1日のクロールで終わらないため)
  • セキュアについて
    • 認証状態により検索結果を出し分ける
      • ad連携
      • ログイン
    • クロール時に権限情報を付与する
      • 閲覧することができる権限をクロール時に取得するため
    • シングルサインオン
    • 検索システムにも自動でログインする
      • リバースプロキシがた
      • windows統合認証
      • openid connectなど
  • 業務システムとの連携
    • データはデータベースにあるため、sqlを検索サーバーに入れる
  • ファイルの種類について
    • ツールを使って文字列の抽出
      • ms office po
      • pdfbox
      • tika など

料理動画アプリ「クラシル」の検索について

  • クラシルについて
    • 検索対象:動画
    • ドキュメント?数:約2万5千本
  • 同義語対策について
    • 日々検索キーワードをチェックし手動で登録
      • ある程度効果はある
    • 同義かどうかが難しい場合がある
      • 「インゲン豆」「さやいんげん」など
  • 0件ヒット対策
    • 0件のヒットとなっているキーワードのレシピを日々チェック
    • 新生ワードを早期発見するために日々リサーチ(twitterなど)
  • 運用中気になったこと
    • 食材クエリとメニュークエリで離脱率が異なる
    • androidとiosでクエリが異なる
    • テレビの影響は大きい
    • 検索数が少ないキーワードへの対処優先度
  • KPI
    • 最初は離脱率
    • その次、検索経由のCV
      • ただし検索した後、買い物に出かけるなど、タイムラグがあるため純粋なCVを測ることが難しい(検討中)

Rails & Webpack案件でのgmo paymentのトークン決済

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

webpackの仕様を理解しないとたまにトラブルが起きるという話

GMOペイメントゲートウェイのトークン決済とは

ECサイトで決済処理を実装するときにGMOペイメントゲートウェイを活用する事になりました。
多様な決済方式に対応していて便利ですね。

GMOペイメントゲートウェイにはトークン決済という方式があります。
クレジットカード情報をJavaScript上でAPIに送信し、トークン化する事でセキュリティ的な観点で安心して決済処理を行う事ができる、というものですね。

実装

トークン化はコントローラを介さずJavaScriptで行います
必要なライブラリはCDNで配布されています。
本番用と開発用があるのでお間違えの無いように

<!-- トークン決済開発用javascriptを読み込み -->
<%= javascript_include_tag 'https://stg.static.mul-pay.jp/ext/js/token.js' %>
※URLが変更されている場合があるので必ず最新のドキュメントを参照してください

Multipaymentが定義されるのでカード情報をsubmitする際に利用します。

Multipayment.getToken({ 
   パラメータ 
   }, 任意のコールバック関数); 

の形式です

公式ドキュメントのコードサンプルは以下の通り
最低限の機能なので、カード情報の入力に不足がある場合はアラートを表示して送信しない等の処理を挟むのをオススメします。

<script type="text/javascript"> 
  function execPurchase(response) { 
   if (response.resultCode != "000") { 
    window.alert("購入処理中にエラーが発生しました"); 
   } else { 
    // カード情報は念のため値を除去 
    document.getElementById("cardno").value = ""; 
    document.getElementById("expire_year").value = ""; 
    document.getElementById("expire_month").value = ""; 
    document.getElementById("securitycode").value = ""; 
    document.getElementById("tokennumber").value = ""; 
    // 予め購入フォームに用意した token フィールドに、値を設定 
    //発行されたトークンは、有効期限が経過するか、一度 API で利用されると、無効となります。 
    //複数のAPIでトークンを利用される場合は、tokenNumberにてトークンを複数発行してください。

    document.getElementById("token").value = response.tokenObject.token; 
    // スクリプトからフォームを submit 
    document.getElementById("purchaseForm").submit(); 
   } 
  } 

  function doPurchase() { 
   var cardno, expire, securitycode, holdername; 
   var cardno = document.getElementById("cardno").value; 
   var expire = 
   document.getElementById("expire_year").value + document.getElementById("expire_month").value; 
   var securitycode = document.getElementById("securitycode").value; 
   var holdername = document.getElementById("holdername").value; 
   var tokennumber = document.getElementById("tokennumber").value; 
   Multipayment.init("tshop00000001"); 
   Multipayment.getToken({ 
    cardno : cardno, 
    expire : expire, 
    securitycode : securitycode, 
    holdername : holdername, 
    tokennumber : tokennumber 
   }, execPurchase); 
  } 
</script> 

問題点

このサンプルでいうexecPurchaseにあたるコールバック処理は、
グローバルスコープに無いとCDNから取得したライブラリ側で認識されないのですが、

webpackがスコープを管理する都合でサンプルをこのまま記述してもexecPurchaseはundefinedになってしまいました。

解決策

window.execPurchase = execPurchase;

上記をスクリプトに追記し作成したコールバック関数をwindowオブジェクトに持たせることで解決しました。
package.jsonに設定を記載する等の手段がありそうでしたが上手くいかなかったのでこの手法に落ち着きました。

更なるトラブル

Uncaught ReferenceError: r is not defined

おっ解決したと思いきやデプロイしたら動かん…

何故ならwebpackはproduction環境では変数名等を変換して難読化させた状態でビルドするからです。

window.execPurchase = r;

Multipayment.getToken({ 
    cardno : cardno, 
    expire : expire, 
    securitycode : securitycode, 
    holdername : holdername, 
    tokennumber : tokennumber 
   }, r); 

上記のようにコールバック関数がr一文字に変換されていました
window.execPurchase = execPurchase;で宣言してもこれでは動かない…
今回の場合、幸いなことにコールバック関数は文字列を渡しても問題なく処理してくれるので

Multipayment.getToken({ 
    cardno : cardno, 
    expire : expire, 
    securitycode : securitycode, 
    holdername : holdername, 
    tokennumber : tokennumber 
   }, "execPurchase"); 

のようにコールバック処理を指定する引数を文字列にすることで解決できました。
変数名は勝手に変換されますが文字列はそのまま残ります。

普段意識しないですがwebpackはこういう変換処理をしてくれているんですね。
トラブルが起きない分には素晴らしいですがたまにこういう事が起きるという話でした。

Rails & Webpack案件でのgmo paymentのトークン決済

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

webpackの仕様を理解しないとたまにトラブルが起きるという話

GMOペイメントゲートウェイのトークン決済とは

ECサイトで決済処理を実装するときにGMOペイメントゲートウェイを活用する事になりました。
多様な決済方式に対応していて便利ですね。

GMOペイメントゲートウェイにはトークン決済という方式があります。
クレジットカード情報をJavaScript上でAPIに送信し、トークン化する事でセキュリティ的な観点で安心して決済処理を行う事ができる、というものですね。

実装

トークン化はコントローラを介さずJavaScriptで行います
必要なライブラリはCDNで配布されています。
本番用と開発用があるのでお間違えの無いように

<!-- トークン決済開発用javascriptを読み込み -->
<%= javascript_include_tag 'https://stg.static.mul-pay.jp/ext/js/token.js' %>
※URLが変更されている場合があるので必ず最新のドキュメントを参照してください

Multipaymentが定義されるのでカード情報をsubmitする際に利用します。

Multipayment.getToken({ 
   パラメータ 
   }, 任意のコールバック関数); 

の形式です

公式ドキュメントのコードサンプルは以下の通り
最低限の機能なので、カード情報の入力に不足がある場合はアラートを表示して送信しない等の処理を挟むのをオススメします。

<script type="text/javascript"> 
  function execPurchase(response) { 
   if (response.resultCode != "000") { 
    window.alert("購入処理中にエラーが発生しました"); 
   } else { 
    // カード情報は念のため値を除去 
    document.getElementById("cardno").value = ""; 
    document.getElementById("expire_year").value = ""; 
    document.getElementById("expire_month").value = ""; 
    document.getElementById("securitycode").value = ""; 
    document.getElementById("tokennumber").value = ""; 
    // 予め購入フォームに用意した token フィールドに、値を設定 
    //発行されたトークンは、有効期限が経過するか、一度 API で利用されると、無効となります。 
    //複数のAPIでトークンを利用される場合は、tokenNumberにてトークンを複数発行してください。

    document.getElementById("token").value = response.tokenObject.token; 
    // スクリプトからフォームを submit 
    document.getElementById("purchaseForm").submit(); 
   } 
  } 

  function doPurchase() { 
   var cardno, expire, securitycode, holdername; 
   var cardno = document.getElementById("cardno").value; 
   var expire = 
   document.getElementById("expire_year").value + document.getElementById("expire_month").value; 
   var securitycode = document.getElementById("securitycode").value; 
   var holdername = document.getElementById("holdername").value; 
   var tokennumber = document.getElementById("tokennumber").value; 
   Multipayment.init("tshop00000001"); 
   Multipayment.getToken({ 
    cardno : cardno, 
    expire : expire, 
    securitycode : securitycode, 
    holdername : holdername, 
    tokennumber : tokennumber 
   }, execPurchase); 
  } 
</script> 

問題点

このサンプルでいうexecPurchaseにあたるコールバック処理は、
グローバルスコープに無いとCDNから取得したライブラリ側で認識されないのですが、

webpackがスコープを管理する都合でサンプルをこのまま記述してもexecPurchaseはundefinedになってしまいました。

解決策

window.execPurchase = execPurchase;

上記をスクリプトに追記し作成したコールバック関数をwindowオブジェクトに持たせることで解決しました。
package.jsonに設定を記載する等の手段がありそうでしたが上手くいかなかったのでこの手法に落ち着きました。

更なるトラブル

Uncaught ReferenceError: r is not defined

おっ解決したと思いきやデプロイしたら動かん…

何故ならwebpackはproduction環境では変数名等を変換して難読化させた状態でビルドするからです。

window.execPurchase = r;

Multipayment.getToken({ 
    cardno : cardno, 
    expire : expire, 
    securitycode : securitycode, 
    holdername : holdername, 
    tokennumber : tokennumber 
   }, r); 

上記のようにコールバック関数がr一文字に変換されていました
window.execPurchase = execPurchase;で宣言してもこれでは動かない…
今回の場合、幸いなことにコールバック関数は文字列を渡しても問題なく処理してくれるので

Multipayment.getToken({ 
    cardno : cardno, 
    expire : expire, 
    securitycode : securitycode, 
    holdername : holdername, 
    tokennumber : tokennumber 
   }, "execPurchase"); 

のようにコールバック処理を指定する引数を文字列にすることで解決できました。
変数名は勝手に変換されますが文字列はそのまま残ります。

普段意識しないですがwebpackはこういう変換処理をしてくれているんですね。
トラブルが起きない分には素晴らしいですがたまにこういう事が起きるという話でした。

wheneverで時刻を設定する際システムで設定されているのとは別のタイムゾーンを使用する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Railsアプリケーションのバッチ処理を [whenever](https://github.com/javan/whenever) でスケジュール設定する際、デプロイ先のタイムゾーンの設定がUTCなんだけど、スケジュール設定は開発者にわかりやすく日本時間としたいケースがあったので、その対応方法について。

問題と背景

  • デプロイ先のサーバのタイムゾーンの設定は UTC となっている(本当はJSTにしておいて欲しかったが、今更サーバの設定を変更したくない)
  • ただし whenever のスケジュール設定(config/schedule.rb)は日本時間で記述したい
  • whenever の schedule.rb ではタイムゾーンを指定することができず、システムで設定されているタイムゾーンを使用する。

対応方法

  • schedule.rb で時刻設定時にタイムゾーンを変換する関数を用意。その関数使って任意のタイムゾーンからシステムのタイムゾーンに変更する
# config/schedule.rb

# Time クラスの拡張を利用するため ActiveSupport を require する
require 'active_support/core_ext/time'

# 時刻の文字列を日本時間で解釈して、システムのタイムゾーンに変換
def jst(time)
  Time.zone = 'Asia/Tokyo'
  Time.zone.parse(time).localtime($system_utc_offset)
end

# 日本時間の 午前 2:00 => UTC の 17:00 にバッチをスケジュール
every 1.day, at: jst('2:00 am') do
  runner 'HogeFugaBatch.execute'
end

参考

データをIDで水平分割する時の方式を選ぼう

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

舎利子色不異空空不異色色即是空空即是色受想行識亦復如是 舎利子是諸法空相不生不滅不垢不浄不増不減

そもそも水平分割って何さ

同じ情報を複数のテーブルやデータベースに分けて分割する事です。
ユーザー情報が一つのデータベースに入っていたとしたら、

DB1
|ID|name|profile|
|1|イチ|弟達の世話で大変ですが愛おしいです|
|2|ニ|教授は美味しかったです|
|3|サン|お兄ちゃんに良く噛まれます|
DB1
|ID|name|profile|
|1|イチ|弟達の世話で大変ですが愛おしいです|
DB2
|ID|name|profile|
|2|ニ|教授は美味しかったです|
DB3
|ID|name|profile|
|3|サン|お兄ちゃんに良く噛まれます|

こんな風に複数のテーブルやデータベースに情報を分けて保存する事です。

どうして水平分割なんてやるのさ

データベースのレコード検索はインデックスを張る事で高速化が出来ますが、それでも数が莫大になってくると遅くなってきます。
それならば、保存する場所を複数に分ける事で1データベースのレコード数を絞り、その中で検索を掛ける事によって検索が遅くなる事を防ごうという訳です。

どうやって水平分割をするのさ

用途によって必ずしもそうではありませんが、基本的にテーブルの主キーであり、一意の数値であり、連番となるIDを元に保存/検索などをする対象先を判別するようにします。
ここでは、そのIDを元に水平分割をする場合の主に使われる2つの手法を紹介します。

範囲分割

IDを範囲分けして、対象先を判別します。
IDが1から100まではDB1に、
IDが101から200まではDB2に、
IDが201から300はDB3に、
そして301から400まではまたDB1に…という風に分割します。

DB1
|ID|name|profile|
|1|イチ|弟達の世話で大変ですが愛おしいです|
|2|ニ|教授は美味しかったです|
|3|サン|お兄ちゃんに良く噛まれます|
...
|100|ごますり|操られていただけなので勘違いしないで頂きたい|
|301|マンモス|何か話題になりました|
...

DB2
|ID|name|profile|
|101|目覚まし時計|友よ|
|102|サノスおばさん|燃え尽きたぜ…真っ白にな…|
|103|応援部隊その1|ソイヤッ!|
...

DB3
|ID|name|profile|
|201|王様|目覚まし時計が強過ぎて我が家を失いました|
|202|女王様|得意技は磔です|
|203|緊急脱出|ホールインワンしました|
...

剰余分割

IDをDB数で割った余りで対象先を判別します。DBが3つならば、
余りが0ならばDB1に、
余りが1ならばDB2に、
余りが2ならばDB3に、
分割します。

DB1
|ID|name|profile|
|1|イチ|弟達の世話で大変ですが愛おしいです|
...
|102|サノスおばさん|燃え尽きたぜ…真っ白にな…|
...
|201|王様|目覚まし時計が強過ぎて我が家を失いました|
...
DB2
|ID|name|profile|
|2|ニ|教授は美味しかったです|
...
|100|ごますり|操られていただけなので勘違いしないで頂きたい|
...
|103|応援部隊その1|ソイヤッ!|
...
|202|女王様|得意技は磔です|
...
|301|マンモス|何か話題になりました|
...
DB3
|ID|name|profile|
|3|サン|お兄ちゃんに良く噛まれます|
...
|101|目覚まし時計|友よ|
...
|203|緊急脱出|ホールインワンしました|
...

どっちが良いのさ

範囲分割と剰余分割、それぞれに利点欠点はあります。


範囲分割

利点:
対象先のデータベースを増やすといった時に設定の追加が簡単。
欠点:
設定を書くのが多少面倒。想定されるID数までの範囲を分割して、そしてそれを設定として全て書かなければいけない。
また、データの追加が大量に走った場合に処理が1つのデータベースに集中する。
ソーシャルゲームだと、ユーザー登録が沢山走った場合などには1データベースの性能がボトルネックとなる場合がある。


剰余分割

利点:
設定が簡単。IDを割った値で分割するだけ。
範囲分割での欠点のような、データの追加が大量に走る場合でも処理が複数のデータベースに分散されて一つに集中しない。
欠点:
対象先のデータベースを増やしづらい。また、増やしても設定が複雑になってしまう。
このIDまでは3で割った余りで対象先を判別し、このIDからは4で割った余りで分割する…とか、そんな事をしなくてはいけない。


まあ、一長一短ですね。
ただ、汎用性があるのは範囲分割の方だと思います。剰余分割の 対象先のデータベースを増やしづらい。また、増やしても設定が複雑になってしまう。 という事柄がかなり大きいので。他の手法であるハッシュ分割なども似たような形です。
そんな訳で、それぞれの利点欠点を理解した上で、プロジェクトに合った分割方法を選びましょう。

Rails Console から Sidekiq のジョブを操作する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

Sidekiq の Web コンソールが重いので Rails console からサクッとジョブのリトライとかしたい場合のメモ

キューの一覧を取得

 Sidekiq::Queue.all

キューに登録されているジョブの一覧を取得

 q = Sidekiq::Queue.new('キュー名')
 q.entries

ジョブが失敗した場合はリトライのキューに移る

リトライの一覧の確認〜ジョブの強制リトライ

 rs = Sidekiq::RetrySet.new
 rs.size
 rs.entries
 rs.entries[0].retry

リトライ待ちのジョブの削除

 rs.entries[0].delete

Dead (リトライ期限が過ぎたジョブ)

ds = Sidekiq::DeadSet.new
ds.size
ds.clear

docker-compose で開発者毎に異なる設定を使いたい場合 | その他 | DoRuby

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

開発環境として Docker を使っていると、開発者の環境固有の問題に対応するためにその環境固有の設定を追加したい場合がある。そのような場合のTips

背景

  • ローカル開発環境を Docker で構築して開発者間の環境の差異をできるだけ少なくしている
  • ただし、ホスト環境が Windows, Mac, Linux と様々で、個人毎に設定を微妙に変えたいケースがある

追記(2019/6/27)

どうも docker-compose はデフォルトで docker-compose.override.yml を読み込むようなので、以下のように環境変数の設定は不要だった。

対応方法

  • 環境変数 COMPOSE_FILE を使用するexport COMPOSE_FILE=docker-compose.yml:docker-compose.override.yml のように設定すると、 docker-compose.ymldocker-compose.override.yml 両方の設定がマージされる
  • いちいち export ... を打つのが面倒な場合、 direnv を導入すると良い

ローカル環境で’LOADING Redis is loading the dataset in memory’が頻発する

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

表題の件についてのメモ

背景

  • Rails アプリケーションのローカル開発環境を Docker で構築
  • その環境には Sidekiq の worker が稼働する、 worker コンテナ、Sidekiqがバックエンドとして使用している Redis が稼働している redis コンテナが存在する

現象

docker-compose によるコンテナの立ち上げ時、以下のエラーが発生して worker コンテナが落ちる

worker           | LOADING Redis is loading the dataset in memory
worker           | /app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.3/lib/redis/client.rb:124:in `call'
worker           | /app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.3/lib/redis/client.rb:107:in `block in connect'
(略)
worker           | /app/vendor/bundle/ruby/2.5.0/gems/redis-4.0.3/lib/redis.rb:278:in `info'
worker           | /app/vendor/bundle/ruby/2.5.0/gems/sidekiq-5.2.3/lib/sidekiq.rb:113:in `block in redis_info'
worker           | /app/vendor/bundle/ruby/2.5.0/gems/sidekiq-5.2.3/lib/sidekiq.rb:95:in `block in redis'

原因

redisコンテナ起動時に --appendonly yes が指定されていた。

LOADING Redis is loading the dataset in memory というエラーは、 AOF(Append-only File)からデータをメモリ上に展開している間に更新(SET)などのコマンドを実行しようとした際に発生するらしい。

RDB/AOFファイルをローディングしている間、SETコマンドのようなものを実行すれば “(error)LOADING Redis is loading the dataset in memory”このようなエラーを出すが、infoコマンドは実行されます。 したがって、infoコマンドでローディング中なのか確認することができます。
REDIS INFO [section] コマンド

対処その1

Append-only File は、プロセスの予期しない終了等からデータを保護するための機構であるが、ローカル開発環境においてはそのような考慮は不要(消えても構わない)ので、 --amendonly yes オプションを取り除く。

   redis:
     image: redis:latest
     ports:
       - 6379:6379
     volumes:
       - redis:/data
-    command: redis-server --appendonly yes
+    command: redis-server

対処その2

あるいは、ローカルで保持しているRedis内の情報が消えても構わないのであれば一旦 redis コンテナに割り当てている Volume を削除してあげるという方法もある。

ただし、一時的なものなので AOF が肥大化するにつれていずれ問題が再発する。(と思われる)

ボリュームを削除する手順は以下(コンテナを停止している状態で実施する)

<ボリュームの一覧確認>
docker volume ls

<ボリューム削除>
docker volume rm xxxxxx_redis

CloudFront + API Gateway + Lambdaの環境で生きた無属性のペアとそのこと

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

API Gateway のエラー時のレスポンスのメッセージは必ずしもその原因と直結するような内容となっていないことが多々あり、原因の特定に時間がかかりがちなのでメモっておく。

※随時追加予定

※「レスポンス」の内容は、curl -vでのリクエストに対するレスポンスを多少加工して掲載している。

401 ‘Unauthorized’

レスポンス

< HTTP/2 401
< date: Wed, 22 May 2019 08:43:33 GMT
< content-type: application/json
< content-length: 26
< x-amzn-requestid: xxxxxxxxxxxxxxxx
< x-amzn-errortype: UnauthorizedException
< x-amz-apigw-id: xxxxxxxxxxxxxxxxxxx

{"message":"Unauthorized"}

原因

  • カスタムオーソライザに必要な情報(特定のリクエストヘッダ等)がリクエストに含まれていない
    • 例えば Cookiesession_idを使ってAPIへのアクセスを認可するオーソライザを設定している場合、Cookieヘッダがリクエストに含まれていない場合に前述のリクエストが返ってくる

403 ‘Missing Authentication Token’

レスポンス

< HTTP/2 403
< date: Wed, 22 May 2019 08:31:54 GMT
< content-type: application/json
< content-length: 42
< x-amzn-requestid: xxxxxxxxxxxxxxxxx
< x-amzn-errortype: MissingAuthenticationTokenException
< x-amz-apigw-id: xxxxxxxxxxxxxx

{"message":"Missing Authentication Token"}

原因

  • API Gateway のエンドポイントのパスが間違っている
    • 例えば正しいエンドポイントのURLが以下であった場合
      • https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/stage/api/v1/{+proxy}
    • 以下のように間違っている(/apiが抜けている)と前述のようなレスポンスが返ってくる
      • https://xxxxx.execute-api.ap-northeast-1.amazonaws.com/stage/v1/xxxxxx

403 Forbidden

(思い出したら書く)

403 ‘User is not authorized to access this resource with an explicit deny’

レスポンス

< HTTP/1.1 403 Forbidden
< Date: Wed, 22 May 2019 08:56:27 GMT
< Content-Type: application/json
< Content-Length: 82
< Connection: keep-alive
< x-amzn-RequestId: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
< x-amzn-ErrorType: AccessDeniedException
< x-amz-apigw-id: xxxxxxxxxxx

{"Message":"User is not authorized to access this resource with an explicit deny"}

原因

  • カスタムオーソライザから DENY のポリシー文書が返却された場合に返ってくるレスポンス
    • カスタムオーソライザの呼び出し自体には成功しているので、大体のケースにおいては正常動作と言える(正常でない場合はカスタムオーソライザをデバッグすることになる)

503 (HTML形式で) ‘ERROR: The request could not be satisfied’

レスポンス

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<HTML><HEAD><META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=iso-8859-1">
<TITLE>ERROR: The request could not be satisfied</TITLE>
</HEAD><BODY>
<H1>502 ERROR</H1>
<H2>The request could not be satisfied.</H2>
<HR noshade size="1px">
CloudFront attempted to establish a connection with the origin, but either the attempt failed or the origin closed the connection.
We can't connect to the server for this app or website at this time. There might be too much traffic or a configuration error. Try again later, or contact the app or website owner.
<BR clear="all">
If you provide content to customers through CloudFront, you can find steps to troubleshoot and help prevent this error by reviewing the CloudFront documentation.
<BR clear="all">
<HR noshade size="1px">
<PRE>
Generated by cloudfront (CloudFront)
Request ID: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
</PRE>
<ADDRESS>
</ADDRESS>
</BODY></HTML>

原因

  • オリジン(API Gateway)に対して http でアクセスしている
    • CloudFront のオリジンの設定(Origin Protocol Policy)が HTTP Only のようになっていないか確認する
    • API Gateway は HTTPS しかサポートしていないので、 HTTPS Only とするべき

nginx の proxy_pass の転送先が API Gateway の場合に `SSL_do_handshake() failed` と言われた

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ローカル環境のnginxからAPI Gateway で用意したAPIのエンドポイントに proxy_pass 設定したときにハマった件

背景

  • ローカル環境に nginx を立てて、その nginx で特定の path (例えば /api/v1/xxx) に対して proxy_pass を設定して、API Gateway で作成したエンドポイントに対してアクセスを転送したい

現象

  • 該当 path にアクセスすると nginx から 502 Bad Gateway のエラーが返ってくる
  • nginx のエラーログを見ると SSL_do_handshake() failed というエラーが発生していた

原因

proxy_pass の対象となるエンドポイントが SNI を使用している場合発生するっぽい(API Gateway がデフォルトで用意するエンドポイントは SNI 使ってる)

参考: Nginx reverse proxy error:14077438:SSL SSL_do_handshake() failed – Stack Overflow

対処

以下のように proxy_ssl_server_name on の設定を追加してあげたらOK

location /api/ {
  proxy_pass https://xxxxxxxx.execute-api.ap-northeast-1.amazonaws.com/Dev/api/;
  proxy_ssl_server_name on;
}

ボックスガチャの実装をしよう(ソーシャルゲームにおけるサーバーサイド) 7

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

どうして世の中は世知辛いのだろう。

前回のあらすじ

前回
 ボックスガチャの実装が完了しました。
 しかし、そこで完了にするのではなくコードレビューや仕様の確認をして、この先に改修が入ったりしても、誰かにクソコードと喚かれたり、見直して自分でクソコード……と呟いてしまうような、また仕様書に無い仕様が実際には入っていたり、逆に実は仕様が欠けていたり……みたいな悲劇が起こらないようにしましょう。

仕様確認をしよう

くらいあんとえんじにあ「クライアントもアセット組み込んで実装終わったから、仕様確認するぞー」

仕様書を見直すと、

・ボックスガチャは通常ガチャと同様、1連と10連で引ける
・ボックスガチャで引けるものは通常ガチャと同等
・10連を選択した時にボックスの中身が9個以下だった場合、消費される対象はその中身分のみとなり、全てを自動で排出する
・リセットする度に上限までボックスの中身は変わる
・リセットは自由に可能。そのステージのボックスガチャを1回も引かなくともリセットが出来る
+ 排出されるキャラクターの中で最高レアリティのキャラはボックスの中身を1/4以上引いていない時しか出ない
+ ボックスを引き切ると別のマスタで定義してあるおまけが貰える

さーばーえんじにあ「(追加された仕様に関しても実装したし)ここあたりは問題ないですよね。マスタ定義書とかも更新してあるのは見ましたし」

※開発途中に仕様が追加変更される事は多分良くある

くらいあんとえんじにあ「あ、いや、 ボックスを引き切ると別のマスタで定義してあるおまけが貰える ってUI上の表示は無くて良いんですっけ。こっちとしては特に大して聞いてないんですけど」
ぷらんな「現状大した物出さないし、最後まで引ききって遊んでくれてありがとう的な、そんな小さなものだから取り敢えず今回は無しね」
くらいあんとえんじにあ「りょーかい。一応追記しておいてくれると助かります」
ぷらんな「わかっタスマニアデビル」
でざいなー「UIの遷移図、仮画像のままなので本画像に差し替えておいてくださインパラ」
ぷらんな「りょーか犬」
さーばーえんじにあ「サーバー側としては他に特にないです猫」
くらいあんとえんじにあ「……クライアントとしても同じです」
でざいなー「……」
ぷらんな「……」
さーばーえんじにあ「……」
くらいあんとえんじにあ「……やらないよ?」

コードレビューをしよう

さーばーえんじにあ「実装の規模でかいんで部屋取ってコードレビューの時間取ろうと思うんですけど、良いですか?」
れびゅわー「この時間に取っておいて。1時間あれば足りる?」
さーばーえんじにあ「まあ、基本的に新規実装なので、既存コードの改修でごっちゃごっちゃそこまでやってないの考えるとその位で多分大丈夫です」

さーばーえんじにあ「実装は大まかに言うと、既存コードをごねごねせずに、引用して来る感じで行いました。
 で、ボックスガチャの実装で普通のガチャと共通の部分は継承してそのまんま使って、この部分とこの部分だけ違うので、こんな感じでオーバーライドして……みたいな感じです」
れびゅあー「設計はまあ事前に聞いてたし特に問題ないと思う」
さーばーえんじにあ「わかりましたー」
れびゅあー「で、一つ一つ改修したコード見ていこうか」

れびゅあー「データ更新の部分さ、この作りだと10連だと10回update叩かないといけないけどさ、一括で何とか出来なかった?」
さーばーえんじにあ「DBのクラスタ設定とか考慮してやると結構複雑になりそうだったので、一旦やってないです。後、ちゃんとindexとか張ってありますし、不要なデータも基本的に即削除してるので、そんなに問題ないかと」
れびゅあー「分かった。まあ、最大10回なら問題ないかな。パーティションは切ってあって、ガチャ期間が過ぎてN日経ったら削除ね……。そこあたりは何か根拠でも?」
さーばーえんじにあ「ガチャで取ってあるログと同じに一旦してあります」
れびゅあー「そうね。多分無いと思うけど、同じボックスガチャを前に引いていた人はその状態からで復刻してやるとか、そんな事がないかとか、ちゃんとプランナーとかと合意取っといて」
さーばーえんじにあ「分かりましたー」

れびゅあー「じゃあ、言ったところ確認とったりとかしたら本ブランチにマージするね」
さーばーえんじにあ「分かりましたー」

タスク完了

上記が終わり次第、 ボックスガチャの実装 というタスクはやっと、しかしながら 基本的にのみ 完了となります。
QAチェックなどで、コードレビューやテストコードもすり抜けて不具合が発覚する可能性なども多々ありますので、その都度修正などをしていきましょう。


……。
…………。
…………こんな風に実装出来たら良かったなぁ……。

ボックスガチャの実装をしよう(ソーシャルゲームにおけるサーバーサイド) 6

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ロースザブトンもやしのナムルミスジテールスープサーロインカルビ石焼ビビンバタンサガリ米ハチノスチヂミシマチョウたまごスープハツサンチュニンニクのホイル焼きレバートントロ焼き野菜ミドガルズオルム

前回までのあらすじ

前回

 ボックスガチャのサーバーサイドのコードの実装が完了しました。
 また、テストコードの実装及びに、新規マスタのインポート処理も完了し、残るはクライアントとの繋ぎ込みのみです。

クライアントとの繋ぎこみ

くらいあんとえんじにあ「追加されるAPIのパスとかはもう共有されてるけど、まだパラメータとレスポンスの形ちゃんと貰ってないよ」
さーばーえんじにあ「あ、忘れてました……。纏めて返します」

ボックスガチャを引く POST: gachas/draw
parameter
{
  gacha_code: integer, #対象ガチャコード
  draw_count: integer  #引く回数
}

response
{
  characters: [ #引いたキャラクター達の情報
    {
      character_id: integer, #キャラクターID
      character_code: integer, #キャラクターコード
      level: integer, #レベル
      .....
    }
  ]
}

パラメータ、レスポンスは既存から変更なし
現在のボックスの中身を確認 GET: gachas/current_box_contents
parameter (クエリパラメータ)
{
  gacha_code: integer # 対象のガチャコード
}

response
{
  stage: integer, # 現在のボックスガチャのステージ
  total_count: integer, # 現在のボックスガチャの中身の総数
  remain_count: integer, # 現在のボックスガチャの残りの総数
  contents: [ # ボックスの中身
    {
      character_code: integer, # キャラクターコード
      total_count: integer, # 中身の総数
      remain_count: integer # 残りの総数
    }
  ]
}
ボックスガチャのリセット POST gachas/reset_box
......
各ステージでのボックスの中身の確認 GET: gachas/all_box_contents
......

さーばーえんじにあ「取り敢えずこんな感じですけど問題ありますか?」
くらいあんとえんじにあ「うーん、まあ、現状のUIで表示するものだと、これとこれとこれが足りないから追加して」
さーばーえんじにあ「了解です、改修終わったらAPI定義書に纏めておきますね」


※ APIのパラメータなどに限らず、仕様書とは別に定義書があると何かを調べる時にとても役立ちます。改修の度にきちんと更新されている事を前提として。


1時間後

さーばーえんじにあ「で、ソースと定義書の更新終わったからまたテストして……開発環境に反映!」
くらいあんとえんじにあ「不具合あったら報告するね」
さーばーえんじにあ「入念にテストしたから基本的に大丈夫だと思うけど、まあ、完璧な自信は無いので」

数時間後

くらいあんとえんじにあ「ボックスガチャだったら、引いた後の中身のレスポンスも同時に返してくれない? 続けて引く時にさ、ガチャ結果からクライアントが判断してボックスの中身を減算するとかするより、サーバーからその時点の結果一緒に貰っちゃった方が良いと思うんだ」
さーばーえんじにあ「ボックスガチャの時だけそういうレスポンスを返すって感じですか?」
くらいあんとえんじにあ「そういう事」
さーばーえんじにあ「ボックスガチャでない時は空配列を返す形で良いですか?」
くらいあんとえんじにあ「おk」
さーばーえんじにあ「分かりました(バグは起きてないっぽいかな。良かった)」
くらいあんとえんじにあ「あ、Internal Server Error」
さーばーえんじにあ「ふぇっ!?」

その後、クライアントとの擦り合わせやバグの解消をして

くらいあんとえんじにあ「一通り見ましたが、これで基本的に問題ないです」
さーばーえんじにあ「確認ありがとうございますー」

実装は完了しましたがまだ終わりではありません

さーばーえんじにあ「じゃあ、後はコードレビューとか仕様の認識合わせとかして終わりか。レビューする前に自分のコード一回見直そう。
 ……変数名ちょっと分かりづらいやここ。直しておこう。あ、後、ここのレスポンスの追加、定義書に書いてないや。こうして……」

※ コードレビューは大事。動くだけの汚いコードは後々の全てに悪影響を与えます。ただ、そのレビューをする前にちゃんと自分のコードは見直して、気付いた点は直しておきましょう。そしてその修正でエラーが発生しないようにしましょう。
※ また、実装が完了した後での仕様の認識合わせも重要です。口答だけで追加された仕様などが抜け落ちている可能性などをしっかりと排除しておきましょう。

次(最後)

ボックスガチャの実装をしよう(ソーシャルゲームにおけるサーバーサイド) 4

0

この記事はアピリッツの技術ブログ「DoRuby」から移行した記事です。情報が古い可能性がありますのでご注意ください。

ど゛う゛じ゛で゛

前回までのあらすじ

前回

ボックスガチャを作る事になりました。
改修、追加すべきAPIは以下で、

・ボックスガチャを引く POST: gachas/draw
・現在のボックスの中身を確認 GET: gachas/current_box_contents
・各ステージでのボックスの中身の確認 GET: gachas/all_box_contents
・ボックスガチャのリセット POST gachas/reset_box

それらの処理の為に、GachaBoxContentManagerという、ユーザーのボックスガチャの状態を一括管理するクラスを作成しました。

そうすると、

・現在のボックスの中身を確認 GET: gachas/current_box_contents
・ボックスガチャのリセット POST gachas/reset_box

この二つのAPIの実装は大体終わったも同然であり、また、

・各ステージでのボックスの中身の確認 GET: gachas/all_box_contents

このAPIの実装もマスタデータを返すだけなのですぐに終わりました。
残りは、

・ボックスガチャを引く POST: gachas/draw

のみです。

ボックスガチャを引く処理を作る

通常ガチャを引くコードは大まかに以下のように分けられていました。

APIが叩かれる
 受け取ったパラメータを元にガチャのプロセスを初期化
 ガチャのプロセスを実行する
  アサーション
  ガチャを指定回数だけ引く
  ガチャの結果からユーザーデータを更新
  ログの出力
 実行後、レスポンスを返す

さーばーえんじにあ「このコードでの一番の問題は、1回ガチャを引く毎に中身のコンテンツが変わる事を考慮していないという事だ。
 ……どうしようかなこれ。
 ボックスガチャを引く為に大きく改修すべき部分は、
 ・ガチャを指定回数だけ引く
 ・ガチャの結果からユーザーデータを更新
 基本的にこの三つか。それ以外の部分は大きく変えたりは多分しなくて良い。
 A. ガチャのプロセスを継承してその部分だけを変えるか
 B. ガチャのプロセスそのものを拡張するか
 どっちが良いかな。
 うーん、例えば、他にも色んなガチャを実装するとしたらどうなるかな……。
 Aだと、それぞれのガチャの特性に合わせた部分だけを変更した新しいプロセスを作る必要が出てくる。でも、他の部分は基本のガチャに準じている訳だからまあ、見やすいかな。
 Bだと、一つのガチャのプロセスの中に色んなガチャに応じた分岐がどんどん増えていく事になる。完ッ璧に見辛いな。更に、改修を加える度に他のガチャに影響が出る可能性も否定出来ない。
 Aだな、うん。そうしよう」
 そうして、以下のように実装が進みました。

APIが叩かれる
 (受け取ったパラメータを元にガチャのプロセスを初期化 <= ガチャ種が増えた事によって削除)
 受け取ったパラメータと、そのガチャの種類に応じたプロセスの初期化を行う <= new!
 プロセスを実行する
 実行後レスポンスを返す
通常ガチャプロセス
 初期化
 アサーション
 ガチャを指定回数だけ引く
 ガチャの結果からユーザーデータを更新
 ログの出力

ボックスガチャプロセス <= new!
 初期化 <= GachaBoxContentManagerの初期化もする
 アサーション
 ガチャの指定回数だけ
  ガチャを引く
  ボックスの中身を減算する
 ガチャの結果からユーザーデータを更新 <= GachaBoxContentManagerからボックスの中身も更新する
 ログの出力

さーばーえんじにあ「こんな感じか。
 既存の通常ガチャへの影響はほぼ無し。じゃ、APIも作り終えたから、後はテストコード書いて……マスタのインポート処理とかをマスタが来次第作成、クライアントとの繋ぎこみをその後、か。
 あれ、まだまだやる事結構あるんか。
 ちょっと面倒だな……」

最近人気な記事