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

よくある質問 (FAQ)
この営業支援システムのメール配信機能の何が問題だったのか?
おかしな処理フローの何が無駄だったのか?
正常な実装ではどうあるべきだったのか?
この設計の問題が引き起こした副作用は?
このアーキテクチャが営業支援システムとして何が問題なのか?
第一章:修正完了、そして新たな地獄へ
都道府県の並びを直した。 47都道府県が自治体コード順に並ぶ。 当たり前のことが当たり前にできる喜びを噛みしめながら、次の機能をテストする。
営業支援システムのメール配信機能。 顧客データを絞り込んで、メールを一斉配信する。 どこにでもある機能だ。
絞り込み画面を開く。 さっき直した都道府県がきちんと並んでいる。 条件を設定し、件名と本文を入力。 配信日時は5年後に設定した。 ローカル環境だし、テストだからな。
「送信」ボタンをクリック。
「エラーが発生しました」
またか。 例のAPI_ERROR_MESSAGEだ。 何のエラーかさっぱりわからない。 開発ツールのコンソールを開く。
POST 400 (Bad Request)
は?メールの設定程度でサイズ超過?件名と本文、配信日時、それに絞り込み条件。 これでnginxのアップロード制限に引っかかる?
コンソールに大量の配列が表示されている。 まさか、と思いながらネットワークタブを確認する。
俺は目を疑った。
第二章:営業支援システムという名の冗談
数万件のデータを毎回送信
このシステムは、絞り込んだ顧客の件数を送っているのではなかった。
顧客データそのものを送っていた。
数万件の顧客データが、JSONでフロントエンドからバックエンドに送信されている。 メール配信の設定を保存するたびに、数万件のデータが行き来する。
ちょっと待て。 これじゃあ:
- 配信設定が再利用できない - 顧客リストが固定される
- 顧客データの更新が反映されない - 配信時点の最新データじゃない
- 無駄なデータ転送 - ネットワークとストレージの無駄遣い
営業支援システムは顧客との関係性を管理するシステムだ。 顧客データの更新が反映されないなんて、それはもう営業支援システムじゃない。 ただの一斉メール送信ツールだ。
天才的なリソース浪費アーキテクチャ
さらに調べてみると、実装の闇はもっと深かった。
問題のある実装
// 条件と数万件のデータを両方送信
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人材
この実装を見て、そう言えるだろうか。 ベトナムの技術者全体に対する偏見を生む原因になっている。 優秀なベトナムエンジニアもいるはずなのに、こんな会社のせいで色眼鏡で見られてしまう。
無意味なラウンドトリップ
普通なら、絞り込み条件だけを送って、バックエンドで動的にクエリを実行する。 それが当たり前だ。
だが、このシステムでは:
- 条件でSQLを実行してIDリストを作成
- そのIDリストをフロントエンドに送信
- フロントエンドが同じIDリストを送り返す
- バックエンドで同じ条件のSQLを再実行
- 最初に作ったIDリストと同じものを保存
何のためのラウンドトリップ?
これはもう、システム設計以前の問題だ。 論理的思考の完全な欠如だ。
_警告:これは実話である。 オフショア開発を検討している企業は、この地獄絵図をよく見て、業者選定と品質管理体制を真剣に考えてほしい。 特に、エンジニアリングを理解している管理者の存在は必須だ。 _