2025年12月7日日曜日

モノリス状態遷移からイベント駆動型アーキテクチャへの移行

 キューイングシステムを深堀りたい

背景:

SidekiqワーカーがWebサーバーが入っているEC2に同居している状態。Railsモノリスから脱却し、疏結合化を進めることで、スケーラビリティを向上させたい。

現状分析:

  • Railsモノリスの巨大な泥団子システム。
  • 調べるとapp/model/concerns/hoge_enum.rbにワーカー呼び出しが集結
    • app/worker配下にsidekiqのワーカー処理たちが書かれている
  • gemのstateful_enumを使用してイベント駆動で状態遷移をするようになっている。
  • イベントが発火したafterで色々なことをしていて、もしかしたら死んでるキューがあるかもしれない
問題:
  • EC2にSidekiqが同居しているため、リソース競合が発生して、CPU負荷が高い
    • メモリもジリジリと上昇していてサーバーダウン発生
  • 結合度が高いため変更する時バグが入る可能性
解決方法
  • SidekiqワーカーをWebサーバーから切り分けて独立したサーバーに設置
    • メッセージキューを使用して非同期のイベント駆動型アーキテクチャを実現する
    • CPU負荷特化のインスタンスファミリータイプを選び、最低限のリソース選択でコスト最適化
  • 信頼性向上のためにDBで冪等性を確立する
    • イベント記録をして二重実行を防止することで信頼性向上
移行時の注意
  • 冪等性確保のための状態管理テーブル作成
    • イベントが記録されてトランザクション追跡が可能
    • 処理前、キューイング、処理後のステータスを管理
    • 一意にレコードを特定できるよう、複合ユニーク制約などの設計
  • DLQ(デッドレターキュー)・・・何度も失敗しているキューの処理
    • リトライ処理5回以上のキューをDLQとして管理
    • 手動で再実行
      • 何かしらの失敗であれば良いが、永続的な失敗の場合はダッシュボードなどからの対処が必要だったりする
    • 自動で再実行
      • 永続的な失敗
        • 自動で削除または処理ができるように設計
      • 一時的な失敗
        • ネットワーク障害などの一時的な失敗であれば、再度実行する仕組みでリトライ
  • CI/CDの二重デプロイ
    • Webサーバーとワーカーを分離
  • 出品者商品情報のDB書き込みとメッセージキューの送信の整合性
    • Outboxパターンを適用
      • Outboxテーブルを個別用意。出品者のDB書き込みが発生したとき同一トランザクションでOutboxテーブルに書き込む。
      • メッセージキューはOutboxテーブルを見て送信。
      • 実質、「商品の状態=Outboxの状態」となり、冪等性を担保することでメッセージキューはDBとの整合性が保証される。
移行手順
  • ストラングラーフィグパターンを実行
    • ツルが木を巻きつけるようにして徐々に入れ替わる様からそう言われている
      • 段階的に進めるにあたり、一部の処理からスタートしていき徐々に全体へと進める
    • よくSIerはビッグバンリプレイスをするけど、DevOpsをしている会社はこちらを採用する方式になると思う
  • フィーチャートグルスイッチ
    • 外部コンフィグからON/OFFをして失敗時の復旧を外部から瞬時に戻すことができる
    • ブランチバイアブストラクト
    • カナリアリリース
      • 何パーセントのユーザーにだけ新しいリリースの実行結果が行われるようインフラを構成
技術選定
  • メッセージキュー
    • Amazon SQS・・・フルマネージドで運用の負荷は軽い
    • RabbitMQなどOSS
      • オンプレミスとかではこっちだけどクラウドで選ぶなら理由は自分たちで色々と実装をしたいとか?
    • Kafka、Amazon Kinesisなどのイベントストリーム系
      • シャーディングの仕組みなどでSQSよりも大幅なスループットが可能
      • パーティションで区切り、処理を分けることが可能
      • FIFOの先入先出し削除でデータ処理後に削除するのではなく、データの永続化が可能
  • サーバー
    • Webサーバーは継続してEC2だろうね。常時つけるから
    • 問題はワーカーサーバー
      • こっちはコンテナ化してみて部分的にECSを実現してみるとかいいんじゃないかな?

2025年12月6日土曜日

強みねーな・・・っていうとき

👥「naohiroさんの強みって何ですか?」

👦「(やっべ...全部必要だと思ってたし強みとかないな)設計です!」

👥「では、何をされていましたか?」

👦「実装とかDB設計とかAWS触ったりとか運用とか...」

