EventHubにおけるリリースフローの紹介

はじめに

こんにちは。EventHubの西内です。

今回はEventHubで開発した機能がどのようなフローで本番環境にリリースされるかについて、ご紹介できればと思います。

採用面接の際、リリースフローに関する質問をいただくことがありますし、質問はせずともCI/CDがどんな感じなのか知っておきたい方もいるかと思いますので、ぜひ参考にしていただければなと考えています。

記事のスコープ

話すこと

  • 開発サイクル
  • ブランチの運用フロー
  • CI/CDの概要

話さないこと

  • リリース後の話
  • 開発着手前や着手中の細かい話

開発サイクル

EventHubでは週に1度リリースを行うサイクルで開発を行っています。

そのサイクルでリリースを行えるようにするために日々テストコードをメンテナンスしており、何らかの機能開発や修正を行ってもデグレードが起きていないことをできる限り確認できるようにしています。

さらに本番環境(production)と同等の構成で検証可能なQA環境(qa)を用意しており、そこでテストを行ったり開発以外の部署に方に触ってもらったりもしています。

開発サイクルの話題を冒頭に持ってきた理由としては、どのぐらいの速度感でプロダクトをデプロイしていきたいかがブランチの運用やリリースフローといった設計の妥当性に関わると考えているからです。

ブランチの運用とリリースフロー

先程の開発サイクルは、以下の図のようなブランチ運用によって成り立っています。

なお、ローカルでのブランチ運用に関してはエンジニアによって異なるので、一例として捉えていただければと思います。

通常のブランチ運用

  1. 開発時にはmainブランチから開発用にローカルブランチを作成
    • 開発が済んだらPull Requestを作成してレビューを行い、2件以上の承認を得たらmainにマージ(Squash)します
    • ちなみにEventHubではtopicブランチごとに動作確認が可能な環境がAWS上で自動的に構築されるので、その環境を使って都度検証を行います
  2. 週に1度、mainブランチでリリースバージョンのタグを作成し、それを元にしてqaブランチ向けにPRを作成
    • productionブランチ向けのPRは前回リリース後に、その時点のqaブランチを元にして作成してあります
    • その後、qaとproduction向けのPRをマージしておき、リリースに備えます
  3. 翌日のリリース予定時刻になったら、qaとproductionのCIを開始させて自動デプロイ

このフローは私が入社(2023年6月)するよりも前から存在しており、ブランチ運用やリリースフローのドキュメントの履歴を見ると2021年9月には既に出来上がっていたようで、そこからほぼ変わっていないみたいです。

さて、ここまで紹介してきたEventHubでのブランチ運用やリリースフロー、および開発サイクルですが、以下のような良さがあるのではないかと考えています。

  • 機能追加や修正内容に応じてヘルプページの作成/編集などを行う猶予がある
    • 週に一度Sprint Reviewと称して、QA環境や本番環境にリリースされる内容を社内に共有しています。小さい追加修正などはそこで初めて知ることがあるものの、実際にリリースされるまでの時間があるのでヘルプページの作成/編集や特定の顧客への連絡などが必要であっても、うまく回せていると感じています
  • 別の機能を開発中にQA環境でも発生する不具合が見つかったら、本番環境にリリースされるまでの間に修正ができる
    • だからといって、普段の検証をおろそかにしてもいいわけではないのですが、リカバリー可能であることで多少は心に余裕ができますね
  • いわゆるトランクベースな開発のメリットを一部享受できる
    • わかりやすい例としてはコンフリクトが起きづらくなりますし、PullRequestも小さくなるのでレビューしやすくなることでしょうか

mainブランチにマージしてから約2週間後に本番環境へリリースされるわけですが、もしかすると人によっては遅いと感じられたりするかも知れません。

しかし、以上のような事柄を加味すると、ちょうど良いサイクルなのではないかなと私は感じています。

CI/CDの概要

EventHubではCI/CDのツールとして、Circle CIを採用しています。

CI/CDにはQA環境や本番環境へのデプロイ以外に、日々の開発を支えるパイプラインも用意しています。開発ブランチ用のパイプラインでは、主に「自動テスト」と「ブランチごとの検証環境構築」のJOBが実行されるようになっています。

EventHubの自動テストの種類の割合は、バックエンドのコードに対してのテストがざっくり90%を占めているのではないかと思います(カバレッジ等の指標は追っていないため個人の感覚です)。

