Timee Product Team Blog

タイミー開発者ブログ

terraformでPRごとにテスト環境を用意する

この記事はTimee Advent Calendar 2023シリーズ 2の5日目の記事です。

はじめに

DREグループの石井です。

今回はDREグループの管理するデータ基盤に関するインフラのterraformのテスト環境の話をしようと思います。

導入前の課題感

我々のチームではデータ基盤として複数のGCP Projectを管理していますが、その全てをterraformで管理しています。

この時点でGithubActionsによる自動テスト(validate, plan) 及び 自動デプロイは導入されていたため、レビューさえ通れば誰でもインフラの変更を反映できる状態になっています。

しかし、この時点でよく起こっていた問題として以下のようなものがありました。

  • validationが実装されていないリソースの命名規則などでデプロイ時に落ちる
  • 実際にapplyして試してみたいけど、デプロイ先が本番しかない

そこでPRごとにGCP Projectを作成しその中でapplyを実際に試せる仕組みを実装して、しばらく運用してみたので実装からその所感までをまとめてみようと思います。

やったこと

PR時にテスト環境が作成するために、ざっくりいうと以下のようなことをやっていますので、それぞれ詳細に記載しようと思います。

  • リポジトリ構成の変更
  • CIで実際にapplyされるときのリソース名の調整
  • GithubActionsの実装

リポジトリ構成の変更

元々、1つのGithub Repositoryで全てのGCP Projectを取り扱っていたのですが、元々は以下のような構造でした。

(必要なところのみ抜粋)

envs/
  GCP_ProjectA/
    各種terraform
    ..
  GCP_ProjectB/
modules/
  module_A/
  module_B/
global.tfvars ... ユーザの管理等

envs配下にproject単位で切られており、modulesは共通の部品だけ切り出しておくという構成です。

これを以下の様に変更しています。

envs/
  GCP_ProjectA/
    environment/
      prod/
        main.tf
        backend.tf
        ...
           test/
        main.tf
        backend.tf
    modules/
      module_X/
         各種terraform
    ..
  GCP_ProjectB/
modules/
  module_A/
  module_B/
global.tfvars ... ユーザの管理等

プロジェクトを跨いでグローバルに使用していたモジュールはそのままとして、モジュール化されていなかったプロジェクト固有のterraformファイルをモジュールとしてまとめています。

そして、main.tf内でモジュールを呼び出すという一般的なモジュール構成に似た形になっています。

リソース名の修正

リソース名もvalidation対象ではあると思うので本来はそのまま適用していきたいのですが、GCSのようなグローバルに一意にしないといけないリソースはこのまま実行するとテスト環境を壊すのと本番環境を作るときのラグ等でリソース名が利用できなかったりして困るケースがあります。

そのため gcs_suffix というvariableを用意しておいて、module側で例えば以下のようにしています。

resource "google_storage_bucket" "gcs" {
  name = "test${var.gcs_suffix}"
..
}

default値を ""(空文字) としておくことで、本番環境には影響を与えないようにしています。

Github Actionsの実装

それでは上で整理したモジュールを使ってテスト環境を生成する部分の話に移ります。

基本的にはPJを作るテンプレートを別途用意しておき、それをコピーしてきてapplyしてプロジェクトを作成、その後、environment/test内をapplyする、という流れになっています。

project.tf (Projectの作成)

resource "google_project" "test-environment" {
  billing_account = var.BILLING_ACCOUNT_ID
  name            = local.project_id
  project_id      = local.project_id
  org_id          = var.ORGANIZATION_ID
}

resource "google_billing_budget" "budget" {
  depends_on = [
    google_project.test-environment
  ]
  provider        = google-beta
  billing_account = var.BILLING_ACCOUNT_ID

  # 消し忘れ対策にバジェットを指定
  amount {
    specified_amount {
      currency_code = "JPY"
      units         = 10000
    }
  }

  budget_filter {
    projects = ["projects/${google_project.test-environment.number}"]
  }

  threshold_rules {
    threshold_percent = 0.5
...
}

services.tf (サービスの有効化)

resource "google_project_service" "service" {
  depends_on = [
    google_project.test-environment
  ]
  for_each                   = local.services
  project                    = local.project_id
  service                    = each.value
  disable_dependent_services = true
}

(variable等は割愛します)

これをapplyした後に実際のtest配下をapplyするのですが、backend設定だけ差し替えないといけないため、以下のようなテンプレートを用意して書き換えています。

backedn.tf.template

terraform {
  backend \"gcs\" {
    bucket = \"terraform-backend-bucket-name\"
    prefix = \"ci_projects/${PROJECT_ID}/projects.tfstate\"
  }
}

これらを用いて、以下のようなActionsになりました。なお、PJがかなり多いため実際によく変更されるプロジェクトのみを対象としたかったのでそうなるようにしています。

name: terraform-test-apply

on: pull_request

env:
  GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
  GOOGLE_BACKEND_CREDENTIALS: ${{ secrets.GOOGLE_BACKEND_CREDENTIALS }}
  GOOGLE_CLOUD_KEYFILE_JSON: ${{ secrets.TIMEE_CORE__GOOGLE_CREDENTIALS }}

