ユニファ開発者ブログ

ユニファ株式会社プロダクトデベロップメント本部メンバーによるブログです。

僕がアドベントカレンダーに込める思い

こんにちは。スクラムマスターの渡部です。

いよいよこの季節がやってまいりました!!!!!

そう、イルミネーションの季節ですね*1!!!!!!!!!(そうだけどそうじゃない)

そう、アドベントカレンダーの季節ですね。

この記事は、UniFaアドベントカレンダー 1日目の記事となっております。

ユニファではみんなの協力のおかげで、去年に引き続き今年も無事開催することができました。

ちなみに去年のカレンダーはこちら

UniFa Advent Calendar 2019 - Adventar

第1発目は何を書こうかと考えたのですが、せっかく(?)なので、僕がアドベントカレンダーに込める思いをつらつらと綴ろうと思います。

予めご理解いただきたいのは、今回のブログタイトルの主語は僕であり、今回のお話はあくまで僕個人が思っていることであるということです。

  • お祭りだから書きたい!!!
  • たまたま書こうと思ったタイミングがアドベントカレンダーだったんだ。
  • え、特に意識せず書いてるだけだよ?
  • 会社の雰囲気を知ってもらうため!

などなど、いろんな思いや理由があると思いますが、それと同じもので、ただアドベントカレンダーの1日目の記事にあたった、というだけです。

はじめに 〜むかしばなし〜

(ちょっと長いので、本題に入りたい方はこの章は飛ばしていただいて構いません)

僕は、チームで働くことが好きです。

なぜ好きかというと、それが楽しいからです。

*1:余談ですが、僕はイルミネーションに目がありません。メジャーだけど意外と知られていないことに関東3大イルミネーションがありますが、このチョイスは本当に素晴らしいものです。それぞれのイルミネーションは、同じイルミネーションではありますが、全く趣向の異なるイルミネーションですので、どれも違った楽しみができます。その話はまたどこかで…

続きを読む

SQS + Shoryukenのメッセージ重複配信問題にMiddlewareで対応する

まだ鍋シーズン序盤だというのに、ごま豆乳鍋を3日に1回は食べているWebエンジニアの本間です。

最近、Railsアプリケーションのバックグラウンドジョブのworkerとして Amazon SQS, Shoryuken, Active Job を組み合わせて使うことが増えました。 過去にも以下のようなエントリを書いてます。

tech.unifa-e.com

今回は、Shoryukenを使ったバックグラウンド処理を実運用で使用するにあたって1つ悩ましい問題があり、それをMiddlewareを使って解決した話をご紹介します。

続きを読む

心理的安全性がもたらす効果と、安全性を阻害するBadパターン

こんにちは。スクラムマスターの渡部です。

最近出版された「心理的安全性のつくりかた*1」という本が、発売から2ヶ月経たずに4版決まった*2り、Tech系カンファレンスでも心理的安全性についてのセッションがあって*3かなり盛り上がったりと、心理的安全性機運の高まりを感じている昨今です。

当然(?)ながら僕も「心理的安全性のつくりかた」を読んで、短期的にも長期的にも今後のふるまいを見直す良いきっかけになりました。

ただ、いかんせん「心理的安全性ってわかりにくい言葉だなぁ」という感想は今でも変わっていないので、備忘的な意味で次の2つのことをブログに残したいと思います。

このブログで扱うこと

  • そもそも、心理的安全性ってなに?どんな効果があるの?
  • 心理的安全性を阻害するBadパターン

このブログで扱わないこと

  • 心理的安全性を構成する4つの因子の詳細
  • いかにして心理的安全性を高めていくか?

これらは書籍「心理的安全性のつくりかた」を参照していただくか、どこか別の機会で「ユニファにおける取り組み」などをご紹介できればいいかなぁと思っています。

心理的安全性について

そもそも、心理的安全性とは何か?

心理的安全性は、Google の調査結果によってビジネスの世界で一気に広まった概念です。(Googleが定義したものではありません)

rework.withgoogle.com

本来の定義としては「チームの中で、対人関係におけるリスクをとっても大丈夫だ、というチームメンバーに共有される信念のこと*4」とされています。

若干難しいので、本の中で紹介されてる次の考え方がわかりやすくて僕も好きです。

一言でいうと「メンバー同士が健全に意見を戦わせ、生産的で良い仕事をすることに力を注げるチーム・職場のこと*5

心理的安全性の効果

定義はなんとなくわかりましたが、結局、それがあることでどんな効果があるのかがわからないと、興味もわかないですよね。

Googleによれば、以下の説明がありました。

  • 効果的なチームには、心理的安全性を含む5つの因子が関係していた
  • 心理的安全性は、他の因子の土台となるために圧倒的に重要だった
  • 心理的安全性が高いチームには、以下の特徴があった
    • 離職率が低かった
    • 収益性が高かった
    • 「効果的に働く」とマネージャーから評価される機会が2倍あった

