CIを高速化する技術⚡️

この記事は 10X アドベントカレンダー2023 という企画の1日目(12/1)の記事です。

こんにちは、10Xでソフトウェアエンジニアをしている 岡野(@operandoOS)です。

今回 10Xで3回目となるアドベントカレンダー企画の1日目をありがたく担当させていただきます💪

目次

10X アドベントカレンダー2023ってなに?

株式会社10Xのメンバーが送る、2023年アドベントカレンダー企画です🎄 🎅 🎍

10xall.notion.site

12/1から12/25まで毎日10Xのメンバーが様々なテーマでブログを書いてくれるので、ぜひお楽しみに✨12/25 最終日は10X CEOのyamottyさんがバシッと締めてくれるのも見所です!

さてさて、本題へ

記事のタイトルどおり【CIを高速化する技術】の紹介をしていきます。

今回紹介する高速化のテクニックは多くのCI/CDサービスで汎用的に活用でき、比較的に簡単な実装で高速化が見込めるテクニックを中心に紹介します。紹介するテクニックを身につけることで、多くのCI/CDサービス環境下で高速化が実現できるようになります。

テクニックの実装イメージを掴んでもらうために、GitHub ActionsとCircleCIを参考に取り上げます。今回詳細な実装には触れませんが実装の参考になるドキュメントを記載しています。

CIは絶対に速い方がいい

なぜ速い方がいいのかを説明することが本記事の目的ではないため詳細は割愛しますが、簡単に言うと「速いと待ち時間が短くなりフィードバックサイクルを早く回せる = Developer Experience(開発体験)がいい!!」ので、CIは絶対に速い方がいいんです。

またCIの速度がCD(Continuous Delivery)にも影響するので、CIは絶対に速い方がいいんです

大事なことなのでもう一度言います。CIは絶対に速い方がいいんです

CIを高速化するテクニックの紹介

ここからは多くのCI/CDサービスで汎用的に活用でき、比較的に簡単な実装で高速化が見込めるテクニックをいくつか紹介します。最後に紹介する【テストコードの実行速度を上げる】だけ例外なのですが、こちらはCIを高速化するテクニックとして非常に大事なことなので記載してます。

キャッシュの利用


CI上でビルドやテストを行う前準備としてパッケージ管理ツール(npm、gemなど)でライブラリのダウンロードを行うことはよくあると思います。

CIを実行するたびにそれらを毎回ダウンロードするのは無駄です。一度ダウンロードしたものをキャッシュして以降はダウンロードするものに変化がなければキャッシュを復元して利用することで高速化が見込めます。

このテクニックはどのCI/CDサービスでも簡単に実装できるので、CIを高速化する上で必ず利用すべきテクニックです。

当たり前のように利用してると思いきや改めて見てみると「キャッシュしてないじゃん!」とか「あれ?これもキャッシュできそう!」となることもありますので、今一度キャッシュ利用がどうなってるか見直してみるのもおすすめです。

参考までにGitHub ActionsとCircleCIでのキャッシュ利用に関するドキュメントをのせておきます。

docs.github.com

circleci.com

マシン性能の調整


CIはCI/CDサービスが用意したマシン上で実行されますが、利用するマシンの性能(CPU、メモリなど)次第で大幅な高速化が見込めます。各CI/CDサービスで用意されているマシン性能は異なりますが、マシン性能の変更はどのサービスでも簡単に行なえます。

GitHub Actionsであればruns-on 、CircleCIであれば resource_classで各ジョブを実行する際に利用するマシン性能を指定できます。

例えば各サービスでM1 macOSを利用したい場合は以下のように書くだけです。

# GitHub Actions
runs-on: macos-13-xlarge

# CircleCI
resource_class: macos.m1.large.gen1

参考までにGitHub ActionsとCircleCIが用意しているマシン性能に関するドキュメントをのせておきます。

docs.github.com

docs.github.com

circleci.com

マシン性能を調整するだけで高速化されるわかりやすい例がCI上でiOSアプリのビルドにM1 macOSを利用するケースです。こちらはGitHubから公式アナウンスがあるとおりIntel3コア macOSと比較してビルド時間が最大80%短縮される素晴らしい高速化の事例です。しかもこれがruns-onの指定1行変えるだけで実現できます。

github.blog

マシン性能を上げることでビルド時間やテスト実行時間が短縮される環境では簡単な変更で高速化が見込める一方、マシン性能を上げるに比例して利用時間に対してかかる課金量は増えます。私のこれまでの経験では課金量が増えた分CIの実行時間が正比例して短縮されることは珍しく、性能を調整する際は費用対効果の測定をおすすめします。私が効果測定を行う場合は、数回CIを実行してみて増えた課金量に対してCIの実行時間がどのくらい短縮されるのかざっくり計算してみて判断するだけで難しいことはしてません。ちょっとお金かけてでも実行時間が短くなるならいいよね!という前提がチームや組織内で共有されていると高速化の改善が行いやすいと思います。

ちなみに本記事では詳細には紹介しませんが、CI/CDサービスが提供しているマシン性能では満足しない方はセルフホストランナーという自前で用意したマシン上でCIを動かす仕組みを利用して高速化を実現するケースもあります。

docs.github.com

circleci.com

ジョブの並列実行とテスト分割


CI上でテスト実行を高速化したい場合にジョブの並列実行とテスト分割を利用することで大幅な高速化が見込めます。

言語やテスティングフレームワーク次第ですが多くの場合テストコードそのものをいじらなくても、CI設定ファイルの簡単な変更のみでテスト実行を高速化できます。

ジョブの並列実行とテスト分割による高速化は図にすると以下のような感じです。

テストを各コンテナに分配し並列実行することでジョブの実行時間が短縮され、次のジョブに進むまでの時間が早くなります。

多少注意が必要なのは、並列実行にしたことでジョブ全体でかかる実行時間は並列実行しない時よりも長くなることが多いです。下記図のように並列実行時のステップをまとめて横に並べるとわかるとおりテスト実行準備を2回行うことになるからです。結果的にジョブの実行時間は短縮されますが、ジョブ全体の実行時間は増えるため課金量が増えます。並列実行にしたら絶対増えるわけではなく、並列実行にしたことでCPUやメモリへの負荷が減り、各テスト実行が速くなり全体の実行時間が短くなることもあります。その場合は課金量が減るので良いこと尽くしです。

CircleCIではジョブの並列実行とテスト分割を行うための仕組みが用意されています。並列実行の指定をparallelismで行い、テスト分割をcircleci testsコマンドを利用して行います。

詳細は以下のドキュメントを参照してください。

circleci.com

GitHub ActionsではCircleCIほどわかりやすい機能が提供されていないのですが、matrixとシェルコマンドを利用することで並列実行とテスト分割が行なえます。

以下の記事が参考になります。

kojirooooocks.hatenablog.com

最適なテスト分割


先ほどジョブの並列実行とテスト分割を説明するための図を見て勘のいい方は気づいたかもしれませんが、あの図のあまりよくないテスト分割になっています。

以下の図のようになるのが最適なテスト分割です。

このようにテストの実行時間に基づいて最適なテスト分割を行うことでさらなる高速化が見込めます。

全テストの実行時間がわかるものがあればどんなCI/CDサービスでも最適なテスト分割は実現可能です。一般的にテスティングフレームワークにはJUnit XML形式で全テストの実行時間を書き出す機能があります。その機能を利用してテスト実行時間をファイルに書き出し、書き出したファイルを何かしらのツールに通すことで最適なテスト分割を行うのが一般的です。

CircleCIではcircleci tests splitコマンドを利用することで最適なテスト分割が簡単に行えます。

詳細は以下のドキュメントを参照してください。

circleci.com

GitHub Actionsでは以下のようなカスタムアクションを利用することで最適なテスト分割が行えます。

github.com

ジョブの実行順序・依存関係の最適化


CIのワークフローはいくつかのジョブで構成され、それぞれのジョブは実行順序に依存関係があることが一般的です。実行順序の依存関係のつながりが長ければ長いほどCIの実行時間も長くなります。

ジョブの実行順序・依存関係の最適化とは、ジョブ同士の依存関係を見直し、並列実行できるジョブを増やすことでCIの実行時間を短縮するテクニックです。

わかりやすい例として下記図のようにすべてのジョブを逐次実行しているワークフローあったとします。ジョブ同士の依存関係を見直したところ、ジョブ1の実行結果に基づきジョブ2,3,4は並列実行でき、ジョブ2,3,4の実行結果に基づきジョブ5を実行するワークフローに見直せたとします。その結果、並列実行できるジョブが増えたことでCIの実行時間は短縮されます。

