モノグサQAチームの立ち上げについて

こんにちは!やまもと@テスト番長です。今はモノグサでQAマネージャーをしています。 モノグサに参画してから10ヶ月ほど経ちましたので、これまでのチーム立ち上げについて振り返ってみたいと思います。

モノグサは「記憶を日常に。」をミッションとして掲げ、AI学習アプリを提供している会社です。 EdtechのQA事情については、先日公開したエントリをご覧いただけますと幸いです。

モノグサのQAチーム

モノグサのQAチームは2022年に発足しました。最初のQAEが入社したのが1年ほど前のことになります。 それ以前はSWEが実装からリリースまで全ての責任を負っておりましたが、プロダクトが巨大化・複雑化し開発チームの人数も増え、品質を保ち続けるためにQAEの採用が開始されました。 モノグサではQuality Management という部署の中にQAとE2E Test Automationがあり、QAは現在社員3名と業務委託スタッフ2名の体制で稼働しております。

モノグサにjoinして取り組んだこと

さて、モノグサに入ってまず取り組んだことは実情調査でした。Web開発の現場は色々経験してきておりますが、それぞれの現場の状況を知る事なくして正しいアプローチ戦略は立てられません。

最初の1ヶ月はオンボーディングメニュー(会社のルール説明を聞いたり開発環境を作ったり)を受けつつ、ステークホルダーを芋づる式に教えてもらい1on1を設定してペインポイントのヒアリングを実施しました。先に入社していたQAEメンバーからも色々と情報を教えてもらい、その結果、寄せられたお悩みを集約すると概ね以下のようになりました。

  • 開発者の不具合対応工数を減らしたい
  • QAは開発者個々の裁量に任されており、必ずテストされる仕組みがなく不安
  • ビジネスサイドからは開発の進行状況が分かりにくい

それらを受けて当面の方針案を作成することとしました。

  • リリース作業の巻き取り

開発者の作業負担を減らすためにリリース作業の巻き取りプロジェクトを始めました。Android/iOSアプリは2022年7月時点で巻き取り済みで、WEBとAPIのリリースが新たに対象となりました。システム上の制限とサービスポリシーの観点など調整事項が多かったため、こちらは現在も進行中です。

  • 開発プロセスにQAフェイズを明記する&実施する

開発プロセスのドキュメントにQAフェイズを段階的に追加していきました。

  1. リリース前リグレッションの明記

  2. 影響の大きな変更では着手前に召集してもらうように記載

  3. インテグレーションテストの実施を明記

結果、以前に比べ大きなトラブルは減ってきたようです。(古参スタッフ談) 現在のQAEの人数でカバーできる範囲は自ずと限られているため、体制を整えながら段階的にQAフェイズを拡充していく方針です。 今後は開発者テストとQAテストのレベル感合わせなど細かいところも詰めていくことにしています。

  • リリース情報の伝達フローを整理する

モノグサではリリース内容を事前に確約することはせず、リリースが終わってから周知するスタイルでずっと運営されています。 リリース内容はQAに回ってきた段階でほぼ確定しているので、可能な範囲でなるべく早くビジネスサイドに通知する運用フローを整備しました。 これによって、以前は散発的に発生していたビジネスサイドからのリリースについての問い合わせは減ってきました。

方針案ではエンジニアの負荷軽減を最大のフォーカスポイントと考えました。モノグサには優秀な開発メンバーが多く、工数的な余裕が生まれれば他の様々な問題も連鎖的に解決しそうだったからです。まだまだ十分には軽減出来ていませんが、今後も継続して推進して行きたいところです。

最終的に2023年内までの体制案とロードマップの形に落とし込み、立ち上がりの対応としてはひと段落しました。

新設されたQAチームがやるべきこととは?

既にサービス展開中のプロダクトチームに後からQAが入った場合どう動くべきか? 当たり前のことが多いですが、今回改めて感じたことを整理してみます。

  • リグレッションテストから入ると仕様理解が進む

リグレッションテストがあれば本番環境を最低限正常に動作するようキープすることが出来ます。入社して日が浅くプロダクトの仕様に不慣れなQAチームがシステムの全体像を掴んでいくためにも有効でした。 現在モノグサではリグレッションテストをNotion上で管理しています。かなりライトな管理方法ですが、将来的にE2E自動テスト中心への移行を見越してテスト管理システムなどはあえて入れずにやっています。

  • 負荷軽減を意識する

