新聞中心
太長不讀版:
Spring + Angular 的全棧式開發(fā),生產(chǎn)力高、入門難度低(此處省略一萬字),是 Java 程序員擴(kuò)展技術(shù)棧的上佳選擇。

成都創(chuàng)新互聯(lián)公司是一家專業(yè)提供福鼎企業(yè)網(wǎng)站建設(shè),專注與網(wǎng)站設(shè)計制作、網(wǎng)站制作、H5場景定制、小程序制作等業(yè)務(wù)。10年已為福鼎眾多企業(yè)、政府機(jī)構(gòu)等服務(wù)。創(chuàng)新互聯(lián)專業(yè)網(wǎng)站設(shè)計公司優(yōu)惠進(jìn)行中。
如果你動心了,接下來就是那省略的一萬字……
痛點 – 團(tuán)隊分工與協(xié)作
在前后端分離的開發(fā)方式中,拆故事卡是個難題。
如果前后端同時工作于一張卡上,但配合不夠默契或節(jié)奏不同步,就會出現(xiàn)一方空轉(zhuǎn)的現(xiàn)象。如果前后端各一張卡,又不容易實現(xiàn)端到端驗收,可能導(dǎo)致先做完的一方在另一個結(jié)束后還要再次返工的現(xiàn)象。而且,兩個人都要深入理解這張卡所描述的業(yè)務(wù)細(xì)節(jié),而這往往是不必要的。
更重要的是,BUG 最容易出現(xiàn)在邊界處。
業(yè)務(wù)卡不像技術(shù)卡那樣能跟其它卡片劃出明確的邊界,前后端之間必然具有千絲萬縷的聯(lián)系。這種聯(lián)系越緊密,出 BUG 的機(jī)會也就越大。
技術(shù)架構(gòu)上的挑戰(zhàn),也會反映到人員架構(gòu)上。我們?nèi)祟惒皇切庆`,無法做到心靈相通。因此前后端開發(fā)者需要對合作方所擁有的知識進(jìn)行很多主觀假設(shè)。
如果這些假設(shè)中存在錯誤,又沒能及時溝通來消除它(甚至可能都意識不到這些假設(shè)的存在),那么 BUGs 就要登場了。而像業(yè)務(wù)卡這種級別的密切協(xié)作中可能隱含的假設(shè)實在太多了,除非經(jīng)過長時間的磨合,否則很難消除,但大多數(shù)項目上可沒有那么多磨合時間。
解決方案 —— 全棧式開發(fā)
人員架構(gòu)
該如何解決呢?克服上述問題的辦法就是全棧式開發(fā)。也就是說,調(diào)整人員架構(gòu)去適應(yīng)技術(shù)架構(gòu)。
簡單來說:每個人都同時寫前端和后端。他不必是前端專家也不必是后端專家,但是兩邊都要會寫。他的關(guān)注點不是技術(shù)知識,而是業(yè)務(wù)知識。他的工作目標(biāo)是貫穿前后端的價值流,對單個故事進(jìn)行端到端交付。
但是,要如何克服實現(xiàn)中遇到的技術(shù)難題以及保障代碼質(zhì)量呢?那就要靠團(tuán)隊中的技術(shù)專家了。
總體來說,全棧式團(tuán)隊的人員架構(gòu)就是大量全棧業(yè)務(wù)工程師 + 少量技術(shù)專家。當(dāng)然,技術(shù)專家不一定要安排單獨(dú)的人擔(dān)任,只要技術(shù)滿足要求,也可以由某位全棧工程師兼任,只是他做計劃時要留出做技術(shù)支持的時間。
通過 Code Review、Pair 等敏捷實踐,技術(shù)專家可以起到團(tuán)隊放大器的作用,讓整個團(tuán)隊的生產(chǎn)力翻倍。
個人工作流
作為全棧工程師,你首先要對一個業(yè)務(wù)故事進(jìn)行建模,包括業(yè)務(wù)模型、視圖模型、領(lǐng)域模型、存儲模型等,建模的過程也就是你理解業(yè)務(wù)的過程。這時候要注意多和 BA、UX、DBA 等溝通,以確保你的理解不存在方向性錯誤,不要太沉迷細(xì)節(jié),防止見木不見林。
單源建模的優(yōu)點是這些模型之間很容易保持一致,這無論是對前期開發(fā)還是對后期維護(hù)都是有幫助的。
建模完畢之后,就要開始設(shè)計前后端之間的接口了。接口是前后端分離式架構(gòu)中最容易開裂的地方,也是對未來的演化影響最大的地方之一。它很重要,但也不必小心翼翼的 —— 全棧工程師對接口變化的適應(yīng)能力要強(qiáng)大得多。因為接口的提供方和消費(fèi)方都是你,信息非常透明,不存在任何額外的假設(shè)。對不完美的接口,你可以在后續(xù)開發(fā)過程中迭代好幾個版本來把它打磨到最理想的形態(tài),改接口將不再沉重和危險。
接口設(shè)計完之后,有兩種路徑,取決于界面和后臺邏輯的特點。
如果對業(yè)務(wù)理解還不是很有信心,那就先用 Mock 的方式把前端寫出來,然后把這個 Mock 版當(dāng)做可執(zhí)行的原型去跟 BA、QA,甚至客戶進(jìn)行實際操作演示,用可操作原型來驗證你對業(yè)務(wù)的理解。對一般粒度的故事卡,線框圖級的可操作原型通常能在半天內(nèi)完成。通過原型盡早發(fā)現(xiàn)錯誤,可以避免以后沉重的返工。而且,這是一個可演化原型,不是一次性原型,不會浪費(fèi)掉。
如果后端很容易實現(xiàn)(但先不必做優(yōu)化工作),那么就可以不必 Mock,先初步完成后端開發(fā),并讓前端直接對接真實的后端。先拿這個比 Mock 版原型更逼真一點的原型串起流程,然后再進(jìn)行優(yōu)化和打磨工作。
在整個過程中,你可以根據(jù)不同的需要,來與不同的技術(shù)專家進(jìn)行 Pair,并且你最終的代碼也會在例行 Code Review 中得到前端專家、后端專家、DBA、DevOps 專家等人的點評和改進(jìn),不必?fù)?dān)心自己在單項技術(shù)上的短板影響交付。
全棧的挑戰(zhàn)
全棧固然美好,但也要迎接很多挑戰(zhàn),而 Angular 會幫你分擔(dān)這些痛苦。
首先遇到的挑戰(zhàn)是語言切換
前后端 JavaScript 全棧固然在特定場景下有效,但是在很多企業(yè)應(yīng)用中是遠(yuǎn)遠(yuǎn)不夠的。至少到目前為止,企業(yè)應(yīng)用還主要是 Java 的天下。本文所討論的也都是 Java + JavaScript 的全棧。
我們都知道,Java 和 JavaScript 之間的差異就像雷鋒和雷峰塔之間的差異。Java 程序員通常很難適應(yīng) JavaScript,不過現(xiàn)在有了更像 Java 的 TypeScript。而 Angular 就是原生基于 TypeScript 的框架,稍后我會做一個摘要講解,你會發(fā)現(xiàn)自己很熟悉它的味道。
(圖片來自: http://t.cn/RobG5nA )
其次是基礎(chǔ)設(shè)施
基于 JRE 的構(gòu)建體系和基于 NodeJS 的構(gòu)建體系看似差異很大,實際上卻有很大程度的相似性。但前端兩年一換代的瘋狂迭代,以及層出不窮的新名詞、新工具,仍然難免會讓后端心生恐懼。不過不用擔(dān)心,Angular 替你封裝了一切,你只需要裝上 NodeJS 環(huán)境和 Angular CLI 就可以了。你不需要關(guān)心它封裝了哪些第三方工具,至于今后的工具鏈怎么瘋狂迭代,那都是 Angular 開發(fā)組需要操心的事。
最后是最佳實踐
前后端從表面上看差異很大 —— 前端輕靈,后端穩(wěn)重。
但在我看來它們很少存在本質(zhì)性的差異,更像是不同的社區(qū)文化導(dǎo)致的結(jié)果。而在更高的層次上看,兩邊的技術(shù)具有很大的相似性。無論是函數(shù)式編程還是工程化開發(fā),都不是某一方所特有的,而是 IT 領(lǐng)域的共同資產(chǎn)。況且,它們還一直在相互影響,相互滲透 —— 這兩年后端變得越來越輕靈,而前端變得越來越工程化。長遠(yuǎn)來看,文化合流是必然的趨勢。
事實上,前后端很多優(yōu)秀設(shè)計和最佳實踐都是殊途同歸的。像 Spring 和 Angular,它們都采用了久經(jīng)考驗的面向?qū)ο蠓妒?;都使用依賴注入技術(shù)進(jìn)行解耦;都擁抱函數(shù)式編程;都提供了豐富的 AOP 支持等。雖然細(xì)節(jié)上各有千秋,但僅從代碼上就能感受到它們之間的相似性。
我該怎么辦?
聽完這些,你是否已經(jīng)蠢蠢欲動?接下來,就跟我開始 Angular 之旅吧。
語言 – TypeScript
Angular 使用 TypeScript 作為主要開發(fā)語言。如果你還不熟悉 TypeScript,那可以把它看做 Java 和 JavaScript 的混合體。TypeScript 是 ES6 的超集,這就意味著,任何有效的 ES6 語法都同樣是有效的 TypeScript 語法。
事實上,從 Java 出發(fā)學(xué) TypeScript,可能比從 ES5/6 學(xué) TypeScript 還要簡單一些。不過,對于 Javaer 來說,學(xué)習(xí) TypeScript 時有一些重要的不同點要特別注意。
TypeScript 的類型只存在于編譯期
TypeScript 的一個首要設(shè)計約束就是要兼容 ES5/6,因此不能隨意增加基礎(chǔ)設(shè)施,而像 Java 這種級別的類型支持在原生 JavaScript 中是根本不存在的。
你可以把 TypeScript 的類型看做僅僅給編譯器和 IDE 用的。因此,在運(yùn)行期間沒有任何額外的類型信息(只有 ES5 固有的那一小部分),像 Java 那樣完善的反射機(jī)制是很難實現(xiàn)的(可以用裝飾器/注解實現(xiàn),但比較繁瑣)。
TypeScript 的裝飾器 vs. Java 的注解
TypeScript 的裝飾器和 Java 的注解在語法上很相似,但其實在語法含義上有著本質(zhì)的區(qū)別。TypeScript 的裝飾器是個函數(shù),而 Java 的注解是個數(shù)據(jù)。語法上,裝飾器名字后面必須帶括號,不能像注解那樣省略。
不過,在 Angular 中,TypeScript 裝飾器的實際用途就是為類或?qū)傩蕴砑幼⒔舛?。因此,有些文章中,包括早期的官方文檔中,用的都是注解的說法。當(dāng)然,以后寫新文章還是都用裝飾器吧。
類與接口
TypeScript 中的類和 ES6 中的類幾乎是一樣的,和 Java 中的類也很相似。
接口則不同,我們前面說過,TypeScript 中的類型信息只存在于編譯期,而接口作為“純粹的”類型信息,也同樣只存在于編譯期。也就是說,在運(yùn)行期間你無法判斷某個對象的類是否實現(xiàn)了某個接口。在 Angular 中,實際上使用的是暴力探測法來判斷的:查找這個接口中規(guī)定的方法(只匹配名稱),如果存在,則認(rèn)為實現(xiàn)了這個接口。
這也意味著,你就算不顯式 implements 接口,但只要聲明了其中的方法,Angular 也會正確的識別它。但這不是一個好習(xí)慣,你應(yīng)該始終顯式 implements 接口,刪除時也要同時刪除接口聲明和對應(yīng)的方法。不過也不用擔(dān)心,Angular 自帶的 lint 工具會幫你檢查是否有忘了顯式 implements 接口,多注意提示就可以了。
接口是給編譯器和 IDE 看的,這很有用。比如,我們可以在 IntelliJ/WebStorm 中聲明某個類實現(xiàn)了一個接口,然后在這個類名上按 alt-enter ,就會出現(xiàn) “Implement interface XXX” 菜單 —— 就像 Java 中一樣。事實上,一些 IDE 對 TypeScript 的支持程度已經(jīng)接近 Java 了:代碼提示、重構(gòu)、類型檢查、簡短寫法提醒等,應(yīng)有盡有。
值得注意的是:你也可以 implement 一個類,而不僅是 extends 它,也就是說類可以在很多場景下代替接口!Angular 風(fēng)格指南提出,“考慮在服務(wù)和可聲明對象(組件、指令和管道)中用類代替接口”。因為運(yùn)行期間接口不存在,所以在 Angular 中不能把接口用作依賴注入的 Token,也就不能像 Java 中那樣要求注入一個接口,并期待框架幫你找出實現(xiàn)了這個接口的可注入對象,但類存在,因此,上述場景下要盡量用抽象類來代替接口。
鴨子類型
為了支持 JavaScript 的動態(tài)性和遺留代碼,TypeScript 的類型匹配要比 Java 寬松不少。比如,如果兩個類(或接口)的屬性和方法(名稱、類型)都完全一致,那么即使它們沒有繼承關(guān)系,也可以相互替代(但如果類有私有屬性,則不能,就算兩者完全一樣也不行)。表面上看這可能過于寬松了,但在實際開發(fā)中還是很有用的,使用中要注意突破 Java 固有思維的限制。
在 TypeScript 中還支持可選屬性( name?: Type ),也就是說如果兩個類的差別僅僅在可選屬性上,那么它們也是可以相互替代的。
字面量與匿名類型
TypeScript 在某些方面可能更符合你對 Java “應(yīng)該是什么樣子”的期待,至少在我看來是這樣。要聲明一個匿名對象、匿名數(shù)組型變量?直接寫出來就好了 const user = {name: 'tom', age: 20} 。除此之外,它還能聲明匿名類型 let user: {name: string, age: number} = ... 。
當(dāng)然,也不能濫用它們。對于一次性使用或暫時一次性使用的變量或類型,用字面量和匿名類型很方便,可讀性也好,但是如果它要使用兩次以上,那就該重構(gòu)成正式的類型了。
any
TypeScript 中的 any 大致相當(dāng)于 Java 中的 Object ,如果你看到通篇 Object 的 Java 代碼你會不會想罵街? any 也一樣。不必完全禁止 any ,但如果你要使用 any ,請務(wù)必先想清楚自己要做什么。
void
如果你在 Java 中經(jīng)常使用 void ,那就遵循同樣的原則用在 TypeScript 中。在 TypeScript 中,當(dāng)你不聲明函數(shù)的返回類型時,它會返回自動推斷的類型(沒有明確的 return value 語句時會推斷為 undefined 類型),如果你不想返回任何值,那么請把返回類型指定為 void 來防止別人誤用。
this
JavaScript 中的 this 是個奇葩。雖然這是函數(shù)式語言中的標(biāo)配,但從語言設(shè)計上真是讓人忍不住吐槽。要是能像 Groovy 那樣分出 this / owner / delegate 就好了。
吐槽歸吐槽,對于 Java 程序員,該怎么避免自己踩坑呢?很簡單:對普通函數(shù),任何涉及到 this 的地方都用箭頭函數(shù) ()=> ,而不要用普通的 function foo() ,因為前者是替你綁定好了符合直覺的 this 的;對方法,不要把任何涉及到 this 的方法當(dāng)作函數(shù)指針傳給別人,但可以在模板中自由使用。在 Angular 中,這兩條原則可以幫你回避掉絕大部分 this 錯誤。更多的細(xì)節(jié)可以先不管,隨著使用經(jīng)驗的增加,你會逐漸弄明白這些規(guī)則的。
其它
以上這些是開發(fā)中常遇到的注意事項,其它的特性我就不一一列舉了,請自行參考 TypeScript 的官方文檔。
范式與模型
MVVM
Angular 的基本編程模型是 MVVM,你可以把它看做 MVC 的一個變種。事實上,這是一個很符合直覺的模型:你看到一個頁面,先在大腦中抽取出它的信息架構(gòu)(屬性)和操作(方法),定義好它們之間的邏輯關(guān)系和處理流程,這就是視圖模型(VM)。你把它們落實到代碼,變成內(nèi)存對象,然后 Angular 就會幫你把它和頁面(View)關(guān)聯(lián)起來。你不懂怎么操作 DOM?沒關(guān)系,你只要會操作內(nèi)存對象就可以了,這應(yīng)該是你非常擅長的吧?剩下的那些臟活兒 Angular 都會幫你搞定。
不過,Angular 關(guān)心的只是“要有” VM,至于你如何生成這個 VM,它并不會做任何假設(shè)和限制。
自由混搭與切換
你想怎么生成 VM?
- 像后端控制器那樣直接寫在組件中?沒問題!
- 像后端那樣委托給服務(wù)?沒問題!
- 像 Redux 那樣委托給單一 Store?沒問題!
- 像 Java 8 Stream 那樣用流水線生成?沒問題!
- 自己幾乎不處理,完全委托給后端 API?沒問題!
這么多方式各有不同的適用場景,但也不必過早擔(dān)心如何選型。只要你的組件設(shè)計合理(職責(zé)分明、接口明確等),那么在這些方式之間切換,或者混用它們,都不會很難。
作為起點,可以先直接寫在組件中,然后按需重構(gòu)成服務(wù),服務(wù)中可以直接寫代碼,也可以實現(xiàn) Redux 風(fēng)格的單一 Store,或者用 RxJS 寫流水線。
RxJS
在 Angular 開發(fā)人員的成長過程中,有一個很重要的坎就是 RxJS,它的背后是 FRP(函數(shù)響應(yīng)式編程)范式。不過對于 Javaer 來說,它的門檻并不高。如果你會用 RxJava / RxGroovy 等 ReactiveX 族的任何一個庫,那么你幾乎可以不用專門再學(xué),它們都是同一個大家族,編程范式甚至部分操作符的名稱都一樣,稍微對比一下差異就可以了。如果不會,請繼續(xù)往下讀(以下的討論也適用于 RxJava 等,不過我文中只用 RxJS 舉例)。
RxJS 是一種 FRP(函數(shù)響應(yīng)式編程)庫,它同時具有函數(shù)式編程和響應(yīng)式編程的優(yōu)點。
如果你會用 Java 8 Stream,那么也有很多知識可以復(fù)用到這里。相對于 Java 8 Stream,RxJS 的限制稍微寬松一些,但我建議你仍然按照 Java 那種嚴(yán)格的方式使用它(比如不要對流外的變量賦值)。
所謂響應(yīng)式編程,我們可以把它想象成一條流水線,流水線上不斷傳送待加工的材料(原料、半成品、成品等),流水線上每個工序的工人負(fù)責(zé)對傳送到眼前的材料進(jìn)行一定的處理(做出響應(yīng)),然后放回流水線,接著它就會被傳送到下一個工序。
設(shè)計上,每個工序的職責(zé)都應(yīng)該是明確而單一的,這樣才能達(dá)到最高的效率和流水線的可定制性。
把這些概念映射到 RxJS,流水線就是 Observable(可觀察對象),工序就是 operator(操作符),材料就是傳給每個 operator 的參數(shù)。
是不是感到很熟悉?沒錯,它跟 MessageQueue 是一樣的模型,只是應(yīng)用在不同的層次而已。在編程領(lǐng)域,這種現(xiàn)象隨處可見,善于發(fā)現(xiàn)并掌握這種現(xiàn)象,是你作為資深程序員能實現(xiàn)快速跨領(lǐng)域?qū)W習(xí)的根本保障。
相對于 Java 8 Stream,RxJS 比較特別的一點是它完全屏蔽了同步和異步之間的差異。也就是說,其中的 operator 不知道也不需要關(guān)心這個數(shù)據(jù)是同步傳過來的還是異步傳過來的。只要你遵循一些顯而易見的原則,你就可以一直用同步方式給數(shù)據(jù),之后即使要突然改成異步,原有的代碼也不會被破壞。
事實上,我在 Angular 開發(fā)中經(jīng)常利用這種特性來加速開發(fā)。比如假設(shè)我最終需要從后端 API 獲取某些信息,在這個 API 開發(fā)好之前,我可以先在前端模擬出響應(yīng)結(jié)果,進(jìn)行后續(xù)開發(fā)。這時候,如果我用 Observable 的方式聲明數(shù)據(jù)源,那么雖然我目前用同步的方式提供數(shù)據(jù),但是將來我可以直接切換成 HTTP 數(shù)據(jù)源,而不用擔(dān)心破壞現(xiàn)有代碼。
細(xì)部原理
宏觀上的要點已經(jīng)講完了,接下來我們快速過一遍微觀的。我只講要點,要想深入細(xì)節(jié)請參閱文中給出的參考資料。
Angular 模塊
Angular 模塊不同于 JavaScript 模塊,它是一個架構(gòu)級的基礎(chǔ)設(shè)施,用來對應(yīng)用進(jìn)行宏觀拆分,硬化邊界,防止意外耦合。
模塊的劃分主要基于業(yè)務(wù)領(lǐng)域的邊界,而在開發(fā)組織形式上,也要和模塊劃分方式相互對齊,盡量讓每個模塊都有明確的負(fù)責(zé)人。
參見 https://angular.cn/guide/ngmodules 。
路由
傳統(tǒng)的路由功能完全是由后端提供的,但是在單頁面應(yīng)用中,在頁面中點擊 URL 時,將會首先被前端程序攔截,如果前端程序能處理這個 URL,那就會直接在前端處理,而不會向后端發(fā)送這個請求。
前端可以根據(jù)這個 URL 修改視圖,給用戶與后端路由一樣的結(jié)果,但省去了網(wǎng)絡(luò)交互的過程,因此會顯得非常快捷。
路由是業(yè)務(wù)功能的天然邊界,善用路由對于改善代碼結(jié)構(gòu)和可維護(hù)性是很有幫助的。
在 Angular 中,路由還同時提供了惰性加載等特性,因此,早期對路由進(jìn)行合理規(guī)劃非常重要。不過也不用過于擔(dān)心,Angular 中重新劃分路由的代價并不高。
參見 https://angular.cn/guide/router#appendix-emlocationstrategyem-and-browser-url-styles 。
模板與視圖
你可以把模板看做 JSP,主要區(qū)別是 JSP 是后端渲染的,每次生成都需要一次網(wǎng)絡(luò)交互,而模板是前端渲染的,在瀏覽器中執(zhí)行模板編譯成的 JS 來改變外觀和響應(yīng)事件。
模板語法
雖然看起來奇怪,但 [prop] 、 (click) 、 *ngFor 等模板語法中的特殊符號都是完全合法的 HTML 屬性名,實際上,屬性名中只禁用各類空白字符、單雙引號等少數(shù)幾個顯而易見的無效字符(正則: [^\t\n\f \/>"'=] )。
參見 https://www.w3.org/TR/2011/WD-html5-20110525/syntax.html#syntax-attribute-name 。
屬性與……屬性
由于歷史原因,英文的 Attribute 和 Property 都被譯為屬性,然而兩者是截然不同的。Angular 中的常規(guī)綁定語法針對的都是 Property,只有 [attr.xxx] 綁定針對的是 Attribute。
參見 https://angular.cn/guide/template-syntax#html-attribute-vs-dom-property 。
組件與指令
你可以把組件看做后端模板中的 taglib,區(qū)別是它們運(yùn)行在瀏覽器中而不是服務(wù)端。組件與指令在用途上的區(qū)別是,組件充當(dāng)搭建界面的磚塊,它的地位和 HTML 元素并無區(qū)別;而指令用于為 HTML 元素(包括組件)添加能力或改變行為。
所以,組件中不應(yīng)該操縱 DOM,只應(yīng)該關(guān)注視圖模型,而指令負(fù)責(zé)在模型和 DOM 之間建立聯(lián)系。指令應(yīng)該是單一職責(zé)的,如果需要完成多個職責(zé),請拆成多個指令附加到同一個元素上。
服務(wù)與依賴注入
Angular 的服務(wù)與依賴注入和 Spring 中的很像,主要的區(qū)別是 Angular 是個樹狀的多級注入體系,注入器樹是和組件樹一一對應(yīng)的,當(dāng)組件要查找特定的服務(wù)時,會從該組件逐級向上查找,直到根部。
這實際上是職責(zé)鏈模式。當(dāng)前組件找不到某個服務(wù)時,就會委托給其父節(jié)點來查找。和策略模式結(jié)合使用,組件就可以通過自己提供一個服務(wù)來替換父組件提供的服務(wù),實現(xiàn)一種支持默認(rèn)處理的邏輯。
參見 https://angular.cn/guide/hierarchical-dependency-injection 。
表單與驗證
在前端程序中,驗證主要是為了用戶友好性,而不是安全。安全是后端的工作,不能因為前端做了驗證而放松。
Angular 對表單提供了非常強(qiáng)力的支持。如果你的應(yīng)用中存在大量表單、大型表單、可復(fù)用表單或交互比較復(fù)雜的表單,那么 Angular 的表單功能可以為你提供強(qiáng)大的助力。
Angular 的表單提供了不同層級的抽象,讓你可以在開發(fā)中輕松分離開顯示、校驗、報錯等不同的關(guān)注點。也讓你可以先用文本框快速搭出一個表單,將來再逐個把這些文本框替換成自定義編輯框,而不會破壞客戶代碼。
參見 https://angular.cn/guide/user-input 。
測試
Angular 對測試的支持非常全面,可以實現(xiàn)各個不同層次的測試。
但是不要因為拿到把這么好用的錘子就滿世界敲。要根據(jù)不同的價值需求去決定測什么不測什么。
別忘了每個 Angular 的類,無論服務(wù)、組件、指令還是管道等,都是 POJO,你可以用測 POJO 的方式測試它們,得到毫秒級反饋,而且這往往會更高效。
參見 https://angular.cn/guide/testing 。但要記?。弘m然 Angular 支持這么多種方式,但你不一定要用到這么多種方式。
安全
在 Angular 中,你不會無意間造成安全隱患。只要注意一點就夠了: DomSanitizer.bypassSecurityTrust* 要慎用,務(wù)必確保傳給它的東西不可能被攻擊者定制,必要時請找安全專家推演。參見 https://angular.cn/guide/security#sanitization-and-security-contexts。
如果你在發(fā)起 POST 等請求時收到了 403 錯誤,那可能是因為后端開啟了 CSRF 防護(hù)。Angular 內(nèi)置了一個約定 —— 如果服務(wù)端 csrf token 的cookie名是 XSRF-TOKEN ,并且能識別一個名叫 X-XSRF-TOKEN 的請求頭,那么它就會自動幫你完成 CSRF 驗證。當(dāng)然,你也可以自定義這些名稱來適配后端,參見 https://angular.cn/guide/http#configuring-custom-cookieheader-names 。
跨域與反向代理
本地開發(fā)時,前端有自己的服務(wù)器,顯然無法與后端 API 服務(wù)器運(yùn)行在同一個端口上,這樣就導(dǎo)致了跨域問題。要解決跨域問題,主要有 CORS 和反向代理這兩種方式。CORS 是標(biāo)準(zhǔn)化的,但是受瀏覽器兼容性的影響較大;而反向代理則通過把 API “拉”到前端的同一個域下,從根本上消除了跨域訪問。
開發(fā)時,Angular CLI 內(nèi)置了對反向代理的支持;部署時,各個主流 Web 服務(wù)器都能很好地支持反向代理。
一般項目中建議還是優(yōu)先使用反向代理的方式。
(圖片來自: http://t.cn/RgsWKEJ )
雜談
你不必寫 CSS
很多后端初學(xué)前端時會被卡在 CSS 上,在心里喊一句 WTF。但實際上,在團(tuán)隊開發(fā)中,你可能根本不必寫 CSS。
現(xiàn)在已經(jīng)有了很多現(xiàn)成的 CSS 庫,比如已經(jīng)熟透的 Bootstrap,還有后起之秀 Material Design、Ant Design 等等。你只要能根據(jù)其表達(dá)的視覺含義,正確套用它們定義的 CSS 類就夠了。盡量不要自己手寫 CSS,否則可能反倒會給將來的頁面美化工作帶來困擾。
選好了基礎(chǔ)框架,并且和 UX 對齊之后,團(tuán)隊中只需要一個 CSS 高手就能實現(xiàn)所有的全局性設(shè)計規(guī)則。對于全棧工程師來說,充其量只有對當(dāng)前頁面中的少量元素進(jìn)行定制時才需要寫 CSS,況且還可以通過找人 pair 來解決偶爾碰到的難題。
全棧,讓設(shè)計更簡單
前后端技術(shù)各有所長,有些事情用前端實現(xiàn)更簡單,有些用后端實現(xiàn)更簡單。綜合考量前端技術(shù)和后端技術(shù),往往可以產(chǎn)生更簡單、更優(yōu)秀的設(shè)計。廣度在業(yè)務(wù)開發(fā)中往往比深度有用,這也是全棧工程師的優(yōu)勢所在。而團(tuán)隊中的技術(shù)專家主要負(fù)責(zé)深度。
分工是動態(tài)的
技術(shù)專家或全棧工程師,并不是什么榮譽(yù)頭銜,只是分工不同而已。
同一個項目上你可以同時擔(dān)任全棧工程師和技術(shù)專家;這個項目你是全棧工程師,下一個項目上也可能專門擔(dān)任技術(shù)專家。團(tuán)隊的協(xié)作方式永遠(yuǎn)是動態(tài)的、隨需應(yīng)變的。
不用擔(dān)心全棧會限制你的技術(shù)深度,實際上,全棧對提高你的技術(shù)深度是有幫助的,因為很多技術(shù)的“根”都是互通的。
相信你的直覺
資深后端首先是一個資深程序員,你對于“應(yīng)該如何”的期待,很可能是對的。如果你覺得 Angular 應(yīng)該有某項功能或某種設(shè)計,它很可能確實有。去 Stackoverflow 搜一下,找找你的答案,這是你成為高級 Angular 程序員的捷徑。
萬法歸一
形容某人聰明時經(jīng)常說“萬法皆通”,實際上“萬法皆通”不如“一法通而萬法通”。很多技術(shù)之間的相似程度超出你的想象,這些相似的部分其實就是技術(shù)的核心。用萬法歸一的思路去學(xué)習(xí)總結(jié),會給你帶來真正的提高。
資料 & 學(xué)習(xí)指南
學(xué)習(xí) Angular 的最佳資料是它的官方文檔,它無論是從準(zhǔn)確、全面,還是及時性等方面都是最佳的。
它的英文文檔站是 https://angular.io ,中文文檔站是 https://angular.cn ,這是由我和另外兩位社區(qū)志愿者共同翻譯的,期間還得到了很多社區(qū)志愿者的支持。中文文檔和英文文檔至少在每個大版本都會進(jìn)行一次同步翻譯。雖然時間有限導(dǎo)致語言上還有粗糙之處,不過你可以相信它的技術(shù)準(zhǔn)確度是沒問題的。
閱讀時,請先閱讀架構(gòu)概覽 https://angular.cn/guide/architecture ,然后閱讀教程 https://angular.cn/tutorial (有經(jīng)驗的程序員不需要跟著敲代碼,如果時間緊也可跳過),最后閱讀風(fēng)格指南 https://angular.cn/guide/styleguide 。風(fēng)格指南很重要,不用記住,但務(wù)必通讀一遍,有點印象供將來查閱即可。
文檔站中還提供了 API 參考手冊,它提供了簡單快速的站內(nèi)搜索功能,需要了解哪些細(xì)節(jié)時到里面查就可以了。
另外,ng-zorro 組件庫的一位開發(fā)者還整理了一份不完全指南,包括中英文資料: https://zhuanlan.zhihu.com/p/36385830 。
新聞名稱:【推薦】給Java程序員的Angular快速指南
本文地址:http://m.5511xx.com/article/cciosoj.html


咨詢
建站咨詢
