ホーム ブログ ページ 20

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

0

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

この予算内で引けなかったら諦める

前回までのあらすじ

前回

ボックスガチャを作る事になりました。

必要な機能:
・ボックスガチャを引く
・現在のボックスの中身を確認
・各ステージでのボックスの中身の確認
・ボックスガチャのリセット
必要な追加データ:
・ユーザーのボックスの現在状態
・ステージ毎のボックスの中身を定義するマスタ
マスタデータ
 ┣キャラクターマスタ CharacterMaster
 ┃┣キャラスキルマスタ CharacterSkillMaster
 ┃┣キャラ成長マスタ CharacterExpMaster
 ┃┃┗キャラパラメータマスタ CharacterParameterMaster
 ┃...
  ...
 ┣ガチャの親マスタ GachaMaster
 ┃┣ガチャの中身マスタ GachaContentMaster
 ┃┗ボックスガチャの中身マスタ <= new!
 ...


ユーザーデータ
 ┣所持キャラクター群 Characters
 ...
 ┣現在のボックスガチャの状態データ群 <= new!
 ...

仕様書が来ました

読み込むと実装に足りるだけの詳細がありました。

・ボックスガチャは通常ガチャと同様、1連と10連で引ける
・ボックスガチャで引けるものは通常ガチャと同等
・10連を選択した時にボックスの中身が9個以下だった場合、消費される対象はその中身分のみとなり、全てを自動で排出する
・リセットする度に上限までボックスの中身は変わる
・リセットは自由に可能。そのステージのボックスガチャを1回も引かなくともリセットが出来る

さーばーえんじにあ「設計に関しても承認貰ったから実装していこう」

まずはテーブルを作りましょう

さーばーえんじにあ「新規テーブルは
・ボックスガチャの中身マスタ
・現在のボックスガチャの状態データ群
か。
名前はどうしようかな」

 ┣キャラクターマスタ CharacterMaster
 ┃┣キャラスキルマスタ CharacterSkillMaster
 ┃┣キャラ成長マスタ CharacterExpMaster
 ┃┃┗キャラパラメータマスタ CharacterParameterMaster

 ┣ガチャの親マスタ GachaMaster
 ┃┣ガチャの中身マスタ GachaContentMaster
 ┃┗ボックスガチャの中身マスタ

 ┣所持キャラクター群 Character
 ...
 ┣現在のボックスガチャの状態データ群

さーばーえんじにあ「ガチャのマスタは先頭にGachaってついていた方がエディタとかで開いた時、ガチャ関連の定義ファイルが一箇所に集中していて分かりやすいよなあ。
 だと、ボックスガチャの中身マスタはGachaBoxContentMasterとかになるかな?
 で、現在のボックスガチャの状態テータ群もそれに倣う形でGachaBoxContentとかになるかなあ。
 ボックスなのにGachaBoxって逆転させるの気持ち悪いけど……でも、データの並び順序考えるとこの方が良いかな」
さーばーえんじにあ「そんなこんなで、マスタ名、GachaBoxContentMasterにしました。通常ガチャとは別にステージ毎の中身の情報をここにお願いします。
 カラムは、通常のガチャの中身を示すGachaContentMasterの一部を変更、追加する形で、
 確率がweight: integerで定義されているのに対して、こちらが示すものは中身の数量なので、quantity: integerにします。
 後は、どのステージかを示すstage: integerをカラムとして追加してあります。
 問題ないですか?」
ぷらんな「ok」

API名を先に定義しておきましょう

既存のAPIとして以下が既に定義されていました。

・ガチャトップ画面 GET: gachas
・ガチャを引く POST: gachas/draw
・ガチャの確率を確認する GET: gachas/rate_list

さーばーえんじにあ「ガチャを引くAPIはこのままでいっか。引くものは確率確認は、ボックスガチャで各ステージでのボックスの中身の確認、としても良い気がする。
 ……でも、レスポンスの形もUIも変わるよなぁ……分けた方が良いかな?」
くらいあんとえんじにあ「あ、分けて欲しいな」
さーばーえんじにあ「分かりましたー」
さーばーえんじにあ「じゃあ、追加する機能に対してのAPIはこんな感じになるかな」

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

さーばーえんじにあ「じゃあ、実装かな」

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

0

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

この無料分で引けなかったら諦める

ガチャから派生させてボックスガチャを作る事になりました

ぷらんなー「このゲーム、普通のガチャはあるけどさ、ボックスガチャやりたいから作って」
さーばーえんじにあ「ボックスガチャか」
ぷらんなー「必要な機能は大まかに言うと、
・ボックスガチャを引く
・現在のボックスの中身を確認
・各ステージでのボックスの中身の確認
・ボックスガチャのリセット
ね。リセット回数はガチャを定義する親マスタで制限かけるから。
 細々とした仕様は後で仕様書が完成したら共有するけど、取り敢えず確定事項です」
さーばーえんじにあ「りょーかい」

ボックスガチャってなぁに?

 例えるならば、ガチャポンです。
 中身が有限なガチャです。
 排出率が1%のレアキャラが出るガチャだったら、通常は100回引いても大体63%の確率でしか引けませんが、ボックスガチャならば中身が有限なので、中身を全て引けば100%出す事が出来ます。
 やったね!!

ガチャから派生させてボックスガチャを実装するにはどういうAPIとどういう追加データが必要だろう

さーばーえんじにあ「必要なAPIとしては、まあ、必要な機能の通りで、
・ボックスガチャを引く
・現在のボックスの中身を確認
・各ステージでのボックスの中身の確認
・ボックスガチャのリセット
で大丈夫だよな」
さーばーえんじにあ「で、サーバー側で持つべきデータとしてはまず、
・ユーザーのボックスの現在状態
が必要だよな。で、えっと? 機能に 各ステージでのボックスの中身の確認 なんて項目があるって事は、リセットする度にボックスの中身変わるのかな?」
ぷらんな「そうだよ。仕様書もうそろそろ出来るから、ちょっと待ってて」
さーばーえんじにあ「あ、はい。なら、
・ステージ毎のボックスの中身を定義するマスタ
を別に作った方がいいか。通常のガチャの中身を定義するマスタとは段々かけ離れてくるし。
……その位か」

必要な機能:
・ボックスガチャを引く
・現在のボックスの中身を確認
・各ステージでのボックスの中身の確認
・ボックスガチャのリセット
必要な追加データ:
・ユーザーのボックスの現在状態
・ステージ毎のボックスの中身を定義するマスタ

さーばーえんじにあ「で、ユーザーのボックスの現在状態をどうやって保存するかちょっと悩むな。二つ案あるんだけど」

案1:
中身のコンテンツ一種類毎にレコードを作る
利点: 
・構造が簡単。ユーザー動向の調査の為の検索や緊急対応の為の一括更新などがし易い。
欠点:
・ユーザー一人辺りのデータが多くなる。総レコード数は簡単に考えて、(ユーザー数×ボックスガチャの数×ボックスガチャの平均コンテンツ種別量)となる
・10連でガチャったりする場合、SQLの更新回数が多い(O(n))
案2:
ボックスガチャ一つに対し、データをJSONなどで一括管理。
利点:
・ユーザー一人辺りのデータが少ない。総レコード数は簡単に考えて(ユーザー数×ボックスガチャの数)となる。
・10連だろうと1連だろうとSQLの更新回数は1回(O(1))
欠点:
・ユーザー動向の為の調査の為などの検索、緊急対応の為の一括更新がし辛い。JSONを生で保存するならlike検索などは辛うじて出来るが、圧縮してバイナリなどにした場合、全く出来なくなる
・管理、更新の為に毎回JSONなどを展開、圧縮などする必要がある為、やや面倒

さーばーえんじにあ「……1だな! 2の欠点が、結構でかいからなぁ。ユーザー動向の調査とかはともかく、何か緊急対応しなきゃいけなくなった時、一括更新とか出来なくてユーザー一人一人に対して処理掛ける必要が出てきて、時間が酷く掛かったりとか、そんないやーな予感がする。
 データベース容量は結構余裕あるし、古いボックスガチャのデータとか、引き切ったボックスのデータとかはパーティション区切れば一括削除出来るし、ユーザー単位でそんな数百件もデータ保持しないだろ!
 それに、更新の為の計算量はO(n)だけど、最大10連とかだったら、1回での更新は最大10回だし、ちゃんとインデックス張れば大丈夫でしょ!
 ……まあ、設計書とかちゃんと作るとして」

テーブル概要書

マスタデータ
 ┣キャラクターマスタ CharacterMaster
 ┃┣キャラスキルマスタ CharacterSkillMaster
 ┃┣キャラ成長マスタ CharacterExpMaster
 ┃┃┗キャラパラメータマスタ CharacterParameterMaster
 ┃...
  ...
 ┣ガチャの親マスタ GachaMaster
 ┃┣ガチャの中身マスタ GachaContentMaster
 ┃┗ボックスガチャの中身マスタ <= new!
 ...


ユーザーデータ
 ┣所持キャラクター群 Characters
 ...
 ┣現在のボックスガチャの状態データ群 <= new!
 ...

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

0

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

ここまで来て引き下がる訳にはいかない!

前回までのあらすじ

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

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

実装する前に

さーばーえんじにあ「これ……全てのAPIに対して、ボックスの中身を確認変更する操作が必要になるな。
 で、ボックスの中身を確認やら変更やらするのは、レコードの仕組み上、複数のレコードを常に触る事になる。
 ちょっと、一つ一つ実装する前にボックスの中身に対する操作をクラスで一括で行う事にして、そこから触った方が良いな……」

 必要な操作を纏めたところ、以下のようになりました。

・ボックスの中身を初期化する
・ボックスの中身を確認する
・ボックスの中身を引く
・ボックスの中身をリセットする(次のステージに進ませる)
+各種デバッグ機能

さーばーえんじにあ「これらをクラスにして、名前、どうしよっかな。ボックスの中身に対する処理を全てやるんだから、GachaBoxContentManagerとかでいっか。で、そこから全てのボックスに対する操作を一括して行う、と」

クラス GachaBoxContentManager
 コンストラクタ : ユーザーとガチャマスタを受け取り、ユーザーに対するボックスが無かったら初期状態で作る(ガチャマスタがボックスガチャ対応でなかったらエラー)
 確認メソッド : ボックスの中身を用途に合った形に整形して渡す
 引くメソッド : ボックスの中身を更新する
 リセットメソッド : ボックスを次のステージへと移行させる
 デバッグ機能 : 取り敢えず強制初期化とかはデバッグで必要になりそうだけど保留

さーばーえんじにあ「じゃあ、今度こそ実装に入るか……って、ボックスの中身を確認するAPIって大体実装終わったも同然じゃんこれ」