「ふむふむなるほど、心理的安全性があると効果的に働けるんだな!」ということはざっくりわかりますね。

ただ、どんな理屈で効果的に働けるのか?はまだちょっとわかりにくいですよね。

それについて、「心理的安全性のつくりかた」では、以下のように解説されていました。

心理的安全性が効果的な主な理由
  • 心理的安全性があることにより、チーム内で情報が積極的に共有されるようになったり、意見の衝突頻度が増えるようになる。それによりチームが学習していくことで、パフォーマンス向上へ繋がる。
  • 心理的安全性があることにより、タスクにおいて意見の衝突が起こるようになる。(いまやるべき?その方法だとこんな問題があるよ。etc)その結果、イノベーションやプロセス刷新が促され、パフォーマンス向上へ繋がる。

心理的安全性は、チームや組織の学習や、イノベーション・プロセス刷新に寄与することで、最終的にパフォーマンス向上に繋がるということです。

「どうにかしてパフォーマンスを向上させていきたい」という場合には、心理的安全性向上を視野に入れてみるのも良さそうです。

ただ、「学習は、心理的安全性の状況に依らず、普段の業務の中で個人が各々見出していくべきもの」または「学習は、業務とは切り離してプライベートでするべきもの」という考えですと、あまりピンとこないかもしれません。

心理的安全性についてのよくある誤解

ここまで、「心理的安全性とは何か?」「どんな効果があるのか?」について触れてきましたが、その言葉が持つイメージからか、誤解されて広まってしまっているのも事実です。

ここでは念の為、よくありそうな誤解をいくつか紹介しておこうと思います。

誤解①:くだらない話もできて仲が良いから心理的安全性は高いよ!

話しやすい状態のように思われますので、良いチームなのは間違い無いでしょう。

そのチームの中で、「このタスクって本当に必要なんだっけ?」「この進め方が一番良いんだっけ?」「勉強会でこんなアイデアを知ったんだけど、試しに1~2週間試しにやってみない?失敗するかもだけど」的な会話を、変に思われる心配なく繰り広げられていたら、間違いなく心理的安全性の高いチームです。

逆に、雑談はしているし、チャットも和気あいあいとしているけど、上記のような話し合いができていなかったり、あえて議論を避けているようなふしがあるとすれば、心理的安全性は低い状態だと言えます。

誤解②:アイデアを募るとたくさん出てくるから心理的安全性は高いよ!(最終的な決定事項には納得していない人がいて、成果も出にくい状態)

こちらも、「そもそも発言や提案がされない状態」ではないので、良いチームではあるでしょう。

ただ、本当に心理的安全性が高いのであれば、「決定事項に対して、自分はまだこんなところがわかっていない」などの発言が出てくるようにも思えますので、納得していない人が多い状態なのであれば、やはり心理的安全性は低い状態だと言えるでしょう。

リスクの無い発言や提案ができるかどうかではなく、リスクのある行動を、心配することなくとれるかどうかがポイントです。

誤解③:いつも特定の人は臆することなく発言してくれているから心理的安全性は高いよ!

人によってはそんな人も当然いますが、それだけでは判断できません。

そもそも、そのチーム内の人であれば誰しもが、勇気なんて持たなくても行動できる状態が、心理的に安全な状態です。

ですので、一部の人が勇気を振り絞って行動してくれている状態は寧ろ、勇気を出す必要がある程度には、心理的な危険が潜んでいる状況なのでしょう。

誤解④:「なんでも話して良いよ」と言っているから心理的安全性は高いよ!

マネージャーからそのようにコミュニケーションを取ること自体は重要なことです。

が、それを言っている = 心理的安全性が高い という訳ではありません。

誤解についてパッと浮かぶところはこんな感じでしょうか。

そもそもなぜ誤解が広まってしまったのかについては、正確な情報は辿れていないので定かではないのですが、「安全」と「安心」の意味が日本では混同されてしまっているからではないか?という説があるようです。

そう考えると確かに誤解にも納得がいきますね。

もし、誤解が広まっている経緯について詳しい方がいましたら、是非コメントなどでお知らせいただけると大変うれしいです。

心理的安全性の4つの因子

この章では、今後の話のために、書籍で紹介されていた「心理的安全性の4つの因子」について、概要だけ触れておきたいと思います。

本当にさらっとだけ触れるので、詳しく知りたい方は書籍を参照していただくのが良いです。

書籍によると、日本においては、次の4つの因子が満たされているとき、心理的安全性が高いと感じられるとあります。

  • ① 話しやすさ因子
    • 話す、話を聞く、相づちを打つ、雑談するetc
  • ② 助け合い因子
    • 相談する、相談にのる、自分一人では対応できないと認める、チームの成果を考えるetc
  • ③ 挑戦因子
    • 挑戦する、機会を与える、新しいことをする、失敗を歓迎するetc
  • ④ 新奇歓迎因子
    • 個性を発揮する、強みに応じて役割を与える、違いをただ違いとして認めるetc