既にジョブ同士の依存関係が整理されているワークフローでも改めて依存関係を見直すことでCIの実行時間を短縮できる可能性がありますので、定期的に見直してみることをおすすめします。

ジョブ同士の依存関係はCircleCIであればrequires、GitHub Actionsであればneedsで定義することができます。それぞれ参考になりそうなドキュメントをのせておきます。

circleci.com

docs.github.com

不要なジョブ・ステップを削除する


CIのワークフローをよくよく眺めてみると不要なジョブやステップを見つけることがあります。それらを削除することでCIの実行時間が短縮されるかもしれません。

長期間色んな人がメンテナンスしてきたワークフローは削除チャンスに出会うことが多いです。不要なものを消すことでCIの実行時間短縮だけでなく、ワークフローのメンテンス性も向上するため定期的に見直してみることをおすすめします。

テストコードの実行速度を上げる


これまで紹介してきたテクニックは主にCI/CDサービスの仕組みを活用してCI設定ファイルを変更することで高速化を実現するものでした。しかしこれらのテクニックを駆使しても思ったよりCIが早くならない場合もあります。

例えばテストコードの実行がなんかすごく遅いなどがそれにあたると思います。テストコードそのものの改善は利用している言語やテスティングフレームワークによって改善方法は様々です。

様々な中でもテスティングフレームワークによくある機能やテスト周辺にある技術、CI/CDサービスに用意された機能などを使いテスト実行速度を上げることで、CIの高速化が見込めます。

テストコードそのものを改善するヒントを得るために、CI/CDサービスのテストインサイトを活用する方法があります。

CircleCIにはテストインサイトというテストのパフォーマンスを表示してくれる素晴らしい機能があります。これを見るだけでテストがどんな状態なのかざっくり理解でき、改善すべきポイントを絞り込むことができます。

circleci.com

利用しているCI/CDサービスのテストインサイト的な機能がない場合は、利用しているテスティングフレームワークの機能を使いテストの状態を可視化できないか調べてみましょう。

例えばrspecには–profile オプションがあり、これを利用することで遅いテストを抽出してくれます。

https://rspec.info/features/3-12/rspec-core/configuration/profile/

他にもテスティングフレームワークには何らかの形式で全テストの実行時間を書き出す機能がついてることが多く、その結果を利用することで遅いテストを特定することができます。

またテスティングフレームワークではなくテストのプロファイリングに特化したライブラリなども言語によっては存在します。

github.com

こういったものを利用し、遅いテストやテスト実行を遅くしている原因を解消することで、さらなるCI高速化を実現できます。

テストコードそのものを変更せずテスト実行時間を短縮したい場合には、CPUコア数分テストを並列実行するような仕組みを検討してみるものいいでしょう。

私達がStailerの開発で利用しているDart testにはconcurrencyオプションがあり、これを使うとより多くのテストを同時に実行できるようになります。

pub.dev

もしお使いのテスティングフレームワークにそういった機能がない場合は、Rubyで代表的なparallel_testのようにテスティングフレームワークとは別のライブラリを使い、並列実行ができないかを調べてみるといいでしょう。

github.com

紹介したテクニックを活用した10XでのCI高速化事例

ここまで紹介してきたテクニックを活用して私が10XでCIの高速化を行った事例を2つ紹介します。

アプリのビルド時間の大幅短縮に成功!!


私達が開発しているStailerではお客様や店舗スタッフさんが利用するアプリをFlutterで開発し、iOS / Androidで提供しています。これらの開発ではCIにGitHub Actionsを利用しています。

Stailerのアプリはパートナー企業様ごとに作成されています。そのため全パートナー企業様のアプリをビルドするためには、2023/12現在OSごとに26ビルド並列実行する必要があります(開発版アプリのビルドも含めると2倍になるので52ビルド…🙄)。

アプリが増え続ける中で特に困っていたのがiOSのビルド時間が長いことでした。GitHub Actionsでは長い間 Intelコア版のmacOSランナーしか提供されておらず、ビルド時間がなかなか縮まりませんでした。セルフホストランナーを利用する選択肢もありましたが、メンテンスコストが懸念であり採用を見送りました。

そんな中今年の10月 GitHub ActionsでM1 macOSランナーの提供が始まりました。

github.blog

Intelランナーで平均ビルド時間が16分だったのが、M1ランナーに変更したことで平均ビルド時間が8分になりビルド時間が半分になりました!やったね!

またAndroidアプリのビルドでも同じようにCPU2コアランナーをCPU4コアランナーに変えたことでビルド時間が半分になりました。

github.blog

このために行った変更はたったの1行のみです。これは高速化テクニックで紹介した【マシン性能の調整】がうまく行った事例です。

その他にも Flutter / Flutter package / Gradleのキャッシュ、不要なステップの削除などを行い、CIの実行時間をかなり短縮できました。

紹介したテクニック【マシン性能の調整】、【キャッシュの利用】、【不要なジョブ・ステップを削除する】を実践した事例紹介でした。

APIのテスト実行時間の大幅短縮に成功!!


私達が開発しているStailerのバックエンド(API)はDartで開発しています。これらの開発ではCIにCircleCIを利用しています(一部GitHub Actionsも利用)。

機能がどんどん増え続ける中で特に困っていたのがテスト実行の時間が長いことでした。またFlakyなテストもあり「困ったな〜😣」って感じでした。

改善を進めるにあたりまずはテストの状態を知るためにCircleCIのテストインサイトを活用し、遅いテストの特定を行ってから遅い原因を調査しました。

調査した結果、原因はテストデータの大量作成による処理のつまりでした。つまりテストコードの実装起因で実行が遅くなっていました。

テストコードを修正しこの問題を解消することで、ハチャメチャに遅いテストが速くなりテスト実行時間が半分になりました!やったね!(この時調査を手伝ってくれた沢田さんありがとう🥹)

その他にも最適なテスト分割、並列実行数を上げる、ジョブの依存関係最適化、Lintの実行時間短縮などを行い、CIの実行時間をかなり短縮できました。

またマシン性能の調整においてはCPUとメモリの使用率がそこまで高くなかったことからresource_class: largemedium+にダウングレードすることで課金量の節約も行いました。

紹介したテクニック【テストコードの実行速度を上げる】、【ジョブの並列実行とテスト分割】、【最適なテスト分割】、【ジョブの実行順序・依存関係の最適化】、【マシン性能の調整】を実践した事例紹介でした。

CIを高速化するために日々取り組んでいること

CIを高速化するために私が日々取り組んでいることをいくつか紹介します。

CI/CDサービスの集計情報を定期的に確認する


CIは生き物なのでいつどんな変化が起きるかわかりませんので、日々体調チェックしてあげることが大事です。

CircleCIであればInsightsダッシュボードがとても役に立ちます。時系列でCIの実行結果を知ることができるため、何か異常が起きた際にいつから起きたのかなども簡単に調べることができます。その他にも実行時間が遅い順にテストを表示してくれるので便利です。

circleci.com

GitHub ActionsにはまだCircleCI相当のInsightsダッシュボードが存在しないため、気になるワークフローは定期的に実行時間を見て異常が起きてないかチェックしています。チェックして「あれ?なんか遅いかも?」と思ったら、実行結果やワークフローを確認して問題がないか確認しています。弊社ではDatadogを利用しているので、今後GitHub Actionsの実行結果可視化はDatadog CI Visibilityを活用する予定があるみたいです。早く使いたい☺️

www.datadoghq.com

CI/CDサービスの最新情報を追う


最新情報が流れてくるブログのRSSを購読したり、Xのポストを追ったりしています。

GitHub Actionsの情報は以下あたりを見てます。

github.blog

https://twitter.com/ghchangelog

CircleCIの情報は以下あたりを見てます。Developer Advocateの方が隔週でWhat's Newまとめ記事をQiitaに書いてくださっていてありがたいです😊

circleci.com

https://twitter.com/circleci

qiita.com

その他にも今度どういった機能が追加される予定なのかを知るために各サービスのロードマップもたまに見てます。

github.com

circleci.com

CI高速化事例のブログなどをいっぱい読む


私と同じように日々CIの高速化と向き合っている方が世界中にたくさんいます。その方々の成果から高速化の知見を得る機会は多いです。自身が知っている高速化テクニックだったとしても細部まで見てみるとそれぞれの工夫がされており、学んでいて飽きない領域だなーと思います。

とにかく色々試す


高速化できそうなアイデアが思いついたり、CI/CDサービスで新機能がリリースされたらとにかく試してみることを心がけています。

