我為什麼選擇 Angular 2?

InfoQ - 汪志成發表於2016-07-10

沒有選擇是痛苦的,有太多的選擇卻更加痛苦。而後者正是目前前端領域的真實寫照。新的框架層出不窮:它難嗎?它寫得快嗎?可維護性怎樣?執行效能如何?社群如何?前景怎樣?好就業嗎?好招人嗎?組建團隊容易嗎?

每一個框架都得評估數不清的問題,直到耗光你的精力。這種困境,被稱為“布利丹的驢子” —— 一隻驢子站在兩堆看似完全相同的乾草堆中間,不知道如何選擇,最終餓死了。

當然,那只是一個哲學寓言。現實中,大多數人採用了很簡單的策略來破解它:跟風,選擇目前最流行的那個。這是一個低成本高收益的策略,不過也有風險:成為現實版的《猴子下山》。最理想的方案還是要看出這兩堆“乾草”之間的差異,選擇更適合自己的那個。

本文就將帶你瞭解Angular 2這個“乾草堆”的各種細節。

ALL-IN-ONE

不管是1還是2,Angular最顯著的特徵就是其整合性。它是由單一專案組常年開發維護的一體化框架,涵蓋了M、V、C/VM等各個層面,不需要組合、評估其它技術就能完成大部分前端開發任務。這樣可以有效降低決策成本,提高決策速度,對需要快速起步的團隊是非常有幫助的。

讓我們換一種問法吧:你想用樂高搭一個客廳,還是買宜家套裝?

Angular 2就是前端開發領域的“宜家套裝”,它經過精心的前期設計,涵蓋了開發中的各個層面,層與層之間都經過了精心調適,是一個“開箱即用”的框架。

當然,你可能還記著Angular 1帶給你的那些快樂以及……痛苦。這是有歷史原因的。由於它是從一個用來做原型的框架演化而來的,加上誕生時間很早(2009年,作為對比,jQuery誕生於2006年),當時生態不完善,連模組化機制都得自己實現(這就是angular.module的由來,也是Angular 2中拋棄它的理由)。在長達七年的演化過程中,各種進化的遺蹟非常明顯,留下了不少“闌尾”。

但Angular 2就不同了,它的起點更高,整合了現代前端的各種先進理念,在框架、文件、工具等各個層面提供了全方位的支援。比如它的“元件樣式”能讓你在無需瞭解CSS Module的前提下獲得CSS Module的好處,它的Starter工程能讓你在無需瞭解Webpack的前提下獲得Hot Module Replacement等先進特性,它能讓你從Web Worker(你知道這是什麼嗎?)中獲得顯著的效能提升。

你只管在前臺秀肌肉吧!剩下的,讓Angular在幕後幫你搞定!

模組化的技術

雖然Angular是一個ALL-IN-ONE的框架,但這並不妨礙它同時是一個靈活的框架。還記得OCP(開閉原則)嗎?一個好的設計,對擴充套件應該是開放的,對修改應該是關閉的。

Angular 2很好的踐行了OCP原則以及SoC(關注點分離)原則。

它非常有效的分離了渲染與互動邏輯,這就讓它可以很好的跟包括React在內的渲染引擎搭配使用,除此之外,它還可以使用記憶體渲染引擎,以實現服務端渲染;還可以使用Native渲染引擎,以編譯出真正的原生程式(NativeScript)。

它還分離了資料供應與變更檢測邏輯,從而讓它可以自由使用包括RxJS以及ImmutableJS在內的第三方資料框架/工具。

不僅如此。

在Angular 1和Angular 2中最具特色的應該算是依賴注入(DI)系統了,它把後端開發中用來解決複雜問題、實現高彈性設計的DI技術引入了前端。Angular 2中更是通過引入TypeScript賦予它更高的靈活性和便利性。

不過,Angular 2並沒有敝帚自珍,把它跟框架本身緊緊黏結在一起,而是把它設計成了一個獨立可用的模組。這就意味著,無論你正在使用什麼前端框架,甚至NodeJS後端框架,都可以自由使用它,並從中獲益。

全生命週期支援

除非你打算寫一個一次性應用,否則軟體的生命週期會很長。巨集觀來看,真正的挑戰來自多個方面,而且在不斷變化。

開始的階段,我們需要非常快速的建立原型,讓它跑起來,引入終端使用者來試用,這個時候,挑戰來自開發速度以及可複用資產。

之後,會建立一個逐漸擴大的專案組,來完善這個原型的功能。主要的挑戰是讓這個原型通過重構不斷進行演化,特別是在演化的後半個階段,產品需要保持隨時可以上線的狀態。但技術上的挑戰那都不是事兒!關鍵是人。

