Classi開発者ブログ

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

なれる!データエンジニア

はじめに

こんにちは。データプラットフォームチームのマイン(id:manhnguyen1998)です。

2024年1月からデータエンジニア留学(第1期)という制度を利用して、データプラットフォームチームに配属されています。第1期生として、このデータエンジニア留学制度について、自分の経験をもとに紹介したいと思います。

データエンジニア制度とは

データエンジニア留学制度は基本的にSRE留学と同じですが、留学先はデータプラットフォームチームです。SRE留学に関する記事はいくつかありますのでご覧ください。

tech.classi.jp tech.classi.jp tech.classi.jp

なぜ留学したのか?

もともとバックエンドエンジニアとしてRailsのアプリケーション開発を行っていましたが、ある時社内のBigQueryでデータを見る機会がありました。どうやってRDSからBigQueryまでデータが反映されるのかに興味を持ち、データエンジニアの仕事に興味を持つようになりました。

その時、データエンジニア留学制度の告知があり、不安もありましたが、チャンスを逃すまいと留学を希望しました。

自分と同じようにデータエンジニアに興味を持っているけれど、不安でチャレンジしない方もいると思います。この記事で「誰でもできるよ!」ということを伝えたいです。

データエンジニアの仕事とは?

データエンジニアの仕事は、データ活用の基盤を作ることです。具体的にはデータの収集、処理、保存、提供などがあります。

Classiでは主に以下のようなことを行います。

  • 他チームのデータ活用の支援、相談、作業依頼

  • 改善活動

また、データエンジニアが使用するツールや技術はBigQuery、dbt、Cloud Composerなどがあります。

他チームのデータ活用の支援、相談、作業依頼

データ基盤は社内の多くのメンバーが利用しており、さまざまな意思決定を支えるシステムとなっています。そのため、データを活用する上で、データ基盤に対してもさまざまな要望があります

  • マーケティングチームは顧客の利用状況を把握するためにダッシュボードを作成したい
  • プロダクトチームがリリースした機能の効果測定をしたいが、方法がわからないので相談したい
  • データサイエンティストがデータ分析のためにデータセットを準備したい
  • データ活用に関するアドバイスやベストプラクティスを共有して欲しい

などの要望です。このような相談に対してエンジニアとして意見を出し、他チームの開発をサポートしていました。

改善活動

データ基盤の改善もデータエンジニアの重要な業務の一つです。データ基盤は膨大なデータを扱うシステムであり、うまく改善しないとデータの提供もできないことがあったり、コストも高くなることがあります。

改善活動として、私が対応したものは以下のようなものがありました。

  • データパイプラインをCloud Composer (Airflow) からdbtに移行する
  • データの品質を監視する環境の整備
  • コスト削減
  • 不要なリソースの削除

留学中にやったこと

BigQueryに抽出されたデータの欠損検知

データ基盤の毎日のデータ抽出には欠損リスクがありますが、欠損がある場合、これまで気付くことができませんでした。そこで、欠損を発見しやすくするための改善に取り組みました。

BigQueryに保存されたテーブルのレコード数の推移の異常を検知し、欠損など急な変化を検知できるようにしました。例えば、特にアクションがないにもかかわらず、レコード数が急激に増減する場合、データの欠損や何らかのミスが発生した可能性があります。逆に、繁忙期におけるデータの推移を監視することで、利用状況を把握することもできます。

Design

開発したSlack通知

通知の例

Tableau

TableのView

ダッシュボード機能のETLのdbtへの移行と改善

ダッシュボード機能のETLは元々Cloud Composerで直接クエリを実行してデータを管理していましたが、管理が難しかったため、dbtに移行しました。dbtに移行することで、データの処理や管理が容易になり、データに関する説明も整理することができました。

この機能は管理職が利用し、学校全体に関する統計情報を閲覧するため、その重要性が非常に高く、データに誤りがあると重大な影響を及ぼす可能性があります。そのため、dbtに切り替える前に、移行前後の差分確認をしっかり行い、慎重に対応しました。しかし、確認不足の部分があり、学校IDをクラスタキーとして使用することを忘れてしまったため、リリース直後に課金が増加してしまいました。この経験から、コストに対する理解を深めることができました。

このコストの問題を認識した上で、ダッシュボード機能のETLを見直す機会があり、毎日のスキャン量を約85%削減することができました。 ダッシュボード機能のクエリでは学校IDをクラスタキーとして使用していました。しかし、クラスタはクエリごとにスキャン量が異なり、効率的な測定が難しいという課題がありました。そこで、調査の結果、学校IDの空間でパーティションを使用することにより、スキャン量を削減することができました

GCPコストの削減

メタデータシステムPlatoをクローズ、dbtに移行

Platoは以前ブログでも紹介したメタデータ管理システムです。

tech.classi.jp

当時、メタデータの普及に重要な功績を残してくれたシステムでしたが、近年では運用コストが上がり、手間も増えたため、別の仕組みに移行するモチベーションがありました。

この対応により運用作業が減少し、毎月のGCPコストも削減することができました。既存のメタデータもdbt docsに移行でき、社内でのdbt docsの存在を改めて認識させることができて良かったです。

dbtに関しては下記の記事をご覧ください

tech.classi.jp

dbt docsの例

dbt docs画面

RedashのCloudSQLのPostgreSQLを9から15にバージョンアップ

データベースのメジャーバージョンアップデートは初めての経験だったので、最初から調査し、ダウンタイムを短くするための計画を立てました。作業自体は非常に勉強になりました。今回は20分以内に作業を終え、ダウンタイムを短く抑えることができてよかったです。

Slackでやり取りました

勉強になったこと

留学中に学んだことは技術に限らず、以下の点が特に勉強になりました。

分析力

データから仮説を立て、それをもとに結論や次のアクションを提案することができました。少しずつですが、分析について学ぶことができました。

チーム間コミュニケーション

留学の目標の一つはチーム間で協力することでした。自分のタスクに関わるだけでなく、SRE、マーケ、開発チームなど他のチームとも関わり、情報共有やコミュニケーションが必要でした。

「how」より「why」の考え方

以前はタスクに直接飛び込むことが多く、その理由がわからないまま適当な解決方法を出すことがありました。今回の留学で、「なぜ」そのタスクが必要なのか、誰がその成果を求めているのかを十分に理解した上で、適切な提案をすることが大切だと学びました。

難しかったこと

知識の広さ

データエンジニアは多くのチームと関わるため、求められるスキルは多岐にわたります。インフラ管理の知識、データ管理の知識、開発スキル、マーケ側とのコミュニケーション能力など、広い範囲で深く理解する必要があります。

横断的な振る舞い、考え方の難しさ

データプラットフォームチームは他のチームをサポートすることが多く、横断的な振る舞いや考え方が求められます。しかし、留学中はチーム課題に集中しすぎて、データエンジニアとして他チームをアドバイスして支援することが難しかったです。

あなたもできる!

データエンジニアは魅力的な仕事ですが、チャレンジも多いです。しかし、難しいからといってできないわけではありません。もともと何もわからなかった自分ができたので、誰でもできると思います。日々の仕事でスキルを磨き、必ず達成できます。