ボックスの中身を確認するAPI gachas/current_box_contents
  # GachaBoxContentManagerを対象ユーザーでインスタンス生成
  # インスタンスメソッドから中身を受け取る
  # 整形して返す

さーばーえんじにあ「リセットも」

ボックスのリセットAPI gachas/reset_box
  GachaBoxContentManagerを対象ユーザーでインスタンス生成
  インスタンスメソッドからリセットを実行
  リセット出来たらレスポンスを、既にリセット回数の上限に達しているなどでリセット出来なかったらエラーを返す

さーばーえんじにあ「レスポンスとかはまあクライアント次第だけど、各ステージでのボックスの中身の確認も後はマスタのデータそのまま返すだけだし……

各ステージでのボックスの中身の確認API gachas/all_box_contents
 対象のガチャのマスタデータ取得
 整形して返す

 あら、後はボックスガチャそのものの実装だけみたいなもんじゃん。
 あれま」

味噌カツで例えるソーシャルゲームのサーバーサイドにおける新規実装の流れ 4

0

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

そしてソースカツ丼となった

前回までのあらすじ

前回

以下のゲームで、

牧場経営ソーシャルゲーム:
ユーザーは牧場を経営する。また、牧場などで育てたものを調理し、食べる事が出来る。
ユーザーにはステータスが存在し、様々な行動によってステータスが変動する。ある一定のステータスを伸ばすと出来る事が増える。
ステータスは割合で決定されており、どれかのステータスを上げると他のステータスが落ちる。
一度得た能力は消えない。

味噌カツを作る事が決定しました。
提示された仕様書を読み込み、それに対して曖昧な点や改善すべき点を会話して解消、サーバーエンジニアがすべき事が明確になった後に仮実装、暫定での実機確認が完了。その後に仮実装で適当に作っていた部分をちゃんと作り込み、テストコードも作り、実装を一旦完了させました。

コーディング完了後にすべき事

 コーディング完了してそれで全て終わりにしてしまうと、後々負の遺産が溜まっていく事になります。
 そうしてしまうと、そのコードを他者が弄る事になった時に、「ク・ソ・コォォォォドゥォォォォォォォォオオオオオオ」とかその人に叫ばれたりとか、ずーっと誰にも気づかれないまま潜んでいたバグが唐突に本番環境で発生したりとか、そんな事が起きてしまう可能性がとても高くなっていきます。
※クソコードによる影響はどこかしこに記事やブログとして載っているのでここでは書きません。ただ、クソコードはクソだからクソコードと呼ばれるのです。クソコードはクソだからクソコードと呼ばれるのです。

 そんな事を極力防ぐ為に、例えば、以下のような事をしましょう。

実装完了後の仕様書の読み合わせ

 味噌カツ作りを実装がサーバー、クライアント、デザイナー、プランナー全ての担当が完了し、繋ぎ込みも一旦終わった後に、仕様に対して漏れや差異がないかなどを再確認しましょう。


くらいあんとえんじにあ「追加するって言ってたこの仕様、仕様書から漏れてるよ」
ぷらんなー「えっ」
さーばーえんじにあ「あ、後から追加されたこの仕様に対して実装するの忘れてた……」
くらいあんとえんじにあ「えっ、あっ、ここデフォルトデータしか入ってないじゃん……」
でざいなー「UI出来たので本画像渡します、仕様書のここの仮画像、本画像に差し替えておいて下さい」
ぷらんなー「りょーかい」
さーばーえんじにあ「……実装してから気づいたけど、仕様書通りだと、これこれこういう場合にこんな挙動になるけど、これで良いの?」
ぷらんなー「あー、これ、駄目だな、仕様から直します」
くらいあんとえんじにあ「影響はサーバーだけ?」
さーばーえんじにあ「そですね」


 要するに、実装の上で認識のズレが生じていないかの確認が出来ます。
 その認識のズレは基本的にQAチェックなどを行えばある程度はバグとして弾く事が出来ますが、QAもバグを100%弾ける訳ではありません。
 そして、こういう事をしないでQAチェックまでそのまま通って本番に反映されてしまうと、


ぷらんなー「何か変な挙動するんだけど」
さーばーえんじにあ「えっ……あー、これは、仕様です」
ぷらんなー「バグっぽいんだけど」
さーばーえんじにあ「仕様書通りの仕様です」


 みたいな事が起きたりします。確認を何度も挟んだとしても起きる可能性はありますが、チェックを複数段階で行なう事でその可能性を減らす事は出来ます。

影響範囲を纏める

 基本的に新規実装となるとQAチェックもその新規実装に対して全面的にチェックする、という簡単な構造になるのですが、既存コードへの修正はテストコードも改修して通ったとしても、ある程度はQAチェックを挟む必要があります。
 また、新規実装の為に既存コードにも手を加えた、という事に関しては仕様書への記載としてはSV側の改修点として見えない時もあります。
 なので既存コードに対して修正を入れたならば、それもきちんと纏め、QAチェックを依頼しましょう。

デバッグツールを作る

 QAが確認する際に、既存のデバッグツールでは時間が掛かる、などと言った苦情が来る可能性があります。
 余裕があったら必要そうなものを先んじて作っておいても良いでしょう(こういう事こまめにやっておくと好感度UPするんじゃないかな……)。
さーばーえんじにあ「特定の味噌カツのレシピを作れる素材を一括付与するとか、作っといたら便利かな?」

コードレビューを行なう

 第三者を招いてコードレビューを行いましょう(今更ですが、実装が複雑だったり、実装者が初心者だったりするのならば実装する前に設計レビューも設けた方がいいです、書くの忘れた……)。

 コードレビューの際には、コードを直接見せるのとは別途、追加したデータ構造などを記載したエクセルなども用意しておくと分かりやすくなります。


さーばーえんじにあ「今回は味噌カツ作りの実装を行いました。
 まずは、新規追加したモデルの構造から話します。
 マスタに関してですが、味噌カツ作りの為に新規マスタを二つ追加してあります。
 まず一つ目は、味噌カツの親マスタで……、
 次にユーザーデータは、ログが一つです、このログはユーザーの味噌カツ作成履歴を保存、更新しており……、
 ……インデックスは、ユーザーIDとレシピコードでユニークなのでそれでユニークインデックスを張ってあります……。
 ……です」
れびゅあー「マスタインポート時のチェックはどの位やってる?」
さーばーえんじにあ「指定された素材の存在確認くらいですね」
れびゅあー「explain取った?」
さーばーえんじにあ「マスタはメモ化してあるのでクエリは初回しか行われませんし、インデックス張ってある親コード単位とかでしか取ってきてないのでしてないです……。ユーザーデータもそんな感じですね……、問題無いとは思うのですが、余裕があったらやっておきます」
れびゅあー「問題ないと思うが、やっといてね」


さーばーえんじにあ「次に今回の基幹となる、指定された素材群からレシピを確定するというロジックの説明をします。
ここのロジックですが、これこれこういう風に作られるレシピを確定しています」
れびゅあー「そこ、計算量がO(n2 )で、マスタの数が大幅に増えたら計算量ヤバくならない? 改善出来ないかなぁ……」
さーばーえんじにあ「nはマスタの数ですよね、マスタそんなに今は数多くないので現状は大丈夫だと思いますが……でも改善出来そうなのでやっておきますね」
れびゅあー「わかった、その時はまたレビュー頼む」
さーばーえんじにあ「わかりましたー」
れびゅあー「あ、後、もうちょっとコメントあった方が良いと思う。コード自体に問題なくても、仕様がちょっと複雑だから」
さーばーえんじにあ「はーい」


 自分自身の観点からだと、クソコードもクソコードだと気づけない場合が良くあります。クソコードでなくとも、ぱっと見では分からない複雑さになっていたりとか。
 文章とかでもそうですが、一旦時間を置いてまた読み直してみると、前には気付けなかった欠点などにも気付けたりします。

コーディング後のチェックが完了したら

 そうして、自分のコードに対する影響や、後々に対するコスト、QA確認の為の事柄などを鑑みた上で他者からのお墨付きを貰う事で、最終的に味噌カツ作成のサーバー実装が完了となります。

 上記以外にも、バグや後々のリスクなどを防ぐ為に出来る事は色々とあると思いますが、時間も有限ですし、出来る事柄をやったとして、それら全てをやって全てに効果があるかもやや不明でしょう。
 確認行為などを行うにせよ、それをマニュアル的に行うのではなく、どういう目的の為に行うのか、それを念頭に入れて行いましょう。

より良い実装の為に(まとめ)

 サーバーに限らず、クライアントも同じ事だと思いますが、
 実装の最終目標は、仕様に沿った動くコードを作りあげ、追加/新規機能を実現する事です。しかしながら実装=コーディングではありません。
 ただ動くコードを作り上げるのではなく、後々のコストが肥大化しない為に、シンプル且つ柔軟で拡張性のあるコードを作り上げる事。認識の齟齬から後々の不具合を生み出さない事。既存部分への影響を鑑み、それに対する問題がないかの確認。そんな将来に向けた配慮が必須となります。

 上記の実装に対する例は自分が実装をしている時はこんな感じで進めているというようなものですが、これでも不完全な部分はあるでしょうし、改善出来る部分はしていきたいと思っています。
 
さーばーえんじにあ「腹減ったし、今日はソースカツ丼でも食べるか」
ぷらんなー「は?」
さーばーえんじにあ「昨日味噌カツ食べたので」
ぷらんなー「よーしよしよしよしよし」

多分終わり

味噌カツで例えるソーシャルゲームのサーバーサイドにおける新規実装の流れ 3

0

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

もはや味噌カツではない

前回までのあらすじ

前回

以下のゲームで、

牧場経営ソーシャルゲーム:
ユーザーは牧場を経営する。また、牧場などで育てたものを調理し、食べる事が出来る。
ユーザーにはステータスが存在し、様々な行動によってステータスが変動する。ある一定のステータスを伸ばすと出来る事が増える。
ステータスは割合で決定されており、どれかのステータスを上げると他のステータスが落ちる。
一度得た能力は消えない。

味噌カツを作る事が決定しました。
提示された仕様書を読み込み、それに対して曖昧な点や改善すべき点を会話して解消した後に、サーバーエンジニアがすべき事は以下のように明確になりました。

・味噌カツを消費する事でユーザーのステータスのナゴヤ成分が上昇する、は既存のコードで対応可能か確認する
 =>変わらず
・味噌カツを作るAPIは既存の調理APIとは別として新規に作成する
 =>既存の調理APIとはかけ離れた部分が多くなった為
・味噌カツトップ画面の為のAPIを作成する
 =>クライアント側で持っていない情報を表示する必要が確定した為
 返すものは
  ・味噌カツを作成する為に必要な素材種別群