👥「...(なさそうや)不採用」

👦「ああああなんでいつもこうなんや」

今までフルスタック(全部やれ)をやっていたから全然強みとかないな。。どうしよ。と将来大人になったときが心配になってしまったので強みを探していく実際の流れを書いてみたいと思います。

背景:そもそも前職では技術力というより、リーダーシップの発揮がとても大切な会社でした。そうするとエンジニアとしての強みというのは技術的にはあまり主張できないことになってしまいます。

テーマ:T字型人材を目指す

幅広い強みがあることはいいことですが、何か専門的なスペシャリティを持っていた方がよいというのが最近のトレンドなんじゃないかな?と最近面接していて思いました。(される方です)

なので、T字型人材を目指すために振り返りをしたことや分析してみたことを実際にステップごとに書いていきます。

前提

  • 今まで強みとかないし何でもかんでもやっていた人
  • 選ぶ=他を捨てる

自分の好き・得意を掘り下げる

  • 今まで自分がやっていてこれは得意そうだとか好きだなって思ったこと
  • 気づいたらなんか情報収集してるやつ
  • こういうことをやっていた時結構集中して熱中してたなと思うこと
経験が多いこと
  • 何だかんだ経験が多いことは?
相手を見る
  • 市場に幅広く求められている
  • スペシャリティ
    • ニッチな分野
    • 他の人が見てなさ過ぎて競合がいないため枯渇している部分
  • インパクトの大きさ
    • ビジネス的なインパクト
    • 開発チームへのインパクト
      • 会社へのインパクトが大きい
テーマで区切る
  • 自動化
    • IaC
    • テスト自動化
  • 信頼性
  • セキュリティ
  • クラウド
    • クラウドアーキテクチャ設計・構築
    • マルチクラウド対応
    • AWS特化、GCP特化、Azure特化
  • パフォーマンスチューニング
    • 性能調査
    • オブザーバビリティ
  • データ設計
    • データ構造→非構造、半構造、構造化データ
  • コーディング
    • 言語別
  • アジリティ・デリバリー
  • アーキテクチャ
    • ドメイン駆動設計
    • 分散型アーキテクチャ
  • コスト最適化
  • マネジメント
  • 顧客折衝
  • 品質保証
  • ...etc
何が欲しいか
  • 年収
  • 将来性
    • 安定性
    • ワークライフバランス
  • 自由さ・責任の境界
  • 会社のブランド
    • 会社規模
    • 社名
  • 活躍度・楽しさ
  • 0→1
  • 知名度
  • ...etc

自分は?
  • 年収欲しい
  • 将来性欲しい
  • 責任感からか、より根本を直したいと思う性格からか結構事業リスクとか考えてやっていたかもしれない
    • 開発プロセスとか
    • サーバーの障害リスクとか
    • 技術負債とか
    • やべー誰も分からねぇっていう状況をゼロにしたいと思った
      • ドメインをいの一番で理解しておいて人に教える
      • リファクタリングとかコメントとかめっちゃ書いてた
      • ていう割にはテストはあまり書いてなかった
    • ドキュメンテーションみんなやらなすぎじゃね・・?って思った
      • 逆に言うと割と書きたいかもしれない
  • だから逆にいうと新規機能開発ってあんまりやってなかったかも
    • ていうかやりたい人多すぎてた
    • そういえばSIerの時にやってたのってほぼほぼ拡張か構成管理かリプレイスだった
      • 新規機能の耐性ついてないな
      • カオス好きじゃないな。不確実性はめっちゃ減らしたい
  • 設計とか楽しい
    • DB設計とかは楽しいんじゃないかな
      • 一番負債になるのここだったし
    • DDDとかも結構勉強はしてた
      • でもRailsではやらない方がよいっぽい
    • システム移行とかリアーキテクチャには興味がある
      • でかいことやりたいな
    • AWS
      • めっちゃコストかかってね?って思ってからは最適化したいと思った
      • 運用大変じゃね?って思ってからは自動化したいって思った
      • これ構築とか楽しくね?って思った
      • サーバーの冗長化とかDRとかマルチAZとかレプリケーションとかDBの移行とか楽しくね?って思った
  • 実装
    • 楽しくはなかったかもしれない
    • AIでよくね
    • 実装めんどくせって思っちゃう
  • 勉強してて楽しいのは?
    • スケーラビリティ
      • オートスケーリング
        • 垂直スケール、水平スケール
      • キューイングメッセージ
      • ロードバランサー
        • リクエスト負荷分散
      • データベース
        • レプリケーション
        • パーティショニング
        • シャーディング
    • パフォーマンスチューニング
      • 可観測性
      • クエリ分析
