Classi開発者ブログ

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

Classiで行われている部活動の紹介 〜CTF caféはじめました〜

こんにちは、Classi株式会社 プロダクト開発部所属のid:kiryuanzu です! 2020年4月から新卒のエンジニアとして入社し、現在は学習記録でサーバーサイドエンジニアの業務を担当しています。
今回の記事では、Classiの中の部活動の一つとして運用されている「CTF café 」、そしてその部活の課外活動の一環として参加したHardening 2020のイベントの体験記を紹介します。

CTF café はじめました!

ご存知かもしれませんが、CTFとは「Capture The Flag(キャプチャー・ザ・フラッグ)」の略であり、フラグ(Flag)と呼ばれる隠された答えをセキュリティの知恵を駆使して探し出す競技のことです。競技の中身は、クイズ形式のものや実際にサーバを攻撃・防衛する形式といったものがあり多岐にわたります。

Classiの中にはセキュリティやCTFに興味を持つ方が多くいます。
過去のClassiのWantedlyの記事では、活動に関わっている野溝が女性限定のCTF大会「4-Girls CTF 2019」というイベントに参加した際の体験記を書いています。 www.wantedly.com

筆者自身も、入社前にこの記事を読んで「CTF、やったことないけど楽しそうだな〜、会社の中に詳しい人がいるのならちょっと触ってみようかな……!」と興味が湧き始めました。
そして、Twitterや入社後に作った分報チャンネルでCTF興味がある旨を呟いた後日のことです。「社内の有志を集めて一緒にCTFの問題を解いてみませんか!」と誘われ、CTFを始めるようになりました。

そのような流れを経て、社内のSlackに「#ctf」というチャンネルを立て毎週火曜のお昼にSlack callに集まる部活が誕生しました!その部活をCTF caféと呼んでいます。

f:id:kiryuanzu:20210317154407p:plain
部活動メンバーとの和気藹々とした様子を一枚におさめました

CTF caféの主な活動内容はオープンに公開されているCTFの問題(ksnctf, cpawctf, picoCTFなど)を協力して解き合ったり、定期的に開催されるセキュリティ関連のイベントに参加するといったものです。
ずっとガチガチにやるといったものではなく、問題を解きつつ近況を交えた雑談を挟んだり、古のインターネット話に花を咲かせることも時折あります。

筆者自身、完全初心者ということもあり最初はどう解くか分からない問題も多かったですが、CTF経験者のメンバーからのアドバイスによって、次第に頻繁に出てくる暗号の解き方を理解したり、「こういう時はstringsコマンドでバイナリファイルの中身を見たらいいんだ!」とすぐに気付くようになりました。問題で用意されるパケットキャプチャを覗きたい時はWireSharkを使うのも慣れてきました。
まだまだ初心者ではありますが、「この時にはこのツール/コマンドを使おう」と頭の中で繋がるようになってきました。
また、OSINT(簡単に説明するとネットに公開された情報だけで目的の情報を特定する形式の問題です)をやるようになってからは迂闊に店名や特徴的な建物が写り込んだ地理写真をあげるのはできるだけ気をつけようと思うようになりました。

活動記録に関しては、メンバーの一人がesaの中でセンスあるタイトル付きで毎回まとめて社内に共有しています。

f:id:kiryuanzu:20210317154749p:plain
「なれる! SE」風と社内で評判です

Hardening 2020 に行ってみた!

筆者がCTF caféに参加するようになって1ヶ月ほど経ったある日、部活メンバーから「Hardening 2020というイベントに参加してみませんか」と声をかけられました。

Hardeningとは、簡単に要約すると外部からの攻撃を防御しつつ、運用を任されたサービスの売り上げを最大化する競技のことです。このイベント自体はCTFに分類されるものではありませんが、CTF同様にセキュリティの知識を駆使して競技に挑むといった点では同様であると言えます。 公式サイトの説明では以下のように書かれています。

Hardening競技会は、基本的にチームに託されたウェブサイト(例えばEコマースサイト)を、ビジネス目的を踏まえ、降りかかるあらゆる障害や攻撃に対して、考えうる手だてを尽くしてセキュリティ対応を実施しつつ、ビジネス成果が最大化するよう調整する力を競うものです。

その説明だけを聞いた時点では、「どうやって守っていけばいいの……!そもそもどんな攻撃が飛んでくるんだ……!?」とまだまだ未知の領域でしたが、チームを組むことになった方々や過去にHardeningに参加したClassiの社内メンバーによって講習会が開催され、どのような準備や戦略立てが必要であるかを知ることができました。
準備期間は1ヶ月で、応募者の中から10人構成のチームを組んで準備を進め、本番当日は上記で説明したように出されたお題に応じてサービスを運用し、攻撃から守り抜くことになります。
ちなみに、大会応募時には個人応募とチーム応募(3人まで)を選ぶことができ筆者はチーム応募で部活メンバーの2人と一緒に参加しました。 他の7人のメンバーの方は、Classiと似たようなWeb関係の出身の方もいれば生活インフラのシステムや病院のシステムを運用されている方、学生とエンジニアの二足のわらじをやっている方など多種多様なメンバーで構成されており、普段交流できないような方々と協力し合いながら学ぶことができ、セキュリティ関係のコミュニティの空気感についても知ることができました。
チーム名はISUCONジェネレーターを使って「おにぎりまみれ」という名前に決まりました。アイスブレイクとして好きなおにぎりの具を言い合ったり、チームメンバーの一人かつClassi社員の野溝がロゴを作成しました。 f:id:kiryuanzu:20210317155006p:plain

