ホーム ブログ ページ 19

味噌カツで例えるソーシャルゲームのサーバーサイドにおける新規実装の流れ 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のアカウント、およびリポジトリはすでに存在する前提で話を進めます)

Angular と cordovaでアプリを作ってみる

0

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

スマホアプリはJavaやObjective-Cなどでごりごり書くのが最もスタンダードな方法ですが、HTMLからアプリを生成してくれるフレームワークを使うハイブリッドアプリと呼ばれる方法もあります。 Angular と Cordova からアプリの機能を提供する機会があったので、まとめます。

開発環境

CordovaとAngular CLIのインストール

npm install @angular/cli --save
npm install cordova --save

npmパッケージをローカルのnode_modules以下にインストールしています。
グローバルを汚してもよい方は -g オプションでどうぞ。

Cordovaプロジェクトの作成

npx cordova create bibioapp

同じフォルダに bibioapp が作成されます。
このままアプリを作成することも可能ですが、今回はAngularのアプリを作成をすすめます。

npx は、ローカルにいれたnpm パッケージのコマンドを実行するコマンドです

Angularプロジェクトで上書きする

はじめに、www 以下とpackage.jsonを待避します

mv bibioapp/www bibioapp/www.bak
mv bibioapp/package.json bibioapp/package.json.bak
npx ng new bibioapp

Angularアプリを起動する

デフォルトで使用するブラウザで開きます。

cd bibioapp
npx ng serve --open
enter image description here

Angularをビルドする設定

