文章出處

這篇是我參加QCon北京2014的演講內容:

提綱:

企業應用在軟件行業中占有很大的比重,而這類軟件多數現在也都采用B/S的模式開發,在這個日新月異的時代,它們的前端開發技術找到了什么改進點呢?

B/S企業軟件前端開發模式大體上與桌面軟件類似,都是偏重量級的,在前端可能會有較多的業務邏輯,這些業務邏輯如何被合理模塊化,與界面分離,以便測試,成為這個領域的一個重要挑戰。另一方面,由于企業應用的界面相對規整,偏重的是數據存取,沒有太多花哨的東西,所以常見的界面控件也是可枚舉的,如何讓開發界面的工作能更快完成,甚至由不擅長編寫代碼的業務設計人員來做,與界面原型的工作合二為一,能提高不少開發效率。

在AngularJS等MV*框架出現之后,給這個領域帶來一些契機,架構師們能夠有機會去重新規劃前端的架構,甚至是開發流程,從而讓整個軟件的生產更為高效。

本文將探討它給這個領域帶來的變化。

正文:

企業應用前端的特點

企業應用系統是一種很常見的軟件系統,這類系統的特點是面向某個行業,功能較復雜,對界面的要求一般是整齊,不追求花哨。這類系統通常有C/S和B/S兩個流派,其中的B/S方式因為部署和集成的便利,使用得較為普遍。

同樣是在瀏覽器中做東西,寫企業應用和網站的差別也很明顯。企業應用的業務邏輯較重,前端有一定的厚重性,但是對效果并不追求很多,主要是各類控件的使用,表單的存取值等等。

企業應用產品的一些特點如下:

  • 獨占模式。

一般用戶使用互聯網產品,都是片段時間使用,比如購物或者閱讀,做完之后就刷新或者關閉瀏覽器了,而企業應用往往是工作的全部,從早上上班開始打開,到下班才關掉,一天絕大部分工作都在上面完成,比如一個呼叫中心的操作員。

  • 重業務,輕視覺

企業應用對視覺的追求是比較低的,一般不會要求花哨效果,以業務操作的流暢性為第一目標。

  • 界面規整,模式單一

企業應用的界面布局相對有模式可循,可以用很少的場景來窮舉,界面橫平豎直,比較規整,使用到的控件元素也是可窮舉的,基本沒有什么特效。

  • 鍵盤操作

由于企業應用的用戶都相對比較專業,在上崗之前需要經過統一培訓,而且每個用戶使用的頻度較高,很多時候他們會用盡量快捷的方式來做操作,比如鍵盤,這一點在互聯網產品中比較少見。所以,有時候大家為了追求好看,把系統原生的select用div來替換,在這種情況下反而增加了用戶的麻煩。

  • 邏輯復雜

我之前所在的行業中,業務邏輯很復雜,前端可能會需要寫很多復雜的邏輯,JS代碼大部分是在處理邏輯,而不是界面交互。

  • 加載速度的側重不同

互聯網產品往往很重視首屏優化,但是其策略可能與企業應用不同。比如說,3個200k的模塊,在網站型產品中可能優化成一個100k加三個150k的模塊,但在企業應用中,很可能優化成一個400k加三個50k的模塊。為什么會這樣呢?因為內容型的網站講究的優化策略是分攤,如果首次加載太慢,會很影響用戶的信心,但企業應用用戶的容忍度是較高的,他并不在乎剛打開的時候慢一些,因為打開了之后就要用一天,對于之后每步操作的模塊加載速度倒是要求很高。另外,對于內存泄露的處理,也要求得比較高一些。整個這些策略,其實是來源于C/S系統的影響。

  • 瀏覽器版本相對寬松

很多時候提到企業應用,大家的想法就是低端,IE6,但其實這個的原因是客戶只購買軟件,運維一般自己做,每年不會有很多持續的投入來改進,所以導致很多老系統不能持續升級。軟件廠商其實反倒可以用更激進的策略去升級瀏覽器,用戶對這個的接受度還是比較高的,使用系統的群體也是比互聯網用戶小很多的,拋棄老舊瀏覽器的事情也確實可以干,比如我就見過幾年前某電信營業系統預裝的都是Firefox。