まずは小さなプロジェクトから始めましょう。このアプローチは、少ないリスクで新しいスキルを試し、成長するための確かなステップです。例えば、データエンジニアとして初めてのプロジェクトとして、日々のログデータから特定の指標を抽出するタスクを考えてみましょう。このプロジェクトでは、SQLクエリを使用してデータを加工し、分析結果をダッシュボードで可視化することが目標です。小規模なデータセットと少ないリソースで取り組むことで、自分のアイデアを具体的な成果物に変えるプロセスを学ぶことができます。

さらに、タスクを進めながら、メンターやチームに積極的に質問し、理解を深めましょう。この過程で、ソフトスキルも成長し、データエンジニアとしてのスキルだけでなく、チーム全体での協力や連携能力も養われます。チーム内だけでなく、インフラチームなど他の部門の意見も積極的に取り入れて、より良い成果を目指しましょう。

最後に

データエンジニアというキャリアは挑戦と学びの機会に満ちています。最初は不安でしたが、一歩踏み出すことで多くのスキルと知識を得ることができました。他チームとの協力や支援を通じて自分の成長を実感しています。

データエンジニアを目指す皆さんにも、その一歩を踏み出してほしいと思います。初めは難しく感じるかもしれませんが、挑戦し続けることで必ず成長できます。その過程で得た知識やスキルは、今後のキャリアに大いに役立ちます。

Classiのデータエンジニアに興味を持った方は下記をご覧ください

hrmos.co

Classiのエンジニア2名が RubyKaigi 2024 に参加しました

はじめに

こんにちは、エンジニアの id:kiryuanzu です! 今回の記事は 5月15日(水)から 5月17日(金)の3日間を通して開催された RubyKaigi 2024 の参加レポートです。

rubykaigi.org

弊社からは 2名のエンジニアが参加しました。本記事では各メンバーによる参加レポートをお送りします。

id:kiryuanzu の参加レポート

改めて今回の RubyKaigi 2024 に参加してきた id:kiryuanzu です。
自分自身は学生の頃(2017年)からほぼ毎年参加していますが、弊社のメンバーと参加するのは RubyKaigi 2022 以来で 2年振り 2回目となりました。

tech.classi.jp

前回と同じく初参加のメンバーにもできる限り楽しんでもらえるように意識しつつ、自分もたくさんインプットできるように心がけて過ごすようにしました。

発表の感想

Community-driven RBS repository (pockeさん)

Rubyの型情報を収集するOSSリポジトリである gem_rbs_collection の運用についての発表でした。
GitHub Actions のワークフローの仕組みを使いつつメンテナのレビューに依存しない運用に切り替えていった話について紹介されており、筆者もここ最近の業務で GitHub Actions を使って運用フローの効率化について考えていたため、とても親近感が沸く内容でした。
OSSリポジトリの場合、様々な人がコントリビューターとして関わる際に開発の効率性とセキュリティのリスクの双方を気にしつつ運用フローを考える必要があるのが難しいポイントだなと思いました。

発表が終わった後、早速ワークフローのコードを見に行ったのですが、ワークフロー内で呼び出すスクリプトを全部 Ruby で書いている点に強い Ruby愛を感じました。

github.com

スライド内でも「It uses Ruby scripts Because I love Ruby」と言及されていますね。

Adding Security to Microcontroller Ruby (sylph01さん)

PicoRuby に暗号機能を実装する話についての発表でした。
現地では英語発表で分からない部分も多かったのですが、とても楽しそうに話されている姿が印象に残っていました。その後、るびま(Rubyist Magazine)で日本語版が公開されていて改めて発表の内容について知ることができました。

magazine.rubyist.net

記事中の「Ruby での真のIoT」という表現がかなり印象的で、今後もまだまだやれることがありそうな雰囲気を感じました。

実際の IoT 環境ではこれらの違ったスペックを持つハードウェアは協調して動作させるので、PicoRuby が WiFi に繋がるようになったことで、「Ruby での真の IoT」は現実に近づいたといってよいでしょう。IoT に関するプロトコルは数多く存在しており、これらを PicoRuby で扱えるようにすることで、Ruby での IoT の可能性は広がっていくものと考えられます。このことから、Ruby での IoT は「ブルーオーシャン」であるといえます。コミュニティは皆さんのコントリビュートをお待ちしています。

自分は PicoRuby 自体書いたことがなかったのですが、他の発表でも多く言及されていたトピックの一つで「なんだかみんな楽しそうにやってていいな……」と思い会期終了後にRassberry Pi Pico W を購入しました。
まずは以下の記事を見ながらLチカチャレンジしてみようと思います。(この記事の執筆者の hasumikin さんは PicoRuby/R2P2 の開発者かつ今年の RubyKaigi のスピーカーの方です)

shimane.monstar-lab.com

発表以外で印象に残ったこと

会期中の社外の方々との交流についてはいもりさんのパートでたくさん取り上げているので、id:kiryuanzu のパートでは RubyKaigi に絡めて行われた社内での活動についてピックアップします。

今回の現地参加組はいもりさんと私の2人だけでしたが、社内の Slack で #spot-rubykaigi-2024 チャンネルを作って、会社のメンバーに向けて発表の感想や現地での出来事をその都度発信するようにしました。
今回は現地参加されなかった方々も、発表の解説ツイートや私たちの発言に対して反応してくださり一緒に楽しむことができました。

社内slack での様子

また、今年の4月から株式会社万葉から参画し、tetoru チームで関わってくださっている櫻井さんも RubyKaigi に参加されていました。
イベント直前に社内で企画した予習会では、初参加の人向けの RubyKaigi の楽しみ方についてお話ししていただき、会期中にも交流の機会をたくさん作っていただきました。
会期中は Classi Tシャツも着てくださっていたのが大変嬉しかったです。なんとよく見ると名札の方にも tetoru のロゴを手書きで描いてくださっています。

RubyKaigiが終わってすぐのタイミングで、会期中に印象に残ったことについて語る会も実施しました。
筆者が「パーサーについてみんなどうやってインプットしてるんだろう……」とぼやいた際に、同僚の方から「まずはインタプリタの作り方の第二部まで読むのがおすすめです」とアドバイスをもらい読むことにしました。紙の本を購入したところですが、中々の分厚さにびっくりしています。

(当時の会話をメモした社内esaを一部抜粋)

そのようにして、現地参加組とリモートで見守ってくれたメンバーの間で交流を深めつつ一緒に RubyKaigi の空気感を楽しむことができました。
来年はもっと多くのメンバーに現地参加してもらえるよう社内での発信を続けていきたいです。

いもりの参加レポート

2024年4月に新卒入社したいもりです!

今回、ありがたいことに新卒研修期間中にRubyKaigiへ参加する機会をいただきました。 ところが当時私のRuby学習歴はたったの4日…

そんな人間のレポートとなっています。生暖かい目でご覧ください。

参加しての感想・交流について

第一印象として、とにかく新参者に優しいコミュニティでした!