やってみてうまくいかなければ適用しなければいいだけですし、試す過程でワークフローの見直しや高速化できそうな勘所が身につくのでガンガン試していきましょう!

ほどほどに高速化する


高速化のためにメンテンス性を犠牲にした結果、自分しかメンテンスできないものができてしまってはいい高速化とは言えません。

「目先の1分を短縮できるけどこの実装は分かりづらいし、このCIが実行される頻度を考えると…やめたほうがいいな!」みたいに自問自答することが大切です。

できる限りシンプルな実装を保つことで、CI/CDサービスが提供する新機能を試しやすくなるメリットもあります。

「CI遅い…待てない…」と日々思い続ける


高速化しても時間が経つにつれてまた遅くなったり、遅くならなくても感覚的な慣れによって「CI遅い…待てない…」となることが多々あります。この気持はとても大事です。

「遅い!」と思った時が見直し時であり、「遅い!」という思いから改善は始まります。

おわりに

「なぜそんなにCIの高速化が好きなんですか?」と聞かれたら、「CIが早くなるとみんな嬉しいじゃないですか」と答えます。

単純にCI/CDが好きというのもありますが、自分が好きな技術を駆使してみんなが喜んでくれるのは幸せなことです。

今回紹介したテクニックなどを参考にした読者の方々のCI/CDが高速化され、共に働くメンバーに喜んでもらえることを祈っています。

ちょっと早いですが、メリークリスマス🎅🎄🎁

10XはプラチナスポンサーとしてISUCON13に協賛します

こんにちは。ソフトウェアエンジニアの@sota1235です。

10Xは来る11/25に開催されるISUCON13にプラチナスポンサーとして協賛します!

ISUCONに協賛するのは去年に引き続き2回目となります。

product.10x.co.jp

協賛に至る考え方の軸は昨年と大きく変わっていませんが、この記事ではなぜスポンサーを行うのか。

そして社内からISUCON13へ参加するチームの様子を少しだけお伝えしたいと思います。

続きを読む

How to 会議ビッグバン

こんにちは、10Xでコーポレートエンジニアをやっているハリールです。このブログは 会議全部ふっとばして社員の集中力を10xした話(バッグバン) の付録として会議ビッグバンの実現方法についてまとめたものになります。

はじめに

結果的に多くの成果とポジティブフィードバックで完遂できた10Xの会議ビッグバンですが、udonさんのアイデアを初めて聞いた時に、実は強めに反対していました。

実行することで得られるメリットは理解できるものの、安全に実行するためのロジックの準備やテスト期間が短いこと、なによりまずは段階的にルール策定と啓蒙を行い、それでもイシューが解決できない場合に、次のステップとして会議ビッグバンの流れがよいのではと当時は思っていました。

そんな私に対して、それならばとまずは特に会議が多いメンバーに対して実態をヒアリングし、そのほぼ全員が賛同している点、また、ロジック準備・テストのための時間確保に奔走し、なによりできない理由を探すのではなくどうすれば実行できるかに徹底的にこだわるudonさんの熱意に触発され、自分の考えを改め一緒に実現に向けた方法論を模索することになりました。

今思い返すと本当にこの施策に携われてよかったと思っています、この場を借りて udonさんへ感謝の意を表します!!!

流れ

会議ビッグバンでは大まかに

  1. 会議データの取得
  2. 会議データの分析
  3. 会議データの更新

のフェーズに分かれて処理していきます。以降それぞれのフェーズごとにまとめていきます。

会議データの取得

まずは全社員の会議予定を可視化していきます。

Step1. GASによる取得

Googleカレンダーのデータ操作でまず最初にアプローチするのはGAS(Google Apps Script)だと思います。以下がイベントデータ取得部分の抜粋です。

function getCalData(cal, date, email) {
  const list = cal.getEventsForDay(date, {author: email})
  for (let elm of list) {
    if (elm.getVisibility().toString() == 'CONFIDENTIAL' || elm.getVisibility().toString() == 'PRIVATE' ) {
      // 非公開イベントはスキップ
      continue;
    }

    // スプレッドシートへ書き込み(省略)
  }
}

カレンダーから日付とメールアドレスを指定してイベントを取得し、条件に合致したものだけをスプレッドシートに書き込んでいます。なお今回の要件では非公開イベントは除外しました。

あとはこのfunctionを取得したい日付・対象社員のメールアドレスのリストの組み合わせでループすればデータの取得はできそうです。

課題

GASでは一回の起動で最大6分しか実行ができません。そのため上記ロジックの場合分割して処理するなどの工夫が必要になってきます。

単発での実行ではなく、繰り返しでの実行、ましてビッグバンでは更新操作も必要となることを考えるとGASでの実行は現実的ではありません。

試しに一ヶ月間で全社員のデータを分割取得したところ2〜3時間かかってしまいました。

参考:https://developers.google.com/apps-script/guides/services/quotas?hl=ja

なお、実行時間の課題さえクリアできれば有用であり、現在この処理は日時で全社員の会議データを蓄積する処理として活用しています。

Step2. ICSファイルからcsvへのコンバート

GASによる制限・性能問題をクリアし、繰り返し何度も実行可能な状態を実現するため、次に試したのはICSファイルにエクスポートし、そのデータをcsvに変換する方式です。

Googleカレンダーは各自のカレンダーデータを簡単にicsファイルとしてエクスポートすることができます。

参考:https://support.google.com/calendar/answer/37111?hl=ja

また、自分のカレンダー以外にも特定の権限があれば他の人のカレンダーも一括でエクスポートすることができます。試したところ、複数人のカレンダーでも数秒でエクスポートが可能でした。

icsを扱うライブラリもいくつかあるので以下のようなイメージでローカルでcsvに変換してみます。

import icalendar

with open([iscファイル]) as f:
    calendar = icalendar.Calendar.from_ical(f.read())

    for event in calendar.walk('VEVENT'):
        if event.get('CLASS') == 'PRIVATE':
            # 非公開イベントは対象外
            continue
        
        # CSVへの書き込み

これでGASと同程度の柔軟さを持った上で実行時間を圧倒的に短縮することができる、、、はずでした。

課題

icsエクスポートは複数人でも可能なのですが、一定数を超えるとエクスポートされません。実際10人以下で検証した際には一括でエクスポートできましたが、いざ全社員分をとなるとエクスポートされない(エラーにもならない)事がわかりました。ドキュメントの記載は見つけられませんでしたが、何かしら件数の制限があるようです。

また、icsファイルには非公開イベントも含まれることから、一時的にとはいえそれらがファイルとして生成されることを避けるためため、この方法は見送ることにしました。

Step3. OAuth Clientでのデータ処理

最終的に採用したのは、ローカルマシン上からライブラリを経由してGoogle APIを呼び出す方式です。

Google公式ドキュメントの他にも様々な記事があるため環境周りは割愛しますが、この方式によっていつでも全社員分の最新スナップショットを2~3分で取得できるようになりました。

このデータを使えば、会議コスト算出や主催者ごとの傾向などをありのまま可視化することができます。

nextPageToken = '';
while(True):
    eventsResult = service.events().list(
        calendarId=[取得対象者のメールアドレス], 
        timeMin=[取得開始日時], 
        timeMax=[取得終了日時], 
        singleEvents=True,
        pageToken=nextPageToken,
        orderBy='startTime').execute()
    events = eventsResult.get('items', [])
    nextPageToken = eventsResult.get('nextPageToken', '')

    if not events:
        print('event not found.')
        continue

    for event in events:
        if event.get('visibility') == 'private':
            # 非公開イベントはスキップ
            continue
        if event.get('organizer').get('email') != [取得対象者のメールアドレス]:
            # 主催者とカレンダーIDが異なる場合はスキップ(招待されたイベント)
            continue
        
        id = event.get('id') if event.get('recurringEventId') is None else event.get('recurringEventId')
        cache = list(filter(lambda item: item['ID'] == id, result))
        if len(cache) > 0:
            # 繰り返しイベントの重複フィルター
            continue

        ## 書き込み用のデータ生成処理(省略)

    if nextPageToken == '':
        break

フィルター処理1. 招待されたイベント

Step2までと同様に非公開イベントは除外していますがそれ以外にも招待されたイベントは除外しています(コスト算出時のノイズとなるため)。

フィルター処理2. 繰り返しイベントの重複

今回抽出したデータは、最終的には目視などでフィルタした後は、後続となる更新処理(会議の削除や更新)のインプットデータとする予定です。