企業應用常見的前端框架

在開發B/S企業應用前端的人群中,有很大一部分群體選擇了服務端的組件化方式,比如JSF之類,它的弊端是與異構服務端的第三方系統集成比較麻煩。也有不少人使用Bindows和ExtJS這樣的框架,最近的KendoUI也是個不錯的選擇。

每種類型選一個有代表性的來說說:

  • HTC 在瀏覽器端擴展標簽

早期有些團隊采用的方式,一般會跟XMLHTTP等結合使用,易于使用,界面代碼整潔,但已被主流瀏覽器拋棄。

  • JSF等 在服務端生成界面

以后端為主的架構師最推崇的方式,受Struts的MVC模型影響很深,弱化了前端,使得前端蛻化為后端的一種附屬。

  • GWT 編譯階段生成界面

寫其他語言來生成HTML和JS,一般會依賴于一種前端UI庫。這種方式也比較受后端架構師喜歡,因為他們覺得寫JS很頭疼,寧可寫Java。

  • ExtJS 用JS封裝界面組件,干脆就不要HTML了

這是另外一種極端,從Bindows開始,使用純邏輯代碼來描述界面,走著跟Java Swing一樣的道路,也有不少人喜歡。但這種方式在沒有好用的界面設計器的情況下非常痛苦。

  • Flex等 脫離HTML體系,另辟蹊徑

這條路其實是對Java Applet的一種延續,好處是可以不受HTML體系的制約,獨立發展,所以其實這些體系在企業應用領域的成熟度遠超HTML體系。

曾經的企業B/S應用幾件寶

有一段時間,我們幾乎只有IE6,所以那個時候的前端開發人員很快樂,沒有兼容的壓力。那時候,我們如何構建前端應用呢?

參見http://weibo.com/1858846672/B1fL3vuYN?mod=weibotime

  • HTC

這是最好用的聲明控件的方式。

  • XMLHTTP

盡管還沒有AJAX的概念,但我們已經可以用它做前后端分離的傳輸機制了。

  • VML

在IE里面畫矢量圖,不使用插件,有其他選擇嗎?

  • XSLT

把XML數據轉換成HTML,跟現在的前端模板像嗎?

  • popup

創建右鍵菜單最好的方式。

用這些技術構建的一個典型企業應用

單頁應用和前端分層

當時這些系統的構建方式也可以算單頁應用,我們用iframe來集成菜單,每個菜單有自己獨立的功能,整個主界面是始終不會刷新的。

時光飛逝,這些年,前端有了什么本質的改變,產生了翻天覆地的變化嗎?

有時候我們回顧一下,卻發現多數都是在增加完善一些細節,真正有顛覆性的有比如以RequireJS和SeaJS為代表的模塊定義和加載庫,npm這樣的包管理器,grunt,gulp,百度fis這樣的集成開發模式。為什么它們算是本質改進呢?

因為這些標志著前端開發從粗放的模式,逐漸變化到精確控制的形態。比如我們再也不能不管代碼的依賴關系,也不能一打開界面就不分青紅皂白把所有可能要用到的代碼都立刻加載過來,那個時代已經過去了,從任何角度講,現代的前端開發都在精細化,從代碼的可控,到界面體驗的精細優化,到整個團隊甚至公司甚至互聯網上的組件共享,以及前端團隊協作流程的改進,這已經是一個很成規模的產業了。

我們把眼光放到2013年,在這一年里最火的前端技術莫過于NodeJS和AngularJS,前者給我們帶來的是一種開發方式的改變,后者是一種典型的前端分層方案。Angular是前端MV*框架的一個流派,用過的人都會覺得很爽。它爽在什么地方呢?因為它幫我們做的事情太多了,一個雙向綁定,無所不包,凡是存取值相關的操作,基本都不用自己寫代碼。在企業應用前端功能里,表單的存取值和校驗占據了很大的比例,這些事都不用干了,那簡直太好了。