交流の場として、日中はRubyKaigiで知り合った人と一緒に昼食を食べたり、夜には多くの交流の場が設けられていたのでそちらに参加したりしました。
その場では初学者でも非常に温かく出迎えてくださり「今日の発表は何が印象に残った?」「普段はどんな研修を受けているの?」など、私の目線で会話に加えていただいたことが本当にありがたかったです。

登壇者の方ともお話しする機会に恵まれ、RubyKaigiの沿革や、登壇者ならではの苦労などを話していただきました。
特に「自分が発表している時間の発表を聞きに行きたいんだ!」という一言は忘れられません。

また、私は現在フィヨルドブートキャンプにて研修しているのですが、同じフィヨルド生の方とも交流できました。
研修で使っている『ゼロからわかる Ruby 超入門』の著者であり、Classiの新卒研修の設計に携わられていたigaigaさんとも快くお話ししていただき、サインもいただきました。大事にします!

発表

全体として、登壇者の方々が「この技術はこの方の登壇を聞けばより詳しいことがわかる 」と、他の方の発表を引用し合っているのが非常に印象的でした。

これは本当に素晴らしいことだと思います。Rubyコミッターの方々が互いを知り、また信用していないとできない引用だと思います。 改めてRubyコミュニティの活発さを感じ取った瞬間でした。

ここでは特に印象に残った発表3つについて、簡単ではありますが感想を書かせていただきます。

Writing Weird Code

初日トップバッターのキーノートの登壇です。 正直なところ、この発表がなければ私はRubyKaigiを楽しめていなかったかもしれません。それくらい衝撃的で感銘を受けた発表でした。

内容としては、irbで奇妙なコードを書くというものです。その奇妙さが本当に強烈でした。

これは紹介された一例ですが、irb上でコードのクラゲが泳ぎ、マウスでクリックするとそれに反応して変形するという内容です。

この発表では、この他にも視覚的に楽しむことができる奇妙なコードが合計で6つ用意されており、そのどれもが本当に衝撃的でした。

肝心の実装についての説明はあまりに高度な内容で、会場含め「…?なるほど…ね?」という反応にならざるを得ませんでしたが、irbすごい!これから使っていこう!と思えた発表でした。

Cross-platform mruby on Sega Dreamcast and Nintendo Wii

こちらは1日目午後の登壇でした。内容としては、mrubyを用いてNintendo WiiとDreamcastのクロスプラットフォームを作成するというものでした。

この方の発表はとてもゲーム製品への愛が伝わってくる内容で、ゲームコントローラーがいわゆるスライドポインターの働きをしており、登壇中は軽快にWiiコントローラーを振っていました。また、Tシャツが非常に個性的でした。

この発表で驚いたのは、最初はまた個性的だと思っていた発表スライドが、実は起動したゲーム内でテキストを表示させていたことでした。

発表の後半ではDreamcastを起動していたのですが、先ほどまで見ていた全く同じテキストが、Dreamcastのフォントで表示されていることに気づいた時は鳥肌が立ちました。

Ruby Committers and the World

こちらは3日目最初のRubyコミッター同士の対話形式登壇でした。 内容としては、2日目深夜にRuby3.4.0-preview1がリリースされたこと、そしてこれからのRubyについて議論するという内容で、活発に意見が交わされていました。

この対談で印象的だったのは、コミッターの方が現在検討しているRBSの文法について、参加者がどちらを好むか多数決で世論調査を行ったことでした。
この多数決が将来のRBS文法を決めるものになるかもしれないと思うと、Rubyコミュニティに少し関わることができて嬉しかったです。

また、対談は日本語と英語の二か国語で実施されたのですが、途中からMatzさんによる同時翻訳が始まったのが面白くもあり、非常にありがたかったです。

まとめ

今回、先輩の id:kiryuanzuさんを通して多くのRubyistの方とお話しさせていただきました。貴重な交流の時間、本当にありがとうございました。

また、株式会社万葉から参画しClassiに携わっていただいている櫻井さん、社内から後押ししてくれたClassiメンバーの皆さん、RubyKaigiを運営していただいたスタッフの皆さん、その他ランチや飲み会の場で交流をしていただいた方々に深く御礼申し上げます。

次回は愛媛県松山市開催ということで、関西在住の私にとっては比較的好立地なこともあり、ぜひ参加したいです。

これからもRubyコミュニティに関わっていき、一人前のRubyistを目指します!

おわりに

以上、Classi メンバーの感想レポートをお届けしました! 今回の RubyKaigi での経験を経て普段の業務や趣味の開発を頑張っていこうという気持ちを改めて持てました。

RubyKaigiの翌週には Classiオフィスで開催された shinjuku.rb #92 ではいもりさんが「RubyKaigi 2024 行ってきたレポ」というタイトルでLT発表をされていました。

tech.classi.jp

このように早速コミュニティ活動へと飛び込んでいく姿を見せており、RubyKaigi での経験が後押しになったとしたら嬉しい限りです。

来年の4月には愛媛県松山市で RubyKaigi 2025 が開催されます。その時に向けて日々の生活の中で学びを重ねつつ、今回よりも更に RubyKaigi という非日常の場を楽しめるようになりたいです。

来年もまた RubyKaigi でお会いしましょう!

Strict CSP を Content Security Policy Level 3 に対応したブラウザに絞って適用する

こんにちは、プロダクト本部エンジニアの中村 (kozy4324) です。

現在 Classi が提供している Web サービスでは Content Security Policy を導入しています。その導入時の話は以下の記事で紹介させてもらいました。

今回の記事では、運用を続けていく中でわかったことや出てきた課題、またそれらを踏まえて現在どういった CSP のポリシーで運用を行っているのか紹介します。

オリジンの許可リストをベースにしたポリシー

導入時の記事でも紹介している通り、運用開始時のポリシーは以下のようなものでした。

Content-Security-Policy:
  default-src 'self';
  script-src  example.com 'sha256-xxx' 'nonce-hogehoge111';
  style-src   example2.com 'sha256-yyy';

ベースは ’self’ (文書が提供されたオリジンと同一オリジンのリソースを許可する)とホスト名による許可リスト方式で、特定のインラインコードやインラインスタイルを追加で許可したい場合にハッシュ値や nonce を追加しています。

最初はできる限り厳格な規格に沿ってポリシーを設定、違反レポートを確認しながら必要に応じてポリシーを追加、もしくは無害と判断できるものは無視するという運用ルールとしていました。

出てきた課題1: オリジンの許可リストベースでは攻撃とは見なせない違反レポートが雑多に出てくる

上記ポリシーで運用を始めたところ、すぐに多くの違反レポートが日々あがってくる状況になりました。ところがそのほとんどがブラウザ拡張機能や 3rd party 製の何かによる img や style 、script の挿入に見受けられ、総合的にみて「攻撃とは見なせない」という判断になるものばかりでした。

Sentryに収集された実際の違反レポートの一部

違反レポート自体にはそれほど多くの情報は含まれておらず、頻度やブラウザの分布なども確認しながら一つ一つ丁寧に調査していく必要があります。新しいレポートが発生するたびに調査対応していくと運用負荷は大きなものになっていきました。