QAが新設されたということは品質に何らかの懸念があるわけで、その状況下では開発メンバーに相当負荷がかかっているケースが多いように思います。 不具合対応に費やす工数割合が多いと新規開発はなかなか思ったように進みません。市場不具合を減らしていく努力が必要です。 かといって単純にテストの工程を増やすと更に負担を増やしてしまいかねないので、工数を増やさず手戻りを減らせるように意識してプランニングしました。

また、BtoBのビジネスモデルにおいてリリース時期を予告しないスタイルは、顧客対応の難易度が高くなります。可能な限りの事前共有を行うことで、スムーズなサポートが可能になり開発・ビジネスサイド双方の業務負荷が軽減出来るのではと思っています。

  • プロダクトや会社の文化を理解しながらQA文化をデザインする

参画直後はどうしても会社の独自ルールが目につくものです。すぐに色々変えたくなりますが、しかしそれはそれなりの過去の経緯が存在するものなので、改善は慌てずに進めるべきです。 過去の時点の組織においてはそれがベストソリューションだったはず。たとえ標準と乖離していても非難されるべきではないのです。

  • 当たり前の水準を上げる

専任のQAが居なかった頃は検証周りの整備にリソースが割けないため、十分にチェックできる状況が整っていませんでした。 2022年7月時点では、対象OSの幅の広さに対して検証端末の数が少なく、主にエミュレーター上でデバッグすることが多かったようです。 とりあえず最初の3ヶ月で検証端末の台数を倍にしてもらいました。 検証環境のダミーデータも少なく、十分にチェックを行えない状況だったのでQAチームでどんどん作成していきました。 日々の備えがあってこそ、守れる品質の水準が上がります。

モノグサQAは最高に楽しい

モノグサのQAチーム立ち上げ話はいかがだったでしょうか?ここ数年、QAチーム立ち上げや一人QAの情報が多く発信されているようですね。QAの重要性に対する認識が広がってきて活躍の場が増えているのだとしたら、とても良いことだと思います。

モノグサは社員たちのオーナーシップが強く互いにリスペクトする文化があり、働き者が多いです。Valueに「いつでもボードゲームを遊ぶ余裕を持つ」とあるように、いつも誰かしらゲームで遊んでいる人がいる稀有で素敵な会社です。 QAチームの環境だけ見ても、どんなアプローチで品質向上に取り組むかは自由に考えられますし、アプリのリリースタイミングがQA主導であったり、開発者が協力的で検証に困ることがなかったり、かなり働きやすい環境だと思います。

モノグサにおけるQAの取り組みはまだまだこれからですが、今後は更に体制を強化して事業に貢献できるチームになっていきたいと思っています。 QAE絶賛募集中ですので、ご興味のある方はぜひご応募ください!

このブログ記事が何かのご参考になりましたら幸いです。

最後に:

記事は状況説明のために一人視点で書いてありますが、これら立ち上げのあれこれはモノグサのQMチーム全員で実現してきたことですので、メンバーのみなさまにも感謝を述べさせていただきたいと思います。 いつも一緒に働いてくれてありがとうございます!

EdtechアプリのQA事情

こんにちは!やまもと@テスト番長です。2022年の7月からモノグサでQAマネージャーをしています。 僕はこれまで20年弱くらいWeb系の会社でQAのお仕事をしてきているのですが、Edtechと呼ばれる教育系のジャンルはモノグサが初めてです。普通のスマートフォンアプリと結構違うところがあって、毎日面白いなと関心しながら仕事をしています。

折角ですので今回はEdtechならではのQA事情をご紹介してみたいと思います。

続きを読む

AHC019 に参加してみた

ソフトウェアエンジニアの杉江(AtCoder ID: tsutaj)です。

2 年ほど前から、プログラミングコンテストサイト「AtCoder」でヒューリスティックコンテスト(通称:AHC)が開催されています。どんなコンテストなのか簡単に説明すると、最適解を出すことが難しい問題に対して、できるだけ良い解を出すプログラムを期間内に作成するコンテストです。

先日 MC Digital プログラミングコンテスト2023(AtCoder Heuristic Contest 019) に参加して、結果は 89 位(正の得点を得た 737 人中)でした。どんな解法になったのか書いていきます。

この記事を読んでヒューリスティックコンテストに興味が出ましたら、ぜひコンテストにも参加してみてください!

問題概要

atcoder.jp

