
你是不是也遇到過這種情況用 AI 編程助手比如 Cursor、GitHub Copilot時精心寫了半天 prompt結果生成的代碼要么跑不通要么和你的項目上下文完全不搭邊。你開始懷疑是不是自己的 prompt 技巧太差或者 AI 模型還不夠聰明但 Matt Pocock一位知名的 TypeScript 專家和開發者布道師提出了一個顛覆性的觀點真正決定 AI 編程效果的往往不是你的 prompt而是你的代碼庫本身的結構。換句話說如果你的代碼寫得一團糟AI 再聰明也讀不懂。他引入了一個叫做“深模塊”Deep Module的架構設計理念認為這是“治療”AI 讀不懂你代碼的良方。這篇文章要解決的正是這個被很多開發者忽略的核心問題。我們花了太多時間研究“如何向 AI 提問”卻很少思考“如何讓 AI 更好地理解我們已有的代碼”。本文將深入拆解 Matt Pocock 的觀點并結合大量實際開發場景為你講清楚為什么“深模塊”架構比“神 prompt”更重要背后的邏輯是什么“深模塊”具體是什么它與“淺模塊”有何本質區別如何在實際項目中無論是前端 React/TypeScript還是后端 Node.js/Java應用“深模塊”思想來重構代碼有哪些立即可用的代碼示例和重構技巧能立刻提升 AI 在你項目中的表現如果你已經受夠了 AI 生成無關代碼、無法理解業務邏輯的窘境那么改變代碼結構可能是你接下來最值得投入的一項“基礎設施”投資。本文不僅有理論更有能直接復制粘貼到項目中的實踐方案。1. 問題的本質AI 如何“閱讀”你的代碼庫在討論解決方案前我們必須先理解問題。當你向 Cursor 的 Chat 或 Copilot 提出一個需求時AI 并不是像人類一樣通讀整個項目然后深思熟慮。它的工作流程更接近于一種“受限的上下文檢索與模式匹配”。1.1 AI 編程助手的上下文處理機制以目前主流的 AI 編程工具為例有限的上下文窗口無論是 GPT-4 還是 Claude都有 token 限制如 128K。工具會智能地選取與你當前編輯文件最相關的代碼片段、打開的文件、最近的修改等填充到這個窗口里作為 AI 的“短期記憶”。基于嵌入的檢索更高級的工具如 Cursor 的“引用代碼庫”功能會為你的代碼庫建立向量索引。當你提問時它會檢索語義上最相關的代碼塊并將其作為上下文提供給 AI。模式匹配與補全在行內補全場景AI 主要關注當前文件的前后文和語言慣例進行“下一個 token 預測”。關鍵洞察AI 對代碼的理解深度嚴重依賴于它所能“看到”的上下文的質量和清晰度。如果你的代碼結構混亂、職責不清、接口復雜那么即使被檢索到AI 也很難提取出準確的意圖和模式。1.2 糟糕的代碼結構如何“毒害”AI假設你有一個用戶管理模塊代碼分散在多個文件且互相緊耦合// 文件src/utils/helpers.ts 一個什么都放的“工具雜貨鋪” export function validateEmail(email: string): boolean { /* ... */ } export function formatUserName(user: any): string { /* ... */ } export function sendEmail(to: string, subject: string, content: string) { /* ... */ } export function calculateUserScore(orders: any[]): number { /* ... */ } export const APP_CONFIG { /* ... */ }; // 文件src/components/UserProfile.tsx import { formatUserName, calculateUserScore } from ../utils/helpers; // 同時這個組件還直接調用了 API 層和狀態管理當你在這個UserProfile組件里問 AI“幫我在用戶頭像旁邊添加一個根據最近活躍度顯示的徽章”。AI 可能會看到calculateUserScore但不知道orders參數具體是什么結構從哪里來。看不到“活躍度”的業務定義在哪里。可能會錯誤地復用formatUserName的邏輯或者生成一個全新的、與現有工具函數重復的calculateActivityBadge函數。結果生成的代碼需要你大量修改才能集成或者引入了新的重復邏輯。你感覺 AI 很“笨”但實際上是你的代碼沒有給它提供清晰的“地圖”。2. 解藥深模塊Deep Module架構設計這個概念并非 Matt Pocock 獨創它源自 John Ousterhout 的經典著作《A Philosophy of Software Design》。其核心思想是評價一個模塊好壞的標準不是行數多少而是接口的簡潔度與內部功能的強大度之間的比值。2.1 深模塊 vs. 淺模塊一個直觀對比特性淺模塊 (Shallow Module)深模塊 (Deep Module)接口復雜、龐大、暴露大量細節簡單、小巧、隱藏復雜細節實現可能很簡單與接口復雜度不匹配內部可能很復雜但對外接口簡潔認知負荷高。使用者需要了解很多接口細節才能使用。低。使用者通過簡單的接口就能獲得強大的功能。對 AI 的影響AI 需要處理大量無關接口信息難以理解核心職責。AI 通過簡潔接口就能把握模塊核心功能易于正確調用和擴展。類比一臺面板上有100個按鈕但只能播放音樂的“播放器”。一臺只有一個“播放”按鈕但內部集成了高品質音響、降噪、網絡流媒體的智能音箱。2.2 深模塊的四個關鍵特征強大的抽象模塊提供一個高層次的、解決問題的抽象而不是一系列低層次的操作步驟。簡潔的接口暴露給外部的 API 或方法數量盡可能少參數清晰。隱藏的實現將復雜性、算法、數據轉換、第三方依賴等封裝在模塊內部。明確的職責一個模塊只做一件事并把它做到極致。3. 實戰重構將“淺模塊”代碼轉化為“深模塊”讓我們用一個具體的例子看看如何重構代碼使其對 AI 更友好。場景一個電商應用中的“價格計算”邏輯。3.1 重構前分散且透明的“淺模塊”代碼// 文件1: src/utils/priceCalculations.ts export function applyDiscount(price: number, discountRate: number): number { return price * (1 - discountRate); } export function addTax(price: number, taxRate: number): number { return price * (1 taxRate); } export function formatPrice(price: number, currency: string): string { return new Intl.NumberFormat(en-US, { style: currency, currency }).format(price); } export function isFreeShipping(subtotal: number, threshold: number): boolean { return subtotal threshold; } // 文件2: src/components/Checkout.tsx import { applyDiscount, addTax, formatPrice, isFreeShipping } from ../utils/priceCalculations; function Checkout({ items, userDiscount }) { // 業務邏輯散落在組件中 const subtotal items.reduce((sum, item) sum item.price, 0); const discountedPrice applyDiscount(subtotal, userDiscount); const finalPrice addTax(discountedPrice, 0.08); // 硬編碼稅率 const shippingEligible isFreeShipping(subtotal, 50); return ( div pSubtotal: {formatPrice(subtotal, USD)}/p pFinal Price: {formatPrice(finalPrice, USD)}/p pShipping: {shippingEligible ? Free : $5.99}/p /div ); }問題AI 在Checkout組件里看到一堆零散的函數調用和硬編碼的數字。如果讓它“添加一個會員雙倍積分功能”它很難判斷積分應該基于subtotal、discountedPrice還是finalPrice計算邏輯該加在哪里。3.2 重構后封裝良好的“深模塊”代碼我們創建一個PriceEngine深模塊。// 文件: src/lib/price/PriceEngine.ts export interface PriceCalculationParams { items: Array{ price: number; }; discountRate: number; taxRate: number; freeShippingThreshold: number; } export interface CalculatedPrice { subtotal: number; discountedAmount: number; taxAmount: number; finalAmount: number; isEligibleForFreeShipping: boolean; } export class PriceEngine { private params: PriceCalculationParams; constructor(params: PriceCalculationParams) { this.params params; } calculate(): CalculatedPrice { const subtotal this.calculateSubtotal(); const discountedAmount this.applyDiscount(subtotal); const taxAmount this.calculateTax(discountedAmount); const finalAmount discountedAmount taxAmount; return { subtotal, discountedAmount, taxAmount, finalAmount, isEligibleForFreeShipping: this.checkFreeShipping(subtotal), }; } format(price: number, currency: string USD): string { return new Intl.NumberFormat(en-US, { style: currency, currency }).format(price); } // 私有方法隱藏實現細節 private calculateSubtotal(): number { return this.params.items.reduce((sum, item) sum item.price, 0); } private applyDiscount(subtotal: number): number { return subtotal * (1 - this.params.discountRate); } private calculateTax(amount: number): number { return amount * this.params.taxRate; } private checkFreeShipping(subtotal: number): boolean { return subtotal this.params.freeShippingThreshold; } }現在組件中的使用變得極其簡潔// 文件: src/components/Checkout.tsx import { PriceEngine } from ../lib/price/PriceEngine; function Checkout({ items, userDiscount }) { // 所有復雜邏輯被封裝 const priceEngine new PriceEngine({ items, discountRate: userDiscount, taxRate: 0.08, freeShippingThreshold: 50, }); const price priceEngine.calculate(); return ( div pSubtotal: {priceEngine.format(price.subtotal)}/p pFinal Price: {priceEngine.format(price.finalAmount)}/p pShipping: {price.isEligibleForFreeShipping ? Free : $5.99}/p /div ); }3.3 為什么重構后對 AI 更友好接口極簡AI 在Checkout組件里只看到一個PriceEngine的導入和兩個方法調用calculate,format。它立刻明白這里是處理價格的。意圖明確當你想讓 AI“添加會員雙倍積分”時你可以直接在PriceEngine類上下文中提問。AI 看到calculate()方法返回CalculatedPrice類型它會自然地建議在這個類型中添加pointsEarned: number字段并在calculate()方法內部添加積分計算邏輯。所有相關邏輯都聚集在一個文件里AI 的上下文高度相關。隱藏變化稅率、免郵閾值等細節被封裝在參數和私有方法中。AI 不會在業務組件里被這些細節干擾從而更專注于核心業務流。4. 跨技術棧的深模塊設計模式深模塊是一種思想不限于 TypeScript 或前端。4.1 后端Node.js with NestJS服務層封裝// 淺模塊風格控制器里充滿邏輯 Controller(users) export class UsersController { constructor(private usersService: UsersService) {} Post(register) async register(Body() dto: RegisterUserDto) { // 驗證、業務邏輯、加密、郵件發送全堆在這里或分散在多個服務方法中 const exists await this.usersService.findByEmail(dto.email); if (exists) throw new ConflictException(Email exists); const hashedPwd await bcrypt.hash(dto.password, 10); const user await this.usersService.create({ ...dto, password: hashedPwd }); await this.mailService.sendWelcomeEmail(user.email); return user; } } // 深模塊風格一個清晰的“用例”服務 Injectable() export class UserRegistrationService { // 依賴注入其他服務 constructor( private userRepo: UserRepository, private mailService: MailService, ) {} // 一個強大的公共方法隱藏所有復雜性 async execute(dto: RegisterUserDto): PromiseUser { await this.validateRegistration(dto); const user await this.createUserEntity(dto); await this.userRepo.save(user); await this.sendWelcomeNotification(user); return user; } // 私有方法封裝細節 private async validateRegistration(dto: RegisterUserDto): Promisevoid { // ... 檢查郵箱唯一性、密碼強度等 } private async createUserEntity(dto: RegisterUserDto): PromiseUser { // ... 密碼哈希、生成驗證令牌等 } private async sendWelcomeNotification(user: User): Promisevoid { // ... 發送郵件、記錄日志等 } } // 控制器變得非常薄 Controller(users) export class UsersController { constructor(private registrationService: UserRegistrationService) {} Post(register) async register(Body() dto: RegisterUserDto) { return this.registrationService.execute(dto); } }對 AI 的益處AI 在修改注冊邏輯如添加手機號驗證時只需關注UserRegistrationService這個深模塊無需跳轉查看控制器、倉庫、郵件服務等多個文件上下文集中生成代碼的準確性大幅提高。4.2 通用原則創建“領域語言”深模塊的終極目標是讓你的代碼庫形成一套高級的“領域特定語言”DSL。當你的模塊提供了像PriceEngine.calculate()、UserRegistrationService.execute()這樣高層次的抽象時AI 就能用這種高級語言和你對話而不是糾纏于底層的applyDiscount或bcrypt.hash。5. 結合 AI 工具的最佳實踐工作流理解了深模塊我們可以優化使用 Cursor/Copilot 的工作流。5.1 第一步在正確的上下文中提問錯誤在龐大的App.tsx里問“如何實現價格計算”正確打開或創建src/lib/price/PriceEngine.ts文件然后問“在這個PriceEngine類中如何添加一個計算會員積分的方法積分規則是每消費1美元得1積分折扣后金額計算。”5.2 第二步利用 AI 進行重構你可以直接給 AI 指令“將當前這個分散的utils/priceCalculations.ts和Checkout組件中的邏輯重構為一個深模塊PriceEngine。” 一個設計良好的 AI 能夠根據現有代碼生成類似于第 3.2 節的初步結構。5.3 第三步定義清晰的接口和類型這是幫助 AI 理解模塊邊界的關鍵。在創建新模塊時先讓人或 AI 寫出主要的接口Interface和類型Type。// 先定義清楚模塊要做什么 export interface Campaign { id: string; name: string; discountType: percentage | fixed; value: number; } export interface PricingResult { original: number; discounted: number; applicableCampaigns: Campaign[]; } export interface PricingCalculator { calculateFinalPrice(items: LineItem[], campaigns: Campaign[]): PricingResult; }然后讓 AI 去實現PricingCalculator。有了清晰的接口約束AI 的實現會更符合預期。5.4 第四步迭代與封裝AI 生成代碼后檢查是否有暴露過多的內部細節。將不必要公開的輔助函數改為private將配置參數收攏到構造函數或配置對象中。不斷問自己“這個模塊的接口還能更簡單嗎”6. 常見問題與排查思路問題現象可能原因排查方式解決方案AI 生成的函數總是操作錯誤的數據結構模塊接口混亂數據結構不一致或未隱藏。檢查相關模塊的輸入輸出類型定義是否清晰、統一。定義并導出清晰的 DTO數據傳輸對象或領域模型讓所有函數都基于這些標準類型操作。AI 無法理解跨多個文件的業務邏輯邏輯過于分散形成“淺模塊”網絡。尋找一個業務流程如“用戶下單”看它涉及了多少個文件。將該業務流程重構為一個“深模塊”服務、用例或管理器聚合相關邏輯。AI 在補全時提供完全不相關的建議當前文件職責不單一包含太多不同領域的代碼。審查當前文件是否混合了視圖、邏輯、工具等多種代碼。使用“抽取函數”或“抽取類”重構將不同職責的代碼分離到不同的深模塊中。使用“引用代碼庫”功能后AI 引用了無關代碼代碼庫中命名相似但功能無關的模塊太多。檢查被引用的無關代碼的命名和位置。采用更具描述性、唯一性的模塊名和文件名。遵循功能分區目錄結構如/lib/auth,/lib/payment。對 AI 描述需求很費力需要寫很長 prompt代碼抽象層次太低缺乏領域語言。嘗試用一句話描述你想讓某個模塊做的事如果這句話很長且包含“和”、“然后”、“首先”等詞說明抽象不夠。將這一連串操作封裝到一個新的深模塊方法中并用那句描述來命名這個方法。7. 最佳實踐與工程建議從領域驅動設計DDD中汲取靈感聚合根Aggregate、實體Entity、值對象Value Object和領域服務Domain Service天然就是深模塊。它們定義了清晰的邊界和職責。依賴注入DI是好朋友它強制你定義清晰的接口并將模塊的依賴關系顯式化這極大地幫助了 AI 理解模塊的上下文和職責。如上文 NestJS 示例。編寫簡潔的模塊文檔JSDoc/TSDoc在模塊和類級別用一兩句話說明它的核心職責。AI 在檢索時會讀取這些注釋從而更好地理解模塊用途。/** * 核心定價引擎負責計算訂單的各類價格、折扣、稅費及運費資格。 * 封裝了所有定價規則和計算邏輯。 */ export class PriceEngine { ... }為深模塊編寫單元測試測試即文檔。清晰、覆蓋全面的測試用例向 AI 展示了模塊在各種邊界條件下的預期行為是極佳的上下文。避免“上帝對象”和“工具類陷阱”一個包含 50 個靜態方法的Utils類是典型的淺模塊。應該按領域將其拆分為StringUtils、DateUtils、PriceUtils等并最終演進為更深的領域模塊。循序漸進不必一步到位不要試圖一次性重構整個項目。下次當你需要 AI 協助修改某個功能時就以那個功能為起點將其重構為一個更深的模塊。積少成多代碼庫對 AI 的友好度會逐漸提升。8. 總結與后續方向Matt Pocock 的觀點之所以深刻是因為它指出了人機協作中的一個根本性轉變在 AI 時代代碼的可讀性對象不再僅僅是人類同事還包括 AI 智能體。“深模塊”架構本質上是在為 AI 優化代碼的“可檢索性”和“可推理性”。提升 AI 編程效率從癡迷于編寫“完美 prompt”轉向精心設計“清晰代碼結構”是一個更高杠桿率的投資。這不僅能讓你更好地駕馭 AI 工具更能從根本上提升代碼質量降低維護成本讓團隊協作也更順暢。你的下一步行動可以是審計一個模塊在你的項目中找一個經常讓 AI“犯糊涂”的功能點用本文的“深模塊”標準評估它。進行一次小規模重構花 30 分鐘嘗試將這個功能點重構成一個接口更簡潔、職責更明確的模塊。測試 AI 協作效果在重構后的模塊上向 Cursor 或 Copilot 提出一個新的、相關的功能需求感受生成代碼的準確度變化。記住最好的 prompt 工程可能就是從寫好你的下一條代碼注釋、設計好下一個函數接口開始的。當你開始像為一位強大的、但注意力有限的合作伙伴編寫文檔一樣去編寫代碼時你就已經走在了人機協同編程的前沿。