結果は……?

チームの方々と一緒に大会本番に向けて準備を続け、ついに当日を迎えました。 本番中のインシデントでは、ショップのトップページが何者かに改ざんされ当時流行していたドラマの画像が貼られたindex.htmlに変えられてしまったり……(チームメンバーの1人かつClassi社員の高田が30分で直して事なきを得ました)。
運用の手続きに必要なWEBページがDNSエラーで到達不能になり、Discordで運営の方に購入サイトのIPアドレスを教えてもらい危機を回避するなどがありました。
技術的なイベント以外にも、発生したインシデントについて親会社の役員に説明を求められたという設定で、怖い役員に扮した運営メンバーの方から呼び出されるといったこともありました。どうやらこの公開呼び出しイベントは毎年お馴染みのようです。

そして結果は……! 筆者も含めたClassi社員の3名が所属するチーム「おにぎりまみれ」が総合優勝しました!!!!!!

f:id:kiryuanzu:20210317155146p:plain

まさかの初参加でこのような素敵な体験をさせていただくことができ、本当に感謝しています。後日行われた振り返りの場でもこのような結果が残せたのは、チームワーク重視で動き続けたことがよかったのではないかとチーム内で意見が一致しました。

具体的には、チーム内のメンバーの誰かが困っている時はすぐにチャットで反応したり声かけを行うなど、リアクションを徹底して行い、誰かの発言が虚空に消えそうな雰囲気を感じた場合はすぐに反応をして不安を取り除けるよう動くようにしたことで、お互いの役割を認識し合いながら作業内容を把握して進めていくことができたのではないかと思います。

まだまだ「旅」は続く

CTF caféがきっかけとなりこのような大変面白い体験ができました。しかし、これで終わらず部活メンバーと共にセキュリティに関する知見を深め合いながら問題を解き進めたり、他の面白そうなセキュリティ関連の大会に参加して経験を積んでいきたいです!

Classiでは、このような面白い課外活動が活発に行われております。 この記事を読んで「自分もこのようなコミュニティに関わってみたい!」と感じた方の応募をいつでもお待ちしています!

リモートでPeople+AI Guidebookの輪読会をやった話

こんにちは。データAI部部長の伊藤(@tetsuroito)です。

Classiの組織はマトリクス型の組織を採用しており、縦では職能別の部門、横では機能チームごとに分けて、日々の業務にあたっています。

今回の記事では、データAI部とUXデザイン部が共同で取り組んだ輪読会の内容をお伝えします。輪読したものはGoogleが2019年に公開したPeople+AI Guidebookの日本語版です。

輪読会開催のきっかけ

日々の業務では横軸のチームで動くことが多く、部門間のやり取りもチーム内でやりとりすることが多くありました。しかし、縦の部門でそれぞれの職務における能力開発が担われており、UXデザイン部ではUIやUXデザインに関する専門的な能力開発が、データAI部ではデータサイエンスや機械学習などの専門的な能力開発がそれぞれ行われていました。

しかし、データサイエンスや機械学習などは取得されたデータから新たな価値を創出していく活動のため、システムやプロダクトにおけるユーザー体験がデータを生み出すメカニズムそのものに強く影響を与えます。

そのため、2つの部門で同じような課題意識を共有できる取り組みができないかと思っていました。そんな課題意識をUXデザイン部の副部長の松本さんに相談したところ、まずは輪読会をやってみようということになりました。

輪読会の開催概要

リモート環境下における輪読会なので、どのような体裁で開催するかは少し工夫をしました。

項目 方法
開催頻度 毎週金曜日11:00-12:00
読む物 People+AI Guidebook(翻訳版)
各回の概要 1回目:はじめに
2回目:ユーザーニーズ+成功の定義
3回目:データ収集+評価
4回目:メンタルモデル
5回目:説明+信頼感
6回目:フィードバック+コントロール
7回目:エラー +上手な失敗
8回目:ふりかえり
輪読会構成 前半30分 担当箇所を読みながら付箋に書き出す
後半30分 付箋を眺めながら気になった観点を議論する
締めにグラフィックレコーディングを確認する
使うツール Miro

輪読会の開催方式は色々とありますが、今回は専門領域の異なるメンバーが参加しているため、同じ認識を持ちながらそれぞれの立場での読み解きの視点や感想などをシェアすることを重視しました。

そこで、特に担当箇所などは割り振らず、毎週決まった章をみんなで読んで、感想を出し合う形式にしました。各回の分量も適切なサイズに切り分け、事前に予習してこなくても大丈夫なように、前半30分を読む時間にあて、その中で気になる観点を書き出し、後半にそれを話し合うことで気づきを得られるようにしました。

今回、UXデザイン部のメンバーが参加してくれたことで、輪読会での議論の様子をグラフィックレコーディングにしてもらいました。最後にそれを眺めて振り返ることで、理解を促進するような構成にしました。

輪読会の様子

