<?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>程式碼品質 on Tarragon</title><link>https://tarrragon.github.io/blog/tags/%E7%A8%8B%E5%BC%8F%E7%A2%BC%E5%93%81%E8%B3%AA/</link><description>Recent content in 程式碼品質 on Tarragon</description><generator>Hugo -- gohugo.io</generator><language>zh-TW</language><copyright>Tarragon (CC BY 4.0)</copyright><lastBuildDate>Wed, 04 Mar 2026 00:00:00 +0000</lastBuildDate><atom:link href="https://tarrragon.github.io/blog/tags/%E7%A8%8B%E5%BC%8F%E7%A2%BC%E5%93%81%E8%B3%AA/index.xml" rel="self" type="application/rss+xml"/><item><title>設計驅動重構方法論 - Domain Root 檢查與技術債務清理實戰</title><link>https://tarrragon.github.io/blog/record/%E8%A8%AD%E8%A8%88%E9%A9%85%E5%8B%95%E9%87%8D%E6%A7%8B%E6%96%B9%E6%B3%95%E8%AB%96-domain-root-%E6%AA%A2%E6%9F%A5%E8%88%87%E6%8A%80%E8%A1%93%E5%82%B5%E5%8B%99%E6%B8%85%E7%90%86%E5%AF%A6%E6%88%B0/</link><pubDate>Wed, 04 Mar 2026 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/record/%E8%A8%AD%E8%A8%88%E9%A9%85%E5%8B%95%E9%87%8D%E6%A7%8B%E6%96%B9%E6%B3%95%E8%AB%96-domain-root-%E6%AA%A2%E6%9F%A5%E8%88%87%E6%8A%80%E8%A1%93%E5%82%B5%E5%8B%99%E6%B8%85%E7%90%86%E5%AF%A6%E6%88%B0/</guid><description>&lt;p>在一次常規的 Phase 4 重構評估中，我們打開了 &lt;code>library_domain.dart&lt;/code> 這個檔案，發現它足足有 600 多行，裡面混雜著聚合根、Value Object 和服務類別，彼此糾纏在一起。更糟的是，統計書籍狀態的函式正在使用根本不存在的枚舉值——程式編譯不過，但那些錯誤已經在那裡不知多久了。&lt;/p>
&lt;p>如果在重構之前沒有系統性地理解設計意圖，我們很可能會把問題修錯方向，或者在「修好」一處的同時破壞了其他地方。&lt;/p>
&lt;p>於是我們建立了一套方法論，把設計文件的閱讀和驗證，放在所有重構動作的最前面。&lt;/p></description><content:encoded><![CDATA[<p>在一次常規的 Phase 4 重構評估中，我們打開了 <code>library_domain.dart</code> 這個檔案，發現它足足有 600 多行，裡面混雜著聚合根、Value Object 和服務類別，彼此糾纏在一起。更糟的是，統計書籍狀態的函式正在使用根本不存在的枚舉值——程式編譯不過，但那些錯誤已經在那裡不知多久了。</p>
<p>如果在重構之前沒有系統性地理解設計意圖，我們很可能會把問題修錯方向，或者在「修好」一處的同時破壞了其他地方。</p>
<p>於是我們建立了一套方法論，把設計文件的閱讀和驗證，放在所有重構動作的最前面。</p>
<h2 id="為什麼設計文件要在程式碼之前讀">為什麼設計文件要在程式碼之前讀</h2>
<p>看到壞味道就處理、看到重複就提取——傳統重構路線沒有問題，但對 Domain 層的核心實體來說，這樣做有個盲點：我們可能根本不清楚這段程式碼的業務意圖。</p>
<p>不清楚「Library 為什麼要追蹤 SourceType 而不是 ReadingStatus」，技術上漂亮的重構可能在業務上悄悄引入錯誤。設計驅動重構的前提是：所有重構決策必須基於現有的設計文件，而不是單純從程式碼的技術形狀來判斷。</p>
<h2 id="驗證流程">驗證流程</h2>
<h3 id="第一階段設計文件檢查">第一階段：設計文件檢查</h3>
<p>在動任何一行程式碼之前，我們先回頭讀文件。閱讀順序很重要：從需求規格出發，再到用例說明，再到 UI 設計規格，最後到錯誤處理設計。</p>
<p>這個閱讀順序的邏輯是：先確立業務目標（需求規格），再理解使用場景（用例），再看 UI 層如何呈現（UI 規格），最後檢查系統如何應對異常（錯誤處理）。這樣走一遍，Domain Root 在整個系統中扮演的角色就會變得清晰。</p>
<p>以 Library 實體為例，文件告訴我們它需要支援不同來源類型的書籍統計——實體書、電子書、借閱書各有不同的計算邏輯。但程式碼裡用的是 <code>ReadingStatus</code> 枚舉，而且還在使用 <code>'digital'</code>、<code>'borrowed'</code> 這些根本不在枚舉定義裡的值。這不是設計問題，這是實作根本跑錯了方向。</p>
<h3 id="第二階段測試覆蓋率分析">第二階段：測試覆蓋率分析</h3>
<p>讀完文件之後，我們看測試。測試是另一種形式的設計文件，它告訴我們這段程式碼「被期待如何運作」。</p>
<p>這個階段最常發現的問題是測試的方向跑偏了。我們在 <code>book_test.dart</code> 裡發現，它引用了 <code>flutter_test</code> 套件，但 Domain 層的單元測試根本不應該依賴 Flutter 框架——這意味著這些測試在純 Dart 環境中根本無法執行，CI 流程也因此產生了盲點。</p>
<p>此外還有大量被 skip 的測試。每個 skip 都是一個未被驗證的業務假設，累積起來就是風險。</p>
<h3 id="第三階段程式實作驗證">第三階段：程式實作驗證</h3>
<p>前兩個階段讓我們建立了對「設計意圖」的理解。第三階段才是真正對照程式碼，逐一確認哪裡偏離了設計。</p>
<p>這個階段的關鍵產出是一份問題清單，而且每個問題都有分類：是類型系統錯誤、是架構違規、是技術債務，還是可維護性問題。分類決定了後續的修復優先級。</p>
<h2 id="問題分類與修復優先級">問題分類與修復優先級</h2>
<p>我們在實際的 Book 和 Library 重構中，識別出了四類問題，按照影響範圍決定修復順序。</p>
<p><strong>類型系統錯誤優先級最高。</strong> 使用不存在的枚舉值、把 <code>String</code> 傳給期望強類型的參數，這類問題一旦進入生產環境就是執行時崩潰。我們把所有這類問題排在第一批處理。</p>
<p><strong>異常處理不統一緊隨其後。</strong> Library 實體裡有自定義的 <code>DuplicateBookException</code>，但整個專案其他地方都統一使用 <code>AppError</code> 體系。這種不一致性不只是風格問題，它讓錯誤處理的呼叫端無法用一致的方式應對。</p>
<p><strong>技術債務屬於第二優先級。</strong> 最典型的例子是 <code>author</code> 欄位使用 <code>String</code> 類型。這在功能上可以運作，但它限制了後續的多作者支援、譯者解析和富文字搜尋能力。這類問題有明確的演進路徑，但不是緊急的。</p>
<p><strong>可維護性問題排在最後。</strong> 包括缺乏需求追蹤編號的註解、業務規則說明不足等。這些問題不影響功能，但它們是技術債務的溫床——當下一個人來維護這段程式碼時，他沒有足夠的上下文。</p>
<h2 id="幾個具體的重構模式">幾個具體的重構模式</h2>
<h3 id="類型系統修正">類型系統修正</h3>
<p>問題很常見：用字串或錯誤的枚舉值來做判斷，而不是使用正確的類型。</p>
<p>修正前：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">books</span><span class="p">.</span><span class="n">where</span><span class="p">((</span><span class="n">book</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">book</span><span class="p">.</span><span class="n">readingStatus</span> <span class="o">==</span> <span class="s1">&#39;digital&#39;</span><span class="p">)</span></span></span></code></pre></div><p>修正後：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="n">books</span><span class="p">.</span><span class="n">where</span><span class="p">((</span><span class="n">book</span><span class="p">)</span> <span class="o">=&gt;</span> <span class="n">book</span><span class="p">.</span><span class="k">source</span><span class="p">.</span><span class="n">type</span><span class="p">.</span><span class="n">isDigital</span><span class="p">)</span></span></span></code></pre></div><p>表面上看這只是換了一個屬性，但背後的意義完全不同：前者依賴字串的巧合匹配，後者依賴類型系統的保證。</p>
<h3 id="異常處理統一">異常處理統一</h3>
<p>自定義異常類別散落在程式碼各處，是一種常見的技術債務模式。</p>
<p>修正前：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">throw</span> <span class="n">DuplicateBookException</span><span class="p">(</span><span class="s1">&#39;message&#39;</span><span class="p">,</span> <span class="nl">bookId:</span> <span class="n">id</span><span class="p">,</span> <span class="nl">title:</span> <span class="n">title</span><span class="p">);</span></span></span></code></pre></div><p>修正後：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="k">return</span> <span class="n">OperationResult</span><span class="p">.</span><span class="n">failure</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">2</span><span class="cl">  <span class="n">BusinessLogicError</span><span class="p">(</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">    <span class="nl">message:</span> <span class="s1">&#39;message&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="nl">businessRule:</span> <span class="s1">&#39;BOOK_DUPLICATE_PREVENTION&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">    <span class="nl">code:</span> <span class="n">ErrorCodes</span><span class="p">.</span><span class="n">duplicateBook</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">    <span class="nl">context:</span> <span class="p">{</span><span class="s1">&#39;bookId&#39;</span><span class="o">:</span> <span class="n">id</span><span class="p">,</span> <span class="s1">&#39;title&#39;</span><span class="o">:</span> <span class="n">title</span><span class="p">},</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl">  <span class="p">),</span>
</span></span><span class="line"><span class="ln">8</span><span class="cl">  <span class="s1">&#39;userMessage&#39;</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">);</span></span></span></code></pre></div><p>這個轉換不只是換個類別，它同時把拋出異常改成了回傳結果——這是更適合 Domain 層的錯誤傳遞方式，讓呼叫端可以明確地決定如何處理每種失敗情況。</p>
<h3 id="value-object-重構">Value Object 重構</h3>
<p>把 <code>String</code> 提升為 Value Object 是一個需要仔細計畫的重構，因為它涉及所有使用處的同步更新。</p>
<p>修正前：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">final</span> <span class="kt">String</span> <span class="n">author</span><span class="p">;</span></span></span></code></pre></div><p>修正後：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="kd">final</span> <span class="n">BookAuthor</span> <span class="n">author</span><span class="p">;</span></span></span></code></pre></div><p>關鍵在於轉換策略要設計好：<code>BookAuthor.fromString(stringValue)</code> 負責從舊有字串資料遷移，<code>bookAuthor.displayValue</code> 負責在需要字串輸出的場合提供相容性。有了這兩個轉換點，才能在保持向後相容性的前提下完成遷移。</p>
<h2 id="分階段執行每段必驗">分階段執行，每段必驗</h2>
<p>每個修復階段結束後都要驗證：<code>dart analyze</code> 無錯誤、核心功能正常運作、API 介面保持不變。我們曾經跳過這個步驟，結果後續階段的問題疊加在一起，讓除錯變得極其困難。</p>
<h2 id="從這次重構中得到的">從這次重構中得到的</h2>
<p>這次對 Book 和 Library 兩個 Domain Root 的重構，最終涉及了 35 個以上的檔案，把 24 個編譯錯誤降到了零，並且完整建立了需求追蹤的 <code>REQ-LIB-XXX</code> 編號體系。</p>
<p>收穫更大的是設計文件優先讓我們避開了幾個危險方向。如果直接看到 <code>author</code> 是 <code>String</code> 就去重構，可能會建出不符合業務需求的 Value Object。如果直接看到自定義異常就去統一，可能會在類型系統問題還沒修好的基礎上做錯誤的抽象。</p>
<hr>
<p>下次面對需要重構的模組時，先花 15 分鐘讀相關設計文件，再決定從哪裡下手。那 15 分鐘很可能讓你避開一個需要幾個小時才能發現的方向錯誤。</p>]]></content:encoded></item><item><title>系統化除錯方法論</title><link>https://tarrragon.github.io/blog/record/%E7%B3%BB%E7%B5%B1%E5%8C%96%E9%99%A4%E9%8C%AF%E6%96%B9%E6%B3%95%E8%AB%96/</link><pubDate>Fri, 26 Sep 2025 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/record/%E7%B3%BB%E7%B5%B1%E5%8C%96%E9%99%A4%E9%8C%AF%E6%96%B9%E6%B3%95%E8%AB%96/</guid><description>&lt;h2 id="為什麼需要系統化除錯方法論">為什麼需要系統化除錯方法論&lt;/h2>
&lt;p>除錯不是試錯過程，是品質提升的系統性工程。隨機修復會產生隨機品質。系統化除錯產生一致的架構改善。&lt;/p></description><content:encoded><![CDATA[<h2 id="為什麼需要系統化除錯方法論">為什麼需要系統化除錯方法論</h2>
<p>除錯不是試錯過程，是品質提升的系統性工程。隨機修復會產生隨機品質。系統化除錯產生一致的架構改善。</p>
<p>當AI協作處理複雜程式問題時，系統化除錯方法論成為唯一的執行準則。模糊的修復策略會產生模糊的結果。明確的除錯方法論產生一致的品質改善。</p>
<h2 id="系統化除錯的本質">系統化除錯的本質</h2>
<h3 id="系統化除錯不是什麼">系統化除錯不是什麼</h3>
<p>系統化除錯不是：</p>
<ul>
<li><strong>症狀修復</strong>：不掩蓋警告，只找根本原因</li>
<li><strong>批量處理</strong>：不自動修復，只精確分析</li>
<li><strong>簡單先行</strong>：不從容易修的開始，只按風險優先級</li>
<li><strong>表面清理</strong>：不只消除警告，只完成未完成的設計</li>
</ul>
<h3 id="系統化除錯是什麼">系統化除錯是什麼</h3>
<p>系統化除錯是：</p>
<ul>
<li><strong>根因分析</strong>：明確區分未完成實作vs過度設計</li>
<li><strong>風險導向</strong>：按業務風險和架構影響排序修復</li>
<li><strong>主從分工</strong>：主線程管控進度，代理人執行修復</li>
<li><strong>品質提升</strong>：每次修復都強化程式設計完整性</li>
</ul>
<h2 id="除錯的第一原則根因分析優先">除錯的第一原則：根因分析優先</h2>
<h3 id="問題本質分類">問題本質分類</h3>
<p>每個unused警告都屬於以下三類之一：</p>
<h4 id="未完成實作">未完成實作</h4>
<ul>
<li><strong>識別</strong>：功能設計完整但驗證邏輯缺失</li>
<li><strong>處理</strong>：補完實作而非移除程式碼</li>
<li><strong>範例</strong>：測試中建立了secondImport變數但未驗證重複匯入行為</li>
</ul>
<h4 id="過度設計">過度設計</h4>
<ul>
<li><strong>識別</strong>：功能已完成但包含不必要的複雜性</li>
<li><strong>處理</strong>：移除多餘程式碼保持精簡設計</li>
<li><strong>範例</strong>：建立獨立服務實例但架構採用單例模式</li>
</ul>
<h4 id="程式碼風格問題">程式碼風格問題</h4>
<ul>
<li><strong>識別</strong>：邏輯正確但命名或結構不一致</li>
<li><strong>處理</strong>：重構改善可讀性和一致性</li>
<li><strong>範例</strong>：使用File物件但混用path字串操作</li>
</ul>
<h3 id="分析判斷標準">分析判斷標準</h3>
<ul>
<li>變數有明確的業務意圖 → 未完成實作</li>
<li>變數創建後立即被丟棄 → 過度設計</li>
<li>變數使用方式不一致 → 程式碼風格問題</li>
</ul>
<p>不存在「可能是」的情況。如果無法明確分類，則需要更深入的程式碼分析。</p>
<h3 id="範例完整的根因分析">範例：完整的根因分析</h3>
<h4 id="情境test檔案中unused變數-initialmemory">情境：test檔案中unused變數 &lsquo;initialMemory&rsquo;</h4>
<h5 id="錯誤分析">錯誤分析</h5>
<p>「這個變數沒用到，直接刪掉。」</p>
<h5 id="正確分析過程">正確分析過程</h5>
<ol>
<li><strong>變數意圖</strong>：記憶體效率測試的基線測量</li>
<li><strong>使用模式</strong>：建立但未在驗證邏輯中引用</li>
<li><strong>分類判斷</strong>：未完成實作（測試設計完整但驗證缺失）</li>
<li><strong>修復策略</strong>：補完基線比較邏輯而非移除變數</li>
</ol>
<h2 id="除錯的第二原則風險導向排序">除錯的第二原則：風險導向排序</h2>
<h3 id="檔案風險等級">檔案風險等級</h3>
<p>檔案修復必須按風險等級執行：</p>
<h4 id="高風險檔案立即修復">高風險檔案（立即修復）</h4>
<ul>
<li><strong>核心業務邏輯</strong>：Domain層實作檔案</li>
<li><strong>基礎設施元件</strong>：Database、Service、Repository</li>
<li><strong>關鍵測試</strong>：端到端測試、整合測試</li>
</ul>
<h4 id="中風險檔案計畫修復">中風險檔案（計畫修復）</h4>
<ul>
<li><strong>輔助功能</strong>：Utility、Helper類別</li>
<li><strong>測試工具</strong>：Mock、TestData產生器</li>
<li><strong>配置檔案</strong>：Configuration、Environment設定</li>
</ul>
<h4 id="低風險檔案可延後修復">低風險檔案（可延後修復）</h4>
<ul>
<li><strong>單元測試變數</strong>：純測試輔助變數</li>
<li><strong>範例程式碼</strong>：Demo、Sample實作</li>
<li><strong>文件產生器</strong>：Documentation工具</li>
</ul>
<h3 id="風險評估標準">風險評估標準</h3>
<ul>
<li>影響核心功能 → 高風險</li>
<li>影響開發效率 → 中風險</li>
<li>純粹警告清理 → 低風險</li>
</ul>
<p>每個檔案只能歸類到一個風險等級。無法分類表示需要進一步的架構分析。</p>
<h3 id="修復優先序執行規則">修復優先序執行規則</h3>
<ul>
<li>高風險檔案：立即修復，不考慮複雜度</li>
<li>中風險檔案：當前Sprint完成</li>
<li>低風險檔案：下個版本或維護期處理</li>
</ul>
<h2 id="除錯的第三原則主從分工模式">除錯的第三原則：主從分工模式</h2>
<h3 id="角色定義">角色定義</h3>
<p>系統化除錯採用明確的角色分工：</p>
<h4 id="主線程職責">主線程職責</h4>
<ul>
<li><strong>進度管控</strong>：追蹤修復狀態和整體進展</li>
<li><strong>策略決策</strong>：確定修復優先序和資源配置</li>
<li><strong>品質檢查</strong>：驗證修復結果符合品質要求</li>
<li><strong>工作記錄</strong>：更新工作日誌避免遺漏</li>
</ul>
<h4 id="代理人職責">代理人職責</h4>
<ul>
<li><strong>詳細分析</strong>：深入檢查程式碼設計意圖</li>
<li><strong>修復執行</strong>：實際編寫和修改程式碼</li>
<li><strong>測試驗證</strong>：確保修復後功能正常</li>
<li><strong>技術回報</strong>：提供修復細節和影響評估</li>
</ul>
<h3 id="協作執行規則">協作執行規則</h3>
<ul>
<li>主線程永不直接修復程式碼</li>
<li>代理人永不決定修復優先序</li>
<li>每修復一個檔案都必須更新工作日誌</li>
<li>所有修復決策都必須通過主線程確認</li>
</ul>
<h3 id="範例完整的協作流程">範例：完整的協作流程</h3>
<h4 id="情境發現5個檔案有unused警告">情境：發現5個檔案有unused警告</h4>
<h5 id="主線程執行">主線程執行</h5>
<ol>
<li><strong>風險評估</strong>：將5個檔案按業務風險分類</li>
<li><strong>優先排序</strong>：確定高風險檔案的修復順序</li>
<li><strong>委託分析</strong>：要求代理人分析第一個檔案</li>
<li><strong>進度追蹤</strong>：更新TodoList標記當前處理檔案</li>
</ol>
<h5 id="代理人執行">代理人執行</h5>
<ol>
<li><strong>根因分析</strong>：判斷unused變數屬於未完成實作vs過度設計</li>
<li><strong>修復實施</strong>：根據分析結果執行對應的修復策略</li>
<li><strong>結果驗證</strong>：執行靜態分析工具確認警告消除</li>
<li><strong>影響報告</strong>：回報修復內容和對整體架構的影響</li>
</ol>
<h5 id="主線程確認">主線程確認</h5>
<ol>
<li><strong>驗證結果</strong>：檢查靜態分析工具輸出確認修復成功</li>
<li><strong>更新記錄</strong>：在工作日誌中記錄修復成果</li>
<li><strong>繼續協作</strong>：標記完成並委託下一個檔案分析</li>
</ol>
<h2 id="品質標準">品質標準</h2>
<h3 id="修復完成的判斷標準">修復完成的判斷標準</h3>
<p>每個檔案修復完成必須滿足：</p>
<ul>
<li><strong>警告消除</strong>：靜態分析工具不再顯示該檔案的unused警告</li>
<li><strong>功能完整</strong>：所有測試通過，不引入新的錯誤</li>
<li><strong>架構一致</strong>：修復符合Clean Architecture分層原則</li>
<li><strong>文件更新</strong>：工作日誌記錄修復內容和影響</li>
</ul>
<h3 id="整體品質提升指標">整體品質提升指標</h3>
<ul>
<li><strong>警告減少率</strong>：unused警告數量持續下降</li>
<li><strong>功能完整性</strong>：修復過程中完成更多未完成的實作</li>
<li><strong>架構一致性</strong>：程式碼風格和設計模式更加統一</li>
<li><strong>可維護性</strong>：程式碼可讀性和邏輯清晰度提升</li>
</ul>
<h3 id="品質驗證機制">品質驗證機制</h3>
<ul>
<li>每個檔案修復後立即執行靜態分析工具驗證</li>
<li>定期檢查整體警告數量變化趨勢</li>
<li>記錄修復過程中發現的架構改善機會</li>
<li>確認每次修復都強化而非弱化程式品質</li>
</ul>
<h2 id="執行流程">執行流程</h2>
<h3 id="標準修復流程">標準修復流程</h3>
<ol>
<li>
<p><strong>問題評估</strong>
執行靜態分析工具識別所有unused警告</p>
</li>
<li>
<p><strong>風險分析</strong>
將含有警告的檔案按風險等級分類</p>
</li>
<li>
<p><strong>優先排序</strong>
確定高風險檔案的修復順序</p>
</li>
<li>
<p><strong>逐檔修復</strong>
按優先序對每個檔案執行：</p>
<ul>
<li>委託代理人詳細分析</li>
<li>根因判斷(未完成實作vs過度設計vs程式碼風格)</li>
<li>執行對應修復策略</li>
<li>驗證修復結果</li>
<li>更新工作記錄</li>
</ul>
</li>
<li>
<p><strong>整體驗證</strong>
確認警告總數下降且無新錯誤引入</p>
</li>
</ol>
<h3 id="修復策略對應表">修復策略對應表</h3>
<table>
  <thead>
      <tr>
          <th>根因類型</th>
          <th>修復策略</th>
          <th>驗證標準</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>未完成實作</td>
          <td>補完功能實作</td>
          <td>變數在邏輯中被正確使用</td>
      </tr>
      <tr>
          <td>過度設計</td>
          <td>移除多餘程式碼</td>
          <td>功能完整但程式碼更簡潔</td>
      </tr>
      <tr>
          <td>程式碼風格</td>
          <td>重構改善一致性</td>
          <td>邏輯不變但可讀性提升</td>
      </tr>
  </tbody>
</table>
<h3 id="例外處理原則">例外處理原則</h3>
<ul>
<li><strong>分析器誤報</strong>：確認變數確實被使用後保持現狀</li>
<li><strong>架構衝突</strong>：優先解決架構問題後再處理警告</li>
<li><strong>測試失敗</strong>：立即修復測試問題，暫停警告修復</li>
<li><strong>複雜邊界</strong>：分解為更小的問題單位處理</li>
</ul>
<h2 id="成果評估">成果評估</h2>
<h3 id="量化指標">量化指標</h3>
<ul>
<li><strong>警告消除數量</strong>：已修復的unused警告總數</li>
<li><strong>警告減少率</strong>：相對於初始狀態的改善百分比</li>
<li><strong>檔案修復數量</strong>：完成修復的檔案總數</li>
<li><strong>架構改善項目</strong>：修復過程中完成的設計改善</li>
</ul>
<h3 id="質化評估">質化評估</h3>
<ul>
<li><strong>根因解決率</strong>：真正解決問題vs僅消除警告的比例</li>
<li><strong>架構一致性</strong>：程式碼風格和設計模式統一程度</li>
<li><strong>功能完整性</strong>：修復過程中完成的未完成實作數量</li>
<li><strong>可維護性提升</strong>：程式碼清晰度和邏輯簡潔性改善</li>
</ul>
<h3 id="實戰案例v0819成果">實戰案例：v0.8.19成果</h3>
<p><strong>量化成果</strong>：</p>
<ul>
<li>初始警告：49個</li>
<li>最終警告：25個</li>
<li>改善率：49.0%</li>
<li>修復檔案：7個高風險檔案</li>
</ul>
<p><strong>質化成果</strong>：</p>
<ul>
<li>補完3個未完成的功能實作</li>
<li>移除4處過度設計的複雜程式碼</li>
<li>統一5個檔案的程式碼風格</li>
<li>解決2個架構不一致問題</li>
</ul>
<h2 id="持續改進">持續改進</h2>
<h3 id="方法論優化">方法論優化</h3>
<p>系統化除錯方法論必須持續優化：</p>
<ul>
<li><strong>記錄邊界案例</strong>：遇到的特殊情況和處理方式</li>
<li><strong>更新風險分類</strong>：基於實戰經驗調整風險評估標準</li>
<li><strong>改進協作模式</strong>：優化主線程和代理人的分工效率</li>
<li><strong>補充修復策略</strong>：新增針對特定問題類型的處理方法</li>
</ul>
<h3 id="知識累積">知識累積</h3>
<p>每次系統化除錯的經驗都必須沉澱為方法論改進：</p>
<ul>
<li>成功的修復策略納入標準流程</li>
<li>失效的方法從規範中移除</li>
<li>新發現的問題模式補充到分類標準</li>
<li>協作過程中的效率改善點持續優化</li>
</ul>
<h2 id="結論">結論</h2>
<p>系統化除錯方法論是品質提升的執行標準。它的價值在精確，它的目的是完成設計。</p>
<p>每個修復都是一次架構改善。每個分析都是一次設計檢視。每個協作都是一次品質提升。</p>
<p>執行系統化除錯就是執行品質標準。遵循這個方法論，我們能持續強化程式架構完整性和設計一致性。</p>
<p>這是工程規範，確保每次除錯都提升而非妥協專案品質。</p>
<h2 id="延伸套用到-linux-系統除錯">延伸：套用到 Linux 系統除錯</h2>
<p>這套方法論是語言與領域無關的通則。把它落到 Linux 系統除錯這個具體領域——「讀權威狀態而非肉眼猜表象」的紀律、症狀到情境的分流、逐層定位——見 <a href="/blog/linux/debug/diagnosis-read-authoritative-state/" data-link-title="診斷心法：讀權威狀態，不靠肉眼猜表象" data-link-desc="Linux 上一個現象看起來像 A 卻可能是 B、想建立一套先讀權威狀態再下判斷的除錯紀律、避免看畫面就猜而猜錯時回來讀">Linux 除錯與診斷：診斷心法</a>。那裡用實機案例（把鎖屏誤判兩次的教訓）展示同一套系統化紀律在 Linux 現場長什麼樣。</p>]]></content:encoded></item><item><title>Package 導入路徑語意化方法論</title><link>https://tarrragon.github.io/blog/record/package-%E5%B0%8E%E5%85%A5%E8%B7%AF%E5%BE%91%E8%AA%9E%E6%84%8F%E5%8C%96%E6%96%B9%E6%B3%95%E8%AB%96/</link><pubDate>Sun, 21 Sep 2025 00:00:00 +0000</pubDate><guid>https://tarrragon.github.io/blog/record/package-%E5%B0%8E%E5%85%A5%E8%B7%AF%E5%BE%91%E8%AA%9E%E6%84%8F%E5%8C%96%E6%96%B9%E6%B3%95%E8%AB%96/</guid><description>&lt;h2 id="為什麼導入聲明很重要">為什麼導入聲明很重要&lt;/h2>
&lt;p>在程式開發中，導入聲明往往被視為技術細節，但它們實際上是&lt;strong>架構文件的第一行&lt;/strong>。每個 import/require 都在告訴讀者：這個模組的依賴關係、系統的組織方式、以及設計者的架構思考。&lt;/p></description><content:encoded><![CDATA[<h2 id="為什麼導入聲明很重要">為什麼導入聲明很重要</h2>
<p>在程式開發中，導入聲明往往被視為技術細節，但它們實際上是<strong>架構文件的第一行</strong>。每個 import/require 都在告訴讀者：這個模組的依賴關係、系統的組織方式、以及設計者的架構思考。</p>
<p>相對路徑如 <code>import '../../../utils/helper.js'</code> 只是路徑的機械表達，而語意化路徑如 <code>import 'package:app/core/utils/helper.dart'</code> 則清楚傳達了模組的架構位置和責任。</p>
<h2 id="導入聲明的本質">導入聲明的本質</h2>
<h3 id="導入不是什麼">導入不是什麼</h3>
<p>導入聲明不是：</p>
<ul>
<li><strong>文件路徑的機械化表達</strong>：不是為了節省字元數而設計</li>
<li><strong>相對位置的簡化表示</strong>：不是為了避免長路徑而妥協</li>
<li><strong>開發便利性的工具</strong>：不是為了快速輸入而犧牲可讀性</li>
<li><strong>IDE 自動生成的結果</strong>：不是讓工具決定程式碼結構</li>
</ul>
<h3 id="導入是什麼">導入是什麼</h3>
<p>導入聲明是：</p>
<ul>
<li><strong>依賴關係的明確宣告</strong>：清楚表達模組間的連接</li>
<li><strong>程式碼架構的文件化</strong>：展示系統的組織結構</li>
<li><strong>依賴來源的即時說明</strong>：讓讀者立即理解依賴的性質</li>
<li><strong>架構意圖的表達方式</strong>：體現設計者對模組劃分的思考</li>
</ul>
<h2 id="核心原則">核心原則</h2>
<h3 id="第一原則導入路徑的架構語意性">第一原則：導入路徑的架構語意性</h3>
<p>每個導入都必須清楚表達來源的架構位置：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 正例：清楚表達架構層級
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/domains/library/entities/book.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/core/errors/standard_error.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1">// 反例：隱藏架構關係
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;../entities/book.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;../../../core/errors/standard_error.dart&#39;</span><span class="p">;</span></span></span></code></pre></div><h3 id="第二原則依賴來源的即時識別">第二原則：依賴來源的即時識別</h3>
<p>從導入聲明立即理解依賴性質：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 從導入立即理解：這是 Library Domain 的核心實體
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="p">{</span> <span class="nx">Book</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@app/domains/library/entities/book&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">
</span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1">// 從導入立即理解：這是 Core 基礎設施
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="p">{</span> <span class="nx">StandardError</span> <span class="p">}</span> <span class="nx">from</span> <span class="s1">&#39;@app/core/errors/standard-error&#39;</span><span class="p">;</span></span></span></code></pre></div><h3 id="第三原則禁用別名與妥協">第三原則：禁用別名與妥協</h3>
<p><strong>別名是程式設計不佳的象徵</strong>。當我們遇到重名衝突時，核心解決方案是重構和改善命名，而不是用別名掩蓋設計問題。</p>
<h4 id="為什麼禁用別名">為什麼禁用別名</h4>
<p>別名反映的根本問題：</p>
<ol>
<li><strong>命名不夠清晰明確</strong>：導致不同模組產生重名衝突</li>
<li><strong>架構設計缺陷</strong>：同一概念在不同領域使用相同名稱</li>
<li><strong>職責劃分不清</strong>：模組邊界和責任沒有明確定義</li>
<li><strong>技術債務累積</strong>：用別名掩蓋設計問題而非解決問題</li>
</ol>
<h4 id="錯誤的別名解決方案">錯誤的別名解決方案</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 反例：使用別名掩蓋設計問題
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;package:app/domains/library/entities/book.dart&#39;</span> <span class="k">as</span> <span class="n">LibBook</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:app/domains/search/entities/book.dart&#39;</span> <span class="k">as</span> <span class="n">SearchBook</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1">// 使用時仍然模糊不清
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"></span><span class="n">LibBook</span><span class="p">.</span><span class="n">Book</span> <span class="n">bookEntity</span> <span class="o">=</span> <span class="n">LibBook</span><span class="p">.</span><span class="n">Book</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="n">SearchBook</span><span class="p">.</span><span class="n">Book</span> <span class="n">searchResult</span> <span class="o">=</span> <span class="n">SearchBook</span><span class="p">.</span><span class="n">Book</span><span class="p">();</span></span></span></code></pre></div><h4 id="正確的重構解決方案">正確的重構解決方案</h4>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 正例：重構命名，消除重名衝突
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;package:app/domains/library/entities/book.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:app/domains/search/entities/search_result.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1">// 使用時語意清楚，職責明確
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"></span><span class="n">Book</span> <span class="n">libraryBook</span> <span class="o">=</span> <span class="n">Book</span><span class="p">();</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="n">SearchResult</span> <span class="n">searchData</span> <span class="o">=</span> <span class="n">SearchResult</span><span class="p">();</span></span></span></code></pre></div><h4 id="重構策略">重構策略</h4>
<p><strong>1. 重新審視命名責任</strong>：</p>
<ul>
<li>保留核心領域的概念名稱（如 Library Domain 的 Book）</li>
<li>重構其他領域的名稱為更精確的描述（如 Search Domain 的 SearchResult）</li>
</ul>
<p><strong>2. 領域邊界清晰化</strong>：</p>
<ul>
<li>根據職責重新命名類別和模組</li>
<li>確保每個名稱都有明確的領域歸屬</li>
</ul>
<p><strong>3. 架構重構優於別名妥協</strong>：</p>
<ul>
<li>禁用別名迫使開發者正視設計缺陷</li>
<li>推動更清晰的領域劃分</li>
<li>維護程式碼品質標準</li>
</ul>
<h2 id="跨語言實踐標準">跨語言實踐標準</h2>
<h3 id="dartflutter-package-系統">Dart/Flutter: Package 系統</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// Package 導入 + 完整路徑語意
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/domains/library/entities/book.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/domains/search/services/api_service.dart&#39;</span><span class="p">;</span></span></span></code></pre></div><p><strong>實現機制</strong>：<code>pubspec.yaml</code> 定義 package 名稱，Dart 編譯器將 <code>package:</code> 映射到 <code>lib/</code> 目錄。</p>
<h3 id="nodejs-混合策略-v1-專案實踐">Node.js: 混合策略 (V1 專案實踐)</h3>
<p><strong>生產環境</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 嚴格的目錄規範 + 明確的相對路徑
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="nx">BaseModule</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./lifecycle/base-module&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kr">const</span> <span class="nx">PageDomainCoordinator</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;./domains/page/page-domain-coordinator&#39;</span><span class="p">);</span></span></span></code></pre></div><p><strong>測試環境</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// Jest moduleNameMapper 實現語意化
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="kr">const</span> <span class="p">{</span> <span class="nx">ErrorCodes</span> <span class="p">}</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;src/core/errors/ErrorCodes&#39;</span><span class="p">);</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kr">const</span> <span class="nx">QualityAssessmentService</span> <span class="o">=</span> <span class="nx">require</span><span class="p">(</span><span class="s1">&#39;src/background/domains/data-management/services/quality-assessment-service.js&#39;</span><span class="p">);</span></span></span></code></pre></div><p><strong>Jest 配置關鍵</strong>：</p>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// tests/jest.config.js
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="nx">module</span><span class="p">.</span><span class="nx">exports</span> <span class="o">=</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nx">moduleNameMapper</span><span class="o">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">    <span class="s1">&#39;^src/(.*)$&#39;</span><span class="o">:</span> <span class="s1">&#39;&lt;rootDir&gt;/src/$1&#39;</span><span class="p">,</span>           <span class="c1">// src/ 路徑語意化
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1"></span>    <span class="s1">&#39;^@/(.*)$&#39;</span><span class="o">:</span> <span class="s1">&#39;&lt;rootDir&gt;/src/$1&#39;</span><span class="p">,</span>             <span class="c1">// @ 別名映射
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"></span>    <span class="s1">&#39;^@tests/(.*)$&#39;</span><span class="o">:</span> <span class="s1">&#39;&lt;rootDir&gt;/tests/$1&#39;</span><span class="p">,</span>      <span class="c1">// 測試檔案語意化
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"></span>    <span class="s1">&#39;^@mocks/(.*)$&#39;</span><span class="o">:</span> <span class="s1">&#39;&lt;rootDir&gt;/tests/mocks/$1&#39;</span> <span class="c1">// Mock 檔案語意化
</span></span></span><span class="line"><span class="ln">8</span><span class="cl"><span class="c1"></span>  <span class="p">}</span>
</span></span><span class="line"><span class="ln">9</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="php-laravel-框架--composer">PHP Laravel: 框架 + Composer</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-php" data-lang="php"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="o">&lt;?</span><span class="nx">php</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1">// Laravel 的命名空間 + Composer Autoloader
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1"></span><span class="k">namespace</span> <span class="nx">App\Domains\Library\Entities</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">
</span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="k">use</span> <span class="nx">App\Domains\Search\Services\ApiService</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="k">use</span> <span class="nx">App\Core\Errors\StandardError</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">use</span> <span class="nx">Illuminate\Database\Eloquent\Model</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="k">class</span> <span class="nc">Book</span> <span class="k">extends</span> <span class="nx">Model</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="c1">// 完整命名空間讓讀者立即理解依賴來源
</span></span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="c1"></span><span class="p">}</span></span></span></code></pre></div><h3 id="go-module-system">Go: Module System</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-go" data-lang="go"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="kn">package</span> <span class="nx">main</span>
</span></span><span class="line"><span class="ln"> 2</span><span class="cl">
</span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="ln"> 4</span><span class="cl">    <span class="c1">// 外部依賴使用 module path</span>
</span></span><span class="line"><span class="ln"> 5</span><span class="cl">    <span class="s">&#34;github.com/gin-gonic/gin&#34;</span>
</span></span><span class="line"><span class="ln"> 6</span><span class="cl">    <span class="s">&#34;gorm.io/gorm&#34;</span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl">
</span></span><span class="line"><span class="ln"> 8</span><span class="cl">    <span class="c1">// 內部模組使用完整 module path</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl">    <span class="s">&#34;book-overview-app/domains/library/entities&#34;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl">    <span class="s">&#34;book-overview-app/domains/search/services&#34;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl">    <span class="s">&#34;book-overview-app/core/errors&#34;</span>
</span></span><span class="line"><span class="ln">12</span><span class="cl"><span class="p">)</span></span></span></code></pre></div><h3 id="typescript-module-resolution">TypeScript: Module Resolution</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-typescript" data-lang="typescript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// Module 導入 + 完整路徑語意
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="kr">import</span> <span class="p">{</span> <span class="nx">Book</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@app/domains/library/entities/book&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">ApiService</span> <span class="p">}</span> <span class="kr">from</span> <span class="s1">&#39;@app/domains/search/services/api-service&#39;</span><span class="p">;</span></span></span></code></pre></div><h2 id="v1-專案無框架的成功實踐">V1 專案：無框架的成功實踐</h2>
<h3 id="為什麼-v1-可以不需要絕對路徑">為什麼 V1 可以不需要絕對路徑</h3>
<ol>
<li><strong>一致的目錄結構</strong>：所有模組都在 <code>/src/background/</code> 下，層級關係固定</li>
<li><strong>明確的相對路徑語意</strong>：<code>./</code> = 同級，<code>../</code> = 上一級，路徑語意清楚</li>
<li><strong>避免深層嵌套</strong>：最多 3-4 層目錄，相對路徑仍然可讀</li>
<li><strong>Jest 測試環境的語意化支援</strong>：透過配置實現測試檔案的語意化路徑</li>
</ol>
<h3 id="npm-test-vs-jest-直接執行的選擇">npm test vs Jest 直接執行的選擇</h3>
<p>V1 專案選擇 <strong>npm test</strong> 的原因：</p>
<ol>
<li><strong>一致性管理</strong>：統一的測試入口</li>
<li><strong>環境隔離</strong>：確保所有開發者使用相同配置</li>
<li><strong>工具鏈整合</strong>：可以執行測試前後的額外工作</li>
</ol>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// package.json - 統一的測試入口
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1"></span><span class="s2">&#34;scripts&#34;</span><span class="err">:</span> <span class="p">{</span>
</span></span><span class="line"><span class="ln">3</span><span class="cl">  <span class="nt">&#34;test&#34;</span><span class="p">:</span> <span class="s2">&#34;npm run test:core&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">4</span><span class="cl">  <span class="nt">&#34;test:core&#34;</span><span class="p">:</span> <span class="s2">&#34;jest tests/unit tests/integration&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">5</span><span class="cl">  <span class="nt">&#34;test:unit&#34;</span><span class="p">:</span> <span class="s2">&#34;jest tests/unit&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="ln">6</span><span class="cl">  <span class="nt">&#34;test:integration&#34;</span><span class="p">:</span> <span class="s2">&#34;jest tests/integration&#34;</span>
</span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="p">}</span></span></span></code></pre></div><h3 id="測試路徑語意化的實現機制">測試路徑語意化的實現機制</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-javascript" data-lang="javascript"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// Jest 如何解析語意化路徑：
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1">// 1. 測試檔案寫入: require(&#39;src/core/errors/ErrorCodes&#39;)
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1">// 2. Jest moduleNameMapper 攔截: &#39;^src/(.*)$&#39;: &#39;&lt;rootDir&gt;/src/$1&#39;
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1">// 3. 實際解析路徑: /project-root/src/core/errors/ErrorCodes.js
</span></span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="c1">// 4. Node.js 載入模組: 成功匯入 ErrorCodes
</span></span></span></code></pre></div><h2 id="語言特性對比">語言特性對比</h2>
<table>
  <thead>
      <tr>
          <th>語言</th>
          <th>實現機制</th>
          <th>優勢</th>
          <th>測試環境支援</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Dart</strong></td>
          <td>Package system</td>
          <td>編譯時解析，IDE 支援佳</td>
          <td>原生支援 package: 導入</td>
      </tr>
      <tr>
          <td><strong>Go</strong></td>
          <td>Module system</td>
          <td>強制語意化，無相對路徑</td>
          <td>測試檔案使用相同 module path</td>
      </tr>
      <tr>
          <td><strong>PHP Laravel</strong></td>
          <td>框架 + Composer</td>
          <td>自動載入，標準化目錄</td>
          <td>PHPUnit 自動載入命名空間</td>
      </tr>
      <tr>
          <td><strong>TypeScript</strong></td>
          <td>Module resolution</td>
          <td>彈性配置，工具支援</td>
          <td>Jest/Vitest 支援 path mapping</td>
      </tr>
      <tr>
          <td><strong>Node.js (V1)</strong></td>
          <td>相對路徑 + Jest 映射</td>
          <td>生產簡單，測試語意化</td>
          <td><strong>Jest moduleNameMapper 實現語意化</strong></td>
      </tr>
      <tr>
          <td><strong>Python</strong></td>
          <td>Package imports</td>
          <td>簡潔語法，標準化</td>
          <td>pytest 原生支援 package 導入</td>
      </tr>
  </tbody>