Strict CSP をベースにしたポリシーへの変更

オリジンの許可リスト方式で厳密に制限して運用していくのは運用負荷が大きいということが分かりました。また許可リスト方式では CSP バイパスの問題も指摘されています。なので方針を変更し、nonce + strict-dynamic による Strict CSP をベースにしたポリシーとすることにしました。Strict CSP では XSS に対する防御に重点を置き、基本的にはスクリプトに対してのみ制御を行います。XSS に対して効果の薄いスクリプト以外のリソースには制御を行わないため、スクリプト以外で発生する雑多な違反レポートが抑止されることを期待しました。

Strict CSP をベースにしたポリシーは以下のようになります。

Content-Security-Policy:
  object-src 'none';
  script-src 'nonce-{random}' 'unsafe-inline' 'unsafe-eval' 'strict-dynamic' https: http:;
  base-uri   'none';
  report-uri https://your-report-collector.example.com/

この設定内容は、例えば strict-dynamic をサポートしていないブラウザでのフォールバックが含まれています。 Strict CSP のページでも説明がなされていますが、より詳しく整理したものが以下です。

  • CSP Level 3 まで対応しているブラウザの場合
    • 'nonce-{random}' が採用されるので 'unsafe-inline' は無視される
    • 'strict-dynamic' が採用されるので https: http: は無視される
    • よって nonce + strict-dynamic で許可されたスクリプトだけが実行される
  • CSP Level 2 まで対応しているブラウザの場合
    • 'nonce-{random}' が採用されるので 'unsafe-inline' は無視される
    • 'strict-dynamic' が解釈できないので https: http: が採用される
    • よって nonce で許可されたインラインスクリプトと外部スクリプトだけが実行される
    • nonce が付与されないインラインスクリプトは実行が制限される
  • CSP Level 1 まで対応しているブラウザの場合
    • 'nonce-{random}' が解釈できないので 'unsafe-inline' が採用される
    • 'strict-dynamic' が解釈できないので https: http: が採用される
    • CSPによる実行制限はない(保護されない)
  • CSPに対応していないブラウザの場合
    • CSPヘッダは何も作用しない
    • CSPによる実行制限はない(保護されない)

出てきた課題2: Strict CSP ベースでは一部ブラウザで Google Tag Manager による違反レポートが発生する

Classi サービスでは Google Tag Manager を利用している箇所がいくつかあり、Google Tag Manager が動的に追加するスクリプトで違反レポートが発生しました。これは一部のブラウザのみで発生し、確認したところ CSP Level 2 まで対応しているブラウザ、2024年5月時点では iOS 14.x〜15.3 の Mobile Safari が該当しました。Classi サービスにおいてまだ一定数のアクセスがある状態です。

CSP Level 2 まで対応しているブラウザでは strict-dynamic は解釈されないため、動的に追加するスクリプトの実行を許可するには nonce を付与する必要があります。 Google Tag Manager のガイドに nonce 対応バージョンの言及があるので、この nonce 対応バージョンとすることで問題なく CSP の実行許可がなされると思われましたが、一つ落とし穴がありました。Google Tag Manager の「カスタム HTML 」で追加されるスクリプトタグには nonce を付与することができませんでした。補足として Google Tag Manager 上で「 document.write をサポートする」というオプションを有効にすることで nonce を付与することは可能になりますが、 Classi での利用方法的にこのオプションを有効にすることもできませんでした。

CSPで制御されるスクリプトの種類とディレクティブの整理

ここまでに遭遇した課題をうまく回避できる CSP 設定はないものかと思い、スクリプトの種類とディレクティブについて整理をしてみました。

種類 具体例 制御ディレクティブ ‘self’ と host-source による許可 nonce による許可 strict-dynamicによる許可
外部スクリプト <script src="outer.js"></script> script-src-elem できる できる できる
インラインスクリプト <script>alert(1)</script> script-src-elem できない できる できる
インラインイベントハンドラー <a onclick="alert('clicked')">link</a> script-src-attr できない できない できない
JavaScript URL <a href="javascript:void(0);">link</a> script-src-elem できない できない できない

a タグの href 属性に設定する javascript: で始まるスクリプト記述は script-src-attr ではなく script-src-elem で制御されるというのは押さえておきたいポイントです。

またこの整理の中で strict-dynamic 以外に script-src-elem と script-src-attr の両ディレクティブについても CSP Level 3 からの機能であることに気づきました。 CSP Level 3 に対応していないブラウザではこれらのディレクティブは単純に無視されます。

Strict CSP を CSP Level 3 に対応したブラウザに絞って適用する

上記の整理を行うことで、以下の CSP 設定を導き出すことができました。

Content-Security-Policy:
  object-src      'none';
  script-src      'report-sample' 'unsafe-inline' 'unsafe-eval' https: http:;
  script-src-elem 'report-sample' 'nonce-xxxxx' 'strict-dynamic';
  script-src-attr 'report-sample' 'none';
  base-uri        'none';
  report-uri      https://your-report-collector.example.com/;

この設定における整理は以下の通りです。

  • CSP Level 3 まで対応しているブラウザの場合
    • script-src-elem, script-src-attr によって Strict CSP と同等の効果が得られる
  • CSP Level 2 / CSP Level 1 まで対応しているブラウザの場合
    • script-src-elem, script-src-attr は無視され script-src のみが採用される
    • CSP による実行制限はない(保護されない)

Classiの運用ポリシーとしてインラインイベントハンドラーで違反となるスクリプトについては極力インラインスクリプト形式にリファクタリングをするべきとしています。リファクタリングが妥当でない場合と JavaScript URL については unsafe-hashes で許可をすることも認めており、 script-src-elem と script-src-attr の適切な方にそれぞれ hash を追加していくことになります。最終的には以下のような設定例になっていきます。

Content-Security-Policy:
  object-src      'none';
  script-src      'report-sample' 'unsafe-inline' 'unsafe-eval' https: http:;
  script-src-elem 'report-sample' 'nonce-xxxxx' 'strict-dynamic' 'unsafe-hashes' 'sha256-xxxxxx';
  script-src-attr 'report-sample' 'unsafe-hashes' 'sha256-xxxxxx';
  base-uri        'none';
  report-uri      https://your-report-collector.example.com/;

まとめ

この CSP 運用を続けていく中でわかったことは以下の通りです。

  • オリジンの許可リストベースではレポート運用負荷が高くなり、CSP バイパスという問題も含めると費用対効果の観点では微妙と判断せざるを得ない
  • Strict CSP ベースで Google Tag Manager を利用している場合に、一部ブラウザでの違反レポートが抑止できない問題が発生しうる

CSP のディレクティブを整理することで、 CSP Level 3 に対応したブラウザに限定されますが適切な設定方法が見出せました。行き詰まった時は一度立ち止まって仕様や実装状況を整理することも大事だということを痛感しました。