はじめにを読んで、輪読会に期待することを書いた初回 f:id:tetsuro-ito:20210311124619j:plain

データ収集+評価の回 f:id:tetsuro-ito:20210311124706p:plain

エラー+上手な失敗の回 f:id:tetsuro-ito:20210311124637j:plain

このようにはじめの30分で章を読みながら気になった箇所を個々で付箋に書き出し、他の人がどのような観点が気になっているのかをみることで、また新たな発見や視点を得ることができました。その様子をグラフィックレコーディングで描いたのが右手に描かれている内容です。

ふりかえり

すべての章を読み終えた後に、輪読会自体のふりかえりも行いました。

f:id:tetsuro-ito:20210311124648j:plain

People+AI Guidebookには章によってデータ系に近い章とUXに近い章がそれぞれありましたが、みんなが共通して印象だった箇所として、「メンタルモデル」や「期待値調整」、「AIの目的は自動化か拡張」などの観点があげられました。

また、最終的にAIシステムのためのUXデザインについて学んでいたはずが、一般的なシステム開発にも活かせる内容も多く、そうした気づきを得られてよかったことや、自身の関わっているプロジェクトにも活かせそうだという意見も多く書かれていました。

今回、職能を超えた活動をする上で、People+AI Guidebookが非常に取り組みやすいコンテンツだったと思います。こうした活動の媒介となるコンテンツがあるということは非常にありがたいなと感じました。

まだまだ質的な部分と量的な部分のコラボレーション事例はそれほど多くはありませんが、こうした活動をきっかけに良い取り組みができるように頑張っていきます。

AWS ECS監視のオオカミ少年化を防ぐために考えたちょっとしたこと

こんにちは。エンジニアの遠藤です。

Classiでは、Datadogを使ってシステムの各種メトリクスをモニタリングし、異常があればSlackにアラート通知を飛ばすように設定しています。

今回は、AWSのECSのタスク数に関するアラート通知の設定を変更する機会があり、そのとき何を考え、どう変更したのかという日々の運用の様子を紹介したいと思います。

もともとの設定

あらゆるECSのサービス(以後、サービス)のタスク数について、

aws.ecs.service.desired - aws.ecs.service.running

が5以上になればアラート通知を飛ばすように設定していました。

f:id:ut61z:20210224144325p:plain
もともとのDatadogの設定

理由としては、例えばサービスAについては desired task が 10 で設定されていて、サービスBについては desired task が 20 で設定されていたとしても、上記の設定であれば問題なく異常(予期せぬ稼働タスク数の減少)を検知できて、汎用性があるからです。

問題

しかし、あるサービスでタスクのスケジュールベースのオートスケールを設定したとき、上記の設定では問題が発生するようになりました。

そのサービスのタスクは、17:00になると10 -> 30 にスケールアウトし、 18:00になると 30 -> 10 にスケールインします。

先のタスク数のモニタリング設定では、17:00に必ず aws.ecs.service.desired - aws.ecs.service.running = 20 となるので、毎日 17:00 にアラート通知が飛ぶようになってしまいました。

これだとアラート通知がオオカミ少年化しているので、なにか対策をしたいところです。

対策

一案として、上記のサービスのみ通知先のSlackチャンネルを変更し、もともと通知を飛ばしていたアラート用のチャンネルからノイズを取り除きつつ、別チャンネルで検知するという対応が考えられました。

ただ、温度感の高いアラート用チャンネルに通知されなくなるので、本当に予期せずタスク数が減少していることを検知する機会を逃すかもしれず、不安です。

何を監視・検知したいのかを改めて考える

そこで「何を監視したいんだっけ?」に立ち返って考えてみると、結局、検知したいのは予期せぬタスク数の減少です。

シンプルに、そのタスク数の減少をモニタリングすればいいのでは?という考えに至りました。 結果的に、以下のように設定しました。

f:id:ut61z:20210224144947p:plain
変更後のDatadogの設定

通常稼働しているタスク数は10であるサービスなので aws.ecs.service.running が8以下になったとき、アラート通知を飛ばすように設定しました。
(ちなみにこのサービスについては Blue/Green デプロイをしているので、デプロイ時に稼働中のタスク数が瞬間的に10を下回ることはありません)

このモニタリングの設定は汎用的ではありませんし、タスク数の定義を変更するたびにアラートの閾値を変更する必要があるという若干のトレードオフはありますが、目的は十分に達成できるので採用しました。

まとめ

Datadogのモニタリングの小さな設定変更ですが、タスク数の予期せぬ減少は致命的な障害が起きている可能性が高いので、注意深くメンテナンスしていく必要があります。

Classiでは、今回のような運用の改善をポジティブに捉える文化が根付いていて、日々継続的な改善に取り組んでいます。

ほんの一例ですが、事例としての紹介でした。

これからもこういった日々のメンテナンスを怠らず、積極的に改善していけたらと思います。

GitHubのテンプレートリポジトリを継続的に運用する

フロントエンドエキスパートチームのlacolacoです。今回はClassiの中で運用しているGitHubのテンプレートリポジトリについて、その運用方法を紹介します。これが最善である自信はないですが、一例として誰かの参考になれば幸いです!

テンプレートリポジトリ機能とは?

docs.github.com