次の章では、それらの因子(と、因子に紐づく行動)を阻害してしまっている、よくありそうだなぁと思うパターンを紹介していきます。

本当であれば、「じゃあどんな言動が良いだろうか?その理由は?」まで書こうかと思っていたのですが、大長編になって大変なので、今回は割愛しています…

心理的安全性を阻害するBadパターン

「話しやすさ因子」を阻害すること

  • 相手の目を見て話をきかない。
  • 相手の話しに相づちを打たない。
  • 雑談しない。認めない。
  • 悪い報告があったとき、ミスを責める。
  • 課題に思っていることや問題を報告したとき、「じゃあ、◯◯さんやっといて」と戻ってくる。
  • 何かに付けてすぐ怒鳴る、大声を出す。
  • 提案時、資料の些細なミスをあげつらう。
  • 反対意見が出てきたとき、「いやそれは〜」「でもさぁ〜」とすぐに抵抗する。
  • わからないことを質問したとき「自分で考えた?」「わからないの?」「前も教えたよね?」と言う。
  • 会議で、ちょっとした思いつきが発言されたとき、上司やマネージャーから冷たくあしらわれる。

「自分の話に興味を持ってくれてないな〜」「忙しいんだろうな〜」と思わせてしまったら、当然「本当に重要なこと以外は話さなくていいかなぁ〜」と思ってしまいますよね。

また、報告した結果責められれば、例え本当に100%その部下のミスが原因だったとしても(実際にはそんなことはあり得ないと思いますが)、報告する = 自分にとって損 という構図を学習してしまいます。

課題の提案も同様です。良かれと思って発言や行動を起こしても、自分の負担が増えるだけで、更にはそこで失敗して責められでもしたら、発言せず静観しているのが一番得な行動になってしまいます。

重要なことは、業務に関してでも、業務と関係無いことでも、「話す」という行動を積極的に推奨すること、「行動」と「行動の内容」をしっかり分けてフィードバックすることでしょう。(発言してくれた行為そのものは、どのような内容であれ、歓迎したいことのはずです)

「助け合い因子」を阻害すること

  • 何か問題が起きたり、失敗したときに、「誰のせい?」と犯人探しをする。
  • 評価は全て減点主義。
  • 相談をするために、厳格なルールが定められているなど、相談に対するハードルが高い。
  • 相談を持ちかけられたとき、嫌な顔をしたり、時間が無いことを理由に断ったりする。
  • 与えられた仕事は◯◯という役割の人が責任を持って一人で遂行するべき、という風潮、仕組みにしてしまう。
  • 個人としての成果のみを重視して、チーム全体としての成果を考えない。

減点主義や、それに近い雰囲気が漂っていると、できるだけ減点される要素を減らそうと考えますよね。そうなれば当然、自分が組織から明確にアサインされた仕事以外に手を広げることは、純粋なリスクになります。

ちょっと困ってるから相談したいけど、そのためには何らかのルールに則って行う必要があったり、「相談は相手の時間を奪う行為である」という風潮になっていれば、その場合もやはり「仕方ない、みんなのことを思って、みんなに迷惑を掛けないために自分ひとりでなんとかするか…」と思ってしまいます。 相談のアクションに対する反応がネガティブだった場合も同様です。

また、組織として「◯◯(ある作業)は△△(役割名)が担うべし」という決まりも、それだけが表にでてしまうと、当然のことながらその枠内だけを努力しようとするでしょう。

「マネジメントコストを減らすこと」だけにフォーカスすれば、個人は決められた仕事だけをやる仕組みにした方が管理がしやすいのは間違い無いと思いますが、その管理をなんのためにするのか?そしてそれは果たしてマネジメントしていると言えるのか?を考えることが重要かもしれません。

「挑戦因子」を阻害すること

  • 何かアイデアを持ちかけたとき、「それ、本当にうまくいくの?効果あるの?」と問い返す。
  • 「これまでやったこと無いから」「今と違うから」という理由でNGを出す。
  • ちょっと非現実的のように思える提案に対して、即「いや、うちの会社(うちのチーム、いまの状況)では無理だよ、合わない」と返す。
  • 企画自体は会社に承認されたものだが、実際やってみて失敗したら、実行者の評価に影響が出る。
  • 極端に失敗を避けようとする。

そもそも新しいことにチャレンジしようとするとき、書籍やカンファレンス、ネットなどである程度の情報は仕入れることができますが、100%上手くいく保証なんてどこにもありません。

「上手くいくかもしれないし、失敗するかもしれない。」というのはある程度仕方の無いことですので、「本当に上手くいくか?」と問われれば「わからない」と言う他ありません。

完璧を求められるのであれば、やはりリスクを伴ったチャレンジは受け入れられないんだ…と学習していき、何も変えることのできない環境になっていくでしょう。