如果就因為這個用Angular,那還有些早。有一些第三方代碼被稱為庫,另外一些稱為框架,Angular是框架而不是庫。框架的含義是,有更強的約束性,并非作為輔助功能來提供的。

先看一下企業應用的通常形態吧,會有一個可配置的菜單,然后多半會采用MDI的形式,能打開多個業務功能,用選項卡的形式展示起來,可以隨時切換操作。每個人每天常用的功能是可以窮舉的,他進入系統之后,一般要用到下班才關掉。所以這種系統非常適合做成單頁應用,開始的時候加載一個總體框架,每點擊一個菜單,就加載這個菜單對應的功能模塊,放在一個新的選項卡或者別的什么地方展示出來。

在早期做這種系統的時候,一般都會用iframe來集成菜單,這種方式很方便,但是每個菜單頁都要載入共同的框架文件,初始化一個環境,數據之間也不能精確共用。

所以現在我們做企業信息系統,不再適合用iframe來集成菜單,所有菜單的業務代碼,會在同一個頁面的作用域中共存。這在某些方面是便利,比如數據的共享,一個選擇全國城市的下拉框,在多個功能中都存在,意味著這些城市的數據我們可以只加載一次。但從另外一個角度來說,也是一種挑戰,因為數據之間產生干擾的可能性大大增加了。

我們回顧一下在傳統的客戶端開發中是怎么做的,早在經典的《設計模式》一書中,就提到了MVC模式,這是一種典型的分層模式。長期以來,在Web開發人員心中的MVC,指的都是Struts框架的那張圖,但我們單頁應用中的MVC,其實更接近最原始的《設計模式》書中概念。所以我們要在前端分層,而不僅僅把整個前端都推到視圖層。

做單頁應用,前端不分層是很難辦的,當規模擴大的時候,很難處理其中一些隱患。分層更重要的好處是能夠從全盤考慮一些東西,比如說數據的共享。跨模塊的數據共享是一個比較復雜的話題,搞得不好就會導致不一致的情況,如果考慮到在分層的情況下,把各種數據來源都統一維護,就好辦多了。

所以,以AngularJS為代表的前端MV*框架最重要的工作就是做了這些對于分層的指導和約束性工作,在此基礎上,我們可以進一步優化單頁應用這類產品。

前端的自定義標簽體系

構建一個大型企業應用,最重要的是建立整套組件體系。一般針對某行業的軟件,長期下來都會有很多固定的模式,可以提煉成組件和規則,從前端來看,體現為控件庫和前端邏輯。控件庫這個是老生常談,在很多框架里都有這個概念,但各自對應的機制是不同的。

從寫一個界面的角度來講,最為便利的方式是基于標簽的聲明式代碼,比如我們常見的HTML,還有微軟的XAML,Flex中的MXML等,都很直接,設想一下在沒有可視化IDE的情況用類似Java Swing和微軟WinForm這樣的方式編寫界面,毫無疑問寫XML的方式更易被接受。所以,我們可以得出初步的結論,界面的部分應該寫標簽。

很遺憾,HTML自帶的標簽是不足的,它有基本表單輸入控件,但是缺乏DataGrid,Tree之類更富有表現性的控件。所以絕大多數界面庫,都采用某種使用JavaScript的方式來編寫這類控件,比如:

<div id="tabs">
  <ul>
    <li><a href="#tabs-1">Nunc tincidunt</a></li>
    <li><a href="#tabs-2">Proin dolor</a></li>
    <li><a href="#tabs-3">Aenean lacinia</a></li>
  </ul>
  <div id="tabs-1">
  </div>
  <div id="tabs-2">
  </div>
  <div id="tabs-3">
  </div>
</div>
$(function() {
    $( "#tabs" ).tabs();
});