※実装する事が複雑でなくとも設計書として纏めて共有しておくとベターです。

 仮実装までの想定日数は2日と定めました。

仮実装

 実装に対して何から始めていくのかはどのような開発手法を取っているかによって違ってくるかと思いますが、ゲーム開発においての最優先事項は実機で確認出来る状態を作る、という事だと思いますので、それに沿って仮実装を行います。

さーばーえんじにあ「まあ、軽いやつからやっていくか」

味噌カツを消費する事でユーザーのステータスのナゴヤ成分が上昇する、は既存のコードで対応可能か確認する

さーばーえんじにあ「料理を消費する事でユーザーのステータスが上昇する仕組みはもうあって、料理には出来の良さの値も保存されていて、それに依存してステータスの上昇度合いが変動する仕組みもある。
 だから、それが味噌カツだろうと味噌カツじゃなかろうと、特に何もする必要はやっぱり無いな」

味噌カツトップ画面の為のAPIを作成する

さーばーえんじにあ「やるべき事は、あれ……これ、調理トップ画面もいじらないといけないか。
 味噌カツ以外にもそういう風に調理できるものが増えた場合、調理トップ画面からの遷移先が複数になるかもしれない。その複数の遷移先を判別出来る情報を調理トップ画面でも渡さなきゃいけないか。
 クライアントエンジニアさん、そんな感じで良いですか?」
くらいあんとえんじにあ「りょーかい。今回は取り敢えず遷移先1個だけだけど、レスポンスの形は、今回は配列じゃなくて良いかな?
 遷移先が複数になったらUIもそういう風に対応しなきゃいけないだろうからさ」
さーばーえんじにあ「分かりましたー」

さーばーえんじにあ「じゃ、味噌カツトップ画面では、クライアントから受け取った値を参照して、対応するマスタの情報を返す。
 レスポンスの形はクライアントエンジニアと相談する必要あるな」
くらいあんとえんじにあ「素材の種類が最大6つって決まっているなら、配列じゃなくて、それぞれ別のキーとして返して欲しい」
さーばーえんじにあ「りょーかい。現状だとそれだけだか。すぐ終わる」

味噌カツ作成のAPIを作成する

さーばーえんじにあ「えーっと、普通の調理APIをコピって、違う部分を変えていけばいいな。
 パラメータは味噌カツの素材群と味噌カツを作るという宣言が必要。
 通常の調理の時の素材存在確認とかのアサーションに加えて、本当にその素材で味噌カツが作れるかを確認。
 マスタを参照してどの味噌カツが作られるかを決定。ユーザーのステータスに加えて、そのマスタのデータを基にして味噌カツの出来の良さを決定。
 …………。
 まあ、取り敢えずそこあたりは仮実装だから適当にやっておこう。また後で必要なアサーションをリスト化したりしよう。
 レスポンスは作られた味噌カツでいいのかな?」
くらいあんとえんじにあ「そーだな、調理完了演出はそんなに普通の調理と変わらないから、多分それで事足りる」
さーばーえんじにあ「おっけ。後は必要なマスタのテーブルを作る処理とか、CSVからインポートする処理とか入れて……。
 明日には仮実装反映出来そうです」
くらいあんとえんじにあ「わかりました」
さーばーえんじにあ「APIのURLと必要なパラメータ、返されるレスポンスはこっちに書いておきました。後、調理APIでの追加パラメータはこんな感じです。これでいいですか?」
くらいあんとえんじにあ「……多分」
さーばーえんじにあ「追加で欲しいものあったら言ってください」
さーばーえんじにあ「で、後はマスタ待ちか。
 適当に作ってあるところしっかりと作ったり、テストコード書いたり、影響範囲纏めたり、そういう事しておこう」

仮マスタが来ました

ぷらんなー「マスタ、仮で出来たよ」
さーばーえんじにあ「入れてみますー。あ、ミスった、直して……ん? ちょっといいですか?」
ぷらんなー「ん?」
さーばーえんじにあ「何でも良い部分の素材アイテムコードって、0を入れるんですっけ?」
ぷらんなー「あ、それじゃまずい?」
さーばーえんじにあ「まー、どっちでも良いです。えーっと、既存コードに合わせるとして、他の部分どうだったっけ……基本的に0だけどnullの部分もある……あー、うー、えー……。0の方が多いか……。こっちが対応します」
※既存のクソコードは影響範囲が大きくなるのならばそっとしておいた方が良いかもしれません
ぷらんなー「わかった」
さーばーえんじにあ「後は問題なさそうですね」
ぷらんなー「りょうかい」
さーばーえんじにあ「APIの確認もして……あ、getだとパラメータは全部文字列か……直して……出来た、反映出来る」

仮実装反映後〜補強して本実装

実機確認

さーばーえんじにあ「開発環境に反映しました」
くらいあんとえんじにあ「りょーかい、確認しておく」
くらいあんとえんじにあ「なんかInternal Server Error起きた」
さーばーえんじにあ「えっ、確認します」
さーばーえんじにあ「あー……さっきの確認の時、この条件の時の事漏れてたな……」
さーばーえんじにあ「修正反映しました」
※仮実装でもこういう事を頻発させるとエンジニアとしての信頼度が落ちていきます
くらいあんとえんじにあ「りょーかい……大丈夫、取り敢えず後は問題無さそう」
さーばーえんじにあ「りょーかいです」
くらいあんとえんじにあ「こっちも後で確認出来る状態のもの上げておくから、上げたらそっちでも確認してみてね」
さーばーえんじにあ「わかりましたー」

仮実装から本実装へ

さーばーえんじにあ「さて、アサーションとかちょっと適当にやってた部分ちゃんとやるか。
 今回でやるべきなのは……普通の調理と比較した場合……まあ、この位だな。
 コード修正、書き加えて、その分のテストコード書いて。
 味噌カツ作りが失敗する。
  条件1:味噌カツなのに豚肉ではなく牛肉を選んだ
  条件2:味噌カツなのに味噌が無い
  条件3:味噌カツを作る為のお金が無い
  条件4:味噌カツを作る為に選んだ素材が既に存在しない
  条件5:味噌が賞味期限切れ
  ……
 味噌カツ作りが成功する。
  判定1:味噌カツを作ったので豚肉、味噌、パン粉等が消費される
  判定2:味噌カツを作ったので味噌カツが増えている
  判定3:味噌カツを作ったのでお金が減っている
  判定4:この材料で味噌カツを作ると名古屋コーチンという名の味噌カツが作られ、また、出来栄えは乱数を鑑みた上でこの範囲内に絶対に収まり、その作成情報がログとして保存される
  判定5:この材料で味噌カツを作るとマスタ内のどのレコードの条件も満たせないので、平凡な味噌カツが出来る
  判定6:味噌カツを合計1000個作るとそのアチーブメント”最早名古屋”が達成される
  判定7:神聖なる新生味噌カツ新星を作るとアチーブメント”新しい名古屋”が達成される
  ……
 ……え、単純に箇条書きしたら20件ほど必要なテストが出てきたんだけど、これ全部テストコード書くの?」
※そうです。書かないと改修が必要になった時の既存コードの保証が出来ません。
さーばーえんじにあ「ダミーユーザー作ってダミーマスタ作ってダミーユーザーデータ作って……今日の昼はコ●ダで味噌カツサンド食べよう……。
 マスタの準備さえ出来れば後は似たようなコードコピーして判定部分だけ変えていけばいいはずだから……」

数時間後

さーばーえんじにあ「あー、終わった。まあ、ちょっとバグも直せたし、これで一旦大丈夫か……じゃあ後は、影響範囲纏めて、QAに提出する確認すべき範囲も纏めて、コードレビューして、終わり、か。
 ちょっと遅くなったけどコ●ダ行こう」
くらいあんとえんじにあ「ちょっと良い?」
さーばーえんじにあ「えっ」

次で多分最後

味噌カツで例えるソーシャルゲームのサーバーサイドにおける新規実装の流れ 2

0

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

味噌カツは進化する

前回までのあらすじ

前回

以下のゲームで、

牧場経営ソーシャルゲーム:
ユーザーは牧場を経営する。また、牧場などで育てたものを調理し、食べる事が出来る。
ユーザーにはステータスが存在し、様々な行動によってステータスが変動する。ある一定のステータスを伸ばすと出来る事が増える。
ステータスは割合で決定されており、どれかのステータスを上げると他のステータスが落ちる。
一度得た能力は消えない。

以下の仕様にて味噌カツを作る事が決定し、

仕様概要
 ・既存の調理機能にて味噌カツページを作成し、ユーザーの所持する特定のアイテム群を消費する事によって、味噌カツを作れるように機能拡張

味噌カツについて
 ・味噌カツを消費するとユーザーのステータスのナゴヤ成分が上昇する。
  ・上昇度合いは味噌カツの出来の良さによって決定される。
   ・味噌カツの出来の良さは、既存の調理機能では、ユーザーのステータスだけで決定されていたが、味噌カツはそれに加え、消費するアイテムによっても変動する
    ・どのような味噌カツが出来るかはMisokatsuMasterで定義する

ナゴヤ成分
 ・ナゴヤ成分とはユーザーのステータスの新しい種類である
  ・ナゴヤ成分の上昇に伴う作用
   ・ナゴヤ成分の割合により新たなレシピを作れるようになる(例: 小倉トースト、抹茶スパ、名古屋コーチン)
   ・新たなアチーブメントの追加
 ※ナゴヤ成分の追加による事柄は全て既存マスタへのデータ追加で対応可能

ユーザーインターフェース要件(以下ユーザーインターフェースはUIと略す)
 ・調理トップ画面に味噌カツトップ画面への遷移ボタンを追加
  ・味噌カツトップ画面で表示するものは以下
   ・ユーザーの所持する味噌、豚肉、その他味噌カツを作成する為のアイテム一覧を表示、選択出来る
   ・ユーザーがこれまで作成した味噌カツを表示、消費出来る
   ・味噌カツ作成ボタン

仕様書を読み込んだらサーバーエンジニアが行うべき事は以下に纏められました。

・味噌カツを消費する事でユーザーのステータスのナゴヤ成分が上昇する、は既存のコードで対応可能か確認する
・味噌カツ作りは既存機能では対応出来ないので、既存機能の拡張、または専用機能の追加を行う
・味噌カツトップ画面で返すべき情報があるのならば、返すAPIを作成する

実装に入る前に考えよう

 さて、ここまで分かったなら実装に入りたいところですが、その前に一旦立ち止まりましょう。
 これをこのまま文言通りに実装して運用していったら、将来どういう事柄が起きるのかなどを想定してみると、色々と困る事が浮かんできます。

 例えば、今回の拡張が好調だったから、今度は博多ラーメンでハカタ成分の上昇とかやりたい! と言われたらどうなるでしょう。
