學(xué)生團(tuán)隊(duì)的前后端分離及持續(xù)交付探索歷程

原文鏈接: http://www.luckyjing.com/posts/front-end/arch-explore.html

回顧大學(xué)四年,在學(xué)院課程大作業(yè)范圍內(nèi)的項(xiàng)目沐兰,并沒(méi)有一次印象深刻的團(tuán)隊(duì)開(kāi)發(fā)經(jīng)歷哆档,往往都是三兩程序員一聚,便草草開(kāi)始了僧鲁。在阿里云實(shí)習(xí)的幾個(gè)月里,相比代碼本身象泵,學(xué)到的最多的便是人力資源的合理利用寞秃,工具的效率輔助,年已至末偶惠,最后一次大作業(yè)春寿,將自己在實(shí)習(xí)過(guò)程中積累的經(jīng)驗(yàn)運(yùn)用起來(lái),指定合理規(guī)范的項(xiàng)目開(kāi)發(fā)流程忽孽,平穩(wěn)地推進(jìn)項(xiàng)目的開(kāi)發(fā)绑改,不會(huì)讓項(xiàng)目邊界越來(lái)越大以至于收不住邊界,特地做此記錄分享給大家兄一。

背景

項(xiàng)目背景

本次的項(xiàng)目是一個(gè)在線購(gòu)物商城系統(tǒng)溺欧,這個(gè)詞相信大家已經(jīng)耳熟能詳了樱哼,具體細(xì)節(jié)不必多說(shuō),分為三個(gè)子系統(tǒng)Customer,Owner,Administrator,需要將項(xiàng)目分為三個(gè)階段弃理,Release1,2,3,采用原型開(kāi)發(fā)模式咪奖,每個(gè)版本給出一個(gè)可供交付的產(chǎn)品辅鲸,總結(jié)來(lái)說(shuō),項(xiàng)目性質(zhì)為無(wú)復(fù)雜功能點(diǎn)展箱,但業(yè)務(wù)量繁多旨枯。

成員介紹

團(tuán)隊(duì)成員共有20人,其中開(kāi)發(fā)同學(xué)共10位混驰,前端同學(xué)4位攀隔,后端同學(xué)6位。首先進(jìn)行技術(shù)調(diào)研栖榨,和在公司不同竞慢,在公司大家技術(shù)棧其實(shí)差不多,在學(xué)校則不是治泥,最終得出結(jié)果筹煮,前端熟悉React同學(xué)1位,其余3位熟悉jQuery居夹,后端同學(xué)全部熟悉SSH框架败潦,為保證后端的統(tǒng)一本冲,后端技術(shù)棧不作調(diào)整,但前端因考慮到自動(dòng)化構(gòu)建的工具的接入劫扒, 以及用jQuery前期成本小檬洞,后期成本大,難以維護(hù)的現(xiàn)狀沟饥,故全部采用React技術(shù)棧添怔,并對(duì)不熟悉的同學(xué)進(jìn)行一次集體培訓(xùn)以及后續(xù)答疑解惑。

前期準(zhǔn)備

三個(gè)子系統(tǒng)之間其實(shí)前端關(guān)聯(lián)度不大贤旷,可以認(rèn)為是三個(gè)獨(dú)立的系統(tǒng)广料,對(duì)于前端而言,React全家桶搭建起來(lái)并不容易幼驶,涉及到代碼目錄的規(guī)定艾杏,Webpack的配置等等,故前端由我做出基層的腳手架盅藻,實(shí)現(xiàn)業(yè)務(wù)同學(xué)可以直接寫業(yè)務(wù)购桑,無(wú)需關(guān)系構(gòu)件流程的目的,對(duì)于后端而言氏淑,不同數(shù)據(jù)之間是共享的勃蜘,故由一名主力后端同學(xué)負(fù)責(zé)數(shù)據(jù)庫(kù)的設(shè)計(jì)與構(gòu)建,并且搭建好基礎(chǔ)后端目錄假残,其他同學(xué)在此基礎(chǔ)上進(jìn)行業(yè)務(wù)層面的開(kāi)發(fā)元旬。

項(xiàng)目構(gòu)建歷程

基礎(chǔ)結(jié)構(gòu)預(yù)覽