もちろん、フロントエンドでも必要であればコンポーネントのテストを書いたり、独立したfunctionのテストを書いたりすることもあります。また、ヘッドレスブラウザを使ったEnd-to-Endの自動テストを書くこともあります。

Cicle CIはSlackと連携させているので、失敗するとすぐにわかるようになっています

また、EventHubのリポジトリはモノレポの構成を採用しているため、フロントエンドとバックエンドのソースコードが1つのリポジトリで管理されています。このモノレポの良さの1つとして挙げられそうなのは、CI/CDの構築のしやすさがあるのではないかなと感じています。

先程も少し触れましたが、topicブランチごとに動作確認が可能な環境がAWS上で自動構築されるようになっています。

こういった仕組みを異なるリポジトリを組み合わせて行おうとすると、なかなか複雑なものになると思いますし、後から参画した人にとっても触れづらい領域になってしまいかねないと思うので、EventHubぐらいの規模感であればモノレポで開発できることはメリットだと捉えています。

さいごに

「EventHubの開発やリリースってこんな感じでやってるんだな」というのが良くも悪くも伝わっていれば幸いです。

そして、テックブログ以外にも会社全体の雰囲気を知るためのブログやXもありますので、もし興味を持っていただけたらそちらも是非見てみてください!

jobs.eventhub.co.jp

note.com

x.com

TSKaigi 2024では配信プラットフォームとしてEventHubが採用され、弊社CTOの井関がスポンサーLTで登壇したときの動画がありますので、こちらも是非。

www.youtube.com

EventHub メール配信の仕組み

こんにちは!EventHubの勝田です。

イベントマーケティングにおいて、メール配信は欠かすことができません。 イベント開催前のリマインド、開催後のアンケート、次回イベントの告知など、参加者とのエンゲージメントを高める重要な役割を担っています。 適切なタイミングでメールを送ることで、参加者の関心を継続的に高めることができます。

EventHubが扱うメール

EventHubでは、大きく分けて2種類のメールを扱っています。

  1. 参加者のアクションをトリガーに配信するメール
    イベント申込み完了時などの特定のアクションに紐づいて自動で送信されるメールです。

  2. 主催者が自由に文面、送信対象、送信タイミングを制御できるメール
    主催者が柔軟にメールの内容や送信先、タイミングを設定できる自由度の高いメールです。

今回は、2つ目の主催者制御メール(以降、リマインドメールと呼びます)について解説していきます。

リマインドメールの特徴

リマインドメールでは、主催者が自由にメールの文面を編集でき、送信対象や送信タイミングを細かく制御できます。(HTML形式でリッチなデザインを施すことも可能です。)

リマインドメールの流れ

この自由度の高さによって、以下のようなユースケースが可能になります。

  • 参加者を属性(会社、役職など)別に分けて、それぞれに合わせた文章やタイミングでメールを送る
  • イベント前と当日で異なるメールを送る
  • アンケート実施時にメールを送る
  • 次回イベントの告知メールを送る

メール文面は、参加者ごとの氏名やその他属性情報でカスタマイズすることもできます。

実現方法

EventHubはメール配信基盤としてSendGridを利用しています。 SendGridは、メール配信だけでなく、送信メールのイベント(開封、クリックなど)をWebhookを通してPOSTする機能を提供しています。 EventHubではこれらの機能を活用し、配信と配信状況の可視化を実現しています。

配信状況の可視化

配信状況の可視化には、SendGridのEvent Webhookを使用しています。

Event Webhookとは、SendGrid経由でメールを送信した際に発生するイベント(バウンス、到達、開封、クリックなど)を、指定したURLにPOSTする機能です。

SendGrid の Event Webhook は、SendGrid経由でメールを送信する際に発生するイベントを、指定したURLにPOSTすることができます。 このデータの用途は、配信停止アドレスの削除、迷惑メール報告への対応、エンゲージできなかった受信アドレスの判定、バウンスされたメールアドレスの特定、メールプログラムの高度な分析などです。

https://sendgrid.kke.co.jp/docs/API_Reference/Webhooks/event.html