ここで重要なのは、短期ばかりに目を向けるのではなく、長期を見据えてある程度の失敗リスクは許容してでも成長していけるチーム・組織としての目標を業務として設定することと、仮に失敗したとしてもリスクを最小限に抑えられるよう、小さな挑戦を推奨することのように思います。

「新奇歓迎因子」を阻害すること

  • 強みや個性をいかすのではなく、決められたら役割のなかで当てはめる
  • 同じ考えの人だけでまとめる。そのような人選をする。(特に経営陣でそのような状態はよろしく無いようです)
  • 人を、一律に扱うマネジメントをする。
  • 採用において、意識して多様性を取り込もうとしない。

VUCAの時代(変動が激しく、不確実性が高く、複雑で、曖昧な時代)に、チームや組織として競争力を保ち続けるためには、個々の多様性を尊重して強みを掛け算し、それを全体として一つの方向にマネジメントしていく必要があるとのことです。

ですが、「◯◯という役割であれば、全員が同じようにこの作業をするべし」とされてしまうと、弱みをカバーしあいながら、強みを活かすことができません。

また、組織のほとんどが同質で構成されていると、異質な価値観の人は自分の声に重要性を感じなくなり、組織に所属している感覚も薄れるそうです。

チームや組織としては、同質でない人も声をあげやすくなるよう配慮することと、意識的に多様性を取り入れていくこと、そして、そもそものところで、個々の価値観をお互いが知ろうとすること*6から始める必要があるのかもしれません。

おわり

以上となりますが、「それって違うのでは?」というご指摘や、「こんな言動もあるよね〜」などあれば、ぜひお知らせいただけると助かります。

今回は、心理的安全性そのものと、よくありそうなBadパターンのみの紹介でしたが、「心理的安全性のつくりかた」では、4つの因子の詳細な解説から、「心理的安全性を高めるためにはどのようなリーダーシップが求められるのか?」「行動分析学にそって、いかにして心理的安全性を高めていくか?」などがわかりやすく書かれています。

もし、この記事を読んでちょっとでも興味が湧いた方は、ブログ末に書籍へのリンクがあるので、購入して読んでみても良いかもしれません。

比較的読みやすい文体と、内容もわかりやすく説明されているので、早いひとなら2~3日で読めると思います。(僕は遅いので2週間くらいかかりましたが…)

…と、あまり「ユニファ」要素がほぼ無い記事でしたが、楽しんでいただけたら幸いです。

そして、共に心理的安全性の高いチーム・組織を作ろうという熱い思いのある方は、是非一緒に働きましょう!!!

それではまた次回。

unifa-e.com

*1:https://www.amazon.co.jp/dp/4820728245www.amazon.co.jp

*2:

*3: speakerdeck.com

*4:https://web.mit.edu/curhan/www/docs/Articles/15341_Readings/Group_Performance/Edmondson%20Psychological%20safety.pdf

*5:心理的安全性のつくりかた p22

*6:チーム内でお互いの価値観を知っていく方法としては、アジャイルサムライで紹介されているドラッカー風エクササイズ(リンクは別のブログ)がおすすめです。社内の方であれば渡部までご相談いただければ嬉々としてファシリに伺います!tech.pepabo.com

ユニファのエンジニアの業務領域とは?

こんにちは。 ユニファのエンジニアマネージャーの田渕です。

気づけば今年も、残り二ヶ月になってしまいました! コロナの影響などもあり、ハロウィンも例年ほどにお祭り騒ぎにはならなかったので、落ち始めた気温と乾燥した空気で季節を感じています。。。

各種媒体や弊社コーポレートサイトでも掲載しているように、現在ユニファでは技術職を盛大に募集しています! 過去にも何度か採用関連のお話を書いたことがありますが、今回は「ユニファのサービス開発のエンジニアって何してるの?」の最新状況を、これまでに掲載された記事の内容と合わせて書いてみたいと思います。

参考:過去の採用関連記事 tech.unifa-e.com

一口に「サーバーサイドエンジニア」と言っても色々ある

私自身がサーバーサイドエンジニアなので、差し当たりサーバーサイドエンジニアを例にとってお話を進めます。 外部コミュニティに参加したり、あるいは同業他社に知り合い/友人が居るエンジニアの方なら、一度は感じたことがあるかもしれません。

「同じサーバーサイドエンジニアでも、会社によって仕事の内容結構違うな。」

そうなんです。 一口に「サーバーサイドエンジニア」と言っても、その仕事内容や仕事の範囲は会社規模や扱う製品、サービスによってまちまちです。 「プログラムを書くこと」が役割のケースもあれば、「要件をまとめること」「顧客と話をすること」とか「インフラ構成を考えること」「モバイルのアプリを書くこと」までもその仕事の範囲に含んでいるケースもあります。 これはエンジニアに限った話ではなく、どの職種に於いても言える話だと思います。