さーばーえんじにあ「えっ、そうなるとMisokatsuMasterに博多ラーメンを入れる必要があるんだけど、MisokatsuにHakataを入れるの? そのテーブルに作る大元のものが味噌カツか博多ラーメンか区分するカラムも追加しなきゃいけないし、変数名もmisokatsuとか使ってるし、え、えぇ……」
 他にも、
・パン粉も追加で素材として選べるようにしたい!
・今まで作った味噌カツ履歴を更に詳細に表示出来るようにしたい!
・味噌カツよりソースカツの方が美味しい!
・抹茶スパの必要性
 などが浮かんでくるでしょう。
 要するに汎用性に欠けた作りにしてしまったりすると、後から改修を入れるとなった時に、手を加えるべき範囲が広くなってしまうという事になります。
 そうなると実装コストの増大、確認するべき場所が多岐に渡る、テストコードの大幅改修などなど、対応に掛かる時間及びに改修へのリスクの増加というとても面倒臭い事になってしまいます。
 そんな事を避ける為に、この味噌カツ作成に対してはこれから先、どこまでの拡張が想定されるのか、などをしっかり考えた上で実装に対して臨まなくてはいけません。
 じゃあ、それを誰に聞くのか。
 勿論、仕様を考えた人、プランナーに聞きましょう。


さーばーえんじにあ「仕様に関して質問があるんですけど」
ぷらんな「何でしょう」
さーばーえんじにあ「今回は味噌カツに対してそういう機能を追加するっていう実装ですけど、今後味噌カツ以外で何か博多ラーメンでハカタ成分を向上させたりとか、レモン牛乳でトチギ成分を向上させたり、海藻でチョウシ成分を向上させたりとか、そんな事は有り得ますか?」
ぷらんな「海藻……? まあ、無いとは言い切れないかな」
さーばーえんじにあ「じゃあ、味噌カツに特化した作りじゃちょっと困りますね。特にマスタ名とか、MisokatsuMasterに博多ラーメンとかサーターアンダギーとか野沢菜漬けとかそんなもの入れる事になっちゃうので、別名でお願いします」
ぷらんな「えー、あー、うー、……はい」

さーばーえんじにあ「後、ソースカツの方が美味しいと思います」
ぷらんな「は?」


 曖昧な仕様や今後拡張されたらこのままの仕様だとマズいとか、そういうものはプランナーやエンジニア、デザイナーとも話し合ったりして、実装する前にしっかりと固めていきましょう。
 話し合ったとしても、実装する途中、後でやっと発覚する事などもあったり、またどんな形での拡張も柔軟に対応出来る作りにするというのは流石に出来ませんが、早め早めの対応で将来的なコストは出来るだけ少なくなるように心掛けた方が吉となる事は確かです。
 その結果、以下のようになりました。

・味噌カツに特化した作りにはしない
 =>えんじにあ「芋煮作る時困るよ」
・味噌カツなどの素材を選べるレシピに対し、素材の数は最大6とする
 =>でざいなー「素材の種類の最大数が決まってないとUIのデザインが決めづらいよ」
・作成履歴を保持。作れる味噌カツの種類単位で最良の出来となったものを1個ずつ。
 =>えんじにあ「味噌カツ履歴とか将来的に表示する可能性あるなら、保持しといた方が良いよね」
  ぷらんな「可能性は無きにしも非ず」 
・抹茶スパは必要
 =>ぷらんな「ナゴヤ成分が100%の時のみ強力なバフアイテムとして作用するのさ」

 仕様書も更新され、マスタの形などもしっかりと固まりました。
 
 サーバーエンジニアがすべき事も、これからの拡張を鑑みた柔軟な作りをベースに実装できるようになりました。
 そしてすべき事も、更に明確になりました。

・味噌カツを消費する事でユーザーのステータスのナゴヤ成分が上昇する、は既存のコードで対応可能か確認する
 =>変わらず
・味噌カツを作るAPIは既存の調理APIとは別として新規に作成する
 =>既存の調理APIとはかけ離れた部分が多くなった為
・味噌カツトップ画面の為のAPIを作成する
 =>クライアント側で持っていない情報を表示する必要が確定した為
 返すものは
  ・味噌カツを作成する為に必要な素材種別群

さーばーえんじにあ「まあ、やる事はそんなに複雑じゃないし、大体新規実装になったから既存コードの調査とかあんまり要らないし、実装の為の新規マスタの形も整ったし、テストコード含めなければそんなに長い時間は必要じゃないかな」
さーばーえんじにあ「マスタが間に合うなら、仮実装で2日くらいで開発環境に反映、確認できるようになると思います」
くらいあんとえんじにあ「りょーかい」

まだまだ続く

味噌カツで例えるソーシャルゲームのサーバーサイドにおける新規実装の流れ 1

0

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

味噌カツ

こんなソーシャルゲームを作っているとします

牧場経営ソーシャルゲーム:
ユーザーは牧場を経営する。また、牧場などで育てたものを調理し、食べる事が出来る。
ユーザーにはステータスが存在し、様々な行動によってステータスが変動する。ある一定のステータスを伸ばすと出来る事が増える。
ステータスは割合で決定されており、どれかのステータスを上げると他のステータスが落ちる。
一度得た能力は消えない。

そして、このソーシャルゲームの運用はサーバーエンジニア、クライアントエンジニア、プランナー、デザイナー、プロジェクトマネージャー、ディレクターで運用されています。

サーバーエンジニア: メインの事柄は、ユーザーデータを管理。
クライアントが味噌カツを作りたいと要求してきたら、本当に味噌カツを作れるかどうか確認して、味噌カツを作る処理を行い、ユーザーデータを編集する。
味噌カツでいうと味噌カツを置く為の机や食べる人が座る為の椅子。土台。

クライアントエンジニア: ゲームの実部分。ユーザーが実際にゲームを遊ぶ部分の実装。
ユーザーが味噌カツを作る為のUIなどの表示、ユーザーが味噌カツを作るとボタンをタップしたら、サーバーに味噌カツを作ると要求を飛ばし、作れたらその旨の表示をする。
味噌カツでいうと味噌カツを食べる為の箸や味噌カツを載せる為の皿。

プランナー: ゲームの内容を決定する。
味噌カツを作ると決定する。味噌カツの味やどのような味噌カツを作れるのかなどを決定する。
味噌カツでいうと、味噌カツのレシピやメニュー。

デザイナー: ゲームの絵やUIを作成する。
味噌カツを描く。味噌カツ作成の為のUIなどを作成する。
味噌カツでいうと味噌カツ。

プロジェクトマネージャー: ソーシャルゲームのプロジェクトのマネジメントをする。
味噌カツでいうと、味噌カツを作る人を支える人。

ディレクター: ソーシャルゲームのディレクションをする
味噌カツでいうと、味噌カツの方向性を決定する人。

新規実装が決まりました

ぷらんな「先日の話し合いにより、納期までに使えるリソースを鑑みた上で、次のバージョン、ver味噌.カ.2にて、ウチの出している牧場ゲームに味噌カツを作る実装が入りました」
さーばーえんじにあ「わかりました」
ぷらんな「仕様書はまだざっくりとですが、こちらを参考にお願いします」

仕様書

仕様概要
 ・既存の調理機能にて味噌カツページを作成し、ユーザーの所持する特定のアイテム群を消費する事によって、味噌カツを作れるように機能拡張

味噌カツについて
 ・味噌カツを消費するとユーザーのステータスのナゴヤ成分が上昇する。
  ・上昇度合いは味噌カツの出来の良さによって決定される。
   ・味噌カツの出来の良さは、既存の調理機能では、ユーザーのステータスだけで決定されていたが、味噌カツはそれに加え、消費するアイテムによっても変動する
    ・どのような味噌カツが出来るかはMisokatsuMasterで定義する

ナゴヤ成分
 ・ナゴヤ成分とはユーザーのステータスの新しい種類である
  ・ナゴヤ成分の上昇に伴う作用
   ・ナゴヤ成分の割合により新たなレシピを作れるようになる(例: 小倉トースト、抹茶スパ、名古屋コーチン)
   ・新たなアチーブメントの追加
 ※ナゴヤ成分の追加による事柄は全て既存マスタへのデータ追加で対応可能

ユーザーインターフェース要件(以下ユーザーインターフェースはUIと略す)
 ・調理トップ画面に味噌カツトップ画面への遷移ボタンを追加
  ・味噌カツトップ画面で表示するものは以下
   ・ユーザーの所持する味噌、豚肉、その他味噌カツを作成する為のアイテム一覧を表示、選択出来る
   ・ユーザーがこれまで作成した味噌カツを表示、消費出来る
   ・味噌カツ作成ボタン

ぷらんな「細かい点は追って記載しますが、現状は上記が確定事項です」

サーバーエンジニアがまず考えなければいけない事

納期までに使えるリソースを鑑みた上で、と前置きされているとは言え、サーバーエンジニアはまず最初に実装を完成させなければいけません。
そうでなければ、クライアントエンジニアはサーバーに味噌カツを作りたいと要求が出来ずに、ダミー味噌カツを使っての仮確認程度しか出来ないのですから。
なので、
・ 実装までにどれだけの時間が掛かりそうなのかをまずは計算したい
です。
その為にはまず、
・味噌カツ作りを実装する為に、サーバーはどのような事を実装しなければいけないのか
をリスト化しましょう。
それが分からなければ、実装コストも分かりません。

味噌カツ作りを実装する為に、サーバーはどのような事を実装しなければいけないのか

仕様書を見ると、味噌カツ作りの実装には3つの要素があります。
・味噌カツを作る事
・ナゴヤ成分の追加
・味噌カツの為のUIの追加
しかしながら、ナゴヤ成分の追加に関しては仕様書にも書いてある通り、既存マスタへのデータの追加で事足りると言うので、サーバーエンジニアが行う事は味噌カツを作る事及びに、味噌カツの為のUIの追加となります。


それではまず、仕様書の味噌カツについての部分を読み込んでいきましょう。

味噌カツについて
 ・味噌カツを消費するとユーザーの特性のナゴヤ成分が上昇する。
  ・上昇度合いは味噌カツの出来の良さによって決定される。
   ・味噌カツの出来の良さは、既存の調理機能では、ユーザーのステータスだけで決定されていたが、味噌カツはそれに加え、消費するアイテムによっても変動する
    ・どのような味噌カツが出来るかはMisokatsuMasterで定義する

その中で、トップに来ている以下の一文を見てみましょう。

・味噌カツを消費するとユーザーのステータスのナゴヤ成分が上昇する。