その際、繰り返しイベントは全件ある必要はないため、recurringEventIdで一意になるように抽出時点でフィルタしています。単純に出力後にフィルタしてもよいのでこのあたりはお好みとなります。

ハマった点1. OAuthユーザーや認可設定の変更方法

大まかな流れは ここ に従って作成しましたが、一度OAuth認証・認可した後にSCOPEを変更する手順が分からずにハマりました。

上記のクイックスタートに従っている場合には、token.jsonというファイルにaccess_tokenなどOAuthに必要な情報が書き込まれているので、このファイルを一度削除することで再度認証・認可を求められ、SCOPEや認証ユーザーを変更することができます。

※ 生成されるファイル名や場所は実装に依ります

ハマった点2. execute呼び出し漏れ

GoogleのAPIを呼ぶ際の作法として、listやgetなどの後にexecuteを実行してようやくAPIが呼ばれます。このexecuteはコールしなくてもエラーが起きるわけではなく、処理自体は正常に終了します(目的のデータが取れないだけ)。

サンプルとして提示されているコードもそうなっているのでコピペしている分には問題ないのですが、自分でコードを組み立てる場合にexecuteを忘れてしまい、原因調査に時間を取られました。

参照:https://github.com/googleapis/google-api-python-client

会議データの分析

取得した全会議データを分析し可視化していきます。詳細は こちら にまとまっています。参照先にもある通り、最終的には以下の条件で削除対象外となる会議を定めました。

ただ、機械的なフィルタではどうしてもヌケモレがあるため、安心安全なビッグバンのため上記にプラスして人手によるチェックで除外するイベントをFixさせました。

課題

会議ビッグバンを単発で終わらせずに、今後も再現可能な形で継続していくための一番の課題が実はこの人手によるチェック部分です。

どうやって目視チェックを減らせるかについては、極論会議ルールの整備と徹底(タグやプレフィックスのルール整備、繰り返しの場合は必ず期限を設定するなど)に尽きるため、今後運用をブラッシュアップさせていきます。

会議データの更新

インプットデータの準備ができたのでいよいよ会議ビッグバンになります。

当初は、事前のバックアップも取得済みのため未来の会議データはすべて思い切って削除する想定でした。

繰り返しではない単発イベントはそのまま削除し、繰り返しイベントも “これ以降のすべての予定” を選択して削除するイメージで考えていました。

ただ、残念ながらAPIではこのオプション相当の挙動を指定することができません

余談1. Google Calendar Events Deleteの挙動

Calendar Eventsオブジェクトは単発のイベントの場合には26桁のIDを持っていますが、繰り返しイベントの場合、以下の通り26桁のIDと日時データの組み合わせになります。

単発イベントのIDの例 繰り返しイベントのIDの例
7ed7uj5aou6b3m48t4kgodt2ql 7ed7uj5aou6b3m48t4kgodt2ql_20231030T200000Z

上記のように26桁のIDでイベントを識別し、その上で繰り返しの場合には日時を付与することで個別に特定できる仕様になっています。なお、繰り返しの場合 recurringEventId というフィールドに別途26桁のIDが設定されています。

そして余談の本題(?)ですが、Calendar Events DeleteAPIではパラメタには上記IDを指定できますが、 繰り返しイベントの場合、26桁のIDを指定すると繰り返しイベントが過去のイベントも含めて全て削除されます。日時付きのフルIDを指定すると、繰り返しイベントのうちの特定イベントのみを削除することができます。

余談2. GoogleカレンダーからEvent IDを確認する方法

APIで取得する以外にもブラウザからイベントIDを確認する方法があります。通常アクセスしているGoogleカレンダーのURLの末尾に ?eventdeb=1 を付与してアクセスします。

IDを確認したいイベントをクリックし、3点ケバブメニュー(?)をクリックすると、通常は表示されない トラブルシューティング情報 というメニューが表示されるのでクリックします。

すると以下の情報が確認できます。このeidがEventIDです。その他、繰り返しイベントの詳細な設定であるRRULEなども確認することができます。

イベントの削除. 単発イベント

ここから本題へ戻ります。上記の通り、単発イベントの場合には単純にdeleteできます。

前述の分析フェーズでの成果物であるcsvファイルをループで確認しながら、単発イベントでかつ削除対象外の場合のみ以下のコードで削除していきます。

service.events().delete(
    calendarId=[対象メールアドレス], 
    eventId=[カレンダーID], 
    sendUpdates='none').execute()

なお、バックアップがあるとはいえ、更新操作となるため入念に準備をしてから実行することをおすすめします。

イベントの更新. 繰り返しイベント

繰り返しイベントに対する削除は、特定イベントかもしくは全件しか対象にはできません。そこで、削除するのではなく繰り返しイベントの終了日を指定する(更新する)ことで将来のイベントを全てなくすことにします。

  1. 対象繰り返しイベントのrecurrenceを取得

    フェーズ1の会議データの取得では実は繰り返しの詳細な設定データは取得していません。単純な削除であれば不要だからです。

    ただ、繰り返しイベントの終了日を設定するためには、現在の繰り返しの設定が必要になります。

    以下のコードでイベントの詳細データを取得し、そこから繰り返しの設定である recurrence を取得することができます。

     service.events().get(
         calendarId=[メールアドレス],
         eventId=[イベントIDの]).execute()
    
  2. recurrenceの更新準備

    上記で取得したデータの recurrence には以下のような繰り返しの詳細が設定されています。

    RRULE:FREQ=WEEKLY;WKST=SU;COUNT=4;BYDAY=SA

    もし期限がある場合には

    RRULE:FREQ=WEEKLY;WKST=SU;UNTIL=20240331T145959Z;BYDAY=SA

    のように UNTILというエントリが設定されています。イベントにUNTILがあってもなくても、指定した日付を指定したUNTILをUpsertして準備します。

  3. イベント更新

    イベント更新はUpdatePatchの2つの方法がありますが、特定属性だけを更新するためPatchを利用します。

     service.events().patch(
         calendarId=[メールアドレス],
         eventId=[対象イベントID],
         body={"recurrence": [2で準備したrecurrence]}).execute()
    

これで会議ビッグバンの完成です、、、と言いたいところですが未解決な課題があるのでそれも記しておきます。

未解決の課題

上記の削除・更新で概ね意図した状態にはなったものの、一部で繰り返し期限が設定されているにも関わらずその期限を超えても存在しているイベントがありました。

具体的な条件としては、繰り返しイベントのイレギュラーパターンでこの事象が起きていると考えられます。例えば毎週月曜日開催だが、特定の週だけは火曜日開催となっているケースなどです。

このケースにおける recurrence の指定方法については、もうひと工夫必要なようですが、現在調査中となっており、次回ビッグバンまでには解消させたいと思います。

まとめ

ここまで、会議ビッグバンのためのデータ取得から更新までの試行錯誤やTIPS、ハマった点をまとめました。

ちなみに終始とてもスマート・スムーズにことが運んだような書き方になっているかもしれませんが、準備期間含めてビッグバン当日は想定外のデータが噴出し、一部は手作業で(震えながら)対応しました。

udonさんの記事にある

何がいいたいかというと、再発行できるものはなんとかなるということです。不可逆な人の信頼や家族、大切な友人は失ってはいけません。会議をなくすことはこわい気持ちもあるかもしれませんが、いつでも再発行できるので強い気持ちで明日も生きていきましょう。

この気持ちで完遂することができました。

次回開催時にスムーズに実行できるよう(震えなくていいよう)に、記録としてまとめています、いつか誰かの参考になれば幸いです。

なお、いきなりビッグバンは難しい場合でも、全社的な会議開催状況を取得して可視化するだけでも相当のインサイトが期待できます、ぜひみなさん会議にビッグバンを!

期待に応えながら自由に仕事を楽しめるお会計チームの文化

はじめに

こんにちは!ソフトウェアエンジニアのyamakazuです。

普段はお会計チームで開発課題をなんとかする役で立ち回っています。

10月から下期が始まったことで、社内で「開発イシュー」と呼ぶ実装課題の大枠が定まり、チームのギアも徐々に上がってきました。

対して9月は上期を振り返るシーンが多くあり、お会計チームは総じて良い成果を残せた期だったなと振り返っています。

体感値での手応えもそうですが、計測数値にも表れていて、チームがQA Processをパスしてリリースしたプロダクトへの変更の数はチーム比較で見ると1番多かったです。

(2023上期にQA Processをパスした数)

色々な前提条件や状況があるので、一概にこの数字の妥当性を比較評価できるものではないとは理解しているものの、それでも自分たちがそれなりの成果を残したことは証明できると思っています。