如何讓新人快速融入專案組,貢獻生產力?這可沒那麼簡單。“你先去學xxx 0.5、yyy 0.9、zzz 5.3…還要了解它們前後版本之間的差異,我再給你講程式碼”,這種話,我可說不出口。一個優秀的框架需要對分工提供良好的支援,每個人都可以先從一些簡單任務開始,逐步的從修改一個檔案擴大到修改一個目錄再到獨立實現一個特性。

有了這種分工,每個團隊成員就可以從一個成功走向一個更大的成功。這就需要框架在設計上具有良好的區域性性:你可以放心大膽的修改一部分,而不用擔心影響另一部分。你可以只修改CSS,可以只修改HTML,可以只修改TS/JS,而不用擔心自己的修改破壞了其他部分。而Angular 2通過宣告式介面、元件樣式以及獨立模板檔案等對這種安全感提供了有力的保障。

再然後,如果你的軟體順利的進入了線上維護階段,那麼恭喜你,你終於迎來真正的大Boss了!這個大Boss就是可維護性。Angular開發組有很多程式設計師來自Google,如果要問誰的軟體維護經驗最豐富,Google和微軟必然名列前茅。微軟通過TypeScript的強型別機制體現了自己的經驗,而Google則通過將OCP、SoC、SRP等一系列軟體設計原則融入Angular體現了自己的經驗。具體技術上則體現為:DI、生命週期鉤子、元件等等。

最後,如果你的軟體完成了歷史使命需要逐步退出,是不是就能鬆口氣了?不行,你還得繼續留人維護它。如果你選擇的是一個閉源的或某個社群很羸弱的開源技術,你就把以前的主力架構師、資深程式設計師留下來繼續維護它吧。或者你就得鼓起勇氣跟使用者說:你們玩兒,我先走了。而Angular是一個大型開源專案,並得到了Google的鼎力支援。即使經歷過Angular 2專案組初期的公關失敗,它仍然有著其它競品無法企及的繁榮社群 —— 無論在全球還是在中國。顯然,無論是對傳統社群資源的繼承,還是對新社群資源的開拓,我們都有理由相信,Angular社群仍將一如既往地繁榮。至少,如果你不想讓自己的軟體建立在一大堆由個人維護的核心庫上,那麼Angular毫無疑問是最好的選擇。

逃離“版本地獄”

如果是一兩個人開發一個預期壽命不到一年的系統,那麼任何框架都可以勝任。但,現實中我們都把這種系統稱之為“坑”。作為一個高度專業、高度工程化的開發組,我們不能把“坑”留給友軍。這些坑中,最明顯的就是“版本地獄”。

想象一下,你僅僅升級了庫的次版本號,原來的軟體就不能用了,損壞了N處單元測試以及M個E2E場景。這種情況對於開發組來說簡直是一個噩夢 —— 畢竟,誰也不想做無用功,更何況是一而再、再而三的。或者,它每次小的改動都會修改主版本號 —— 對,我就是不向後相容,你能咋地?你所能做的就是每一次決定升級都如臨大敵,不但要小心翼翼的升級這個庫本身還要升級與它協作的幾乎所有庫。

可見,亂標版本號可能會讓使用者付出巨大的代價。這不但體現在工作量上,還會體現在研發團隊的招募與培養上,想象一下,對小版本之間都不相容的框架,研發團隊都需要記住多少東西?那簡直是噩夢!

但是,版本號的問題在業內早就有了事實性標準,那就是SemVer語義化版本標準。唯一的問題是,作為框架/庫的作者,遵循SemVer標準需要付出的努力是巨大的。是否願意付出這些代價,是一個框架(及其開發組)是否成熟的重要標誌。

Angular就是這樣一個框架,其開發組曾作出的努力是有目共睹的。如果你是從Angular 1.2開始使用的,那麼你為1.2所寫的程式碼都可以毫無障礙的遷移到最新的1.5版,新的版本只是引入了新特性,而沒有破壞老特性。這是因為Angular開發組寫了大量單元測試和E2E測試,藉助CI來保障這種平滑過渡。只有在從1.0到1.2的遷移過程中(1.1一直是beta,忽略不計),出現了一系列破壞性變更,這些變更被明確的記錄在文件中,並且解釋了做出這些變更的理由 —— 大多數是因為提升前端程式碼安全性。即使你恰好遇到了這些破壞性變更,它也會給出明確的錯誤提示。

這些必要而無聊的工作,正是幫助我們逃離“版本地獄”的關鍵。是否願意做這些無聊而瑣碎的工作,是一個框架的開發組是否成熟、專業的關鍵特徵。而Angular的開發組已經證明了它值得你信任!

遇見未來的標準

程式設計領域,創新無處不在。但對一個工程團隊來說,最難得的是標準。標準意味著:

  • 招人容易。因為標準的東西會的人最多,而且人們願意學它 —— 因為知道學了就不會浪費。
  • 養人容易。因為網上有很多教程可用,即使不得已自己做教程,價效比也是最高的。
  • 換人容易。標準就意味著不是私有技術,一個人離開了,就能用另一個人補上,而不會出現長期空缺,影響業務。