現在、 Strict CSP をベースにした前述のポリシーで数週間運用をしていますが、違反レポートのノイズも少なく運用負荷も気になるレベルではありません。 Report Only で運用をしていましたが、一部ページでは Report Only も解除し、実際に不正なスクリプト実行には CSP によるブロックがかかる状態にも問題なく移行できています。 CSP の適用範囲を広げ、よりセキュリティ強度の高い設定を目指していくのが次の目標です。

今後も CSP に関わる運用が続いていきますので、また共有できる事例があれば紹介したいと思います。読んでいただきありがとうございました。

Shinjuku.rb#92をClassiで開催しました

ソフトウェアエンジニア&Shinjuku.rbオーガナイザーの onigra です。5/31にClassiオフィスにてShinjuku.rbを開催いたしました。足元の悪い中ご参加くださった方々、本当にありがとうございました。

Shinjuku.rb とは、新宿周辺のRuby技術者たちが気軽に集まるコミュニティです。 ミートアップでは一方的な発表のみならず、ディスカッションを通じたインタラクションを大事にしているのが特徴の1つです。

今回の開催にあたり、同じくShinjuku.rbオーガナイザーである yuki3738さんが所属する 株式会社mov様より、フード&ドリンクスポンサーの協賛をいただきました。mov様は先日のRubyKaigi2024でもAfter Party Sponsorを行なっており、お世話になった方も多いと思います。心より感謝申し上げます。

Classiのエンジニアメンバーも設営兼ねて数名参加したのですが、今回、千葉県教育委員会から研修でお越しの小川先生がShinjuku.rbに興味をお持ちでしたので、参加いただきました。現役の学校の先生がプログラミングコミュニティに参加するのは珍しい機会だと思いますので、Classiらしさを出せたと思っています。

また、LTにはClassiメンバーのkozy4324さんと2024年新卒の伊森さんが参加してくれました。伊森さんは新卒らしからぬ小慣れた調子で発表しており、驚きました。

