Classi開発者ブログ

教育プラットフォーム「Classi」を開発・運営するClassi株式会社の開発者ブログです。

2021年Classiに起こった変化の振り返り

VPoTの id:nkgt_chkonk です。この記事は Classi developers Advent Calendar 2021 25日目の記事です。昨日は平田(@JesseTetsuya)さんによるFlask App Builderでコンテンツマネジメントシステムとメタデータマネジメントシステムをさくっと作ってみたら役立った話でした。

さて、あと少しで2021年も終わってしまいますが、2021年、みなさんはいかがお過ごしでしょうか。Classiにとっては去年から引き続き「変化の年」だったなあ、というのを強く感じています。本記事では、この一年、Classiがどのような課題に直面し、どう変化してきたのかを振り返ってみたいと思います。

年明けから春まで

去年の話になってしまいますが、Classiは2020年4月に、大型アクセス障害を起こしてしまいました。この反省から、同じような事故でユーザーのみなさまにご迷惑をおかけしてしまうような事態を繰り返さないために、対症療法ではなく根治療法として組織の形の変革や仕組みの変更を行いました。その詳細は2020年11月に書いた セキュリティインシデントと大規模障害を経てClassiは開発組織をどう変化させたのか - Classi開発者ブログ に譲ります。

その後、年明けから今年の春に向けて、新しくなった組織で、各チーム、各メンバーはとにかくシステムの課題の改善に必死にとりくんでくれました。わたしにとって印象的だった例としては、「スーパーN+1」「大迂回が必要な改修」や「オブザーバビリティへの継続的な取り組み」があります。

スーパーN+1

まず、「スーパーN+1」です。Classiには、社内で「スーパーN+1」と呼んでいた高いシステム負荷を引き起こす問題が散見されていました。あるユーザーからの1リクエストに対して、パラメータを変えながら何回も内部APIを呼び出します。この時点でAPIに対するN+1が起こっているのですが、なんとその内部APIでも、DBに対してN+1問題を引き起こしているような問題です。

スーパーN+1を改修するためには、APIを呼んでいる側呼ばれている側双方にまたがる改修を行う必要があるため、修正が高コストになりがちです。また、Classiでは、自動テストが不足しており、このこともスーパーN+1を改修するにあたって修正の高コスト化を呼んでいました。それだけではなく、以前のClassiはデプロイが事故りやすかったりロールバックに時間がかかったりというデプロイ上の問題も抱えていました。これも、スーパーN+1を解消するための修正コストを跳ね上げていたひとつの原因です。

そんな中で、デプロイ上の問題を解決するためにECS化を進めたり、それと同時進行でスーパーN+1を解消したりと、自分たちの管理しているサービスに対して適切にシステム上の問題を解決していったメンバーを見ていて、大変心強かったのをよく覚えています。このように、日々きちんとシステム上の問題が解決されていくような光景は、2020年春以前にはなかなか見ることができない光景でした。本当に心強く「Classiって変わったな」と思うことが多い日々でした。

大迂回が必要な改修

次に「大迂回が必要な改修」です。実はClassiには、RDB上でデッドロックを引き起こしてしまう機能が存在していました。その機能はデッドロックを引き起こしてしまうということの他にも、ユーザーにとって不利益となる根本的な仕様上の問題を抱えており「この機能はなくしてしまうべきだ」という判断がなされました。

しかし、その機能を無くしてしまうことにより、不利益を被ってしまうユーザーも当然存在するわけで「いまある機能とは別のやり方で、その機能で実現できていたことを実現させる」という必要が出てきます。つまり「問題を起こしている機能をなくすためには、別の機能をリリースしてからその機能を無くさなければならない」という、迂回が必要になるわけです。

このようなロングスパンの改善も、しっかりとやり切ってくれて「コストがかかるけどわかりやすく新しい価値が生まれるわけではない。しかし問題は抱えている」というような部分の改修をきちんとやりきれたことも、Classiの大きな変化を感じる例でした。

オブザーバビリティへの継続的な取り組み

最後に「オブザーバビリティへの継続的な取り組み」があります。これは id:ruru8net によるAmazon EventBridge(CloudWatch Events)で動かしているバッチをDatadogで監視する仕組みを構築した話などがわかりやすいかと思います。