特定のアイテムを消費するとユーザーの特定のステータスが上昇する。これは、 ユーザーにはステータスが存在し、様々な行動によってステータスが変動する。 というゲームの特性上、普通にマスタの追加などで、サーバーの改修は必要とせずに完了しそうですね(食べるという行為をする事でステータスの上昇を今までは想定していなかったとか、そういう事がない限り、それで出来なかったらそのコードはクソです)。
まあ、上記を満たす為に行うべき事は、本当にサーバーの改修が必要でないか、の確認程度になりそうです。
プロジェクトに参画している期間にも依るでしょうが、そう時間は掛からないでしょう。

TODO: 味噌カツを消費する事でユーザーのステータスのナゴヤ成分が上昇する、は既存のコードで対応可能か確認する

とすると、残りは以下になります。

・上昇度合いは味噌カツの出来の良さによって決定される。
 ・味噌カツの出来の良さは、既存の調理機能では、ユーザーのステータスだけで決定されていたが、味噌カツはそれに加え、消費するアイテムによっても変動する
  ・どのような味噌カツが出来るかはMisokatsuMasterで定義する

 これらは既存の機能では対応できないので、既存の調理機能の改修または、味噌カツを作る為の専用機能の追加、で対応する事になりそうです。

TODO: 味噌カツ作りは既存機能では対応出来ないので、既存機能の拡張、または専用機能の追加を行う


 次に、味噌カツUIの追加に関して見ていきましょう。

 UIの実装に対してはサーバーエンジニアは余り影響しないような気もしなくもありませんが、そのUIを表示する為に必要な情報をクライアントが全て常に持っているとは限りません(データ漏洩などの観点から、基本的にクライアントには必要最低限の情報しか渡さないようにすべきです)。
 なので、味噌カツUIを表示する為にクライアントが必要な情報をAPIを作成して適切に返してあげたりする必要があります。

UI要件
 ・調理トップ画面に味噌カツトップ画面への遷移ボタンを追加
  ・味噌カツトップ画面で表示するものは以下
   ・ユーザーの所持する味噌、豚肉、その他味噌カツを作成する為のアイテム一覧を表示、選択出来る
   ・ユーザーがこれまで作成した味噌カツを表示、消費出来る
   ・味噌カツ作成ボタン

 この要件から鑑みるに、味噌カツトップ画面でサーバーがクライアントに渡す必要がありそうな情報は、
・ユーザーの所持する味噌、豚肉、その他味噌カツを作成する為のアイテム一覧
・ユーザーがこれまで作成した味噌カツ
の二つです。
 これを実際味噌カツトップ画面を表示する上で渡す必要が出てくるのならば、その情報を返すAPIを作らなくてはいけません。
 クライアントエンジニアと相談になりますね。

TODO: 味噌カツトップ画面で渡すべき情報があるのならば、それ用のAPIを作成する


 さて、これでサーバー側が実装すべき事は纏まりました。

・味噌カツを消費する事でユーザーのステータスのナゴヤ成分が上昇する、は既存のコードで対応可能か確認する
・味噌カツ作りは既存機能では対応出来ないので、既存機能の拡張、または専用機能の追加を行う
・味噌カツトップ画面で返すべき情報があるのならば、返すAPIを作成する

 ここまで分かれば、実装に必要な期間も明確になってくるでしょう。それを共有し、スケジュールなどを組み立てましょう。
 しかしながら、ここまでが分かっても、まだ実装に移るのは早いです。

次回に続く

魔王を説き落とす前に説き落とした後の事を考えよう(負荷テストをしよう)

0

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

魔王を説き落とした(リリースを迎えた)からと言ってその後の事はちゃんと想定しておきましょう。

魔王を説き落とす(リリース)前に

ゆうしゃ「信頼できる仲間(コンテンツ)がいる! 設備(マスタ)も揃えた! 商品(リソース)も十分! 魔王と交渉に(リリース)行くぞ!」
おうさま「ちょっと待ってね」
ゆうしゃ「え? あの、おうさま、なんでこんなところに? この辺り一人で居ると、まだ色々と危険なのですが」
おうさま「この体、分身体だから。それはそれとして、君と交わした契約には魔王との交渉(リリース)だけじゃなくて、その後の町の運営(運営)まで任せているよね?」
ゆうしゃ「え、あ、うん? ええ、はい。一応町作ってありますよ? 機能もしっかりしてます。有志を住まわせてちょっとテスト(QAチェック)もしてもらいました」
おうさま「どのくらい住民が来るとか考えた? ちゃんとその人数想定(DAU)で機能するか見た?」
ゆうしゃ「え、いや、あんまり……」
おうさま「じゃあ、ホムンクルスを人数分だけ貸しておくからさ、テストしておいて」
ゆうしゃ「ホムンクルス」
おうさま「材料は安いからね」
ゆうしゃ「安い」

ホムンクルスに行動設定をしよう(負荷テストを作ろう)

ゆうしゃ「ホムンクルスが十万人も居ると凄いなあ」
ホムンクルス「あー」
ホムンクルス「びぇー」
ホムンクルス「ふぇふぇふぇふぇふぇふぇふぇふぇ」
ホムンクルス「ふるぅつ」
ゆうしゃ「えーっと、取り敢えず、ホムンクルスに命令を書き込めば後は勝手に動いてくれるんだよな(負荷テスト用のシナリオをJMeterとかで作りましょう)。一通りの動作を確認しておかなきゃいけないから、朝に起床してからご飯を作って、バスに乗って勤め先に行って、お仕事をして、お昼休憩、昼からも仕事をして、……残業設定とかどうしようか、ある程度ランダムに動かしておくか…………ここ辺りもランダムにしておかないとちゃんとテスト出来ないよな…………、えっと休日の設定? 図書館と警察署と運動場と劇場に色んな機能チェックしておかなきゃいけないよね(API単位で出来るだけ網羅しつつ、実際の行動を想定して作りましょう)、うん、えっと、魔王との交渉いつだったっけ、2ヶ月後? え? 間に合う?」

1週間後(シナリオテストの作成にかかる時間は規模に応じます)

ゆうしゃ「書き終えた……、眠いよ……さてテスト」
ホムンクルス「ばぎゃむみぇぁらべぽぶー」
ゆうしゃ「壊れちゃった。書き直して」
ホムンクルス「あみゃめれごみばるぶぶぶぶぶー」
ゆうしゃ「別の部分壊れてる。書き直して」
ホムンクルス「おぎゃああああああああああああああああああ」
ゆうしゃ「おぎゃああああああああああああああああああああああああああ」

2日後(バグ取りは頑張って下さい)

ゆうしゃ「……」
ホムンクルス「おはようございます。朝ごはん作ります。マンドラゴラと満月大根のスライム煮を作ります。食べ終えてからはスーツに着替えてバスに乗り会社に向かいます。会社に向かったらパソコンの前に3時間座った後お昼ご飯を食べます。お昼ご飯は8割の確率でコンビニ、1.5割の確率でラーメン、0.5割の確率で洒落たランチを食べます。お昼ご飯を食べ終えた後は……」
ホムンクルス「……夜ご飯を食べた後は日付が奇数ならばお風呂に入ります。日付が3の倍数ならばゲームをプレイし、また5割の確率でドラゴンウイスキーを飲みます。また、ドラゴンウイスキーを飲んだ時、3割の確率で明日に寝坊イベントが発生します。本日は12月25日ですので、クリスマスイベントが優先され、恋人がいる場合は今から外出します。私には現在恋人が居ませんのでクリスマスイベントは安売りのコカトリスターキーを食べる事になりました」
ゆうしゃ「……できた? できた! やったああああああああああああああああ(シナリオテストを作るのはとても大変です)」

実際に近い状況を作ろう(テストデータをデータベースに入れよう)

ゆうしゃ「まだ終わっちゃいない、終わっちゃいないんだ。次はちゃんと施設を仮でも実際の環境に近くしなきゃ……。図書館には本を入れて警察署には武器を用意して、刑務所には囚人を用意してスーパーには食材を会社にはパソコンを……。本は中身なんてどうでもいいとして、銃器も実際に発砲するイベントは起きないレベルだから起きないとしちゃって、うん、囚人は人形でいいや、うん、うん(テストデータはそこまできちんとしている必要は余りありません。入っている事、それ自体が結構重要な事です)」

3日後(テストデータを作成するソースを作る時間も規模に応じます)

ゆうしゃ「紛い物だらけだけど、形になった、残された猶予は後1ヶ月ちょっと、ホムンクルス達、動かすぞ!!!!!!!! やっと、やっと始まるんだ!」

一つの町でテストをしよう(単体APIサーバーでの性能を確認しよう)

ゆうしゃ「まずは軽く走らせてみよう。ホムンクルス起動!! スイッチオーン!」
ホムンクルスA「おはようございます。私は身長3m、体重272kgです。私は寝坊イベントが発生したので寝坊します」
ホムンクルスB「おはようございます。私は身長50cm、体重10kgです。私は歩いて会社へと向かいます。途中バスに乗ります」
……
ホムンクルスK「建設業として建設途中の建物の前で3時間立ちました。お昼ご飯に向かいます。抽選の結果本日はコンビニで食事を買います」
ホムンクルスPX「公務員として役所の中で4時間座りました。朝のイベントで弁当を作成したのでお昼ご飯イベントは存在しません」
ホムンクルスJJ「タクシー運転手として一定の道路を3時間周回しました。お昼ご飯に向かいます。抽選の結果突発的タスクの発生の為、お昼ご飯イベントは抹消されました」
……
ホムンクルスGA「おぎゃああああああああああああああああああ」
ホムンクルスPT「仕事を終了しました。夜イベントは無趣味の設定の為存在しません。直帰します」
ホムンクルスRR「残業イベントが発生した為仕事を終了出来ませんでした。もう2時間立ち続けます」
ホムンクルスAE「仕事を終了しました。夜イベントは遊び人の為抽選が行われます。本日はギロッポンでレッツパーリィします」
……
……
ゆうしゃ「ちょっとバグ起きたから直さなきゃ……(沢山動かすと発生するバグも良くあります)」
ゆうしゃ「でも、簡単なデータは取れたぞ。えーっと? 図書館で本を借りるイベントと警察署から処刑場にまで行くイベントが何か遅いなあ。何だこれ、調べてみよう(調査ツールを入れておくとボトルネックが分かりやすいです)」
ゆうしゃ「図書館で遅い原因は索引が無いからか。ちゃんと入れよう(データが沢山入っているとデータベースのindexの漏れなどが分かりやすくなります)。
 で、警察署から処刑場までは、これ、そもそも回り道ばっかり使っているじゃないか。ちょっと一本で行ける道を作ろう(ロジックが重かったりするとそれも重い原因になります。O(n2 )とかになってしまっているロジックはしっかり見直しておきましょう)」