EventHubでは、以下のようにEvent Webhookを活用しています。

  1. Event WebhookからPOSTされたイベントデータ(メール開封、クリックなど)をAWS API GatewayでJSON形式で受け取ります。
  2. API GatewayがAWS Lambdaを呼び出し、イベントデータを渡します。
  3. Lambdaから、EventHubのAPIにイベントデータを送信します。
  4. EventHubのAPIでは、受け取ったイベントデータをもとに送信対象の配信ステータスを更新します。
  5. 管理画面上で、メールごとの送信対象別の配信ステータス(バウンス、到達、開封済/未開封)を確認できます。

配信ステータスのモニタリングを行うことで、以下のようなメールマーケティングの効果測定が可能になります。

  • 開封済み率を測定し、メール文面や送信タイミングの改善ポイントを特定する
  • 一定期間が経過した後の未開封者に対してリマインドメールを送るなどのフォローアップを行う

このように、配信状況可視化によって、PDCAサイクルを回しながらメール施策を最適化していくことが可能となります。

取りこぼし対策

Webhookによる各ユーザーへの配信ステータス更新が失敗する可能性に備え、メール配信ステータスが更新されていないユーザーを特定し、バッチ処理で強制的に更新を行うリカバリーメカニズムを導入しています。これにより、実際にメールが届いているにもかかわらず、不達とされてしまうケースを防ぎ、主催者が各ユーザーの配信ステータス情報を正確に把握できるようにしています。

まとめ

本稿では、EventHubにおけるリマインドメール機能の概要と、SendGridを活用した配信状況可視化の仕組みについて解説しました。 メール送信時の本文のカスタマイズ(置換タグの利用、カスタムオブジェクト)などの紹介もしたいのですが、次回の機会とします。 今後、メールマーケティングをより効果的に実施できるよう、機能拡張を続けていく予定です。

最後に

テックブログ以外にも会社全体の雰囲気を知るためのブログやXもありますので、もし興味を持っていただけたらそちらも是非見てみてください!

https://x.com/i/flow/login?redirect_after_login=%2FEventHub_inc

note.com

jobs.eventhub.co.jp

型共有の恩恵を享受するEventHub

はじめに

こんにちは!! エンジニアの川井です!

テックブログの最初の技術記事ということで、EventHubではフロントとバックで型共有をしています。 今日はそれについて書いていきたいと思います。

EventHubの技術構成

フロント及びバックはTypeScriptで統一されています。 フレームワークとしては、フロントはReact、バックはNestJSを採用しています。

なぜTypeScript、React、NestJSを採用したかはこちらの記事を見てみてください! https://note.com/eventhub/n/n642967756043

ディレクトリ構造について

EventHubはMonorepoで構成されています。 ルートディレクトリはざっくり下記(一部割愛してます)みたいな構成になっています

.circleci
.github
client
├ package.json
└ src
cms
├ package.json
└ src
server
├ package.json
└ src
shared
├ package.json
└ src
shared-front
├ package.json
└ src

clientやcmsはwebアプリケーション、serverはAPIサーバー、sharedは共通の型定義やユーティリティ関数を置いています。 shared-frontはclientやcmsで共通化できるコンポーネントが置いてあります。 ここらへんの詳しい説明は別の機会に!

型共有について

お待たせしました!! 本題の型共有についてです。 前述でsharedに型定義が置いてあることを記載しました。 ここではもう少し詳細に書いていきたいと思います。 まず、フロントとバックで共有したい型定義ですが、主にAPIへのRequest定義やResponse定義になると思います。 もちろん、他にもEnum等の共通の型定義もあるかと思いますが、今回はAPIのRequest/Responseに絞って書いていきます。 例えば、Request情報を基にEventを作成するようなAPIがあったとします。 そのAPIのRequestとResponseは以下のようになるかと思います。 (EventHubではclass-validatorでRequestのvalidateを行っていますが、今回は説明用として割愛します)

export class EventCreateReq {
  name: string;

  constructor(arg: {
    name: string;
  }) {
    this.name = arg.name;
  }
}

export class EventRes {
  eventId: string;
  name: string;

  constructor(arg: {
    eventId: string;
    name: string;
  }) {
    this.eventId = arg.eventId;
    this.name = arg.name;
  }
}

これらのRequest/Responseはフロントとバックで共有したいですよね。 なので、これらをsharedに定義していきます。 例えば、フロントがこれらの定義を参照してAPIを叩くときは以下のようになるかと思います。 (今回はわかりやすさ重視で色々な部分を簡略化しています)