この生み出した変化幅は何を起因としているのか?を考えてみると、それはチーム文化が一番大きい様に思えました。

チーム文化は多様な変数で生み出されるため、再現性は低いかもしれません。それでも今の時点でお会計チームに生まれている文化を今回は紹介してみようと思います。

チーム文化に関心のある方の参考になれば嬉しいです。

背中を合わせる

お会計チームにある一番強い文化は「背中を合わせる」です。

チームのイシューに集中すること、界隈でよく見る言葉で言い換えると「コトに向かう」を考え方の前提に置いた上で、みな背中を合わせて仕事しています。

メンバー構成は Software Engineer 3 + QA/SET 1 + Test Engineer 1 + Product Manager 1のオーソドックスで、バランスの取れたフォーメーション。(カタカナ多い…)

エンジニアは1人1サブドメイン (決済, ポイント, 売上, 会員情報) に強いオーナーシップを発揮するポジションを取っており、オーナーでなくとも部分的に知識を有していたり、領域を2人が持てる様な状態を意図的に作り出して、双方にフィードバック可能な状態を作っています。例えば、決済と売上, ポイントと決済, ポイントと会員情報の様な感じ。

これをとある界隈の言葉を借りて類推すると "初期配置と二次配置を決めておく" です。

(他チームの他職種であるメンバーとも密にコミュニケーションを取る)

職種や立場に関係なく、皆プロ意識を高く持って仕事をしているので、イシュー解決に奔走している時には過度な介入はしません。

だからといって「サポートしないのか」というとそんなことはなく。推進方針の相談やレビュー依頼、定常業務のローテーションなどを適宜相談して調整し合うことで、最終的にチームイシューが解かれやすい状況をメンバーの関係性で意図的に作り出す様な立ち回りをしています。

具体的には、Aさんが今重要な局面に入っているなら、問い合わせやアラート対応は一時的にBさんが受け持つ。Cさんが過度にイシューを持つ状況になりつつあるなら、Dさんが介入して量を減らしにかかるなど。

チームで「コトに向かう」ために互いに助け合いながら立ち振る舞い、最終成果をみんなで分け合う。決して独りよがりではなく、相互に信頼し合いながら、個々の可能性を信じながら目の前の課題を全力で解く。

チームに起きている現象を表すのには「背中を合わせる」が言葉として最適でした。

理想からの逆算

2つ目にあるのが「理想からの逆算」です。

会社のValueとしてThink 10xという哲学があります。この哲学に沿う形で、お会計チームでも常に「理想は何だっけ?」という問いを考え続けて業務を進めています。

(BizDevとPdMとコラボレートしながら理想を追求する)

お会計チームの理想は「安全で容易に影響力の大きな成果を出し続けられる状態の実現」です。

これはあくまで自分の意見ですが、おそらく他のメンバーも同意してくれるのではないかと思っています。

金銭や個人情報が関係するドメインである以上、安全性は外せないのと、開発と品質保証の負荷が他ドメインよりも高くなってしまうのは避けられません。

だからこそ、構造的に、あるいは仕組みとして成果の安全性を容易に担保できる状況を作ることにこだわりながら、つまりは理想から逆算して考えながら、日々の業務を組み立てて成果を作っています。

具体的にこれが現象として表れているのはリファクタリングです。

自分たちは積極的にリファクタリングを行って成果を出してきました。

リファクタリングは短期で見ると遠回りしているようにも見えます。しかし、仮に20時間を先行投下することで将来定常的に月5時間かかる業務を1時間で済ませられるようになる場合、およそ5ヶ月で投資回収が見込めます。

すごく単純化した計算例ですが、意味のある先行投資であることが仮説立てられ時点で、自分たちは躊躇せずにそこに時間を投下して成果を獲得してきました。

時には理想を諦める意思決定をすることもありますが、積極的に先行投資に向かう姿勢を持ち、中期での成功を掴む姿勢がお会計チームにはあります。

責任と自由

お会計チームには「責任と自由」があります。

ここでの「責任」とは、事業本部や機能本部からの要求に応えることで、「自由」とは自分たちの願望の実現です。

チームが半期で取り組む開発イシューのおおよそ7割はトップダウンで決まります。

(2023下期のお会計チームイシュー)

「事業目線ではここまで行きたい」「機能本部としてはこの問題だけは必ず解決したい」といった要求が練り上げられたイシューが2~5個のリストに挙げられ、その内自分たちの目線で見てもこれは解決したいと思えるイシューを1~3に絞って必ず達成するようにコミットします。

イシュー自体はBizDev, PdM, EMのメンバーが緻密に練り上げて選び抜いたものであるため、納得感があり、認識や理解の齟齬は起きづらいです。2023下期はすんなり決まりました。

もちろん順序や詳細の部分ではチームの立場でフィードバックをするシーンはあります。

それでも大枠は事業本部や経営の意思を信じて、これまた「背中を合わせる」気概で素直に受け入れ、自分たちは最善のHowを考え抜いて期待に応える開発をします。それがプロフェショナルとしての振る舞いだと、チーム内では暗黙的ですが、そう合意が取れているように思います。

残りの3割は遊びとしての自由です。これは責任を果たし切った上で、自分たちが得ている余白とも言えます。

“3割は何に使っても良い” という考えでいます。

仕事を好きなタイミングで休んで良いし、創作活動に使っても良い。より高いパフォーマンスを発揮できるように仕事環境を整えるでも良い。

責任を果たしていれば何も縛るものはありません。ちなみに、この文章も自由な時間で書いてます。

期待される責任にきちんと応えながら、”自由に働く” を目指すチームでありたいです。

最後に

お会計チームに生まれている現象から類推できる文化を紹介してきました。

“お会計”という言葉から、お堅いイメージを持たれることが多いです。

言葉からの推論の通り、実際の仕事もほぼイメージ通りお堅いものが多いのですが、それに向き合うチームはここで挙げた特徴を備えた文化を形成して日々成果を作っています。

どうでしたか? 「堅い」とは真逆の「自由」といった考えを持っていて、意外な印象を持たれたかもしれません。

お会計チームは、外からの期待に誠実に応えながら自由に仕事を楽しめるチームこそが良いと考え、日々プロフェッショナルな意識を持つメンバーが働いています。

チームのイメージをここまでの内容で掴んでいただけたら嬉しいです。

上期のペースを維持して、下期も大きな成果を残せるように頑張っていきます。

今回はソフトウェアエンジニア目線でのチーム文化を取り上げて見ましたが、チームの品質管理部のメンバー目線での動き方が以下の記事で紹介されているので、こちらも合わせてぜひ読んでみてください。

product.10x.co.jp

宣伝

10Xではソフトウェアエンジニアを募集しています。

もし、お会計チームに関心を持っていただけたらぜひ1度お話ししましょう。🤝

カジュアルにお話しできるので、お気軽にご応募ください。

open.talentio.com

会議全部ふっとばして社員の集中力を10xした話(ビッグバン)

こんにちは!経営企画の仕事をしているudonです。1年半前の見習いQA以来、2度目の文章です。今回は10X社内の会議のルールを整理し、そして全社員の未来のカレンダー予定を一旦全部消す、通称「ビッグバン」の第一回を実施したのでその背景や内容について書きます。

(イメージ)

10Xでは社内におけるコミュニケーションを大きく「同期」「非同期」に分けています。同期は会議や突発的な電話など同じ場にいることが前提であるコミュニケーションを指し、Slackなど非同期は必ずしも同じ時間での往復を前提としない文章やドキュメントによるコミュニケーションを指します。入った当初は「ドウキ・・?ヒドウキ??」とドキドキしてた私ですが、2年も経つと慣れてしまいました。慣れって怖いですね。

話が長いという皆様の期待を裏切ることなく、タイトルにもなっているビッグバン(会議の全削除)の話にいくまで5,000文字嵩んでしまったので、ビッグバンに興味がある方は全部読み飛ばして「Step 3: 会議の全削除(ビッグバン)の実行」までいってください。

見直しの背景

10Xの非同期コミュニケーションにはSlack(蓄積していかないフロー情報のやりとり)、Notion(蓄積すべきストック情報*のやりとり)が使われています。これらは1年前に整理をしています。

note.com

なお10Xではドキュメント文化と、当初からSlack/Notionが浸透しているため、コミュニケーションに使うツールでのゆらぎはありません。他社の話を聞いていても、一部の部署はGoogle documentに残ってしまっていて、、といったコストがないのは実行者としてラッキーだなと感じます。