……
……
ゆうしゃ「バグ取って、明確に遅い部分もちゃんと取り除いた。もう一度」
ホムンクルスA「おはようございます。本日は昨晩の残りの囚人ステーキがある為、それを朝食とします」
ホムンクルスB「おはようございます。風邪イベントが発生した為本日は自宅で何もしません」
ホムンクルスC「おはようございます。昨晩にご飯を炊き忘れるイベントを発生させた為、本日の朝ごはんはありません」
……
ホムンクルスTN「本日はイベントに来ています。現在の所持金が27301円である為、20000円の写真集を購入します」
ホムンクルスAS「先日に失業イベントが発生した為、ハローワークに来ています。面接イベントが20%で発生します。発生しませんでした。帰宅します」
ホムンクルスRK「本日昇給イベントが発生した為、75%の確率でディナーイベントが発生します。発生しました。ディナーイベントの為お金が7000円消費され、現在の所持金が-2988円となりましたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたたた」
ホムンクルスPI「本日宝くじイベントが発生した為、1%の確率で20億円が当たります。当選しました。現在の所持金は1928309576 + 2000000000 = -1780825929となりりりりりりりりりりりりりぃぃぃぃぃぃぃぃぃぃぃぃぃぃ」

ゆうしゃ「まだちょっとバグあるなぁ……所持金周り見直さないと」

3日後(バグ取りは頑張って下さい)

ゆうしゃ「バグもわかってる限りは直した。明らかに重い処理も潰した。さて、やっと性能を測れる(性能を測るのはバグや取り除ける重い処理を潰してからにしましょう)」
ゆうしゃ「えーっと、取り敢えず今の街の性能でどの位のホムンクルスを捌けるか見てみようかな」

ゆうしゃ「5000人は簡単に捌ける」
ゆうしゃ「10000人も捌けた、でもちょっと危ないかな……」
おうさま「進捗はどうかね」
ゆうしゃ「あ、おうさま。一つの街にどれだけの人が快適に住めるか確かめているところです。現状の結果がこれです」
おうさま「なるほど……。一つ聞くがね、食事というのは皆が一斉に摂るものではなかろう。全てのホムンクルスが1時に昼食を採るように設定されているが」
ゆうしゃ「あ、そうですね……」
おうさま「そこが一番先に限界値が訪れそうだが、実際の限界値はもう少し先になるのではないかね?」
ゆうしゃ「そうですね、少しブレを出してみます(重いAPIなどが一斉に同時に叩かれないように負荷試験は一斉の実行はしないようにしましょう。例えば、JMeterならばRampUpやsleepなどの値を操作しましょう)」
おうさま「頼んだぞ。あ、後、魔王との交渉は45日後までには行っておくように。そうでないと食用の死刑囚達の管理費が赤字になる」
ゆうしゃ「……分かりました」

2日後

ゆうしゃ「大体15000人が一つの街で捌けるかな……? これ以上増やすと渋滞とかが多発して良いことにはならないな……」
おうさま「結果が出たのかね」
ゆうしゃ「あ、はい。これです」
おうさま「ふむ……、これならば今の性能の街を想定人数まで捌けるように増やしていけば予算内に収まりそうだ」
ゆうしゃ「ですね(ほっと胸を撫で下ろす)」
おうさま「それで、一番先に限界が訪れるのは交通かね?」
ゆうしゃ「はい」
おうさま「そうした場合、電車やバスの本数を増やせば対応が可能か?」
ゆうしゃ「可能です(最も先に限界が来る要素を確認し、もし到達してしまった場合にどの部分を優先的にスペックアップすれば良いのか確認しておきましょう)」
おうさま「また、ホムンクルスを使って擬似的に街の機能をいろいろ使っているが、実際に機能は動いているのかね?」
ゆうしゃ「ホムンクルスの所持する金額やスーパーの商品の増減、処刑場に建てられた墓の数から問題ありません(DBのデータなどを確認して、実際の処理がきちんと行なわれているかを確認しましょう)」
おうさま「では、想定人数である75000人を実際に5つの街を作って確認してみようか」
ゆうしゃ「え、間に合いませんよ?」
おうさま「この街をそっくりそのままコピーすればいいのだろう? それなら構成情報をそっくりそのままコピーして移せばいいだけだ」
ゆうしゃ「?????」
おうさま「2日後までには対応しておく。待っておけ」
ゆうしゃ「???????????」

実際の想定で街を動かしてみよう(実際のDAU想定で負荷試験を行おう)

二日後

おうさま「できたぞ」
ゆうしゃ「ありがとうございます??(マジで作り上げたよこの人)」

ゆうしゃ「さて、まあ、取り敢えず、動かしてみるか。街をベッドタウンとオフィス街にそれぞれ分割して、1つのベッドタウンから5つのオフィス街にそれぞれ出勤させるようにして、と(ロードバランサを介してアクセスを複数のサーバーに分割させましょう)」
ゆうしゃ「実行」
ホムンクルスA「おはようございます、オフィスAへ出勤します」
ホムンクルスB「おはようございます、オフィスBへ出勤します」
ホムンクルスC「おはようございます、オフィスCへ出勤します」

1日後

ゆうしゃ「おかしい……」
おうさま「どうかしたのかね?」
ゆうしゃ「75000/5 = 15000ですよね?」
おうさま「そうだな」
ゆうしゃ「75000人を5つのオフィス街で働かせているのに、15000人を1つのオフィス街で働かせているより悪い結果が出るんです」
おうさま「結果は……時々、ところどころで詰まるようだな……」
ゆうしゃ「何故……?」
おうさま「うん? あー、ほれ、ここを見てみろ」
ゆうしゃ「はい? あ、あー……残業イベントがオフィス街Cで殆ど起きていない……だから、定時で帰る人が想定よりも多いから、その定時時刻での交通がパンクする……」
おうさま「一つの街でテストしていた時は、常に事象の発生確率が一定に保たれていたが、複数の街ではそれが偏る場合があるという事だな(ロードバランサはリソースを見て空いている場所にリクエストを投げるとか、そんな事は基本的にしてくれません)」
おうさま「幸い、予算はまだ十分だ。街をもう一つ二つ増やして試してみよう(余裕を持ちましょう)」

2日後

ゆうしゃ「問題……なし! 終わった、終わったよ、おうさま。これが結果レポートです」
おうさま「ふむ……問題ないな。それではホムンクルスを地に戻すか」
ゆうしゃ「え?」
おうさま「維持にも金が掛かるからな」
ゆうしゃ「あ、はい」
おうさま「cd path/to/homunculuses; sudo killall」
ホムンクルス「みゃぁぁぁぁぁぁぁ」
ホムンクルス「にゃぁぁぁぁぁぁぁ」
ホムンクルス「私は生きていぃぃぃぃぃぃぃ」
ホムンクルス「だずげでぇ゛ぇ゛ぇ゛……」
ゆうしゃ「…………(何か聞こえたような気がするけど、聞かなかった事にしよう)」

魔王を倒そう!(やっとリリース)

ゆうしゃ「魔王! こちらが我が王国が提示する、魔族と人間が共存する新モデルケースでございます」
魔王「トイレある。バスルームある。清潔好きな奴意外と多いからな。ベッドの質は十分。様々な形態の我が国民が住まうのに適している。そして重要なのは刑務所だ。人間も魔族も美味いからな。しっかり脱獄出来ないように作られているか? よし、大丈夫だな。そしてビジネス形態に変なところなし。……まあ、大丈夫だろう」
ゆうしゃ「やっだあ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛あ゛」

数日後

ゆうしゃ「満員電車とかは多少あるけど、想定範囲内。トラブルは多少あるけど、この街はちゃんと動いている。多分」
魔王「おい、勇者」
ゆうしゃ「なんでしょう?」
魔王「浄水場に食用スライムが入り込んで、その酸性の体のせいでぶっ壊れた」
ゆうしゃ「えっ」
魔王「早急に直してくれ」

僕達の戦いはこれからだ!!(バグは起こるよ。)

サイト内検索のインターフェースガイドライン

0

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

検索をデザインする上で意識すべきインターフェース

有益なフィードバックを提供すること

・レスポンス速度が速いこと
・サイトに適した別の検索キーワードの提案すること
 →ユーザーがサイトや商品に適したキーワードで検索してくれるとは限らないので、より具体的な結果になるよう提示する必要がある
・シンプルは表示項目
 →表示項目が多いと見づらく、少ないと詳細遷移すべきか分からないので、ユーザーの判断材料となる項目を適切に表示する必要がある

ユーザーのコントロールと自動的な制御のバランスがいいこと

検索結果一覧を表示する際、人気のアイテムを上位に出すことは大事だが、人気アイテムは確認済のリピートユーザーや、安い順に見たいユーザーなどのために並び順変更できることは大事。
・価格や並び順での並び替え

短期記憶の負荷を減少させること

ユーザーが検索を行う際必ず、確認したい目的のイメージを持っている。
検索画面でつまずいてしまうと、検索することに集中してしまい、目的のイメージへの意欲が薄くなってしまうので、ユーザーが詳細遷移するまでの負荷を減らす必要がある
・自動補完(サジェスト)
・絞り込み条件の表示
・履歴の表示

ショートカットを提供する

過去に訪問したページに再度訪問したいユーザーや、過去に行った検索条件で新しいアイテムを確認したいユーザーが、キーワード入力や検索を行わず目的を達成できるようにする必要がある。
・検索履歴
・お気に入り
・検索条件の記録

0件ヒットを減らす

誤字や絞り込みすぎによる0件ヒットを防ぐことが大事
・選択した絞り込み条件でのヒット件数の表示
・もしかして?の表示
・同義語対応

細部のレイアウトが重要

・検索窓が長いと入力されるキーワードも長くなる
・商品一覧の上部の文章は見られにくい
・検索に関係ないバナーなどを表示するのは良くない

美的意識も重要

いまいちなUIに比べUIが美しいと、検索結果0件の場合でも再検索を行ってくれるユーザーが多くなる

参考

情報検索のためのユーザインタフェース

カスタマーサクセスドリブン組織作り方のレポート JSCS#7

0

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

カスタマーサクセスとは?(おさらい)

顧客を成功させるために提供サービスの価値を最大に引き出せるよう支援すること。

登場人物

◆登壇者
 Repro株式会社 佐々木 翼
◆パネリスト
 HiCustomer株式会社 高橋 歩
 ベルフェイス株式会社 吉本 猛
◆モデレーター
 ベルフェイス株式会社 小林 泰己
◆内容
 地獄系CSの、組織のあり方や連携の仕方の解説


プロダクトとCSの関わり

顧客から要望を聞き出し、CSがユースケースを特定する。そして、顧客と機能の認識合わせを行った開発を行う。
CSは顧客からの声をチャットツールでダイレクトに収集し、使われない機能を開発させないことに注力する。
また、顧客の要望リストを管理し優先度を敏感に調整することが重要。