import { EventReq, EventRes } from 'shared';
import { useState } from "react";


const useEventHooks = () => {
  const [name, setName] = useState("")


  const createEvent = async () => {
    const req = new EventReq({ name });

    await fetch(`${APIのURL}`, {
      body: JSON.stringify(req)
    });
  }

  return { name, setName, createEvent }
}

では、どのような恩恵があるかというと、例えばEventに説明という項目を追加したいとします。 まず、Request/Responseの型定義を変更してきます

export class EventCreateReq {
  name: string;
  description: string;

  constructor(arg: {
    name: string;
    description: string;
  }) {
    this.name = arg.name;
    this.description = arg.description;
  }
}

export class EventRes {
  eventId: string;
  name: string;
  description: string;

  constructor(arg: {
    eventId: string;
    name: string;
    description: string;
  }) {
    this.eventId = arg.eventId;
    this.name = arg.name;
    this.description = arg.description;
  }
}

すると、フロントの下記部分でコンパイルエラーが発生します。

import { EventReq, EventRes } from 'shared';
import { useState } from "react";


const useEventHooks = () => {
  const [name, setName] = useState("")


  const createEvent = async () => {
    const req = new EventReq({ name }); ← ここでdescriptionが必要になったのでエラーが発生する

    await fetch(`${APIのURL}`, {
      body: JSON.stringify(req)
    });
  }

  return { name, setName, createEvent }
}

このように、変更時には影響箇所が検知でき、修正範囲や修正の規模感も把握できます!

こういった形でEventHubでは型共有の恩恵を受けています!

さいごに

もし、これをみてEventHubに興味をお持ちいただけらぜひ以下のリンクから詳細をご覧ください!

https://jobs.eventhub.co.jp/

https://x.com/i/flow/login?redirect_after_login=%2FEventHub_inc

note.com

テックブログ始めます!!!

はじめに

こんにちは!EventHub CTOの井関です。

実は、テックブログを開設しよう!という話が社内でこれまでも何度かあがっていたのですが、開発スピードを優先したり、新しく参画してくれたメンバーのオンボーディングを優先していたため、「挑戦してみたいけれど、結果的に優先的に取り組めていない・・・」という状況でした。ただ、この度、満を持して!? EventHubのテックブログを開設することにしました!!

今回はなぜテックブログを始めるかを今までの経緯を含めてまとめます。

過去の立ち上げ

テックブログを立ち上げようとしたのは今回が初めてではなく、2021年の8月に開始しようと動きがありました。ただ、その時は開発がたて込んでいたタイミングと新しく入ってきた方も多くまずは業務に慣れることが重要ということで流れてしまいました。それからも何度か話にあがりましたがまだ時期ではないということで開始にはいたらなかったです。

そんな状況でしたが、2023年からコーポレートチームに手伝ってもらいエンジニアチームのインタビュー記事や雰囲気を知れるための記事を公開し始めたことで徐々にブログを見て弊社の雰囲気を知ってくれる方が増えてきました。

note.com note.com note.com note.com

テックブログをやる目的

テックブログを始める理由はいくつかありますが、より重要なのは情報発信文化の醸成・維持に意義があると考えてます。 エンジニアとしての業務を続けていると日々新しい気付きや、得られる知識が多くあると思います。ささいな気付きでもそれらの情報を発信することはチームの誰かや、世の中の誰かを助けることにつながります。

今の開発組織はお互いの知見や疑問に思っている点などを社内のSlackに積極的に発信している方だと思います。知見を共有することで開発組織全体のスキルがあがりより良いプロダクトを作ることができるようになります。 ただ、こういった雰囲気や文化はチームのメンバーが増えていくことで次第に失われていきやすいと思います。(正確には人数が増えたことにより全体発信のハードルが上がってしまい、エンジニア内でも特定のチーム内で閉じてしまうことが原因です)

もちろん採用広報という意味もありますが、今の規模だから生まれやすい気軽に議論しあって情報を共有し合う文化をこれからも維持もしくはより強く発展させるためにテックブログを開始したいと考えてます。

さいごに

テックブログ以外にも会社全体の雰囲気を知るためのブログやXもありますので、もし興味を持っていただけたらそちらも是非見てみてください!

note.com

https://twitter.com/EventHub_inc