1. 程式人生 > 其它 >【轉】前端開發與後臺開發如何協作?

【轉】前端開發與後臺開發如何協作?

作者:小豬
連結:https://www.zhihu.com/question/27226086/answer/35811288
來源:知乎
著作權歸作者所有。商業轉載請聯絡作者獲得授權,非商業轉載請註明出處。

首先,

@learnshare 給出的兩種開發模式基本上就是我們所有的選擇了,後端提供api,完全前端渲染的開發模式如果可行的話,angular或者react都是不錯的選擇。但如果網站業務決定了必須seo友好而必須進行服務端渲染的話,如同 @learnshare 所述,現有的開發模式下,前端和後端人員的協作是很困難的。下面我來談談我對這個困境的看法以及我們正在實踐的一個非常棒的模型(最近我在好幾個問題下面都回答了類似的內容,會不會被當成spam。。。)。

首先,服務端渲染的前後端分離之所以困難,根本的原因不在於模板技術的複雜性上,而在於MVC模式本身是有問題的。本質上講,MVC是面向業務過程的,對於企業應用開發,MVC模式的確是無上利器,可以清晰的分離業務邏輯層次,讓程式設計師將精力集中在業務邏輯的整合上(其實,我覺得即使對於這一點,傳統的MVC模式也沒有做得足夠好,這裡重點不討論MVC,就不展開了,有興趣的可以看看這個:Asta4D Framework User Guide,算是我對傳統MVC模式的一些思考),但是,MVC模式本身的重點在於M和C,而V只是一個附屬品,一個用來展現業務流程的視覺化介面而已,因此,通常對前端工作的要求是很低的,能夠展示資料,能夠將業務流程向前推進,這就足夠了。

回過頭來,對於重點是展示內容並幫助使用者獲得有效資訊為主的網際網路網站來說,MVC本身就是不合時宜的,常見的例子就是,比如淘寶的首頁,model是什麼?再進一步的,淘寶的寶貝頁面,也許可以把當前寶貝作為model,問題是,邊欄之類的周邊資訊怎麼整合到這個model中去?當然,不是做不到,但就此帶來的複雜性,實際上已經宣告了MVC的軟弱。

我上知乎的時間不太長,很奇怪在知乎沒有看到過任何討論view first模式的帖子,這個模式是由lift(Lift :: Home)最先提出並實踐的,可以說,view first模式從根本上解決了內容展示型的網站的MVC困境,可以極大的提高開發效率。

(說到這裡,還沒有說到前後端如何分離。。。我都有點著急了。。。)

view first的基本理念來說,就是檢視,view,才是整個系統的第一優先物件,所有的程式碼結構,所有的邏輯,都要圍繞view來展開,傳統的MVC模型,一個url,要先對映到一個controller,然後controller構建model,最後導向一個view,但在view first下,一個url,就對應一個view,服務端接受到request,view就開始渲染了,在渲染過程中,不斷的取得需要的資料,並完成整個頁面,這個過程中不需要controller來控制,也就更不需要model來溝通controller和view,一切都是以檢視為基礎進行的。說到這裡,其實很多人應該已經明白過來了,這不就是傳統的PHP開發模式嘛,先寫html,然後把php的動態程式碼嵌進去,OK,搞定啦,是快呀,可這程式碼沒法維護呀,前後端也沒法分離呀。。。別急,快了。。。

可以說,view first這個模型,其實就是傳統的php開發模式,lift的貢獻在於,首先明確並命名了這樣一個開發模式,從理論上解決了開發效率的問題並且將開發人員從MVC的迷思中解放出來,然後,lift更重要的貢獻是,從實踐上解決了view first模式下程式碼不可維護與前後端分離的問題,提供了一個前後端完全分離的模板模型。這裡多說兩句,lift本身是基於scala的,我們公司在用了兩年lift之後鑑於對scala的種種不爽,決定還是退回到java上,雖然lift本身也支援用java進行開發,但我們覺得一個pure java的方案會更舒服,而且lift本身也有一些細節我們覺得是有改進必要的,因此我們開發了自己的框架Asta4D(astamuse/asta4d · GitHub),雖然我們提供了很多不同於lift的功能,但單就view first和前後端分離的模板來說,基本上是一個95%拷貝加5%改良的lift,下面我就用我們自己的框架來舉例,相信java程式碼大家看起來也會更舒服一點。

