15+人團隊的前端體系架構應該如何管理?

{"type":"doc","content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如何在大型組織中管理前端體系架構,相關文章不多, 寫得也不好。本文所說的大型組織,是指公司前端工程師超過 15 人,有多個前端項目。我不想討論管理問題或業務問題,這些問題在大公司中很常見,我們只關注前端架構。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"目前前端架構涉及的領域太多,建議分幾個部分:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/98\/98e1ef7a1b60cc4b965b2b5cc647ee32.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"前端架構方案"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"1. 視覺代碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從最簡單的話題開始,我認爲,它是應用程序的視覺代碼。(譯者注:前端是最接近用戶的軟件開發環節,通過創建 Web 頁面或 App 應用,提供可視化信息給用戶,需要更加關注視覺效果和用戶交互)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"同一家公司開發了多個前端應用程序,希望他們有:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"明確的標識"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"統一的界面和用戶體驗"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了實現這一點,需要一個設計系統,由設計團隊提供,並在所有未來的產品設計中遵循這些設計準則。這項任務非常複雜,需要設計團隊、工程師和產品經理之間進行大量的討論和協調。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從前端角度來看,我們需要提供一個工具來實現這個設計系統,同時在工程師之間共享。一個很好的解決方案是創建 npm 包,由 storybook 或類似的工具來直觀的展現。我認爲,有一個專門的網絡資源(帶 URL)以及關於如何使用這個 npm 包的文檔非常重要。這個網絡資源將被前端工程師和設計師使用,並且可以成爲他們之間很好的紐帶。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/d6\/d68c396b02ad71ffd4743a81dc524452.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"視覺代碼"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"總結:"},{"type":"text","text":" 此時,我們有一個設計系統,表現爲一個 npm 包和交互式文檔,在所有前端應用程序共享並使用。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"2. 代碼結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們來談談工程師的日常工作,我們要實現新特性、修復 bug、甚至重構代碼。我們關注自己的代碼,寫的漂亮、易於理解。但是,當公司裏不是 1 個,2 個,而是幾十個小的或大的項目時,會發生什麼呢?通常,通過不同項目對開發者進行分組,他們只處理對應的項目。由於體力和時間有限,通常一段時間內我們只能處理幾個項目。自然地,我們開始受到這些分組的影響。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但是會出現越來越多的情況,當人們進行跨團隊協作時,需要檢查彼此的代碼和解決方案,甚至修復其他應用程序中的一些錯誤,或者在一些外部應用程序中添加他們需要的東西(對他們的分組來說影響是外部的)。壞消息是,這一過程正在大公司發生,幾乎無法控制。好消息是,我們可以幫助改進它。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"怎麼辦?是的,針對公司所有項目,提供相同的代碼結構、編碼,以及結構規範。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"讓我們更深入地瞭解代碼結構的含義:"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"項目中的目錄結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當工程師第一次加入新項目時,新項目與他們已有項目中的目錄結構相同,在那裏他們可以知道相關的所有東西,這對鏈路和搜索有很大幫助。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"配置或輔助文件"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在每個項目中,它們應該總是在同一個地方。如果需要,也可以類推到測試配置文件或 CI 文件(CI 是持續集成,從代碼提交到軟件交付到自動化過程)。常見的有:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"README.md(項目說明文件,Github.com 或 gitlab 託管時,會自動生成項目首頁)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"package.json(前端項目的入口文件,包含了依賴庫和執行命令等,yarn.lock 或 package-lock.json 是對應等緩存文件)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":".gitignore(Git 代碼管理時忽略的文件)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":".editorconfig(用來協同團隊開發人員之間的代碼的風格及樣式規範)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"webpack.config.js(Webpack 打包配置文件)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":".eslintrc.js(Eslint 的配置文件,用來管理和檢測 js 代碼風格)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":".travis.yml(CI 配置文件,用來描述持續構建步驟,編譯語言,系統環境等)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"postcss.config.js"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":".babelrc 或 babel.config.js"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":".prettierrc.js"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":".npmrc"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":".browserslistrc"}]}]}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"根據文件類型約定的固定位置"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果相同文件類型的位置總是遵循相同的結構,也會非常方便。例如,組件目錄始終具有 style.css 文件:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"null"},"content":[{"type":"text","text":"\/Component\n--\/Component.tsx\n--\/style.css\n--\/index.ts\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"組件內部結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"文件內部的結構應該是相同的:導入、導出的順序、公共函數的位置、類型等。在每種類型的文件中,你應該知道導出了什麼。(譯者注:導入 import、導出 export 是 ES6 的關鍵詞,用於模塊的引用和對外暴露)"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"命名約定"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"包括目錄、文件、變量、函數、類、類型的名稱等。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"編碼約定"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在一般情況下,我會說,編碼約定是一個非常廣泛的部分,這裏我只想說一些後面幾個章節不會再講的內容,例如是否以分號結尾(譯者注,前端 js 代碼中,結尾的分號在大部分情況下是可選的,但是團隊協作時,最好能達成一致,知乎上也有"},{"type":"link","attrs":{"href":"https:\/\/www.zhihu.com\/question\/20298345","title":"xxx","type":null},"content":[{"type":"text","text":"相關話題"}]},{"type":"text","text":")等類似的問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"相同的代碼結構和項目工具集在實踐中緊密結合在一起,相互幫助共存。我所說的工具集是指 CLI 工具(項目腳手架、語法和代碼風格檢查 linting、測試等)、IDE 擴展等。我們將在下一節討論工具集。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/93\/938371dd9b43eec4a694bc57f3394f53.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"代碼結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"總結:"},{"type":"text","text":" 在掌握並使用本節所講的之後,我們應該讓組織中的所有項目都用相同的目錄結構、命名準則、文件結構等。理想情況下,每個開發人員都可以輕鬆轉到任何其他項目中,而不會完全迷失在那裏。這個“完全迷失”也與項目中使用的技術棧密切相關,我們來討論一下。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"3. 技術棧"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"與上一節類似,我們希望在整個組織的項目中有統一的技術棧。原因非常相似——希望我們的工程師能適應公司的所有項目。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前端項目中,技術棧的組件可以是:框架、基於該項目的構建、主編程語言、樣式處理器、數據層(如 Apollo)、狀態管理、測試、linting、構建系統等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然,所有規則都有例外。我還想說一句,有些技術非常適合某些特定項目,即使這些技術不屬於全公司範圍的技術棧。但是,每當這種想法偏離公司技術棧時,你都應該三思而後行,因爲支持這些東西的成本非常高,所以收益必須是巨大的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我在這裏提一些通用的技術棧,它適合現在大多數項目(當然它只涵蓋了真正技術棧的一部分,但是對有些人來說是一個很好的起點):"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"React(用於構建用戶界面的 JS 庫)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Typescript(是 JavaScript 的一個超集,支持 ES6 標準,由微軟公司開發)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Apollo(是強類型查詢語言 GraphQL 的一種具體實現,包含 Apollo Client、Apollo Server 和 Apollo Engine)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Styled Components(樣式化組件,可以編寫 CSS 代碼來設計組件樣式,不需要組件和樣式之間的映射,即創建後就是一個 React 組件,並附加樣式到當前組件)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"React Router(React 官方路由,可以基於 URL 渲染不同的組件)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Jest(前端測試框架,它注重簡單性,集成了斷言、JSDom、覆蓋率報告等開發者所需要的所有測試工具,可用於 Babel, TypeScript, Node, React, Angular, Vue 等項目)"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Cypress(端到端功能測試框架,基於 Node.js,jQuery。開箱即用,不僅支持本地瀏覽器模擬測試,也支持終端測試。還有測試錄屏功能,方便在測試失敗的時候,查看當時的失敗場景)】Create React App(React 腳手架,用於快速搭建 React 項目)"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們定義了公司的技術棧並達成一致後,還有兩點非常重要。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們需要把技術資料寫在文檔上。這個文檔應該很方便在工程師之間共享,這樣他們就可以隨時給彼此一個鏈接來參照。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們應該再次寫下並分享文檔,說明如何使用指定的技術棧來啓動和引導新項目。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/50\/50a76744b9320a335ca8e740daf6e00c.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"技術棧"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"總結:"},{"type":"text","text":" 在我們實現並採納了上面提到的所有內容之後,你應該讓組織中的所有項目共享相同的技術棧。理想情況下,所有項目沒有任何區別,即使有一點小的差異也沒關係。如果再結合上一節,項目中的代碼、目錄、文件結構也應該幾乎相同。因此,任何項目中的鏈路都應該非常簡單明。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"4. 工具化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個話題很重要,我們現在到處都在使用輔助工具(開發新的工具,也叫“造輪子”),如 linting、應用程序構建、CI、組件生成器等等。所以,是否能爲項目選擇正確的工具至關重要,好的工具和差的工具(或者根本沒有工具)就像自動化和手動測試。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前面的章節中,我們剛剛討論了技術棧和代碼結構,並提到我們需要編寫大量的文檔,讓開發人員關注它們。但正確的工具集可以讓你自動遵循公司的指導原則。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果有指定的編碼樣式,你可以爲人們提供 linting 工具,它會默認遵循這些規則。如果你已經定義了技術棧,那麼好的 CLI 工具將爲你提供一個方法,從現有的技術棧轉到具有這些特定技術的新項目。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"讓我們試着討論一下,工具可以覆蓋前端體系結構的哪些部分:"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"代碼樣式和結構"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們前面討論過,可以很容易地通過工具實現自動化。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"項目腳手架"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你不再需要一個新的項目結構,不再手動安裝所有依賴包等。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"組件生成"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大多數情況下,應用程序中的某些組件甚至不只包含單個文件,因此創建、鏈接 \/ 導入文件可能需要一些時間,因此可以自動化。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"啓動和構建"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當然,最明顯的是要自動化——如何構建或啓動應用程序。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"測試"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲測試構建應用程序並實際運行所有類型的測試(單元測試、集成測試等)的過程。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"依賴關係管理"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們知道,現在大約 80% 的代碼都是依賴關係。因此,我們需要不斷更新,在一家大公司裏管理這一點並非易事。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"跨項目依賴"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們的項目很可能不是孤立的,可能依賴於其他項目,或者被其他項目依賴,因此我們可能需要一些工具來簡化關聯它們的過程,在多個項目的組合中進行開發(例如 Bit)等。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"CI"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"CI 是我們日常基礎工具集的重要組成部分,它的自動化和統一對團隊來說是非常有用。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你不想開發自己的工具集,我推薦 NX 工具集,它是最有趣的工具之一。另外,Babel 的作者也有類似的解決方案,Rome 瞭解一下。這些工具沒有涵蓋全部內容,而是我們所討論內容的一大部分,可以是很好的切入點。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/5a\/5aa6575c6549f29c74fc65379e708002.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"總結"},{"type":"text","text":":想象一下,在我們完成並採用了所有章節所講的之後,我們的架構會變得多麼厲害"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每個項目都有相同的結構,由統一的工具集進行維護和管理。每個項目都以相同的方式啓動和構建。組件都放在相應的目錄,並使用相同的命名準則。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"但這是優點還是有缺點?任何解決方案都有缺點。其中之一是,需要時間來招聘新的工程師。但是,如果一切都是以一種非常常見的方式(人們已經習慣了其他現有工具)並且有文檔記錄,那麼當你將它和開發效率的好處、工程師輕鬆使用任何代碼庫的機會等進行比較時,就是小事情。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"5. 生產環境"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對於前端架構的這一部分,工程師通常最不關心。可能是它大部分都與編碼本身無關,也許沒那麼令人興奮,但也很最重要。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在生產中,我們通常需要注意以下事項:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"分析"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"各種不同的事件跟蹤,如 Google Analytics(網站流量,用戶行爲,頁面鏈路等分析平臺),Segment(收集、清理和處理客戶數據平臺),HotJar(行爲分析和用戶反饋服務,瞭解網站用戶的行爲並通過熱圖,會話記錄和調查等工具獲得他們的反饋)等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"狀態監視"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"類似健康檢查,甚至是生產環境上運行的測試,錯誤報告(比如:Sentry)等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"性能"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這有點類似於上一項,但更注重性能。這包括響應時間估算、首屏渲染等(相關工具:Lighthouse)"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"A\/B 測試"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"各種 A\/B 測試解決方案(A\/B 測試是一種產品優化方法,爲同一個優化目標制定兩個方案,讓一部分用戶使用 A 方案,另一部分用戶使用 B 方案,統計並對比不同方案的轉化率、點擊量、留存率等指標,以判斷不同方案的優劣並進行決策)或功能標記(feature flag 控制線上功能開啓或者關閉,通常採取配置文件的方式。feature flag 允許關閉未完成的功能,在主幹上進行迭代開發,新功能即便未開發完成也不會影響發佈,因爲它對用戶是關閉的,也可以修改配置讓功能對特定的用戶可見。當功能開發完成之後,修改配置便可以讓功能發佈)。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"緩存"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Varnish,Cloudflare 之類的工具。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"所有這些都可以在公司的前端應用程序中統一,這將簡化工程師的工作。例如,通過添加具有預定義初始配置的包,並將這些包添加到新項目中。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"發佈生產的另一部分是代碼預處理,例如:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"壓縮:只是代碼壓縮"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"源代碼映射:一些其他工具也可能需要源代碼映射,如 Sentry。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"資源預處理:不同屏幕分辨率的處理,圖像裁剪等。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這些都可以添加到前端應用程序的工具集中,在工具化一節討論過。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/1a\/1a268ca39963c1f4910aa65e7800a30b.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"生產環境"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"總結:"},{"type":"text","text":" 理想情況下,所有這些都應該在初始化階段自動添加到每個前端項目中。工程師只需要添加配置到工具集相應的地方。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"6. 開發環境"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"CLI 工具"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"當我們談到前端 CLI 工具時,已經在工具化一節討論過開發經驗,統一的工具是工程師日常工作的一大部分,但不是全部。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"API"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們要做的第二件有意義的事情,是本地使用便捷的 API,它可以提高開發人員體驗和開發速度。通常,在本地爲前端工程師提供 API 並不簡單:這可能包括安裝他們不熟悉的工具或框架。即使安裝程序已經使用容器化部署,這也會佔用開發人員機器上的大量計算資源(否則,可以考慮做一個安裝程序)。在這種情況下,解決方案是什麼?——外部服務 API。這可以是一個供所有工程師使用的單一服務器,也可以是一些簡單的設置,指向你自己的專用服務器進行調用。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"CI"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"CI 是第三大部分。假設你的公司已經爲前端選擇了一些 CI 工具,並使用此唯一工具(例如 Circle CI、Concourse CI,或任何其他工具)。如果沒有,你應該把它統一起來。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在我看來,特定項目的 CI 配置應該是團隊工作的一部分,而團隊正致力於這個項目。這就要用到 CI,每天都要使用它。有人對 CI 感興趣,使它保持穩定,並且擁有修復、配置和改進它的能力和技能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"然而,並不是所有的工作都應該由團隊來完成。對於前端應用程序,存在一組非常特定的工作,這些工作可能是需要的。特別是,如果我們能設法統一目錄 \/ 代碼結構、技術棧等,那麼在貴公司工作一段時間後,你可能會在 CI 工具的各個階段接觸到這些模式,將這些階段作爲某種“構建塊”來實現,併爲你的工程師提供從這些統一的“構建塊”到 CI 流水線構建的可能。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"演示環境"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"最後我們要對開發好的功能進行了驗證。在工程師完成並實現了所有的任務之後,他們幾乎總是需要檢查它的外觀和功能,並與其他工程師、設計師或其他利益相關者分享。對於這樣的需求,爲特定 PR(合併請求)提供應用程序的臨時部署版本,同時提供一個 URL,會非常方便。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/15\/155664913581bb0bd326c7de314cdeea.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"應用程序臨時部署"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個解決方案大大加快了不同團隊和人員之間的溝通,我認爲這只是基礎必備的。但是,這個臨時部署的版本應該儘可能接近生產環境,因爲它也可以檢查一些明顯的錯誤或 bug。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果前端應用程序的構建和部署過程的流水線是統一的,那麼可以很容易地添加到項目中並實現自動化。此外,類似 Kubernetes(容器集羣管理工具,簡稱 K8S)和 Helm(K8S 包管理器)這樣的工具在自動化實現中也會有很大幫助。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/12\/122e0c024751881c523e85bf9346da40.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"開發環境"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"總結:"},{"type":"text","text":" 舒適高效的開發流程,使用單一的 CI 工具和構建塊,使用統一的 CLI 前端工具和演示環境創建各種 CI 流水線。所有這些都應該使我們的開發過程儘可能順利。把這個乘以你在公司的工程師人數,你就會明白這是多麼有益。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"7. 模塊化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"這個主題非常大,可能需要單獨的一篇文章來討論,但我會嘗試簡要地介紹一下。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在大型組織中,龐大的代碼庫並不少見,伴隨着所有已知的問題,比如緩慢的 CI 流水線、協作工作的問題、緩慢的測試等。因此前端架構的一個重要部分是決定我們希望看到獨立的前端應用程序 \/ 模塊的粒度。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我們現在有三種主要類型:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Monolith"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"大型倉庫只有一個項目,包含所有代碼,所有團隊同時在這個倉庫工作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Monorepo"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有許多項目,但仍然是一個大的倉庫(維基百科詞條)。所有團隊仍在同一個倉庫中工作,但使用不同的項目。現在已經有機會解決一些問題,我們採用的是 monolith 方法,只爲特定項目運行流水線,項目有更小的測試套件等等。如果你選擇這種方法,像 Lerna 這樣的工具可以讓你變得更輕鬆。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"每個項目一個倉庫"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"每個項目有自己的倉庫和全部輔助文件,比如 CI 流水線、部署等。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在所有這些模型中,項目可能意味着一個獨立的前端應用程序、頁面、獨立的前端模塊等。這取決於你想要決定拆分前端應用程序的粒度。在大多數情況下,這種劃分應該與所需的組織結構和人員管理同步。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在你決定拆分應用程序之後,第二個大的話題就是如何將他們連在一起,我們有如下幾個方法:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"構建時組合:你的項目可以只是 npm 包,在構建時安裝和組合。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"服務器端合成:這種方法通常包括服務器端呈現和服務器上發生的合成。像 Hypernova 這樣的工具可以幫助更好地組織它。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"客戶端合成:瀏覽器內項目的合成。在 Martin Fowler 的博客 中,對這些方法有很好的解釋。另外,要重點提一下 Module Federation,這是 Webpack 5 中引入的新方法。"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"路由合成:每個項目都有自己的 URL,在“Nginx 層面”我們決定將用戶重定向到哪裏。"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"正如我之前所說的,用這麼小的篇幅來報道這個話題非常困難,但我希望你有一些自己感興趣的想法,並且去挖掘這些話題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/9f\/9ff436fde24d0c03fafb961cc04aef5e.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"模塊化"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"總結:"},{"type":"text","text":" 我們找到了一種方法,通過組織倉庫,將項目分成更小的部分(儘可能),使團隊彼此更加獨立,讓我們的團隊成員感到快樂和高效。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"8. 測試"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"有很多可用到前端應用程序測試資源,可以很容易地找到,所以我儘量不談細節,而是更多地關注大型組織的問題以及我們如何解決這些問題。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"首先,每個工程師對測試技術的理解各不相同,在哪種情況下應用哪種技術,如何編寫“好的”測試等等。因此,準確地記錄公司使用的測試層面的所有細微差別和指導方針,以及每個測試層面的指導方針是非常有意義的。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"從測試策略方面看,你希望有哪些可能的測試類別:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"單元測試"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"集成測試"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"E2E 測試"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"其他"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"作爲第二步,我們需要將它們統一到公司的不同前端應用程序中,這樣人們就不會對遷移到不同項目時如何測試和測試什麼產生疑問。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果你成功地統一了測試級別和方法,那麼你可以自動幫助解決第二個問題——測試基礎結構設置。每個項目本身都需要在本地和一些測試基礎設施上進行設置和配置。例如,我們決定使用 Cypress,它需要在 Docker 容器中運行。這需要花一些時間在本地和 CI 上進行設置。如果我們把它乘以我們擁有的項目的數量——這是一個巨大的時間量。所以,對應的解決方案是再次統一,併爲項目提供一些工具。聽起來很簡單,但需要大量的時間來實現。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"非開發時間測試"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"我還想談談另一種方法,在已經實現和部署了特性之後測試應用程序。監控當然是其中的一部分。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前面的章節中,我們已經提到了前端應用程序的錯誤和性能監控、正常運行時間監控以及來自不同地區的響應。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在你的網站上運行 Lighthouse 測試也很好(可以包含在 CI 流水線中)。更容易找到性能瓶頸、可用性問題,並整體上改進網頁質量。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"對最重要的業務流進行最後的生產測試。如果你直接在生產環境中運行這些測試,它們很可能工作得最好,但如果我們可以在非常接近生產環境甚至鏡像生產環境的暫存 \/ 測試環境中運行此類測試。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/static001.geekbang.org\/wechat\/images\/08\/08d5aa5d98c8119b52b17fc8b886ce16.png","alt":null,"title":null,"style":null,"href":null,"fromPaste":false,"pastePass":false}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":"center","origin":null},"content":[{"type":"text","text":"測試"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"總結:"},{"type":"text","text":"我們有了明確的測試規範,爲每個前端應用程序定義必要的測試級別。每個應用程序都有一個單一的 CI 流水線,以及一個 CLI 工具,它可以幫助你在本地進行測試。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"原文鏈接:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/medium.com\/swlh\/frontend-architecture-in-scale-for-large-organizations-593930ed10cd","title":"","type":null},"content":[{"type":"text","text":"https:\/\/medium.com\/swlh\/frontend-architecture-in-scale-for-large-organizations-593930ed10cd"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章