DevTools と デバッグ と 私(kozy4324

RubyKaigi行ってきたよレポ(いもり)

Shinjuku.rbはこれからも新宿界隈のRubyコミュニティを盛り上げていきたいと思います! 次回開催の際は是非お越しください!

dbtを導入した話、そしてClassiのデータ基盤「ソクラテス」の現在地

こんにちは、データプラットフォームチームの鳥山(@to_lz1)です。

Classiでは、2019年ごろからデータ基盤に「ソクラテス」の愛称をつけて運用を続けています。初期の構成は2021年に書かれたエントリ*1にも詳しいですが、数年の間に進化したことも増えてきました。

大きな変化の一例として、最近、私たちのチームではdbt*2を導入してジョブ間の依存管理やメタデータの管理を改善しました。

本記事ではこの取り組みをピックアップして紹介します。また、進化したソクラテスの構成図をアップデートするとともに、Classiデータプラットフォームチームの最新版の雰囲気もお伝えできればと思います。

dbt移行前の構成

正直に言ってしまえばdbt移行前の構成でも運用が崩壊するほどには困っていなかったのですが、個人的には大きく以下の2点に課題を感じていました。

  • ジョブ間の依存管理がつらい
  • メタデータの管理がつらい

以下、それぞれ説明します。

ジョブ間の依存管理がつらい

dbt導入以前のジョブはCloud Composer(Airflow)が提供するOperator*3が担っており、1クエリ1タスクになるような構成でした。

ところで、データマートのテーブルは材料となるテーブルがあって初めて作れます。そして材料となるテーブルもまた加工テーブルである可能性があるので、必然的にクエリ間には依存関係が生じます。移行前はこうしたクエリの依存関係を以下のようなyamlの設定ファイルに書いて対応していました。

- task_id: update_classi_dwh.students
  file_path: queries/dwh/students.sql
  destination_table: classi_dwh.students
  table_type: table
  write_disposition: WRITE_TRUNCATE
  dependent_tasks:
    - update_classi_dwh.schools
    - update_classi_dwh.users

生徒のdwhは、学校のテーブルとユーザーのテーブルに依存して作られる...納得感が高いですね。

dependent_tasksが比較的自明であるうちは良いのですが、これだとテーブル数が増えてきたときや、処理の中心に新たにテーブルを加えたくなったときに認知コストが非常に高いという問題があります。また、このアプローチでは依存タスクの記述漏れがあったときにも気づくことができません。依存関係を目で追ってそれを慎重にyamlファイルに反映していくことが作業時間を圧迫するようになってしまっては本末転倒というものです。

メタデータの管理がつらい

Classiでは、過去在籍していたメンバーがFlask-AppBuilder*4を用いたメタデータ管理システムを作ってくれていました。

tech.classi.jp

このシステムの功績は大きく、特にデータエンジニアでないメンバーが定義を書き込めるようになっていたことで、関係各所から「このテーブルのこのカラムはどういう意味?」といった重要なメタデータを収集することに成功しました。

しかしながら、独自管理Webシステムの限界もまたあります。

例えば、新たなテーブルをデータ基盤に追加したときにその説明をわざわざ書きに行くのか?というと微妙なところです。手間が勝ってしまうので充足率がいまいち高くならない、という課題もまた残っていました。

この点、dbtではmodelの定義ファイルにそもそもテーブルごと、カラムごとのdescriptionを記述できます。「新たなテーブルを追加するときに、そのPull Requestには同時にメタデータも書いてある」という世界なら、「リリース後にメタデータを書きに行く」という作業そのものが不要です。データ基盤の改善を加速させていくためにも、早くこのような構図に移行したい、というモチベーションがありました。

過去との差分と、移行への機運

実は、過去Classiではdbtに移行しようとしたものの諸々の状況を考慮して取りやめたことがあります。

tech.classi.jp

当時との状況の差分としては、以下のようなものがあると思います。

周辺ツールのエコシステムが整った

「dbtならyamlにdescriptionを書ける」と言っても、全テーブルの全カラムに手でdescriptionを付けていくのは実際のところかなり大変です。しかし、 dbt-osmosis のようなツールが出てきたことでこうした作業を効率化できるようになり、dbtのエコシステムに乗るメリットが大きくなってきました。

GitHub - z3z1ma/dbt-osmosis: Provides automated YAML management, a dbt server, streamlit workbench, and git-integrated dbt model output diff tools

dbt-osmosisについてはこちらのブログなどが詳しいため、詳細については割愛します。

dbt-osmosisを利用して、なるべくコストを抑えつつ効率的にメタデータ管理を行なう - yasuhisa's blog

エンジニア以外のメンバーがPull Requestを出すことが減った

Classiではかつて、データサイエンティストやビジネス側のメンバーもデータ基盤のリポジトリにPull Request(以下、PR)を出す、という光景が当たり前でした。しかしながら、エンジニアリングを熟知したメンバーばかりではなかったので、これが逆に新たなツールを導入することをためらわせる要因にもなっていました。

時が経ち、ビジネスメンバーからエンジニア陣へのドメイン知識の移転(≒dwh化)はある程度果たされたので、継続的にPRを出し続ける必要は無くなってきました。これにより、「学習コストが隣のチームの人達には厳しすぎるかも...」といった心配をする必要がなくなり、自分たちの裁量で新しいツールをより気軽に導入できるようになりました。*5

移行に際しての工夫点

上に述べたような状況を踏まえて、2023年末から2024年初頭にかけてdbtへの移行をやり切りました。移行においては以下のようなことを意識しました。

少しずつ行う

ビッグバンリリースではトラブル発生時の影響が計り知れないので、独立してリリース可能な範囲を切り分け、比較的難易度・複雑度が低いと思われるものから以下の順に移行を進めていきました。

  1. 社内でしか使わない、独立した小さいワークフロー群
  2. 社内でしか使わないが、データ基盤のコアとなるワークフロー
  3. エンドユーザーにも使われる、プロダクト機能に関連するワークフロー

また、社内データ基盤のコアを移行する際にはテーブルの棚卸しも実施しました。少数ですが、「移行せずとも2024年度になれば必然的に要らなくなる」といったテーブルも混じっていたため、こうしたテーブルはあえてdbt移行せず古いバージョンのまま残しました。

これにより、後述する差分確認の手間を減らしつつ、利用者がいなくなってから削除することでユーザーに影響を与えることなく古い処理系を一掃することに成功しました。

後から思ったことですが、このように徐々に移行を進めていくアプローチは、Martin Fowlerが提案したstrangler figパターンに近いものがあるかもしれません。

strangler fig パターンを実装してモノリシックなアプリケーションからマイクロサービスに移行するプロセスは、変換、共存、排除の 3 つのステップで構成されています。

strangler fig パターン - AWS 規範ガイダンス

差分確認を怠らない、でも楽にやる

さて、dbtへの移行ですが、クエリを移動して、必要な部分を書き換えて、全体のジョブが成功したら終わり...でしょうか?

いえ、それでは不十分なケースもあります。例えば処理は成功しているのにテーブルには差分が出ている...ということになると大変ですよね。データ基盤ではデータの正確性が重要な要素の一つですから、移行前後のデータの比較をしておけると安全です。

BigQueryでは、こうしたテーブル同士の比較はExcept句を用いた集合演算で実現できます。

Query syntax  |  BigQuery  |  Google Cloud

移行前のテーブルbefore、移行後のテーブルafterがあるとして、以下のようなクエリが結果を返さなければ、2つのテーブルは完全に一致していると言えるわけです。

select * from before
except distinct
select * from after

こうしたクエリの作業を全テーブルで行うのは大変なので、小さなシェルスクリプトを書いてチーム内に共有し、簡単に差分比較を行えるようにしました。実際はもう少し機能を追加しましたが、概ね以下のようなものです。

#!/bin/bash

# 比較元と比較先のテーブル名の組をCSVで作っておく
TARGET_FILE="./target.csv"
if [[ ! -f "$TARGET_FILE" ]]; then
    echo "File $TARGET_FILE not found!"
    exit 1
fi

project_id=$1
tables_with_diff=()

while IFS=, read -r compare base; do
    table_id_compare="${project_id}.${compare}"
    table_id_base="${project_id}.${base}"

    echo "Checking diff between ${table_id_compare} and ${table_id_base}."

    SELECT_MINUS_QUERY="\
    (select '${table_id_compare}' as table_name, * from ${table_id_compare} except distinct select '${table_id_compare}' as table_name, * from ${table_id_base} limit 3)\
    union all\
    (select '${table_id_base}' as table_name, * from ${table_id_base} except distinct select '${table_id_base}' as table_name, * from ${table_id_compare} limit 3)"

    result_rows_with_headers=$(bq query -q --nouse_legacy_sql "$SELECT_MINUS_QUERY" | tee /dev/tty | wc -l)
    if [[ $result_rows_with_headers -gt 0 ]]; then
        tables_with_diff+=("${table_id_compare} and ${table_id_base}")
    fi
done < $TARGET_FILE

if [[ ${#tables_with_diff[@]} -gt 0 ]]; then
    echo "Tables with diff:"
    for table in "${tables_with_diff[@]}"; do
        echo "- ${table}"
    done
    exit 1
else
    echo "No diff found with $(wc -l < $TARGET_FILE) table pairs✨"
fi

スクリプトを流した結果をrevieweeがPRに貼ることで、差分がないことについてはわざわざSQLをレビューしなくても分かります。これにより、それ以外の場所、例えばmacroの設計や命名、過去遡及時の冪等性の確保といったより重要な部分のコードレビューに集中できました。

反省点

以上述べたようにスクリプト等も駆使しつつ大きなトラブルなくdbt移行を終えたのですが、一部テーブルでCluster列*6の設定を忘れたまま移行してしまい、移行直後のクエリコストが急騰するという問題が発生しました。

幸い数日で気づけたので影響は小さかったのですが、皆さまに置かれましてはデータだけでなくメタデータ(descriptionに限らず、labelやpartition設定等も含む広義のメタデータ)もきちんと移植できているか、という観点も忘れられませんようご注意下さい。

ソクラテスの現在地

dbt移行などいくつかの刷新を経て、Classiのデータ基盤は今このようなアーキテクチャになっています。

Classiのデータ基盤構成図

ジョブの依存関係の管理の他、メタデータの提供もdbtの機能を使って実現できたのが大きな改善点です。

dbtをDockerizeされたジョブとして動かすようにしたため、model間の依存関係がComposer上では見れなくなってしまったのですが、dbt Docsを確認すればmodelごとのlineageグラフを可視化出来るので、大きな問題は出ていません。

dbt Docs上で可視化されたデータリネージュの一部

先述した独自のメタデータ管理システムについても、クローズする前にすべてのデータをCloud SQLから吸い上げ、dbtのConfigに反映する対応を行いました。これにより、これまでメンバーが書いてくれた有益な情報をdbt Docs上に集約でき、データカタログの利便性も向上したと思います。

dbt移行の他に大きい差分としては、ログのBigQueryへの連携を毎時のバッチで動かすようになりました。

実はそれまではAWS Athenaをベースに作られていたログ分析基盤を使っていました。それはそれで便利な点もあったのですが、AWS内に独自にホストされたRedashがメンテナンス不能になっていたり、BigQuery上のデータともjoinできないなど、負の側面も強くなっていました。このため、2024年初頭にBigQueryへの連携パイプラインを構築し、旧システムも先日すべて無事に削除しました。

これらの取り組みによって、RDBデータはdaily、ログデータはhourlyで、それぞれBigQuery(a.k.a. ソクラテス)に安定して供給される状態が実現できました。

今後の展望

Data Catalog as a Code

dbtによってメタデータの管理性は向上しましたが、今後のメンテナンスが本当に円滑に行われるか、という点では更なる工夫が必要です。メンテナンス業務にあたっては、descriptionをあちらにもこちらにも書かないといけない...といった二重管理を避けることが何より重要ではないでしょうか。

これに関しては、RDBのテーブルと加工テーブルのメタデータをそれぞれ1回記述すれば他のすべてのコンポーネントに反映されるような仕組みを構築中です。目指したい構成は以下のようなものです。

順を追って説明します。

  1. データエンジニアおよびデータ供給者(プロダクトチームのエンジニア)は、RDBのテーブルをBigQueryに連携するときにdescriptionを記述する
  2. bq load時に、書かれたテーブル定義を参照して実テーブルにメタデータが付与される
  3. dbt-source-importerによって、sourceテーブルのメタデータがymlに反映される
  4. dbt-osmosisによって、sourceテーブルのメタデータは加工テーブルのymlにも反映される
  5. データエンジニア及びデータ利用者は、集計カラムなど加工テーブル独自の列があればそのdescriptionを記述する
  6. dbt build時に、ymlを参照して実テーブルにメタデータが付与される
  7. dbt docs serveの定期的な実行により、最新のデータカタログが社内に公開される

dbt-source-importerが初出なので説明しておきますと、これはBigQueryの実テーブルからsourceの設定ファイルの内容を生成してくれるCLIツールです*7。sourceのメンテナンスについて、dbt-helperやdbt-osmosisなど公式に近いツール群ではかゆいところに手が届かないケースがあるのですが、こちらは必要な機能が軽量にまとまっているため重宝しています。

余談ながら、先日機能追加のPRを送った際も迅速に対応いただき、非常にありがたかったです。この場を借りて感謝いたします!

github.com

上図のような世界が実現できれば、人間の手が必要な作業は「RDBのテーブルのメタデータの記述」「加工テーブルのメタデータの記述」だけになります。あとは各ツール群が実テーブルにも設定ファイルにも、データカタログにも最新の状態を反映してくれるという算段で、細かい部分を調整しつつこうした自動化を進めています。

ここに書き切れないさまざまなこと

本記事では技術的なトピックに焦点を当てて来ましたが、ここに書き切れない施策もたくさん行っています。例えば、私のチームが属するプラットフォーム部では、より事業成果に直結する取り組みを増やすべく、全チームそれぞれがプロダクトのKPIに直接コミットするような目標を盛り込みました。

これに伴い、データプラットフォームチームでは例えば、

  • KPIのモニタリングと提言
  • 施策の立案と効果検証
  • ユーザー向け調査の設問設計

などビジネス的にチャレンジングな活動にも取り組み始めています。KPIをタイムリーに測定するためのデータマートの整備もアナリティクスエンジニアリングの一環ですから、当然我々の守備範囲です。データとビジネスが重なることは何でもやる。という覚悟で引き続きやっていきます。

We are hiring!

dbt移行プロジェクトの詳細と、データプラットフォームチームの近況についてお話してきました。何でもやる、とは言いましたが、現在データプラットフォームチームは4月からリーダーとなった筆者を含め3名しかおらず、やりたいことに対しては手が足りていない状況です。

データエンジニアリングもアナリティクスエンジニアリングも存分に行える環境が揃いつつあるため、Classiのデータプラットフォームチームに興味をお持ち頂いた方はカジュアル面談や面接にエントリー頂ければ嬉しいです!

hrmos.co

*1:https://tech.classi.jp/entry/2021/05/31/120000

*2:https://www.getdbt.com/

*3:https://airflow.apache.org/docs/apache-airflow-providers-google/stable/operators/cloud/bigquery.html

*4:https://flask-appbuilder.readthedocs.io/en/latest/

*5:かつてPRを出してくれていたメンバーはSQLやBIツールを使って今もガンガン力を発揮してくれていますし、dbt Docsへのフィードバックやデータ項目の追加依頼をもらうことで間接的にデータ整備にも貢献してくれています。PRが頻繁に飛んでくる文化も素敵とは思うのですが、形を変えて引き続き良い関係が築けているため、自分はこの変化はポジティブに捉えています。

*6:https://cloud.google.com/bigquery/docs/clustered-tables?hl=ja

*7:https://www.yasuhisay.info/entry/2022/01/22/121000

Classiは技術コミュニティの勉強会・ミートアップに会場提供を行います

はじめに

ソフトウェアエンジニアの onigra です。タイトルの通り、Classiは技術コミュニティの勉強会・ミートアップ等に、自社のイベントスペースを会場として提供致します。

昨今、オフラインでの勉強会・カンファレンス・ミートアップの盛り上がりを強く感じており、RubyKaigiはもちろんのこと、 Omotesando.rb などをはじめとした地域Ruby Meetupもオフライン開催がされるようになってきました。私も先日再開した Shinjuku.rb のドリンクアップに参加してきました。

参加者と交流する中で、今後の会場探しに困っていると伺ったので、西新宿にオフィスがあるClassiも会場提供できるという話をし、その流れからオーガナイザーの1人である tdakakさん より運営参加のお誘いを受けたので、引き受けることにしました。

Shinjuku.rbの再会&運営参加の経緯については同じくオーガナイザーの trebyさん のブログ記事が詳しいので、ぜひこちらもご覧ください。

Shinjuku.rbを再開した + 今後の話 https://treby.hatenablog.com/entry/2024/04/04/010121

Classi、tetoru自体がRubyやGo、TypeScriptをはじめとした多数のOSSで成り立っているサービスであり、私自身も地域Ruby Meetupやカンファレンスに参加したり、OSS活動を通じた人との出会いの中で成長できた恩があるので、会社として、いちプログラマとして会場提供という形でコミュニティへの参加と 恩送り を積極的にしていきたいと考えています。

もちろん、Shinjuku.rbのような地域RubyMeetupに限らず、さまざまなコミュニティに会場提供を行っていきたいので、技術コミュニティを運営されてる方々はお気軽にご相談ください。

会場スペック

追記

  • 2024/06/06 収容人数をMAX30名から35名に増やしました

会場の雰囲気

会場の雰囲気
会場の雰囲気

会社概要

住所

  • 〒163-0415 東京都新宿区西新宿2丁目1-1 新宿三井ビルディング 14階

アクセス

  • JR山手線 / 中央線 / 埼京線 小田急線 京王線「新宿駅」 徒歩約6分
  • 東京メトロ丸ノ内線「西新宿駅」 徒歩約2分
  • 都営地下鉄大江戸線「都庁前駅」 徒歩約1分
  • 都営地下鉄新宿線「新宿駅」 徒歩約11分

収容規模

  • MAX 35名(余裕見て)

設備

  • スクリーン: 1基
  • マイク: 2本
  • スピーカー: 1基
    • Bluetooth、ステレオミニプラグで接続が可能
    • マイクスピーカー兼用
  • ゲストWi-Fi: あり
  • オンライン配信設備: なし
    • 準備中

費用

  • 無料

利用可能日程

  • 原則平日夜(18時以降開始で21時頃までに完全撤収イメージ)

備考

  • 飲食可能(アルコール可)

貸出条件

  • 技術的な勉強を目的とした技術コミュニティであること
    • 自社にスペースが無い企業コミュニティでも、技術イベントの開催目的であれば貸し出し可能です
  • 目安として10名以上の参加が見込まれていること
    • 厳密でなくても大丈夫です
    • 参加見込みが2, 3名だと提供は難しいです
  • 会場提供企業として、Classi株式会社の会社情報告知をOKしていただけること

貸出希望の際の連絡先

  • venue-booking-request@classi.jp
  • Classi株式会社 技術戦略室 鈴木

GitLab本輪読会、他社と合同で振り返りを行いました

こんにちは。プロダクト本部でエンジニアをしています daichi ( id:da1chi24 ) です。

先日、社内でGitLab本の輪読会を実施しました。

さらに今回はそれだけでなく、同時期に同じ本の輪読会をした他社の方と合同で振り返りを行うイベントに参加しました。

今回は輪読会や、他社と合同で行った輪読会の振り返りの内容、経緯や学び、参加した感想をシェアします。

GitLab本とは

GitLabに学ぶ世界最先端のリモート組織のつくりかた」(以下 GitLab本)という本です。

www.shoeisha.co.jp

この本はGitLab社が公開している「The GitLab Handbook」というドキュメントを参考に、著者が自社をリモートワーク化した実体験を通して得られたノウハウをまとめた内容が書かれています。

大まかな章立ては以下のようになっています。

  • リモート組織のメリットを読み解く
  • 世界最先端のリモート組織へ移行するためのプロセス
  • GitLabが実践するリモート組織を活性化させるカルチャー醸成法
  • GitLabが成果を出すために実践している人事制度や業務ルール

輪読会を開催しようと思ったきっかけ

Classiはリモートワークがメインなので、リモートワークを活用して生産性を高める実践例に興味がありました。

しかし、本の内容を把握するのは簡単ですが、その背景やコンテキストを理解するのは難しいです。

そこで他の人の意見を聞きながらディスカッションすることで、本の内容の理解がより深まるのではないかと思い、実施しました。

また、本で紹介されている事例は、個人やチームのみならず、文化や方針などの会社全体に関わるものも多いです。

そのため、普段一緒に仕事をすることのない他の部署や別のチームの方々と課題意識を共有することで、新しい気づきや発見があることも期待していました。

輪読会の進め方

輪読会はソフトウェアエンジニアだけでなく、データエンジニアや労務の方などさまざまな職種の方に参加していただき実施しました。

メンバーの層もジュニアから部長クラスの方まで幅広くいました。

1章ずつ担当を割り振り、担当者はその章を事前にまとめて発表、その後参加者同士で気になったことをディスカッションしました。

この本は全部で13章あり、単純計算で3ヶ月以上かかる長期戦です。

そのため途中で息切れしないよう、参加者の都合が合わない場合はスキップをするなど柔軟に開催しました。

輪読会を通して学んだこと・合同振り返り会に参加する動機

GitLab社が強く打ち出しているドキュメント文化や、リモート化におけるコミュニケーションの方法、新入社員のオンボーディングなど、明日からすぐ使える知識や基準が数多くあり満足度の高いものになりました。

以下は、参加者の感想です(一部抜粋)

  • 中途入社の人から違う会社の話、他の部署の人から違う組織の話、若手メンバーから違う年次の話が広く聞けたのがめちゃくちゃ良かった。
  • 具体例が多いので読み進めやすく、それでいてコミュニケーションといった普遍的な所作に通ずるところも多い。
  • フィードバックの様式やコミュニケーションガイドラインが具体的ですぐに取り入れやすくて良い。
  • 「前向きな意図を想定する」から始まるコミュニケーションガイドラインが、同意できるところが多くて個人的に最も気に入った部分。
  • 読んで終わりと違って、感想を書き合う・話し合うことで内容がより自分の中に落とし込めた感じがします。他の本でもやってみたい。

また、この本で推奨されている方法の中で、Classiでも既にできていたり文化として根付いているものは改めて良いものだと認識することもできました。

例えば、この本では「リモートワークだとメンバーが何をしているかわからない、マネジメントやメンバーの成果に対する評価がしにくい」という課題が取り上げられています。

Classi ではたびたび引用されている Working Out Load (大声作業をしなさい)という行動を推奨しているという話がありました。

www.workingoutloud.com

一方で、生産性を高め仕事を円滑に進める工夫を、他社ではどのようにやっているのかは、社内の輪読会だけではわかりませんでした。

また、これからリモートワーク化を進める組織やハイブリットな組織にとってどのような障壁があるのかは、既にリモート化された組織にいる身として実感が湧かない部分もありました。

そんな時ちょうどGitLab本の輪読会を同時期に行っている方々と合同で輪読会を行うイベント(後述)があることを知りました。

このイベントに参加することで、さまざま他社の悩みや事例を共有しさらに学びを深められるのではないかと思い、参加することにしました。

他社との合同振り返り

参加した合同振り返り会とは、KINTO テクノロジーズ株式会社様が主催されていたイベントです。

各社それぞれで行った輪読会について振り返りを行い、どのような気づきや学びがあったかを共有するものです。

connpass.com

私はワークやパネルディスカッションに参加し、自社ではどのように輪読会を行ったか、輪読会を通してどういう変化があったかなどを、お話しさせていただきました。

実際のパネルセッションの様子

実際に話したディスカッションの内容

参加者の方々はさまざまな勤務形態で、フルリモートで遠方から参加していた方もいれば、出社がメインの企業の方もいらっしゃいました。

また、職種はマネージャーやITコンサルタント、SREなど幅広く、それぞれのコンテキストで議論が盛り上がりました。

振り返りでの話題

色々な話で盛り上がったのですが、輪読会の実施方法と本の内容から1つずつ共有します。

輪読会の方法はたくさんある

あらためて輪読会の実施方法はたくさんあることを再認識しました。

KINTOテクノロジーズさんの事例では、生成 AI を利用して要約する、欠席した方のために同じ内容を2回行うなど、いかに参加者に負荷なく参加してもらうかをかなり工夫されていて実施していました。

blog.kinto-technologies.com

他にも本を読むタイミング(事前に読むか、当日読むか)、予定が合わない時のスケジュールの調整方法も会社ごとに違いがありました。

実施方法は本の内容や参加者の属性によっても異なるので、色々な選択肢を持ちつつも状況に合わせて良い方法を選んだり、途中で変えたりするのが良さそうだと思います。

リモート化でのインフォーマルなコミュニケーションの工夫

GitLab本ではインフォーマルコミュニケーション(いわゆる雑談)は生産性を高めるために大事だと書かれていますが、それぞれの企業で継続するのはなかなか難しいという話で盛り上がりました。

その中でも工夫している企業では、共通の話題を日報や週報から見つけ会話の接点を増やす、制度化せずに自然発生するコミュニケーションを大切にする、オンサイトで話すタイミングやきっかけを作る、などを実施していました。

後に気づいたことですが、輪読会自体が同じテーマで話しやすく親睦も深まるため、チームや部署を超えた関係の発展に寄与するものだと感じました。

全体の感想

今回は社内だけでなく、普段関わることがないような業種の方々と振り返りを行いました。

社内に留まらない一般的な共通の課題を再認識すると共に、Classiの良い文化や強みを改めて実感する良い機会となりました。

今後も社内だけに閉じず、社内外でディスカッションや知見共有をする活動は続けていきたいです。

輪読会に参加されたメンバー、合同振り返りを主催いただいたKINTOテクノロジーズ様、ご参加いただいた方々、ありがとうございました。

© 2020 Classi Corp.