当時非同期コミュニケーションについての見直しを行った際に、同期コミュニケーション(=会議)については後述するNo MTG Dayの導入のみで、具体的な定義や仕組みの導入まではしていません。それから1年経過しメンバーも2倍近くに増え、組織の拡大とともに接点をどう持つのが良いのかは難しくなります。そのこともあり社内でも「会議が多い」「集中した時間の確保が難しい」という声を聞くことが増えました。そうしたことから、当時は見直しの対象外であった同期的なコミュニケーションについても、見直しをかけることにしました。

*なお1年経って経過を見ていると、slack = フローはかなり浸透していると思いつつ、notion = ストックと一概にも言えず、フローもかなりあり悩ましいなと思っています。このあたりはまだ整理はできていませんが、下記のような整理を進めていくと良いのだろうとぼんやり考えています。

kakehashi-dev.hatenablog.com

Step 0: No MTG Dayの導入

「集中した時間が確保が難しい」については1年前からも上がっていた声でした(or どの会社もそう?)。その対策として、Notion/Slackの見直しにあわせ、No MTG Dayの導入というのは先んじて行い、この1年間運用してきました。

下記のように経営会議や全社会議といった社内の公式の会議体を起点に、曜日別のサイクルを示した上で、水曜の午後のみ定例の会議の開催を原則禁止、というルールを導入しました。

導入当初ならびに1年経った今でもNo MTG Dayの評判はよく、少なくとも5日のうち半日は集中して取り組める時間があるということが生産性の担保や心理的なハードルの低さに繋がっているようです。振り返ると、どの曜日に設定するか・1日or半日といった論点はありましたが、あえて半日にしたことが「少なくともここは死守」という牽制を社内でも相互にかけられるようになったのではないかと考えています。

曜日について、正解はないとは思いますが、10Xでは水曜の11−12時に全社会議を実施していることから、一定社内でのワイワイ感は味わった上でそれぞれ集中時間を持てるといった流れが功を奏しているように感じます。週ナカということも良いかもしれません。実際導入前にヒアリングする際には「◯曜日がいい」「午前 / 午後がいい」といったゆらぎはみられたものの、最終は決めの問題なのでエイヤで決めました。◯曜日がいいという意見は今も聞くし、今後も変わりうるかもしれませんが、ないよりはある方が皆ハッピーだろうと割り切っている部分もあります。

また、形骸化しないか?というところは心配していましたが、a) 社内のリテラシー b) そもそものニーズの高さ(例 「木曜にできませんか?」といったオープンなコミュニケーション) c) 口酸っぱく言う といったことで概ね実効性をもっていると言えるかなと思います。

FB、だいじ

Step 1: イシューの抽出、ヒアリングの実施

現状理解

10Xの社員は120人です。まずは8月の実績を抽出し、現状理解を進めました。Corporate ITの原口さんにログを抽出してもらった上で、スプレッドシートで集計しました。

また、後述するように会議の主催者の自覚を強めたかったという思いもあり、主催者である人がどれほど時間を費やしているかも可視化しました。また、後述するように会議の主催者の自覚を強めたかったという思いもあり、主催者である人がどれほど時間を費やしているかも可視化しました。これは単純に順位が高い = 悪いということではないですが、皆自分の順位は気になるため、ヒアリング実施する際などの材料としてはよく機能したし、一度見直すきっかけにはなったかと思います。

イシューの抽出

前回のSlack/Notionの見直しでもそうでしたが、まずは何を解決するのか(=イシュー)の特定をします。イシューの特定のためには自分の頭で考えること、及びヒアリングやリサーチが重要ですが、今回は(社内の雑談や飲み会で)ある程度メンバーの課題意識はクリアであったため、下記のように書き下しました。

  1. 会議のオーナー(主催者)の役割と責任を明確化し、ルールが定義されている
  2. 会議の参加者としての心構えが定義されている
  3. 会議の実施量が可視化され、モニタリングされている状態を担保する
  4. 足元の会議の重複や過不足を解消し、定期的にチェックする仕組みを作る

💡 10Xでは「イシュー」という言葉がよく用いられますが、「〇〇をどうするか?」(疑問形)や「▲▲が最適化されていない」(問題提起形)ではなく「□□を構築する」(あるべき姿系)という形式が多くとられています。 (10XのNotionを引っ越しした話より)

ヒアリングの実行

その上で仮説のブラッシュアップと実ルールや仕組みの検討のためヒアリングを行いました(15件程度)。対象は役職者及びメンバーです。メンバーは各本部それぞれに + こうしたことに感度の高いメンバーを独断と偏見で選びヒアリングを実施しました。もちろん意見があればオープンに受け止める場は作るという前提はありますが、こうしたことを進め実行する上で皆の意見を聞く・全社アンケート等は必ずしも必要でないと私は考えます。もっと言えば、ヒアリング = 御用聞きではないため、抽出した意見をすべて反映できるわけでもなく、「話を聞いた」という証跡を残すことで納得度を高めルールや仕組み導入後の実効性を高める側面もあると思っています。

ヒアリングを経ての所感

前述のように今回は仮説構築のためのヒアリングというよりも、イシュー(≒課題)をある程度定めた上でヒアリングを実行しました。そのためヒアリング前後で向かうイシューを大きく変更はしていません。ただし、ヒアリングを踏まえて私自身の課題意識に影響が大きかった点が2点あります。

1/ ライン外1on1が多すぎる

10Xでは、カジュアルなものから業務の話まで「1on1」という名称で1対1のコミュニケーションが多く見られます。今では慣れましたが、スタートアップ及びソフトウェア企業が初めてだった私は当初新鮮でした。1on1はうまく使うと効果的なものですが、同時にリスクのあるものだとも思っています。

特に、私はライン外の1on1に対しての課題感が強いです。ライン1on1(社内ではライオン🦁とも呼ばれる)とは、評価者と被評価者との1on1であり、これは評価やメンバーのモチベーション維持のためにもきちんと実行がなされるべきものです。

一方ライン外の1on1とは、別の部門やチームの特定の個人との接続になります。もちろん部門横断で部門長が話す、といった場が効果的に機能する面もあるでしょう。ただし1on1、その中でも業務の話が中心になりやすいライン外の1on1については、そこに情報が閉じてしまうリスクを孕んでいます。ある人と話したことを定例、あるいは再度別の人と話すということも発生しえ情報伝達のコストが上がります。正直人数の多い定例の場よりも役職者への1on1があれば、その場の方がいいやすい、といったことはあると思います。ただCEOのyamottyが常々言っているように「平場で話す」*ということを常に問うべきだと思います。また平場で話すことは、話した本人以外の姿勢にも影響を及ぼすことだと思います。DMはなるべくやめましょう、という声がけをする会社は結構あると思いますが、こうした会議や1on1についても目を向けるべきと思います。

なお今回会議のあり方の見直しを行う上でヒアリングをしていると、ライン外の1on1について、役職者上位者からは「なくてもよい」、下位者(あくまで組織図上の表現です)からは「残したい」ということが多かったです。情報を得る、又はレイズするという意味で1on1の場は便利な側面もありますが、同様に情報取得やレイズが既に存在する部門定例等で担保できないか?は招待側も被招待側も一度考えていただきたいというメッセージも出しています。過去のなりゆきで残っている1on1について、経営や本部長であっても、完全に関わりがないわけでもないし辞退するのもなァ..という声もあったゆえ、今回のビッグバンによりかなり減る可能性を持っているのではないかと思っていました。(実際に定例のライン外1on1は300件 —> 100件に減った)

ビッグバン実行の際の告知には下記のようなコメントを入れました。

1点注意点としては、上記のライン外1on1については「定例(かつ無期限繰り返し)をやめましょう」というメッセージが強いです。逆に単発のレイズはもっとあって良いと考えています。定例のライン外1on1が10件以上もある役職者もいたため、今回の見直しにより余白がうまれ、メンバーからも単発のレイズがあげやすくなることを期待しています。

(何かに笑っているCEO)

2/ 会議主催者の責任感は伸びしろがある

10Xではあまり不毛な会議は少ないと考えています。他方で、組織の変化が大きいゆえ、もうその組織にいない人が主催者の会議が残っていることも。全員がなぜこの会議があるかわからない、までの極端なものはなくとも、これってそういえば何が目的なのでしたっけ?というものは意外とあるんだなという所感でした。

これは主催者が強いオーナーシップを持ち、その開催意図や目的の想定、そして解散も含めた期限の設定をすべきです。そのため今回「会議オーナー(=主催者)」と「参加者」に分けて特に主催者が何を満たすべきか、そして参加者は何をフィードバックして良いのか、ということを明示する必要があると感じました。