</table>
<h2 id="實踐選擇指南">實踐選擇指南</h2>
<h3 id="有框架的專案">有框架的專案</h3>
<ul>
<li>使用框架提供的模組系統</li>
<li>例如：Laravel、Angular、Next.js</li>
<li>測試環境通常自動繼承框架的模組解析</li>
</ul>
<h3 id="無框架的專案-如-v1-範例">無框架的專案 (如 V1 範例)</h3>
<ul>
<li><strong>生產環境</strong>：採用嚴格的目錄規範 + 相對路徑</li>
<li><strong>測試環境</strong>：使用 Jest moduleNameMapper 實現語意化</li>
<li><strong>關鍵優勢</strong>：生產簡單，測試語意化</li>
</ul>
<h3 id="混合策略專案">混合策略專案</h3>
<ul>
<li>生產環境使用簡單的相對路徑</li>
<li>測試環境透過工具配置實現語意化</li>
<li>適合輕量級 Node.js 專案</li>
</ul>
<h2 id="架構透明性的價值">架構透明性的價值</h2>
<h3 id="從導入理解系統設計">從導入理解系統設計</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln"> 1</span><span class="cl"><span class="c1">// 從這個檔案的導入可以立即理解：
</span></span></span><span class="line"><span class="ln"> 2</span><span class="cl"><span class="c1">// 1. 這是一個跨 Domain 的協調器
</span></span></span><span class="line"><span class="ln"> 3</span><span class="cl"><span class="c1">// 2. 主要整合 Library、Import、Search 三個領域
</span></span></span><span class="line"><span class="ln"> 4</span><span class="cl"><span class="c1">// 3. 使用 Core 的標準錯誤處理
</span></span></span><span class="line"><span class="ln"> 5</span><span class="cl"><span class="c1">// 4. 依賴外部的 HTTP 套件
</span></span></span><span class="line"><span class="ln"> 6</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln"> 7</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:http/http.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 8</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/core/errors/standard_error.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln"> 9</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/domains/library/services/library_service.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">10</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/domains/import/services/import_service.dart&#39;</span><span class="p">;</span>
</span></span><span class="line"><span class="ln">11</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/domains/search/services/search_service.dart&#39;</span><span class="p">;</span></span></span></code></pre></div><h3 id="依賴方向的視覺化">依賴方向的視覺化</h3>