テンプレートリポジトリは通常のリポジトリと同様にcloneやpull、pushなどできるGitリポジトリとして機能します。テンプレートリポジトリが通常のリポジトリと違うのは、新しいリポジトリを「テンプレートから作成」できる点です。 テンプレートからリポジトリを作成することは、リポジトリをフォークすることに似ていますが、以下の点で異なります。(ドキュメントより引用)

  • 新しいフォークは、親リポジトリのコミット履歴すべてを含んでいますが、テンプレートから作成されたリポジトリには、最初は 1 つのコミットしかありません。
  • フォークへのコミットはコントリビューショングラフに表示されませんが、テンプレートから作成されたリポジトリへのコミットはコントリビューショングラフに表示されます。
  • フォークは、既存のプロジェクトにコードをコントリビュートするための一時的な方法となります。テンプレートからリポジトリを作成することは、新しいプロジェクトを素早く始める方法です。

Classiにおけるテンプレートリポジトリ

テンプレートリポジトリは似たプロジェクトを何度も作成するときの雛形を管理する方法としてとても適しています。その一例として、Classiのフロントエンドエキスパートチームでは、AngularJSからAngularへの段階的移行を支援するテンプレートリポジトリを作成しています。

Classiのコードベースは機能やデプロイ単位に基づいていくつかのリポジトリに分割されています。そのため、ひとつの大きな移行ではなく、いくつもの段階的移行が並行して進行することになります。

AngularJSからAngularへの段階的移行では、AngularコンポーネントをCustom Elementsに変換して、それをAngularJSを利用している旧実装のHTML中に埋め込んで置き換えていくという手法を取っています。Angularコンポーネントは単にCustom Elementsにするためだけのソースコードではなく、移行の最終段階ではそのままAngularアプリケーションとして根本から置き換え可能である状態を作っていきます。

つまり、ひとつのプロジェクトの中でAngularのソースコードを通常のアプリケーションとしてデプロイできるビルド設定と、Custom Elementsのパッケージとしてデプロイできるビルド設定の共存が必要になります。毎回それぞれのプロジェクトにリポジトリの作り方をレクチャーしていくのは骨が折れますし、設定を改善したときにそれを全体に伝えるのも共通の土台がないため難しいです。

テンプレートリポジトリを運用することで、どのプロジェクトも同じスタートラインになっており、設定の改善も同じ変更を適用できることをある程度保証できるようになりました。また、実際にプロジェクトを進めていく中での発見をテンプレート側へ還元するループも生まれやすくなりました。

継続的な運用のための変更履歴

このようなテンプレート的存在は時間の経過につれメンテナンスがされなくなったり、テンプレートから新しく作成した時点からいままでの差分がわからないということになりがちです。この問題を緩和するために、テンプレートリポジトリの変更履歴を文書化しています。

具体的には、テンプレートリポジトリ内ではConventional Commits のルールに従うことで、 standard-version CLIを使ってCHANGELOG.md を自動生成できるようにしています。キリのいいタイミングでテンプレートのバージョンを更新することで、「テンプレートを更新したので各チームで変更点の追従お願いします」というコミュニケーションが容易になります。 コミットログだけではノイズが多いため、Conventional Commitsによってfeatとfixの差分がまとめられることで本当に重要な変更だけを伝えやすくなっています。

f:id:lacolaco:20210218102146p:plain
CHANGELOGの例

今後の課題

現状どうしても人力に頼っているのは、テンプレートのバージョンアップを派生先のリポジトリ達に伝えに行くところです。ここは何かしらの方法を使って自動化できないかと考えているところです。たとえばGitHub APIでそのテンプレートから作られたリポジトリを走査してIssueを作成にしにいくなどできるかもしれません。 また、変更の追従自体もテンプレート側のDiffをなぞって真似することになるため、マイグレーションパッチを適用するだけで済むようになれば楽になるかもしれないと考えていますが、テンプレートからの作成後に加えられた変更でパッチの互換性がなくなってしまうケースも考えると一筋縄ではいかないですね。

とはいえ、変更履歴とバージョニングを自動化するだけでもテンプレートリポジトリの運用がやりやすくなりました。読者の中でテンプレートリポジトリを運用している方の参考になれば幸いです。

SQL勉強会を通して痛感したデータ民主化への長い道のり

こんにちは、ClassiデータAI部の石井です。 私は2019年4月にソフトバンクからClassiに出向し、マーケティング部を経て、現在データAI部でデータエンジニアとして分析基盤の構築を担当しています。今回は私が現部署で最初に担当したSQL勉強会についてご紹介します。

背景

2020年春頃から、新型コロナウイルスの影響による休校や教育現場の急激な状況変化に対応するため、Classiサービスの詳細な利用状況把握の必要性が高まっています。 Classiは弊社の強みともいえる膨大な教育データを蓄積していますが、残念なことに全社的には貴重な教育データを活用しきれていないことが課題でした。 2020年夏に全社で行った「データAI部に期待すること」に関するアンケートでも、「基礎的なデータ活用方法を教えてほしい」という回答が多く寄せられました。 この状況をふまえ、データ活用のための知識の底上げを行い、全社的なデータ活用へコミットするべく、オンラインでのSQL勉強会を開催することにしました。

Y:やったこと