jobs:
  set-matrix:
    runs-on: ubuntu-latest
    outputs:
      target_project: ${{ steps.get-diff.outputs.value }}
    steps:
      - uses: actions/checkout@v3
      - name: Fetch changes
        run: git fetch origin ${{ github.base_ref }}
      - name:
        id: get-diff
        run: |
          diff=$(
            echo "$(git diff --name-only origin/master..HEAD | \
            cut -d'/' -f2 | \
            grep -e 'Project1' -e 'Project2' -e 'Project3\' | \
            jq -R . | jq -s .  | jq -c '.|unique')"
          )
          echo $diff
          echo "value=${diff}" >> $GITHUB_OUTPUT

  apply:
    needs: set-matrix
    if: ${{ needs.set-matrix.outputs.target_project != '[]' }}
    strategy:
      fail-fast: false
      matrix:
        PROJECT_NAME: ${{fromJson(needs.set-matrix.outputs.target_project)}}
    runs-on: ubuntu-latest
    env:
      PROJECT_ID: "tf-test-${{ matrix.PROJECT_NAME }}-${{ github.event.number }}"
      PR_NUMBER: ${{ github.event.number }}
    steps:
      - uses: actions/checkout@v3

      - name: Setup Terraform
        uses: hashicorp/setup-terraform@v2

      - name: create project tf and apply
        run: |
          pushd tests/project
          eval "echo \"$(cat ../templates/backend.tf.template )\"" > backend.tf
          terraform init -lock=true -lock-timeout=60s
          terraform apply -var="PROJECT_ID=${PROJECT_ID}" -auto-approve -var-file=../../global.tfvars -lock=true -lock-timeout=60s
          project_number=$(terraform output google_project_number | head -n 2 | tail -1)
          echo "project_number=$project_number" >> $GITHUB_ENV
          popd

      - name: apply `iam/`
        run: |
          pushd envs/${{ matrix.PROJECT_NAME }}/environment/test/
          terraform init -backend-config="prefix=${{ matrix.PROJECT_NAME }}/${PROJECT_ID}/test.tfstate"
          terraform apply -var="project=${PROJECT_ID}"  -auto-approve -var-file=../../../../../global.tfvars -lock=true -lock-timeout=60s -parallelism=20

      - name: Terraform apply Link
        uses: actions/github-script@v6
        with:
          result-encoding: string
          script: |
            github.rest.issues.createComment({
              issue_number: context.issue.number,
              owner: context.repo.owner,
              repo: context.repo.repo,
              body: "### Test Apply of `${{ matrix.PROJECT_NAME }}` :rocket:" + "\n" + "Link: https://console.cloud.google.com/welcome?project=" + process.env.PROJECT_ID
            });

やってみた感想と課題

正直1PRごとに1GCP Projectを立てるのはやりすぎかなと思っていましたが、実際立っていると確認はしやすく、かつ他の影響も受けないため特に新しい機能を開発するようなタイミングでは大変良かったように思います。

ただ、現実問題としてapplyにかかる時間がだいぶ長いという問題はあり、環境によっては4,50分かかっていたこともありました。

検証する必要性の薄いリソースを対象外とするなど色々改善しましたが、それでも軽微な変更をするのにもこれを回さないといけないというのはやりすぎでは?という側面も正直あるかなと思っています。

このあたりは程度問題な気もするので、今後も見極めていければとは思っています。 

個人的には初めて行う設定などでterraformの書き方にやや自信がないものをある程度自信を持ってレビューを出せるようになったことに最も価値を感じているところではあります。

We’re Hiring

DREグループではまだまだやっていきたいことがたくさんあるのですが、まだまだ手が足りておら

ず、ともに働くメンバーを募集しています!!

データに係る他のポジションやプロダクト開発などのポジションも絶賛募集中なのでこちらからご覧ください

障害発生時間をFactから改善する取り組みをアップデートした話

こんにちは、CTO室グループでQAスペシャリストを担っている依光です。

今年を振り返ってという視点から、施策として動き始めた「障害対応をFactから改善する取り組み」について紹介させてください。

今までの取り組みと課題

タイミーのプロダクト部ではFour Keysを活用して改善サイクルに取り組んでおり、 プロダクトの品質を改善するという側面から「変更失敗率」と「サービス復元時間」を 計測しています。 この「サービス復元時間」を短縮するに当たり、障害を時系列にまとめて事後検証として 振り返るポストモーテムだけでは、改善するポイントを客観的に判断することが難しい という課題がありました。

取り入れた施策

障害発生の時間を短縮するために発生時間の内訳を計測して、客観的に判断するようにしました。 まず計測する際に時間を分解する切り口は、O'Reilly社から出版されている「Seeking SRE(SREの探求)」に記載されているプロセスを参考に収集するようにしました。

図の参照元https://www.oreilly.com/library/view/seeking-sre/9781491978856/ch04.html

  • TTD:検出時間
  • TTE:エンゲージ時間(エスカレーションプロセスの時間)
  • TTF:修正時間
  • TTM:軽減時間(障害発生から対応が完了するまでの時間)

続いて客観的に判断するために、各障害のレベルごとにTTD、TTE、TTF、TTMの目標指標を定義しました。

表:障害レベルと各プロセスの目標指標の例

施策を取り入れた効果

ポストモーテムの実施タイミングで、発生した障害のレベルに応じて TTD、TTE、TTF、TTMが目標指標内に収まっているかを確認する ステップが追加されました。 そして未達の指標に対して改善案を深ぼるアプローチができるようになり 障害発生時間の短縮に結びつく改善に繋がりやすくなりました。

  • 指標例:TTD(検出時間)が未達だった
  • 改善例:メトリクスの追加とアラートについて検討する

今後の取り組みに向けて

今回紹介した施策は、時系列にまとめて事後検証を行うポストモーテムだけでは 見つけられなかった改善ポイントが、障害発生時間の内訳時間というFactを基に、 客観的に把握して品質改善ができるようになった1例だと考えています。

今回の事例だけでなく、今後もタイミーのプロダクト本部ではFactを基にした 品質の維持、向上の取り組みを大切にしていきたいと考えています。 私達の取り組みにご興味がありましたら、情報交換など気軽にご連絡下さい。

最後まで読んでいただき、ありがとうございました。

Railsアップグレードを楽にする取り組み 〜社内向け管理画面編〜

こちらはTimee Advent Calendar 2023シリーズ1の5日目の記事になります。
昨日は @redshoga による Vercel REST APIを用いたステージング環境反映botについて で明日は @yama_sitter による フロントエンドアプリケーションの認知負荷とテスタビリティに立ち向かう です。

タイミーでバックエンドエンジニアをしている id:euglena1215 です。

