E-Groceryにおけるカード決済処理の難しさと設計戦略

はじめに

こんにちは!yamakazu (@yamarkz) です。プロダクトブログへの登場は昨年ぶりになりました。

さて、6月は欧州サッカーのシーズンオフになりますが、対してインターナショナルマッチ(国際Aマッチ)が行われる月なので、代表ファンとしてはワイワイ!な月です。今年は冬のW杯も楽しみですね。

という趣味の小話は最初だけにして、今回はStailerで向き合っているカード決済の難しさと、その難しさに対応するために選択した設計戦略を紹介していこうと思います。

今10Xが賭けているE-Groceryという領域はまだまだニッチで、開発知見がほとんど出回っていないのが現状です。決済に関しては海外含めてGoogle検索でもほとんど確認できませんでした。(ex: instacart, Target)

本記事が、E-Groceryの様な複雑なドメインで決済処理を実装する際の参考になれれば嬉しいです。

なぜ、E-Groceryの決済は難しいのか

早速結論から述べると、E-Groceryの決済が難しい理由は、サービス体験の品質として譲れない機能性を担保するために、不確実性を受け入れなければいけないからです。

これはドメインの特徴として、機能性と不確実性がトレードオフという関係性にあり。片方を取ったら片方を捨てる。機能性を追求するなら、ソフトウェアは不確実で複雑な要件に応えるということです。

このトレードオフは一般的な対比でもあるかもしれませんが、E-Groceryにおいてはその特徴が顕著に現れるものであることを、ここで明言しておきます。

多種多様な商品のまとめ買い体験を提供する

E-Groceryは多種多様な商品を一度にまとめて注文し、注文後の変更余地を残しながら最終的な商品の有無を確定、準備できた商品をお客様に届けて初めて価値提供できるものです。

商品をネットで買って自宅で受け取るという意味ではECと同じですが、その過程が特殊であるため、意図的にE-Grocery (ex: ネットスーパー, ネットドラッグストア) という表現を選択しています。ECという概念の部分集合がE-Groceryというイメージです。Quick Commerceと対比されたりもしますが、これもまた別の部分集合です。

特殊なドメインであることを念頭に置いて、その過程で何が起きるのか、起きた場合に決済周辺ではどういった対応を行うのかをStailerを題材に整理していきます。

前提

  1. Stailerは決済代行業者と提携し、決済処理を委譲しています
  2. Stailerは複数の決済代行業者と連携しています
  3. Stailerは2022/06時点でモノリシックアーキテクチャを選択しています
  4. 一般的なオーソリ(与信)やキャプチャー(売上請求)といった決済手順に則ります

注文過程に存在する不確実性の整理

注文過程と不確実性の整理

Stailerの注文過程とそこで起きうるイベント(= 不確実性)を簡易的な図にまとめると↑になります。各イベントシーンで提供される機能はどういった価値があるのか。その裏側で必要となる決済対応が何なのかを1つずつ取り上げます。

決済確定までの時差

まず最も特徴的なのが時差です。

E-Groceryのサービスは確定までの時間が長く、またその過程で生まれる不確実性も多いです。

注文から決済確定までに時差があること自体は実は一般的で、Amazonや他のECでも一定時間を経て決済確定を行なっていたりします。

この時差を設ける理由の大半が、最終的な物理在庫の確定と配達業務完了を最終的な決済確定タイミングとして、注文後の”もしも”の在庫準備不可や配達不備による例外に対応できる様にするためです。(参考)

Stailerでもそういった側面で時差を設けたりしていますが、それ以上に多くの理由が存在します。それが以下で取り上げる機能性を担保するためです。

機能性を担保するために時差を生み出していますが、これによりシステム観点では都度発生する変化に対応し、決済代行側とのデータ整合性を保つことが求められます。

決済では、

  • 決済ではオーソリを取ってから、キャプチャーを取るまでに時間差を設ける
  • 注文作成の過程ではキャプチャーを取らない
  • オーソリ額は変わる可能性があり、キャプチャーはお客様の手元に商品が届けられたことの確実性が高い確率で証明できる状況で実施する

注文変更による金額変動

締め切りまで注文変更ができる

Stailerには注文変更が機能として存在します。

現代のECはAmazonに代表されるように1タップで注文、即配達という世界から考えると ”注文を変更する” という感覚自体が異質に感じるかもしれません。

注文作成後、指定時間までであれば何度も注文内容を変更でき、「やっぱり追加して買いたい」や「家にあったからやっぱり買うのやめよう」といった「やっぱり」な購買体験を提供します。これは1度の注文で多量の商品を扱うことや、その大半が食料品であるために過不足が調整しやすくあって欲しいという要望からです。

実店舗でも商品をカゴから売り場に戻す行為は推奨されていませんが、禁止されていません。

決済では、

  • 決済では注文変更が起きた場合、オーソリ(与信)を取り直す
  • ただし、内容が変わっても支払い金額が変わらない場合は、取り直さない
  • オーソリが何らかの理由で取れなかった場合、注文変更自体を取り消す

配達/受け取り日時変更による金額変動

配達/受け取り日時変更によって金額が変わる例

Stailerには配達と受け取り日時を選択する機能が存在します。

いつでも自由に届く/受け取れるわけではなく、一定の時間制約が設けられています。これは扱う商品が生鮮食品が中心で時間管理がシビアであることが主な理由です。

注文作成後でも指定時間までであれば何度も希望日時に変えることができ、「やっぱり遅い時間に受け取りたい」や「やっぱり次の日の午前中でいいや」という、これまた「やっぱり」な買い方を提供します。

日時変更によって商品金額が変わるケースがあります。時間で金額が変わるの…??? と思われる方もいるかもしれません。

ネット上の食料雑貨店といえど、実店舗と運営自体は同じであることがほとんどなので、セール価格も店舗と同じサイクルで反映されます

例えば、4/15にセールで148円だった商品が4/16には178円になるといったことが起こります。その際に支払い金額が変わります。

決済では、

  • 決済では配達/受け取り日時変更が起きた場合、オーソリ(与信)を取り直す
  • ただし、日時を変更しても金額が変わらない場合は、取り直さない
  • オーソリが何らかの理由で取れなかった場合、日時変更自体を取り消す

注文のキャンセル

指定時間まで注文のキャンセルが可能

Stailerでは注文後の変更可能な時間までであれば、キャンセルすることができます。

ECでキャンセルした経験がある方は少ないのではないでしょうか。一般的な感覚ではECは注文完了後にキャンセル余地を残していないケースが多いです。

E-Groceryならではの1度に注文する商品の多さから調整しやすくする配慮や、受け取り時間の指定という制約に対する代替としての配慮である意図が強いです。

決済では、

  • 決済では注文キャンセルが起きた場合、オーソリを取り消す
  • オーソリはお客様の決済利用可能枠を一時的に抑えることであり、キャンセルしない場合お客様の決済利用可能枠を圧迫してしまう

品切れによる金額変動

品切れの発生により注文金額が変動する

Stailerには品切れという概念があります。言葉の通り注文自体は受け付けたが、実際には商品を準備できなかったということです。

これはECとしてはかなり特殊な不確実性で、ほとんど発生し得ないと考えられていますが、E-Groceryという領域に絞るとその遭遇頻度は一般ECよりも体感で10xほどになります。

その理由は店舗型に限ってですが、実店舗と物理在庫を共有しているため、時間帯やお客様の購買頻度によっては先に売り場から商品がなくなってしまうからです。

つまりは在庫数管理はしているものの、それ自体が購入を確実に補償するものではないのです。もちろんそうではなく、E-Grocery専用の在庫管理ができれば理想ですが、それでは現状は採算性が合わない、確実に補償するオペレーションを組みきれていないというのが現状です。

品切れになった商品はキャンセルと同等の扱いで注文内容から商品単体で取り消されます。

決済では、

  • 決済では品切れが起きた場合、オーソリを取り直さない
  • 品切れは金額が下振れる現象であり、与信枠が不足する現象ではないから

代替品選択による金額変動

希望する方に代替品を提供する

先の品切れへの補填として、代替品を選択して提供することがあります。

例えば、牛乳Aが売り切れていた場合、牛乳Bを選択して届けるということです。これは実店舗でも行われる行為で、いつも買ってるアレがなかった時に、その代わりを選んで購入すると思います。これをStailerでは代替品選択という機能で実現されています。

品切れ商品に対して代替品が選択されても、お客さまへの支払い金額は下振れることはありますが、上振れることはありません。150円の商品が品切れにになり、170円の商品を代替品として選んだ場合、150円の支払いのまま決済に進みます。これは商品の準備ができなかったことがお客様都合の問題ではなく、店舗の問題だからです。

