作って、壊して、やめた — MapLibre マップジェネレーターで撤退を決めた話

2026.02.14
Share:

はじめに — 「もう1機能あれば完璧なのに」

プロダクト開発をしていると、「あと1つ機能を追加すれば完璧になる」と感じる瞬間があります。その1つの機能が、実は技術的に実現不可能だと分かったとき、どう判断するか。この記事は、そんな「撤退の判断」の話です。

ZERONOVA LAB の無料ツールに「簡易マップジェネレーター」(/tools/map-generator)を追加した際、徒歩ルート表示機能を実装しようとして4回の試行錯誤の末に断念しました。313行のコードを削除し、「ルート表示なし」でリリースする判断をした過程を、開発日記から振り返ります。

簡易マップジェネレーターの概要

まず、マップジェネレーター本体の話をします。このツールは「チラシや案内状に載せる簡易地図をブラウザだけで作る」ことを目的にしたものです。ユーザーからの「design-map.com の上位互換が欲しい」というフィードバックがきっかけでした。競合サービスは緯度経度入力のみでカスタマイズ性が低いという弱点があり、住所検索・ラベル制御・PNG書き出しを備えたツールに需要があると考えました。

技術スタックは以下の通りです。

  • MapLibre GL JS(BSD-3-Clause): 地図レンダリング
  • OpenFreeMap: 無料ベクタータイル(APIキー不要・レート制限なし)
  • Nominatim API: 住所検索(OpenStreetMap公式、日本語対応)

MapLibre GL JS + OpenFreeMap + Nominatim API。GeoJSON source + circle layers でマーカー描画(DOM マーカーではなくWebGLレイヤー)。PNG エクスポートにマーカーが含まれるようにするため

MapLibre GL JS + OpenFreeMap の組み合わせを選んだ最大の理由はランニングコストです。Google Maps API は1,000リクエストあたり $7 のコストが発生しますが、OpenFreeMap は完全無料でAPIキーも不要です。個人開発の無料ツールとして $0 コストを維持できることが決め手でした。

地図上のマーカーを DOM 要素(HTML)ではなく GeoJSON の circle レイヤーとして描画している点がポイントです。DOM マーカーだと WebGL キャンバスの外に描画されるため、canvas.toDataURL() で PNG エクスポートした際にマーカーが消えてしまいます。GeoJSON レイヤーなら WebGL キャンバス上に直接描画されるため、PNG にマーカーが含まれます。

4つのバグを乗り越えて

本体の実装でも4つの主要バグに遭遇しました。

4つの主要バグを修正: 1) setStyle()のフリッカー → setLayoutProperty() に変更、2) DOMマーカー消失 → GeoJSONレイヤーに変更、3) PNGにマーカーが含まれない → WebGLキャンバスレンダリング、4) ラテン語名が先に表示 → coalesce式で name:nonlatin を優先

特に setStyle() のフリッカー問題は印象的でした。地図上のラベル表示/非表示を切り替えるために setStyle() を使うと、タイルが再読み込みされて地図全体がちらつきます。setLayoutProperty() で個別のレイヤーだけを操作するように変更して解消しました。

ここまでは順調でした。問題は、次の機能追加で起きました。

「徒歩ルートを表示したい」

チラシ用の地図に「最寄り駅からの徒歩ルート」を表示できたら、ユーザーにとって大きな価値があると考えました。OSRM(Open Source Routing Machine)という無料のルーティングエンジンが公開されており、これを使えば2点間の徒歩ルートの座標列を取得できます。

ZeronovaZeronova
マップジェネレーターに徒歩ルート表示を追加したい。最寄り駅から目的地までの道順を地図に描画できれば、チラシの地図として一気に実用的になる。
Claude Code
OSRM のデモサーバー(router.project-osrm.org)を使えば、2点間のルート座標列を GeoJSON LineString として取得できます。MapLibre の addSource + addLayer で描画可能です。ただし、デモサーバーは商用利用が推奨されていないため、トラフィックが多い場合は自前のOSRMサーバーを立てることを検討する必要があります。
ZeronovaZeronova
まずはデモサーバーでプロトタイプを作ってみよう。表示品質が十分か確認してから、サーバーの問題は考える。

この判断が、4回の試行錯誤の始まりでした。

4回のスタイル変更 — 正解が見つからない

OSRM API 自体は問題なく動きました。2点間のルート座標列が返ってきて、MapLibre 上に線として描画できる。技術的には「動く」状態でした。

しかし、見た目の問題が解消できませんでした。

ルート表示で4回のスタイル変更: 全マーカー表示 → S/Gマーカー表示 → 道路アンダーレイ → 赤点線。根本的問題: OSRM のルート座標と OpenFreeMap の道路座標が一致しない

試行1: 青オーバーレイ線 + 全ウェイポイントマーカー

最初は OSRM の座標列をそのまま青色の太い線で描画し、全中間点にマーカーを表示しました。しかし、線が道路からわずかにズレていて、建物の上を突っ切っているように見えました。「チラシで使えない」というフィードバックが返ってきました。マーカーが多すぎて地図が見づらいという問題もありました。

試行2: 出発・到着マーカーのみ + 太赤線

マーカーを始点(S)・終点(G)のみに絞り、白ケーシング(12px)+ 赤線(7px)に変更しました。見やすくはなりましたが、座標ズレの問題は解消されません。「線がズレている」というフィードバックは変わりませんでした。

試行3: 道路下の色帯方式