結論:お前、それWebエンジニアか?
総括:共通してるのは分析して解決かなぁ。今の問題点ってなんだろう?っていうところから考えて解決するまでの調査と分析をして解決策を考えて実装。


会社が動かない問題のなぜなぜ分析

テーマ:全然会社が動かない

開発者の意見が通らない

数字に目がいきすぎて全然ユーザー価値考えていない

  • やることが多いと錯覚をしていて、動いていない
  • 負債が溜まっていてなかなか動けない。
  • 改善が進められていない
    • 社内の業務の生産性が悪い
    • 人材が定着していない
    • 改善を進める前に成果を求めてしまう
      • 元いた社員の重圧が大きい
      • 覚えてから成果へ繋げる前に辞めさせちゃう
      • 成果を評価するため、それ以外の成果を出す場を作る下地が作れずに少量の成果しか出せていない
        • 社長からの人材への期待値が高い
        • 一人のスーパースターを求めている
        • 少数の社員で成り立たせたいと思ってリソースを節約している
          • その他がその人を支えるという仕組みを作る
          • イメージが先行して、どういう人材がよいかという固定観念が強い
            • 短期的な投資と成果を求めている
              • 資金がショートするかもしれないという焦り
              • 事業が投資家にとって魅力ではない

総括

資金難と人材の確保ができていない、業務効率が悪い、成果も出せない

というループができてしまっていて、成長していない

これの改善方法

  • 開発部は開発部で仕切り、一人が開発部を責任を持って生産する
  • 痛みを伴う変化というのを間違って解釈しているので修正をしてもらう
    • 人を変えるんじゃなくて、システムを変える
    • こだわりが変化を遠ざけているため、自分の意識だというのを理解してもらう

定期購読プランの設計

 主要テーブルは2つ

  •  ポイント
    • 冪等性を確保する
      • 状態管理テーブル
    • 会社保有のチケット
      • チケットの失効の仕様策定
    • 契約テーブル
  • 実装計画
    • 第一phase
      • 定期購読契約テーブルとバッチ状態管理テーブルを作成
      • 過去のデータで不整合が生じるため削除orデータ変更
    • 第二phase
      • Railsアプリケーション側開発
      • バッチを実装(Lambda、EventBridgeのクラウドネイティブなバッチ)
    • 第三phase
      • チケット失効仕様のためチケットテーブルを追加設計
      • チケット失効バッチを実装
  • 制約
    • 定期購読停止申請は契約更新月の前月末までにしないと次回更新時になる
      • 参考にしたのはNintendo Switchオンライン契約の定期購読の仕組み(ちょっと違うけど、人と会話する時に参考になりやすい)
      • https://support.nintendo.com/jp/nso/automatic-purchase-extension/index.html
    • チケット効力失効が新たに追加
      • 定期購読停止とはまた違い、チケット自体の効力である
        • Amazonポイントとかわかりやすい
  • 定期購読契約テーブル
    • 契約開始
    • 契約終了
    • 次期契約開始
    • 次期契約終了
    • 次回停止申請期限
    • 次回更新停止申請日
    • ステータス
      • 契約中、契約更新停止申請中、契約解除、契約更新処理中
  • バッチ状態管理テーブル
    • バッチの二重実行の防止
    • 冪等性の確保のための設計
      • 複合ユニーク制約の作成バッチ実行日時+ID
      • ステータス管理
        • 失敗、成功、保留、実行中
  • バッチ設計
    • 契約更新バッチ
      • 次回更新停止申請日がNULLでない
        • 次回更新停止申請日が次回更新停止申請期限より前である
        • ステータスを契約更新処理中に
        • ステータスを契約解除に
      • 次回更新停止申請期限を次期契約終了日の一ヶ月前に更新
      • 次期契約開始日を契約開始日にコピー etc
    • チケット補充バッチ
      • 契約している分のチケットを追加する


2025年11月24日月曜日

最近のソフトウェアエンジニアの転職難しくなってます?

概要

転職活動をしているがソフトウェアエンジニアとして体感難しくなってる気がする(ワイの問題?)。なので、ちょっと備忘録を書いておく。

  • 技術面接の通過基準が厳しい