ターゲティングと目標設定

顧客のニーズを正しく捉えたプロダクトを継続して提供するためには、カスタマーサクセスとディレクターがデータ分析するスキルを身につけることが必要です。しかし、Classiではデータ活用の程度にばらつきがあり、施策の打ち出しや機能リリースを行っても、データを用いた効果検証ができておらず、その結果、さらなる施策の打ち出し等の際に顧客にデータに基づいた提案ができないという状況でした。 この状況に鑑み、最もデータを活用してもらいたいこの2職種を中心に参加者を募集。参加希望のあったカスタマーサクセス5名、ディレクター9名、セールス1名に対し勉強会を実施しました。 もともとは全社で1週間あたりの分析基盤利用者数が20名に満たない状況でした。まずは利用者数を20名以上とすることを目標に設定しました。

コンテンツ

業務におけるデータ活用のイメージがわきやすいように、カスタマーサクセスとディレクターそれぞれに各業務に近いデータを準備しました。 また、講義は参加者の習熟度を測るため下表のようなレベルに分けて行いました。

Lv. 説明 主な文法
0 SQLとは/RDBとは/Classiのデータについて
SQLの処理順序/データ型
1 1つのテーブルを利用して、データ抽出ができる select/from/where/and/or/in/case/like
2 1つのテーブルを利用して、集計ができる order by/group by/having
count/sum/avg/distinct/
3 1つのテーブルを利用して、高度な集計ができる with/日付関数/日時関数
4 2つ以上のテーブルを利用して、抽出・集計できる join(left,inner,cross,full)/unionall

データAI部3名が講師を担当し、以下の流れで学習を進めました。

講義編:SQL基礎を学んでもらう(1〜5週目、1時間/週を計5回)
実践編:チームに分かれて実際に分析をしてもらう(6〜7週目の計2週間)
分析結果発表会(1時間)

工夫したこと

講義編

オンラインでの勉強会は、参加者のリアクションや講義のペースが速すぎないかが分かりにくいため、講義の最後に演習問題を入れ理解度をチェックする等、可能な限り参加者全員が理解を深められるようにしました。

実践編

2チーム(3名ずつ)に分かれて実施し、各チームに講師が1名ずつサポートで入りました。分析を行う上では、以下のステップを踏みました。

  • 各チームメンバーが分析してみたいテーマを出し合う
  • 出てきたテーマに対して講師が分析の難易度を設定する
  • 難易度をふまえてチームメンバー自身で分析テーマを選んでもらう
  • 抽出するデータの順序を決めて段階的に抽出してもらう
  • 一つ一つ抽出できているかを講師が繰り返し確認、解説する

なお、ディレクターは全員他業務との調整がつかなかったためディレクター向けの実践編を開催できず、課題を残す結果になりました。

分析結果発表会

各チーム15分で発表・質疑を行いました。その後、今後のデータ活用の参考として、普段からSQLを使ってデータ分析しているカスタマーサクセスのメンバー2名に、実際に業務でどのようにデータ分析しているかについて15分ずつ説明してもらいました。

W:わかったこと

成果

勉強会開催中は講義内で分析基盤を使用したため、目標利用者数20名以上を達成することができました。 勉強会終了後は再び利用者数が減ってしまったものの、勉強会実施前に比べると利用者数が増え、勉強会の成果が出た形となりました。

f:id:yaya-data:20210127184727p:plain
分析基盤利用者の推移

振り返り

勉強会後、講師陣で振り返り、以下の気づきを得ました。

  • 講義を進める中で、Lv.2のgroup byや集計関数の部分は概念が難しく特につまづきやすいので、演習問題の経験を増やして理解を深めるのが最適だと思いました。

  • 実践編で、チームに分かれて分析した方がチーム内で意見を出し合って良い分析ができると予想していましたが、実際は各チーム内にいる講義編の習熟度が高いメンバー1名に依存する状況になり、全員の分析力を高めることの難しさを感じました。

  • SQL初心者から「with句の抽出名やカラム名に日本語は使えないのか」という質問が出ました。日本語を使用した方が各データが何を指すかわかりやすいという意図かと思いますが、私には日本語にしようという発想がなかったので新鮮なコメントでした。

  • 今回、本人の強い希望で勉強会に参加していたセールス担当から、「セールスはデータ抽出しないがデータを見ることはよくあるので、データ抽出を依頼する際にどの程度作業時間を要するか、どのように依頼したらスムーズかが分かり参考になった」と言ってくれました。セールスは業務中にデータ抽出する時間がないため今回はターゲット外としていたのですが、データ抽出との関連が薄そうな職種でも、勉強会への参加でデータを扱う業務への理解が深まるという思いがけない効果がありました。

  • 分析発表会の参加者の気づきの中も参考になるものがあったので以下ご紹介します。

    • アウトプットイメージを先に明確にしたうえでテーブル抽出する
    • 仮説を立てる際の目的を明確にすること
    • 抽出データの構成を考えるスキルの向上(横持ち?縦持ち?等)

フィードバック

勉強会後、以下の3つの観点で参加者にアンケートを実施しました。

  • 習熟度
  • 満足度
  • 今後のデータ分析に対する主体性