現在のClassiでは、なんらかの障害が起こったあと、レトロスペクティブで「これを検知できていたら傷は浅かった」みたいな項目が見つかるたびに、そのための監視の仕組みが整備されるような動きが継続して行われています。これも「そこに投資しても直接わかりやすく新しい価値を産むわけではないが、将来の障害を減らし、素早くプロダクトを進化させていくためには必要」という種類の投資です。このような投資が当たり前にされるようになったことに、やはり大規模アクセス障害以前との変化を強く感じています。

このような変化をメンバーひとりひとりが自発的に起こしてくれた結果として、今年の春は去年よりも大きなトラフィックがあったにも関わらず、大きな事故なく春のピークを乗り切ることができました。これは本当にメンバーひとりひとりが尽力してくれたおかげだと思っており、とても感謝しています。

とくに、システム改修のために力をたくさん発揮してくれた若手のエンジニアが、今やClassiに欠かすことのできない戦力として活躍してくれていることが本当に嬉しく、心強く思っています。

夏〜秋

さて、春にアクセスのピークを乗り換えたあと、苦しい時期が続いたと思っています。というのも、システム面の問題の改善は、マイナスをゼロに近づけるための仕事です。一方、ユーザーの抱えている課題を解決する為には、システムの機能適合性や使用性の向上のような「ゼロをプラスに」する仕事もしなければならないわけです。

「去年のような事故を起こさない」という大きな目標をひとつ越えましたが、まだまだ直さないといつか爆発してしまうシステム課題も残っています。この課題に取り組みながら、システムの機能適合性や使用性を向上させていく取り組みが、夏〜秋にかけて多くなってきました。

ここで課題になってきたのが、リポジトリ単位でチームが組成されていることと、分断され絡み合ったモノリスになっていることです。

Classiのリポジトリは、基本的には機能単位で分かれているのですが、中央に巨大なDBが存在し、そのDBを各リポジトリで共有しています。一方、「機能単位」とはいえ、Classiというひとつの大きなプロダクトに対して「ひとつの機能」だけで価値を提供することは難しく、さまざまな形でリポジトリ同士が絡まり合っています。

また、「Classi」という大きなひとつのプロダクトで使用性や機能適合性を向上させるためには、探索的にユーザーの課題を解いていく必要があります。そのため、これらの向上のためには、システム課題の改修以上にリポジトリを超えた柔軟な協働が必要となります。

さらに、分断され絡み合ったモノリスの中では、影響範囲が分かりにくい中で、自分のリポジトリだけではなくて全体を見ながらやりたいことを達成するための、技術的な戦術を描けることが必要になります。このような戦略を描くためには、アーキテクトと呼ばれるようなひとたちが持っている、かなり高度かつ広範囲なエンジニアリング能力が必要です。そして、各チームが自律的にその動きをできるようにならないと、Classiの進化をスケールさせることはできません。

また、各チームには各チームのやりたいことがあって、しかし分断され絡み合ったモノリスの中ではそのやりたいことを実現しようとするとどうしても他チームの協力が必要となります。しかしそのチームにもやりたいことはありますので、チーム同士の利害がバッティングしてしまうことが多発します。

こういった技術的な課題、組織的な課題が健在化してきたのが、夏〜秋にかけての苦しい時間だったと感じています。また、この時自分は、まだVPoTとして解くべき課題がわかっていなかった、と反省しきりです。わたしがVPoTとしてすべきことを模索している中で、チームのメンバーは組織に起因する課題にぶつかって日々苦しんでいました。

「みんな全力で頑張ってくれているのに、どうしてもうまく成果につながらない」という時期を過ごすことで「みんなが全力で頑張ってくれたらその分だけちゃんと成果がでる仕組みを作ること」が自分の仕事のひとつなのだ、と理解することができたのですが、それを自分が学んでいる間は、本当にメンバーに苦しい思いをさせてしまいました。

秋〜今にかけて