首先,無論是lift,還是我們的山寨Asta4D,前端工程師面對的都是pure html的模板,如下:

<section>
    <article>
        <div>
            <p id="name">name:<span>dummy name</span></p>
            <p id="age">age:<span>0</span></p>
    </article>
</section>

前端工程師可以自由的填入stub資料來除錯他們想要的效果或者互動邏輯,在他們完成工作後,這個模板交給後端工程師的時候,後端工程師會在模板中嵌入一點程式碼:

<section>
    <article afd:render="SomeSnippet:showProfile">
        <p id="name">name:<span>dummy name</span></p>
        <p id="age">age:<span>0</span></p>
    </article>
</section>


好吧,這個時候想像一下,前端工程師發現了一點bug需要進一步修正,我們可以相信的一點是,在99%的情況下,後端工程師加入的那一行“afd:render”的程式碼應該不會給前端工程師造成干擾,因此,這個時候,我們的前端和後端就已經可以開始同時工作了,先把前端的工作放在一邊,看看後端怎麼填入真實資料:

 public Renderer showProfile() {
        Renderer render = Renderer.create();
        render.add("p#name span", "asta4d");
        render.add("p#age span", 20);
        return render;
    }

後端用css selector來標定資料錨點並將真實資料填入,因此,在最簡單的情況下,只要資料錨點不變,無論前端工程師如何重構模板程式碼,都不再需要後端工程師的介入了。當然,這裡有一個顯而易見的問題,前端工程的重構並不能保證資料錨點不變,因此,我們在實踐中,引入了一個所謂的“X約定”,簡單的講,我們的後端工程師會在模板中再多加一點東西:

<section>
    <article>
        <div afd:render="SomeSnippet:showProfile">
            <p id="name">name:<span class="x-name">dummy name</span></p>
            <p id="age">age:<span class="x-age">0</span></p>
    </article>
</section>

大家可以注意到,後端工程師在資料錨點上加入了以x開頭的偽類,這樣,後端的渲染程式碼就變成下面這個樣子:

 public Renderer showProfile() {
        Renderer render = Renderer.create();
        render.add(".x-name", "asta4d");
        render.add(".x-age", 20);
        return render;
    }

仍然是用css selector,只不過不再用tag而是用class來錨定資料,我們可以看到,class中加入的“x-”一方面不會對前端工程師的工作造成任何干擾,另一方面也起到hint的作用,前端工程師只要能夠將“x-”標記的資料錨點保持不變就可以放心大膽的重構程式碼而不需要後端工程師的介入。

在我們的實踐中,一般的開發流程是前端先完成頁面,然後後端接手填入資料,這個中間通常不會進行交流,因為我們的前端和後端甚至是分開在兩個部門的,大家的互動就是redmine的ticket的轉交而已。當然,在某些時候,後端工程師無法理解前端的模板不知道應該將資料填在哪兒的時候,還是會有必要的交流,但這種交流真的很少發生,至少不需要他們非得坐在一起工作:)

更進一步的,某些時間很緊的開發任務,前後端甚至是同時開始工作的,後端會開一個debug頁面,在裡面只用div和x-來標記資料錨點並完成後端的渲染邏輯,而同時前端會完成正式的html頁面程式碼,最後,由後端將渲染邏輯合併到正式頁面即可。當然,這種情況下,前後端的交流會多一些,我們的前端mm擺脫後端猥瑣大叔們糾纏的辦法就是儘可能快的先完成基本的html骨架push上去,然後告訴他們,你們自己玩去吧,別來煩我了^_^

更為具體的一個我們的實踐的例子是,一個耗費前端兩個人月的頁面大規模重新設計和重構,在前端完成工作後30分鐘,我們的後端就完成了所有必要的修改並將程式碼合併到主幹準備進入release流程了。嗯,因為我們能做到這個,所以我們的前端和後端就一直是兩個部門沒人提合併的事情。