勉強会参加者16名のうち半数の8名が習熟度最高レベルのLv.4までマスターすることができました。また、講義編、実践編、講師の説明、コンテンツに対して5段階評価でそれぞれ4.6以上と、高い満足度を得られました。 しかし、勉強会本来の目的である「今後のデータ分析への主体性」に変化があったかのアンケートの結果、全体では5段階評価で平均3.2、SQLを習熟度Lv.4までマスターした参加者でも評価は平均3.7となり、高い満足度の割に低いスコアとなりました。 理由として、参加者コメントに「分析する時間が取れない」、「SQLの理解はできたが、現業務にどのように活用したらよいかが分からない」といったSQLの知識の有無とは別のところに課題があることが分かりました。

参加者コメント(一部)

  • 意欲はあるのですが、他業務との調整がなかなかつかず。。
  • ここで得た知見を今後どう活用していけるかがまだ見えてはいない
  • 現時点で具体的なテーマ設定ができない
  • より身近に使える題材を演習にできるとなお良かった

T:次にやること

今回の勉強会を通じて、データ活用を進めるためにSQLを学習することと別に、(1)分析時間の短縮化(2)現業務と分析テーマとの結び付けに本質的な課題があることが分かりました。

(1)分析時間の短縮化について、Classiでは容易に分析できるように各プロダクトチームのユーザビリティが高いDWH/DMを再構築をしています。

(2)現業務と分析テーマとの結び付け方については、非常に難しい問題ですが、データ活用を推進している我々がデータを活用する立場の彼らに寄り添い、業務を理解した上で共に考えていくことが大切なのだと思います。 そもそも「”基礎”的なデータ活用方法」というのは、”基礎”技術ではなく「業務のどこで活用するのか」という意味での”基礎”であるということが参加者のコメントからもうかがえます。”基礎”と聞くと、”基礎”技術を思い浮かべがちですが、非エンジニアの認識は必ずしもそうではないようです。 現在は、各プロダクトチームに対するヒアリングにより一層力を入れています。データAI部が分析した結果を提供し、その際に分析手法も伝えるようにしたり、施策打ち出しや機能リリースのタイミングを見計らって関係部署に「今が分析のタイミング」とお知らせする等しています。

また、その他の勉強会後の活動として、SQLの理解度アップのために、ClassiオリジナルのSQL練習問題を100問作成(通称:100本ノック)してトレーニングしてもらっており、そこでわからない問題については定期的なもくもく会で個別サポートを行っています。

データ活用ができていないというのは他の企業様でもよく耳にする課題かと思います。今回ご紹介した弊社のSQL勉強会の学びが参考になれば嬉しいです。

TDD研修 by t_wada さん を開催しました

こんにちは。エンジニアの原です。 先日、「テスト駆動開発」の翻訳者として知られるt_wadaさんこと和田卓人さんをお招きして、テスト駆動開発ワークショップの第1回目をオンラインで開催しました。 今回はその様子をお届けします。

きっかけ

Classiでは毎年外部講師をお招きして勉強会を行っています。 新卒研修を行う中で、「テストコードを実装する際の勘所」をどう伝えようかという話があり、第一人者のt_wadaさんをお呼びして研修を行っていただくことになりました。 そこで新卒以外にも参加希望者が多かったため、プロダクト開発部の誰でも参加できる全体の勉強会として開催することになりました。

事前準備

研修の定員が10名のところ、30人近い参加希望者がいたため、3チームに振り分けを行い、3回に分けて実施することにしました。 事前にt_wadaさんから参加者の自動テスト経験の有無と、自動テストで課題に感じていることについてアンケートを行って頂き、その結果をもとに研修内容のすり合わせを行いました。 参加者全員が自動テストの実装経験があるということで、TDDの前提知識はTDD Boot Camp 2020 Online #1 基調講演/ライブコーディング を事前に視聴してくる前提で、当日は質疑応答とライブコーディングを行うという反転学習形式で進めることになりました。

ClassiのSlackワークスペースにシングルチャンネルゲストとしてt_wadaさんをお招きして、事前に簡単なコミュニケーションが取れたため、当日スムーズにワークショップに入ることができました。

当日の内容

午前中は質疑応答、午後は演習を行いました。

午前の部

質疑応答では、事前アンケートで出た質問や、TDD Boot Campの基調講演に関する質問にお答えいただきました。

Classiの参加メンバーからは、

  • どのくらいテストを書くかの指標に code coverage を使うことが多いが他にどういう指標があるか?
  • 目標とすべきテストカバレッジはいくつか? といった質問が出ました。

それに対して

  • カバレッジに関して、テストがないプロジェクトではまずは65%を目指して、テストがあるプロジェクトでは85%を目指すといい
  • カバレッジ以外のプロジェクトの健全性を示す指標として静的解析ツールで複雑度を検証したり、Lintでフォーマットを統一したりすることができる

といった答えを頂き、目指すべきプロジェクトの姿を言語化することができました。 古くからあるプロジェクトにテストコードが無かったり少なかったりという状況を打開する指針になったと思います。 また個人的に印象に残っているのが、「TDDは実装コストは2割増えるが、不具合発生率は8割減らすことができる」という言葉で、TDDのメリットを伝えるのに最適な言葉だと感じました。

午後の部

