《前端技術架構與工程》之編程語言筆記

《前端技術架構與工程》之編程語言

前言:昨天寫了部分這本書的筆記,今天把剩下的寫一寫。共分爲三部分筆記。一次講緒論、一次講技術架構、一次講工程服務體系。

《前端技術架構與工程》初次筆記

接下來講技術架構部分(編程語言、技術規範、組件化、前後端分離、性能)其中的編程語言。

不會按照書本上的內容照抄,不然好沒意思,除非非常必要,一般用自己的理解解釋。

不過這本書好多東西我都想寫上來,書上的內容就是我想要了解的。會有許多篇幅是來自原文的。只能說都是精華。

第一部分我會着重書寫~~,後面的我只搭建一個框架,具體細節我做筆記在書上,再敲到這博客裏好麻煩。~~

每一部分都很精華,還是按照每一章來寫,技術架構這一部分不好一次性講完。

前情回顧

軟件架構

軟件架構和軟件工程的概念是有區別的。架構強調的是強調軟件系統的設計方法論和實施模式,具體到做一個網站的時候,架構師做的是一個組長的角色,做的工作是把框架搭好,組織其他人員做架構以內的細節部分 ,如前端、後端、測試、運維。

工程學的核心是結合實際情況建立科學的、規範的設計和生產流程,降低生產成本,把這理念帶入軟件開發領域便形成了軟件工程。

這本書的核心:以業務爲出發點,架構聚焦於代碼,工程聚焦於流程。

代碼和流程是軟件工程的核心關注點。從代碼的角度考慮,工程的模板是保證軟件的高可用性、可擴展性、可伸縮性、性能以及安全,這些要素共用組成了軟件的技術架構;在架構之外,工程從更宏觀的角度完善開發和運維流程的管控,強調項目迭代的規範性、有序性、可控性和高效性,並更加架構特徵提供額外的輔助功能,也就是說,架構是工程的子集,其關係是(工程(架構(業務)))。

爲了便於區分和理解,本書將前端工程化中架構之外的部分稱爲前端工程服務體系。如此得出前端工程化的定義:前端工程化=前端技術架構+前端工程服務體系。

開發Dev與運維Ops

在前幾年,許多公司在技術團隊的組織架構劃分秉承研發與運維分離的原則,即負責業務設計(產品經理、設計師)、開發(工程師)、測試(測試員)的崗位組成應用研發團隊,而負責部署和發佈(運維師)的崗位獨立爲線上保障團隊。

項目經過需求設計、交互設計、開發以及測試後,開發人員將項目代碼遞交給運維人員,遞交方式是將壓縮包通過QQ或郵件直接交付。運維人員收到代碼的時候將項目文件進行部署和發佈,同時還負責服務器預警處理以及版本回滾。

將開放與運維分離的目的是保證線上的穩定性,開發人員不直接接觸生產環境,可以減少很多人爲失誤導致的低級錯誤。同時可以建立固定的上線週期。但是缺點是影響迭代的自由度。

故DevOps模式開始崛起,目標是實現軟件開發、測試和發佈的敏捷性和持續化。

前端架構師的職責

根據前面對前端工程化的定義,前端架構師的職責可以概括爲兩方面:

根據業務特徵設計合理的前端技術架構。
根據架構特徵搭建高效的前端工程服務體系
這本書的核心:以業務爲出發點,架構聚焦於代碼,工程聚焦於流程。

技術架構方面從五個部分講:編程語言、技術規範、組件化、前後端分離、性能;

工程服務體系方面從五方面將:開發、構建、測試、部署、持續化、監控與統計;

成本控制(時間成本、生產成本)是工程的核心關注點。具體到實際工作中,成本細分爲人力成本和溝通成本。前端工程服務體系的目標是:降低開發本身所消耗的人力成本;降低跨團隊協作消耗的溝通成本。

編程語言

這一章對HTM、CSS、JavaScript的內容進行了架構角度的理解。

HTML部分講了客戶端渲染CSR和服務端渲染SSR將了其各自的概念以及優缺點。其中CSR部分點到的virtual DOM、預處理、SEO十分恰到好處,切入點精彩。

CSS部分講了CSS預處理。

JavaScript部分講了異步編程的方案選擇。