タイミーはユーザー向け・企業向け・社内向けの機能を1つの Rails アプリケーション上で動かしています。
10/5に Rails 7.1 がリリースされ、タイミーも11/1に 7.1.1 に上げることができました。現在は Rails 7.1.2 が本番で元気に動いています。
Rails 7.1.1 へのアップグレードは比較的スムーズに行うことができたものの、アップグレードのプロセスにはまだ改善の余地があると感じました。今回はどこに改善の余地があると思ったのか、具体的な改善の取り組みについて紹介したいと思います。

背景・課題

タイミーでは、Rails アップグレードの動作確認は手動での動作確認をせずとも自動テストで動作を担保して問題ないという合意が得られています。これはテストの網羅性が高く(Code Line Coverage が 91%)十分に動作が担保できているだろうという前提があるためです。

しかしこのルールにもいくつかの例外があります。例えば、暗号化アルゴリズムの変更やキャッシュフォーマットの変更、 Cookie の属性変更など普段書くアプリケーションロジックの自動テストでは検出が難しいと考えられるものです。これらの例外は毎アップグレードで確認すべき箇所が異なり自動テストで検出するのは現実的ではないと考えているため、自動テスト以外の方法で動作を担保しています。

一方、他の例外として「社内向け管理画面は手動でのチェックを行う」というものがあります。これは社内向け管理画面はテストコードの網羅性が低く、自動テストを信頼できないというのが理由です。理由としてはもっともだと思いますが、ユーザー向けの機能は手動でのチェックをしなくていいのに、社内向けの機能は手動でのチェックが必要なのはチグハグさを感じました。

今回はこの 社内向け管理画面はテストの網羅性が低く自動テストを信用できないため、Rails アップグレードの手間が増えている ことが課題だと捉えました。

指標その1:Code Line Coverage