但是,標準永遠會比創新慢一拍或N拍。這就意味著如果你追新,那麼在獲得技術上的收益的同時,也要付出工程上的代價。固然,兩者不可兼得,但是還是有一些策略能夠調和兩者的。最簡單的策略就是:遇見未來的標準。

所謂未來的標準,就是某個標準的草案,它很有希望成為未來的標準,這代表了業界對某項技術的認可,於是,即使它還不成熟,人們也願意為之投資。比如雖然Google曾經提出過N種自有技術,包括SPDY、Gears、OGG等,但卻並沒有把它們變成私有技術,而是對社群開放以及併入W3C的標準草案。

Angular 2採用的就是這種策略。它所參照的標準草案比較多,一個是WebWorker,它藉助WebWorker來把繁重的計算工作移入輔助執行緒,讓介面執行緒不受影響;另一個是WebComponents,Angular 2的元件化體系就是對WebComponents的一種實現;最後是CSS scoping,現在雖然市面上有了很多CSS模組化技術,但事實上最終還是會被統一到CSS Scoping標準上,屆時,如果:local等關鍵字無法進入標準,就會成為私有技術。而Angular 2選擇的方式是直接實現CSS scoping標準草案,比如:host、:host-context等。顯然,採用這種策略,“遇見未來的標準”的成功率會高得多。

可以看到,Angular 2的設計哲學中貫穿著對標準化的熱烈擁抱,這是我判斷它將贏得未來的另一個信心來源。

速度與激情

Angular 2終於擺脫了舊的技術框架束縛,開始了對速度的極致追求。在Angular 1中,雖然絕大多數場景下效能都不是問題,不過還是因為其程式碼中存在的一個用來實現髒檢查的三重迴圈而飽受抨擊 —— 似乎真有人能感受到30毫秒和100毫秒的差異似的。

不過,有軟肋總是不太好。於是,在Angular 2中,通過重新設計和引入新技術,從原理上對速度進行了提升,據官方以前提供的一個資料說是把“變更檢測”的效率提升了500%。

它在“變更檢測”演算法上做了兩項主要的改進:

  • 在設計上,把以前的“多輪檢查、直到穩定”策略改成了“一輪檢查、直接穩定”策略。當然,這會對自己的程式碼產生一定的限制,但實際上只在有限的少數幾個場景下才會遇到這個限制,而且官方文件中也給出了明確的提示。
  • 在實現上,把“變更檢測”演算法移入了由WebWorker建立的輔助執行緒中執行。現代的家用電腦很多都已經是多核超執行緒的,但是瀏覽網頁時實際上無法充分利用全部執行緒,而WebWorker提供了一個新的機制,讓一些相對繁重的計算工作執行在輔助執行緒中,等執行完了再通知主執行緒。即使你不明白WebWorker的工作原理,至少也能知道Ajax請求是不會阻塞介面響應的,WebWorker也一樣。

除此之外,Angular還對資料來源進行了抽象,你完全可以用ImmutableJS來作為Angular的資料來源,獲得其在提升“變更檢測”速度方面的所有優勢。

除了“變更檢測”外,Angular以及所有前端SPA程式,都有一個通病:首次載入太慢,要下載完所有js和css才能渲染出完整的介面來。React通過虛擬DOM解決了此問題,而Angular 2則通過獨立的服務端渲染引擎解決了這個問題。我們前面說過,Angular 2把渲染引擎獨立了出來,因此可以在NodeJS中實現服務端的記憶體渲染。所謂記憶體渲染就是在記憶體中把DOM結構渲染出來併發回給瀏覽器,這樣,客戶端不需要等JS程式碼下載完就可以顯示出完整的介面了。這種分離還帶來了另一個好處,那就是SEO。SEO同樣是傳統SPA的一個難點,它和服務端渲染是同一個問題的兩個方面,因此隨著服務端渲染的完成,SEO問題也被順便解決了。

讓你無縫升級

Angular 2開發組在早期階段曾犯下一個嚴重的公關錯誤:過早宣佈不相容Angular 1,也不提供從Angular 1到2的升級方案。

這讓Angular 2開發組付出了沉重的代價,可謂傷透了粉絲的心。作為技術人員,這種失誤固然是可以理解的,但卻需要付出更多的努力來彌補它。而Angular 2確實這麼做了。

在Angular 2中,開發組提供了一個UpgradeAdapter類,這個升級介面卡讓Angular 1.x的所有部件都能和Angular 2.x中的所有部件協同工作。