開發iOS可以選擇swift、開發安卓應用可以選擇Java、kotlin,服務端編程語言可以選擇PHP、Java、go,而前端語言始終只要HTML、CSS、JavaScript,未來WebAssembly的進一步完善和普及能給前端帶來更豐富的編程語言選擇。

技術棧單一的好處是初學者有明確的學習方向,不必像其他領域的開發者一樣糾結編程語言的選擇;缺點是長期使用固定的編程語言很容易令開發者形成思維定式,缺乏跨領域思考和解決問題的能力。技術演變與架構設計不僅以本領域技術棧的特徵爲基礎,同時也需要在其他領域攝取靈感,比如Vue等流行前端框架所採用的MVVM架構模式便借鑑自WPF。

HTML

web網站誕生到發展至今的二十幾年時間裏,用JavaScript編寫HTML和CSS的趨勢越來越明顯。如Vue等開發框架。

web網站從靜態的webpage到動態webapp的過程中,客戶端渲染和服務端渲染佔了其中濃墨重彩的一部分。HTML渲染是前後端耦合最緊密的環節,客戶端渲染和服務端渲染是兩種基本模式。

相對而言,服務端渲染SSR有更深的技術沉澱和產業生態,但是客戶端渲染更有利於前後端分離。在實際開發中,不同渲染模式適用於不同特徵的業務。

SSR

在服務器端渲染,相比而言,其主要優勢在於其支持SEO且首屏時間短,前者從web整體產業生態出發,後者從用戶體驗出發。SSR適用於交互簡單、以靜態內容爲主並且有SEO需求的業務產品。

傳統模塊引擎:傳統SSR的實現模式是藉助於服務端編程語言或框架搭配的HTML模塊引擎將數據編譯爲HTML文檔。如Java的freemarker、PHP的smarty、node.js的pug。模塊引擎可以理解爲一個功能強大的字符串處理工廠,最大的優勢是快速和緩存。

react/vue SSR:virtual DOM令前端脫離對瀏覽器環境的強依賴,使用React/Vue承擔SSR的主要優勢是同構編程,同一組件可以同時適用於客戶端和服務端,但缺點是目前性能差。

CSR

在客戶端渲染,其優勢是更好地支持離線場景和前後端分離方案的實施,劣勢是弱SEO且首屏時間長。導致首屏渲染時間長的原因是服務器的配置通常優於個人電腦,同時搭配模塊引擎的緩存功能,但隨着個人電腦硬件性能的不斷提示、網絡傳輸、瀏覽器性能的提升,這些劣勢也逐漸縮小;而SEO也可以通過技術慢慢提示。

virtual DOM

虛擬DOM大幅度提升了對修改HTML元素的性能,使網頁響應更快。

DOM儲存於內存中,提供操作和修改HTML元素的一系列API。DOM操作是前端開發的核心,最早流行的前端框架都以優秀的DOM操作聞名,如jQuery。與JavaScript邏輯相比,DOM操作的性能消耗非常高,在以靜態內容爲主的webpage時代,少量DOM操作的性能損耗基本可以忽略,然而對於存在豐富動態內容的webapp而言,大量、頻繁的DOM操作逐漸成爲了性能瓶頸。

virtual DOM技術的核心是創建DOM對象的一個輕量級克隆對象,虛擬DOM擁有原始DOM除了操作HTML元素的API以外的所有屬性。對於JavaScript而言,虛擬DOM僅僅是一個擁有豐富屬性的對象,所有針對DOM的操作被映射爲對JavaScript對象的修改,性能上大幅度優於直接對DOM的操作。在接收到動態數據或用戶操作後,Vue或react會在內存中將虛擬DOM樹全量更新,對比檢查受影響的對象,隨後對這些對象所對應的真實DOM進行對應修改。得益於Vue或react的diff算法,可以採用全量更新策略並且能夠保障對比性能。

預渲染

預渲染從交互設計的角度上使網頁響應更友善。

用戶從輸入網站地址按下回車鍵到能夠在瀏覽器中有內容輸出,這段時間被稱爲首屏的白屏時間。除去DNS查找、TCP握手等開發者無法干預的瀏覽器前期工作外,SSR的白屏時間之所以相對短的原因是HTML文檔的HTTP請求響應內容有真實內容,渲染即可見。而由於瀏覽器解析

解決方法就是預先渲染出頁面骨架來代替空白的加載頁面,讓用戶能夠優先得到視覺上的反饋,從而一定程度上減少用戶耐心的 消耗。

SEO