三次元物体を正面から見たシルエット・右から見たシルエットが 2 組与えられます。 1 \times 1 \times 1 の立方体を面同士でくっつけてできるポリキューブ状のブロックの集合をひとつ決め、それらのブロックを使って正面・右シルエットが完全一致するようなポリキューブの配置を求めてください。同じブロックの集合を使って 2 組のシルエット両方について完全一致できる必要があります。

(ざっくり言うと)できるだけ大きく、できるだけ少ない数のブロックの組み合わせで実現できると高い評価が得られます。片方のシルエットの組でしか使われず、もう片方では使われないブロックが存在しても良いですが、そうするとスコアが減点されてしまいます。

自分の解法

一言で言うと「力まかせに答えを見つける」という解法で、条件を満たすまでランダムにポリキューブを決めて配置することを繰り返します。ですが、闇雲に探索をしても良いスコアにはならないため、いろいろ工夫しました。

配置するポリキューブのサイズを制限する

 N 個の立方体からなるポリキューブは何種類あるか考えてみます。以下の表は Wikipedia の記事 から引用したものですが、 N が大きくなると爆発的に増えるようです。(今回は鏡像を区別するので左側の列が参考になります)

このことから、サイズ 5 までのポリキューブに限定して探索することにしました。適当にはめていくだけで本当に解が作れるの?と思われるかもしれませんが、意外と作れます。

しかしこれに限定して探索しただけだと、当然ですが得られる解にはサイズ 5 までのポリキューブしか登場しません。より大きなポリキューブも欲しいので、シルエットの条件をある程度満たしたらポリキューブをマージしたり伸ばしたりすることで、より大きなポリキューブになるようにしました。その操作をしたあとに、解として正当な状態になっていれば OK です。

ちなみに、上位陣の解法を見ていると、ポリキューブの形状と位置を決めてから配置できるか試すのではなく、各シルエットについて適当に始点を決めて、始点から伸ばせるだけ伸ばしている方がちらほらいました。私は「この方針だったらブロックの大きさのバランスが取れないだろう」と思って捨ててしまいましたが、うまくやるとできるんですね。。。

条件を満たしたら、解を部分的に破壊する

最終日の前日まで、私の解法は「正当な解を求めることを繰り返す」ものでしたが、正当な解がひとつ得られたあと、それを完全に忘れてまっさらな状態でもう一度探索を始めていました。解が得られるまでに割と時間がかかることもあってこれでは非効率的です。

そこで、正当な解が得られたあとは部分的に破壊して、途中から再度探索するようにしました。ポリキューブのサイズが最も小さいもの(複数ある場合はどれか 1 つ)を選んで、それ自身とその周囲にあるものを消すことで部分的破壊をしました。サイズの小さいポリキューブを除去した状態からまた探索できるので、これを実装するだけで順位表上のスコアが約 1.25 倍になりました。

解を部分的に破壊しているため、状態の近傍(少し変化させた状態)を取っています。上位の解法を見ていると、ざっと見ただけでも他に以下のような近傍のとり方があるようです。とても勉強になりました。

  • ポリキューブの平行移動
  • セルの譲渡(一方で使用していた領域を、隣接している他方のポリキューブに譲る)
  • 取り除いても解の条件を満たすようなセルの削除

高速化

探索がどれくらい回るのかは解法の性能に直結します。多く回れば回るほど良いです。そのため、どのコンテストでも高速化は重要になります。今回もたびたび高速化に迫られました。

私は Rust でコンテストに参加していますが、flamegraph でボトルネックを見つけるのをよくやります。処理時間全体に対して各処理がどれくらいの割合で行われているかがわかるので、幅の大きい部分を重点的に直していきました。

高速化にたびたび効いたのは Zobrist Hashing でした。各座標に乱数を事前に割り振っておき、ポリキューブ(の位置を正規化したもの)が占める座標に対応する乱数の XOR を取ることで、ポリキューブ同士が同型かどうか判定しました。Zobrist Hashing については以下の記事を参考にしました。

trap.jp

同型なポリキューブのペアについて、座標と回転方向のマッピングができればハッシュを使わなくても処理が出来るかとは思いますが、複数の方向で同型になる場合があったり、ペアの入れ替えをしたくなったりしてどうも納得いくものができず、結局ハッシュにずっと甘える形になりました。。。どこかで表現度を落としてでも高速化に振り切ってもよかったかもしれません。

解法まとめ

自分の解法を簡潔にまとめると次のようになります。やっていること自体はシンプルですが、実装はそこそこ大変でした。