まあ会社にはよるし自分次第なところもあると思う。会社によってはとりあえず最終面接で技術面接をしてみてCTOが判断するっていう会社もある。大体は一次面接とかでエンジニアやEMが候補者の技術スキルを測る。その時の基準っぽいことはこれ。

    • ちゃんとAIを使っているか。
    • どういう技術を選定してきたか。
    • どういう問題を解決してきたか。

今はAIがあるから選定基準は厳しい。だって技術的なことは聞けちゃうからあとはどういう思考で進める人かが重要なんじゃないかなと思う。

皆リードエンジニア、テックリードとしての素養を求められているんだと思う。ジュニアは厳しい。。

  • スキルの測り方は多種多様

10社ほどにまとめると、コーディング試験 : DB設計 : 口頭質問が体感2 : 2 : 6の感覚。

  • 2割はコーディング試験(Codilityやハイヤールーなど)
  • 2割はデータモデリング、DB設計の技術課題を提出させて、面接で聞くタイプ
  • 6割は技術課題を出さず、面接で問うスタイル

データモデリングの問題については自社のシステムに近い製品を仮定してテーブルを設計させてみたり、オンタイムでデータモデリングをさせ、その場で説明をさせてみるみたいなのもあった。

  • 特殊なケースではケース面接っていうのもあった

例えば

    • システムのフロントエンドをSPAにする場合に出てくる問題やその場合を想定したときの進め方
    • マルチテナントSaaSのDBの設計の問題点

などのリードエンジニアとしての思考を問うところもあって、なかなか厳しかったところもあった。

事前にAIに聞いていれば要点はこれなんだろうなぁっていうのはもしかしたらわかる人は分かるかもしれないけど、ハイレベルだなって思った。

  • やっておくといいと思うこと
    • 今までの自分のやってきたことはとにかく、振り返った方がいい。
    • AIに聞いて、AIと一緒に自分がどういう選定をしてきたか。もっといい方法はなかったか。
    • そもそも面接をすると振り返った時に結構勉強になる
      • 例えばコーディング試験だったらデータ構造とかアルゴリズムの勉強になってる
      • 面接で聞かれたことは意図を紐解いてみると会社が欲しい強みみたいなところを聞いている
      • 再現性を自分で考えて整理できる


2025年9月12日金曜日

システム現状分析と再構築プラン

現状分析

  • 古いシステムがありそちらはクローズをしたい
  • 何かしらの追加をしたい時に時間がかかりすぎる
  • サーバーダウンする

組織的な問題

  • 経営者が開発に関与しすぎ
  • システムの裏側の負債の問題について無視しすぎ
  • 社員の業務生産性について目を背けすぎ

システム上の設計問題

  • 運用効率の悪さ
  • 自動化の未完成
  • データモデリング
  • Rubyパフォーマンスの悪さ
  • AWSの設計の可用性の低さ
  • コストの悪さ

SIerの方法だと

  • ビッグバンリプレイス
    • Rails→他言語へのリプレイスして全部置き換え
  • 言語の総置き換え

捨てた選択肢

  • 細かい要望を止める
    • 窓口を減らし
    • 開発者の窓口をPMにしてもらう
      • PMから開発者へ相談をしてもらう
      • 営業やサポートはPMに介して開発者への要望をしてもらう
        • その間開発者は業務を効率化させる
        • システムの直し

実践するべきと判断したこと

  • システム開発の主導
  • 負債の返済
  • 業務生産性を上げるための業務自動化

やること

  • AWSサーバーを冗長化して可用性を上げる
    • EC2インスタンスを冗長化
      • オートスケーリンググループを作成してオートスケールする
      • 障害に備えてDR対策
        • フェイルオーバーの仕組み
          • アクティブ-パッシブの構成
          • 最小構成で置いておく
            • 稼働したら自動スケール
    • DBをレプリケーション
      • 読み取り専用と書き込み専用で分ける
      • マルチAZにする
    • サーバーをコンテナ化
      • EC2インスタンスからECSへの移行
      • デプロイはECRへDockerイメージを置く
    • コスト最適化のためのサーバーレス化
      • 管理者操作のDBはAuroraServerlessで局所的な使用方法にする
      • リザーブドインスタンスで1〜3年のEC2インスタンスの契約をする
        • コアドメインはEC2インスタンス
      • 送客ロジックをコンテナ化
        • Lambdaで運用15分稼働とコールドスタート
        • 分離したロジックの言語は自由にしてよい
          • Python ? Go ?
        • API化してAPI通信+メッセージキュー
          • SQS,  RabbitMQ
      • キューイングシステムを再構築
      • 冪等性を確保
        • 状態管理テーブル
        • Gemでsidekiq-unique-jobs
    • 運用を効率化
      • サーバーのフルマネージド化
        • Aurora、ECS/Fargate、Lambda、DynamoDB
      • 可観測性
        • フルマネージドにするためEC2ストレージに直接吐いていたログを集約
          • Fluentd、CloudWatch
      • デプロイの自動化
        • CodePipeline?
        • Github Actions?
      • 日々の作業で非効率的な手動の作業を減らす
        • トイルの削減
        • バッチ化
          • スケジュールではなく分離していく
  • パフォーマンスを測定してボトルネックを解消する
    • DataDogを使用して、クエリを特定
      • Explainなどでスロークエリを分析
    • gem BulletでN+1の発生しているActiveRecordを抽出
      • ActiveRecordが作るクエリを分析し、ボトルネックを探す
        • N+1修正をしてボトルネックを解消
  • DB設計をしてデータモデルを再構築する
    • 負債によって一番開発効率が下がっている部分を特定
      • コアドメインのデータモデルを再構築する時間を取る