ルートラインを road レイヤーの下に配置し、幅広のピンク帯(22px)でハイライトする方式に変更しました。ズレは目立たなくなりましたが、帯が太すぎて複数の道路を覆ってしまい、「どこを通るのか分からなくなった」というフィードバックでした。

試行4: 赤い破線

road レイヤーの上に白ケーシング(10px)+ 赤い破線(6px)で描画しました。しかし、破線にすると白地が見えるぶん、かえってズレが強調されてしまいます。「やはりはみ出す」というフィードバックで、印刷品質には到底及ばない状態でした。

撤退の判断 — なぜ座標がズレるのか

4回のスタイル変更を経て、問題の本質に気づきました。

根本的問題: OSRM のルート座標 ≠ OpenFreeMap の道路座標。データソースが異なるため、ピクセルレベルの精度が出ない。チラシ印刷品質には到達不可能

OSRM が返すルート座標と、OpenFreeMap が描画する道路の座標は、異なるデータソース(OSM のバージョンや加工方法が異なる)から生成されています。OSRM は OpenStreetMap の道路ネットワークグラフからルートを計算し、そのジオメトリを返します。一方、MapLibre は OpenFreeMap のベクタータイルをレンダリングしますが、タイル生成時に座標が簡略化・変換されます。世界地図レベルでは同じ「道路」を指していても、ピクセルレベルでは数メートルのズレがあります。

この問題は Google Maps API のような統合プラットフォームでは発生しません。ルーティングとレンダリングが同じ座標系を共有しているためです。OSS の組み合わせ(OSRM + OpenFreeMap)では、それぞれが独立したデータパイプラインを持つため、オーバーレイ方式のルート描画で品質問題が生じやすいのです。

Web 上で閲覧する分にはギリギリ許容範囲ですが、チラシに印刷する地図としては致命的です。「駅から歩いて5分」のルートが建物の上を通っていたら、地図としての信頼性がゼロになります。

ZeronovaZeronova
4パターン試したが、座標ズレの根本問題が解決しない。OSRM と OpenFreeMap のデータソースが異なる以上、ピクセルレベルの一致は原理的に不可能だと判断している。この機能は削除する。
Claude Code
ルート表示関連のコードは合計313行です。GeoJSON ソース追加、レイヤー追加、OSRM API 呼び出し、UI コントロールを含みます。すべて削除しても、マーカー配置・ラベル切り替え・PNG エクスポートなどの既存機能に影響はありません。
ZeronovaZeronova
全削除で。品質が基準に達しない機能を残しておくと、ツール全体の信頼性が下がる。

313行のコードを削除しました。

削除した後に思ったこと

機能を削除した後、開発日記にこう書きました。

機能を減らす勇気。品質基準を満たさない機能を残しておくとツール全体の信頼性が下がる。撤退判断のプロセス: 4回の試行で根本問題が特定 → データソース不一致は修正不可能 → 削除

コードを書いた時間は無駄だったのかと考えると、そうではないと思っています。4回の試行錯誤を通じて「OSRM と OpenFreeMap のデータソース不一致」という根本原因を特定できました。もし1回目で諦めていたら、「もう少し工夫すればできたかもしれない」という後悔が残ったでしょう。

4回試して「原理的に不可能」と確信できたからこそ、迷いなく313行を削除できました。

本体の完成度を上げる方に注力

ルート表示を諦めた代わりに、マップジェネレーター本体の品質向上に注力しました。

  • シンプルモード: 地図のラベルを減らしてチラシ向けにスッキリ表示するモードを追加
  • テキスト個別削除: 地図上の不要なラベルをクリックで非表示にする機能
  • 座標入力対応: 住所だけでなく、緯度経度(35.681, 139.767)や郵便番号での検索に対応
  • 位置情報考慮の検索: Nominatim API の viewbox パラメータで、現在の表示範囲に近い結果を優先表示

検索機能の改善: viewbox パラメータで位置を考慮した Nominatim 結果、座標入力対応(35.681, 139.767)、郵便番号検索(2060013 / 206-0013)

「ルート表示はないが、マーカー配置とラベル制御が自在にできる地図ジェネレーター」として、十分に実用的なツールに仕上がったと考えています。

まとめ — 撤退の判断基準

この経験から得た「撤退の判断基準」をまとめます。

  1. 根本問題を特定する: 「見た目が悪い」は症状であり、原因ではない。4回の試行でデータソース不一致という根本原因を特定できた
  2. 「修正可能か」を判断する: 自分たちのコードで修正できる問題なのか、外部データソースの制約なのか。後者は待っても解決しない
  3. 品質基準を明確にする: 「Web で見る分には OK」と「印刷品質として OK」は異なる基準。ツールの用途に照らして判断する
  4. 削除のコストを見積もる: 313行の削除は既存機能に影響ゼロ。削除コストが低いなら、迷わず削除する
  5. 空いたリソースを別に使う: ルート表示の代わりに、シンプルモードやテキスト削除機能を実装できた。撤退は「次に何をやるか」とセットで考える

「もう1機能あれば完璧」という気持ちは、プロダクト開発で最も危険な誘惑の一つかもしれません。品質基準を満たさない機能は、存在するだけでプロダクト全体の信頼性を下げます。「作らない判断」「削除する判断」もPMの重要な仕事です。

関連記事:

Zeronova avatar

Zeronovaゼロノバ

Product Manager / AI-Native Builder

Web/IT業界19年以上・20以上のWebサービスを担当したPdM。東証プライム上場企業の子会社代表として事業経営を経験。現在はAIを駆使して企画から実装まで完結させる個人開発を実践中。