Step 2: 会議のルールの素案作成

さて、ビッグバン(会議を消す)話に中々いきませんが辛抱ください。余談ですが私は話が長いと良く言われます。それは2割は厳密さの担保のため補足事項が長くなること、それから8割は単純に余談が好きという性質ゆえです。「文章なのに話してるみたいに話が散らかってるね」という褒め言葉を折に触れて頂くのですが、先日はついにconclusion firstと言われる英語の文章でも同様のコメントを頂き、グローバルになったなァとひとりごちてました。

medium.com

さて本論です。

なぜ会議のルールを定義するか

今振り返っても社内のメンバーの印象はビッグバン(会議を消す)ところが大きいですが、イシューとして記載したように、会議がどうあるべきかの定義をしないと、会議をビッグバンしたとしてもまた会議の量が増えたり、質の改善も望めません。10Xは無駄な会議や準備のされていない会議は少ないですが、それゆえ特にルールや心がけについても特に定められたものはありませんでした。それゆえそのルールの定義を行いました。

会議には大きく分けて主催者と参加者の2つの役割が存在しますが、結局のところ会議を通した成果責任を負えるのは会議オーナー(=主催者)です。なぜなら会議の目的・アジェンダ・時間・招待者といった変数の殆どは会議オーナーによって規定されるためです。会議オーナーはこの責任と権限を認識し、そのための必要な設計と準備、及び期限を設定すべきです。そのため全体のルール、及び会議オーナー向けと参加者向けの詳細を作成しました。これらの文言は、私udonがドラフトの上、経営会議、特に本件について熱量の高かった我らがCTO Ishkawaの監修のもと記述をしました。

Ishkawaさんはスライドが(私とは対照に)衝撃的に少ない文字数でわかりやすく物事を伝える達人なのですが、イシューを解くためには会議が本当に解決策か?ということには課題感があったようです。下記ルールに記載にある「コトをなすには、i) 誰かが頭を捻って考えた上で、」は石川さんの言葉を借りています。

ルール制定の背景と全体ルール

会議オーナー(=主催者)と参加者の責任と権限

ルール詳細(主催者向け)

ルール詳細(参加者向け)

Step 3: 会議の全削除(ビッグバン)の実行

さて、本稿の主題である会議の全削除(ビッグバン)についてです。

実行内容

内容としてはその名の通り非常にシンプルで、全社員の未来の予定を全削除する、平たく言えば会議をぜんぶふっとばすということをしました。但し下記のお知らせの通り、社外や共有カレンダーにの予定等は削除の対象外としました。

除外の処理

特に実行の上で注意を払ったのが社外の予定です。社外面談にしろ採用面談にしろ、相手方からするとすっぽ抜かしてしまうと大問題です。実際の実行にあたっては性能と柔軟性を重視して、ローカルでのpythonでの実行に切り替えました(当初はGASでの実行を想定)。下記のようなロジックを作って安心安全な実行に努めました。

  1. 主催者が社外(社外アドレスから招待されているもの)は削除対象外
  2. 10X社員が主催者だが招待アドレスに@10x.co.jpでないものは含まれる場合は削除対象外
    • 細かいが、社内の会議だが会議室をとるために会議室のアドレスが招待に入っているものは識別して社外とならないような分岐を作り削除対象とした
  3. 詳細欄にZoomのアドレスが含まれるものは削除対象外
    • 10Xは社内はGoogle meet又はSlackハドルのため、Zoomが入っているものはすべて社外という実態があったため

率直に言って、これだけでは識別されないものもありました。例えば「〇〇社様 調整中」という社外との調整中の予定で社内メンバーのみ招待されている予定。第一回ということもあり、こうしたものの漏れはゼロにしたく、最後は私が1,700件の予定名を手作業で確認してQAしました(QAの経験とコネクティングザドッツしてますね)。「社外」「会食」といったキーワード検索及び目視での確認を2周しました。基本的にはタイトルで識別できると考えており、実際実施後クレームはきていません。

今後は半期に一度実施しようということになっており、今回の経験も活かし次回はより手作業を自動化する・prefixで「社外」と記載のあるもののみ残す、といったことはできていくと信じています。

再度の予定入れについて

再度の予定入れについては、実行(火曜日深夜)の後1日を挟んで、木曜朝(10時〜)開放としました。1日あけたのは、10XはNo MTG Dayである水曜日に一度真っ白なカレンダーを眺めるという余白を挟んでから再度入れること、及びなるべく早いもの勝ち(になってしまう側面は避けられないが)を軽減したかったからです。

前述したように主催者は特にそれを自覚いただきたいという思いがあっため、下記のようなフローチャートや主催者(オーナー)については記載の上告知しました。

実施のきっかけ

このビッグバンですが、きっかけはある日思いついたというのが正直なところです。私は走りながら考えるタイプのため、色々な人と日々話す中で、「皆会議減らしたいと言ってるのになぜ増えてしかいかないのだろう」という思いから、「じゃあ一度消しちゃえばいいんじゃないか」と乱暴なアイデアを思いつく。そこから社内でちょくちょくアイデアを当ててみると、見事に話した人全員(N=15程度)が賛成だったので、経営メンバーにあてて、実行が決まりました。

削除対象のログはすべてリスト(スプレッドシート)へ出力して参照可能にし、またカレンダーの情報であるicsのバックアップ方法(Googleカレンダーで数分で可能)も案内しているため、必要な会議は戻すことができリスクはほぼないようにしています。

前回のSlack/Notionの見直しの際もそうですが、こうしたことはトップダウンでやらないと難しい側面もあるため、特にCEOのyamottyとCTO Ishkawaの賛同を得られたことは大きかったかなと思います。

社内コミュニケーション

賛同が得られても、ある日いきなり消されても困ってしまいます。着想から実行まで約1ヶ月強でしたが、3週間前には週次の全社会議での一度実行の告知、ならびに1週間前に詳細の告知を行いました。

結果的にはスムーズにいったかなと思いつつ、実行にあたっては特に一緒に密に動かしていたCorpITの原口さんと「この時間軸だと安心安全の実行は難しい」「実行にどうしても時間がかかる」といったように健全な意味でぶつかりあいながら実行まで至ることができました。この場を借りて感謝したいと思います。準備の中では、文字通りログの抽出のスピードが100xしたこともあり、このあたりの技術的側面はかなり知見が溜まりました。このあたりはきっと原口さんが追って記事を書いてくれるはずです。

After story: 結果と振り返り

実行からまだ1週間しか経っていないこともあり、あくまで暫定での振り返りとなります。1週間経って、大体定例会議や必要な1on1は入った印象なので、一旦の振り返りとして記します。

定量面

1/ 会議の総量

全体の会議の比較です。正直まだ社内の懇親会のようなものも会議として出力されてしまっていて、本質的な比較ができていない状況ですのであくまで参考まで。例えば直近は期初のため社内で目標設定の面談(単発)が多くややそれらがややノイズになっていそうです。

2/ ライン外1on1

310件 —> 127件 (▲60%)

これは全体に比べて正確に出力できているので、比較できていそうです。当初課題感が強かったものの一つですが、これは明確に影響が出ています。実際、招待を送ったが辞退、あるいは見直しといったものも起こっているようです。

ライン外の1on1自体が悪というものではなく、適切な場で担保されるのが望ましいと思っています。社内での声を聞いていても、かなり整理されたという声を聞きます。また復活しても形式や頻度を見直した、という声を聞きます。私の上司の山田さんは14件から3件になっていました。

定性面

1/ 物理的に余白が生まれた

シンプルに余白が生まれたことでの喜びの声が届いています。シンプルに作業時間が確保できたことでコトをなすことへ集中力が高まっていると言えます。

繰り返しになりますが、会議が一律にNGというよりも、既存の他の会議体へのマージであったり、単発でアジェンダベースで実施するということを考えて頂きたいと思っています。

2/ 会議の位置づけの見直しが生まれている

そもそもこの会議のオーナーって私でしたっけ?どうしますか?という見直しが各所で起こっています。

余談1: ルールというものの立ち位置を考える

会議のルールについて告知をし、ビッグバンを実行しました。会議が減ったり見直しがかかっているという嬉しい報告も色々と聞こえてきています。その中で一つ困ったことが私の中にありました。それは、今回設定した会議「ルール」なるものはどういう立ち位置なんだ??という疑問です。