目的別に機能をジャンル分けしている。
・新規顧客開拓
・チャーン防止
・UX改善
・社内運用
etc

セールスとCSの連携(境界線?)

・CSは新規顧客のクロージングに参加し、顧客の期待値調整を行う。
・また既存顧客の商談を発見し商談を行う。
・CSと営業の仕事が重複するため、KPIをそれぞれ調整する必要がある。
 ※新規顧客獲得時のKPI
  CSも関わっているがCSは顧客獲得以外にも注力する必要があるため営業のKPIとしている。

部署全体のKPIの設定

KPIをツリー構造にしてどの項目を誰が達成するかを明確にするのは大事。
しかし、部門ごとで切り分けすぎると部分最適化してしまうため、KPIを共有することも大事。

CSの目的

カスタマーサクセスは、目的を持って1つづつクリアしていくのが重要。
そのために
①カスタマ―サクセス活動のゴールを考える
②事業KPIとCS活動を一致させること
が大事。

CSの業務範囲は企業担当制?役割担当制?どちらでやるべき?

・最初は企業担当制。その後、役割で切出せたり、メンバーで増えたりしてきたら役割担当制にする。
・最初はCSの役割を見つけることが大事。

オンボーディングとは?

・明確に決まったものはない
・お客さんのゴールを定義し達成すること

日本でもっとカスタマーサクセスを盛り上げよう!!の年末イベント

0

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

様々な会社のカスタマーサクセスを行っている人が登壇し、これまで経験してきた失敗談などをディスカッションしていく

日本でもっと”カスタマーサクセス”を盛り上げよう!!
俺たちの屍を超えていけ!!~実はこんなこと失敗してきました~

のセミナーに行ってきたのでどんな内容だったかを記載します。
食事とお酒も出て、笑いながらもとてもためになる内容でした。

◆モデレーター
 ベルフェイス株式会社
◆スポンサー
 JCSC
◆登壇者
 Sansan株式会社 田中二郎
 HiCustomer株式会社 高橋歩
 株式会社ビズリーチ 鈴木雄太
 ベルフェイス株式会社 小林昭宏、小林泰己(モデレーター)
 弁護士ドットコム株式会社 岩熊勇斗
◆内容
 過去を振り替えりこんな失敗をしてきたという話を登壇者達がディスカッションしていく

【失敗談】

◆顧客情報管理

顧客情報が散在
請求情報を参照するためにいろいろな情報を参照する必要があり、顧客がおおくなってくるとその分負荷が上昇していった。
データ分析正確にできず、何となくあっているだろうという不確かな状態であった。
スプレットシート管理などは最初から行わず、セールスフォースなどを利用するなどしたほうがよい
少なくとも、金額にかかわる部分の情報はまとめて管理しないといけない。

◆再現性

良いことでもあるが、顧客に入っていく対応を行っていた。
できる人は好いが、個々の顧客に対して入っていく対応を行いなおかつ多くの客の対応を行うことは難しい。
CSを俗人的にしないためにも、CSレベルを下げてでも誰にでもできるような対応を目指すことも重要
ただし、最初からCSレベルを下げるのではなく、いろいろ試し、サービスに合ったCSを探っていくことが重要

◆忖度

営業からエンジニアへのフィードバックで良かった点のみが伝えられたが、エンジニアですら問題点と思っている個所も上がってこず、営業に対して疑問を感じるようになることがあった。
フィードバックする際に情報を取捨選択するのもよいが、そのまま伝えたほうが良いこともある

◆ユーザー会

ユーザー会とは、ユーザーの言葉をエンジニアに伝える場であるが、エンジニアを参加させたところで、現場の話をするのが主で、コンテンツの話はせず、ユーザー会の目的を達成できていなかった。
ユーザー会という名の飲み会を行うと会話の敷居が下がり、何気ない会話の中からユーザーの言葉をエンジニアに伝えることができる場合もある

◆戦略なき戦術

すぐ目の前の顧客対応に集中しサービス全体の今後を見たうえでの対応ができていなかった。
いろいろな施策を無作為に行うのではなく、コンセプトを決め、一貫性をもって戦術を実施することが重要

【Q&A】

Q:BtoBで顧客対応者が辞めると顧客が離れるがどうしたらよいか?

A:契約時もしくは定期的に、契約の意思決定者は誰かを把握し、会社に対して担当者を複数人あてること

Q:カスタマーの業務範囲は?

A:顧客が活用してよかったと思う箇所すべてが業務範囲

Q:再現性を高めるための具体的な方法は?

A:マニュアル化

Q:カスタマー作成の立ち上げに何をすればいい?

A:・一人のお客さんを幸せにするにはどうすればいいか検討
・顧客と会い徹底的に話す
・とりあえずいろいろな対策をやりまくる
・オンボーディング

【Rails】I18nの言語データをDBから取得【i18n/i18n-active_record】

0

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

I18nの言語データをymlではなくDBから取得する方法を記述します。

準備

1.Gemfileに追記してbundle install

Gemfile

gem 'i18n-active_record', :require => 'i18n/active_record'

2.migrateファイル作成

$ bundle exec rails g migrations CreateTranslations locale:string key:string value:text interpolations:text is_proc:boolean
class CreateTranslations < ActiveRecord::Migration
  def self.up
    create_table :translations do |t|
      t.string :locale
      t.string :key
      t.text   :value
      t.text   :interpolations
      t.boolean :is_proc, :default => false

      t.timestamps
    end
  end
end

3.config/initializers/i18n_active_record.rbの作成

require 'i18n/backend/active_record'

Translation = I18n::Backend::ActiveRecord::Translation

if Translation.table_exists?
  I18n.backend = I18n::Backend::ActiveRecord.new

  I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Flatten)
  I18n::Backend::Simple.send(:include, I18n::Backend::Pluralization)

  # 一度呼んだkey,valueをインスタンス変数に保存する場合に使用。
  # 毎回SQLを実行しなくて済むがI18n.reload!しないとDBの値が書き換わっても前回の値が表示される
  # マルチテナント非対応
  # I18n::Backend::ActiveRecord.send(:include, I18n::Backend::Memoize)
  # I18n::Backend::Simple.send(:include, I18n::Backend::Memoize)

  I18n.backend = I18n::Backend::Chain.new(I18n.backend, I18n::Backend::Simple.new)

  # I18n.t()でDBでもファイルでも言語がヒットしなかった場合、その時のkeyやoptions等の情報ををDBに保存したい時に使用
  # 後でレコードやlocaleファイルを追加・更新する時に便利になるが毎度saveが走るためパフォーマンス低下の恐れあり
  # I18n::Backend::Chain.send(:include, I18n::Backend::ActiveRecord::Missing)
  # I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n::Backend::Simple.new)
end

使い方

1. 通常

config/locales/ja.yml

ja:
  user:
    name: ymlのユーザー名
$ bundle exec rails c

[1] pry(main)> I18n.t('user.name')
=> 'ymlのユーザー名'

[2] pry(main)> Translation.create(locale: :ja, key: 'user.name', value: 'DBのユーザー名')
=> #<I18n::Backend::ActiveRecord::Translation...........

[3] pry(main)> I18n.t('user.name')
=> 'DBのユーザー名'

2. proc

$ bundle exec rails c

[1] pry(main)> Translation.create(locale: :ja, key: 'test.proc', value: '1+2', is_proc: true)
=> #<I18n::Backend::ActiveRecord::Translation...........

[2] pry(main)> I18n.t('test.proc')
=> 3

Kernel.eval(value)してるだけみたい。ソース

3. I18n::Backend::ActiveRecord::Missingの使用時

config/initializers/i18n_active_record.rb

# I18n::Backend::Chain.send(:include, I18n::Backend::ActiveRecord::Missing)
# I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n::Backend::Simple.new)

↓コメントアウトを外す

I18n::Backend::Chain.send(:include, I18n::Backend::ActiveRecord::Missing)
I18n.backend = I18n::Backend::Chain.new(I18n::Backend::ActiveRecord.new, I18n::Backend::Simple.new)
$ bundle exec rails c

[1] pry(main)>  I18n.t('user.name', name: 'なまえ', append: 'です')
=> "translation missing: ja.user.name"

[2] pry(main)> Translation.last
=> #<...Translation... id: 1, locale: :ja, key: 'user.name', value: nil, interpolations: [:name, :append], ....

DBに入っていないものを参照したときにレコードが自動的に作られる。
interpolationsカラムにその時の引数の名前が入る。

注意事項

このままではI18n.tを呼ぶたびに毎回DBアクセスが走るのでキャッシュを使用する方法も次回記述します。
次回の記事

【Rails】I18nの言語データをDBから取得 / キャッシュ使用【i18n/i18n-active_record】

0

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

前回「I18nの言語データをDBから取得」では毎回DBアクセスが走りパフォーマンスに不安があるためキャッシュを使用する方法を記述します。

前回の記事

3.config/initializers/i18n/cacheable.rbの作成

i18nのオープンクラスを使用

module I18n
  module Base
    def translate(*args)
      options  = args.last.is_a?(Hash) ? args.pop.dup : {}
      key      = args.shift
      backend  = config.backend
      locale   = options.delete(:locale) || config.locale
      handling = options.delete(:throw) && :throw || options.delete(:raise) && :raise # TODO: deprecate :raise
      translate_result(key, backend, locale, handling, options)
    end
    alias t translate

    def translate_result(key, backend, locale, handling, options)
      cache_key = translate_cache_key(locale, key, options)
      # キャッシュから取得orキャッシュを作成
      Rails.cache.fetch(cache_key) do
        enforce_available_locales!(locale)
        result = catch(:exception) do
          if key.is_a?(Array)
            key.map { |k| backend.translate(locale, k, options) }
          else
            backend.translate(locale, key, options)
          end
        end
        result.is_a?(MissingTranslation) ? handle_exception(handling, result, locale, key, options) : result
      end
    end

    def translate_cache_key(locale, key, options = {})
      File.join(locale.to_s, key.to_s, options.presence.to_s)
    end
  end
end

3.config/initializers/translation/cacheable.rbの作成

レコードとキャッシュを一緒に作成、更新、削除する

Translation.class_eval do
  after_create :create_i18n_translate_cache
  after_destroy :delete_i18n_translate_cache
  after_update :reset_i18n_translate_cache

  private

  def create_i18n_translate_cache
    I18n.t(key, locale: locale) # 一回呼んでキャッシュ作成
  end

  def delete_i18n_translate_cache
    Rails.cache.delete(delete_cache_key)
  end

  def reset_i18n_translate_cache
    delete_i18n_translate_cache
    create_i18n_translate_cache
  end

  def delete_cache_key
    I18n.translate_cache_key(locale_was, key_was)
  end
end

【jQuery】開閉パネルを最初から開いた状態にする

0

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