そしてそのことが、時々起こる「転職者と会社のミスマッチ」の原因にもなります。 それ故に、ユニファの採用活動ではそのミスマッチを防ぐため、極力応募者の方と面接の段階で業務内容や範囲、期待する役割のイメージ合わせをさせて頂くようにしています。

ユニファのエンジニアの業務範囲

かつて(と言っても5年前。。。)は正社員エンジニアが片手で数えられるほどしかいなかった弊社ですが、今では海外メンバーも合わせ多数のメンバーが参画してくれています。 昔は要件の取りまとめなども含めてエンジニアが広くやっていましたが、今はプロダクトマネージャーやディレクターが居るため、その部分はそちらのメンバーにお任せするなど、役割も少しずつ変わってきています。 そんな中で、現在のユニファのエンジニアの業務範囲ってどんな感じなんだろう?と言うことを、現時点の情報として書いてみたいと思います。

サーバーサイドエンジニア

要件はPdM、ディレクターの方々がまとめてくださるため、基本的にはその内容に沿って開発を行っていく形になります。 また、画面設計/デザインについては、必要と判断したケースではデザイナーさんに作って頂いています。 要件決めの際にはもちろん技術的な実現性の考慮も必要となってくるため、要件検討段階でなんらかの形で検討に加わっています。

前回、赤沼がご紹介した午睡チェックのケースでは、大凡の要求定義の段階でシステム的な様々な課題(5分に一回一斉にデータが飛んでくるなど)が分かってきたため、早い段階からモバイルエンジニア、サーバーサイドエンジニア、インフラエンジニアが協力してアーキテクチャ設計を行っていました。 その後、運用が始まってからも、少しずつ改良を重ね現在の構成を作っています。

tech.unifa-e.com

大きな会社ですと、各社員の役割分担がかなり細分化されているため、例えばサーバーサイドのエンジニアが一切インフラの設計には携わらないケースもあります。 一方、弊社では技術検討段階でサーバーサイドエンジニアが実際にAWSの環境でテスト用の構成を作って試してみたり、「この仕組み使いたいんだけど」とインフラエンジニアに持ち込んで相談したりと、インフラ構築面にも比較的入り込んだ形で開発を進めています。

モバイルエンジニア

要件やデザインに関してはサーバーサイドエンジニアの項目で記載した通りです。 同様に、要件検討段階でももちろん検討に加わります。 モバイルエンジニアの提案により要件が大きく変わることもあり、「ただ言われたものを作る」と言う立場ではありません。 提供しているサービスの性質上、モバイルアプリは実際に保育士さんや保護者の方が一番目にする機会が多くなります。 その使い勝手や品質によって大きく利用者の満足度が変わるため、とても重要な役割をになっています。

モバイルのアプリはiOS/Androidでそれぞれにデザインのガイドラインがあり、それが各OSのバージョンアップなどに伴い少しずつ変わっていくなど、Webとは違った状況もあります。 また、それぞれに独特の「セオリー」や「トレンド」が存在し、それに追従した形での開発が求められます。 そのため、現在弊社ではモバイルのエンジニアが主導しモバイルアプリのデザインのガイドラインの輪読会を開催しています。 これを行うことで、企画や仕様検討段階で皆が想像するアプリや各種デザインのイメージを少しでも近くしようとしています。

インフラエンジニア

弊社はAWSを利用しているため、主としてAWS内の環境構築/管理を行っています。 前述した通り、サーバーサイドやモバイルのエンジニアから「この仕組み使いたい」と持ち込まれることも多々あるので、それらの相談を受け付けつつ、最終的な構成をどうするのかと言ったあたりを決めていきます。 ログ管理や監視周り、バックアップの計画/設定など、信頼されるシステム運用に欠かすことの出来ない大切な領域について担ってもらっています。 Terraformを利用した環境構築の自動化などにも取り組んでいます。 tech.unifa-e.com 提供するサービスが増えていくに連れて、インフラエンジニアが管理するサーバーが増えてきたため、現在はサーバーサイドエンジニアと一部業務の分担を計画しているところです。

でも、棲み分けは絶対ではない。

と言う感じで、ここまで長々書いた通り、各職種ごとに一応の棲み分けは存在します。 ただ、この棲み分けも、絶対ではありません。 どう言うことかと言えば、自分の主たる職種に近い領域については「はみ出して」仕事をすることが多々あります。 会社によってはサーバーサイドエンジニアが本番のインフラ設定を直接変更するなんてことは許されないケースもありますが、そう言うことも実施しています。 また、現在は募集条件の都合上「サーバーサイドエンジニア」「iOSエンジニア」「Andoroidエンジニア」と言う職種で募集をしていますが、「サーバーサイドエンジニアだからモバイルのコードを書いてはいけない」と言うことも実はありません。 ですので、募集要項職種にぴったりとハマらないケースであっても、十分にご活躍頂ける可能性があります。