「みんなが全力で頑張ってくれたらその分だけちゃんと成果がでる仕組みを作ること」が自分のVPoTとしての仕事なのだ、と理解したのち、まずは「なぜ頑張ってくれているのに成果に結びつけることができていないのか、それを解決するためにはどういう構造をとればいいと思っているのか」の自分なりの分析を社内に対して発信し、社内のさまざまな立場の人と対話をし始めました。この発信と対話の中から生まれたひとつの解が「チーム横断バックログ」として現在運用され始めています。

このチーム横断のバックログは、チームの利害関係がバッティングしスタックしてしまう課題に対して「まずはどのチームがどんな解きたい問題を持っていて、そのためにどのチームの協力が必要なのかを可視化、管理する必要がある」と考え、作成しました。このバックログを作るにあたって、作ると決めて考えるまでは簡単だけど、全社の理解を得て実効させていくのはかなりカロリーの高い仕事であるということも学びました。個人的な話になってしまいますが、こういう高カロリーな仕事は片手間ではなかなか進めることはできないので、自分のような責任者がきちんと進めていくことが必要で、それが今現在のClassiでVPoTがやるべき仕事のひとつなのであろうと学んだ時期でもあります。

ただ、このチーム横断のバックログはまだ運用がへろへろで、その改善は継続的に必要だとも考えています。いつか続報をお知らせできたら嬉しいです。

さて、チーム横断のバックログがあることで、チームごとの利害がバッティングしたときの調整は以前よりもうまくできるようになりました。しかし、それだけでは、組織的な問題はある程度解決しても、チームがそれぞれアーキテクト的な動きをできなければ結局物事が進まない問題は未解決となってしまいます。

ここに対しては、ふたつのアプローチを現在考えています。ひとつは、技術的なアプローチ、もうひとつは組織的なアプローチです。

まずは技術的なアプローチに関してです。そもそもなぜこんなにも機能開発やシステム修正の難易度が高いのか。それは、内部品質の低さに依るものです。内部品質が高ければ高いほど、プロダクトイシューを解決するために必要となる技術的難易度は下がっていきます。なので、技術面でいえば、「外部品質や利用時の品質につなげるために、内部品質を向上させること」が必要なわけです。

弊社のプロダクトは、お世辞にも変更容易性やテスト容易性が高いわけではありません。ここに対して、スケジュールを切った上でまずは自動テストの拡充から始めています。今のままだと、高度かつ広範囲なエンジニアリング能力がプロダクトイシューの解決に必要となってしまうわけですが、内部品質を継続的に高めることによって、より多くのメンバーのより多くの力がプロダクトイシューの解決に寄与できるようになることを目論んでいます。

一方、組織的なアプローチとしては「では目下足りていない内部品質に対して、2022年度はどのようなチーム構造を作り、どのような仕事の進め方をすれば、最も素早くプロダクトイシューを解決できるのか」の戦略を各組織長とともに立て、実効させていくための立て付けを、目下構築中です。

まとめ

今年一年を振り返ってみましたが、ひとりひとりのメンバーが課題感を持って動いてくれた結果、Classiは本当に変わったと実感します。結果として、新しい問題が立ちはだかっている状態ではあるのですが、これはつまり「ボトルネックが移動した」というやつだと思っているので、前向きに、新しくでてきたボトルネックに対応し続けていけるVPoTとなっていきたいと思っています。その結果、来年はさらなる変化を起こして、もっとユーザーの感じる価値に真摯に向き合い素早くプロダクトを進化させていけるようになりたいし、そのための仕組みをきちんと作っていくのがぼくの仕事なので、周りに助けを求めながらしっかりその職責を果たしたいと考えています。

最後に、今回の記事で赤裸々に書いた通り、現在のClassiは決して技術的にも組織的にも「理想的な環境」とは言い難いです。しかし、一から綺麗な環境を作るよりも、すでに問題を抱えている環境をより良い環境にしていくことは技術的にたいへんチャレンジングな課題だと私は考えていて「課題解決ジャンキー」にとっては大変に刺激的な組織であると思っています。課題解決がやりたいひとにとっては本当に無限に機会があるので、自分の力で大きな課題を解決したいみなさまはぜひ! 採用情報 | Classi(クラッシー) - 新しい学びが広がる未来の教育プラットフォームを創る からご連絡いただければ幸いです! カジュアルにお話しするところから始めましょう!

© 2020 Classi Corp.