テストカバレッジが低いのならテストを書けばいいじゃないということで、社内向け管理画面 (/admin/* )の Code Line Coverage を指標としテストを書き始めました。

Code Line Coverage とは

「Code Line Coverage」は、ソフトウェアテストの際に使用される指標です。その目的は、自動テストによって実行されたソースコードの行数の割合を測定し、どの程度のコードがテストされているかを把握することにあります。計算方法は、テストで実行されたコード行数を全コード行数で割り、それを100倍してパーセンテージで表します。この指標はテストのカバレッジ定量的に評価するために使われます。

タイミーの Rails アプリケーションでは codecov を使って以下のようにテストで実行されたコード、実行されていないコードを可視化しています。

この時点での app/admin/* ディレクトリの Code Line Coverage は 75% でした。

前提として、タイミーでは社内向け管理画面を実装するために ActiveAdmin gem を利用しています。ActiveAdmin gem を使うこと自体には社内でも賛否両論ありますが、大いなるデメリットもあれば大いなるメリットもあるということで使い続けています(この辺りの話に興味があればぜひ話を聞きに来てください。カジュアル面談はこちら)。

問題とは、ActiveAdmin を使って管理画面を実装した場合 Code Line Coverage と体感のテストカバレッジが一致しないことです。 代表例を挙げます。下記は User モデルに対応した管理画面を実装するコードです。 この2行を書くだけでいくつのエンドポイントが定義されるかを確認してみましょう。

# app/admin/users.rb

ActiveAdmin.register User do
end

下記は上記2行の実装によって定義されたエンドポイントの一覧です。2行書くだけで9つものエンドポイントが定義されています。

root@ba8730884fed:/usr/src/app# bundle exec rails routes | grep admin/users
batch_action_admin_users POST       /admin/users/batch_action(.:format)       admin/users#batch_action
             admin_users GET        /admin/users(.:format)                   admin/users#index
                         POST       /admin/users(.:format)                    admin/users#create
          new_admin_user GET        /admin/users/new(.:format)                admin/users#new
         edit_admin_user GET        /admin/users/:id/edit(.:format)           admin/users#edit
              admin_user GET        /admin/users/:id(.:format)                admin/users#show
                         PATCH      /admin/users/:id(.:format)                admin/users#update
                         PUT        /admin/users/:id(.:format)                admin/users#update
                         DELETE     /admin/users/:id(.:format)                admin/users#destroy

また、ActiveAdmin は動的にルーティングを生成するため、/app/admin/* ディレクトリ以下のファイルはRails 起動時に読み込まれ評価されます。そのため、 app/admin/users.rb に対応するテストを1つも書かなくても app/admin/users.rb の Code Line Coverage は 100% になります。

もちろんこれは極端な例で、普段は一覧の要素を変更するなど実際にアクセスしないとカバーできないコードが生まれるため Code Line Coverage が 100% になるケースは少ないです。だとしても対応するテストがないのに 50%以上のファイルがいくつかあったりと全体的に高く出過ぎているように感じました。 ActiveAdmin は高機能な DSL によって数行でいくつもの画面を生成できます。そのため、コード量の機能量が比例しません。よって、ActiveAdmin による管理画面の実装において Code Line Coverage は指標として不適切だろうと判断しました。

指標その2:Endpoint Coverage

タイミーでは一番外側のテストとして system spec は書かず request spec を書いています。エンドポイントに対応したテストが1つ以上あれば一定動作は保証されているだろうと考え、 /admin/* のエンドポイントに対して request spec が何割カバーできているかを指標として改善をしていくことにしました。

具体例

GET  /admin/users     テスト🙆‍♂️
GET  /admin/users/:id テスト🙆‍♂️
POST /admin/users     テスト🙅‍♂️

↓ ↓ ↓ ↓ ↓ ↓

テストされたルート数: 2
テストされていないルート数: 1
全ルート数: 3
カバレッジ: 66.67%

ここでは Endpoint Coverage と呼称することにします。(正式名称あれば教えてください。訂正します。)

なるべくシンプルな方法で Endpoint Coverage を集計することにしました。ステップは以下です。

  1. rails routes 相当の情報を取得
  2. spec/requests/* ファイルを読み込みルーティングに対応する describe 句を抜き出す(describe 句があればテストケースは1つ以上あるだろうと判断)
  3. 1.と2.で得られたデータを組み合わせて、テストされているエンドポイント・テストされていないエンドポイントを分類し、割合を算出する

集計用の Rake タスクは以下になります。興味があれば見てみてください。

エンドポイントごとのテストカバレッジを計測するための rake タスク · GitHub

上記の Rake タスクをタイミーの Rails アプリケーションで実行すると以下の結果が得られました。

root@084b7fc12fd0:/usr/src/app# bundle exec rake endpoint_coverage:collect_for_admin
テストされたルート数: 165
テストされていないルート数: 367
全ルート数: 504
カバレッジ: 32.74%
root@084b7fc12fd0:/usr/src/app# bundle exec rake endpoint_coverage:collect
テストされたルート数: 457
テストされていないルート数: 445
全ルート数: 827
カバレッジ: 55.26%

確かに admin はカバレッジが 32.74% と高くないことが分かります。体感としてもそのくらいです。 次に全体のカバレッジは 55.26% でした。こちらの結果には admin も含まれているため、admin を抜くと 78.9% です。

上記の結果より、admin とそれ以外とでは2倍以上の開きがあることが分かりました。これならテストの網羅性が低いという判断も納得できます。ということで、Endpoint Coverage を指標として用い社内向け管理画面のテストの網羅性を高めていくことにしました。

また、「社内管理画面の手動での動作確認では機能の60%もカバーできていないだろう」ということで Endpoint Coverage は 60% を目標として進めていくことにしました。

改善その1:index actionのテストめっちゃ書く

Endpoint Coverage の集計 Rake タスクの副産物として、テストが書かれていないエンドポイント一覧を入手しました。これを元にテストの拡充を進めていきたいと思います。

まずは、index action に対応する request spec を書いていくことにしました。テストケースとしては 200 を返すことを検証します。
この判断をした理由は以下の通りです。

  • index action は一覧を取得するためのエンドポイントであり、多くの利用者は一覧画面を起点にして操作を行うため比較的重要度が高い
  • index action の 200 を返すテストはある程度機械的に追加できるため、テストを追加するのが楽
  • spec ファイルが元々あるのとないのとではテストを追加する際の心理的ハードルが異なるため、とりあえずファイルだけでも作っておくことで他のエンドポイントのテスト追加がされやすくなるのではという期待

というわけでテストを書き始めていると嬉しい誤算に気付きました。それは GitHub Copilot がかなり補完してくれることです。

# frozen_string_literal: true

require 'rails_helper'

RSpec.describe 'Admin::User' do
  describe 'GET /admin/users' do
    # ここまで書くと...
  end
end
# frozen_string_literal: true

require 'rails_helper'

RSpec.describe 'Admin::User' do
  describe 'GET /admin/users' do
    # 以下を全て補完してくれる!
    subject { get admin_users_path }

    context '正常系' do
      before do
        create_list(:user, 2)
      end

      it '200を返す' do
        subject
        expect(response).to have_http_status(:ok)
      end
    end
  end
end

テストが書かれていないエンドポイント一覧は手元にあるため、ほとんどエンドポイントをコピペするだけで index action に対応する request spec を増やしていくことができました。

その結果、以下のように 32.74% → 41.47% までカバレッジを伸ばすことができました 🎉

root@084b7fc12fd0:/usr/src/app# bundle exec rake endpoint_coverage:collect_for_admin
テストされたルート数: 209
テストされていないルート数: 326
全ルート数: 504
カバレッジ: 41.47%

改善その2:使われていない batch_action の削除

テストが書かれていないエンドポイント一覧を眺めていると、多くのリソースに対して batch_action エンドポイントが生えていることが分かりました。これは一覧画面で各リソースにチェックを入れて一括で削除するといった処理を行うために ActiveAdmin が用意しているものになります。
Active Admin | The administration framework for Ruby on Rails

batch_action をデフォルトで有効にするかどうかは設定で変更可能なのですが、タイミーでは有効になっているようでした。

「一括操作ってそんなに行うことある?」と思い過去1年間のログを確認したところ、batch_action が使われているリソースは1つしかありませんでした。そのため、全体では無効化し使われているリソースにのみ batch_action を有効化しました。
これまで定義されていた batch_action は気付かず定義されていたのか、開発者による善意のものだったのかは判断できませんが Code Line Coverage では気付くことが難しく Endpoint Coverage を見ていたからこそ気付けたものかなと思っています。

その結果、以下のように 41.47% → 48.98% までカバレッジを伸ばすことができました 🎉

root@084b7fc12fd0:/usr/src/app# bundle exec rake endpoint_coverage:collect_for_admin
テストされたルート数: 217
テストされていないルート数: 257
全ルート数: 443
カバレッジ: 48.98%

目標としていた Endpoint Coverage 60% にはまだ届いていませんが、元々が 32.74% だったことを考えるとかなり近づいたのではと思っています。

まとめ

Rails アップグレードの手間を減らすために社内向け管理画面のテストを拡充させようと考え、Endpoint Coverage という指標を定義しました。Endpoint Coverage を改善するためにいくつかの改善を行い、約30%から約50%と目標の60%に近づけることができました。Endpoint Coverage を定義し、テストされていないエンドポイント一覧がわかったことで様々な改善アイデアが思いついたように感じます。

これからも Endpoint Coverage を高めていき Rails 7.2 アップグレードでは手動での動作確認が必要なくなるよう頑張っていこうと思います。

ストレングスファインダー共有会を実施しました!

こんにちは、データ統括部でデータアナリストをしているyuzukaです。

今回は、データ統括部のアナリストを対象に実施した「ストレングスファインダー共有会」について紹介します。

ストレングスファインダーとは?

ストレングスファインダーとは、米国のギャラップ社が開発した「強みの診断」ツールです。

WEB上で177個の質問に答えると、34の資質の中から自分の強みや資質を知ることができます。

診断は有料ですが、弊社では会社の経費で受けられます。(ありがたい・・・!)

私の強みTOP10はこんな感じでした。

ストレングスファインダーに着目した背景

個人の強みに着目するコンセプト

職場での性格診断に適したツールとして、MBTIやDISCなど有名どころはいくつかありますが、中でもストレングスファインダーは個人の「強み」にフォーカスしているところが良いと感じました。

ただ相互理解を深めるだけでなく、それぞれの強みを仕事に活かしていこう、という前向きな気持ちになることができます。

実際にストレングスファインダー共有会で利用した資料

実際に取り組んだこと

事前準備

ストレングスファインダー共有会の開催にあたり、準備した内容は以下の通りです。

  • ストレングスファインダーのアクセスコードを、人数分まとめて購入して配布する
  • 参加者にはあらかじめ診断を受けてもらい、診断結果とひとこと所感を記入しておいてもらう

参加者に負担がかからないかつ、当日の進行がスムーズになるようにロジ周りを意識しました。

ストレングスファインダー共有会の内容

オンラインで集まり、和気あいあいとした雰囲気で強みの共有会を行いました。

  • ルーレットでランダムに指名して、1人ずつ自分の強みを発表
  • 事前に記入してもらった診断結果と所感を見ながら、4-5分話してもらう
  • みんなでわいわい、感想や質問を言い合う

これを人数分繰り返す形式で実施しました。

当日は想定していた以上に盛り上がり、時間があっという間に過ぎ去りました。

「新しいことを始めるのが得意」「学習欲が強い」「目標に向けて、人一倍努力できる」「ゲームのオリジナルルールを考案するのが得意」など、参加者それぞれのユニークな強みを知ることができました。

おわりに

ストレングスファインダー共有会の開催からしばらく経ちますが、通常業務のコミュニケーションの中でも、お互いの強みに言及する機会が増えたように思います。

データ統括部は今後も積極的にメンバーを増やしていく予定なので、ストレングスファインダー共有会も、メンバーが増えたタイミングでの定期開催を考えています。

We’re Hiring!

タイミーのデータ統括部では、私たちとともに働くメンバーを募集しています。

現在募集中のポジションはこちらです。

カジュアル面談も行っていますので、興味を持っていただけた方は、ぜひお話しさせてください!

マネフォとタイミーでdbtに関する合同勉強会を実施しました!!!!

この記事は "Timee Advent Calendar 2023" の2日目の記事です。

qiita.com

こんにちは、株式会社タイミーの土川 (@tvtg_24) です。

先日、マネーフォワードさんとアナリティクスエンジニアリング周りの合同勉強会を開催しました!

自分が所属するデータ統括部では初めての試みだったんですが、とても良い会になったと思うので少しこの記事で紹介できたらと思います!

きっかけ

マネーフォワードの木宮さん (@yuu_kimy) と自分は定期的にご飯に行っていて、いつもお互いのデータ関連の話をたくさんさせていただいてました!

そんな中、もっと社内のメンバー巻き込んで情報交換したいね、みたいなお話をしていたところ、ちょうどRettyさんとマネーフォワードさんで合同勉強会を開いたとのことでしたので、それを参考に合同勉強会を実施しました。

木宮さんには、当日のアジェンダ作成など合同勉強会実施のための諸々準備をしていただいて、とても感謝してます!

当日の様子

当日のアジェンダ

アジェンダは以下のようになっていて、発表は各社2つずつ行い、最後に時間が許す限りフリーディスカッションでdbtについて話しました。

会自体はオンラインで行い、お互いの会社から計10名以上が参加する賑やかな会になりました!

アジェンダ

発表振り返り

発表はタイミー側から 大越さんと、okodoon (@miburo_data) が、それぞれ「データアナリストがdbtを触ってみた」、「dbtジョブ分割実行について色々考えた話」というテーマで発表しました。

マネフォさん側からは、奥野さん (@RossOkuno)と木宮さんが、それぞれ「マルチテナント分析基盤について」、「dbtをAirflowで動かす道のりは続く」というテーマで発表しました。

発表のダイジェストについてはマネフォさん側の記事 (https://note.com/yuu_kimy/n/n236c5d5047ad) で紹介されているので、詳しくはそちらをご覧ください。

マネフォさんとタイミーは使っているデータ基盤サービスは似ているんですが、プロダクトの数や、事業規模が違ったりするため、複数組織でのデータ分析環境の提供についてのノウハウや、苦労したところなどがたくさん聞けて、すごく勉強になりました。また、Cosmosといったタイミーが使っていない新しめのpythonパッケージについての利用感が聞けたのはとてもよかったです。タイミーでも今後の参考にしていきたいと思いました。

dbt活用に関するフリーディスカッションについて

フリーディスカッション

会の最後には、dbt活用に関するフリーディスカッションを1時間ほどしました。

発表自体で消化できなかった質問や、dbt Coalesce で話題になっていたdbt Cloud CLIなどを使った、dbt Core, dbt Cloudの使い分けについてなど、様々な議論をしました。

また普段あまりオープンな発表では公開しづらい、各々のデータモデリングの詳細などについて話せたのはとてもよかったと思います。

終わりに

今回は、初めての合同勉強会でしたが、とても楽しく、有意義な時間になりました。

会社ぐるみで一つのテーマに対して、深く議論する機会は普段なかなかないのと、やはりオープンな場より、一歩踏み込んだ情報をもとに議論ができることが個人的にとても良いなと思いました。

また、より良いデータ分析環境を提供するという同じ目標を掲げて試行錯誤しているマネフォさんをみて、タイミーも追いつけるように頑張らないと!という気持ちになりました!

これからも合同勉強会のような機会は増やしていけたらなと思っているので、興味のある会社さんはぜひX (旧Tiwtter) でお声かけください!

採用関連

タイミーは絶賛採用中です!ぜひお力を貸してください!

hrmos.co

技術的な雑談をするテックトークを開催して半年が経ちました

はじめに

こんにちは、マッチング領域でバックエンドエンジニアをしているぽこひで ( @pokohide ) です。

タイミーのアドベントカレンダー2日目の記事です。

今回は、タイミーのプロダクト組織で毎週開催している技術的な雑談を行うテックトークの紹介をします。なぜ開催しようと考えたか、どのように運用をしているかなどをお話しします。

開催の背景

タイミーのプロダクト組織では、働き方の柔軟性を担保する観点などからフルリモートという働き方を選択しています。また、タイミーではチームトポロジーを採用しており、それに沿ってチーム構成などを考えています。

チームトポロジーの変遷や取り組みについてはCTOとCPO(発表当時はVPoT)が過去に発表を行っているので詳しく知りたい方はこちらをご覧ください。

チームトポロジー Vol. 2 「組織をチームトポロジーで振り返るメリット」タイミー 亀田 彗 | ITエンジニア向けのトレンド情報

組織をスケールさせるための Four Keys とチームトポロジー - Speaker Deck

チームトポロジーによって、チームが疎結合になることでコミュニケーションの複雑性が抑えられたりチームの柔軟性が増すなど利点はありますが、インフォーマルコミュニケーション(業務外の日常的な会話や雑談)が減り仲間意識が薄れる可能性もあります。さらに、フルリモートはこの流れを助長する可能性があります。

疎結合性を確保しつつも適度なコミュニケーションや協力を促進するバランスが重要と考え、テックトークという会を開催*1しようと考えました。

2023年9月に発売された「GitLabに学ぶ 世界最先端のリモート組織のつくりかたドキュメントの活用でオフィスなしでも最大の成果を出すグローバル企業のしくみ」でもリモート組織を作る観点でですが、インフォーマルコミュニケーションが従業員のパフォーマンス向上やメンタルヘルスの問題解決に重要な役割を果たすという研究結果が紹介されています。

GitLabのカルチャーは、「GitLab Value」「仲間意識(信頼と友情)」「ワークスタイル」という3つの要素で構築されており、仲間意識を醸成するためにインフォーマルコミュニケーション(業務外の日常的な会話、雑談、何気ないやり取り)が「意図的」に設計されています。

オフィスなしのオールリモートで成長するGitLab社、世界中の2,000人をつなぐカルチャーとは|CodeZine(コードジン) から引用

と、それっぽい理由を書いていますが、他のチームで起きた技術的に面白い事やその時々の興味深いテックニュースなどをゆるく駄弁りたいという個人的な欲求が発端というのもあります。

毎週ゆるく開催するテックトークについて

2023年2月から毎週金曜日に夕方から最長1時間枠で開催している技術的な雑談を行う会です。

SlackのHuddleを利用しており、会話から抜ける時の確認は不要で入退室は自由です。

テックトーク

技術的な話題である事のみが制約で、あとは雑談でもLTの練習場でも何でも自由に使って良い時間としています。

話題は持ち寄り制で、最近の技術ネタや面白いPRなどがあれば自由に書いてもらう形式で運用しています。何もなければその場の雰囲気で会話したり、早めに会を終わらせています。

とはいえ、持ち寄るのも大変なので会の冒頭10分に、1週間にあった技術的なWINやポストモーテムの学びを共有する時間を設けています。ここからさらに深掘りたいものがあれば話題に移して話しましょうといった流れです。

テックトークの仕組み化

テックトークを開催するにあたって、参加者に満足してもらいたいのは勿論ですが、それ以前に継続的に開催する事が大切と判断し、そちらを重視しました。

そこで運用コストを最小化するためにも内容をシンプルにし、仕組み化にもこだわっています。

開催するからには気軽に参加してもらいたいのでSlackbotのリマインダーを活用しつつ、Slack Huddle上で開催しています。当初はGoogle Meetを使っていましたが、カレンダーに招待されていないと暗黙的でクローズドな会と誤解されると思ったからです。

時間配分や会の内訳はシンプルです。

  • 会の説明や目的の共有
  • WINの共有
  • ポストモーテムの学び共有
  • 雑談タイム

以上です。前半の共有は経験則的に長くとも10分程度で終わります。タイムキーパーを用意していません。あとは適当に駄弁るだけです。

会の説明や目的の共有

会によっては、初めて参加してくれる方もいるので「この会は、テックな話題である事以外は特に制約はなく、入退室も自由なゆるい会ですよ」とお伝えしています。

WINの共有

タイミーのプロダクト組織では、技術的に面白い取り組みやドキュメントの更新、エラー対応、パフォーマンス改善など文字通りWIN!と感じたものに :win: スタンプをつける文化があります。そこで、 :win: スタンプが付いた投稿を特定のチャンネルに集約して、テックトークで触れやすくしています。

ここでは、WINを共有するだけに留め、パフォーマンス改善などその背景にあったツラミをもう少し深掘りたい場合は、後続の雑談タイムで話すようにしています。

余談ですが、:win: というスタンプはあまり汎用的すぎる名前で他の部署がつけたWINも収集してしまい収集チャンネルがノイジーになっていました。そこで、メンショングループXに所属するユーザーがスタンプYをつけた時にチャンネルZに通知するSlack BOTを作りました。

このBOTについては、またどこかで紹介できればと思います。

この辺も今後はNotionに自動で転記するなどより自動化していきたいですね。

ポストモーテムの学び共有

ポストモーテムをNotionのDBで管理しているので、その週に開催されたポストモーテムだけを表示するようにフィルタリング条件を調整し、準備不要で触れられるようにしています。

ここでも時系列を振り返るのは時間をとりすぎるので、影響範囲や原因、学びのまとめのみを共有しています。

雑談タイム

この時間に話す話題をDBの1レコードとして管理しています。最近は参加者も話題も増えたため、気になる人は投票してもらう制度を導入し、どの話題から触れていくかを決めています。

議事録は話題レコードの中に雑に記載しています。話題をDB管理しているのは、テックトークでの雑談からTechBlogや登壇のネタになると嬉しいな考えているからです。これも特に目的として明文化してませんが、この仕組みが機能していく事に乞うご期待です。

  • Rails 7.1に上げるための残作業
  • 論理削除のつかいどころ
  • テクノロジーレーダー9月号を眺めてみる
  • モジュラモノリスにおけるパッケージ間のDBトランザクションの扱い
  • 技術検証を活性化するためにはどうすればいいか

例ですが、過去にはこういった話題が話されていました

やってみて

2023年2月から開催し、開催回数は30回を超えました。

準備も特に必要なく、自分もただの一参加者気分で参加できているので気負わず継続できているのも良いことです。当初考えていた技術的な話題を駄弁りたい欲求も満たされ、他のチームメンバーとも交流ができています。

自分だけ述べても公平性に欠けるので、参加してくださっているみなさんのコメントも欲しかったのですが、アドベントカレンダーの締切間近すぎて間に合いませんでした。なので、これは自分一人の勝手な妄想かもしれないですが、最近は常に6人以上は集まってくれているので客観的に見て満足はしてくれているのでしょう…(そう信じたい笑)

さいごに

今回は技術的な雑談を行うテックトークの紹介や、継続的に開催するためにどのように仕組み化しているかをお話ししました。

テックトークの参加者は増えてきています。嬉しい悲鳴ですが、参加者が増えすぎるとこの会の主目的である雑談が難しくなります。それは今後の課題なので、テックトークフランチャイズ化やランダムに参加者を分割してブレイクアウトルームのようにするなど色々試していければと思います。

また、ここで話された話題からテックブログのネタなどが生まれる事を個人的に期待しているのでそちらも乞うご期待ください。

この活動について、より詳しく知りたいと思った方はカジュアル面談受け付けておりますので、是非お話ししましょう!過去の話題や議事録は残っています笑

product-recruit.timee.co.jp

*1:定例は増やせばいいという訳ではなく適切に開催することが大切です。過去には、技術改善の文化を根付かせるためにプロダクトミライ会議という技術的負債を扱い、どのように解消していくか話し合う会議体を設けていましたが、技術改善の文化が根付いてきたこともあり、テックトーク開催と並行して現在はクローズしています。

タイミーのRailsアプリをシニアなエンジニアが採点したらだいぶ辛口だった

この記事はTimee Advent Calendar 2023シリーズ 1の1日目の記事です。

はじめに

こんにちは、タイミーでバックエンドエンジニアをしている須貝(@sugaishun)です。昨年は弊社でアドベントカレンダーに取り組んだか覚えていないのですが、今年はなぜかいきなり3トラックで臨むということで、非常に勢いがあるなと思いました。量と勢いで攻めていくところが弊社らしいなと感じています。全て完走できると良いですね。

さて私はその中のひとつのトップバッターということで、タイミーのRailsアプリケーションについて弊社のシニアなエンジニアたちと雑談した内容を座談会風にお伝えできればと思います。事の発端は弊社Slackのバックエンドエンジニアが集まるチャンネルで「タイミーのRailsアプリケーションの健康度はどのくらいなのか?」という会話をしたことでした。その時の私の感想は「人によってけっこう基準が違うなあ」といったものでしたが、改めて話を聞いてみると自分の中で発見がありました。参加者は以下のとおりです。

参加者プロフィール

難波さん(@kyo_nanba

シニアバックエンドエンジニア
ファッションEC系スタートアップの開発責任者やメドピア株式会社のGMなどを経て2022年にタイミーに入社。プラットフォームチームの立ち上げやフィーチャーチームとのコミュニケーション設計に取り組み、直近では会社の技術戦略と現場の技術的ロードマップを接続する役割を担う傍らRailsアプリケーションの設計やリアーキテクチャに関わっている。

神速さん(@sinsoku_listy

バックエンドエンジニア
2022年11月入社。CTO室に所属し、Railsアプリケーションの開発効率を向上するために型(RBS)の導入やCIの実行速度の改善などの施策に取り組んでいる。

須貝(@sugaishun

バックエンドエンジニア
2022年1月入社。スポットワークシステム領域でエンジニアとして活動。Ruby on Rails ChapterのChapter Leadも務める。Leadとついているが偉いわけではない。好きな言葉は「容赦ないリファクタリング

では、ここからが本編です。

タイミーのRailsアプリは60点

須貝:以前SlackでタイミーのRailsアプリケーションが健康かどうかという話をしたと思うんですけど、ここでは健康 = アプリケーションの保守性が高い状態ということにして話をしていきたいと考えています。難波さんはけっこう厳し目の評価をしていたと思うんですけど、主観で構わないので今のタイミーのRailsアプリケーションを100点満点で点数をつけるなら何点くらいなんですか?

難波:60点くらいですかね。

須貝:やっぱりけっこう厳しい。

神速:高専だと赤点ギリギリですね。

難波:不可ではない、という感じです。入った当初の印象は60点くらいでこの1年で色々取り組んできて65点になったかな、というイメージです。タイミーはプロダクトとしては成長できているし、頻繁に障害が起きているわけでもない。世の中に価値を提供できているのでその点では合格だとは思います。

ただ、ここから上を目指していくためには、まだ我々は合格ラインのギリギリ上くらいなんだぞ、と。そういう想いも込めてこの点数にしています。

須貝:具体的にどの辺りが伸びしろだと考えているんですか?

難波:ひとつはSentryのアラートですね。僕が考えるヘルシーなプロダクト組織だったら基本的にはSentryのアラートは鳴らないし、鳴ったらみんながそれを直すべき対象だと思ってできるだけ直す。で、直したらちゃんとresolveして、というのができるようになったらもっと点数が上がるかなと思います。
もうひとつはスロークエリが管理できていない。スロークエリが出ているということはユーザー体験に直結することなので、バッチ処理などであればまた話は別ですけど、現在はきちんと管理できていないのは課題ですね。
最後は自動テストの信頼性です。テストが全部パスしているということは本番にデプロイしても大丈夫ですよねという状態を期待しているんですが、テストがパスしているから大丈夫とはあまり思えない。

須貝:たしかにテストの信頼性は僕も課題に感じています。テストカバレッジ自体は低くはない*1んですけど、仕様のカバレッジが高いかというとちょっと不安なんですよね。
反対に良い点は何でしょうか?

難波:システムがモノリスでやっていけているところは良いところだと思います。マイクロサービスと比べるとモノリス*2のほうが保守性が高いと思っているので。
あとはアプリケーションの保守性に直結するわけではないんですが、CIが速いことでしょうか。CIが速いイコール何かあったらすぐわかるので色々なトライもしやすい。結果的に保守性に寄与する良いところだと思います。

須貝:CIは今何分くらいでしたっけ?

神速:デプロイまで含めると12〜13分くらいですかね。CIだけで見ると8、9分くらいだと思います。

難波:最後にもうひとつ、github-flowで運用できていることも良い点だと思います。いわゆるgit-flowのようにreleaseブランチ的なものを用意して、QAしてmainブランチにマージしてデプロイというのもそれはそれで良いやり方だとは思います。ただ、mainブランチにマージしたら即デプロイというgithub-flowはコードの品質をみんなが信頼していないとできないことだと思います。

カナリアリリースが普通、みたいなチームを目指したい

須貝:神速さんは100点満点で点数をつけるなら何点くらいですか?

神速:45とか50点ですかね。

須貝:だいぶ低いですね(笑)

神速:自分の中での100点となるとGitHub社みたいにバンバン本番にデプロイして、カナリアリリースも当たり前で、みたいな組織です。さらにテストコードもRails本体のリポジトリと同じレベルのクオリティで書く。それが私の中の理想で、それと比べたら今は45点くらいかなと。

須貝:デプロイの話が出てくるあたりが面白いですね。神速さんらしいといいますか。

神速:これは私がインフラもやっているからとかではなく、顧客へ価値をいかに早く届けるかですとか、障害が起きた時もいかに早く直すかというのを大事にしていて、デプロイが大事だと思っているのが根底にあります。

須貝:神速さんはどういう状態が健康と考えていますか?

神速:健康さでいうとまず、RubyRailsの最新のバージョンを使うことです。あとはこれに付随して、RubyRailsを最新のバージョンにするためにgemのバージョンを上げ続ける運用があるか。dependabotの整備などもこれにあたります。
あとはテストコードがあるとかレビューをしている、とかでしょうか。難波さんに比べてだいぶ基準が低いんですけど(笑)

須貝:これは過去に経験してきた現場によって基準は変わってきそうですよね。テストを書いているとかレビューしているとか、自分は当たり前だろうと思うんですけど勉強会などで他社のエンジニアと話すと「テストないです」「レビューもないです」というのは普通に耳にします。

神速:ただそこを基準にするよりはもっと上を見たいですね。カナリアリリースが普通、みたいなチームを目指したい。

須貝:タイミーの良いところは?

神速:難波さんが挙げてくださった以外だと、CIでRailsのedgeを使ってテストを走らせているのはレアなのでそこは良いところです。それに付随して弊社のエンジニアがRailsの最新機能を教えてくれる、みたいな福利厚生がある。
後はRBSのような最新機能を導入することにみんなポジティブで、止める人がいない。やってみようという空気があるのは良い点です。

須貝:やっていきのある人が多いですよね。だから一回やってみましょうという文化がある。逆に伸びしろは?

神速:さっきデプロイ時間の話がありましたけど、私はもっと速くしたい。今はデプロイまでの時間が長いと思っています。
Railsアプリの話でいうと、難波さんと同じでテストの書き方とか保守性はもうちょっと考えたいですね。バグがあったらバグを再現するテストを書くとか。機能を追加する時も既存のテストに手を入れるのではなく、テストを追加してカバレッジを高めるような考え方は広まってほしいとは思います。

須貝:パフォーマンスの自動テストはちょっと難しそうですね。

神速:でもたとえばコミットログに残すとかはできそうですけどね。パフォーマンスのテストは増やさないにしても、Rails本体でもパフォーマンスを計測してコミットメッセージに残したり、SQLのEXPLAINの内容を貼ったりとできることはあります。「私が速くなったと思うから」ではなくて根拠はほしい。
他の伸びしろを挙げるならレビューの仕方ですかね。「良さそう」でapproveではなく、パフォーマンスや保守性まで考慮したレビューがほしい。それを気にする人が増えてほしいです。ただ良いレビューをする方法を私が教育したいかというとそれは難しいな、という気持ちがあります。

難波:その気持ちはよくわかります(笑)。

須貝:課題感はあるけど自分が率先してやりたいわけではないという。そういったものはRailsに限らず社内にはいくらでもありますよね。
ここまででタイミーでの開発の良いところや伸びしろについて語ってきましたが将来的にこうなっていてほしいというイメージを伺えますか?

難波:なかなかすぐに実現するのは難しいと思うんですけど、良い設計のシステムにしていきたいですね。例えばRSpecのcontextがわかりやすいんですけど、contextが多重に入れ子になっている時はテストコードの問題というよりはテスト対象クラスの複雑性の問題なんですよね。責務が適切に分解されていないのがテストコードに表出してしまうという。そういうことが起きないようなアプリケーション設計になっていってほしいなと思っています。

須貝:頑張ります。だいたいChapter Leadの僕に返ってくる話ですね。

神速:ただジュニアなエンジニアが頑張っても難しいところはあるので、できる人が教えてあげる環境は何かしら作らないといけないですよね。

難波:そうしたほうが良いというのはすごくわかります。それでいうと今タイミーでは各Squad(チーム)が独立して開発できることを良しとしていて、そこと先輩が教えて知識を伝搬していくことを両方満たそうとすると各Squadに最低一人はミドル〜シニアレベルのエンジニアがいる必要が出てくる。それはけっこう難しいですよね。

須貝:なのでシニアなエンジニアの方、ぜひ弊社に来てくださいという。ちょっとオチがついたっぽい感じになったので今回はこの辺にしておきましょうか。

おわりに

いかがでしたでしょうか。弊社のエンジニアは基準が高いなと思いましたね。やっていくしかない。タイミーでの開発についてもっと知りたいという方、ぜひカジュアル面談でお話しましょう。

product-recruit.timee.co.jp

最後になりますが、執筆にご協力くださった難波さん、神速さん本当にありがとうございました。

*1:2023/11/27現在、ラインカバレッジで91.5%

*2:タイミーでは現在モジュラモノリス化を進めている