決済では、

  • 決済では代替品選択が起きた場合、オーソリを取り直さない
  • 代替品選択は金額が下振れる or 同額に収まる現象であり、与信枠が不足する現象ではないから

割引(ポイント利用 / クーポン利用)による金額変動

ポイント利用によって割り引かれる

大半の小売企業ではお客さまへのエンゲージメントを高めるために、一定の利用頻度に対して割引を効かせることがあります。その際たる例がポイント利用とクーポン利用です。

ポイントは中期での割引還元、クーポンは短期での割引還元という位置づけです。どちらも支払い金額に割引を効かせることができます。

決済では、

  • 注文作成でポイントやクーポン利用によって支払い金額が0円になった場合、オーソリを取らない。1円以上である場合はオーソリを取る
  • 注文変更でポイントやクーポン利用によって支払い金額が0円になった場合、オーソリを取っていればオーソリをキャンセル。元々取っていない(0 → 0)場合はオーソリを取らない

支払い金額0円のケースを想定するとかなり複雑になってきました... 🤨

カード種別 (デビットカード) による二重引き落とし対策

カード決済にはクレジットカードの他にデビットカードが使われる可能性があります。

デビットカードとは、口座から即時引き落とされるカードのことです。(参考)

デビッドカードであるかどうかはカード番号から識別できないため、デビッドカードというケースもあり得ることを想定して実装する必要があります。

デビットカードの場合、オーソリを取った時点で口座引き落としがなされます。この仕様は、何度も注文変更を行うとその都度指定額が口座から引き落とされることになり(一時的な二重引き落とし)、お客さまにとって都合が悪くなります。ちなみに、変更のオーソリを取る前の額は後ほど返金されます。

決済では、

  • 決済ではお客様の口座残高を圧迫させないため、金額が上振れた場合にのみオーソリを取り直す
  • 金額が下振れた場合は支払い可能枠が保証されているため、オーソリを取り直さない
  • デビットカードでキャプチャーを取るタイミングに生まれた差額は、後日返金される

ここまでのオーソリ取る/取らない/取り消すがどの場合に選択されるのかを整理したのが以下の図です。

分岐地獄 🤯

以上がStailerにおける、注文過程に存在する不確実性の整理でした。

各機能性が何を狙いに存在するのか、それらを決済の視点で捉えた時にどういった考慮で期待の振る舞いを定義しているのかを理解いただけたのではないでしょうか?

この内容を踏まえて、さらに踏み込んで実装上選択した設計判断を次に紹介します。


Stailerで選択した設計戦略

ここでの設計戦略とは、機能性, 信頼性, 効率性といった、守りたいソフトウェアの品質特性を得るために選択された、論理整合性が担保された設計判断(技術意思決定)の集合のことです。

1. 非同期処理化

Stailerでは決済処理の一部を非同期処理化しています。非同期処理を選択することで、障害やデータの不整合が発生した場合に、同期処理に比べてリカバリーがしやすくなります。

具体的には、キャプチャーを取る処理は定時実行のバッチ処理になっています。

配達完了処理(同期処理)でキャプチャーを取った場合でも機能性は満たせるかもしれませんが、お客さまに商品を届けた後に何らかの問題が発生して返品や返金の対応が発生する可能性があります。そういった不確実なケースへの備えとしても、非同期処理でキャプチャーを取った方が信頼性や効率性を守りやすくなります。

もし処理の同期性が仕様として求められていない (= 犠牲にしても問題ない) のであれば、非同期処理を選択するのが良いでしょう。

2. 支払い方法の再選択可能性を諦める

注文後は支払い方法を変更することができない

Stailerでは機能性を諦める選択もしています。注文後に支払い方法を変更することができません。

純粋に機能性を追求するなら、支払い方法を注文後に変更できると嬉しいと思います。 しかし、その機能性を担保することで対応しなければいけない不確実性の方が大きいと判断し、また支払い方法を変更することで救われるお客様の母数を想定すると、機能価値が低いという結論に至り、注文後は変更不可という仕様にしています。

3. 各社決済代行のAPIに存在する仕様差分を吸収する層を設ける

これはStailerという複数の決済代行業者と連携する仕組みである場合の話なので、かなり特殊なケースです。

Stailerではパートナーの希望に応じた決済代行業者と連携して決済機能を提供しています。決済としての機能は同じなのですが、I/Fが違うことはもちろん、小さな仕様差異が生まれてしまうのは避けられず。そういった差分をなるべく意識しなくて良いように共通のI/Fで体裁を整える考慮がなされています。

具体的にはAPIクライアントは完全に独自の実装、PaymentServiceクラスから共通のI/Fを踏襲、PaymentTransactionServiceクラスで振る舞いの仕様差異吸収と複雑な制御を行う構成になっています。

4. リコンサイルで異常がないか検知する or 検知できる状態をつくる

決済の仕組みは外部の決済代行サービスを利用して実現しています。Stailer自体はモノリスであるものの、外部サービスに依存すると分散システム的な考慮が必要になってきます。

特に気をつけなければいけないのがデータの整合性です。データに差異があることをどのように検知するか、検知した場合どう対処するか (= どちらの何のデータを正と見做して修正するか) まで考慮して設計が必要です。

これに関しては定時実行で期待通りに決済の処理が行われているかを確認するバッチ処理や、リカバリーツールを用意して異常検知とリカバリー対応を行える体裁を整えています。

5. オーソリを取り直さないケースを持つ

Stailerではオーソリを取り直さないケースを持っています。

クレジットカードだけであれば、都度取り直しても良いと思いますが、デビットカードではお客様の口座残高を圧迫してしまいます。これを避けるためにも一部のケースでオーソリを取り直さないという判断をしました。

取り直さないのは支払い予定金額が元の金額よりも下振れた場合のみで、上振れた場合は取り直しています。でなければお客さまに支払い能力がないにも関わらず、注文を受けてしまうという可能性があるからです。これにより、一定の口座金額利用圧迫の負荷を低減しています。

6. ドキュメンテーションで有事の際に共通認識を持てる様にする

いかに複雑で認知負荷が高く、把握が難しいかを理解いただけたかと思います。

複雑な構造でも長くメンテナンスしていく覚悟が必要です。少しでも楽にできるようにドキュメントも拡充を進めてきました。全てを言葉で説明するよりも図を使って、整理した方がわかりやすくなるからです。

ドキュメントではシーケンスフロー、状態遷移、シナリオケースを記載して決済制御を整理し、有事の際や追加変更を加える際にエンジニア、PdM、BizDevが素早く現状理解ができる様に工夫しています。

まとめ

長くなりましたが、ここまで触れてきた内容を端的にまとめると次のような内容でした。

  1. E-Groceryの決済は不確実性が多く存在するドメインである
  2. Stailerでは多様な設計判断を駆使して対応してきた
  3. 総じて不確実な変数とその組み合わせをどう捌くか、開発者としての腕が問われる

最後に

Stailerを例にとってE-Groceryにおける複雑な決済仕様を紹介してきました。

書き始めてみれば思っていた以上に重厚な内容になってしまい、決済がいかに複雑で奥深い領域であるかを改めて実感させられました。 (ps: 書き初めの頃はもっと軽く収まると思っていた…)

これも見方を変えれば、複雑であるが故に技術者としての腕が問われる領域であり、複雑さを受け入れてでも機能性を追求しなければE-Groceryという領域のプロダクトは価値を生み出せないということでしょう。

本記事を読んで、決済機能の技術意思決定がより良いものになっていただけたら幸いです。

Stailerもまだまだ発展途上で、解かなければいけない課題がたくさんあります。

少しでも興味を持っていただいた方はカジュアルな面談にぜひ応募してみてください。

meety.net

元コンサル、コーポレート部門の人間が10Xで2か月QAやって学んだこと

はじめに

それは、昨年の瀬のこと。12月24日夕刻。やれ七面鳥だ、やれケーキだ、やれネットスーパーだと世が浮かれている頃、私もご多分に漏れずKFCや波乱万丈のカーネルサンダースの半生に思いを馳せながら、久しぶりにオフィスに出社して仕事のラップアップをしていた。

「・・はい、今目の前にいますよ」右前方の席でWeb会議をしているプロダクトマネージャーのA氏の声が聞こえる。そのときオフィスにいたのは私を含めて3名。私の左斜め後方にはBizDevのエースB氏がWeb会議をしているところだった。

コーポレート部門所属の私を挟んだA→Bの外角高めのスライダーであると判断し、きちんと意識をチキンに戻す。そのとき、スッコココと、Slackの通知が鳴る。代表からの「@udon、今トゥゲザーしましょう*1」というメッセージだった。 QAの人手が足りてないという話と、今目の前にある仕事はいったん棚上げでQAにダイブして欲しいという依頼だった。 QAってQuestion &Answerではないやつですよね.. という愚問はグッと堪えて、「君にしか頼めないんだ」という言葉を胸に、そうかな〜そういうもんかな〜とホイホイ踊り、2つ返事で引き受けたのだった。