如果這樣,這些復雜控件就都要通過JavaScript來創建和渲染了,這與我們剛才提到的原則是違背的。那我們尋找的是什么呢,是一種能擴展已有HTML體系的東西。在早期,IE瀏覽器中有HTC,可以通過引入命名空間來聲明組件,現在的標準瀏覽器中又引入了Web Components,在Polymer這個框架中可以看到更多的細節。說到底,這類方式要做些什么事情呢?

  • 隔離組件的實現,讓使用變得簡單
  • 支持自行擴展新的組件
  • 作一些作用域上的隔離,比如Web Components里面,style標簽上可以加作用域,表示這個樣式只生效于組件內部

從另外一個角度講,為什么我們非要這么做不可?最大好處來自哪里?對于大型項目而言,管理成本和變更成本都是需要認真考慮的。如果一個組件,需要在DOM中聲明一個節點, 然后再用一個js去獲取DOM,把DOM渲染出來,再填充數據的話,這個過程的管理成本是很大的,因為HTML和JS這兩個部分丟了一個都會有問題,無論在什么時候,維護一個文件總是比維護多個文件要強的,我們看HTC那種方式,為什么它的使用成本很低,因為它可以把控件自身的DOM、邏輯、樣式全部寫在自己內部,整個一個文件被人引用就可以了。在現在這個階段不存在這么好用的技術了,只能退而求其次。

所以,在這個點上,Angular帶來的好處是可擴展的標簽體系,這也就是標簽的語義化。Angular的主打功能之一是指令,使用這種方式,可以很容易擴展標簽或者屬性。比如,業務開發人員可以直接寫:

<panel>
     <tree data="{{data}}"></tree>
</panel>

這樣多么直觀,而且可以跟原有的HTML代碼一起編寫,不造成任何負擔。語義化的標簽是快速編寫界面的不二法門。

業務邏輯

有了語義化標簽之后,如果我們只寫界面不寫邏輯,那也夠了,但現實往往沒有這么美好,我們還要來考慮一下業務邏輯怎么辦。

企業應用一般都是面向某行業的,在這個行業內部,會有一些約定俗成的業務模型和流程,這些東西如何復用,一直是一個難題。以往的做法,會把這些東西都放在服務端,用類似Java這樣的語言來實現業務元素、業務規則和業務流程的管理。

這種做法所帶來的一個缺點就是對界面層的忽視,因為他只把界面層當作展示,對其中可能出現的大量JavaScript邏輯感到無所適從。很多從事這一領域的架構師不認同界面層的厚度,他們認為這一層只應當是很薄的,純展示相關的,但在這個時代,已經不存在真正輕量級的界面了。

前面提到,我們在前端作分層,把展現層跟業務邏輯層完全隔離,帶來的好處就是邏輯層不存在對DOM的操作,只有純粹的邏輯和遠程調用,這么一來,這一層的東西都可以很容易做測試。對于一個大型產品來說,持續集成是很有必要的,自動化測試是持續集成中不可缺少的一環。如果不做分層,這個測試可能就比較難做,現在我們能把容易的先做掉,而且純邏輯的代碼,還可以用更快的方式來測試。

之前我們做前端的單元測試,都需要把代碼加載到瀏覽器來執行,或者自行封裝一些“無頭瀏覽器”,也就是不打開實際的展示,模擬這個測試過程。這個過程相對來說還是有些慢,因為它還有加載的這個網絡傳輸的過程,如果我們能在服務端做這個事情呢?

我們看到,最近很火的NodeJS,它從很多方面給了前端工程師一個機會,去更多地把控整個開發流程,在我們這個場景下,如果能把針對前端邏輯的單元測試都放在node里做,那效率就會更高。

二次開發平臺

我們來看看,有了這么一套分層機制,又有了界面標簽庫之后,該做些什么呢?

做企業軟件的公司,有不少會做二次開發平臺,這個平臺的目標是整合一些已有的行業組件,讓業務開發人員甚至是不懂技術的業務人員通過簡單的拖拉、配置的形式,組合生成新的業務功能。

從界面的角度看,拖拽生成很容易,很多界面原型工具都可以做,但要如何整合數據和業務?因為你要生成的這個功能,是實實在在要拿去用,不是有個樣子看就可以,所以要能跟真實數據結合起來。 但這事情談何容易!