Cordovaでビルドできるように angular.json を編集します。
(5から6になって、ファイル名がかわりました。Angular は設定がころころ変わりますね)
outputPath を www に変更します。

      "architect": {
        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
             "outputPath": "www",
             "index": "src/index.html",
             "main": "src/main.ts",

ビルドを実行します

npx ng build

www 以下にbundleされたhtml,css,jsが出力されます。

index.htmlを書き換える

src/index.html がビュー側のエントリポイントとなります。
Angularアプリを作成する前にとったバックアップから必要なタグを追加します

変更点を列挙していきます。

Baseタグは.からの相対パスに変更します。

<base href="./">

Content-Security-Policy を追加する

<meta http-equiv="Content-Security-Policy" content="default-src 'self' data: gap: https://ssl.gstatic.com 'unsafe-eval'; style-src 'self' 'unsafe-inline'; media-src *; img-src 'self' data: content:;">

view port を変更する

<meta name="viewport" content="user-scalable=no, initial-scale=1, maximum-scale=1, minimum-scale=1, width=device-width">

bodyに cordova.js のscriptタグを追加する

<script type="text/javascript" src="cordova.js"></script>

config.xml を編集する

widget要素 の id 属性がパッケージ名になるので、適当に変更する。
今回は com.example.bibioapp にしました。

プラットフォームの追加

Android を追加します。

npx cordova platform add android@6.4.0

なお、パッケージ名を書き換えた場合は、一度削除してから再度追加しましょう。

npx cordova platform remove android

SDKとエミュレータの追加

Android Studioを起動し、アプリルート/platforms/android を開きます。

SDKを追加します。
Tools > SDK Manager を選択し、SDK Platforms タブから Android 8.1(API Level27)を選択します。

その後、エミュレータを追加します。

AVD Managerを起動して、エミュレータを追加します。

Android Studio のメニューバー Toolsから AVD Managerを起動します。

Create Virtual Deviceボタンをクリックし、Nexus 5Xを選択しNextをクリック、Oreo(API Level27)をDownloadしたあとに Nextをクリック、最後に内容を確認したあとに Finishをクリックします。

その後、エミュレータを起動します。

エミュレータで起動する

npx cordova emulate android

ビルドが開始され、しばらくするとアプリが起動します。

enter image description here

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

0

Information

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

自動的にデプロイ

どんなアプリケーションであれ、
世の中に価値を提供するためには、デプロイメントを行う必要があります。

そして、
アプリケーションを一度作ったら終わりということは稀で、
継続的に、かつ頻繁に改修を加えていくことが多いので、
必然的にデプロイも継続的に、かつ頻繁に行うことになります。

いわゆるCI/CDですね。

casperjs のスクリプトを crontab で実行する

0

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

JavascriptでレンダーされるWebページの特定部分の情報を取ってくるみたいなことをするとき casperjs を使ったスクリプトが便利だけれど、cron実行しようとしたところ思うように動くまでに手こずったのでメモ。

環境

$ uname -mprsv
Darwin 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64 i386
$ node -v
v10.7.0
$ phantomjs --version
2.1.1
$ casperjs --version
1.1.4
$ python --version
Python 2.7.15

スクリプト

$ cat /Users/kadosawa/bin/doruby

#!/usr/bin/env casperjs

var url = "https://doruby.jp/";
var casper = require('casper').create();

casper.start(url, function() {
  var that = this;
  var title = casper.evaluate(function() {
    return $('#newest-entries div.entry').first().text();
  });
  this.echo(new Date + ' ' + title);
}); //開始

casper.run();

crontab内容

PATH=$PATH:/usr/bin:/usr/local/bin
* * * * * /Users/kadosawa/bin/doruby >> /tmp/doruby.log.txt 2>&1

ポイント
crontab だと node や phantomjs や python やらのパスがなくてエラーになるのでPATH変数を設定してさしあげます。


  • 118 views

自分のファイル名を見て振る舞いを変えるシェルスクリプト

0

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


長いことsshコマンドの横着方法を検討しておりましたが「これでいいや」と思うことにしました。そこで使った小技を書きます。

linux を覚えたころ bashrc や bash_profile に alias xxx=’ssh -p 65522 -l loginu’ のようなことをしていました。.ssh/config を利用することで scp, rsync のときにオプションが落ちるという課題が解決されましたが、他のマシンに移動させるときや対象を増やすときの手数が少し多いことが課題でした。若干原始的ですが実行ファイルを作成する方法です。

環境

$ uname -mprsv
Darwin 17.7.0 Darwin Kernel Version 17.7.0: Thu Jun 21 22:53:14 PDT 2018; root:xnu-4570.71.2~1/RELEASE_X86_64 x86_64 i386
$ bash --version
GNU bash, version 4.4.12(1)-release (x86_64-apple-darwin16.4.0)
## 省略 ##

基礎:実行すると自身のファイル名を返すスクリプト

#!/bin/bash

basename $0

※ 適当な名前のファイルにして実行権限を与えておきます。

解説
$0 を呼び出すとコマンド名(ファイル名) が返されます。
パスも含まれる為 basename で脱がせます。ファイル名だけになります。

応用:ssh横着に役立てる

~/bin/localhost というパスのファイルを作成しました。

#!/bin/bash

timestamp=`date "+%y%m%d_%H%M%S"`$1
mkdir -p $HOME/sshlog
DST=`basename $0`
logfile="$HOME/sshlog/$USER.`uname -n`_to_$DST.$timestamp.log"
ssh $DST $* | tee $logfile
echo $logfile

所感

  • ln -s ~/bin/localhost ~/bin/サーバー名とすることで1回のコマンドで接続先を増やすことができます。.bashrc を書き換えて、source コマンドを実行してみたいにしなくてよいです。
  • 変数展開を利用すればより複雑なコマンドの実行もできそうです。
  • こういうスクリプトなどを書くことを想定してホストの命名規則やミドルウェアの構成が整理されているとスクリプトに例外用のコードを書く手間が省けます。

googlebotのレンダリングは古い。そして普通のブラウザとちょっと違う。

0

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

Googlebotでjavascriptが読み込める様になってきてはいますが、最新のjavascriptの機能には対応しておらず、chrome41で動いているようです(2018/7ではバージョン67)。そのためブラウザでは正常に表示されていてもgooglebotではエラーになり、javascriptが実行されない状態でキャッシュされてしまう可能性があるので注意です。ちなみにこのレンダリング機能のことをWebレンダリングサービス(WRS)と言うそうです。

chrome41のWRSでサポートされている機能、されていない機能は以下で確認できます。
●chrome41でサポートされている機能
https://www.chromestatus.com/features#milestone%3C%3D41
●chrome41でサポートされていない機能
https://www.chromestatus.com/features#milestone%3E41

個人的な感覚ではIEと同じような対応範囲です。逆にIEにjavascriptが対応していればgooglebotでも動くかなと思います。

また、googlebotはchrome41といってもブラウザの表示と全く同じではなく、

  • WebSQLやService Worker、WebGL
  • は無効 ローカルストレージやCookieはクリアされる
  • 許可が必要なものは許可しない(Notificationsなど)

などの違いがあります。

このようにブラウザの表示と違いがあるため、googlebotがどのようにページを取得しているかちゃんと確認する必要があります。

search consoleの
・Fetch as Google
https://www.google.com/webmasters/tools/googlebot-fetch
・(スマホの場合)モバイルフレンドリーテスト
https://search.google.com/test/mobile-friendly
などで確認でき、エラーがあった場合もエラー内容が返却されるためわかりやすいです。

javascriptで画面を作成した後は、googlebotで正常に動くか確かめた方がよいかもしれません。

最近人気な記事