以下は、奥深いQAの世界に非エンジニア、元コンサルのコーポレート部門の人間が2か月間ダイブ、コシを入れて取り組んでみて学んだことを徒然に記したものである。

改めて自己紹介

新卒でL.E.K.という欧州系のコンサルでM&A戦略等に関わった後、丸亀製麺を運営するトリドールでうどんの海外展開や米国の海鮮丼チェーンの買収などをやっていました。 店舗のキッチンに立ってオペレーション改善もやりました。その後政府系PEファンドを挟み、昨年10月に10Xに入社しました。 30年uemuraとして生きてきましたが、最近は諸事情によりudonとして生きています。

10Xには、Corporate Strategyという、いわゆるコーポレート部門の経営企画(経企)に近い機能をもつ部署の一人目として入社しました。 エクセル弾いて予実管理や事業計画、ということもやりますが、そもそも事業をきちんと理解していないと血の通った事業計画も戦略も立てられないし、組織に課題が合ったとて常に人的リソースが潤沢にあるわけではないということも重なり、期間を区切ってさまざまな現場に行って問題解決にも取り組む機会に恵まれました。 入社直後に次の記事にあるようなスーパーのバックヤードで箱詰めするところから始まり、その後はCS部門の立ち上げのサポート、そして今回のQAへのダイブと繋がっています。

背景

10Xには、4月から待望の1人目のSET(Software Engineer in Test)のメンバーが入り、 1人目QAエンジニアも6月に入社予定となりました。 それまでは、QA専任のメンバーはおらず、PdM、SWE、BizDev、CSといったさまざまな職種のメンバーが協力しながら取り組んでいる状況でした。

私が関わり始めた当時は、第三者検証会社の方々の協力を頂きながら、QAという機能を独立した活動として定義しましたが、社内で専任の人はいないという状況でした。 品質保証・テストのプロフェッショナルである第三者検証会社の方々の手を借りることはできますが、基本はPdM陣がプロダクト開発と兼任しながらQAの部分も見ていました。

その中で、複数の小売パートナー様のローンチというのが平行して走る中で、本業のプロダクト開発も佳境に入り、いよいよこれは回らないぞ・・!ということで社内で暇そうな、スーパーの現場でプロダクトを使った経験のおかげでキャッチアップが早そうな私に白羽の矢(矢の元は代表)が立ったという状況でした。 結果的にではありますが、最初にスーパーの現場でスタッフ向けアプリを浴びるように使っていたことが役立ったように思います。

取り組んだこと

最初入った時には、QAとかソフトウェアテストというものへの解像度がゼロだったこともあり、「なんかQAやばそう」くらいの認識でしたが、振り返って2か月間で取り組んだことは主に下記です。

  • 各パートナー向けのローンチ(計4社)に向けてのQAのスケジュールの管理
  • 10X社内の開発チームと第三者検証会社の方々とのコミュニケーションの間をとる
  • 自身のQAについての理解向上、及び社内への共有

2か月取り組む中で、自身のQA分野への理解は深まりましたが、(どの分野もそうかもしれませんが..)やればやるほど深いなあという感触で、まだまだ浅いなと感じます。 それでも、スケジュール管理というのは脳内のキャパシティを結構とられるもので、そこを外部化して、概観と基礎の理解をベースに担ったことの意味は一定あったのかなと思います。

苦労した点(非エンジニアからすると何が難しいか)

テストの呼称がさまざまであり、かつ定義にブレがある

ここが一番苦労した点かもしれません。 新しい分野・領域に飛び込む際にまず私がすることが、単語帳を作ることです。 外国語の習得も似たところがありますが、新しい分野だと、そこでは当然のように使われている用語(多くはアルファベットやカタカナ)なのかがわからない。 専門書とか業界記事を読んでて目が進まないのは、多くは自分が知らない単語に対して自身の脳が拒否反応を示していることの累積だと思っています。

QAの分野に入った際も、「QA とは」とググるところから始め、薦められた教科書を読みました。

最初の壁は、「テストレベル」「テストタイプ」という、テストの種別を分類するための2軸でした。 これらのうち、前者は比較的本やネット上の記事での定義が揃っている一方、後者はさまざまな呼称があり、混乱した記憶があります。 たとえば「機能テスト」という言葉は、次にの記事に詳しく書いてありますが、テストレベルでもありテストタイプの話でもあるので、混合して使われると、結構困ります

特にはじめの方は、自分がまだ知らないものと、業界でもやや定義にブレがあるものの差分がよくわからないので、ざっくり理解する→書いてみる→専門家(社内や外部の専門家)に聞いてみるというプロセスを回してました。

プロセスの例

スケジュール管理自体は、ある意味、やることをタスクベースで書き出してそれを社内外のリソース鑑みて、あとは日付で追っていけば回るという側面もありますが、社内外の専門家の意見を聞きながら自身の中でQAの全体像と各種テストの立ち位置(たとえば今取り組んでいることはQAのうちの最後の砦のQC(Quality Control)部分であり、その中でも特にシステムテストの中の〇〇テストをやっている)ということがわかってから、スケジュール管理の肝である見通しとか、リスクといった部分が分かるようになってきた感覚があります。

また、同時に、前述のようにテストタイプについては各社によって呼称がバラバラであることもあって、ある意味「決めの問題だ」ということを専門家からも聞くことがあって、社内でQAという用語の使われ方を一定モニタリングした上で(例 Slackで「QA」という単語で自身に通知がいくようにする)、現状10Xで行われているテストはこれがあって、それぞれこのように呼んで、GitHubやNotion上ではこのように命名しましょうといったことを整理していきました。

社内でのテストの呼称の例(現時点)

エンジニア、(第三者検証会社の)品質保証エンジニア、BizDevチームで、QAというふわっという言葉の中で何を指しているかというのは微妙な違いがあることがあり、リリースまで◯日と1日1日を刻んで取り組んでいる日々の中では、その微妙な違いが爆弾となることがあります。そうした差分に気づいた時に、問題提起をするという動きもしていました。

私も毎度ズバッと「XXとYYに違いがあり、これはZZです」といえたらいいけれど、初めはそうもいかないこともあったので、とりあえず自分をダシに、「今ってXXの部分のYYテストのZZの項目についての話で自分の認識合ってます?」と初歩的な質問をすることで、8割の人にとっては「当たり前」かもしれないけど2割の人にとっては怪しかったかもという部分を潰す動きをしていたこともあったように思います。

QAにはじめて取り組む方(特に非エンジニア)へのアドバイス

  • 上記でも挙げた教科書はわかりやすかったのでお勧めです
  • 言葉の定義でブレがありそうだったら、早いところ仮置で定義してみて、周り(BizDevであれエンジニアであれ)壁打ちをしてて、社内の認識の統一を図っていくのがいいと思います
  • 言葉の定義を定めていくにあたって、まずは社内でどのように使われているか?を調査するには、Slackの通知にその用語の登録をしておくのが便利です

プロダクト開発のプロセスがよくわかってない

私はコンサル、事業会社(外食)、PEファンドを経て10Xに入りました。テクノロジーという分野は常々興味ある分野であったし、ガジェットについても結構こだわる派であったので、「IT」というものはむしろ得意と思っていました。

一方、今回QAという、開発に近い領域に関わらせてもらう中で、改めて自分がソフトウェアというものがどうやって作られていて、どう出荷(リリース)されるかの流れについて無知だったなあということをひしひしと感じました。 自分が何気なく使っているアプリの裏側で、サーバーとクライアントという概念があったり、個別の小売パートナーへの開発がプラットフォーム上の他の挙動に影響を及ぼしうるということであったり、「イシュー」という単語がコンサルと開発どちらもよく使われるが用法が違ったり、等々

QAというひとつの切り口ではありますが、次の記事でも書かれているように、QAとは出荷前の最後の砦として存在しているものでなく、本来は開発プロセス全体に関わるものであるのです。

非エンジニアの自分にとっては、こうした機会でその片鱗を見ることができたのは非常に貴重な機会でしたし、本業である事業戦略を作っていくとか、あとは小売パートナーと提携をしていく中で、こういった解像度が高まったのは非常にありがたかったと感じます。

余談ですが、私がいた外食企業でも確かにQA/品質保証という部署はあり、そのカバー範囲は、調理前の原料や提供前の料理の最終チェックということだけでなく、それを未然に防ぐための手洗い励行だったり、調理のプロセスや器具へのフィードバックだったり、広範なものだったなと思います(なお品質保証部長と1週間US出張しての学びは、「手洗いメッチャ大事」)。