もちろん、その時の開発計画などの兼ね合いもあるため、必ずしも希望通りのことが出来る訳ではありません。 ですが、状況が許す限りはご本人の志望を汲んだ形でお仕事がお願い出来るように考えています。

We are hiring!!!

そんな感じで、ユニファでは現在技術職を絶賛募集中です! 少しでもご興味をお持ちの方は、ぜひ一歩踏み出してみてください! unifa-e.com

ルクミー午睡チェックの Well-Architected なポイント

皆様こんにちは、ユニファ CTO の赤沼です。

もう1ヶ月以上前になってしまいますが、 AWS Startup Architecture of the Year Japan 2020 で優勝したことはこのブログにも書かせていただきました。

tech.unifa-e.com

ですが実際のアーキテクチャの内容についてはほとんど書いていなかったので、今回は改めてどのような点が Well-Architected であると評価されたのか、ピッチでアピールした内容を説明させていただきたいと思います。 ピッチで使用したスライドは下記に公開していますので、よろしければご覧ください。

www.slideshare.net

ピークタイムに合わせた Auto Scaling

f:id:akanuma-hiroaki:20201030000500p:plain

iPadから送信される午睡チェックデータを受け取るサーバサイドのRailsアプリケーションはEC2インスタンス上で稼働しています。ピークタイムはある程度特定されていますので、時間指定でオートスケールし、インスタンス数を増やして負荷に対応します。午睡チェックの開発開始当初は今ほどにコンテナ関連の環境が充実していなかったり、メンバーのナレッジ等の都合でコンテナ化はしませんでしたが、アクセスパターンがある程度読めて、急激なトラフィック増加の懸念もあまりないプロダクトであれば、EC2でも十分に安定的な運用ができますので、何でもコンテナ化するのではなく、それがどれぐらいメリットがあるのか、ビジネスに貢献するのかを考えてアーキテクチャを選定するのが良いかと思います。

Redis を使用した処理順番の担保

f:id:akanuma-hiroaki:20201030001149p:plain

サーバサイドで受け取ったセンサーデータは、後述するように SQS に格納され、Worker によって DynamoDB に格納されます。その際に Worker が複数の場合には SQS からデータが取り出される順番は保証されません。ただこのプロダクトにとっては処理順番も重要ですので、サーバサイドでデータを受け取るとまず Redis(ElastiCache) に午睡チェックシートの各セルのステータスをフラグ情報として書き込みます。そして Worker が SQS からデータを取り出した際には、そのフラグ情報を確認し、期待した通りのステータスになっていれば DynamoDB に書き込むことで、処理順番を担保するようにしています。

SQSを介した非同期処理によるDynamoDBへの書き込み

f:id:akanuma-hiroaki:20201030001722p:plain

このプロダクトのアクセス特性として、5分毎に数千施設の iPad アプリから一斉に午睡チェックシートのデータが送信されてくるという点があります。それをサーバサイドで直接 DynamoDB に書き込もうとすると、 DynamoDB のスケールが間に合わない、もしくはオンデマンドキャパシティーでオートスケールが間に合ったとしても、スパイクするアクセスパターンの最大値にフィットしてしまい、利用料金が高額になってしまうということになります。そこでデータを一度 SQS に格納し、Worker が非同期で順次処理していくようにすることで、安定的に処理をしていくと共に、キャパシティー値をリーズナブルな範囲に止めておくことができています。

また、Worker は EC2 インスタンスに相乗りしているため、オートスケールによって EC2 インスタンスが増えると Worker も増えるのですが、その場合にキャパシティーの設定値を超過しないように、 ElastiCache に DynamoDB のキャパシティーの設定値を登録しておき、各 Worker は起動時に自身の情報を ElastiCache に登録すると共に、稼働中の Worker の情報とキャパシティーの設定値を取得し、キャパシティーを超えないように書き込み速度を調整するようにしています。

DLQを使用した失敗データ対応

f:id:akanuma-hiroaki:20201030002943p:plain

SQS から取り出した午睡チェックデータが正しく処理されなかった場合、10回まではリトライされますが、10回処理に失敗したデータは DLQ(Dead Letter Queue)に格納され、エンジニアに通知が来るようになっています。エンジニアは通知を受けるとそのデータの内容を確認し、対応が必要であれば対応を行います。対応が必要ないデータは4日間DLQに格納されたままになると削除されます。

Design for Failure

f:id:akanuma-hiroaki:20201030003439p:plain

プロダクトの利用中に、ネットワーク障害等で iPad アプリがサーバに接続できなくなった場合に、既に午睡チェック業務が開始されている状態であれば午睡センサーと iPad アプリ間だけで最低限の午睡チェック業務が継続可能になっています。

セルラー回線使用によるネットワーク安定性の担保