最終提出へのリンク

焼きなまし法の適用

コンテスト後に「解を部分的破壊しているところは近傍選択っぽいし、焼きなまし法にできるのでは?」とふと思ったので、やってみました。

今までの解法は「常に解を採用し、それを部分的破壊して次の探索に進む」というもので、貪欲に解の生成を繰り返しているだけでした。これを次のように変えてみました。

  • 解が良くなったら常に、解が悪くなったら確率的に採用したのち、それを部分的破壊して再開する。採用しない場合は最後に部分的破壊を行った状態から再開する。
  • 不採用が一定回数続いた場合、何も置いていない状態から再度探索する。

こうすることで、手元で 1000 ケース回したときのスコア平均が 6% ほど改善しました。近傍を増やしたり、温度を調整したりするとさらに伸びるかもしれません。焼きなまし法にもっと慣れていきたいですね。

焼きなまし法を適用した提出へのリンク

さいごに

この問題の答えを人力で見つけるのはかなり大変だと思います(というか自分には無理です)。ですが、自分が書いたプログラムに任せればいい感じの答えが見つかります。自分の書いたプログラムで、自分には不可能なことが可能になる点が、ヒューリスティックコンテストの面白さのひとつだと感じています。

最終日の前日までスコアが思うように伸びず挫けそうにもなりましたが、粘り強く考えて最後にいい手法が思いつけてよかったです。とはいえまだまだ伸びしろは十分なので復習したいですね。

モノグサでは、記憶のプラットフォーム「Monoxer」を全人類に届けることを諦めない、粘り強いエンジニアを募集しています!!

careers.monoxer.com

Monoxer Intern Report #11_日本語誤答生成の改善

自己紹介

モノグサのソフトウェアエンジニアインターンに参加した北村祐稀です。普段は大阪大学で情報科学教育の教材研究に取り組んでいます。

続きを読む

正しい嘘解法入門

ソフトウェアエンジニアの大橋(AtCoder: amylase)です。

今回は競技プログラミングの話をします。それも、企業の技術ブログにありがちな “競技プログラミングが業務に役立った話” ではなく、純粋にコンテストに出た問題の話です。一見怪しく見える幾何の近似を正当化します。最後までお付き合いください。

問題

atcoder.jp

辺の長さが  A, B である長方形の中にできるだけ大きな正三角形を描くとき、その辺の長さを出力してください。

  •  1 \le A, B \le 1000
  • 答えと出力の絶対誤差または相対誤差が  10^{-9} 以下ならば正解

近似解

本問を解く上で重要な性質は「最大の正三角形は長方形と頂点を共有する」というものでした。今回これの解説はしませんが、公式解説が非常にきれいなので見てない人は今見てください。

この性質が成り立っているとき、共有する頂点で長さ  A の辺と三角形の近い辺がなす角を  \theta とすると、この問題の答えは共有する頂点から伸びる2辺のうち短いほうの長さ、すなわち

\displaystyle{
\max_{0 \le \theta \le \frac{\pi}{6}} \min\left( \frac{A}{\cos\theta}, \frac{B}{\cos \left( \frac{\pi}{6} - \theta \right)} \right)
}

です。

ここで試したくなる嘘解法が「 \theta を細かく刻んでたくさん試す」であり、実際に弊社の競プロ部員もこの解法で正解しています。部内で話題になったのが彼の「6000万分割ではWAになるが8000万分割ではACになる」という報告でした。これはたまたまなのでしょうか? 誤差を見積もってみましょう。

誤差評価

 A \lt B \cos{\frac{\pi}{6}} のときは簡単にわかるので、以下  B \cos\frac{\pi}{6} \lt A \lt B とします。

\displaystyle{
f(\theta) = \frac{A}{\cos{\theta}}, g(\theta) = \frac{B}{\cos{(\frac{\pi}{6} - \theta})}
}

とおくと、 f が単調増加、 g が単調減少 なので、求める最大値は  f(\theta) = g(\theta) なるただ一つの  \theta = \theta_{\max} により与えられることがわかり、 f(0) \gt g(0) かつ  f(\frac{\pi}{12}) \lt g(\frac{\pi}{12}) なので、 0 \lt \theta_{\max} \lt \frac{\pi}{12} であることがわかります。

 f, g のグラフを  \theta_{\max} の周辺で拡大すると次の図のようになります( f, g は直線で近似します)。角度を分割する戦略では、角度の分割幅を  \varepsilon とするとある角度  \theta があって  \theta \le \theta_{\max} \le \theta + \varepsilon となるので、そこに着目すると図のような点の位置関係になります。

 f, g の微小変化を見積もります。 \theta_{\max}の周辺での傾きは、 f, g を微分してそれぞれ