在看過(guò)上面這個(gè)圖以后,項(xiàng)目的整個(gè)輪廓已經(jīng)清晰守问,為了實(shí)現(xiàn)以上架構(gòu)匀归,我們需要定一些小小目標(biāo):

  1. 前后端采用分離模式開(kāi)發(fā),通過(guò)一份提前給出的API文檔進(jìn)行協(xié)商耗帕,數(shù)據(jù)則通過(guò)以json作為基礎(chǔ)格式的接口進(jìn)行交互穆端。
  2. 打造一個(gè)Mock服務(wù)器,實(shí)現(xiàn)API文檔已給出仿便,但后端接口還沒(méi)有寫好的時(shí)候体啰,前端通過(guò)模擬接口可以透明地請(qǐng)求接口了。(注:透明的意思即Mock服務(wù)器可以攔截前端的所有請(qǐng)求嗽仪,達(dá)到和真實(shí)線上服務(wù)調(diào)用接口一樣的效果)
  3. 動(dòng)靜資源分離荒勇,我們只有一臺(tái)服務(wù)器,是很實(shí)惠阿里云學(xué)生機(jī)闻坚,所以前后端數(shù)據(jù)都要放在這臺(tái)機(jī)器上沽翔,前端靜態(tài)資源存儲(chǔ)在nginx服務(wù)器下,后端服務(wù)放在tomcat/webapps目錄下,因?yàn)闉閱雾?yè)應(yīng)用仅偎,后端只需要在那份index.html里引入前端靜態(tài)資源就可以了(直接寫入絕對(duì)路徑)跨蟹,最終訪問(wèn)的時(shí)候,服務(wù)器能夠辨別是請(qǐng)求靜態(tài)資源還是后端服務(wù)器橘沥,也就是俗稱的動(dòng)靜分離窗轩。
  4. 快速部署,部署的時(shí)候如何輕松,快捷座咆,避免配置各種環(huán)境痢艺,要配也是一個(gè)人配,不能讓開(kāi)發(fā)同學(xué)苦惱介陶。

下面我們來(lái)一步步實(shí)現(xiàn)堤舒。

前端

簡(jiǎn)述

  1. 前后端分離開(kāi)發(fā),所以路由要放到前端斤蔓,用React-Router植酥。
  2. 前端要自動(dòng)化構(gòu)建镀岛,用Webpack弦牡。
  3. React+Redux配置其實(shí)挺麻煩的,如果能寫好模板漂羊,然后自動(dòng)生成就好了驾锰,用redux-cli
  4. mock2easy作為mock服務(wù)器走越。

基礎(chǔ)目錄結(jié)構(gòu)

在項(xiàng)目開(kāi)發(fā)前椭豫,我提前將項(xiàng)目的腳手架提前搭建好,項(xiàng)目的大概目錄如下所示:

├── README.md  
├── blueprints  # 這就是上述第三點(diǎn)的模板旨指,大家可以去github上搜 redux-cli  
├── build # 構(gòu)建后的文件  
├── dev.js # 類似webpack-dev-server 加入了mock的服務(wù)  
├── package.json  
├── src  
└── webpack.config.js  

自動(dòng)化構(gòu)建命令

使用Webpack提前寫好配置文件赏酥,不管webpack.config.js里有多少步驟,最終呈現(xiàn)出來(lái)的只有build目錄下那幾個(gè)打包好的文件谆构,將相關(guān)命令寫到package.json中裸扶,前端同學(xué)只需執(zhí)行一個(gè)命令就可以啟動(dòng)服務(wù)了。

  "scripts": {
    "dev": "node dev.js",
    "pub": "NODE_ENV=production webpack && git add . && git commit -m':grin:發(fā)布新功能' && git push origin master"
}

mock服務(wù)

mock服務(wù)器什么原理搬素,一張圖給大家展示一下呵晨。

解釋一下,webpack-dev-server簡(jiǎn)單點(diǎn)就是一個(gè)express的服務(wù)器熬尺,那么如果我們直接用它的話摸屠,直接訪問(wèn)/ajax/test.json肯定是跑不起來(lái)的,因?yàn)檫@個(gè)接口404啊粱哼,所以我們要想實(shí)現(xiàn)如下目標(biāo):既能擁有webpack-dev-server獨(dú)特的熱刷新功能季二,還可以當(dāng)請(qǐng)求后綴為xxx.json的時(shí)候,去請(qǐng)求一個(gè)mock服務(wù)器去拿數(shù)據(jù)然后返回揭措,我們這個(gè)mock服務(wù)使用的是mock2easy戒傻,大家可以去GitHub上搜搜看税手,一切皆透明,于是我們的dev.js配置如下所示:

// 先實(shí)現(xiàn)一個(gè)webpack-dev-server
var app = connect();
var compiler = webpack(config);
app.use(require("webpack-dev-middleware")(compiler, config.devServer));
app.use(require("webpack-hot-middleware")(compiler));
// 核心代碼 之 mock服務(wù)就是一個(gè)中間件
app.use(function(req,res,next){
    if (req.url.indexOf('.json') == -1) {
      return next();
    }
    // 發(fā)現(xiàn)是接口請(qǐng)求需纳,然后去請(qǐng)求mock服務(wù)器芦倒,然后把數(shù)據(jù)返回
    var _req = http.request(options, function (_res) {
      var data = '';
      _res.on('data', function (chunk) {
        data += chunk;
      });
      _res.on('end', function () {
        res.setHeader('Content-Type', 'application/json; charset=utf-8');
        res.end(data);
      });
    });
});
app.listen(config.devServer.port, function () {
  console.log('開(kāi)發(fā)環(huán)境已經(jīng)啟動(dòng): http://127.0.0.1:' + port);
});
// 啟動(dòng)mock服務(wù)器
require('mock2easynew')(options, function (app) {
  app.listen(options.port, function () {
    console.log('mock服務(wù)器已經(jīng)啟動(dòng),地址:http://localhost:' + options.port);
  });
});