f:id:akanuma-hiroaki:20201030003718p:plain

iPad アプリからサーバへの接続は、 SORACOM Air Sim によるセルラー回線を使用しています。これによって保育園の Wi-Fi 環境の有無や安定性に左右されることなく、安定的なネットワーク接続を提供することができます。

また、サービスの導入時に保育園側で Wi-Fi 接続の設定を行うのはハードルが高い場合も多いのですが、SORACOM Air Sim をセットし、アカウント登録も済ませた状態で iPad や午睡センサーをお届けすることで、箱から出したらそのまますぐにお使いいただくことができるようになっていますので、導入に対する保育園側のハードルを下げることにも役立っています。

まとめ(そして We are hiring!!)

以上がピッチの中でアピールさせていただいた、ルクミー午睡チェックの Well-Architected なポイントになります。アーキテクチャには絶対的な正解はなく、そのプロダクトの特性や制約、ビジネスメリットを考慮して適切な選択をしていくべきですが、ご紹介した内容が参考になれば幸いです。

そしてユニファでは、より良いプロダクトを提供するためのアーキテクチャ構成に挑戦したいインフラエンジニアの方を始めとして各種ポジションを絶賛募集中ですので、興味がありましたらぜひご連絡ください!!

www.wantedly.com

「価値の押しつけ」とならないように。

f:id:unifa_tech:20201010174141p:plain こんにちは、PdM(プロダクトマネージャー)の田嶋です。

プロダクト開発において、何を置いても大切なのは、顧客に「使われる」こと。そして、そのために顧客を「よく知る」ということ。
理想を求めるばかり、最近は基本を忘れかけていました。改めて思い出すためにもこのブログを書こうと思います。

これから新規事業に取り組まれる方にとっても、「使われる」を目指すペインの超入門編として参考にして頂ければ幸いです。
※特定の参考文献はなく、様々な知識の寄せ集めのため、別の理解があればぜひ教えてください。

続きを読む

強化学習で最強の打順を求める(前編)

こんにちは。機械学習やデータ分析に加えて最近インフラ周りにも入門して修行中の浅野です。新しいことにチャレンジするのは楽しいですね。新しいことといえば機械学習の中でも強化学習についてはなかなか手をつけられていなかったので、今回はその強化学習を使って何かを作ってみたいと思います。息子が野球をやっていることもあり、「シチュエーション別の打率データから最強の打順を求める」という課題設定にします。通常は解くべき課題に対して最適な解法を選択していくのが筋ですが、今は「理解を深めるために強化学習をオリジナルの課題に使ってみたい」というのがモチベーションなので、強化学習を使うのが適切か、そもそも解けるのか、といったところはあまり気にせず探索していきたいと思います。

長くなりそうなので次のように2回に分けてまとめていく予定です。

  • 前編:打率データの作成とシミュレーション環境の構築 ← いまココ
  • 後編:強化学習モデルの学習と評価

強化学習としての大まかな問題設定

強化学習では、ある環境においてエージェントが観測した状態をもとに行動を起こし、それによって得られる報酬の累積値を最大化するような行動指針を学習していきます。今回の課題では、9人の打者のシチュエーション(アウトカウントとランナーの有無)別の打率データがあるとき、ランダムな打順からスタートしてある二人の打順を入れ替えていき、得点力がなるべく大きくなるような打順を求める、という立て付けを考えています。強化学習の枠組みに照らし合わせると、打順が状態に対応し、打順の中で1組を入れ替えることが行動にあたります。報酬については、与えられた打順で各イニングの攻撃をシミュレートし、1試合(9イニング)で得られる総得点をもとに設計していくつもりです。まだこのモデル化が良いのかどうか定かではありませんが、この前編ではそれを検証する上で必要になってくる打率データの生成と得点シミュレーション部分の作成について書いていきます。後編ではそれをもとに実際に行動モデルを強化学習によって求めます。

打率データ

f:id:unifa_tech:20201005143500j:plain
高打率タイプの打者のランナー状況毎のアクション割合(ノーアウトの場合)

上図はある打者の状況別の打率を定義したものです。ランナーがいるほうが一般に打率が高くなりますが、この打者はランナー状況によってヒット(single), 2塁打(double)、3塁打(triple)、ホームラン(homerun)、犠打(sacrifice)、アウト(out)の割合は変化しない設定です。どんな状況においても35%の確率でシングルヒットを打ち、3%の確率で2塁打、3塁打とホームランは1%ずつです。犠打は行いません。1人の打者に対してこれをアウトカウントごとに定義します。それを9人分作成します。ノーアウトかワンアウトでランナーがいれば高確率で犠打を成功させる川相タイプ、満塁になると異常に打率があがる駒田タイプ、2塁打が多い立浪タイプなど、いろんなバリエーションの選手を用意します(例えが昭和ですね)。一般にツーアウトになると投手が有利なので打率を全般に下げたりするなどの調整も自由ですし、現実のデータを利用することも可能です。今回準備した9人のラインナップは下記のような感じです。

  1. リードオフマンタイプ:ランナーがいないときの出塁率が高い
  2. 川相タイプ:犠打の成功率が高い
  3. 高打率タイプ:どんな状況でも出塁率が高い
  4. 三冠王タイプ:長打も含めてとにかく打つ
  5. 駒田タイプ:満塁に強い
  6. 立浪タイプ:2塁打が多い
  7. ランスタイプ:打率が極端に低いがホームランだけは多い
  8. 守備の人: 全体的に打率が低い
  9. ジョーカータイプ:なぜかツーアウトになると打ちまくる