最後,題外話,最近react.js突然吸引了很多人的目光,對於客戶端渲染真的是非常不錯的東西,而我們的框架Asta4D,同樣的提供了服務端渲染下的虛擬DOM元件模型。哦,這裡就不贅述了,有興趣的可以自己去看我們的user guide。

大家看幾個我們的頁面吧

Detailed information of toushiba corp.

Publication number 225663) a nonvolatile memory device

Technology and business trends of Glass melting and manufacturing

我們的網站其實是日文的,這個英文網站是做給華爾街的大爺們看的一個簡裝版,相對內容要簡單些,但大家仍然可以看到,我們在前後端完全分離的模式下可以做得很漂亮。


============感謝

@賀師俊 的評論,評論回覆裡面沒法回答太多,我把回覆貼到這裡=====
賀師俊
你的 showProfile 其實就是變相的 model,x-name 和 x-age 就是 model 的屬性。

這取決於你如何定義model。

從簡單的ORMAP的角度來說,我們必然有一個entity,對我們的這個架構來說,這個entity是一定存在的,從這個角度上說,這裡的確有一個model,就是ormap中的entity。

但是從MVC模式的model來說,MVC的model並不是簡單的entity,而是一個包含了所有前端必須資料的container,從這個意義上講,我們沒有model。

最後,我上面的回答跟你指出的事實,其實有點不搭界,你的意思是,render的方法本身就是一個邏輯上的model,而x-就是model的屬性,老實說,這個觀點真的很有趣。

你指出的事實讓我陷入了長考,這裡究竟有沒有model,從邏輯上講,你是對的,我思考了很長時間,這種邏輯上的model跟MVC的model的區別是什麼?

我的理解是,首先,我們不需要在程式碼中構建一個大雜燴的資料容器,而是在一個極小的範圍類定義了一個區域性適用的小資料結構,從這一點說,跟傳統MVC比起來,我們做到了更細粒度的解耦。其次,從實現的角度講,我們鼓勵開發人員儘可能簡單的取得資料,我們近乎變態的儘可能的執行以一行為單位的無join查詢(效能依靠快取保證, ),這絕對比傳統的MVC模式的開發效率和可維護性都高得多。進一步的,我在原文中已經強調過了,這裡的“x-”約定,只是一個hint,對前端沒有任何強制的約束能力,前端不會因為破壞了這個約定而導致頁面崩潰出錯,反過來,前端在有必要的時候可以完全無視這個約定,資料的整合是由後端完成的,但頁面的邏輯,是前端主導的,開玩笑的說,“x-”約定是我們後端人員對前端大爺的哀求:“大爺啊,不要亂搞我好嗎。。。”。

所以,我們對前後端分離的開發模式的理解是,最重要的一點是,前端具有主導權,由前端決定開發的走向而不是後端,後端的職責是滿足並提供前端需要的資料,反過來,前端沒有義務和必要為了後端的各種技術上的理由而去學習或者說匯入各種跟前端無關的技術(有任何前端開發人員會喜歡velocity之流的模板的嗎?),前端需要最大限度的自由度去完成創造性的工作,後端的職責是配合他們。進一步的,後端的技術意義在於,以更合理的後臺架構,更方便,快捷的提供前端需要的資料,在這個層次上,我們需要快取的設計,需要合理的api設計,需要後臺儲存架構的各種變化,但是,在最終向前端提供資料這一個邏輯層次上,後端可以比前端開發人員寫出更有效率的利用現有API取得必要資料的邏輯,但後端不可能比前端知道如何更有效率的將資料展現給使用者,因此,我們對view這一層的分工的理解就是,前端負責資料如何展現,後端負責取得資料並提供給前端。

最後,無論那種模式,最終總有一個標記資料位置的引數,或者是MVC中model的屬性,或者是我們這裡的css selector hint,或者是一個嵌入的變數名,從這個意義上講, 任何模式都有個model,都有個屬性,所以,即便我很同意你說的邏輯上showProfile就是個model,但我仍然認為,我們從本質上是anti-MVC的。

Austin Liu 劉恆輝
Lzhdim Group's Chairman,Project Manager and Software Designer
E-Mail:[email protected]
Blog: http://lzhdim.cnblogs.com

歡迎收藏和轉載此部落格中的博文,但是請註明出處,給作者一個與大家交流的空間。謝謝大家。