SmartHR Advent Calendar 2023 シリーズ2の14日目です。
SmartHRでプロダクトエンジニアをしている kazukun です。
2023年は4チームを経験し、個人的には激動の1年だったので、その記録を残します。
所属チームの変遷
- 〜 2023.04 分析レポート
- 2023.04 〜 2023.09 スキル管理
- 2023.08.28 〜 2023.09.20 社内新規事業
- 2023.10 〜 配置シミュレーション
けっこう異動が多いですね。
去年の今頃は、まさか1年でこんなにたくさん異動するとは思っていませんでした。
分析レポート
2021年8月の入社以来、分析レポートを担当してきました。
SmartHR基本機能のBIツール的な立ち位置で、内部では生SQLを動的にゴリゴリ組み立てる、Railsを使っているのにRailsっぽくないプロダクトです。
リリースしてから4年以上経過しており、feature開発よりも機能改修やパフォーマンス改善を中心に行っています。
今年に入ってから自分が担当したタスクの一つで、Pull Requestごとに検証環境を用意する仕組みを導入しました。
お手軽にPull Requestごとに検証環境を作成できるので、PMなどエンジニア以外の人に開発中の機能を触ってもらったり、スプリントレビューの準備が短縮できたり、色々とメリットが多かったです。
仕組みの詳細は「GCPを使ってPRごとに検証環境を用意した話 - SmartHR Tech Blog」で紹介されていますので、併せてご確認ください。
この先も分析レポートをずっと担当していくのかなぁ、とぼんやり考えていた矢先転機が訪れました。
スキル管理
4月上旬、上長から「スキル管理チームにレンタル移籍で行ってみない?期間は4月中旬から6月いっぱいまでだよ」という打診を受けました。
レンタル移籍って何やねん、って思いました。
スキル管理は当時まだリリース前で、それに向けてどんどん機能開発しているフェーズでした。
インフラの準備ができておらず、最初はそこを巻き取ってほしいとのことで、レンタル移籍という少し特殊な異動ではありましたが、自分のスキルを活かせると思い快諾しました。
開発メンバーは最初2人で、そこに私が入り、さらにリリース直前に4人、5人と増えていきました。
開発チームの雰囲気が掴める「スキル管理チームの「入社半年〜ズ」が感じる、仕事と成長をドライブするSmartHRの文化 - SmartHR Tech Blog」という座談会形式の記事もあるので、併せてご確認ください。
自分の担当したタスクの話に戻りますが、まずインフラ構築にあたって、内容を整理しながらざっくりとした構成図を作成しました。
最初に構成図を用意しておくと、その後の構築作業がイメージしやすいです。
詳細は省きますが、Cloud Runを使用してNext.js用とRails用のサーバをそれぞれ動かし、App Engineを使用してワーカーを動かす構成です。
SmartHRではterraformでインフラのコード管理をしているのですが、terraform用リポジトリに共通で使用できるモジュールが用意されているので、それを組み合わせることで比較的スムーズに構築ができるようになっています。
実際の作業の流れとしては、大まかに以下のようなイメージです。
- ネットワーク・セキュリティ・ミドルウェアの設定および構築
- サーバ・ロードバランサ・DNSまわりの設定および構築
- CI/CDの整備やアプリケーション側リポジトリに設定ファイルの追加
また、今後の引き継ぎなども考慮して、早い段階でドキュメントを整備したり、チーム内で知見の共有会を実施するなど、極力属人化しないように注意しました。
ここまで技術的な話をあまりしていないので、構築にあたって苦労した点を一つご紹介します。
スキル管理ではDockerイメージのビルドにkanikoを使っているのですが、その際にSecret Managerから秘匿情報を参照してビルド時に渡す方法でつまづきました。
以下はCloud Build上で実行するための設定ファイルの抜粋なんですが、args フィールドに配列形式で秘匿情報(secretEnv)を渡しても展開されませんでした。
steps:
- id: 'Build and push image'
name: 'gcr.io/kaniko-project/executor:latest'
args: [
'--build-arg=PROJECT_ENV=$${_PROJECT_ENV}',
'--build-arg=SECRET_VALUE_FOO=$${SECRET_VALUE_FOO}',
'--build-arg=SECRET_VALUE_BAR=$${SECRET_VALUE_BAR}',
'--build-arg=SECRET_VALUE_BAZ=$${SECRET_VALUE_BAZ}',
'--destination=${_IMAGE_URL}',
'--cache=true',
'--compressed-caching=false',
]
env:
- 'DOCKER_CONFIG=/kaniko/.docker/'
secretEnv:
- SECRET_VALUE_FOO
- SECRET_VALUE_BAR
- SECRET_VALUE_BAZ
options:
# snip
timeout: 600s
substitutions:
_APP_NAME: 'default_name'
_PROJECT_ENV: default_env
_IMAGE_TAG: default_value
_IMAGE_URL: 'asia-northeast1-docker.pkg.dev/${PROJECT_ID}/${_APP_NAME}/${_APP_NAME}:${_IMAGE_TAG}'
availableSecrets:
secretManager:
- versionName: projects/${PROJECT_ID}/secrets/secret_value_foo/versions/latest
env: 'SECRET_VALUE_FOO'
- versionName: projects/${PROJECT_ID}/secrets/secret_value_bar/versions/latest
env: 'SECRET_VALUE_BAR'
- versionName: projects/${PROJECT_ID}/secrets/secret_value_baz/versions/latest
env: 'SECRET_VALUE_BAZ'
argsフィールドに /bin/bash の-cオプションでdockerコマンドを実行する形式だと秘匿情報(secretEnv)が展開されます。
steps:
- id: 'Build and push image'
name: 'gcr.io/kaniko-project/executor:latest'
entrypoint: /bin/bash
args:
- '-c'
- |
docker run \
--network=cloudbuild \
-v $(pwd):/frontend \
gcr.io/kaniko-project/executor:latest \
--context=dir:///app \
--dockerfile=Dockerfile \
--build-arg=PROJECT_ENV=${_PROJECT_ENV} \
--build-arg=SECRET_VALUE_FOO=$$SECRET_VALUE_FOO \
--build-arg=SECRET_VALUE_BAR=$$SECRET_VALUE_BAR \
--build-arg=SECRET_VALUE_BAZ=$$SECRET_VALUE_BAZ \
--destination=${_IMAGE_URL} \
--cache=true \
--compressed-caching=false
env:
- 'DOCKER_CONFIG=/kaniko/.docker/'
secretEnv:
- SECRET_VALUE_FOO
- SECRET_VALUE_BAR
- SECRET_VALUE_BAZ
options:
# snip
timeout: 600s
substitutions:
_APP_NAME: 'default_name'
_PROJECT_ENV: default_env
_IMAGE_TAG: default_value
_IMAGE_URL: 'asia-northeast1-docker.pkg.dev/${PROJECT_ID}/${_APP_NAME}/${_APP_NAME}:${_IMAGE_TAG}'
availableSecrets:
secretManager:
- versionName: projects/${PROJECT_ID}/secrets/secret_value_foo/versions/latest
env: 'SECRET_VALUE_FOO'
- versionName: projects/${PROJECT_ID}/secrets/secret_value_bar/versions/latest
env: 'SECRET_VALUE_BAR'
- versionName: projects/${PROJECT_ID}/secrets/secret_value_baz/versions/latest
env: 'SECRET_VALUE_BAZ'
同様の事象で困っている方は参考にしてみてください。
そんなこんなで、development, staging, production環境の構築を完了することができ、その後はひたすらリリースに向けて機能開発をしていました。
もともとは6月末までのレンタル移籍でしたが、リリース日が8月22日(通称パニーニの日)になったこともあり、9月いっぱいまではスキル管理チームで仕事をする予定となりました。
社内新規事業
8月22日のリリースを無事終えた後、上長から「社内でやってる新規事業のMVP開発を9月中旬までに完了させる必要があって、人が足りないみたいだからレンタル移籍で行ってみない?他に空いてる人がいなくて…」と打診を受けました。
レンタルのレンタルかぁ、って思いました。
スキル管理のリリースが終わった直後だし少し休みたいな、2週間ちょっとでまっさらな状態からリリースまで持っていくのは大変そうだな、と少し躊躇しましたが、他チームですぐに対応できそうな人がいなそうだったので受諾しました。
開発メンバーは自分含めて3人でした。
とにかく時間がなかったので通常SmartHRの開発チームで導入しているスクラムは採用せず、極力ミーティングの時間を減らしひたすら開発する方針になりました。
まずは大急ぎでstaging, production環境のインフラ構築をしました。
Herokuなど別の選択肢もありましたが、社内のインフラ環境はなるだけ揃えておきたかったので、スキル管理とほぼ同じ構成で、だいたい2日ちょっとで構築しました。
MVP開発ごとに環境をつくるのは大変だと思うので、今後は簡単に環境を用意できる仕組み化の整備をやってみるのも良さそうだなと思っています。
そのあとは、ひたすら機能開発を進めていき、なかなか無茶なスケジュールではありましたが、途中で開発スコープを調整するなどして、当初の目標の9月中旬に間に合わせることができました。
配置シミュレーション
ちょうど社内新規事業の開発に入る直前に上長から「10月以降、配置シミュレーションチームでチーフを引き受けてほしい」と打診を受けました。
これまではメンバーとして開発をしていたので、チーフとして開発チームをマネジメントすることに自信はなかったのですが、これも良い機会だと思い快諾しました。
ちょうど配置シミュレーションチームは、10月以降1チーム体制から2チーム体制に移行するタイミングでした。
もともと別システムを開発していたチームがそのまま配置シミュレーションチームに加わる形です。
またそれに合わせて、開発フレームワークも1チームスクラムからLeSSに移行するなど、かなりドラスティックな変更が入るタイミングでした。
不安はありましたが、もともと配置シミュレーションで開発していたチームの手厚いサポートを受けながら、比較的スムーズにJOINすることができたと思います。
複数チーム間でのスムーズなコミュニケーションを実現する取り組み事例として「チーム間コミュニケーションにおける「ただ話す」のすすめ - SmartHR Tech Blog」も併せてご確認ください。
個人的な話をすると、「チーフになることでミーティングの時間が増え、そのしわ寄せで作業時間が減ってしまうのでは」という不安な気持ちがありました。
実際チーフ会議や1on1などで、メンバーのときと比べ開発に割ける時間は減りました。
そこへの対処法の一つとして、ミーティング週と作業週をきっちり分けてスケジュール管理することが挙げられます。
ミーティング週では主にレビュー作業や壁打ち相手になる程度に留め、作業週ではいちメンバーとしてスプリントタスクをこなす、といった具合です。
現状は開発にリソースを割けるチームメンバーが少ないこともあり、プレイングに重きをおいて振る舞っていますが、今後はバランスを見極めつつマネジメントと開発を両立させていきたいです。
最後に
2023年は個人的にドラスティックな一年でした。
SmartHRでは1年で4チーム経験するのは珍しいことなので、良い経験になりました。
また、レンタル移籍に耐えうるメンタルができた、とも思っています。
打診されたら取り敢えず受けてみて、やってみてから苦労しよ、の精神でこれからも色々とチャレンジしていきたいです。