<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/"><channel><title>Reachability on Tarragon</title><link>https://tarrragon.github.io/blog/tags/reachability/</link><description>Recent content in Reachability on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Fri, 19 Jun 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/reachability/index.xml" rel="self" type="application/rss+xml"/><item><title>路由可達性檢查</title><link>https://tarrragon.github.io/blog/ux-design/01-screen-state-machine/route-reachability/</link><pubDate>Fri, 19 Jun 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/ux-design/01-screen-state-machine/route-reachability/</guid><description>&lt;p>路由可達性檢查比較兩個集合：router 定義的所有路由，和使用者從 UI 操作能到達的所有路由。兩個集合的差集就是問題所在 — 定義了但不可達的路由是入口缺失，可達但未定義的路由是 404 風險。&lt;/p>
&lt;h2 id="定義-vs-可達">定義 vs 可達&lt;/h2>
&lt;h3 id="router-定義的路由">Router 定義的路由&lt;/h3>
&lt;p>現代前端框架（Flutter GoRouter、React Router、Vue Router）通常有一個集中的路由定義檔，列出所有可存取的路徑和對應的畫面元件。這個列表是 router 認知的「所有畫面」。&lt;/p>
&lt;h3 id="ui-可達的路由">UI 可達的路由&lt;/h3>
&lt;p>從首頁（或 app 的入口畫面）開始，透過 UI 上的按鈕、連結、手勢能到達的所有路由。這個集合代表使用者實際能存取的畫面。&lt;/p>
&lt;h3 id="差集分析">差集分析&lt;/h3>
&lt;p>&lt;strong>router 有但 UI 不可達&lt;/strong>：路由定義了、畫面元件也實作了，但沒有任何 UI 元素導航到這個路由。功能存在但使用者找不到入口。&lt;/p>
&lt;p>&lt;strong>UI 指向但 router 沒有&lt;/strong>：UI 上有一個按鈕 &lt;code>navigateTo('/settings')&lt;/code>，但 router 沒有定義 &lt;code>/settings&lt;/code> 路由。使用者點擊後會看到 404 或空白畫面。&lt;/p>
&lt;h2 id="路由存在但不可達的案例">路由存在但不可達的案例&lt;/h2>
&lt;p>app_tunnel 的 router 定義了三條路由：&lt;code>/&lt;/code>（首頁）、&lt;code>/enrollment&lt;/code>（配對）、&lt;code>/terminal&lt;/code>（終端機）。首頁只有一個 Connect Terminal 按鈕導航到 &lt;code>/terminal&lt;/code>。&lt;code>/enrollment&lt;/code> 路由存在，&lt;code>EnrollmentScreen&lt;/code> 完整實作，但首頁沒有任何 UI 元素導航到這個路由（&lt;a href="https://tarrragon.github.io/blog/ux-design/cases/missing-enrollment-entry-point/" data-link-title="U.C4 首頁缺配對入口按鈕、導航流未完整列出" data-link-desc="Flutter app 首頁只有 Connect Terminal 按鈕、沒有 Enroll Device 入口 — 使用者首次使用時找不到配對功能。根因是導航流設計只考慮了日常操作（UC-02 連線）、遺漏了首次操作（UC-01 配對）的入口">U.C4&lt;/a>）。&lt;/p>
&lt;p>從使用者視角看，配對功能不存在。從開發者視角看，配對功能完整 — 路由定義了、畫面寫好了、業務邏輯都通了。問題出在「入口」這個連接層。&lt;/p>
&lt;p>這和程式碼裡寫了一個 function 但沒有任何地方呼叫它的情況結構相同。Function 本身可能正確無誤，但從系統角度看是死程式碼。路由可達性檢查是這個問題在 UX 層的對應。&lt;/p>
&lt;h2 id="檢查方法">檢查方法&lt;/h2>
&lt;h3 id="手動檢查">手動檢查&lt;/h3>
&lt;p>列出 router 定義的所有路由，然後逐一在 UI 上找到通往該路由的操作路徑。找不到路徑的就是不可達路由。&lt;/p>
&lt;p>手動檢查的成本隨畫面數量線性增長。5 個路由的 app 很快能查完；50 個路由的 app 需要系統化方法。&lt;/p>
&lt;h3 id="從操作盤點交叉比對">從操作盤點交叉比對&lt;/h3>
&lt;p>BDD 操作盤點列出了所有使用者操作（UC）。每個 UC 對應至少一個畫面。把 UC 清單和 router 定義對照：&lt;/p>
&lt;ul>
&lt;li>每個 UC 的主要入口畫面是否有從首頁可達的路徑？&lt;/li>
&lt;li>每個 UC 涉及的中間畫面是否都有進入和退出路徑？&lt;/li>
&lt;/ul>
&lt;p>app_tunnel 的操作盤點列了四個操作（配對、連線、輪替、啟停），首頁只提供了「連線」的入口。「配對」是 app 操作，應該有入口但沒有。「輪替」和「啟停」是主機端操作，不需要 app 入口。這個交叉比對能在 5 分鐘內揭露入口缺失。&lt;/p>
&lt;h3 id="自動化檢查">自動化檢查&lt;/h3>
&lt;p>從 router 定義檔解析所有路由路徑，再從 UI 元件的程式碼中搜尋所有 &lt;code>navigateTo&lt;/code>、&lt;code>context.go&lt;/code>、&lt;code>context.push&lt;/code>、&lt;code>router.push&lt;/code> 等導航呼叫的目標路徑。兩個集合取差集。&lt;/p>
&lt;p>自動化檢查能發現靜態定義的入口缺失，但無法發現動態導航（根據執行期條件決定目標路由）的可達性問題。&lt;/p>
&lt;h2 id="go-vs-push-的語意影響">&lt;code>go&lt;/code> vs &lt;code>push&lt;/code> 的語意影響&lt;/h2>
&lt;p>路由可達性確認之後，導航方式的選擇影響使用者的返回路徑。&lt;/p>
&lt;p>&lt;code>push&lt;/code> 把新畫面推入導航堆疊，使用者按 back 能回到前一個畫面。&lt;code>go&lt;/code> 替換整個導航堆疊，使用者按 back 不會回到原來的畫面。&lt;/p>
&lt;p>選擇 &lt;code>go&lt;/code> 還是 &lt;code>push&lt;/code> 取決於使用者的心理模型：這個導航是「暫時離開主畫面去做一件事，做完回來」（push），還是「切換到另一個主要工作區」（go）。&lt;/p>
&lt;p>app_tunnel 修復時選擇 &lt;code>context.push('/enrollment')&lt;/code> 讓使用者配對完成後按 back 回首頁 — 配對是「暫時去做一件事」，不是切換工作區（&lt;a href="https://tarrragon.github.io/blog/ux-design/cases/missing-enrollment-entry-point/" data-link-title="U.C4 首頁缺配對入口按鈕、導航流未完整列出" data-link-desc="Flutter app 首頁只有 Connect Terminal 按鈕、沒有 Enroll Device 入口 — 使用者首次使用時找不到配對功能。根因是導航流設計只考慮了日常操作（UC-02 連線）、遺漏了首次操作（UC-01 配對）的入口">U.C4&lt;/a>）。&lt;/p>
&lt;h2 id="下一步路由">下一步路由&lt;/h2>
&lt;ul>
&lt;li>畫面狀態矩陣完整定義 → &lt;a href="https://tarrragon.github.io/blog/ux-design/01-screen-state-machine/state-matrix-definition/" data-link-title="畫面狀態矩陣的定義與填寫方法" data-link-desc="四欄矩陣（顯示 / 可用操作 / 進入條件 / 退出路徑）的定義、填寫步驟和檢查規則 — 退出路徑為空 = UX 死胡同">畫面狀態矩陣的定義與填寫方法&lt;/a>&lt;/li>
&lt;li>想測試導航路徑的正確性 → &lt;a href="https://tarrragon.github.io/blog/testing/04-ui-automation/" data-link-title="模組四：自動化 UI 驗證" data-link-desc="Widget test 的狀態覆蓋策略、Playwright 驗證流程、螢幕狀態 coverage">testing 模組四 UI 自動化&lt;/a>&lt;/li>
&lt;li>想設計完整導航模式 → &lt;a href="https://tarrragon.github.io/blog/ux-design/05-navigation-patterns/" data-link-title="模組五：導航模式" data-link-desc="Push/pop stack、GoRouter 命名路由、tab bar、drawer — 導航方法選擇是設計決策">ux-design 模組五 導航模式&lt;/a>&lt;/li>
&lt;/ul></description><content:encoded><![CDATA[<p>路由可達性檢查比較兩個集合：router 定義的所有路由，和使用者從 UI 操作能到達的所有路由。兩個集合的差集就是問題所在 — 定義了但不可達的路由是入口缺失，可達但未定義的路由是 404 風險。</p>
<h2 id="定義-vs-可達">定義 vs 可達</h2>
<h3 id="router-定義的路由">Router 定義的路由</h3>
<p>現代前端框架（Flutter GoRouter、React Router、Vue Router）通常有一個集中的路由定義檔，列出所有可存取的路徑和對應的畫面元件。這個列表是 router 認知的「所有畫面」。</p>
<h3 id="ui-可達的路由">UI 可達的路由</h3>
<p>從首頁（或 app 的入口畫面）開始，透過 UI 上的按鈕、連結、手勢能到達的所有路由。這個集合代表使用者實際能存取的畫面。</p>
<h3 id="差集分析">差集分析</h3>
<p><strong>router 有但 UI 不可達</strong>：路由定義了、畫面元件也實作了，但沒有任何 UI 元素導航到這個路由。功能存在但使用者找不到入口。</p>
<p><strong>UI 指向但 router 沒有</strong>：UI 上有一個按鈕 <code>navigateTo('/settings')</code>，但 router 沒有定義 <code>/settings</code> 路由。使用者點擊後會看到 404 或空白畫面。</p>
<h2 id="路由存在但不可達的案例">路由存在但不可達的案例</h2>
<p>app_tunnel 的 router 定義了三條路由：<code>/</code>（首頁）、<code>/enrollment</code>（配對）、<code>/terminal</code>（終端機）。首頁只有一個 Connect Terminal 按鈕導航到 <code>/terminal</code>。<code>/enrollment</code> 路由存在，<code>EnrollmentScreen</code> 完整實作，但首頁沒有任何 UI 元素導航到這個路由（<a href="/blog/ux-design/cases/missing-enrollment-entry-point/" data-link-title="U.C4 首頁缺配對入口按鈕、導航流未完整列出" data-link-desc="Flutter app 首頁只有 Connect Terminal 按鈕、沒有 Enroll Device 入口 — 使用者首次使用時找不到配對功能。根因是導航流設計只考慮了日常操作（UC-02 連線）、遺漏了首次操作（UC-01 配對）的入口">U.C4</a>）。</p>
<p>從使用者視角看，配對功能不存在。從開發者視角看，配對功能完整 — 路由定義了、畫面寫好了、業務邏輯都通了。問題出在「入口」這個連接層。</p>
<p>這和程式碼裡寫了一個 function 但沒有任何地方呼叫它的情況結構相同。Function 本身可能正確無誤，但從系統角度看是死程式碼。路由可達性檢查是這個問題在 UX 層的對應。</p>
<h2 id="檢查方法">檢查方法</h2>
<h3 id="手動檢查">手動檢查</h3>
<p>列出 router 定義的所有路由，然後逐一在 UI 上找到通往該路由的操作路徑。找不到路徑的就是不可達路由。</p>
<p>手動檢查的成本隨畫面數量線性增長。5 個路由的 app 很快能查完；50 個路由的 app 需要系統化方法。</p>
<h3 id="從操作盤點交叉比對">從操作盤點交叉比對</h3>
<p>BDD 操作盤點列出了所有使用者操作（UC）。每個 UC 對應至少一個畫面。把 UC 清單和 router 定義對照：</p>
<ul>
<li>每個 UC 的主要入口畫面是否有從首頁可達的路徑？</li>
<li>每個 UC 涉及的中間畫面是否都有進入和退出路徑？</li>
</ul>
<p>app_tunnel 的操作盤點列了四個操作（配對、連線、輪替、啟停），首頁只提供了「連線」的入口。「配對」是 app 操作，應該有入口但沒有。「輪替」和「啟停」是主機端操作，不需要 app 入口。這個交叉比對能在 5 分鐘內揭露入口缺失。</p>
<h3 id="自動化檢查">自動化檢查</h3>
<p>從 router 定義檔解析所有路由路徑，再從 UI 元件的程式碼中搜尋所有 <code>navigateTo</code>、<code>context.go</code>、<code>context.push</code>、<code>router.push</code> 等導航呼叫的目標路徑。兩個集合取差集。</p>
<p>自動化檢查能發現靜態定義的入口缺失，但無法發現動態導航（根據執行期條件決定目標路由）的可達性問題。</p>
<h2 id="go-vs-push-的語意影響"><code>go</code> vs <code>push</code> 的語意影響</h2>
<p>路由可達性確認之後，導航方式的選擇影響使用者的返回路徑。</p>
<p><code>push</code> 把新畫面推入導航堆疊，使用者按 back 能回到前一個畫面。<code>go</code> 替換整個導航堆疊，使用者按 back 不會回到原來的畫面。</p>
<p>選擇 <code>go</code> 還是 <code>push</code> 取決於使用者的心理模型：這個導航是「暫時離開主畫面去做一件事，做完回來」（push），還是「切換到另一個主要工作區」（go）。</p>
<p>app_tunnel 修復時選擇 <code>context.push('/enrollment')</code> 讓使用者配對完成後按 back 回首頁 — 配對是「暫時去做一件事」，不是切換工作區（<a href="/blog/ux-design/cases/missing-enrollment-entry-point/" data-link-title="U.C4 首頁缺配對入口按鈕、導航流未完整列出" data-link-desc="Flutter app 首頁只有 Connect Terminal 按鈕、沒有 Enroll Device 入口 — 使用者首次使用時找不到配對功能。根因是導航流設計只考慮了日常操作（UC-02 連線）、遺漏了首次操作（UC-01 配對）的入口">U.C4</a>）。</p>
<h2 id="下一步路由">下一步路由</h2>
<ul>
<li>畫面狀態矩陣完整定義 → <a href="/blog/ux-design/01-screen-state-machine/state-matrix-definition/" data-link-title="畫面狀態矩陣的定義與填寫方法" data-link-desc="四欄矩陣（顯示 / 可用操作 / 進入條件 / 退出路徑）的定義、填寫步驟和檢查規則 — 退出路徑為空 = UX 死胡同">畫面狀態矩陣的定義與填寫方法</a></li>
<li>想測試導航路徑的正確性 → <a href="/blog/testing/04-ui-automation/" data-link-title="模組四：自動化 UI 驗證" data-link-desc="Widget test 的狀態覆蓋策略、Playwright 驗證流程、螢幕狀態 coverage">testing 模組四 UI 自動化</a></li>
<li>想設計完整導航模式 → <a href="/blog/ux-design/05-navigation-patterns/" data-link-title="模組五：導航模式" data-link-desc="Push/pop stack、GoRouter 命名路由、tab bar、drawer — 導航方法選擇是設計決策">ux-design 模組五 導航模式</a></li>
</ul>
]]></content:encoded></item></channel></rss>