非エンジニアで開発について知りたい方へのアドバイス

  • 私のように非エンジニアだけど開発について知りたい!と思っている人は、何らかの手段でそのプロセスの一端に関わるのがいいと思います。エンジニアに「開発について教えて!!」と言っても困ってしまうし、そもそも自分としても何が知りたいかワカランというケースも多いと思います
  • はいQAやって!というケースも珍しいと思いますが、テストケースの実行の手伝いをするとか、たとえばアプリアップデートのリリース文書いてみるとか。なにか切り口をみつけて実務で関わると、その一端から見えてくる世界があると思います

「どこまでやったらいいか」の判断が難しい

これは、永遠のテーマな気もします。QAの海をすこし回遊していた私が、未経験の人と話すときに初めに伝えるのは、「QA*という活動を経なくてもソフトウェアの出荷自体はできる」ということだったりします。

なんとなく、私を含めビジネスやコーポレート出自の人間の視点では、最後リリースするまでにQAとして「OK」を出してほしい、黒か白か、というイメージを持ちやすいかもしれません。しかし、すべてのパターンをテストしてパスできましたということを証明するのは現実的に無理です。実際には「ほぼ白」というラインを決めて、OKを出していくことになります。 「どこまでやるか」の決定には主観も入りますので、そういう意味では、「良くできているので何もしないでOK」と決めるのであれば、QA*をしなくても出荷(リリース)はできるということになります。

しかし、当然ながら、バグのない完璧なソフトウェアというのは(おそらく)存在しないので、「ほぼ白」がどこなのか?を判断していくことになります。 なので、「QAやります」の言葉の裏には、そこの「ほぼ白」を定義するという、サイエンスよりはアートに近い世界が存在します。社内でも、社外でも、ここの理解度を高めることが、より平和な世界につながる気がします。

お客様と対面する営業や事業開発の視点では、お客様に「品質担保しっかりやってよ」とか「御社として問題ないようにしてほしい」ということをいわれると、「QAというプロセスをきちんと回す」ことが解決策と考えるのは自然なことだと思います。 ただ、その課題解決に向けた社内の過程は、人を+◯人入れれば良いとか、あと◯シナリオを回す、というサイエンスで切れるものだけでなく、「ほぼ白」のラインを定義するというアートがあります。

ですから、お客様に対して満足のいくプロダクトを出すということは、そうした定義を踏まえた上で、営業や事業開発という、お客様に対面するメンバーが、そうした側面を理解した上で、何を示せば目の前のお客様は納得してくれるか?を因数分解して説明を尽くすということが肝要だと考えます。 特に、10Xは一義的には小売パートナーを相手にするB2B2C企業であり、表側のアプリケーションを作るだけでなくネットスーパーのオペレーションを実現するインフラを提供していますから、完全なるB2C企業と比べても求められる水準も高いと認識しています。

同様の文脈で、「2週間確保していたこのテストを1週間でできないか?」に対する答えはテストする項目や観点を減らせば良いので「できる」ことが多いですが、その分不具合が発生するリスクがあがるということになります。 たいていの場合、スタートアップでは時間に余裕があってテストに時間をかけられる状況より、リリースまであと◯日、と切羽詰まっている状況のほうが多いでしょうから、時間の制約がある中でどれだけ品質担保のレベルを上げられるか?ということが肝になります。

開発の現場に触れはしましたが、実際に開発をしていたわけではないので、この「どこまで良いか?」という判断を私の方でするのは難しく、かつ関わっていたエンジニアやPdMにそこを判断してもらうリソースの制約もあります。 なので、もう少し少ないシナリオ数(=テスト時間)で同程度の品質を担保できたのでは?と思う場面はありましたが、安全に振って多めにやっていたいなという所感はあり、ここは私としては難しさを感じた点でした。

QAに接点を持つことになったすべての方へのアドバイス

  • QAの分野はすべてのパターンをテストする、真っ白を証明するということが難しい一方、締切がある領域だと認識をすること。それゆえ、どこかで線を引かなくてはいけないが、その取組はサイエンスよりアートに近い部分があることを理解した上で、期間を定めて(1−2週間とか)さまざまな人と話すのがいいと思います
  • 大上段の方針は経営レイヤーで決めるという前提のもとですが、細かい部分では、プロダクトを開発するエンジニア、お客様と対面している営業/事業開発職のメンバーからなるべくいろいろな意見をヒアリングする。それを通して、どこに理解のギャップがあって、ここで折り合えそうだというポイントをみつけて提案していく。初めから器用には難しいかもしれませんが、提案を通して議論のたたきを作ることができれば、事業を前に進める一助につながるのでないかと思います

QAはなぜ大切か?

社内で、「QAは大切ですか?」という質問に対してNOと答えるメンバーはおそらくいないと思います。 それでも、10Xを含めQAが課題として上がるのは、それが開発スピードと開発費用とのトレードオフとなる場面があるから。 時間とお金というリソースが無限にあれば、どのプロダクトに対しても品質担保ができますが、基本的にはそのどちらにも制約を抱えているスタートアップという世界において、折り合いをつけていくことになります。

これは上述したSETメンバーからの受け売りですが、バグの検出は、要件定義や設計段階での検出と比較して、リリース後の発見では数百倍になるリスクがあります。

早期検出は大事

私を含めQAの経験がないメンバーからすると、QA=QC(リリース前の最後の砦)というイメージが強い気がします。 時間とお金というリリースの制約がある上で、いかにリリース前に最適なQAプロセスを作れるかを考えよう、という考えに到れるのはおそらく大きな一歩ですが、QAの本来の役割に立ち返ると、これだけでは不十分です。 実際にはそれを設計やその前の段階から未然に防ぐための仕組みづくりが重要となります。

それが作られると、良きプロダクトを、適正なコストで、早く届けることでき、法人のお客様、及びその先のエンドユーザーがハッピーになる。その実現の鍵がQAだと私は考えています。