午後の演習は、簡易的なECサイトの機能を実現するプログラムを以下のTDDのサイクルで書いていくという内容でした。

お題の詳しい内容は以下のリンク先で書かれています(t_wadaさんに許可を頂いて掲載しています)。 https://gist.github.com/twada/856c37103ebd3d1fb973ba2c2654f9d6

まずは与えられた仕様からTODOリストを作らないといけないのですが、仕様の整理の前にコードを書き始めてしまったり、いつもの癖が抜けずにいました。しかし、サイクルを繰り返すことでTDDの手順がしっくり来るようになり、予め目標を考え、その目標を示すテストを書いてからコードを書くことで、テスト容易性を考えられたシンプルなコードが最初から書けるようになったという実感がありました。

途中t_wadaさんとの1on1が複数回あり、TDDの実践方法に関するアドバイスやコードレビューをしていただいたのも貴重な経験でした。

コードレビューの様子
コードレビューの様子

終わりに

集合写真

定員が10名という少人数での開催だったため質問しやすく、1on1の機会もあり参加者全員がt_wadaさんとコミュニケーションを取ることができました。 t_wadaさんの圧倒的な知識の深さに常に圧倒される一日でした。

個人的な感想は以下のツイートの通りで、TDDは少しのコストで何倍ものメリットを享受できることを実感できたので、今後はTDDやっていくぞ!という気持ちで溢れています。

dron: クラウドネイティブなcron代替の紹介

みなさん、こんにちはこんばんは。Classiの基盤バックエンドチームでプロダクトや機能を越えてサーバサイドを中心に困り事を手広く解決する仕事をしているid:aerealです。

今回の記事ではClassiのパフォーマンス改善のため取り組んでいるdronと呼ばれるクラウドネイティブなcron代替 (Cloud Native Cron Alternative) の開発について、運用を見据えてどのような考慮を重ねたのかを紹介します。

背景と課題

dronの説明をするにあたって、現行の非同期処理システム (以下、現行システム) の用途と抱えている課題について簡単に紹介します。

現行のワークロード

主な用途はサービス内通知の送信です。AppleやGoogleのスマートデバイス向けプッシュ通知サービスへ適切なペイロードを送る仕事が大半です。

個々のジョブが要するコストは小さくとも、同時に大量に要求されるためそれなりに計算機資源を消費するという性質があります。

主な用途は通知と述べましたが、これを単純にat least onceな実行モデルのシステムに載せ変えると二重・三重に通知が送信されえます。 通知はトランザクション処理ほどクリティカルな影響をもたらしませんが、エンドユーザーをインタラプトする機能ですからナイーブな実装は利用者の負担にもなります。

加えて未来の時間に所与のペイロードでジョブを実行するという予約実行の仕組みがあり、これの移植も求められます。

課題

DBにやさしくない

Classiの各種データは中央のRDBMSで管理されており、各コンポーネントが読み書きしています。

Webテストの結果や校務記録などコアとなる機能のデータが集まっており、この中央DBの負荷が上がるとClassiの機能すべてに影響があります。 現行システムはこのサービスの根幹ともいえる中央DBをキューとして利用しています。

しかし、これは望ましい用途ではないと考えられます。

Webアプリケーションにおいてリクエストを受けてレスポンスを返すライフサイクルから外れて非同期で処理を実行するモチベーションは概ねレスポンスタイムの向上を図るという一点に集約されると言ってよいと思います。 しかし、データストアを共有していることから現行システムが中央DBを通じてClassiのサービス全体のパフォーマンス劣化を及ぼしうる状況にありました。

アプリケーションのレコードとJOINするようなこともなく同じDBにキューを用意する必然性は無いので、とにもかくにも中央DBの利用をやめたいところです。

スケールアウトの困難なアーキテクチャ

一般にキューを利用した非同期処理システムでは、実行されるジョブの性質に合わせてスケーラビリティを確保するためキューを分離したり、実行環境をスケールアップ・スケールアウトさせることがパフォーマンス改善の手として挙げられます。

現行システムは前述のように中央のRDBMSを利用しPHPで書かれた独自のデーモンとして実行されています。 排他処理は考慮されていないため、素朴にデーモンの実行数を増やすと競合が起きえます。

さらに悲しいことに実行されるジョブの実装もただ一度 (exactly-once) 実行されることを期待しているため、よしんばPHPのデーモンを改修したとしても数あるジョブの実装をひとつひとつ丁寧に排他制御しなければいけず現実的とはいえません。

方針

exactly-onceマナーでの実行、ジョブの予約の実現など複雑かつワーカーとして複雑な責務は凝集させ、各ジョブの実装 (= 知識) は各チームに担ってもらうことで梃子を効かせつつ分権を狙います。

そのために:

  • 各ジョブの実装はプライベートなHTTPエンドポイントとして再実装される
    • リクエスト、レスポンスの形式などアプリケーションプロトコル策定は基盤バックエンドチームが主導する
    • 再実装は各ジョブのオーナーを持つチームに依頼する
  • dronは各ジョブのHTTPエンドポイントを呼び出すところまでを責任境界とする

……とします。

設計

f:id:aereal:20210120172313p:plain
dronのシーケンス図

コンポーネント概説

Facade

  • クライアントが行える操作をHTTP APIとして提供する
  • API Gateway + Lambdaで実装される