SPA如何支持SEO是前端領域這幾年的熱門話題,目前普遍的彌補方案大致分爲兩類。具體看原書。

第一種方案是預渲染靜態內容,在構建階段將內容提前解析爲HTML字符串並添加到index.html中,目前主流的構建工具都提供預渲染功能,如webpack。優點在於實施成本較低,不涉及服務端開發,但對存在大量路由和動態數據的SPA項目,其對SEO提升小。

第二種方案是由仿真瀏覽器環境代替模板引擎,優點是媲美SSR的SEO支持,缺點是部署成本高。

CSS

CSS是一門非常簡單同時非常難的語言,它上手非常容易,就像HTML的配置選項,新手參照手冊可以快速配置出不錯的UI效果。但是CSS沒有變量、沒有命名空間、缺乏計算能力,造成CSS無規律可循,實現方案多樣、難以複用的問題。

CSS的不足

1沒有任何報錯機制。瀏覽器解析CSS代碼只會忽略錯誤代碼,不會拋出任何可見的錯誤,檢查錯誤時,不便解決錯誤;

2沒有命名空間。CSS規則應用於符合CSS選擇器規則的所有元素,後續迭代中,難以拓展;

3兼容性。由於各瀏覽器對CSS規範的支持程度不一,爲了兼容多個瀏覽器,大量兼容性的代碼令CSS文件越來越冗餘,增加了開發和維護難度,還拖累了web性能;

4低複用性。這是非常關鍵的一點。

CSS預處理

CSS預處理是目前被廣泛應用的CSS開發模式之一。less可視爲是一個具備特殊語法規範、可編譯爲CSS的開發框架。它彌補了CSS邏輯處理和複用性的不足,引入變量、混合、模塊、繼承等特性,同時支持更易於編寫和維護的嵌套語法,從細節和整體上提升了CSS的開發和維護效率。

不過缺點是大而全,容易導致代碼規範難以約束;難擴展,核心架構過於封閉,缺失插件生態。

CSS in JS

在JavaScript中編寫CSS代碼不是新鮮概念,在jQuery早期版本中提供相關API就可以實現。但CSS in JavaScript的核心不是簡單在JavaScript中編寫CSS代碼,而是利用JavaScript的語言特性和技術生態彌補CSS開發 模式的不足。

模塊。將JavaScript的模塊體系帶入CSS開發領域可以有效彌補CSS模塊體系的不足;

命名空間。CSS in JSt將組件以及內部元素的樣式限制在唯一的命名空間,從而實現樣式的隔離;

動態性。CSS in JS有樣式規則與JavaScript邏輯的互操作性。

JavaScript

前端發展的功能大部分來自JavaScript語言的推到。基於瀏覽器與JavaScript捆綁銷售的現狀,前端語言的選擇單一。不過JavaScript十分靈活,開發者進行技術選型的時候有豐富的框架、工具和規範可供參考。

編程風格極具個人色彩,雖然編程風格沒有好壞之分,但是多樣的編程風格對團隊和產品是一種災難。JavaScript的靈活性體現在語言本身的多樣性和實現方案的多樣性,針對這兩點,有兩種約束途徑:技術選型、代碼規範。

統一的技術棧是基礎,在此之上才能統一代碼規範。技術棧又細分爲底層技術棧和實現層技術棧。比如針對一個複雜的CMS進行技術選型時,使用TypeScript爲JavaScript編程加入靜態類型屬於底層技術棧,它們解決了語言層次的問題,然後使用vue同時搭配babel/webpack等工具則屬於實現層技術棧。在JavaScript編程領域,靜態類型static types和數據不可變性是目前底層技術棧要解決的兩個主要問題。

代碼規範可以細分爲代碼風格和方案選擇。代碼風格與邏輯無關,大都可以用ESLint等工具進行檢查和校正。方案選擇指一種邏輯可以用多種方案實現,如何選擇最合理的方案,如JavaScript異步編程,是選擇常規的回調函數還是promise,在promise的基礎上使用generator還是async/await。在任何一種方案的基礎上都可以通過合理地進行封裝實現健壯的架構,如接着babel可以在源碼開發階段使用瀏覽器尚不支持的JavaScript未來特性和語法。實現方案代碼的正確性和合理性無法完全使用工具檢測,人工審查必不可少。

靜態類型