而最牛的地方在於,它讓你可以一個檔案一個檔案的逐步升級到Angular 2,而在整個升級過程中,應用可以繼續線上上跑!看著神奇嗎?其實也算不了啥,Google做這種事早就是輕車熟路了。這只不過是對Angular開發組出色的工程化開發能力的一點小小證明而已。

不過,既然如此,當初又何必急匆匆宣佈不相容呢?可見,再出色的工程團隊,如果缺少了和社群溝通的產品運營技巧,也會付出巨大代價。希望Angular開發組以後能謹言慎行,多用行動來平息質疑。

幕後 —— 當Google牽手微軟

當年的瀏覽器大戰,讓人記憶猶新,Chrome的出品商Google和IE的出品商微軟正是瀏覽器大戰的兩大主角。

俗話說:沒有永遠的朋友,也沒有永遠的敵人,只有永遠的…… 精益求精。

正是在這樣的“俗話”指導下,Google與微軟相逢一笑泯恩仇,撤銷了很多針對彼此的訴訟,甚至在一些領域開始合作。而實際上,在他們公開和解之前,就已經開始公開合作了,其契機就是Angular 2。

這就要扯出一點小八卦了。

在Angular 2開發的早期階段,由於傳統JS(ES5)以及當時的ES6草案無法滿足專案組的開發需求,專案組有點煩。後來有人靈機一動開發了一種叫做AtScript的新語言,它是什麼呢?一個帶型別支援和Annotation支援的升級版JS。其實在型別支援方面,TypeScript早就已經做了,而且那時候已經比較成熟,唯一的遺憾是不支援Annotation,也就是像Java中那樣通過@符號定義後設資料的方式。

Angular開發組就這樣孤獨的走過了一小段兒時間,後來也不知道怎麼這兩個歡喜冤家就公然牽手了。總之,最後的結果是:TypeScript中加入了與Annotation相似的Decorator特性,而Angular放棄了AtScript改用TypeScript。

這次結合無論對兩大廠商還是對各自的粉絲,都是一個皆大歡喜的結局,稱其為世紀聯手也不為過。此後,Google與微軟不再止於暗送秋波,而是開始了一系列秀恩愛的動作。無論如何,對於開發者來說,這都是一個好訊息。

軟粉們可能還記得在6.1的微軟開發者大會上,微軟曾公開提及Angular 2。事實上,TypeScript目前雖然已經相當完備,但應用度仍然不高。就個人感覺來說,Angular 2將是TypeScript的一個殺手級應用。TypeScript如果當選TIOBE年度語言,Angular 2的推出功不可沒。

為什麼我要特意插播這段兒故事呢?那是因為我認為一個產品的未來最終取決於開發組的未來,而不是相反。軟體的本質是人!一個心態開放、講究合作、勇於打破陳規陋習的開發組,才是框架給人信心的根本保障。

後端程式設計師的終南捷徑

前端程式設計師自不必說,因為有很多人就是靠Angular進入專業前端領域的。下面這段話主要寫給後端程式設計師。

不管是想學習新技術還是出於工作需要,都有很多後端程式設計師對前端技術躍躍欲試。但面對前端讓人眼花繚亂的大量候選技術以及未知的概念,他們往往感覺感覺無所適從。如果你是其中的一員,那麼Angular可以“治癒”你的選擇恐懼症。

正如前面所說,Angular是一個“ALL-IN-ONE”的框架,這就意味著你只要掌握了Angular就可以完成大量的前端工作了。

這首先得益於它對各種技術的封裝,讓你不用關心它的實現細節。Angular隔離了瀏覽器的細節,大多數工作你甚至都不需要知道DOM等前端知識就可以完成。

其次,Angular選擇了TypeScript作為主語言。如果你是個C#程式設計師,一定會對它的語法感覺似曾相識。沒錯,TypeScript和C#、Delphi有同一個“爹” —— 傳奇人物Anders Hejlsberg。即使是Java程式設計師,也不會覺得陌生:強型別、類、介面、註解等等,無一不是後端程式設計師們耳熟能詳的概念。說到底,並沒有什麼前端語言和後端語言,在語言領域耕耘多年的Anders太熟悉優秀語言的共性了,他所做的取捨值得你信賴。

再次,Angular在前端實現了服務與依賴注入的概念。隨著前端需求的進一步膨脹,即使只算邏輯程式碼,其需求複雜度也即將甚至已經趕上了大部分後端程式。所以,後端遇到過的挑戰前端也遲早會遇到,這正是後端程式設計師彎道超車的好機會,而依賴注入正是後端程式設計師的看家本領。

最後,Angular對團隊作戰提供了良好的支援,比如模板與程式碼的分離、樣式表的區域性化、元件化的設計、服務與依賴注入體系等。這些特性讓後端程式設計師可以先專注於跟後端程式碼最像的模型和互動邏輯部分,而把諸如樣式、模板等自己不擅長的部分交給隊友。

相關文章