難易度の高い課題を技術を楽しみながら解決したい
技術的に難易度の高いシステム設計や構築に関わることにやりがいを感じています。
今後3〜5年後の目標としては、テックリードのような存在として、技術的に難易度の高い課題に取り組み、サービスの技術的な水準を引き上げるような立場を目指したいと考えています。
一番関心があるのはサーバーサイド領域の技術ですが、フロントエンドやインフラ、タスク管理などの分野にも面白味を感じています。他の分野にもある程度見識がある柔軟性を持ちつつも、主軸としてはサーバーサイドを専門として、バランスのとれたエンジニアとしてチームに貢献できる存在でありたいと思っています。
そのために今後も、自分自身の好奇心の気持ちを大事にして、色々な分野に積極的に手を伸ばしたり、技術そのものに対する本質的な探求を続けていきたいと思っています。
医師向けのプラットフォームサイトのうち、製薬企業が医師向けに開催する、薬剤に関する講演会を支援するサービスです。講演会開催に関する情報配信・申込管理・運営支援などを提供しており、主に製薬企業からの開催費用を収益源としています。
当初はサーバーサイドエンジニア7名ほどの体制でしたが、プロジェクトの拡大に伴い分化され、最終的にはサーバーサイド4名、PdM3名程度の小規模なプロダクトチームとして機能していました。
長年運用されており、仕様やデータ構造が複雑化している部分が多く、改修時の影響調査に工数を要する傾向がありました。
講演会が一斉に始まる時間帯にはアクセスが集中し、ピーク時の負荷対策が重要な課題となっていました。
サーバーサイドエンジニアとして、以下の業務を担当しました
製薬企業が医師向けに開催する講演会の管理サービスにおいて、講演会の開催時刻にアクセスが集中する特性がありました。そのため、システムが捌ける講演会数に制限を設けて運用されていました。
本業務では、この制限を緩和することを目的とし、パフォーマンス改善に取り組みました。
【課題】
従来は、ピーク時の負荷に基づいて一日に受注できる講演会数の上限をエンジニアの経験則で設定しており、根拠が曖昧な状態でした。
「なぜこの上限値か」という説明ができず、ビジネス側との調整やリスク判断に課題がありました。
【工夫】
そこで、ピーク時のAPIごとの呼び出し数とサーバ負荷(CPU使用率など)の関係をもとに、各APIの「1リクエストあたりの負荷寄与度」を数値で見積もる手法を考案・確立しました。
このアプローチにより、負荷の見積もりを感覚や過去の記憶に頼らず、過去データに基づいた計算で導き出せるようになりました。
【成果】
受注上限を算出する基準を定式化し、その後に控えている負荷改善を行う際の、改善結果の定量的な測定方法の確立に貢献しました。
また、サーバーのCPU・サーバーのメモリ・DBのCPU使用率のうち、どの要素がどの程度ボトルネックになっているのかを明確に数値として算出しました。
【課題】
システム全体のレイテンシがピーク時に大きく上昇し、特に一部の重いAPIがボトルネックとなっていました。
また、レイテンシ改善のためにはどのAPIから優先的に手を入れるべきか、明確な基準がない状態でした。
【工夫】
まず、DatadogのAPMやログを活用して以下の観点からボトルネックとなるAPIを可視化しました:
特に影響の大きいものから優先順位をつけ、以下のような対応を行いました
【成果】
リリース後はその効果検証まで行い、実際にたしかにパフォーマンスが改善されたことまで確認をしていました。
【課題】
別チームのエンジニアを含む同一リポジトリを触る他のメンバーによる改修で、リリース後に思わぬAPIのパフォーマンス悪化が起きていたとき、それに気づくことなくアクセスピーク時刻を迎えてしまうリスクがあり、仕組みとして改善したいという課題がありました。
【工夫】
DatadogのMonitor機能を使い、リリース後2時間のAPIレイテンシを先週の同時間帯と比較して監視し、大幅に悪化していた場合はアラートを出す監視を構築しました。
【成果】
性能劣化の早期検知が可能になり、改修によるパフォーマンス悪化をいち早く察知・対処できる体制を整備しました。
歩数計機能を中心に、健康情報の配信やクイズ機能を備えたtoC向け健康アプリです。ユーザーの健康状態に応じたセグメント配信や、健康関連企業と連携した広告・アンケート施策により、高単価な広告収入を主軸にマネタイズしていました。
アクティブユーザーはDAU約50万人、総ユーザー数300万人規模のサービスでしたが、残念ながら全社の方針により、2024年11月をもってサービスはクローズしました。
すべての開発メンバーは自社所属で構成されており、資金は協力会社との共同出資型のサービスとして運営されていました。
サーバーサイドエンジニアとして、以下を担当しました
後半からはサーバーサイドチームのリーダーを担当し、以下も対応しました
【課題】
ユーザーの基本情報(生年月日・性別など)に新たな項目を追加するにあたり、アプリ・サーバー・協力会社の会員基盤の3システムを同時に切り替える必要がありました。
それぞれのリリースタイミングや仕様に制約があり、システム間の整合性を保ったうえで安全にリリースする難しさがありました。
【工夫】
スムーズなリリースに向けて、技術面・調整面の両方で工夫を行いました。
【成果】
各チームと連携を取りながら調整・実装を進めた結果、3システムを跨ぐ変更にもかかわらず大きな混乱なく本番移行を完了できました。
また、クリティカルパス図による整理がチーム内の認識共有に役立ち、リリース全体の品質とスピードの両立に貢献していたと思います。
【課題】
ユーザーが毎月の目標歩数を設定・記録できるようにするにあたり、履歴管理が必要でした。
履歴データをRDBでどう持たせるかは一般的な定石がなく、パフォーマンスや保守性に配慮した設計が求められました。
【工夫】
履歴テーブルの構成案を複数検討し、それぞれの「パフォーマンス」「複雑さ」「正規化の程度」といった観点で比較しました。
チームとも相談しながら構成を決定し、リリース後の負荷計測も実施することで、理論と実測の両面から設計の妥当性を検証しました。
【成果】
シンプルかつ拡張性の高いテーブル設計を実現し、過去データを安全かつ効率的に扱える仕組みを導入しました。
リリース後の負荷も想定範囲内に収まり、安定した運用につながりました。
【課題】
毎晩実行されるバッチ処理(夜間JOB)の実行時間が長く、サーバーや他処理への影響が懸念されていました。
停止を伴うDBメンテナンスが難しい状況での対応が求められました。
【工夫】
重いテーブルへの適切なインデックスの追加と、該当JOBのロジックの修正を行いました。
【成果】
JOBの実行時間が大幅に短縮され、夜間処理の安定性が向上しました。
停止なしでのインデックス追加や、安全性を担保したデプロイにより、リスクの高い変更もスムーズに完了させることができました。
【課題】
サービスクローズが決定し、その頃からサービスのサーバーサイドのリーダーを担当することになりました。クローズに際して期日のある開発タスク(指定時刻に指定の機能の仕様を変更する、など)が急増したことで、従来のタスク管理手法では進捗の把握や担当の割り振りが困難になっていました。
【工夫】
まずは現状のタスク管理方法を分析し、以下のような課題を洗い出しました:
この課題に対し、以下のようなタスク管理の仕組み化を行いました:
【成果】
タスクの可視化と管理手法の改善により、締切のある複数タスクをスムーズに進行でき、トラブルなくサービスを終了させることができました。
【課題】
サービス終了に伴い、DB内の各種ユーザーデータ(歩数、ポイント、アンケート履歴など)を、指定フォーマットのTSV形式で協力会社側S3へ連携する必要がありました。
ユーザー数・データ量ともに多く、限られたスケジュール・インフラリソースの中で、信頼性や高い性能が求められるデータ送信基盤を構築する必要がありました。
データ連携の実施自体はクローズの早い段階から決まっており、仕様策定のみは他タスクと並行して早めに進めていました。9月頃から11月頃にかけて、時には先輩エンジニアからの助言も借りつつ、設計と実装、連携本番までを完遂させました。
【工夫】
連携する内容の交渉
初期の要件ではすべてのユーザーデータを送る想定でしたが、テーブル数の多さから開発コストが膨らむ懸念がありました。
内容を精査し、ビジネス上不要と思われるテーブルを送信対象から外すことを提案・交渉し、連携対象テーブル数を当初の半分以下に削減しました。
連携タイミングの分割
サービスクローズ後にAWS環境を1週間程で閉じたいというビジネス要件があったため、連携データすべてを終了後に初めて送るのはリスクが高い状況でした。
ほとんどのデータが過去データが更新されないログ系・履歴系のデータであることに着目し、それらのデータはクローズ前にその日の分までのデータは予め連携する方法を提案し、大半のデータはクローズ前に送信完了できる方法で連携を行いました。
並列実行可能な連携システムの設計
とはいえデータ量が膨大なため、単一の処理で現実的な時間内に連携ができる見込みは到底ありませんでした。
複数の連携処理を同時に走られることができる並列システムを設計し、性能調整と耐障害性を意識したシステム構成にしました。
「日付 × テーブル」単位でJOBを分割し、各JOBが次のJOBをキューに入れる仕組みの、スーパーバイザー相当のJOBが存在しない設計で並列システムを設計しました。
並列実行数Nは管理画面で動的に変更可能とし、途中で並列数の調整や処理の中断・再開ができるような設計を行いました。
パイプライン・ミドルウェアアーキテクチャの導入
JOBの内部処理は「データ取得 → 加工 → 書き込み → アップロード」と段階を分け、各処理単位を「タスク」として同一のインターフェースでクラス化し、シェルのパイプラインのようなアーキテクチャで実装しました。
JOBは必要なタスクを組み合わせて動作する仕組みとし、柔軟性や保守性の高い構成としました。
また、JOB間のデータの受け渡しは、戻り値としてではなく引数のクロージャ(Rubyではブロック)に対して渡すような、ミドルウェアアーキテクチャのような継続渡しスタイルの書き方で実装し、本処理後の後処理のようなものも自然に記述できるようにしました。
【成果】
処理対象のスケールに耐えうる堅牢な仕組みを期間で構築し、サービスクローズ直後のタイミングで、トラブル無くデータ連携を完了させることができました。
また、対象範囲の見直しによる開発効率の向上や、システムの汎用性・見通しの良さにもこだわり、自身にとっても集大成といえる設計や実装を行うことができました。
toB向けの労務管理SaaSを提供しているサービスです。
大学時代に長期インターンとして働いていました。
開発メンバーとして、サーバーサイドにRuby on Rails、フロントエンドにReactを用いて開発していました。
主に機能開発や細かな改修を行いつつ、Ruby(2.7から3.0へ)やRails(6.1から7.0へ)のバージョンアップのタスク等も担当しました。
サーバーサイドではマイクロサービスに切り出さていた機能もあり、マイクロサービス間の通信にはgPRCを、フロントエンドとの通信にはGraphQLを採用している箇所もありました。フロントエンドではRedux, RxJSなどのフレームワークを利用している箇所もあり、様々な思想のライブラリに触れることができた環境でした。
ユーザーが機能を自社向けにカスタマイズできるようなUI/UXを提供していることや、労務関係というドメインの広さも複雑さも大きい分野のサービスということもあり、フロントエンド・サーバーサイド両方の面でアルゴリズム的な難しさのある機能開発に携わることが多かったと思います。
toB向けに、様々なサイトから広告情報をクローリングし、その集めたデータを提供するWeb画面を提供しているサービスです。
大学生時代にアルバイトとして働いていた会社です。
Webクローラーの開発には素のRubyを使用し、Web画面にはRuby on Railsを使用していました。
Webクローラーの開発では、HTTPプロトコルレベルのアプローチから、Webブラウザ上でJavaScriptを実行するアプローチまで、各種知識を総合的に用いた開発を行っていました。
Web画面の開発では、機能開発の他、画面のパフォーマンスの改善等のタスクを担当していました。
他には、収集したデータの加工の分野の開発も一部行っており、PDFファイル内の表データを画像解析を組み合わせて抽出するような機能の開発等も行っていました。
会社の技術ブログの執筆もしており、下記の記事などを書いてきました。
サービスクローズにあたって、サーバーサイドのタスク管理をマネジメントしていました。
それぞれに締切がある複数のタスクを、期日までに完了させるようにタスクのスケジュールと割り振りの管理をする責務がありました。
サービスクローズにあたって、締切のあるタスクが急激に増加し、既存のタスク管理では下記の問題が発生しました
その対策として、下記のタスク管理の仕組み化を行いました
これらの取り組みにより、クローズ関連のタスク管理でトラブルが起きるようなことは無く、無事にクローズ日を迎えることができました。
アーキテクチャパターンのような方面の知識を中心に、サーバーサイドの設計や実装にまつわる色々な知識を身に付けて行きたいです。
また、スキルとしてはまだまだ未熟ですが、データ基盤や分散システムのような領域にも興味を持っています。
まわりのメンバーを巻き込んでチームのコードベースや文化、運用を改善していくような取り組みを、より上手くできるようになりたいです。
趣味として、プログラミング言語の色々なパラダイムや、プログラミング言語処理系やOSの内部実装のような分野をマイペースに学んで行きたいなと思っています。
上記内容とは逸れるものもありますが、直近約1年間(2024年4月〜)で読んできた本を挙げてみます。
消化しきれていないものもありますが、自分のスキルセットや興味関心を知ってもらう一助になれば幸いです。
技術的に一筋縄ではいかないような開発を、裁量を持って進められる環境で、特にパフォーマンスを発揮できると思います。