メニュー

公開日:
8 min read
エンジニアリング

オフショア開発地獄絵図 その1:営業支援システムという名の冗談

オフショア開発地獄絵図 その1:営業支援システムという名の冗談のイメージ

よくある質問 (FAQ)

この営業支援システムのメール配信機能の何が問題だったのか?

絞り込み条件ではなく、数万件の顧客データそのものをフロントエンドからバックエンドに送信しており、最大数百万件のデータ転送が発生する非効率的な設計だった。

おかしな処理フローの何が無駄だったのか?

バックエンドでSQLでIDリストを作成し、フロントエンドに送信し、フロントエンドが同じIDリストを送り返し、バックエンドで再び同じSQLを実行するという無意味なラウンドトリップだった。

正常な実装ではどうあるべきだったのか?

絞り込み条件のみを送信して、バックエンドで動的にSQLを実行してIDリストを作成することで、データ転送量を最小限にできた。

この設計の問題が引き起こした副作用は?

巨大なIDリストの転送でnginxのアップロード制限に引っかかり、多くの都道府県をチェックすると通信エラーが発生し、リスト件数0になる問題があった。

このアーキテクチャが営業支援システムとして何が問題なのか?

顧客データが固定されるため配信設定の再利用ができず、配信時点での最新データが反映されないため、もはや営業支援システムではなくただの一齋メール送信ツールと同様の機能しかない。

第一章:修正完了、そして新たな地獄へ

都道府県の並びを直した。 47都道府県が自治体コード順に並ぶ。 当たり前のことが当たり前にできる喜びを噛みしめながら、次の機能をテストする。

営業支援システムのメール配信機能。 顧客データを絞り込んで、メールを一斉配信する。 どこにでもある機能だ。

絞り込み画面を開く。 さっき直した都道府県がきちんと並んでいる。 条件を設定し、件名と本文を入力。 配信日時は5年後に設定した。 ローカル環境だし、テストだからな。

「送信」ボタンをクリック。

「エラーが発生しました」

またか。 例のAPI_ERROR_MESSAGEだ。 何のエラーかさっぱりわからない。 開発ツールのコンソールを開く。

   POST 400 (Bad Request)

は?メールの設定程度でサイズ超過?件名と本文、配信日時、それに絞り込み条件。 これでnginxのアップロード制限に引っかかる?

コンソールに大量の配列が表示されている。 まさか、と思いながらネットワークタブを確認する。

俺は目を疑った。

第二章:営業支援システムという名の冗談

数万件のデータを毎回送信

このシステムは、絞り込んだ顧客の件数を送っているのではなかった。

顧客データそのものを送っていた。

数万件の顧客データが、JSONでフロントエンドからバックエンドに送信されている。 メール配信の設定を保存するたびに、数万件のデータが行き来する。

ちょっと待て。 これじゃあ:

  1. 配信設定が再利用できない - 顧客リストが固定される
  2. 顧客データの更新が反映されない - 配信時点の最新データじゃない
  3. 無駄なデータ転送 - ネットワークとストレージの無駄遣い

営業支援システムは顧客との関係性を管理するシステムだ。 顧客データの更新が反映されないなんて、それはもう営業支援システムじゃない。 ただの一斉メール送信ツールだ。

天才的なリソース浪費アーキテクチャ

さらに調べてみると、実装の闇はもっと深かった。

問題のある実装

   // 条件と数万件のデータを両方送信
POST /api/mail-send
Content-Length: 50MB+ // 顧客データ全件
{
  "conditions": {
    "prefectures": ["東京都", "大阪府"],
    "age_range": [20, 50]
  },
  "customers": [
    {"id": 1, "name": "...", "email": "...", ...}, // 最大数百万件
    // ...
  ]
}

現在の処理フロー(異常)

   1. フロントエンド → バックエンド:件数問い合わせ
2. バックエンド:SQLでIDリスト取得(※最大数百万件)
3. バックエンド → フロントエンド:IDリスト送信(数MB~数百MB)
4. フロントエンド → バックエンド:案件作成時に同じIDリストを送り返す(数MB~数百MB)
5. バックエンド:SQLでIDリスト取得(件数取得のため)
6. バックエンド:受け取ったIDリストを保存

合計:同じデータの2重転送

要件定義書によると現状で130万件の顧客データが存在するため、最大数百万件のデータ転送が発生する可能性がある。

正常な実装と処理フロー(業界標準)

   // 条件のみ送信
POST /api/mail-send
Content-Length: 1KB
{
  "conditions": {
    "prefectures": ["東京都", "大阪府"],
    "age_range": [20, 50]
  }
}
   1. フロントエンド → バックエンド:検索条件送信(1KB)
2. バックエンド:SQLでIDリスト取得(件数取得のため)
3. バックエンド → フロントエンド:件数送信(数バイト)
4. フロントエンド → バックエンド:案件作成時に条件のみ送信(数百バイト)
5. バックエンド:SQLでIDリスト取得(件数及びIDリスト取得のため)
6. バックエンド:検索したIDリストを保存

合計:最小限のデータ転送

天才的なリソース浪費アーキテクチャだ。

常識的に考えれば、検索条件だけを送信してバックエンドでIDリストを作成すればいい。 フロントエンドからの巨大な配列送信が完全に不要になる。

だが、この摩訶不思議で非論理的なアルゴリズムには、きっと深遠な意味があるのだろう。 凡人には理解できない天才的な発想に違いない。

恐らく、サーバーのリソースを余すことなく、めいっぱい使うための技法なのだろう。

通信エラーという副作用

そして、この美しいアーキテクチャの副作用:

多くの都道府県をチェックすると通信エラー

巨大なIDリストの転送でnginxのアップロード制限に引っかかり、リスト件数が0になる。 設計の根本的欠陥により、転送時にデータ件数が大量になると通信エラーが発生する。 なんと素晴らしくポンコツなのだろうか?もはや敬意すら表したく…なるはずもない。 むしろ殺意を覚える。

高品質なIT人材という看板

このオフショア開発会社のホームページには、こう書いてある:

「ベトナムの高品質なIT人材と日本市場に特化したサービス体制を活かし、コストパフォーマンスと技術力、そして日本語対応力を武器に日本企業のDX・システム開発を強力に支援するオフショア開発パートナーです」

高品質なIT人材

この実装を見て、そう言えるだろうか。 ベトナムの技術者全体に対する偏見を生む原因になっている。 優秀なベトナムエンジニアもいるはずなのに、こんな会社のせいで色眼鏡で見られてしまう。

無意味なラウンドトリップ

普通なら、絞り込み条件だけを送って、バックエンドで動的にクエリを実行する。 それが当たり前だ。

だが、このシステムでは:

  1. 条件でSQLを実行してIDリストを作成
  2. そのIDリストをフロントエンドに送信
  3. フロントエンドが同じIDリストを送り返す
  4. バックエンドで同じ条件のSQLを再実行
  5. 最初に作ったIDリストと同じものを保存

何のためのラウンドトリップ?

これはもう、システム設計以前の問題だ。 論理的思考の完全な欠如だ。

_警告:これは実話である。 オフショア開発を検討している企業は、この地獄絵図をよく見て、業者選定と品質管理体制を真剣に考えてほしい。 特に、エンジニアリングを理解している管理者の存在は必須だ。 _