Job Executor

  • ジョブを実行するStep Functionsのステートマシン
  • Lambdaの呼び出しが統合されているだけではなくDynamoDBのGetItem/PutItem/UpdateItemなどの各種API呼び出しがLambdaを起動することなく直接行えるのでコードの削減やレイテンシの点で優位性がある
  • 失敗可能性のある処理のリトライや状態遷移を移譲することでアプリケーションを素朴に保てる
  • 並列実行に制約はほぼなく、スケーラブルである

Job Scheduler

  • CloudWatch Eventsで毎時起動されるStep Functionsのステートマシン
  • Job Reservationからジョブ情報を取得、Job Executorを並列に実行する

Endpoint Data

  • Worker EndpointのURLを保存するDynamoDBのテーブル
  • 一度登録されたURLは変更できない
    • 新しいURLを用いる場合は新しいエンドポイントとして登録する
    • 過去のある時点のジョブがどのURLへアクセスしえたかを追跡しやすくするため
  • ジョブの実行要求ごとに任意のURLを受け取る場合、瑕疵により誤ったURLであってもその妥当性を判断できない
  • 事前にURLを登録し、ジョブの実行要求にはエンドポイントの識別子を含めると登録済みかどうかでtypoなどの瑕疵を発見できる
  • 将来的にこのテーブルを拡張して最高並列数を持たせたり、URLテンプレートとしてFacadeへの一度の実行要求から複数のURLへジョブを実行できる含みを持たせている

Job Data

  • ジョブの情報を保存するDynamoDBのテーブル
  • 一度挿入されたらクライアントの操作によって削除・更新はされない
  • 不変データとすることで過去の状態を再現する手間がなくなり調査がしやすくなる
  • Job Executorによってロックとして機能する実行中フラグと完了時刻は更新される

Job Reservation

  • ある日時に実行すべきジョブを保存するDynamoDBのテーブル
  • 日時を過ぎても各アイテムは更新や削除されないので、あるジョブが確かにある日時に予約されたかはあらゆる時点から追跡可能

Worker Kicker

  • Lambdaとして実装される
  • URLとHTTPメソッド、リクエストボディを与えられ適切なタイムアウトを設定してHTTPリクエストをWorker Endpointへ送信、レスポンスを返す

Worker Endpoint

  • 各ジョブの実際の処理を行うHTTPエンドポイント
  • Endpoint Dataは少なくともひとつのWorkerに対応する
  • 各利用者アプリケーションの一部として構築される
  • 条件を満たせばClassiが直接管理しないHTTPエンドポイントをWorker Endpointとすることもできる (例: Twitter API)

運用時の考慮事項

追跡・トレーシング

ジョブの追加や実行が成功したか・どのクライアントがどのジョブを追加したかといった情報は顧客の問い合わせに対応したりデバッグを目的としてX-RayによるトレーシングおよびStep Functionsによる実行ログに保存されるのでそれを利用できます。

ジョブの追加および実行の完全な追跡はX-Rayの制限により最大30日間に、ジョブの実行の部分的な追跡はStep Functionsの制限により最大90日間に制限されます。

命名

cronの次を目指す ('c'.succ + 'ron') ということでdronと名付けました。

これまでに述べてきた既存システムの置き換えではcronの定期実行という仕組みは必須ではなくまた現時点で実装もされていないにも関わらずcron alternativeを標榜しているわけは exactly-onceで処理を実行するシステムの難しさ に着目し、cronはこれを部分的にせよ解決していたことに由来します。

cronのexactly-once実現はSPOFを持ち込むことと表裏一体ですので、クラウドサービスを活用し可用性を高めつつ実現することで既存のワークロードからの容易さが社内の利用者に伝わることも願っています。

おわりに

システムのパフォーマンス改善という大きなミッションのためには、時には個々のコンポーネントの置き換えといった大胆な手段をとる必要があります。

こうした大胆な判断をとる意義と必要性を理解した上で、ニューカマーの私にプロジェクトのリードを任せてもらえる、攻めと守りにメリハリのついた健全な技術決定のできる組織になっていると実感し楽しく思っています。

サービスの改善という大目標への道程はまだ始まったばかりですし、もっと言えばマイルストーンはあっても終わりなどないのですが、それでも大事な一歩に少なからず貢献できたと自負しています。

付録: Cloud Native Cron Alternativeとわたし

元々筆者はqronというAWS上で上記に似たシステムを構築するためのAWS CDKライブラリを開発・公開しています。

ちょうどClassiに参加してどんなプロジェクトを担当しようかという話をする中で、この記事で挙げた課題・プロジェクトが候補に上がっており当初はレビュアーとして「こういった解決策があるよ」と提案する立場でしたが、先行してライブラリを作っていたこともあり主担当となりました。

qronについてYAPC Kyoto 2020で発表予定でしたが、COVID-19の拡大に伴いイベントの開催が見送られたこともあってこのアイデアについて紹介する機会が見つけられず残念に思っていたこともあり、実運用へ投入した事例を紹介できるならという思いもありました。

本当に偶然が重なった結果ですが数奇な巡り合わせを感じずにはいられません。 よって命名時にもqronをインスパイアした名前にしました。

© 2020 Classi Corp.