\displaystyle{
f'(\theta_{\max}) = \frac{A\sin(\theta_{\max})}{\cos^2(\theta_{\max})}, g'(\theta_{\max}) = -\frac{B\sin(\frac{\pi}{6} - \theta_{\max})}{\cos^2(\frac{\pi}{6} - \theta_{\max})}
}

とわかるので、 f, g の微小変化はそれらの  \varepsilon 倍です。

解の絶対誤差が最大になるのは2つの近似解候補が等しいとき(図の点  P, Q が同じ高さにある)で、この時の絶対誤差は2つの微小変化の調和平均の半分になります。調和平均を幾何平均で上から押さえて三角関数の計算をゴリゴリすると解の絶対誤差は

\displaystyle{
\frac{ \varepsilon \sqrt{AB} \sin{\frac{\pi}{12}} }{ 2 \cos{\frac{\pi}{6}} }
}

で抑えられます。次の準備として、 B \cos{\frac{\pi}{6}} \lt A を用いて  B を消去し、

\displaystyle{
\frac{ \varepsilon A \sin{\frac{\pi}{12}} }{ 2 \cos^{\frac{3}{2}}{\frac{\pi}{6}} }
}

で抑えておきましょう。

解は少なくとも  (\sqrt{6} - \sqrt{2}) A (正方形の場合)より大きいので、絶対誤差の評価とあわせて相対誤差は

\displaystyle{
\frac{\varepsilon \sin{\frac{\pi}{12}}}{2 (\sqrt{6} - \sqrt{2}) \cos^{\frac{3}{2}}{\frac{\pi}{6}}}
}

より小さくなります。

分割数を  d とおくと  \varepsilon = \frac{\pi}{6d} なので、分割数を具体的に決めることで以下のように相対誤差を評価できます。

6000万分割:  \lt 1.356 \times 10^{-9}

8000万分割:  \lt 1.016 \times 10^{-9}

残念ながら微妙に足りないですが*1、おそらく  \theta_{\max} \frac{\pi}{24} より大きいか小さいかで場合分けするなどして精密に評価すると  10^{-9} より小さいことがきちんといえるのではないかと思います。それかもう8200万分割で提出しましょう(相対誤差  \lt 9.904 \times 10^{-10} )。

いかがでしたか?

 f, g の交点が解であり  f - g が単調であるとわかったときに二分法を適用するのが競技プログラミングとしては最適ですが、コンテストに参加する者なら痛感しているように常に最適な解法を選択できるとは限りません。怪しい近似をするとき、嘘仮定を置くときに本稿を思い出して「もしかしたら証明できるかもしれないしな!」と自信を持って提出していただけると幸いです。

モノグサは、誤差評価を改善して8000万分割の正当性をきちんと言えるような腕力のある人材を募集しています! 一緒に働けたら最高ですが、証明だけでも大歓迎です。

careers.monoxer.com

*1:下書き段階では証明が誤っていて、8000万の時だけ制約を満たすようになっていました。悲しい……

Monoxer Intern Report #10_音声読み上げに関する機能追加

自己紹介

こんにちは、モノグサ株式会社でソフトウェアエンジニアのインターンとして働いていた大森です。この大森さんとは別の大森です。 現在は東京大学大学院でコード並列化の研究をおこなっています。 モノグサでは通年インターンとして昨年の10月ごろから勤務していてちょうど1年になります。 この記事ではインターン中に取り組んだ課題やモノグサでの働き方について紹介したいと思います。

続きを読む

手書き数式認識物語

ソフトウェアエンジニアの深谷です。

MonoxerではAndroid/iOS向けに数式手書き認識機能をリリースすることができました。

↓こんな感じの機能です。

社内外の多くの人が関わりながらUIデザインや実装、QA、OSSへのコントリビュートを経てリリースすることができ、印象深い仕事でした。

スマホ上で数学や物理などの問題を解き回答してもらうというのは、技術的にもデザイン的にもQA観点でもチャレンジングなテーマですが、インターンの大森さんをはじめモノグサの多くの人が職種の垣根を超えて協力することでUIの大きな改善をすることができました。

続きを読む