JavaScript是一種動態類型語言,開發者在聲明變量時無需指明變量類型,解釋器會根據賦值判斷其類型。動態類型能夠很大程度增強語言的靈活性和提高開發效率,對輕量級項目有絕對積極的作用,但涉及大型項目需要警惕動態類型的負面效應。

由動態類型引起的bug對於前端應用不是少數,甚至超過了邏輯上的bug,而且這些bug大多數在測試或生產環境中暴露出來,對產品的穩定性造成巨大威脅。爲JavaScript引入靜態類型的目的便是將與類型有關的bug提前在編譯階段暴露出來,藉助一下支持語法檢查的IDE甚至在開發階段便可解決隱患。

除了提前檢測出bug外,靜態類型還能夠增強代碼的語義性和易讀性,在一定程度簡化邏輯,並且更有利於單元測試。

JavaScript基礎類型是靜態類型體系最初級的部分,此外還有枚舉Enum、接口interface、泛型generic等。這些需要長時間的學習,初期學到的靜態類型代碼可能還不如動態類型代碼健壯,這些需要大量的使用。

TypeSript是目前流行的JavaScript靜態類型編程工具,是JavaScript的超集,是一種編譯型編程語言,本質上與coffeescript相同。

不可變性

JavaScript的不可變性興起於redux的流行,在狀態管理這種特定場景下,不可變性令數據可預測、可追蹤,並且可以實現類似時光迴流的效果。

除了不可變性,redux還採取了函數式編程。函數式編程歷史久遠於面向對象編程,但確實JavaScript編程領域一直未普及的編程方式。函數式編程強調數據的不可變性,在狀態管理這種特定場景下,函數式編程與數據不可變性的結合十分適用。

異步編程

在深入JavaScript異步編程技術之前,有必要對調用棧、堆、任務隊列、事件循環進行解釋。

調用棧call stack:是一種類數組的結構,用於跟蹤函數的調用。

堆heap:是一種無序、散列的結構,用於存儲對象。

任務隊列task queue:JavaScript引擎用於存儲任務的一個有序隊列。

事件循環Event Loop:用上述理論基礎理解Event Loop的運行機制就是Event Loop檢測調用棧爲空閒狀態時將回調函數加入任務隊列中並且執行。在此基礎上對JavaScript單線程的解讀是:JavaScript只存在一個任務隊列,隊列中的任務按照被加入隊列的順序被依次執行。

JavaScript異步編程的基本原理是得到(ajax或HTTP)請求後通知JavaScript引擎,Event Loop檢測調用棧爲空閒狀態時將回調函數加入任務隊列中並且執行。

無論回調函數、promise、async/await都是在此基礎上的具象封裝。promise解決了回調函數的回調地獄問題,但是會產生新的then hell問題。這兩者都是相對底層的異步編程模式,通常需要額外的封裝纔能有效地提高開發效率。目前JavaScript在語言層面較上層的異步編程模式是async/await。得益於babel和polyfill(用於編寫下一代JavaScript的編譯器),這種編程模式可以應用於實際開發中。

總結

前端編程語言雖然單一但是具有高度的靈活性,所以從語言層面和架構模式層面都需要細細打磨。

HTML渲染是前後端耦合最緊密的環境,服務端渲染和客戶端渲染是兩種基本模式。相對而言,SSR有更深的技術沉澱和產業生態,CSR更有利於前後端分離。在實際開發中,不同的渲染模式適用於不同特徵的業務。我的話,爲了前後端分離,以SSR爲基礎,去學習和應用CSR。

CSS的弱編程能力給開發和維護帶來了極大的挑戰。爲了兼容性、可複用性,我先初期學習less和CSS in JavaScript。PostCSS和Houdini等需要用的時候用。

爲JavaScript加入靜態類型能夠有效地開發或編譯階段消除一下由動態類型產生的隱患,對於複雜架構系統非常有必要。數據的不可變性和函數式編程有天然的融合性,兩者結合能夠很大程度上提高JavaScript代碼的可測試性。從技術選型和代碼規範上學習靜態類型、數據不可變性、ESLint、異步編程。提前處理由動態類型引起的bug,使得編寫的程序更穩健。在這裏可以解決Java語言。

最後,本來是想寫自己的理解,卻沒想到這裏許多內容都感覺有必要寫出來。大家如果感興趣的話,親自看書體驗更佳。

更新地址:GitHub

更多內容請關注:CSDNGitHub

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章