Merpay Advent Calendar 2020 の 9 日目は、バックエンドエンジニアの @sou がお送りします。
今日は少し泥臭く、この一年チームを成長させながら運用と戦ってきた話を書こうと思います。
私の所属するチームは加盟店情報の管理を担っており、その性格から運用に伴う作業が数多く発生します。
どんなプロダクトにも運用はあると思いますが、このチームが直面した運用の負荷はそのボリュームと複雑さから、私のキャリアの中でも最大と言えるものでした。
その運用に私たちがどのように立ち向かい改善を行ってきたか、みなさまの参考になれば嬉しく思います。
なぜそんなしんどい運用を頑張っているのか、メルペイでのやりがいや楽しさ、頑張った結果の美味しい牛カツと日本酒のお店に出会えた話も添えさせていただければと思います。
ここで言う運用とは、事業を進めていく上でさまざまな場面で発生する、自チーム以外が起因となって発生する、データ抽出やレコードの修正といった様々な作業を指すものとします。
運用作業はいろいろな理由で発生します。
事業の成長が早く機能の開発が追いつかないような場面では、エンジニアが不足している機能を手作業で代行することがあります。
例えば、加盟店情報の管理画面に足りない機能があり、ある種の更新操作をエンジニアが代わりに SQL で行うといったようなものです。
ある特定のレコードを抽出したいといったようなドメイン知識が求められる抽出業務も運用として降りてきます。
またデータの誤登録も運用による修正が必要になります。
加盟店情報は人が入力するマスタデータが元となることが多く、人が作るものである以上、ある一定の確率で誤入力や取り違えが発生します。
この誤登録が発生した際の影響調査やデータ修正といった対応も運用のひとつとして数えられ、加盟店数の増加や獲得経路の多様化によってその件数は増えていきました。
運用作業はサービスを提供するためには必要なものですが、次のような理由からエンジニアにとって楽しい作業とは言えないことが多いでしょう。
調査や修正のために作成するコードや SQL は大抵その場限りの使い切りになり、本来のソフトウェア開発のように積み上げを図れるものではありません。
作業内容もその領域の業務とシステムに精通した高度なドメイン知識が要求されるものが少なくなく、複雑な業務内容をソフトウェアテストやQAの検証無しにこなすなど難しいケースがあります。
データ修正などトラブルへの対応はマイナスをゼロに戻す作業であり、運用は孤独で消耗的な業務になりがちです。
運用は他の業務にも影響を与えます。
運用依頼はその性質から突発的に発生するものが多く、本来の開発計画に対して差し込みとなり、稼働負荷の上昇やスケジュール変更を招くことがあります。
運用に押されてチームの時間が無くなり、中長期的な取り組みが削られていくこともあり、サービスの安定性向上や技術的チャレンジといったエンジニアドリブンな成長を阻害する要因ともなり得ます。
このような運用は事業が成長するに従ってその負荷や種類を増していき、やがてチームを圧迫しはじめます。
私たちのチームでは徐々にそれが顕著になり、春頃にはピークを迎え、チームメンバー全員が危機感を持つ状況となっていました。
春といえばコロナ影響により WFH での働き方が始まり新たなコミュニケーション、新たな働き方が求められた時期です。
ちょうどメルペイでは期の区切りにも当たり、チーム体制の変更が行われたところでもあり、変化を起こすにはうってつけの時期と言えます。
そこでチームで話し合い、運用をただの作業として受けるのでなく、運用に対してアクティブに向き合い、負荷を下げるための取り組みをスタートさせることにしました。
チーム活動を強化する
運用対応それ自体は個人で行えるものです。
ところが運用とアクティブに向き合おうと思うと、例えば原因の刈り取り、ツール開発といった運用の負荷を軽減し原因から根絶していくような対応を行うことになり、これは組織的な活動となります。
運用改善に時間を投入する、意思を持って運用に向き合うという決定は個人ではなくチームでの決定が必要であり、メンバー間で認識を合わせ、問題や目標の共通化を図り、チーム外へのコミュニケーションでの足並みを揃えることが必要になります。
2020年春に運用改善が始まるまでは私たちのチーム体制は強固なものとは言えませんでした。
案件ごとにメンバーを当てる分業体制を取っており、チームというよりは個人の集合といった側面が強かったと思います。
運用改善に当たってはこれを変える、チームとしての活動を強化するフレームワークが必要と考え、次のことを行いました。
チーム OKR を作る
メルペイでは 目標設定にOKR が用いられていますが、その名前とフォーマットを借りて我々も「チームOKR」というものを作りました。
チーム OKR にはその期に取り組むべきチームの目標がリストされており、チーム OKR を見ればチームが何を目指しているのか、どのような目標を持っているのかが一覧できるようになっています。
チーム OKR はまず「期初の見通し」というその期を俯瞰予測した記述から始まり、その下にチームとして達成したい目標を並べた Objective が続きます。
「期初の見通し」を設けることで、それを作成する議論を通じて、自分たちを取り巻く状況や課題を言語化し、認識合わせを行っています。
「見通し」なので「こんな期になるだろう」という予測も入るのですが、期末にその答え合わせを行うのもちょっとした楽しみになっています。
次に Objective が続きます。
Objective には新規開発から運用への対応、チーム運営まで、その期にチームが行う活動が優先順に並びます。
チームOKRは、チームで議論を行いながら期初にこれを作り、期中を通じて進捗を追い、期末に振り返って採点を行い、その結果から新たな課題や改善ポイントを洗い出してまた次の期の活動に生かしています。
チーム OKR を持つことで運用に対しての取り組みをチームの目標、タスクとして記すことが出来るようになりました。
もちろん、そのために議論を重ねてチームで認識の共通化を図り、その問題に対してどういった手を打つか、その結果、運用と前向きに戦うための Objective が定まるといった流れが大事です。
チーム OKR を開始して3期目になりますが徐々に進化しており、トラッキングを記録して期中の変化を追うような仕組みができたり、前期にどの程度の Objective を消化できたかを参考に PMやチーム外に働きかけてスケジュールを調整するといった試みも始まっており、運用改善のためという枠を超えて、チームでより一体となって仕事を進め安定性を高めるために役立つようになっています。
バックログを作る
チーム OKR があることでその期の課題は追えるのですが、ではその期間を超えるものはどうするか、という問題が持ち上がりました。
それを解決するために、チームでバックログを作成しています。
私たちのチームが管理するマイクロサービスは歴史が長く、メルペイのサービスリリース以前から存在しています。
そのため事業の成長に伴い初期のデータ構造に歪みが生じたり、突発的に必要になった業務要件に対してサービスの改修が追いつかずエンジニアが手作業で機能を代行しているといった課題が存在します。
こういった課題は一朝一夕に片付けられるものではなく、期を超えて適切な投資タイミングが来るまで持ち続けることもあります。
こういった課題をバックログに積んで管理しています。
実はバックログ自体は作ってはみたものの、まだ運用を回せていないのが事実です。
中長期の課題の置き場所を作ったことで精神安定剤にはなったのですが、本来は棚卸しして開発計画に組み込むといったプロセスを回したいと思っており、今後の課題として認識しています。
運用に立ち向かう
チーム活動を強化したことで運用に対しても手が打てるようになりました。
私たちのチームではまず、
- 運用負荷を可視化する
- 手運用の予防を図る
- 手運用の効率化を図る
この3つを進め改善に取り組みました。
運用負荷を可視化する
運用がどれだけの負荷になっているか、対応に費やした時間を計測し、期末に集計を行って可視化するようにしました。
元々私たちのチームでは依頼があったときは GitHub Issues にイシューを立てて作業を進める習慣がありました。証跡として運用対応を残す目的です。
そこで新たに Google Form を用意して、運用対応が終わるとそのイシューの URL と共に、何時間かかったかを投稿するようにしました。
投稿された内容は Google Sheets に記録され、また共有を目的として Slack にも流しています。
こうして Google Sheets に記録されたものを期末にスクリプトで整形して次のようなサマリを作っています。
D列までが Google Form からの投稿による記録です。
それより右の列は、B列の URL を元にローカルで hub コマンドを叩いて GitHub Issues のタイトルと日付を取得して貼り付けています。
これにより、どのような運用対応があってそれぞれに何時間を費やしているか、一目で分かるようになっています。
このサマリからは sou が 39時間、syumai が 68.85時間、それぞれ運用に費やしていることが分かります。
これは前期の記録で、すでに本記事で取り上げている取り組みが奏功して比較的落ち着いた工数になっています。
たったこれだけですが、記録として十分役立っています。
累計時間はバロメーターになり、例えばあまりに大きな運用が生じた場合はその原因解消に取り組む優先度を上げたいと考えるでしょう。
感覚値でなく実測値なので説得力があり、自分たちの判断材料になり、またチーム外に協力を求めるときにも役立ちます。
時間記録は投資判断としても役立ちます。
例えば「この機能を作るとどれくらい運用工数が減るか」といった問いにも答えが出せるようになります。
手運用の予防を図る
運用の中でもエンジニアが手で SQL を作成して本番データベースの更新を行うような作業は最もリスクが高く、私たちのチームではこれを「手運用」と呼んで特別視しています。
手運用はそのリスクだけでなく、工数の負荷も心理的負担も大きかったため、集中的に取り組みました。
本番データベースを直接更新すること自体、本来は受け入れたくない業務だと言えます。
そのためチームとして「手運用をゼロにする」ことを中長期の目標として、まず打ち立てました。
手運用の原因は主に次の2つのケースに分類できます。
- 機能不足: 然るべき機能がなく、エンジニアが手運用で代行するケース
- 事故対応: 間違ったマスタデータの投入など事故が起因となって手運用でデータ修正を行い対応するケース
機能不足であれば、その機能が開発されれば手運用が無くなります。
事故対応であれば、事故がゼロになれば手運用も無くなります。
そのため手運用が発生する依頼を受ける場合は次のいずれかとセットでなければ受け付けないというルールをチームで設けることにしました。
手運用が機能不足によるものであれば、どんな機能があれば手運用が不要になるか未実装機能リストに積むことを求めます。
手運用が事故対応によるものであれば、KPTの開催や事務事故報告と呼ばれるレポートの提出のどちらかを用意してもらい、再発防止の取り組みを付帯させることを求めます。
この目標とルールはドキュメントにまとめています。
ドキュメントは私たちチームメンバーに向けたものであるとともにに、チーム外に対して理解や協力をお願いする、組織全体を強くするコミュニケーションの土台としても使われています。
ドキュメントがあることで依頼を受けた際もチームとしてブレのない統一見解を示して理解、協力を求めることができます。
特に WFH 体制下では口頭ではなく Slack でのコミュニケーションも多くなると思いますが、まずこれを読んでくれとリンクを差し出した上で会話を続けることが出来るようになるためチームで均質化されたコミュニケーションを取るために役立っています。
手運用の効率化を図る
また手運用、本番データベース更新の作業自体の効率化も行いました。
セキュリティ確保の観点からチームのエンジニアは本番データベースに直接アクセスする権限がありません。そのため SQL の実行は SRE チームにお願いしていました。
効率化される前のワークフローを書き出すと次のようになります。
- チームのエンジニアが調査記録、証跡と共に SQL を作成して GitHub に pull request を作成する
- 別のエンジニアがレビューを行う
- Approve を取ってメインブランチにマージする
- SRE チーム への SQL 実行依頼を SRE の持つ GitHub Issues に立てる
- SRE チーム が内容を確認し SQL を実行、その結果を GitHub Issues に貼る
- チーム側で確認して 問題がなければ完了
二つのチームを跨いだ作業になっているのが分かると思います。
これを私たちのチーム単体で完結できるよう、整理と見直しを行いました。
まず SRE チームに依頼していた SQL の実行は、本番データベースの更新を行うためのバッチプログラムとそれを実行する Kubernetes Job を作成し、Spinnaker にパイプラインを作って Web UI から実行できるようにしました。
SQL は Kubernetes の ConfigMap に埋め込み環境変数経由でバッチプログラムに渡しています。
整理されたあとの作業はこのようになりました。
- チームのエンジニアが調査記録、証跡と共に SQL を作成して GitHub に pull request を作成する
- 別のエンジニアがレビューを行う
- Approve を取ってメインブランチにマージする
- ConfigMap を作成する(半自動)
- Spinnaker から Job を実行する
- 結果を確認、記録して完了
登場人物が減り、ワークフローが簡素化されました。
人間が関与するコミュニケーションを減らしたことで実際に作業負荷はぐっと楽になっています。
また自チームで全ての作業を持つことにより、ワークフロー自体の改善がやり易くなりました。
メインブランチへのマージをトリガに 手順4 の ConfigMap の作成を完全自動にしてしまうことも出来るでしょう。
SQL の作成も一部をスクリプト化しています。
例えばあるレコードの更新作業では、SQL テンプレートと primary key を記録したシードファイルを組み合わせ SQL を生成する仕組みを持たせています。
小さな Ruby スクリプトと Makefile を組み合わせたごく簡単なものですが有用であり、いつしか大体の作業がこの仕組みに乗っかるようになりました。
更新対象となるレコードに間違いがあってはならないため BigQuery を使った検算作業も行いますが、これも bq コマンドをスクリプトに組み込み、半自動化しています。
シードファイルを変更するだけで再利用できるようになり、これは作業の簡略化だけでなく、レビュアーの負担軽減にもなりました。
以前に利用されたことがあるファイルセットであれば、シードファイルに間違いがないかどうかを中心にレビューすればよいことになります。
ここまでの効率化には賛否両論があるでしょう。
本来は本番データベースを直接更新する業務自体がリスクが高く、無くすべきものです。
それをただ効率化してしまうと痛みだけが緩和され、本来許容されないリスクが残り続けてしまうことを心配します。
私たちのチームでもこの点は議論され、前述した「手運用をゼロにする」というポリシーとセットにすることで許容する判断を行いました。
正直な筆者の感想を添えると、これら一連の効率化はやってよかったと言えるものです。
一定の自動化、スクリプト化を行うということは作業を定型化する意味も含まれ、作業ごとの揺らぎを無くしてヒューマンエラーの入り込むポイントを絞り、安全性を上げてくれていると感じています。
何より精神的な負荷が大きく減じました。
ただ油断してはならないのは、再掲になりますが、本来これは撲滅されるべき業務だということです。それについてはしっかりと、手運用のゼロ化を目指して予防する取り組みを進めていきたいと考えています。
振り返って
さて、いかがでしたでしょうか。
運用に対してアクティブに向き合うためにチームOKR、バックログといった仕組みを取り入れチーム体制を強化して組織的な対策を立案、実行できる状態を作りました。
また運用の中でも大きな割合を占める手運用に対して、手運用のゼロ化を目指す、同時にその余裕を生み出すために手運用の効率化を行いました。
チーム体制の強化も手運用の改善も同時期に進められたものでしたが、どちらかを無くしては成り立たない不可分なものだったと思います。
今回の記事には書き切れていませんが手運用のゼロ化を掲げてから後、単に事故対応を受けるだけでなく根本原因の掘り下げまで介入して KPT を開催するような活動も増えています。
それが出来るのは、運用負荷を下げる効率化の仕組みを作りある程度の余裕を生み出したことが効いています。
手運用以外の運用作業に関する言及があまり出来ませんでしたが、ちょうどいま取り組んでいるところであり、私たちチームメンバーにとってもまだ解決し切れていない課題で、記事には盛り込めませんでした。
運用に対してアクティブに向き合う、運用改善は継続的な作業であり、ひとつが片付いても別の何かが浮かび上がってくるものだとも思います。
本記事は手運用について多くの割合を割いていますが、参考になれば幸いです。
泥臭い内情を公開するこのテーマを書くべきかどうか悩みましたが、私たちのチームの一年を振り返ったときに最も大きく変わった部分、最も改善できた部分はこの運用との向き合い方だと思い、年の締め括りには相応しかろうと取り上げることにしました^※。
実際、一年前とは状況が大きく変わったと感じています。
冒頭で紹介したように改善前の運用負荷は重くこれまでのキャリアの中で最大と言えるキツいものでした。それを一定であれ改善することが出来たのは経験、知見となり奇貨として置くべきだろうとの期待もあります。
もし皆様の参考にもなれば嬉しく思います。
改善に際しては私たちのチーム、バックエンドエンジニアの取り組みだけではなく社内の様々な場所で運用を改善する取り組みが行われ、それに大きく助けられています。
例えば事故対応、間違ったマスタデータが起因となるような事故に対しては、マスタデータのエラーレートを下げる仕組みを作るチームが別で立ち上がり、以前に比べてその事故割合はぐっと減ったことを体感しています。
機能不足による手運用の発生も PM が主体となってリストを管理し開発計画に盛り込んでくれるようになっており、様々な方々の協力を得て、一時期の運用負荷のピークを脱することが出来ています。
自分たちだけでなく、周囲の協力を得るというのも大事なことだと思います。
今回は筆者が筆を取らせて頂きましたが本稿にある活動はどれもチームメンバーである @__syumai さんと二人三脚で行ってきたものです。@__syumai さんにもこの場を借りて御礼申し上げます。
新橋で牛カツに出会う
こういった運用と向き合ってでも現職を続けているのは、やはりメルペイでのバックエンドエンジニア生活がやりがいがあり楽しいものであるからだと思います。
Kubernetes や Google Cloud Spanner、Go といった技術スタックは筆者のお気に入りですし、マイクロサービスに即した組織体制で、システムのデザインから開発、テスト、デプロイメント、運用まで全てを見るフルサイクルの開発モデルは学ぶことが多く鍛えられていると感じます。
Terraform、Datadog や Spinnaker と触れるツールも多く、上から下まで触れる楽しさがあります。
チームに自主性と裁量が与えられていることも大事です。
今年はこれまで開発が追いつかず手作業で代行していた配送先の抽出業務を新たなマイクロサービスとして切り出すことが出来ました。
単に運用がひとつ無くなるだけでなく配送周りの状況がデータとして可視化されることで契約以後の加盟店の状況を把握できるといったデータ的な価値ももたらせています。
これをマイクロサービスとして切り出すという決定も自分たちで行い、システムをデザインしゼロから開発を進め運用に載せ、その成果を実感できるといった楽しい経験になりました。
こうしてあるときは苦労し、あるときは楽しく作り上げてきたサービスを自分たちで使うのもまた楽しい瞬間です。
エンジニアの多くは自分の作ったプロダクトを使うことが大好きだと思いますが、私も同じように自分の作ったプロダクト、メルペイを使うのが趣味のひとつになっています。
もしゲーム開発者であればゲームで遊ぶのだろうと思いますが、筆者の場合は BigQuery を叩いて呑み歩いています。
今日は新橋で飲むぞ!と思えば新橋のまだメルペイが利用されていない登録の新しい店舗を BigQuery で抽出してリストを作り、ふらふらと梯子しています。
先月、この趣味のおかげで新たなお気に入りの店舗に出会うことができました。
お店から許可を頂いたので紹介させてください。
そのお店は新橋烏森口から徒歩1分の距離にある 牛かつと和酒バル koda さんです。
私には駅チカなお店をスルーしてしまう癖があるのでメルペイ梯子をしなければ出会うことは無かったかも知れません。
店内はカウンターのみ8席のマスターの目配りが届くこじんまりとした落ち着いた空間、飲むには最高のスペースです。
ここは何でも美味しいのですがやはりメインの牛カツは秀逸、目下都内No.1の牛カツです。
また日本酒の揃えも素晴らしく他にはないものが楽しめます。
支払いはもちろんメルペイで。
店頭に置いてある QR コードを届けたのも、先に申し上げた今年作った配送管理のマイクロサービスが仕事をしています。
支払いのときも、決済の裏側では私たちのチームで管理する API が叩かれています。
メルペイとの縁あって発見できた新橋のお店で美味しい牛カツをつつき銘酒を頂く。
自分の書いたコードが関係して届けられたQRスタンドが横にあり、決済でもまた自分の書いたコードが使われている。
そんな世の一角で確かにサービスが動いており、メルペイを使っていただけるお客さまと加盟店さまの役に多少なりと立てている、それを実感しつつのほろ酔い梯子が醍醐味になっています。
メルペイはまだまだこれからの会社で成長と変化を止めてくれないどころか来年も加速するでしょう。
事業が成長する分、また新たな課題が湧いてくるだろうと思います。
それでもチーム力を上げて運用と戦った今年の経験と知見を武器に、美味しいお店との出会いをご褒美に、また来年も頑張りたいと思います。
ここまでお読みいただきありがとうございます。
メルペイではミッション・バリューに共感できるバックエンドエンジニアを募集しています。一緒に働ける仲間をお待ちしております。
是非、募集要項をご覧ください。
明日のMerpay Advent Calendar 2020 執筆担当は、Data Engineer の orfeon さんです。引き続きお楽しみください。