就比如說,界面上有一個選擇所屬行業的下拉框,里面數據是配置出來的,對這個數據的查詢操作在后端,作為一個查詢服務或者是業務對象管理起來,有些傳統的方式可能是在后端作這個關聯,Angular框架可以把這個事情推到前端來。相比Backbone這樣的框架來說,Angular由于有雙向綁定,這個過程會變得特別省事。一個界面片段想要和數據關聯起來,要做的事情就是各種屬性的設置,所以動態加載和動態綁定都會比較容易。

比如:

partial.html

<ul>
     <li ng-repeat="item in items">{{item.name}}</li>
</ul>

main.html

...
<div ng-include="'partial.html'" ng-controller="CtrlA"></div>
...

a.js

function CtrlA($scope) {
    $scope.items = [{name:"Tom"}, {name:"Jerry"}];
}

b.js

function CtrlB($scope) {
    $scope.items = [{name:"Donald"}, {name:"Micky"}];
}

在上面的例子里,這個列表顯示什么,完全取決于ng-controller="CtrlA"這句,如果我們把這句搞成配置的,就很容易把數據源換成另外一個CtrlB,甚至說,即使在同一版本上做項目化,引入另外一個包含CtrlA其他版本的js文件,也基本無需更改其他代碼,這就達到了二次開發的一個目的:盡可能以配置而不是編碼去新增、維護新功能。

移動開發

現在的企業軟件已經不能只考慮PC的瀏覽器了,很多客戶都會有移動辦公的需求。響應式設計是一種常見的解決方案,但是在企業應用領域,想要把復雜的業務功能設計成響應式界面的代價太大了,況且界面設計本身就是開發企業軟件的這些公司的短板,所以我們的比較簡單的辦法是對PC和移動終端單獨設計界面,這樣就有了一個問題了,這兩種界面的業務邏輯并沒有差別,如果我們要維護兩套代碼,代價是非常大的,能有什么辦法共用一些東西呢?

如果不采用分層的形式,那這個很麻煩,我們注意到兩種系統的差異只在UI層,如果我們用分層的模式,可以共用UI層以外的東西。具體到Angular里面來說,比如service,factory,甚至controller都是可以共用的,只有directive和HTML模板隨設備產生差異就可以了。

之前我們很少看到有基于Angular的移動端開發框架,但現在有了,比如Ionic,使用這樣的框架,可以直接引用已有的業務邏輯代碼,只在展示上作一些調整。這么做有很多好處,同時也對代碼的架構水準有一定要求,需要把業務邏輯跟界面展示完全切割開。

這樣帶來的好處也是很明顯的,獨立的業務邏輯,因為它不依賴于界面了,所以很容易控制,做單元測試,集成測試,打樁等等,總之它是純邏輯的東西,在后端可以用什么方式保證代碼質量,在前端的業務邏輯也一樣可以用,業務邏輯可以因此而清晰穩定。

對于企業應用而言,這么做可以極大程度地復用以往的業務邏輯,只在負責最終展示的代碼部分作差異化。

工程化

上面這些技術性的問題都解決了,剩下的都是規模帶來的邊際效應,這需要我們從工程化角度去考慮很多問題:

  • 某個JS模塊被修改,如何得知會影響誰?
  • 某個界面片段被調整,會影響什么界面?
  • 如何最小化發布?
  • 如何一鍵測試、打包、壓縮?
  • 。。。。。。

這些話題,篇幅所限,不在本文中敘述,可以查看我另外的關于Web應用組件化的文章。

 

原文地址: 基于AngularJS的企業軟件前端架構


文章列表




Avast logo

Avast 防毒軟體已檢查此封電子郵件的病毒。
www.avast.com


arrow
arrow
    全站熱搜
    創作者介紹
    創作者 大師兄 的頭像
    大師兄

    IT工程師數位筆記本

    大師兄 發表在 痞客邦 留言(0) 人氣()