優(yōu)化

  • 開(kāi)發(fā)時(shí)不翩,React,Redux就不用被抽離出來(lái)了兵扬,當(dāng)然代碼也不用壓縮了,一切以快為主口蝠。
  • 發(fā)布時(shí)器钟,將React,Redux這些庫(kù)抽離出來(lái),這樣打包出來(lái)文件會(huì)小妙蔗,庫(kù)文件我們可以用免費(fèi)的CDN進(jìn)行引入傲霸。
<script src="http://cdn.bootcss.com/react/15.4.0/react.min.js"></script>
<script src="http://cdn.bootcss.com/react/15.4.0/react-dom.min.js"></script>
<script src="http://cdn.bootcss.com/redux/3.6.0/redux.min.js"></script>

實(shí)現(xiàn)以上優(yōu)化,我們需要在我們的webpack.config.js中加入如下邏輯眉反,即需要擁有區(qū)分開(kāi)發(fā)環(huán)境的能力昙啄。

//  區(qū)別環(huán)境
var debug = process.env.NODE_ENV !== 'production';
// 第三方資源
var externals = {
  "react": 'React',
  "react-dom": "ReactDOM",
  'redux': 'Redux'
};
var config = {
  externals: debug ? {} : externals,
}

經(jīng)過(guò)以上步驟之后,我們的前端開(kāi)發(fā)環(huán)境已經(jīng)搭建好了寸五,開(kāi)發(fā)同學(xué)只要先去填寫一些mock的API梳凛,然后就可以在前端直接訪問(wèn)到了,所以剩下的只需要和后端進(jìn)行約定下接口名稱就可以了梳杏。

# step1
前后端約定API名稱為:/ajax/profile.json
# step2
前端(假設(shè)是3005端口)在mock服務(wù)器(假設(shè)是8005端口)添加這個(gè)接口 && 后端正常工作...
# step3
訪問(wèn)localhost:3005/ajax/profile.json 成功拿到數(shù)據(jù)
# step4
前端代碼里直接書寫 $.ajax('/ajax/profile.json') 即可

后端簡(jiǎn)介

  1. 后端基本上盡可能也要自動(dòng)化韧拒,快捷化,所以使用maven去進(jìn)行項(xiàng)目的構(gòu)建十性,達(dá)到擁有一份源代碼便可四處運(yùn)行的目的叛溢。
  2. 使用postman讓后端同學(xué)進(jìn)行接口的測(cè)試。

服務(wù)器部署實(shí)戰(zhàn)

到目前為止劲适,前后端同學(xué)都可以在各自本地進(jìn)行業(yè)務(wù)開(kāi)發(fā)了楷掉,而且相互不耦合,以一份API文檔為準(zhǔn)便可以開(kāi)發(fā)减响,接下來(lái)要討論的就是構(gòu)建的事情了靖诗,我們要達(dá)到的目的是:前端打包好后的靜態(tài)資源可以自動(dòng)部署到服務(wù)器上,后端代碼推到倉(cāng)庫(kù)后支示,會(huì)自動(dòng)進(jìn)行maven構(gòu)建刊橘,打war包,并自動(dòng)上傳到服務(wù)器上颂鸿,重啟tomcat服務(wù)器促绵。

為了實(shí)現(xiàn)以上目的,項(xiàng)目采用阿里云code進(jìn)行代碼管理,與此同時(shí)败晴,使用阿里云CRP服務(wù)實(shí)現(xiàn)上述持續(xù)化浓冒,描述如下:

  1. CRP服務(wù)檢測(cè)指定的遠(yuǎn)程倉(cāng)庫(kù)master分支是否有更新
  2. 如果有更新,則執(zhí)行一段腳本(由用戶輸入尖坤,往往為一些構(gòu)建命令)
  3. 用戶指定需要上傳的文件(往往是第二步驟的產(chǎn)出)
  4. 用戶指定需要上傳到的服務(wù)器以及路徑
  5. 用戶指定上傳結(jié)束后需要執(zhí)行的一段腳本(往往為一些部署前的命令稳懒,比如移動(dòng)靜態(tài)資源到指定目錄,或關(guān)閉tomcat慢味,解壓縮包场梆,重啟tomcat)