私もコーポレート部門で経営企画の仕事をしていますので、どちらかというと社内向けに案内やルールを出すことが多い立場にいます。10Xでは経営から積極的に方針のアナウンスもあります。「ルール」や「ガイドライン」など、「決まり事っぽいもの」が色々と増えていきます。社内のドキュメントを見ても「指針」「ポリシー」「ガイドライン」「ガイド」「ルール」etc.. 色々とゆらいでてウッとなります。私は自由を標榜する民なので、あまり縛られたくないなァと常々思ってます。その中でじゃあ自分が主体的に今回出すものは何に基づいていて、どういう強度のものなのか?ということに疑念が芽生えました。実際、今回策定した会議「ルール」についても最初は「ポリシー」「ガイドライン」とゆらいでいました。

そこで今回そちらの初期的な整理も行いました。結論から言えば23/10時点では、10Xでは下記のように「指針」というものが第一階層にあり、それ以下のルール(強制力あり)やガイド(強制力なし)が紐づく、という整理をして経営メンバーとも認識を揃えました。

新たに「指針」というポータルも作成しました。全社員が10Xにおける指針を見る際にはここにいけば良いという認知負荷を下げることを目指しています。また「指針」階層のものがボトムアップで乱立せぬよう本ポータルの編集権限は経営メンバーのみ、といった制御もかけています。

なおこれらはあくまで初期的整理と場所を作ったということであり、実際の整理は今後進んでいくものとしています。

今回の会議ルールについては10X オープネス指針に紐づいているという整理をしていますが、この指針自体も別の指針にマージされたりする可能性もあるかと思います。コーポレートに限らず事業部もその中でのルールやガイドを日々作りますが、それらもどの指針に紐づいているか?を明示することで、部門横断での情報へのアクセスのコストが下がると信じています。

余談2: いかに運用に落とすか

ソフトウェアの会社、そしてスタートアップが初めてだった私にとって10Xに入ってからの2年間で学んだことの一つは「いかに運用に落とすか」という問いを立てることです。経営企画という、中長期の未来のことを考える立場にありながら、私の好きな言葉は「刹那」で、友人からも「打ち上げ花火みたいに色々打ち上げて、たまに大きく花開くよね」と褒められ(?)ます。

一方ソフトウェアの世界では、(※私の視点ですが)いかに人が介在しない形で属人化しないか、(自動)運用に落とすかということが問われます。コーポレート側でも、元々こうした思考やスキルが高いメンバーが多いので、それこそ具体ではZapierやSlack WF、GPTを活用していかに人間が考えなくとも運用が回るかということを考える機会が多いです。

今回のビッグバンの実行、ならびにルールが実効性を持つためには、それを推し進める人のパッション(例 わたし)はやはりあったとは思っています。会議の再度入れも、悪気なくすぐ入れてしまったメンバー(含む 経営メンバー)にも強い気持ちでストップをかけていたりします。

今回のビッグバンは社内でも好評であり、「次はいつですか??」という問い合わせも複数あるため実行されるであろうと思っています。実際の実行にあたっては前述のCorpITのメンバーが完全に担当してくれており、私は当日の見守りも不要ということだったので完全に手を離れています(私は酒を手にしていました)。ルールについては完全に仕組み化が難しいですが、例えば「無期限繰り返しのイベント設定は原則禁止」については、月次でログを抽出し、繰り返し期限のカラムが空欄のものに対してFBをかけるといったことを考えています。(なおこれはGASで一気に流し込むという方法もありつつ、そもそも一生必要な会議なんてないというメッセージも込め、一旦は人間にFBをするという判断をしています)。ルールの議論の際にも、仕組みに落とさないとルールはすぐ形骸化するしノイズになる、という議論もしています。

まだ運用に向けての改善点はありますし、きちんと運用がなされるかは今後次第ではあります。が、今回の見直しを経てメンバーのマインドへの影響は一定あると手応えを感じているので、今後も運用がなされると信じています。

余談3: Food for thought

food for thought (思考の糧)という言い回しが好きです。まさに余談ですね。今後考えるべきこと、みたいなニュアンスで書いていますが、今回はやりきれてないことを箇条書きで雑に書きます。

  • 会議ルールを自動で運用すための仕組みづくり(前述の繰り返し設定TRUEのものにFBをかけることに加え、議事録のテンプレの作成、Shopify流の会議コストの算出等)
  • 月次レポート(構想は描いているが、まだできていない)
  • 会議後のメモはどれくらい取るべきなのかのガイドの配備
  • 会議の種別の分類とprefixの設定(そもそもやるかどうかの含めての検討)
  • 個人的にブロックしている枠についてのガイドをつける(やってもよいが、新しくはいったメンバーや関わりの少ないメンバーのコミュニケーションの障害にならないように)
  • 1on1をもっと分解する。ライオンとそれ以外の役割の違いを明確化する
  • よりよい会議にするためのtipsの共有
  • 良い会議の定義、というと本が1冊書けそうだがせめてイマイチな会議の定義を作る(例 ゴール設定が曖昧、必要な人がいない・不要な人がいる、1回あたりの時間x頻度が最適化されてない)
  • 会議の実施時間を寄せたい、スキマ時間を生むための工夫
  • ランダムでもいいから、行われている会議の議事録がtwitter的に流れるのも面白いかも
  • トップダウンで設定する公式会議体の一覧とマスタを参照可能な状態な場所におく など

余談n: おわりに

お疲れ様でした。ここまで1.5万文字(しかも画像内の文字含まない)を読む人がいるのだろうかというセルフツッコミが溢れていますが、一旦書ききりました。

余談ですが、私はよくものをなくします。多分iPhoneは累計7,8回なくしています。財布は最近なくしてなかったですが、この前なくして4年ぶり5度目でした(甲子園強豪校みたいですね)。財布をなくすと困るのですが(困る度合いはものによって異なる*)、相方には怒られます。まあでも死ぬことはありません。また財布かって、お金を稼ぐ日々です。顔認証などですべての決済ができる世の中を5年以上前から望んでいますが、まだ世の中がついてきてくれてません。何がいいたいかというと、再発行できるものはなんとかなるということです。不可逆な人の信頼や家族、大切な友人は失ってはいけません。会議をなくすことはこわい気持ちもあるかもしれませんが、いつでも再発行できるので強い気持ちで明日も生きていきましょう。

そして最後の余談ですが、私はこの記事が最後の仕事で10Xを卒業します。個人的な事情でカナダのバンクーバーへ移住します。あまり込みいった事情もなく、日本も30年近く暮らしてきたので違う生活もやってみようというポップな感じです。仕事も特に決まってないので、空白からのスタートです。私はビッグバンを(会議を)吹き飛ばすニュアンスで使っていたのですが、どうも破壊よりも始まりっぽいです。なので私自身もビッグバンだなァと、PC返却を迫るITメンバーを背中に、最終出社日に鬼のようにこの1.5万字を打っています。

*再発行の工数はマイナンバー>免許証>銀行キャッシュカード>保険証>>>クレカ

月次ではアップデート(月報)を書こうと思ってます。またどこかで会いましょう!

GitHub Actionsのpermissionを粛々と整理した話

こんにちは、セキュリティチームの@sota1235です。

10Xのセキュリティチームではプロダクトに近い領域での権限管理に関して、リスク整理と対応を日々行なっています。

今回はその取り組みの一環であるGitHub Actionsのpermissionsに関しての取り組みをご紹介します!

続きを読む

StailerとPOS連携

はじめに

こんにちは! お会計チームのyamakazuです。

ドメインベースの開発体制に移行して以来、お会計チームに所属し、主に金銭に関わるドメインでの開発を担当しています。

「お会計」と呼ぶと勘定仕分け的なことを想像されるかもしれませんが、自分たちが「お会計」と呼ぶ領域は、決済やポイント、店舗売上といった金銭に深く関係する領域を指します。

今回はそんなお会計チームが受け持つドメインの中でも「店舗売上」に焦点を当てて、Stailerにおける店舗売上データの扱い方、記事タイトルでも示す POS連携 (Point of Sales 連携) をStailerを例に取って紹介します。

目次

  • はじめに
  • 目次
  • 多様な解釈がなされるPOS連携
  • StailerにおけるPOS連携
  • POS連携の実装と運用
  • POS連携を実装する難しさ
    • 共通仕様が存在しない
    • 仕様の把握が難しい
    • 文脈が異なる中で開発を推進しなければいけない
  • 難しさに対処するための考え
    • インターフェースの共通仕様を諦める
    • 部分的な抽象化と断片化の許容
    • 段階的なテスト実施 (開発テスト / 型テスト / 受け入れテスト)
  • まとめ
  • 最後に
  • 関連して
続きを読む