開発プロセスにこだわってしまう罠。それよりも組織を変える必要性

 開発プロセスにこだわりすぎて開発がうまく進まなかったという経験があり、一方でその後きたCTOによりCEOを開発会議から外し、開発チーム+PdM(ビジネス層代表)と開発チームオンリーの会議の2つに分けて会議体を作ったことで見事ビジネスと開発を分けて疎結合にしたということがあり、なるほどと思ったことがある。

それまでは私が開発プロセスを何とかして上手く動かしたかったのだが、全然上手くいかず困ったので記録を残しておきたい。

開発プロセスは大きく分けるとアジャイルとウォーターフォールがある。

ウォーターフォールはSIerなどベンダー企業がユーザー企業から依頼を受けてシステム開発をする際にソフトウェアを工業製品に見立てて、製造業のプロセスをそのまま当てたことで始まったとされている(確かではない)。

それだと上手くいかないよねということで2000年代からアジャイル開発が考案されて、以降、シリコンバレーやWeb業界ではアジャイル開発が主流となっていた。その中でもXP開発やスクラム開発などあり、私が前いたベンチャーではスクラム開発を基に開発を進めていた。

スクラム開発はガチガチにやろうとすると開発が遅くなる。このスクラム開発をガチガチにやろうとし過ぎて、開発者たちからは反感をくらい、経営層の要望を上手く開発に落とし込むこともあまりうまくいかずにとても四苦八苦したと思っている。

ビジネスの要望ばかりを叶えようとしてシステムの重要な要件を満たせていないということがあり、ずっとその会社ではシステムの要件を満たせていなかった。そのため、技術的負債が溜まりに溜まっていた。

システムの重要な要件というのは、運用の自動化やしやすさ、パフォーマンス性、変更容易性、セキュリティ、コスト最適化、スケーラビリティ、信頼性など。

参考:AWS Well-Architected

ベンチャーの経営者はわがままである(『経済評論家の父から息子への手紙』著 山崎元)。

どこのベンチャーも多分そうで、相当ソフトウェア開発に力を入れている企業でなければ(個人的には、例えばLayerX、カミナシなど)、多分どんなベンチャーだって経営者は必死で企業を利益を立たせるために開発者にベンチャー精神を要求し、システムは崩壊している。

参考:開発者体験が良いイメージの企業

ビジネスと開発はある意味グラデーションのように仲介を挟まないと直接ビジネス要件を満たそうとしてえらいめにあう。あるいは開発組織が飲まれているのが実際だと思う。

参考:Cultural Capital Theory in Software Engineering

ベンチャー企業に入り開発プロセスを固めようとしても上手くいかず、CTOが入り、社長が会議に入らないようになってから開発が上手く回り始めたことも目にして、開発のプロセスにはこだわらず、組織構造を変える必要があると思った。

開発プロセスをこだわろうとしても多分ほぼ何も整っていないカオスなベンチャーでは無意味で、経営層に対等に話せる立場が必要、もしくは開発者たちが強くビジネスの要望に対してPdM、PMの意識を持って接することが大切だと思った。

モノリス状態遷移からイベント駆動型アーキテクチャへの移行

 キューイングシステムを深堀りたい 背景: SidekiqワーカーがWebサーバーが入っているEC2に同居している状態。Railsモノリスから脱却し、疏結合化を進めることで、スケーラビリティを向上させたい。 現状分析: Railsモノリスの巨大な泥団子システム。 調べるとapp/...