還需要對(duì)nginx做一下簡(jiǎn)單配置,實(shí)現(xiàn)動(dòng)靜分離纯路。

# 由nginx處理靜態(tài)頁(yè)面
location ~ .*\.(gif|jpg|png|bmp|swf)$
{
  expires 30d;   #使用expires緩存模塊或油,緩存到客戶端30天
}
location ~ .*\.(html|jsp|js|css)?$
{
  expires 1d;
}
# 其余請(qǐng)求全部轉(zhuǎn)到tomcat
location ~ .*$ {
  proxy_pass http://127.0.0.1:8080;
}

我們集成后的效果如下,當(dāng)集成完畢后驰唬,可以通知測(cè)試同學(xué)進(jìn)行及時(shí)測(cè)試顶岸,提前暴露出問(wèn)題,保證項(xiàng)目的穩(wěn)步前進(jìn)叫编。

總結(jié)

全程構(gòu)建系統(tǒng)的過(guò)程中辖佣,一直遵循的守則是自動(dòng)化越高越好(redux-cli,maven,持續(xù)交付),細(xì)節(jié)屏蔽的越高越好(執(zhí)行命令寫到package.json里)宵溅,將部署步驟和開(kāi)發(fā)步驟相互隔離凌简,開(kāi)發(fā)同學(xué)只需要專注業(yè)務(wù)的開(kāi)發(fā)即可上炎,這樣便可以三個(gè)子系統(tǒng)同時(shí)前進(jìn)恃逻,開(kāi)發(fā)同學(xué)可以有更多的時(shí)間去考慮代碼本身的質(zhì)量。

能夠讓我們放心去構(gòu)建整個(gè)系統(tǒng)的基礎(chǔ)藕施,屏蔽底層的不同寇损,多虧了在背后運(yùn)行的Docker服務(wù),本次項(xiàng)目中的嘗鮮體驗(yàn)已經(jīng)感受到了好處裳食,將Docker納入項(xiàng)目的部署環(huán)境矛市,往往會(huì)帶來(lái)驚喜。

路還長(zhǎng)诲祸,保持新鮮感浊吏,不斷去構(gòu)造更加完善的自動(dòng)化系統(tǒng)。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末救氯,一起剝皮案震驚了整個(gè)濱河市找田,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌着憨,老刑警劉巖墩衙,帶你破解...
    沈念sama閱讀 221,888評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡漆改,警方通過(guò)查閱死者的電腦和手機(jī)心铃,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,677評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)挫剑,“玉大人去扣,你說(shuō)我怎么就攤上這事》疲” “怎么了厅篓?”我有些...
    開(kāi)封第一講書人閱讀 168,386評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)捶码。 經(jīng)常有香客問(wèn)我羽氮,道長(zhǎng),這世上最難降的妖魔是什么惫恼? 我笑而不...
    開(kāi)封第一講書人閱讀 59,726評(píng)論 1 297
  • 正文 為了忘掉前任档押,我火速辦了婚禮,結(jié)果婚禮上祈纯,老公的妹妹穿的比我還像新娘令宿。我一直安慰自己,他們只是感情好腕窥,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,729評(píng)論 6 397
  • 文/花漫 我一把揭開(kāi)白布粒没。 她就那樣靜靜地躺著,像睡著了一般簇爆。 火紅的嫁衣襯著肌膚如雪癞松。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 52,337評(píng)論 1 310
  • 那天入蛆,我揣著相機(jī)與錄音响蓉,去河邊找鬼。 笑死哨毁,一個(gè)胖子當(dāng)著我的面吹牛枫甲,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播扼褪,決...
    沈念sama閱讀 40,902評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼想幻,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了话浇?” 一聲冷哼從身側(cè)響起脏毯,我...
    開(kāi)封第一講書人閱讀 39,807評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎凳枝,沒(méi)想到半個(gè)月后抄沮,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體跋核,經(jīng)...
    沈念sama閱讀 46,349評(píng)論 1 318
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,439評(píng)論 3 340
  • 正文 我和宋清朗相戀三年叛买,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了砂代。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,567評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡率挣,死狀恐怖刻伊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情椒功,我是刑警寧澤捶箱,帶...
    沈念sama閱讀 36,242評(píng)論 5 350
  • 正文 年R本政府宣布,位于F島的核電站动漾,受9級(jí)特大地震影響丁屎,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜旱眯,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,933評(píng)論 3 334
  • 文/蒙蒙 一晨川、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧删豺,春花似錦共虑、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 32,420評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至蓬蝶,卻和暖如春尘分,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背疾党。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 33,531評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工音诫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留惨奕,地道東北人雪位。 一個(gè)月前我還...
    沈念sama閱讀 48,995評(píng)論 3 377
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像梨撞,于是被迫代替她去往敵國(guó)和親雹洗。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,585評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容