Javascriptが苦手なWebデザイナーです。基礎的なことから学んでいる状態なので、簡単なことでもつまずいてしまうという方向けの内容です。

◆Javascript

$(function(){
  $(".toggle").show();
    $(".accordion dt").on("click", function() {
      $(this).next().slideToggle();
      $(this).toggleClass("active");
    });
    $(".accordion dt").mouseover(function(){
      $(this).addClass("over");   
      });
    $(".accordion dt").mouseout(function(){
      $(this).removeClass("over");    
  });
});

◆CSS

.accordion {
    clear: both;
    width: 100%;
    padding: 0;
}
/* dt */
.accordion dt {
    background: url(img/arrow.png) no-repeat 98% 50% #aab6ba;
    background-size: 15px;
    padding: 10px;
    color: #fff;
    cursor: pointer;
    margin: 0;
}
    .accordion dt.active {
        background-image: url(img/arrow.png);
    }
    .accordion dt.over {
        background-color: #c8cfd2;
    }
/* dd */
.accordion dd {
    width: 100%;
    border: 1px solid #aab6ba;
    box-sizing: border-box;
    padding: 10px;
    margin: 0;
}

◆html

<dl class="accordion">
  <dt>開閉スイッチ</dt>
  <dd>
    <ul class="toggle">
      <li>内容</li>
      <li>内容</li>
      <li>内容</li>
    </ul>
  </dd>
</dl>

解説
$(".toggle").show(); で最初は開いている状態にします。
.accordion dt をクリックすると、パネルが開閉するという仕組みになってます。


あとがき
最初から表示させつつ開閉バーをマウスオーバーしたら色が変わって矢印をくるってさせる方法がわからず解決までに時間がかかってしまったので、備忘がてらまとめました。
案件や要望によってコロコロとしようが変わるので、臨機応変に対応していく力が必要です。
Javascriptが苦手なWebデザイナーさんのお役に立てれば嬉しいです。


参考サイト
開閉パネルを最初から開いた状態にする

【超初心者向け】Javascriptの確認ダイアログを複数設置する方法

0

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

業務で複数の確認ダイアログを表示させたいことがあり、1つのhtml内に複数設置する方法がわからなかったので備忘します。 検索してもなかなか思った通りの解決方法が見つからず、試行錯誤の上、解決方法を発見しました。

javascript

function sample01() {
    if(window.confirm('サンプル1のコメントです。よろしいですか?')){
    }
}

function sample02() {
    if(window.confirm('サンプル2のコメントです。よろしいですか?')){
    }
}

function sample03() {
    if(window.confirm('サンプル3のコメントです。よろしいですか?')){
    }
}

html

<head>
  <script src="sample.js"></script>
  <script src="jquery.js"></script>
</head>

<body>
  <a onClick="sample01" href="#">サンプル1リンク</a>
  <a onClick="sample02" href="#">サンプル2リンク</a>
  <a onClick="sample03" href="#">サンプル3リンク</a>
</body>

解説
確認ダイアログで表示されるコメントを記述したjavascriptファイルを、html内の <head> ~ </head> 内に記載します。(ここではsample.jsとします。)
javascriptの sample01 とhtmlに記載する onClick="sample01" を同じ名前にすることがポイントです。
たったこれだけで、1つのhtml内に複数の確認ダイアログを設置することが可能です。


あとがき
この方法がもうわからず、数ヶ月後に謎が解けました。
謎が解けてみると簡単ですが、わからない人にはわからないんです。
エンジニアさんはきっとこんなことで悩まないだろうけど、Javascript知識のないデザイナーにはこれだけでも一苦労なんです!

Webデザイナーの方で、Javascriptが得意ではなく、きっと同じような悩みを持った方がいると思うので、参考になればいいなと思います。


参考サイト
確認ダイアログを表示する


検証ブラウザ
Chrome / Firefox / Safari / Edge / IE10
※全て最新版

【レスポンシブ対応】CSSだけで三角矢印の見出しを作る方法

0

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

画像を使わずに、CSSだけでレスポンシブに対応した三角矢印の見出しを作る方法をご紹介します。

① 背景を塗りつぶした三角矢印の見出しを作る

サンプル
enter image description here

.title-01 {
    position: relative;
    background: #000;
    color: #fff;
    text-align: center;
    font-size: 24px;
    padding: 40px 0;
    margin: 0;
}
    /* 下三角 */ 
    .title-01:after {
        border: 30px solid transparent;
        border-top-color: #000;
        border-bottom-width: 0;
        bottom: -29px;
        content: "";
        display: block;
        left: 50%;
        position: absolute;
        width: 0;
    }

親となる要素にposition: relative;を付与します。
三角形となる要素にafter擬似要素を追加しposition: absolute;を付与します。

border: 30px solid transparent; の部分で三角形の大きさを調整します。
bottom: -30px; で三角形の位置を調整します。border: 30px solid transparent; よりも大きい数値の場合、三角形の位置が離れます。
left: 50%; はレスポンシブにしても常に中央に表示されます。

親要素にデザインcssを追加・変更できます。
paddingmarginなどは、用途に合わせて追加してください。


② 三角矢印だけのシンプルな見出しを作る

サンプル
enter image description here

.title-02 {
    position: relative;
    color: #000;
    text-align: center;
    font-size: 24px;
    padding: 30px 0;
    margin: 0;
}
    /* 下三角 */ 
    .title-01:after {
        border: 20px solid transparent;
        border-top-color: #000;
        border-bottom-width: 0;
        bottom: 0;
        content: "";
        display: block;
        left: 50%;
        position: absolute;
        width: 0;
    }

①の応用辺です。
親要素を背景色と同じにして、三角矢印だけ残したシンプルなデザインです。

親要素にデザインcssを追加・変更できます。
paddingmarginなどは、用途に合わせて追加してください。


③ 下線と三角矢印の見出しを作る

サンプル
enter image description here

.title-03 {
    position: relative;
    border-bottom: 2px solid #000;
    color: #000;
    text-align: center;
    font-size: 24px;
    padding: 30px 0 10px;
    margin: 0;
}
    /* 下三角 */ 
    .title-01:after {
        border: 25px solid transparent;
        border-top-color: #000;
        border-bottom-width: 0;
        bottom: 0;
        content: "";
        display: block;
        left: 50%;
        position: absolute;
        width: 0;
    }

border-bottom: 2px solid #000; の solid 部分を dotted や dashed にすると、点線や破線が作れます。border-styleの詳細はこちら。

親要素にデザインcssを追加・変更できます。
paddingmarginなどは、用途に合わせて追加してください。


④ 三角矢印の見出しを線だけで作る

サンプル
enter image description here

.title-04 {
    position: relative;
    border-bottom: 2px solid #000;
    background: #fff;
    color: #000;
    text-align: center;
    font-size: 24px;
    padding: 30px 0 10px;
    margin: 0;
}
    /* 下三角 */ 
    .title-04:before{
        content: "";
        position: absolute;
        bottom: -44px;
        left: 50%;
        margin-left: -2px;
        border: 22px solid transparent;
        border-top: 22px solid #fff;
        z-index: 2;
    }
    .title-04:after {
        position: absolute;
        border: 24px solid transparent;
        border-top-color: #000;
        border-bottom-width: 0;
        bottom: -25px;
        content: "";
        left: 50%;
        z-index: 1;
    }

①〜③の応用ですが、こちらでは三角要素にbefore擬似要素を追加します。
親要素のborder-bottom: 2px solid #000;で線の太さや色を指定しています。
before擬似要素のborder:border-top:の数値を同じ値にし、それらの倍数をbottomにマイナス数値で指定、after擬似要素のborder:を「before擬似要素で設定した数値」−「親要素で設定した数値」の値にすると、線の太さが均一になります。
after擬似要素のbottom:はafter擬似要素のborder:から−1を指定していますが、線の太さによって微調整が必要です。

親要素にデザインcssを追加・変更できます。
サンプルでは線の太さを2pxにしてますが、線の太さと色は自由にカスタマイズ可能です。
paddingmarginなどは、用途に合わせて追加してください。


あとがき

Webサイト制作の業務で「見出しにインパクトがない」とよく言われるので、使いやすい三角矢印の見出しを自分のWebデザイン制作の備忘に書きました。
デザインcssのカスタマイズが可能なので、Webデザイナーのみなさまのお役に立てると幸いです。


参考サイト

【CSS】CSSのみで三角と矢印を作る方法
画像を使わず、CSSで吹き出しを作る


検証ブラウザ
Chrome / Firefox / Safari / Edge / IE10
※全て最新版

[GCP] Cloud BuildでGKEのデプロイ by Slack

0

Information

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

Cloud BuildでGKEのデプロイ

Cloud BuildでGAE/Goデプロイ by Slack の番外編として、Cloud Build を使ってGKE(Google Kubernetes Engine)にデプロイをする設定を実施してみたいと思います。

アプリのコードはこちらです。アプリ自体はGo言語のWebアプリケーションフレームワークGinのQuick Startを少し改変したものです。

[GCP] GAEのエッジキャッシュ利用時の落とし穴

0

Information

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

TL;DR

GAEのエッジキャッシュを利用する時は課金を有効にしましょう。

Google App Engine

みなさん、Goolge App Engineをお使いでしょうか。

Cloud BuildでGAE/Goデプロイ by Slack vol.4

0

Information

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

前回 Cloud BuildでGAE/Goデプロイ by Slack vol.3

Cloud BuildでGAE/Goのデプロイ

Cloud BuildでGAE/Goデプロイ by Slack vol.4ということで、
今回はCloud BuildでGAE/Goをデプロイする設定を行います。

といっても、
ここまでの設定ができていれば、
デプロイ自体はgcloudコマンドを使えば、コマンド一発で済むので難しいことはありません。

では、早速やってみましょう。

Cloud BuildでGAE/Goデプロイ by Slack vol.3

0

Information

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

前回 Cloud BuildでGAE/Goデプロイ by Slack vol.2

Cloud Source RepositoriesのコミットとCloud Buildとの連携

Cloud BuildでGAE/Goデプロイ by Slack vol.3ということで、
今回はCloud Buildをフックする部分について、実施したいと思います。

前回までで、Cloud Source Repositoriesへのマージの連携までできていますので、
このマージをフックしてCloud Build を起動する流れとなります。

Cloud BuildでGAE/Goデプロイ by Slack vol.2

0

前回 Cloud BuildでGAE/Goデプロイ by Slack vol.1

Information

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

SlackとBitBucketの連携

Cloud BuildでGAE/Goデプロイ by Slack vol.2ということで、
今回はSlackとBitBucketとCloud Source Repositoryを連携する設定を行いたいと思います。
(BitBucketのアカウント、およびリポジトリはすでに存在する前提で話を進めます)

最近人気な記事