試合における得点数のシミュレーション

ある打順が与えられたとき、1回の先頭打者から1人ずつ上記で定めた打率データに基づいてアクションを選び、アクションに応じてアウトカウント/ランナー/得点をアップデートし、3アウトになったらイニングを終了させる。それを9イニング繰り返すことで、その打順で1試合でどれだけ得点することができたのか計算することができます。特に実装が難しい部分はありませんが、アクションに応じてランナーを進塁させたり得点を計算したりする部分は下記のようにビット演算にすることで多少すっきりと書けるので一応例を示しておきます。

def update(self, out, runner, action):
    if action == 'out':  # アウト
        out += 1
    elif action == 'sacrifice':  # 犠打:ランナーを1つ進塁(左シフト)してアウトカウントを1つ増やす
        runner = runner << 1
        out += 1            
    elif action == 'single':  # ヒット:ランナーを1つあるいは2つ進塁して1塁走者をおく(第0ビットをたてる)
        if random.random() > 0.5:
            runner = runner << 1
        else:
            runner = runner << 2
        runner = runner | 0b0001
    elif action == 'double':  # 2塁打: ランナーを2つあるいは3つ進塁して2塁走者をおく
        if random.random() > 0.5:
            runner = runner << 2
        else:
            runner = runner << 3                
        runner = runner | 0b0010
    elif action == 'tripple':  # 3塁打: ランナーを3つ進塁して3塁走者をおく
        runner = runner << 3
        runner = runner | 0b0100
    elif action == 'homerun':  # ホームラン: ランナーを4つ進塁し第3ビットをたてる
        runner = runner << 4
        runner = runner | 0b1000

    run, runner = self.get_score(runner)  # アクションの結果入った得点を計算
        
    return out, runner, run
    
def get_score(self, runner):
    run = bin(runner & 0b1111000).count('1')  # 第3ビット以上で1がたっているビット数が得点
    runner = runner & 0b111  # 第0−2ビットに残っているのがランナー
        
    return run, runner

得点力が高い打順の例

9人で組める打順は9!= 362,880通りです。かなり時間はかかりますが全てのケースで上記の得点シミュレーションを走らせることで、どんな打順が得点力が高いのかを知ることができます。各打順で100試合分のシミュレーションを行い平均得点数を調べてみた結果、私が直感でこんな順番がよいのではないかと思った打順での平均得点は3.05点でした。また、すべての組み合わせの中で最も平均得点が高かった打順では4.03点でした(最低は1.76点)。それぞれの打順を比べてみるとこんな感じです。

私の案 (3.05点) 最高の打順 (4.03点)
1 リードオフマン 高打率
2 川相 三冠王
3 高打率 ジョーカー
4 三冠王 駒田
5 駒田 川相
6 立浪 ランス
7 ランス 守備の人
8 守備の人 立浪
9 ジョーカー リードオフマン

平均だけでなく得点の分布も比較してみましょう。水色のヒストグラムが私が考えたオーダーの得点分布で、クリーム色が最高得点の打順の分布です(茶色は両者が重なっている部分)。これを見ると確かに5点以上得点する試合の数がかなり違いますね。

f:id:unifa_tech:20201005180456j:plain
2つの打順における得点の分布
最高得点の打順を見てみると、まず、2番に強打者を置くという最近のトレンドと合致していて面白いです。また、上位に打率が高めのバッターを集め、ランナーが溜まったときにまわりやすい4番に満塁に強い駒田を入れたり、川相/ランス/守備の人と打率が低めな選手を固めることで打線が分断されるのを防ぐなど、言われてみるとそうだよなと納得させられるオーダーになっており興味深いですね。

まとめ

打率データをもとにある打順での得点数を算出するシミュレーションが完成しました。対戦相手の能力や相性、ボールカウント、走力、代打、守備力など野球において考慮できていない要素がたくさんありますが、今回は野球の正確なシミュレーション環境を構築するのが目的ではないので気にしないでおきましょう。また、全探索の結果から得点力の高い打順の例を示しましたが、打者の特徴が少しでも変わるたびにこのような計算を行うことは現実的ではないため、後編では強化学習モデルによって得点力のある打順をより効率的に求める手法に挑戦していきます。