2か月やってみたその後

  • 無事に4社に向けたプロダクトのリリースができた!
  • 1人目のSETメンバーが入り、2人目のメンバーも決まった!(参考: 1人目のSETが話す10XのQAの今と今後
  • 社内のQAの用語とプロセスについての認識の統一が進んだ!
  • 分野を横断して色々やってみていいんじゃないかという雰囲気が出た!(気がする)

コンサルとQAの共通項

最後に少しだけ、あえて共通する部分があればということで書いてみました。 結構コンサルの人とか性質としては向いているのかもしれないと個人的には思いました。

なお、「コンサル」と「QA」はともに、その言葉が指すところは広範なのですが、ここでは人ではなく業務の中の要素における相似について、あくまで私の経験を元にした所感を書きます。

言葉の定義が大切

コンサルの人々は結構言葉にうるさい人種だと思います。 それは、必ずしも自分がクライアントほどに詳細を知らない分野において、構造化をして洞察を出していく必要があるためです。 その構造化、そしてロジックを作っていくために、土台がグラつくとあとが積み上がりませんから、ひとつひとつの言葉について定義をしています。 過去に私が働いたアメリカ人の上司は、「How to work with me」というスライドを1枚持っていて、自分が使う言語や性質について定義をしていました(これはtoo much)。

上記に記載したように、現状QAの業務の中で使われるテストの種別であったり、ひとつひとつの業務については、会社によって呼称が違う部分もあります。 なので、そうした言葉の感度を持って、自身のいる組織における最適な定義をしてそれをベースに業務を組み立てていくということの重要性の高さという意味で、共通する点があるなと感じました。

綿密なプロジェクトマネジメント

QA、特に最後の砦のQCにおいて、結構1日1日を刻むプロジェクトマネジメントというか、スケジュール管理が行われているなと感じました。 コンサルは人月商売なので、どの職位の人を何週間(or 何日)張るかでフィーが決まります。そのため、決まった期間(たとえば3か月)においてかなり詳細にスケジュールを組み、稼働を管理します。コンサルの費用は主に人件費なので、そのコントロールのために、やや炎上しかけている案件とかだと、結構週次単位で人が入ったり出たりということもあり、文字通り1日1日を刻んで生きていた記憶があります。

私が関わったQAの業務は主にリリース前のQCのプロセスでしたから、リリース日は決まっており、そこに向けて必要かつ最適な量の品質担保(=テスト)を実行するのが命題でした。 わからないなりにですが、誰が何をしていて、何日かかりそうで、どのタスクとタスクに因果関係があり、どのタスクは締め切りに柔軟性があるかを把握して1日1日のスケジュールに落としていくというプロセスは、コンサルで1日1日を刻みながらスケジュール組んでいたものと似たものがあるなと感じました。

最後に

私はコンサルで、色々な業界や国に突っ込まれてなんとかキャッチアップして生き抜くということをちょくちょくやってきたので、こうして新しい分野に飛び込むことは好きだし、ある程度慣れがありました*2

それでも、その分野を理解し説明するだけでなく、自分が担い手になるのは新鮮な経験でした。

QAという分野の概観を理解する前から、重要なパートだろうなという予想はあったので、なにかとヒヤヒヤしましたが、こうした重要なパートを任せてくれるところは10Xの良いところだと思います。「新参者だから」とか「専門家でないから」といって遠慮せず、とりあえず主体的にやってみる(「Take Ownership」)ことが大事だなと感じました。

とはいえ、最初の頃は知らないものは知らないし、わからないことはわからないので沢山質問をしていました。 その点では、10Xはさまざまな専門家が集まってきていて、皆知見や知識のシェアに惜しみがないというか、優しいなと感じます。 今回の2か月の中で、本やネットの記事といった二次情報は大いに参考になりましたが、やはり社内のメンバーに教えてもらったことは大きいです。

それは新しい分野に飛び込む機会が沢山あるということでもあると思いますし、それをサポートする体制というか、マインドの人が10Xには多いと思います。 As One Teamというバリューが浸透しているなと感じた一面です。 「IT系の会社で数年働いたけど、そんなにソフトウェアのことはわからない」というビジネス側の人を何人も見てきたので、BizDevとかSWEとかコーポレートとか、職種の違いはありますが、皆ごっちゃになって一緒にコトに向かっている10Xという環境は面白いなと思います。

QAという分野は勿論、さまざまな職種で仲間を募集しています。ぜひ一緒に働きましょう!

*1:社内でのミーティングの一時的な呼称。以降、そこまで浸透しなかった

*2:昔高飛込をやってて日本で8番でした

64人のボードゲーム大会のチームわけを最適化したい

いやー。困った困った。

10X の @metalunk です。先日 10X は全社オフサイトを開催しました。普段はほとんどの社員がリモートワークをしており(10X 社員は日本国内ならば居住地自由です)、直接顔を合わせることが少ないです。そのため今回のオフサイトの目的の一つは、多くのメンバーとコミュニケーションを取り、関係性づくりをすることでした。

そこで、Head of チームビルディングを拝命した私は、コミュニケーション促進に定評のある、ボードゲームをすることに決め、さらに、時間内に効率的にチームをシャッフルすることで、できるだけ多くの人と交流する企画を考えました。

参加人数は64名、各ゲームのプレイ人数は5, 6人であるから、12チームに分ける必要があります。1ゲームのプレイ時間は25分として、5セットプレイできそうです。

さて、このときどんなチームわけをすると、できるだけ多くの人と同じチームになれるでしょうか?

問題設定

参加人数は64名。

時間割は5セット。

ゲームは以下の6つで、それぞれ2つ準備があるため合計12ゲーム。プレイ人数はそれぞれ5, 6人

  • リレー形式マリオカート
  • Dixit
  • はぁっていうゲーム
  • ワンナイト人狼
  • ブラフ
  • コードネーム

さらに、参加者が飽きないよう、同じゲームを2回プレイすることは防ぎます。

この組み合わせの総数はこのようになります。

7のあとに0が182個続く、とても大きい組み合わせで、全列挙するにはあまりに多すぎます。

ところで、数式をブログに書くのはあまりに大変すぎるので、数式は味わいのある手書きで行きますね。

整数計画問題として定式化

このような、組み合わせの総数が爆発的に大きくなる問題は、最適化問題として定式化し、問題の構造を利用して効率的に解くのが良いです。

以下のように定式化しました。

目的関数の工夫

当初、「メンバーごとの、同じチームになる人数の総和」を最大化する問題を解けば良いと考えました。

しかし、これを表現すると以下のようになり、max 関数が入り込み、目的関数は線形でありません。

この問題は MIP (Mixed Integer Programming) solver で解こうとしていたため、目的関数は線形である必要があり、工夫が必要です。

そこで「同じチームになる人数」の最大化を諦め、「同じ人と同じチームになる回数」に上限をつける制約条件にすることを思いつきました。式で書くとこうなります。

しかし、これも線形ではありません。そこで、新たな変数 z を導入することで、線形に変換できました。

プログラミング

MIP に定式化できたため、あとは MIP solver に解いてもらいます。今回は OR-Tools の SCIP solver を利用しました。

OR-Tools を使うと、コードで簡単に MIP を表現できます。私はこの作業を初めて行いましたが、本当に簡単で感動しました。

def solve(
        self,
        people: list,
        times: list,
        games: list,
        game_capacities: dict,
        acceptable_duplicates: int,
):
    # Create the MIP solver
    solver = pywraplp.Solver.CreateSolver('SCIP')

    # Create the variables x and z
    x = {}
    for i in people:
        for j in times:
            for k in games:
                var_name = self._x_var_name(i, j, k)
                x[var_name] = solver.IntVar(0, 1, var_name)
    z = {}
    for i1 in people:
        for i2 in people:
            if i1 >= i2:
                continue
            for j in times:
                for k in games:
                    var_name = self._z_var_name(i1, i2, j, k)
                    z[var_name] = solver.IntVar(0, 1, var_name)
    print('Number of variables =', solver.NumVariables())

    # Constraints
    # Everyone belongs to a team for all time range
    for i in people:
        for j in times:
            ct = solver.Constraint(1, 1, 'ct')
            for k in games:
                ct.SetCoefficient(x[self._x_var_name(i, j, k)], 1)

    # The number of people in a game is smaller or equal to the capacity
    for j in times:
        for k in games:
            ct = solver.Constraint(0, game_capacities[k], 'ct')
            for i in people:
                ct.SetCoefficient(x[self._x_var_name(i, j, k)], 1)

    # Anyone doesn't play the same game twice
    for i in people:
        for k in games:
            ct = solver.Constraint(0, 1, 'ct')
            for j in times:
                ct.SetCoefficient(x[self._x_var_name(i, j, k)], 1)

    # The number of times that one person plays with the same person <= U
    # Linearized version of the constraints below
    # \sum_(j \in J) \sum_(k \in K) x_i1_j_k * x_i2_j_k <= U for all i1 \in I, for all i2 \in I
    for i1 in people:
        for i2 in people:
            if i1 >= i2:
                continue

            sum_z = 0
            for j in times:
                for k in games:
                    _z = z[self._z_var_name(i1, i2, j, k)]
                    _x = x[self._x_var_name(i1, j, k)]
                    _y = x[self._x_var_name(i2, j, k)]

                    sum_z += _z

                    solver.Add(_z - _x <= 0)
                    solver.Add(_z - _y <= 0)
                    solver.Add(_x + _y - _z <= 1)

            # z <= U
            solver.Add(sum_z <= acceptable_duplicates)

    print('Number of constraints =', solver.NumConstraints())

    solver.Solve()

問題サイズの課題

ここで新たな問題が発生しました。問題サイズが大きすぎて解けませんでした。

40人くらいまでは解けます。しかし、1人増えるたびに数百倍問題が難しくなるため、64人では厳しいようです。新たな工夫が必要です。

z の導入で変数サイズ、制約条件の数が増えていることがわかっていたので、モデリングを工夫してどうにか問題を小さくしようと悩みましたが、いい方法が浮かびませんでした。賢いみなさん、どうか助けてください。

仕方がないので妥協して、64人の問題を2つの子問題30人、34人に分割して解くことにしました。

「同じ人と同じチームになる回数の上限」は 1 が最適ですが、それでは解けなかったため 2 としました。

結果

時間ごとに、チームわけが生成できました。同じ人と同じチームになる回数は高々2回です。

評価

参加者たちに聞くと、同じ人と同じチームになった回数はせいぜい2回くらいで、多くの人と交流できたとのことです。解を眺めた感じでも、かなりいい解が得られていた感触があります(ちゃんと評価すれば数字が出せますが横着しています)

最適化されたチームで盛り上がっている様子

その後

オフサイトでたくさん日本酒を飲んだ帰り道、@tapih は、より効率的にチームわけをする手段はなかったのだろうかと考えておりました。そして、より良い手段を発見しました。

この方法でチームわけをすると「同じ人と同じチームになる回数」が高々1回であり、最適解であることが言えます。素晴らしい!!MIP として解いたときはあんなに大変だったのに、最適解を一行で出す方法が発見されました!!

このアルゴリズムの気持ちを表現するとこんな感じです。

実装もシンプルです

def solve(self):
   solution = [{g: [] for g in self._games} for _ in self._times]
   for n, person in enumerate(self._people):
       for t in self._times:
           a = n // len(self._games) + 1
           b = n % len(self._games)
           x = (a * t + b) % len(self._games)
           solution[t][self._games[x]].append(person)

証明に使っているのはこちらです 引用: https://manabitimes.jp/math/680

証明

実は、最初の問題で制約条件としていた「同じゲームを2度プレイしない」ルールについてなにも言っていませんが、うまくやればこのルールも満たすように設計できます。おそらく a と j を入れ替えて証明すればうまくいくはずです。

おわりに

オフサイトでのメンバーのコミュニケーションを最大化するための整数計画問題を解きました。結果は、効率的にコミュニケーションができるチームが生成され、目的が達成されました。

現在 10X は積極採用中であるため、うまく行けば次回のオフサイトではより多くのメンバーが参加することになり、問題サイズはより大きく、困難になると思っていたんですが、@tapih により提案された最適解をかんたんに構成できる手法によって問題は解決しました。安心して入社してください。

このブログは検索、機械学習のエンジニアをはじめとする候補者にちょっとでも引っ掛かれば良いなと思って書いています。面白かった方は著者の @metalunk が取り組んでいる検索、機械学習の Job description をチェックしてください!

ソフトウェアエンジニア(検索)

ソフトウェアエンジニア(機械学習)

10X の検索を 10x したい

いやー、まいったね。

入社して三ヶ月が経ちました @metalunk です。この三ヶ月は検索インフラの改善に取り組み、検索速度 10x, インフラコスト 80% 減の成果が出ました。この記事では検索インフラ改善でやったことを説明します。

ところで、検索インフラの改善ができるということは、先人たちが検索機能を作り、PMF してサービスが利用されるようになったおかげです。感謝して改善しましょう。

2021年12月の Stailer の検索

10X は開発不要でネットスーパーアプリを立ち上げられるシステムである Stailer を開発しております。Stailer での購入のうち 35% が検索経由で行われており、検索はとても重要な機能です。

しかし、2021年12月、増加するリクエストによるサーバー負荷の増大、速度の低下に悩まされておりました。一時的にサーバーを増やし、スケールアウトをすることで対処をしていました。

問題の調査

Stailer の検索は Elasticsearch を使って実装されており、インフラに Elastic Cloud を利用しています。インフラ Metrics を Grafana で分析し、次の問題点がわかりました。

  • ピークタイムの CPU usage が高いこと
  • 平均 Response time が遅いこと

Response time は 95 percentile よりも average の方が大きいことから、ボトルネックになっているクエリがあると予想しました。

ボトルネックのクエリを発見するために Slow log を出力しました。Elasticsearch で Slow log を出力するには、warn, info, debug, trace それぞれの閾値を設定し、さらにどの閾値までログを出力するかを設定します。 https://www.elastic.co/guide/en/elasticsearch/reference/current/index-modules-slowlog.html

次に、Elastic Cloud の画面をポチポチし、分析用 Elasticsearch にログを流す設定をします。これで分析用の Elasticsearch を向いている Kibana からログ解析ができるようになりました。

調査の結果、ボトルネックになっていそうなクエリを発見し、Kibana の Dev Tools の Search Profiler を使ってクエリの解析をしました。

Search Profiler ではこんな感じに、内部的にどんな Lucene クエリが発行され、どれくらい時間がかかっているのか調査できます。モザイクを不必要に多めにしているのは、隠されると見たくなる人間の真理を利用し、カジュアル面談に誘導するためです。Twitter で声かけてください。

long -> keyword で検索速度 10x

Elasticsearch には mapping という機能があり、 field ごとに type を指定できます。type は document から自動で推測してもらうこともできますが、Stailer では mapping を明示的に指定してあります。

問題のクエリを Search Profiler で眺めていると、ある long 型の field による絞り込みで Lucene の PointInSetQuery を発行しており、とても遅いことに気づきました。詳しい Lucene の実装を知らないので想像になりますが、long 型の field を検索したかったら木構造を使うとして O(logN) ほどかかるでしょう。

そこで、サーバーサイドの実装を読んでその field の使われ方を見てみると、enum 的な使われ方をしていることがわかりました。enum のようなデータは keyword 型にすることで、 Inverted index が生成され、検索時に O(1) で絞り込めます。計算量で大きな改善が見込めます。

実験環境で type を変更して Search Profiler で確認すると、クエリ単体で 283x 高速化することがわかりました。リリースしましょう!

新しい mapping を作り、適用のために Reindex を実行し、デプロイした結果、検索速度が 10x しました👏

さらに、CPU usage も 68% 減少しました👏

ちなみに、10x と書いたときは10倍のことで、10X と書いたときは会社のことなんです。

Deployment 引っ越しで費用を 80% 削減

さて、サーバー負荷と Response time には平穏が訪れましたが、スケールアウトしたままなので、お金はどんどん消えていきます。

Stailer の Elasticsearch の Instance type は I/O optimized という、大きな Storage を抱えたものを使っていました。しかし、Stailer の特性は、データ容量がそれほど多くなく、検索が多い、CPU heavy なアプリケーションです。CPU optimized instance に切り替えた場合の試算をしてみると、費用を 80% 削減できることがわかりました。直近の支払い金額が削減できるだけでなく、将来的にお客さまが増え、スケールアウトするときにも安く済みます。

わかりやすく例えると、毎日100個以上の小包をできるだけ速く配送したいんだけれど、これまではたくさんのハイエースを買って並列に配送していました。これからは少ない台数の速いバイクで配送します。バイク便です。

しかし、Instance type は途中で切り替えることができないため、新たに CPU optimized を設定した Deployment を作って引っ越す必要があります。さらに、データを失わず、無停止で引っ越しを完了したいです。

引っ越し計画の概要はこうです。

  1. Elasticsearch の更新をすべて PubSub 経由にする
  2. 新しい Deployment を作り index をコピーする
  3. Double write (両 Deployment への書き込み) 開始
  4. 新しい Deployment に参照を切り替える
  5. Double write 停止
  6. 古い Deployment を削除する

詳しく説明します。

1. Deployment の更新をすべて PubSub 経由にする

これまでは Firestore の元データに変更があったら、Cloud Firestore triggers から直接 Elasticsearch を更新していました。

それをこう変更します。Firestore の元データに更新があったら Cloud Firestore triggers が PubSub topic に publish する。それを worker が subscribe して Elasticsearch を更新する。

間に PubSub を挟むことで、複数の Subscription を生やして Double write ができるようになりました。さらに、耐障害性も向上します。

2. 新しい Deployment を作り index をコピーする

当初は、Elastic Cloud が提供している Restore from snapshot 機能を使って index をコピーしようとしましたが、動きませんでした。理由はいまだ不明で、現在も Elastic 社に調査してもらっています。

そういうわけで、代わりに Reindex from remote 機能を使ったツールを作ることにしました。ツールが行うことは、新しい Deployment に index を作り、mapping 等の設定をし、稼働中の Deployment から Reindex を実行することです。

3. Double write 開始

2つめの Subscription を生やし、それを subscribe して新しい Elasticsearch を更新する2つめの worker を動かせばふたつの Deployment を更新し続けられます。

あとは、安心なタイミングで参照を切り替え、後片付けをするだけです。

結果

無事故で作業が完了し、新しい Deployment の CPU optimized instance で検索機能を提供できる状態になりました。

これによって、費用を 80% 削減できました👏

これからやること

検索速度の改善や、インフラ負荷対策は楽しく、改善点は無くならないので永遠にできます。しかし、わたしたちの目的は、よい検索機能をお客さまに提供することであることを忘れてはなりません。

1月から3月まで取り組んだことで、インフラ負荷がひと段落し、速度も十分速い状態になり、費用も抑えることができました。

そしてついに、4月からは検索精度の改善を始めます。

CTR とゼロマッチ率を KPI とし、Dashboard を作りました。それらを改善する施策を 4, 5, 6月で実施する予定です。やっと精度改善できる状態になり、お客さま体験を改善できることにワクワクしています!

最後に

10X で Stailer の検索改善を一緒にやってくれる人を募集しております!

この記事のとおり、Stailer では検索改善を始め、やることがたくさんあります。エキサイティングな事業領域で、経験豊富でナイスなチームメンバーたちと、このサイズのスタートアップで一緒に働けることは素晴らしいです。

ソフトウェアエンジニア(検索)

そういえば、わたしは元々、機械学習で推薦機能を作るために入社したんでした。しかし、推薦の前にまずは検索、検索のためにまずはインフラということで検索インフラの改善をしておりました。

検索精度の改善に取り組み、採用もできた暁には、ついに推薦に取り組みたいと思っています。一緒に ML に取り組んでくれる人も募集中です!

ソフトウェアエンジニア(機械学習)

10X に SRE Team ができるまでとこれから

SRE Team の @babarot です。今年1月に入社してからおよそ 3 ヶ月が経ちました。

この度、株式会社10X (以下、10X) は、2022年5月14日、15日に開催される SRE NEXT 2022 に、SILVER スポンサーとして参加します。実は 10X では今年1月に SRE Team が発足しました。これまで開発において求められていたことに新たに "Reliability" という観点が加わり、それが今後強く必要になってくるためです。このタイミングに合わせて、10X に SRE Team ができるまでとチームのこれからについて紹介します。

現在、10X では開発不要でネットスーパーアプリを立ち上げられるシステムである Stailer を開発し、バックエンドとそれにつなげるアプリ (iOS と Android) を提供しています。

Stailer をリリースして以降、複数の国内大手企業で導入され、小売企業の DX 推進を支えてきました。これまでは「事業計画期」「事業立上期」の側面が大きく、サービスをローンチしてパートナーとの実績を積み上げ、Stailer としての方向性を確かめながら歩みを進めていたフェーズでした。

これからは「事業成長期」となりつつあります。 いまある Stailer をより確固たるプラットフォームとしての地位を確立させ事業を成長させていくフェーズです。そこで求められるのは開発だけではない「信頼性の確保」という目線です。今後、開発スピードにおいて、たとえ2歩下がることがあっても安心して3歩前にすすめるような提案・施策を展開していきます。

これまでの 10X では SRE チームはなく、開発メンバーでインフラを見れる人が開発・運用をしていました。Stailer ではインフラ基盤に GKE を採用しています(アーキテクチャについては @wapa5pow のブログも参照)。Kubernetes やその周りのエコシステムを効果的に活用し運用するには専任のメンバーがいたほうが良いことに加えて、10X では Stailer の成長によってパートナー企業や店舗数のもあり、二足のわらじでインフラを見れるような規模ではなくなってきていました。ましてやスケールだけではなく "Reliability" 観点でのインフラ投資も求められてきており、より一層 SRE としてチームを成立させることが急務となっていました。

1人目 SRE として僕が入社したタイミングでこれまでインフラを見ていたメンバーと一緒に SRE チームを作りました。SRE チームでは目下、次のことに取り組んでいます。

  • モニタリング基盤の Datadog 化
  • スケーラブルな Kubernetes Cluster のデザイン
  • スケーラブルな Kubernetes manifest management のデザイン
  • Incident response の型化とワークフローの整理
  • インフラリソースの Terraform 化
  • デプロイの高速化、リリースフローの刷新
  • Team development
  • ...

「Terraform の導入」などは事業のフェーズが変わったのを知るのにわかりやすい issue かと思います。Infrastructure as Code は「事業立上期」には必要のないことですが、今後よりスケールさせていくためには必要になってくることです。10X SRE チームでは、このようにこれから事業やインフラのスケールに必要なものもガンガン進めていきます。

まだできたばかりのチームです。最近、SRE チームで1年ロードマップを作成し、今後1年間 Stailer の成長を "Reliability" 観点でどのようにサポートしていくか、また、SRE チーム自体をどうスケールさせていくかをチームで定義しました (一部抜粋のみ。ロードマップのタイムラインは省略)。

1 year Roadmap (タイムラインは省略)

10X SRE ではスタートアップの成長期を支えることが好きな方、インフラ・チームの両面をスケールさせるのが好きな方を募集しています。JD も作成したのでぜひご覧ください。連絡をお待ちしております!

SRE(Site Reliability Engineer) / 株式会社10X

1人目のSETが話す10XのQAの今と今後

はじめまして。 2022年4月に1人目のSETとして入社するtarappoです。

以前、10XにおけるQAエンジニア/SETの募集記事として次のようなブログ記事を公開しました。

ここからの変化として1人目のSETである私の入社が決まりました。 しかし私1人の入社で募集が終了というわけではなく、10XではまだまだQAエンジニア/SETを必要としています。

一緒に動いてくれる人を強く募集している状態です。

そこで本稿では、10XにおけるQAエンジニア/SETに興味を持ってもらえるように次について書いていきます。

  • 現在の10XのQAの状況
  • 入社が決まってからまずおこなったこと
  • 10Xとして目指す姿
  • 今おこなっていること
  • どのような人を求めているか

まず最初に現在の10XのQAの状況について説明をします。

その状況をふまえて、まず私が最初におこなったことがなにか。 10Xとして目指す姿と、それに向かって私が今おこなっていることについて説明をします。

そして最後に10Xではどのような人を求めているかについて説明したいと思います。

現在の10XのQAの状況

現在の10Xにおけるリリースまでの流れをテストというフェーズに注目して簡略化して書くと次のようなプロセスになっています。 ただし、現状リリースするものすべてがこのプロセスにしたがっているわけではありません。

現状のプロセス例

今はこの図にあるように開発後にテスト(手動テスト)をおこなうフェーズがあり、このテストが終わったらリリースをしています。 このテストの箇所は、以前と異なり社内のメンバーではなくて第三者検証会社の方がおこなっています。

第三者検証会社の方が入ってくれたことで以前と比べて、リリース前にバグが一定見つかりリリース後の品質はよくなったといえます。

しかし、この手動検証をおこなうテストのフェーズで解決すべき課題がいろいろとあります。 たとえば、テストのプロセスが整備しきれていなかったり、不具合の可視化もできていません。 そのため改善サイクルをまわせているとはいえません。

また、現時点ではこのフェーズでテストをおこなうぐらいになっており、他のフェーズにおいて初期品質を上げるといった活動はできていません。

現状としては次のような状況になっているといえます。

  • テストフェーズでのQC(Quality Control)のみに頼っている
    • しかしすべてのリリースをコントロールできているわけではない
    • テストの結果をもとに何かしらの改善活動が進んでいるほどではない
  • QA(Quality Assurance)についてのコミットがほぼできていない
  • 全体的にどのような状況になっているかの分析ができていない

この状況のまま進んでいくと今はまだそこまで表面化していないものの、たとえば次のようなことが問題になってくると考えられます。 むしろ一部においては問題になってきているといえるかもしれませんが、可視化ができていないため定性的な判断しかできないという状況です。

  • リリース前のテストがメインとなっており、バグの発見が本来みつけられるべきフェーズより遅くなってしまう
    • 仕様作成時点や開発時点でみつけられたかもしれないバグがリリース前のテストでみつかっているかもしれない
  • リリース前のテストが徐々に肥大化して、テストフェーズがボトルネックになる
    • 結果としてリリース前のテストでおこなえる範囲がさらに狭くなるかもしれない
  • テストフェーズに依存してしまい初期品質が徐々に悪くなってくる

これらの課題を対処するために、テストのフェーズに関わる人員をとりあえず増やしてリリース前のテストを人海戦術でおこなうようにするというのがとれる姿の1つです。

しかし、そのような場当たり的な対応だと一定期間は一部の課題において有効になるかもしれませんが、将来的に違う課題をうみます。

そこで、10Xにおいてはどのように進めていくかについて考えました。 次に入社が決まってからおこなったことについて説明をしていきます。

入社が決まってからおこなったこと

入社が決まってから週に数日だけ業務委託として働いています。 その業務委託の期間にどのようなことをおこなったかについて、説明をしたいと思います。

10Xの選考には「トライアル」というのがあります。 かんたんに説明すると、社内の情報にアクセスができる状態にしてもらった上で、10Xの業務の中でインパクトのあるイシューに対して取り組みをおこなってみるというものです。 トライアルについては次のブログに書かれているので読んでみてもらえればと思います。

私はトライアルで、「プロジェクトの品質」や「開発生産性」についての現状を把握するためにSWEのメンバーやその当時検証に携わっていたメンバー(PdMやCSの方)からいろいろと話を聞きました。

今の状態(プロセス、自動テスト、検証にまつわるいろいろな情報)を聞いた上でおこなうべき課題をリストアップして、なにもしないことによる今後考えられるリスクや取り組む場合の優先順位とその理由をまとめました。

なので、業務委託で仕事を進めていく中で最初はトライアル時点でまとめたことをもとに進めようと思っていましたし、実際少しだけ着手をしました。

しかし「10XにおけるQA体制がいろいろと整っていないという状態」と「そこまで手を動かす時間が私にない」という制約の中でリストアップした課題を進めるのは、10Xにおける変化のスピードに対してついていけずに、私自身がボトルネックとなります。

そこで、わたしが最初におこなったことは「今後の土台作り」としてのQA体制の構築のための準備でした。 その準備をおこない、少しずつ土台を整えていくことに注力をしました。

QA体制の構築のための準備と最初の一歩目

QA体制を構築するために、まず自分たちがどのような姿を目指すかといった最初のゴールが重要です。 そして、その目指している姿にするためにリードしていくQAに関わる職種の人たちの採用や体制づくりが重要となってきます。

そこで、まず「10XにおけるQAはどのような姿を目指すか」について考えました。

目指している姿をかんたんに説明すると次のような姿です。

  • (1)リリースの前のテストフェーズに頼るのではなくてさまざまなフェーズでテストができている
  • (2)QAに関わる職種のメンバーだけでなく品質をつくりあげていくのは「全員」であるというスタイル

これにより次を達成したいと思っています。

「より早い段階で問題をみつけフィードバックをして、より早い段階で解決できる」

そこで次にこの姿を目指すにあたってどのように進めていくかについて次を1つ1つ考えました。

  • どのような状態になっているのがゴールに近づいているといえるか
    • その状態になるためにはどのようなことをおこなう必要があるか
  • 進めていくにあたってどのようなQA体制が必要になるか
    • その中でどのようなメンバーが求められるか

つまり「10Xではどういう姿を目指していて」「そのためには何をおこなう必要があって」「それを進めるためにはどういった人が必要か」をまとめました。

これらのまとめた情報を、10Xのメンバーにも共有して協力してもらいました。 その中で、いろいろな方とカジュアル面談などもおこないました。

その結果もあり、今回1人目のQAエンジニアの採用が決まりました。 しかし10Xが目指す姿を達成するにはまだまだQAエンジニア/SETが必要です。

次に私が今おこなっていることや今後の展望を説明して、そのような中でどのような方を現時点で求めるかについて説明したいと思います。

今おこなっていること

上述したようにまず最初に「今後のQA体制のための土台づくり」をすすめました。

今は新たなメンバーが入ってきたときにバリューを発揮できるようにそれ以外のことも少しずつですが進めています。 主に次の3つのことをすすめています。

  • (1)データの可視化と分析
  • (2)テストのプロセス改善
  • (3)10Xメンバーのソフトウェア品質・テストに関する知識の向上

この3つについて次にかんたんに説明していきます。

1つ目は「データの可視化と分析」

さまざまなデータを可視化し分析できるようにして、改善サイクルをまわせるようにすることは重要です。 まずデータの可視化ができるように整備するところからになりますが、最初のターゲットとしてバグチケットに対して可視化を進めています。

現在、バグチケットはテストフェーズに限らずみつけた時点で起票しているもののその情報を活用できる状態にはなっていません。 そこでバグチケットに記入するべき内容の整理や起票後のフローを整えたりと少しずつ進めています。

2つ目は「テストのプロセス改善」

当然ですが、今もリリースはし続けています。 目指している姿に進めつつも、守るべきところは守る必要があります。

上述したようにテストのプロセスはまだ整備しきれていない状況です。 そこで、現状のプロセスをドキュメントに起こしつつやるべきアクションを1つ1つリストアップして優先順位をつけています。

3つ目は「10Xメンバーのソフトウェア品質・テストに関する知識の向上」

目指すべき姿は全員で品質を作り込んでいくというのがあります。 そのために、10Xのメンバー全員が「ソフトウェア品質やソフトウェアテスト」にたいして知識をもっていることが望ましいです。

そこで、まず現状を把握するために10Xのメンバーに「ソフトウェア品質・ソフトウェアテスト」に関するアンケートを実施しました。 この結果をふまえて、社内勉強会などを予定しており準備を進めています。

この数ヶ月の間、QAに関わっていろいろと学んだ10Xのメンバーが数名います。 その方たちの姿を見て、私はこの目指す姿を達成できると思っています。

参考までに次の資料を見てもらえればと思います。

上述したことはまだ終わってませんし、それ以外にもまだまだやるべきことは多いです。 このような状況の中で「どのような人を求めているか」について次で説明したいと思います。

どのような人を求めているか

目指す姿を達成するために、なにをおこなう必要があるかを現状を把握しながら1つ1つやるべきことを進めていきます。 そのためには次のような人を求めています。

  • 目指す姿に対しての課題とそれに向けてのアプローチを周りを巻き込みながら推進できる
  • プロダクトに向き合ってリリースを支える」にはどうすればよいかを考えられる
  • 今のフェーズでなにをするべきかを自ら考えて動くことができる

また、今目指している姿が10Xとして最終的な姿ではあるとは思っていません。 さらにその先を一緒に考えることができればと思っています。

JDの更新をしました

今回、現状を踏まえた上でJDの更新をおこないました。 上記以外のスキル面など他のことについてはJDに記載しています。

今、公開しているJDは次の「QAエンジニア」と「SET」の2種類になります。

2種類に分けていますが、まだ立ち上げフェーズであるためそれぞれが得意としているスキルを活かしつつ、他のこともおこなえる範囲でおこなっていくこともあります。 そういうこともあり上記のJDには細かく明記してない箇所もありますが「テスト戦略、テスト観点、テスト設計」などを得意とする方も強く求めています。

おわりに

10XのQAの現状や今後についてかんたんに説明しました。 ここまで読んで10XのQAエンジニア/SETに興味を持っていただけたら嬉しいです。

また、今回書いた内容は執筆時点での状況になります。 10Xは日々変化しているので、現時点での状況をもっと詳しく聞きたいという場合は次からカジュアル面談に応募してもらえればと思います。 ぜひ、上記のような話(もちろんそれ以外でも)で盛り上がれればと思います。

是非、一緒に10Xをさらに伸ばしていきましょう。 応募をお待ちしています。

最近の10Xプロダクトチームのあれこれをまとめた資料を公開します

こんにちは、10Xデザイナーの日比谷すみれ(@suuminbot)です。

この度、10Xプロダクト部門に特化した紹介資料を公開することになりました!

転職先を探している・10Xチョット気になっている…そんなプロダクト開発に携わるすべての方に、少しでも10Xプロダクト部門のことをお伝えできればと思い作成しました。
ぜひご覧ください!

10Xプロダクト部門紹介資料

10Xプロダクト部門 紹介資料(新しいタブで開く)

この資料でお伝えしたいこと

今回、次の3点のことをお伝えしたいと思いこの資料を作成しました。

1. 挑戦している課題、提供しているサービスの具体的なイメージを持てる

10Xというと、献立推薦アプリ「タベリー」(※サービス終了)やネットスーパーのアプリを提供している会社というイメージをお持ちの方が多いと思います。

また、「Stailer」って名前は聞いたことあるけど具体的にどんな事業・プロダクトなのかはよくわからない、というのも実際によく伺います。

f:id:suuminbot:20220314103830p:plain

事業概要

サービスイン当初は「ネットスーパーのモバイルUX」にフォーカスしていたStailerですが、実は2021年からStailerは大きく進化。

ネットスーパー運営に必要なすべてのシステムをプラットフォームとして提供しています。じゃぁ具体的に提供しているプロダクトってどんなもの?ユーザーは誰?といったことをご説明しています。

2. 組織・チーム体制に関して具体的なイメージを持てる

f:id:suuminbot:20220314103840p:plain

組織体制

f:id:suuminbot:20220314103850p:plain

チームでの取り組み

2020年末時点では15名だった社員数も、2022年3月現在では55名と大きく拡大しました。

こういった組織人員的な拡大と事業の拡大を背景に、2021年秋〜冬にかけて大幅な組織体制の変更がありました。

組織体制の変更については代表の矢本のブログや、つい先日10Xブログでも矢本とCTO石川の対談ポッドキャストを文字起こしした記事が公開されました。

中にいるいちメンバーからしてもこの改善は大きく、より「チーム」を意識してミッションに集中できる体制になったと感じています。

今回の資料ではこの変更についてもお伝えしたく、いくつかのページでご紹介しています。

3. 中の人の雰囲気が伝わる

f:id:suuminbot:20220314103902p:plain

チーム・メンバー紹介

カジュアル面談で頻繁に「実際雰囲気どんな感じですか」「近づき難いイメージありますが実際はどうですか?」というお言葉をいただきます。。(私も入社前は同様のイメージを持っていました…!)

実際はそんなこともなく、落ち着いていて優しい人が多いのですが、テキストだとなかなか伝えづらい…!

とはいえ少しでも中の人の雰囲気が伝わるといいなと思ってメンバー紹介ページや、10Xの好きなところをヒアリングしたページを追加しました。

最後に

今回作成した資料が、10Xに興味を持ってくださっている方のお役に少しでも立てば幸いです!

また、随時内容は更新していく予定ですので、最近10Xどうなのかしら?と思った際はまたこの資料を見てもらえると嬉しいです。

10Xではプロダクト開発に関するあらゆるポジションを募集しています!
10Xのこともっと詳しく知りたい・中の人に話を聞いてみたい!と思っていただけた場合は、是非お気軽にお知らせください。

▼ Meetyでカジュアル面談を常時受け付けています!

meety.net

▼ 定期的にオープンオフィス(会社説明会)を実施しています。最近はオンライン開催です◎

docs.google.com

▼ 10X会社全体の採用情報はこちらのページでご覧いただけます 🤝 募集中のポジションにつきましてもこちらからご覧ください!

jobs.10x.co.jp