<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-dart" data-lang="dart"><span class="line"><span class="ln">1</span><span class="cl"><span class="c1">// 讀者可以立即看出依賴方向：
</span></span></span><span class="line"><span class="ln">2</span><span class="cl"><span class="c1">// UI → Domain → Core
</span></span></span><span class="line"><span class="ln">3</span><span class="cl"><span class="c1">// 沒有反向依賴，符合乾淨架構原則
</span></span></span><span class="line"><span class="ln">4</span><span class="cl"><span class="c1"></span>
</span></span><span class="line"><span class="ln">5</span><span class="cl"><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/core/interfaces/repository.dart&#39;</span><span class="p">;</span>           <span class="c1">// 向下依賴
</span></span></span><span class="line"><span class="ln">6</span><span class="cl"><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/domains/library/entities/book.dart&#39;</span><span class="p">;</span>       <span class="c1">// 平行依賴
</span></span></span><span class="line"><span class="ln">7</span><span class="cl"><span class="c1"></span><span class="k">import</span> <span class="s1">&#39;package:book_overview_app/domains/library/value_objects/book_id.dart&#39;</span><span class="p">;</span> <span class="o">//</span> <span class="err">向下依賴</span></span></span></code></pre></div><h2 id="總結">總結</h2>
<p>Package 導入路徑語意化方法論的核心價值：</p>
<ol>
<li><strong>架構透明性</strong>：從導入立即理解系統結構</li>
<li><strong>維護便利性</strong>：減少理解和修改的認知負擔</li>
<li><strong>團隊協作</strong>：統一的導入風格提升溝通效率</li>
<li><strong>跨語言一致性</strong>：建立統一的程式碼組織哲學</li>
</ol>
<p>遵循這個方法論，程式碼將成為自說明的架構文件，每個導入聲明都清楚表達系統的設計意圖和模組關係。無論是有框架還是無框架的專案，都能找到適合的語意化導入策略。</p>
<p>V1 專案證明了即使在無框架環境下，透過嚴格的目錄規範和 Jest 測試配置，仍然可以實現生產環境簡潔、測試環境語意化的理想狀態。這為其他類似專案提供了寶貴的實踐參考。</p>
<h2 id="結論">結論</h2>
<p>這是架構透明化機制，讓每個導入聲明都成為架構的即時文件。</p>]]></content:encoded></item></channel></rss>