此文寫于 1 年前拧略,轉(zhuǎn)載至此,大家可以加 Scott 微信: codingdream瘪弓, 成為朋友圈的朋友垫蛆,聊南聊北,哈哈哈
生鮮 B2B 技術(shù)平臺(tái)的前端團(tuán)隊(duì)該如何搭建
線下越重腺怯,線上需要越輕袱饭,這個(gè)輕指的是輕便輕巧和簡(jiǎn)潔易用,通過前面幾章小菜技術(shù)與產(chǎn)品歷史介紹呛占,我們了解到 B2B 生鮮領(lǐng)域在線下是如此之重虑乖,那么在交易場(chǎng)景線上化的過程中,端的移動(dòng)化就勢(shì)在必行晾虑,試想一下疹味,讓菜市場(chǎng)攤位老板人手一臺(tái)筆記本點(diǎn)開網(wǎng)頁(yè)選購(gòu)支付仅叫,讓采購(gòu)銷售抱著電腦去拜訪客戶,一邊聊蔬菜行情佛猛,一邊打開筆記本進(jìn)行記錄惑芭,有沒有一種回到世紀(jì)初的感覺。
產(chǎn)品的移動(dòng)化继找,這將是我們展開這篇文章的背景遂跟,我們會(huì)先了解小菜的產(chǎn)品托管在哪些端上,然后感受這些端帶來(lái)的挑戰(zhàn)婴渡,最后是我們面對(duì)這些挑戰(zhàn)所采取的策略幻锁,以及整個(gè)小菜前端團(tuán)隊(duì)歷練后的技術(shù)成長(zhǎng)和沉淀,和我們對(duì)于自己的一個(gè)評(píng)估和對(duì)未來(lái)的展望边臼,本文將采用最通俗易懂的方式陳述哄尔,會(huì)略有繁瑣,但力求對(duì)技術(shù)新人也足夠友好柠并。
<a name="gf4drc"></a>
一岭接、小菜大前端的端有哪些
小菜早期圍繞著蔬菜銷地以客戶集單批發(fā)的模式摸爬滾打幾年,從上游的蔬菜供應(yīng)商到下游批發(fā)市場(chǎng)的攤位老板臼予,在這個(gè)長(zhǎng)長(zhǎng)的鏈路中鸣戴,我們誕生了這樣幾款線上產(chǎn)品來(lái)服務(wù)于不同的人群和場(chǎng)景,之前文章中也有介紹粘拾,這里再匯總一下窄锅,共 7 款 App:
宋小菜 服務(wù)于銷地批發(fā)老板的下單工具
宋小福 服務(wù)于小菜內(nèi)部銷售團(tuán)隊(duì)的 CRM 銷售管理與客戶管理工具
宋小倉(cāng) 連接司機(jī)-物流-采購(gòu)-銷售的蔬菜在途位置監(jiān)控工具
采秘 服務(wù)于小菜內(nèi)部采購(gòu)團(tuán)隊(duì)的蔬菜品類采購(gòu)工具
麥大蔬 服務(wù)于上游蔬菜供應(yīng)商的大宗農(nóng)產(chǎn)品交易平臺(tái)
宋大倉(cāng) 服務(wù)于上游囤貨配資的進(jìn)出庫(kù)管理平臺(tái)
行情寶 服務(wù)于產(chǎn)銷兩地的行情采集和預(yù)測(cè)工具
前 6 款 App 都是基于 ReactNative 開發(fā)的 iOS/Android App,最后一個(gè)是微信小程序缰雇,它們涵蓋了公司幾乎所有的協(xié)同場(chǎng)景和工作流入偷,其他涉及審核、數(shù)據(jù)觀測(cè)和過程管理的部分械哟,則會(huì)進(jìn)入到我們 PC 端產(chǎn)品中疏之,也就是:
- ERP 后臺(tái)管理系統(tǒng)
生鮮的 toB 場(chǎng)景,角色眾多暇咆,鏈路冗長(zhǎng)锋爪,這種延伸到產(chǎn)地農(nóng)民,延伸到小 B 交易的管理系統(tǒng)一定會(huì)角色雜糯崎,權(quán)限多,操作重河泳,業(yè)務(wù)復(fù)雜度所帶來(lái)的頁(yè)面復(fù)雜度不是一般的小系統(tǒng)可比擬沃呢。
到目前為止,我們已經(jīng)看到小菜的 7 個(gè)移動(dòng)端 App拆挥,以及一個(gè)復(fù)雜的后臺(tái)管理系統(tǒng)薄霜,這些都跟前端工程師息息相關(guān)某抓,除了這些,還有 2 個(gè)重要的內(nèi)部產(chǎn)品惰瓜,就是:
大表哥 數(shù)據(jù)報(bào)表系統(tǒng)
大瓜子 市調(diào)模板配置系統(tǒng)
其中大表哥(諧音:搭 Excel 表格)由前端工程師獨(dú)立研發(fā)和維護(hù)的數(shù)據(jù)報(bào)表系統(tǒng)否副,單拎出來(lái)這個(gè)系統(tǒng),是因?yàn)樵?B2B 公司崎坊,尤其涉及到供應(yīng)鏈的長(zhǎng)鏈路場(chǎng)景中备禀,真實(shí)業(yè)務(wù)數(shù)據(jù)的及時(shí)反饋對(duì)于每一個(gè)執(zhí)行團(tuán)隊(duì)都至關(guān)重要,沒有這些數(shù)據(jù)抓手奈揍,就失去了多維度數(shù)據(jù)觀測(cè)曲尸,都很難快速的做出正確的運(yùn)營(yíng)決策和業(yè)務(wù)調(diào)整,甚至很難發(fā)現(xiàn)業(yè)務(wù)中出現(xiàn)的漏洞和問題男翰,比如不正常的非自助下單(也就是銷售幫忙下單)的比例另患。
關(guān)于報(bào)表系統(tǒng)后文還有介紹,我們?cè)贋榍岸嗽黾右粋€(gè)服務(wù)的產(chǎn)品場(chǎng)景蛾绎,就是微信生態(tài)內(nèi)產(chǎn)品昆箕,比如公眾號(hào)或者小程序,它的技術(shù)棧和運(yùn)行環(huán)境跟原生 App 和 PC 都不同租冠,雖然小程序可以帶來(lái)更多的業(yè)務(wù)可能性鹏倘,也會(huì)對(duì)前端帶來(lái)更大的挑戰(zhàn)。
我們把這些端合并一下肺稀,小菜前端要服務(wù)的端或場(chǎng)景:
移動(dòng)端(iOS/Android App/小程序)
PC 端(ERP)
工具端(大表哥數(shù)據(jù)報(bào)表)
端上全部開花第股,這也應(yīng)了我之前在掘金 JTalk 上小菜對(duì)于長(zhǎng)鏈路流通交易分享的一個(gè)觀點(diǎn):鏈路足夠長(zhǎng),每個(gè)節(jié)點(diǎn)上都可以長(zhǎng)出產(chǎn)品话原。那這些端產(chǎn)品都是與業(yè)務(wù)有強(qiáng)關(guān)聯(lián)的夕吻,還有更多技術(shù)基建的和服務(wù)于團(tuán)隊(duì)內(nèi)的產(chǎn)品,比如:
大伯伯(諧音打包包) 實(shí)現(xiàn) App 選倉(cāng)庫(kù)選分支選環(huán)境配置的自主打包與推包系統(tǒng)
大表姐(來(lái)自饑餓游戲繁仁,寓意開工沒有回頭箭) 實(shí)現(xiàn) 6 款 App 解包差分后下發(fā)熱更新包的發(fā)布系統(tǒng)
姑奶奶 線上異常匯集分析與與 Bug 定級(jí)指派系統(tǒng)
大舅子 向下調(diào)用微服務(wù)接口向上提供 GraphQL 查詢能力的數(shù)據(jù)聚合服務(wù)
RGB 用戶使用 App 的 PV/UV涉馅,以及業(yè)務(wù)數(shù)據(jù)監(jiān)控相關(guān)的可視化平臺(tái)
110 解決端異常收集與報(bào)警需求
堂哥工作臺(tái) 團(tuán)隊(duì)記錄資源分配與 redmine 同步的自動(dòng)化周報(bào)系統(tǒng)
ITms 解決內(nèi)部 App 安裝測(cè)試的配置生成和預(yù)裝服務(wù)
...
這些是服務(wù)于團(tuán)隊(duì)內(nèi)部的工具鏈,全部由小菜前端自行維護(hù)黄虱。到這里我們發(fā)現(xiàn)稚矿,在小菜這樣一家創(chuàng)業(yè)公司內(nèi),前端要服務(wù)的端和場(chǎng)景的確較多捻浦,但這些產(chǎn)品和工具的背后晤揣,整個(gè)前端組也就 10 個(gè)人而已(我們當(dāng)然也求才若渴),但是人雖少朱灿,效率不能自我妥協(xié)昧识,所以我們能服務(wù)到這些端,也正是基于端的多樣性和數(shù)量盗扒,我們稱自己:宋小菜大前端跪楞。
先上小菜端上若干產(chǎn)品和工具的技術(shù)棧圖缀去,幫助大家理解我們的技術(shù)理念:
[圖片上傳失敗...(image-f88477-1555230920414)]
<a name="27bira"></a>
二、多端帶來(lái)的挑戰(zhàn)
<a name="hgf1mu"></a>
1. 【物理現(xiàn)狀】移動(dòng)端的碎片化
古典互聯(lián)網(wǎng)時(shí)代甸祭,因?yàn)橐嫒?IE678 而痛苦不堪缕碎,Hack 黑魔法經(jīng)驗(yàn)基本代表前端水平,如今互聯(lián)網(wǎng)早已移動(dòng)化池户,我們理想中的移動(dòng)端開發(fā)咏雌,看上去是可以大膽使用新語(yǔ)法特性,只需要做好尺寸兼容就好了煞檩,但事實(shí)并非如此处嫌,不僅在移動(dòng)端的瀏覽器不是如此,在移動(dòng)端開發(fā) RN App 也是如此斟湃,這是我們某一款 App 一段時(shí)間內(nèi)熏迹,所收集上來(lái)的手機(jī)廠商分布:
[圖片上傳失敗...(image-dcf641-1555230920415)]
可以發(fā)現(xiàn) Android 的碎片化非常嚴(yán)重,每一個(gè)廠商下面有不同時(shí)期推出的不同型號(hào)的手機(jī)凝赛,這些手機(jī)有著不同版本的操作系統(tǒng)注暗,不同的分辨率和用電策略,不同的后臺(tái)進(jìn)程管理方式和用戶權(quán)限墓猎,要讓一款 App 在哪怕頭部 40% 的手機(jī)上兼容捆昏,都是一件艱難的事情,這個(gè)客觀物理現(xiàn)狀疊加下面的社區(qū)現(xiàn)狀毙沾,App 質(zhì)量保證這件事情會(huì)變得雪上加霜骗卜。
<a name="25lllt"></a>
2. 【社區(qū)現(xiàn)狀】技術(shù)框架的不穩(wěn)定性
回到本文的開頭,我們?cè)陂L(zhǎng)鏈路的 B2B 生鮮場(chǎng)景中左胞,為了更快更輕寇仓,開發(fā)出 7 款 App,而且將來(lái)隨著業(yè)務(wù)場(chǎng)景的拓展會(huì)誕生更多獨(dú)立 App 甚至是集大成的 App烤宙,所以技術(shù)選型不太可能選擇原生的 Java/Object-C 開發(fā)遍烦,尤其對(duì)于創(chuàng)業(yè)公司,6 款 App 得需要多少名原生開發(fā)工程師才能搞定躺枕,高頻繁重的業(yè)務(wù)變化又怎樣靠堆人來(lái)保證服猪?
想清楚這些,一開始我們就調(diào)研 ReactNative拐云,并最終全部從原生切換到了 RN罢猪,通過跑過來(lái)的這 3 年來(lái)看,使用 RN 為公司節(jié)約了大量的人力成本同時(shí)叉瘩,也盡可能的滿足到幾乎所有的需要快速迭代的業(yè)務(wù)場(chǎng)景膳帕,又快又輕,成為宋小菜大前端團(tuán)隊(duì)做事的一個(gè)典型特征房揭。
但換一個(gè)角度看备闲,就是帶來(lái)的問題,又快又輕的背后是 RN 版本的飛速迭代捅暴,截止到目前恬砂,也就是 2018 年 6 月份,RN 還沒有推出一個(gè)官方的正式的長(zhǎng)期維護(hù)的穩(wěn)定版本蓬痒,什么意思泻骤?就是 RN 目前依然處在不穩(wěn)定的研發(fā)周期內(nèi),我們依然站在刀尖起舞梧奢,用不穩(wěn)定的 RN 版本試圖開發(fā)穩(wěn)定的應(yīng)用狱掂,三年走過來(lái),我們?cè)?RN 的框架里亲轨,多少次面對(duì)舊版本局限性和新版本不穩(wěn)定性都進(jìn)退不得趋惨,舊版本的 Bug 可能會(huì)在新版本中修復(fù),新版本引進(jìn)則會(huì)來(lái)新版本自己的問題惦蚊。
除了 RN 自身版本器虾,還有第二個(gè)問題,圍繞著 RN 有很多業(yè)界優(yōu)秀的組件蹦锋,但這些社區(qū)組件甚至官方組件兆沙,都不一定能及時(shí)跟進(jìn)最新的 RN 版本,同時(shí)還能兼容到較老的 RN 版本莉掂,所以 RN 升級(jí)導(dǎo)致的組件不兼容性葛圃,會(huì)引發(fā)你 Fork 修改組件的沖動(dòng),但這樣會(huì)帶來(lái)額外的開發(fā)成本和版本維護(hù)成本憎妙,取舍會(huì)成為版本升降的終極問題库正。
在國(guó)內(nèi)開發(fā),還有第三個(gè)問題尚氛,就是中文文檔缺乏诀诊,社區(qū)資源匱乏,參考文獻(xiàn)陳舊阅嘶,可拿來(lái)主義的開源工程方案甚至社區(qū)線上線下會(huì)議分享都很缺乏属瓣,一個(gè)不小心就會(huì)踩坑,這就是 RN 社區(qū)的現(xiàn)狀讯柔,我們?cè)诘都饫嘶ㄉ溪?dú)步抡蛙,App 選型背后的技術(shù)棧穩(wěn)定性則成為懸在頭上的一把鍘刀,你不知道什么時(shí)候會(huì)咔嚓一聲魂迄。
<a name="50zapv"></a>
3. 【人才現(xiàn)狀】人員能力的長(zhǎng)短不齊
我們知道有一個(gè)詞叫做主觀能動(dòng)性粗截,表示沒有條件創(chuàng)造條件也可以上,這個(gè)詞的主體就是人捣炬,聊完移動(dòng)端設(shè)備現(xiàn)狀和社區(qū)現(xiàn)狀后熊昌,我們來(lái)聊聊人的問題绽榛。RN 在國(guó)內(nèi)真正開始普及使用,是從 2015 年開始婿屹,也就意味著灭美,到 2018 年,一個(gè) RN 工程師也就只有 3 年的工作經(jīng)驗(yàn)昂利,而 RN 的 “Learn once, write anywhere” 也刺激著一切 Care 人員開支届腐, Care 產(chǎn)品研發(fā)投入性價(jià)比的公司紛紛跳水研究 RN,爭(zhēng)搶 RN 人才蜂奸,RN 是前端中的移動(dòng)前端犁苏,前端有多搶手,那么 RN 工程師就比它還要搶手扩所。
這導(dǎo)致基本上 RN 工程師围详,很難靠外部招聘,只能靠?jī)?nèi)部培養(yǎng)祖屏,這也是小菜前端的成長(zhǎng)歷程短曾,我們有 2 名資深 RN 工程師,一個(gè)是從服務(wù)端 Java赐劣,一個(gè)是從原生 Android 開發(fā)轉(zhuǎn)過來(lái)的嫉拐。如果 RN 人手不足,產(chǎn)品支持的力度和速度就一定會(huì)遇到瓶頸魁兼,這就是我們?cè)?jīng)面臨的問題婉徘,就是人才現(xiàn)狀,外招數(shù)量不足咐汞,內(nèi)培速度有限盖呼,RN 工程師的數(shù)量和能力就時(shí)不時(shí)成為公司業(yè)務(wù)擴(kuò)張的瓶頸。
<a name="52euuz"></a>
4. 【公司現(xiàn)狀】高密集業(yè)務(wù)的交付質(zhì)量
作為工程師化撕,我們有很強(qiáng)的自尊心和不容挑戰(zhàn)的代碼潔癖几晤,但在一個(gè)創(chuàng)業(yè)公司里面,甚至大公司的一個(gè)創(chuàng)業(yè)團(tuán)隊(duì)里面植阴,我們需要對(duì)接一些關(guān)鍵的業(yè)務(wù)節(jié)點(diǎn)蟹瘾,沖刺一些特定的時(shí)間窗口,并且要及時(shí)響應(yīng)多變的業(yè)務(wù)掠手,和業(yè)務(wù)背后多變的產(chǎn)品形態(tài)憾朴,這都會(huì)帶來(lái)非常密集的需求隊(duì)列。
這些密集的需求隊(duì)列對(duì)我們的代碼實(shí)現(xiàn)質(zhì)量有非常高的挑戰(zhàn)喷鸽,一個(gè)組件用 5 分鐘思考如何抽象和用 50 分鐘思考众雷,實(shí)現(xiàn)后的穩(wěn)定性、兼容性都是不同的,如何保證產(chǎn)品按期交付上線砾省,會(huì)是擺在我們面前一個(gè)非常關(guān)鍵的命題鸡岗,而這個(gè)難題之外,還有一個(gè)更難的命題等著我們编兄,那就是如何保證交付不延期的同時(shí)纤房,還能保證交付質(zhì)量。
要知道翻诉,如果一個(gè)項(xiàng)目代碼趕的太毛糙,后期維護(hù)起來(lái)的成本會(huì)是巨大的捌刮,甚至只能用更高的成本重構(gòu)重寫碰煌。本質(zhì)上,再次重構(gòu)就一定是公司在為早期的猛沖買單绅作,為這些技術(shù)債買單芦圾,如何不去買單或者如何用最小的成本買單,這跟我們?cè)缙诘臉I(yè)務(wù)密集程度俄认,交付周期个少,質(zhì)量把控有很大的關(guān)系。
綜上眯杏,移動(dòng)端碎片化所帶來(lái)的兼容難度夜焦,RN 框架的局限性,版本間差異帶來(lái)的不穩(wěn)定性岂贩,技術(shù)社區(qū)資源的匱乏和前端團(tuán)隊(duì)技術(shù)能力掣肘茫经,再疊加上高密度的業(yè)務(wù)排期,讓前端開發(fā)這個(gè)本來(lái)很酷的事情萎津,變得晴雨不定卸伞。
這些避不開的現(xiàn)實(shí),是繞不過去的坎兒锉屈,是搭建團(tuán)隊(duì)必須搞定的基礎(chǔ)荤傲,我們想要把 B2B 生鮮的線上線下場(chǎng)景通過端產(chǎn)品關(guān)聯(lián)起來(lái),想要通過前端團(tuán)隊(duì)的用戶側(cè)輸出從而讓這些產(chǎn)品落地颈渊,就必須面對(duì)這些現(xiàn)實(shí)挑戰(zhàn)遂黍,而應(yīng)對(duì)這些挑戰(zhàn),首先必須搞清楚有哪些挑戰(zhàn)俊嗽,搞清楚挑戰(zhàn)以后妓湘,我們就會(huì)認(rèn)識(shí)到,首當(dāng)其沖的事情乌询,是去搭建 B2B 生鮮公司的前端技術(shù)棧和人才梯隊(duì)榜贴,現(xiàn)在我們進(jìn)入到本文的重點(diǎn)。
<a name="vctkrs"></a>
三、如何應(yīng)對(duì)井噴的挑戰(zhàn)
<a name="zh0zvv"></a>
1. 前端梯隊(duì)如何搭建
創(chuàng)業(yè)公司的技術(shù)團(tuán)隊(duì)唬党,本質(zhì)上就是人和事鹃共,用合適的人搞定特定的事,人才的瓶頸就是這家公司產(chǎn)品落地速度和上線質(zhì)量的瓶頸驶拱,因此人是第一位的霜浴,對(duì)于前端團(tuán)隊(duì)來(lái)說,如何一步步形成有綜合戰(zhàn)斗力的團(tuán)隊(duì)蓝纲,取決于搭建什么層次的前端梯隊(duì)阴孟,如果所有人一視同仁,培養(yǎng)同樣的能力棧税迷,發(fā)揮同樣的興趣向永丝,跟進(jìn)同樣的業(yè)務(wù)線,那么這個(gè)梯隊(duì)的扁平就會(huì)帶來(lái)致命的團(tuán)隊(duì)瓶頸:能力可復(fù)制但不能互補(bǔ)箭养,能力可遞進(jìn)但很難跨越慕嚷,不能互補(bǔ)和很難跨越會(huì)導(dǎo)致團(tuán)隊(duì)內(nèi)的技術(shù)路線過于單一,技術(shù)思維趨于固化毕泌,至于技術(shù)儲(chǔ)備的豐富性和技術(shù)溝通帶來(lái)的碰撞就更有限喝检,最終導(dǎo)致人做事越來(lái)越機(jī)械化,甚至失去最初的技術(shù)初心撼泛。
那么小菜前端到底如何搭建挠说,還是要從公司的人員、業(yè)務(wù)和技術(shù)現(xiàn)狀出發(fā)愿题,由于端的碎片化和技術(shù)框架的不穩(wěn)定性纺涤,就必須在質(zhì)量保障上投入巨大的人力保證產(chǎn)品可用,而人才能力局限性和數(shù)量的匱乏,就跟產(chǎn)品的質(zhì)量保證成為了天然的矛盾,不可協(xié)調(diào)抑党,代碼攛太快,線上天天都是 Bug拧咳,代碼攛太慢,產(chǎn)品節(jié)奏跟不上囚灼,至于跟工程師天天宣講要小心小心再小心骆膝,能起到的作用也不大,因?yàn)楣こ處煴旧淼哪芰σ彩菂⒉畈积R的灶体,所以就必須把團(tuán)隊(duì)先拆成兩部分阅签,一部分做基建支持,一部分做業(yè)務(wù)支持蝎抽,基建支持的同學(xué)研發(fā)整個(gè)團(tuán)隊(duì)的工具腳手架政钟、抽象和打磨團(tuán)隊(duì)的基礎(chǔ)通用組件、長(zhǎng)期維護(hù)項(xiàng)目的通用架構(gòu),這些投入都會(huì)反哺到業(yè)務(wù)支持的同學(xué)养交,業(yè)務(wù)的同學(xué)可以放心大膽的基于基建的成果做上層業(yè)務(wù)開發(fā)精算,穩(wěn)定的工程基礎(chǔ)有了保障,上層的業(yè)務(wù)代碼做質(zhì)量保障難度就大大降低了碎连。
除了分出來(lái)人做基建灰羽,做業(yè)務(wù),還需要有核心的技術(shù)骨干鱼辙,做技術(shù)前瞻性的研究廉嚼,為團(tuán)隊(duì) 3 個(gè)月后,半年后倒戏,甚至 1 年后的技術(shù)方向怠噪,做必要的調(diào)研、測(cè)試和實(shí)驗(yàn)性開發(fā)峭梳,因?yàn)閷?duì)于刀耕火種的早期技術(shù)團(tuán)隊(duì),從原始人到邁向外太空跨空間作戰(zhàn)蹂喻,這中間還差著很多個(gè)關(guān)鍵的技術(shù)迭代節(jié)點(diǎn)葱椭,這些關(guān)鍵的技術(shù)迭代節(jié)點(diǎn),一部分是靠外招技術(shù)專家和資深的工程師來(lái)輸血發(fā)力口四,還有一大部分是需要靠團(tuán)隊(duì)內(nèi)部長(zhǎng)期的積累沉淀孵运,也就是人才內(nèi)部培養(yǎng)。
我們總結(jié)一下:
基建的同學(xué)負(fù)責(zé)輸出工具系統(tǒng)蔓彩、基礎(chǔ)組件治笨、流程規(guī)范,保證內(nèi)部效率最大化和質(zhì)量的有效保障
架構(gòu)的同學(xué)負(fù)責(zé)攻克技術(shù)底層難點(diǎn)赤嚼,調(diào)研先進(jìn)技術(shù)旷赖,升級(jí)團(tuán)隊(duì)技術(shù)架構(gòu),沉淀技術(shù)方案更卒,鎖定和推進(jìn)團(tuán)隊(duì)未來(lái)技術(shù)方向
業(yè)務(wù)的同學(xué)負(fù)責(zé)產(chǎn)品跟進(jìn)等孵,高頻使用基建產(chǎn)品,并通過反饋來(lái)優(yōu)化團(tuán)隊(duì)的技術(shù)基礎(chǔ)設(shè)施蹂空,同時(shí)基于業(yè)務(wù)來(lái)抽象更多的基建需求
基建俯萌、架構(gòu)、業(yè)務(wù)這三個(gè)角色并不是相互獨(dú)立上枕,而是互有重合各有側(cè)重咐熙,一個(gè)業(yè)務(wù)的同學(xué),可能也同時(shí)在負(fù)責(zé)基建的事情辨萍,一個(gè)基建的同學(xué)棋恼,可能也同時(shí)在參與架構(gòu)的設(shè)計(jì),在小菜就有同學(xué)以架構(gòu)和基建為主,業(yè)務(wù)也時(shí)不時(shí)的參與開發(fā)蘸泻,架構(gòu)和基建必須依托于業(yè)務(wù)場(chǎng)景來(lái)做琉苇,不能脫離了場(chǎng)景,不然會(huì)輸出畸形的難以落地的技術(shù)方案悦施。
上面是人員的分工并扇,還有三個(gè)重要的保障,這里不做引申抡诞,只列舉一下:
團(tuán)隊(duì)人員的興趣棧穷蛹、能力棧和業(yè)務(wù)要盡量匹配
團(tuán)隊(duì)人員的階段性目標(biāo)、長(zhǎng)期規(guī)劃要跟進(jìn)公司的職業(yè)晉升路線和能力模型
團(tuán)隊(duì)要有持續(xù)性的內(nèi)部技術(shù)互動(dòng)分享和對(duì)外的技術(shù)理念昼汗、方法方案分享
小菜的前端是大前端肴熏,對(duì)人的要求是:一專多精多能,至少在某個(gè)領(lǐng)域內(nèi)朝著專家方向走顷窒,同時(shí)要慢慢精通多項(xiàng)技能蛙吏,最后是具備多個(gè)特定技術(shù)棧的開發(fā)能力,比如 ReactNative鞋吉,在小菜就是一個(gè)必須具備的開發(fā)能力鸦做,不要求每一個(gè)同學(xué)都成為 RN 專家或者精通,但要具備業(yè)務(wù)開發(fā)的能力谓着,通俗點(diǎn)描述泼诱,就是能用 RN 開發(fā)業(yè)務(wù)產(chǎn)品。
最后一點(diǎn)赊锚,就是資源流轉(zhuǎn)治筒,架構(gòu)的同學(xué),基建的同學(xué)和業(yè)務(wù)的同學(xué)的梯次關(guān)系是從下到上舷蒲,越下越接近技術(shù)本質(zhì)耸袜,越上越接近業(yè)務(wù)結(jié)果,越向下需要越好的技術(shù)實(shí)力牲平,越向上需要越好的業(yè)務(wù)理解能力句灌,這兩個(gè)能力都是核心能力,需要讓團(tuán)隊(duì)成員沿著梯隊(duì)關(guān)系慢慢流動(dòng)起來(lái)欠拾,業(yè)務(wù)中技術(shù)能力好的同學(xué)可以有機(jī)會(huì)沉下來(lái)做做基建胰锌,長(zhǎng)期埋頭基建的同學(xué)可以有機(jī)會(huì)上去做做業(yè)務(wù),業(yè)務(wù)理解不錯(cuò)技術(shù)沉淀又好的同學(xué)可以繼續(xù)沉下去參與架構(gòu)藐窄,這樣團(tuán)隊(duì)內(nèi)部的同學(xué)都可以有多樣性的技術(shù)場(chǎng)景和業(yè)務(wù)場(chǎng)景资昧,一旦有同學(xué)請(qǐng)假、陷在別的業(yè)務(wù)不能抽調(diào)荆忍,馬上就有同學(xué)可以補(bǔ)位進(jìn)來(lái)開發(fā)格带,不會(huì)影響到產(chǎn)品上線節(jié)點(diǎn)撤缴。
關(guān)于團(tuán)隊(duì)如何搭建,目前小菜是走到了這個(gè)算是 v1.0 的階段叽唱,未來(lái)還有更多挑戰(zhàn)屈呕,也會(huì)帶來(lái)更多的基于公司現(xiàn)狀的新調(diào)整,無(wú)論如何變遷棺亭,方法論我們先沉下來(lái):
人才梯隊(duì)要有層次:基礎(chǔ)架構(gòu)虎眨、基建和業(yè)務(wù)上層等
人才成長(zhǎng)要有規(guī)劃:興趣棧、能力棧和公司關(guān)系
人才能力要有擴(kuò)展:?jiǎn)稳四芰突パa(bǔ)后的團(tuán)隊(duì)能力
以人為過程镶摘,以事為結(jié)果嗽桩,人事之間要有動(dòng)態(tài)的機(jī)制形成互惠互補(bǔ)的關(guān)系,只有這樣凄敢,團(tuán)隊(duì)才會(huì)初心不變碌冶,激情常在。
<a name="9fssrd"></a>
2. 如何做技術(shù)選型
技術(shù)選型是一個(gè)行業(yè)老話題了涝缝,方法論也有很多扑庞,在小菜我們遵循的是:技術(shù)方向性預(yù)研大踏步,業(yè)務(wù)基建型開發(fā)小碎步拒逮,前者盡可能激進(jìn)罐氨,后者盡可能保守,比如 數(shù)據(jù)報(bào)表系統(tǒng)消恍,我們激進(jìn)的采用 GraphQL 來(lái)解決 SQL => 頁(yè)面 Dom 的鏈路問題岂昭,在宋小福 App 上面以现,我們就求穩(wěn)的采用 v0.48 的 ReactNative 版本狠怨,而不是用當(dāng)時(shí)較新的 v50+ 版本。
在做技術(shù)選型之前邑遏,還有一些比較重要的基礎(chǔ)性問題需要搞定佣赖,那就是團(tuán)隊(duì)技術(shù)動(dòng)作的一致性,這個(gè)一致主要包含兩點(diǎn):
代碼規(guī)范共用一套
倉(cāng)庫(kù)合作方式共用一套
這兩點(diǎn)如果不一致记盒,會(huì)給技術(shù)選型后的落地帶來(lái)內(nèi)耗成本憎蛤,千萬(wàn)不可大意。
再回到技術(shù)選型本身纪吮,拋開激進(jìn)保守的大踏步和小碎步俩檬,我們需要回到技術(shù)本質(zhì)和工程師的本質(zhì)來(lái)看待如何選的命題,技術(shù)的本質(zhì)是效率碾盟,工程師的本質(zhì)是興趣棚辽,如果這一套技術(shù)選型不能帶來(lái)效率,如果工程師普遍不感興趣冰肴,那么通常這一個(gè)選型我們不會(huì)采納屈藐,我覺得這一個(gè)主觀一些的標(biāo)準(zhǔn)榔组,大家可以參考,但這里面也要權(quán)衡好歷史包袱联逻、維護(hù)成本搓扯,上手難度等這些客觀現(xiàn)實(shí),如果一個(gè)新技術(shù)會(huì)帶來(lái)革命性的效率提升包归,那么即使有上手難度和維護(hù)成本锨推,我們也會(huì)果斷入坑,比如 GraphQL 對(duì)于數(shù)據(jù)報(bào)表對(duì)于解放前后端有大幅度的提升箫踩,我們會(huì)果斷入坑大力推行爱态,如果一個(gè)技術(shù)對(duì)于團(tuán)隊(duì)是錦上添花,那么我們會(huì)慎重選用境钟,比如 TypeScript锦担,可以給工程穩(wěn)定性帶來(lái)了較大的保障,但我們只選擇在熱更新這種 RN SDK 和 Server 端的去集成慨削,而不是一下子推廣到整個(gè)團(tuán)隊(duì)項(xiàng)目中鋪開用洞渔,這里面就會(huì)考慮到實(shí)際得到的好處,以及歷史包袱和上手難度缚态,反復(fù)權(quán)衡后并沒有帶來(lái)更大的價(jià)值磁椒,所以這兩類場(chǎng)景的推行和不大力推行,就又不會(huì)太依賴于工程師的喜好興趣玫芦。
那么我們技術(shù)選型后的結(jié)果是如何呢浆熔?
文章最開始的那張圖,里面就是我們的技術(shù)棧桥帆,這里再做一下總結(jié):
工具類:強(qiáng)依賴 Node医增,多而雜的其他技術(shù),如:MongoDB/Redis/MySQL/Shell/Python
業(yè)務(wù)類:強(qiáng)依賴 React/ReactNative老虫,適度集成其他技術(shù)叶骨,如: Redux/GraphQL/Apollo
框架類:除了 React 全家桶會(huì)謹(jǐn)慎選擇,Node 端框架則相對(duì)寬松:Koa/Thinkjs/Eggjs
這些相對(duì)求穩(wěn)祈匙,不求穩(wěn)的部分忽刽,如小程序開發(fā),我們會(huì)使用 mpvue夺欲,也會(huì)用原生跪帝,還會(huì)集成進(jìn)去 GraphQL,同時(shí)一些涉及到數(shù)據(jù)爬取和視頻圖像識(shí)別些阅,我們也會(huì)集成 Python/C++/TenserFLow 等等伞剑,不過這些往往是前瞻性的技術(shù)嘗試,會(huì)讓團(tuán)隊(duì)的同學(xué)適當(dāng)分配精力持續(xù)研究扑眉。
<a name="ntzfzp"></a>
3. RN 的 App 工程如何架構(gòu)
小菜的主要產(chǎn)品類型纸泄,尤其是對(duì)外的產(chǎn)品赖钞,主要是 RN App,而且數(shù)量較多聘裁,那么 RN 項(xiàng)目的合理架構(gòu)就變得尤其重要雪营,我們這里探討下小菜前端在 RN App 上面的沉淀,涉及到原生層面的技術(shù)細(xì)節(jié)太多衡便,這里暫不做討論献起。
首先,我們?cè)跇?gòu)建 RN App 工程時(shí)需要關(guān)注這幾個(gè)關(guān)鍵要素:
配置管理
靜態(tài)文件管理
網(wǎng)絡(luò)請(qǐng)求
組件管理
路由管理
數(shù)據(jù)緩存
App 的熱更新
數(shù)據(jù)搜集
配置管理是指可以靈活合理的管理 App 的內(nèi)部環(huán)境镣陕,主要包括:
App 本身的一些配置
所使用三方插件的配置
我們?cè)跇?gòu)建工程時(shí)盡量將所有的配置抽象統(tǒng)一放置在一個(gè)地方谴餐,這樣便于查找和修改,但是由于大多數(shù)配置都統(tǒng)一放在同一個(gè)地方呆抑,那么就難免有部分文件要使用某個(gè)配置時(shí)其引用路徑比較長(zhǎng)岂嗓,比如:
import { pluginAConfig } from '../../../../../config'
這樣就造成了閱讀性很差且代碼不美觀,因此我們可以使用 Facebook 的 fbjs
模塊提供的一個(gè)功能providesModule
:
//config.js
/**
* config for all
* @providesModule config
* 使用 providesModule 將 config 暴露出去
**/
import pluginAConfig from './plugin_a_config'
export default {
pluginAConfig
}
// 然后在其他文件中調(diào)用
// A.js
import { pluginAConfig } from 'config'
這樣就能很方便地在 App 的任意一處使用 config 了鹊碍,但是我們要避免濫用 providesMoudle
厌殉,因?yàn)槭褂昧?providesMoudle
進(jìn)行聲明的模塊的源碼,想要在編輯器中使用跳轉(zhuǎn)到定義的方式去查看比較困難侈咕,不利于團(tuán)隊(duì)多人合作公罕。
靜態(tài)資源泛指會(huì)被多次調(diào)用的圖片或 icon,我們一般在 RN 使用圖片時(shí)是直接引用的:
import { Image } from 'react-native'
render(){
return (
<Image source={{uri: './logo.png'}} />
)
}
當(dāng)圖片需要在多處使用時(shí)耀销,我們可能會(huì)將這些可能會(huì)被反復(fù)使用的圖片統(tǒng)一管理到 assets
文件夾中楼眷,統(tǒng)一管理和使用,但是當(dāng)需要使用圖片資源的文件嵌套較深時(shí)熊尉,引用圖片就變得麻煩:
render(){
return (
<Image source={{uri: '../../../../assets/logo.png'}} />
)
}
這個(gè)問題與配置管理的問題一樣罐柳,可以首先將圖片資源按照類型進(jìn)行分類,比如 assets 文件夾下有 button/icon/img/splash/svg 等帽揪,每一個(gè)類型的結(jié)構(gòu)如下:
- icon/
- asset/
- index.js
其中 asset
文件夾保存我們的圖片資源硝清,在 index.js
中對(duì)圖片進(jìn)行引用并暴露為模塊:
// index.js
export default {
IconAlarmClockOrange: require('./asset/icon_alarm_clock_orange.png'),
IconAvatarBlue: require('./asset/icon_avatar_blue.png'),
IconArrowLeftBlue: require('./asset/icon_arrow_left_blue.png'),
IconArrowUpGreen: require('./asset/icon_arrow_up_green.png')
}
然后再在 assets
文件夾下編輯 index.js
辅斟,將所有的圖片資源作為 assets
模塊暴露出去转晰,為了避免和其他模塊沖突你可以修改模塊名為 xxAssets
// assets/index.js
/**
* @providesModule myAssets
**/
import Splash from './splash'
import Icon from './icon'
import Img from './img'
import Btn from './button'
import Svg from './svg'
export {
Splash,
Icon,
Img,
Btn,
Svg
}
// A.js
import { Icon } from 'myAssets'
render(){
return (
<Image source={Icon.IconAlarmClockOrange} />
)
}
這樣,我們就能很方便地將分散在項(xiàng)目各處的圖片資源統(tǒng)一到一個(gè)地方進(jìn)行管理了士飒,使用起來(lái)也非常方便查邢。
網(wǎng)絡(luò)請(qǐng)求這塊,react-native 使用 whatwg-fetch酵幕,我們也可以選在其他的三方包如 axios 來(lái)做網(wǎng)絡(luò)請(qǐng)求扰藕,但有我們?cè)陂_發(fā)中遇到過一個(gè)問題,那就是我們明明已經(jīng)在代碼里已經(jīng)修改了 cookie芳撒, 但是每次請(qǐng)求可能還是會(huì)帶上之前的 cookie 從而造成一些困擾邓深,所以這里推薦一個(gè)實(shí)用的組件 Networking
:
import { NativeModules } from 'react-native'
const { Networking } = NativeModules
// 手動(dòng)清除已緩存 Cookie未桥,這樣就能解決上述的問題了
Networking.clearCookies(callBack)
當(dāng)然,Networking
的功能不止于此芥备,還有很多其他有趣的功能可以發(fā)掘冬耿,可以直接用它來(lái)包裝自己的網(wǎng)絡(luò)請(qǐng)求工具,還支持 abort
萌壳,可以參考 源碼 來(lái)具體把玩亦镶。
使用 RN 開發(fā) App 本身效率就比較高,如果想要繼續(xù)進(jìn)階就要考慮組件化開發(fā)袱瓮,一旦涉及到組件化開發(fā)缤骨,就不可避免地會(huì)涉及到組件管理的問題,這里的組件管理比較寬泛尺借,它實(shí)際上應(yīng)該指的是:
組件規(guī)范
組件類型劃分
組件開發(fā)標(biāo)準(zhǔn)
組件規(guī)范指的是 UI 設(shè)計(jì)規(guī)范绊起,我們可以與設(shè)計(jì)同學(xué)交流規(guī)定好一套特定的規(guī)范,然后將通用的樣式屬性(如主題顏色燎斩,按鈕輪廓勒庄,返回按鍵,Tab 基礎(chǔ)樣式等)定義出來(lái)瘫里,便于所有的組件開發(fā)者在開發(fā)時(shí)使用实蔽,而不是開發(fā)者各自為政在開發(fā)時(shí)重復(fù)寫樣式文件,這里推薦一個(gè)比較好用的用于樣式定義的三方插件 react-native-extended-stylesheet 谨读,我們可以使用這個(gè)插件定義我們的通用屬性:
// mystyle
import { PixelRatio, Dimensions } from 'react-native'
import EStyleSheet from 'react-native-extended-stylesheet'
const { width, height } = Dimensions.get('window')
const globals = {
/** build color **/
$Primary: '#aa66ff',
$Secondary: '#77aa33',
$slimLine: 1 / PixelRatio.get(),
/** dimensions **/
$windowWidth: width,
$windowHeight: height
}
EStyleSheet.build(globals)
module.exports = {
...EStyleSheet,
create: styleObject => EStyleSheet.create(styleObject),
build: (obj) => {
if (!obj) {
return
}
EStyleSheet.build(_.assign(obj, globals))
}
}
// view.js
import MyStyleSheet from 'mystyle'
const s = MyStyleSheet.create({
container: {
backgroundColor: '$Secondary',
width: '$windowWidth'
}
})
render....
這樣局装,我們就能在開發(fā)的任意插件或者 App 中直接使用這些基礎(chǔ)屬性,當(dāng)某些屬性需要修改時(shí)只需要更新 mystyle
組件即可劳殖,還可以衍生出主題切換等功能铐尚,使得開發(fā)更加靈活。
關(guān)于組件類型我們會(huì)拋開三方組件以及原生組件哆姻,因?yàn)橐坏┥婕暗竭@兩者宣增,需要寫的東西就太多了,我們將組件按使用范圍分為通用組件和業(yè)務(wù)組件兩大類矛缨。
首先什么是業(yè)務(wù)組件爹脾?即我們?cè)陂_發(fā)某個(gè)業(yè)務(wù)產(chǎn)品常用到的組件,這個(gè)組件綁定了與業(yè)務(wù)相關(guān)的一些特殊屬性箕昭,除了這個(gè)業(yè)務(wù)開發(fā)以外灵妨,其他地方都不適用,但是在開發(fā)這個(gè)業(yè)務(wù)時(shí)多個(gè)頁(yè)面會(huì)頻繁地使用到落竹,所以我們有必要將其抽象出來(lái)泌霍,方便使用。
什么是通用組件述召?即可以在 App 范圍內(nèi)使用甚至于跨 App 使用的組件朱转,這里可以對(duì)這個(gè)類別進(jìn)行細(xì)分蟹地,我們將能跨 App 使用的組件上傳到了自己的搭建的私有 npm 倉(cāng)庫(kù),方便我們的 App 開發(fā)者使用藤为,同時(shí)锈津,具有 App 自己特色的組件則放到工程中統(tǒng)一管理,同樣適用 providesModules
暴露出去凉蜂。
制定一整套組件開發(fā)標(biāo)準(zhǔn)的是很重要的琼梆,因?yàn)楹芏嘟M件開發(fā)可能是多人維護(hù)的,有一套既定的規(guī)范就可以降低維護(hù)成本窿吩,組件使用的說明文檔的完善也同樣重要茎杂。
開發(fā) App 就不可避免地會(huì)遇到如何管理頁(yè)面以及處理頁(yè)面跳轉(zhuǎn)等問題,也就是路由管理問題纫雁,自從 Facebook 取消了 RN 本身自帶的 Navigator 以后煌往,許多依賴于這個(gè)組件的開發(fā)者不得不將目光投向百花齊放的社區(qū)三方組件,F(xiàn)B 隨后推薦大家使用的是 react-community 推出的 react-navigation 轧邪,現(xiàn)在這個(gè)路由組件已經(jīng)獨(dú)立出來(lái)了刽脖。我們?cè)陂_發(fā)時(shí)就是使用的這個(gè)組件作為路由管理組件,只不過是在其基礎(chǔ)上做了一些定制 忌愚,使得使用更加簡(jiǎn)單曲管,部分跳轉(zhuǎn)動(dòng)作更加符合我們的產(chǎn)品場(chǎng)景,推薦大家使用這個(gè)組件硕糊。當(dāng)然院水,除去這個(gè)組件還有很多其他的組件可供選擇:
基于
react-navigation
進(jìn)行深度定制的 react-native-router-flux基于原生解決方案的 react-native-navigation
airbnb 的 native-navigation
路由管理作為整個(gè) App 的骨架,它是這幾個(gè)部分中最重要的一部分简十,合理地定制和使用路由管理可以極大地簡(jiǎn)化我們的開發(fā)復(fù)雜度檬某。
一般情況下需要緩存的數(shù)據(jù)基本上就可能是我們會(huì)在 App 很多地方都會(huì)使用到的全局?jǐn)?shù)據(jù),如用戶信息螟蝙,App 設(shè)置(非應(yīng)用層面的設(shè)置)等恢恼,RN 提供一個(gè) AsyncStorage 存儲(chǔ)引擎,通常的使用方式是對(duì)這個(gè)數(shù)據(jù)引擎進(jìn)行包裝后暴露出符合我們要求的讀寫接口胰默。這里推薦另外一種使用方式:
既然需要緩存的數(shù)據(jù)可能是會(huì)在 App 很多地方使用到的全局?jǐn)?shù)據(jù)场斑,那么我們可以將這些全局?jǐn)?shù)據(jù)使用 redux 來(lái)進(jìn)行管理,而利器 redux-persist 則能讓我們很優(yōu)雅地讀寫我們的緩存數(shù)據(jù)初坠。
同時(shí)和簸,如果對(duì) react-navigation
進(jìn)行合理的定制彭雾,接管其路由管理碟刺,那么我們還能實(shí)現(xiàn)保存用戶退出 App 之前最后瀏覽的頁(yè)面的狀態(tài),用戶在下次打開 App 依然可以從之前瀏覽的地方繼續(xù)使用 App薯酝,當(dāng)然半沽,這個(gè)功能要謹(jǐn)慎使用爽柒!
App 的版本更新,RN 除了傳統(tǒng)的 App 更新外還有一個(gè)熱更新的可選項(xiàng)(傳統(tǒng) App 更新也有熱更新者填,其原理就不太一樣了)浩村,社區(qū)大多數(shù)人都推薦使用 codepush 來(lái)進(jìn)行熱更新,至于其后端解決方案 貌似已經(jīng)有了一個(gè) code-push-server 占哟,我們是使用自己的熱更新方案心墅,其原理就是在不更新原生代碼的基礎(chǔ)上更新 JS 代碼和靜態(tài)資源文件。
搜集的 App 使用數(shù)據(jù)(包括異常數(shù)據(jù))并對(duì)此分析榨乎,根據(jù)分析來(lái)定位問題是保證 App 質(zhì)量的有效手段之一怎燥。你可以選擇自己搭建一套數(shù)據(jù)搜集服務(wù),包括客戶端 SDK 和服務(wù)端搜集服務(wù)蜜暑,或者選擇市場(chǎng)上已有的工具铐姚,目前較為成熟的收據(jù)搜集工具比較多,如友盟肛捍,mixpanel, countly 等等隐绵,在此不作贅述。
總結(jié)一下拙毫,一個(gè) RN App 架構(gòu)應(yīng)該要保證 App 的運(yùn)行穩(wěn)定以及開發(fā)的便捷依许。運(yùn)行穩(wěn)定這一方面,除了從 JS 層面(如單元測(cè)試缀蹄,JS 錯(cuò)誤上報(bào)等)保證之外悍手,很大程度上還要依賴于原生層面的處理,所以團(tuán)隊(duì)里面要有同學(xué)的精力可以投在原生研究上面袍患,至于開發(fā)便捷坦康,我們盡量將復(fù)雜重要或者簡(jiǎn)單繁瑣的操作在構(gòu)建工程時(shí)就做掉,這樣也可以大幅度提高我們的開發(fā)效率诡延,降低開發(fā)者之間的合作溝通成本滞欠。
<a name="6m5obg"></a>
4. 效率協(xié)同工具如何打造
效率協(xié)同往往不分家,效率寬泛一點(diǎn)肆良,就是又快又好筛璧,協(xié)同寬泛一點(diǎn),就是順滑無(wú)內(nèi)耗惹恃,而且效率協(xié)同在不同的場(chǎng)景下夭谤,一定有不同的表現(xiàn),所以效率協(xié)同一定要具體到某一個(gè)場(chǎng)景才有意義巫糙,比如:
我們要發(fā)布 6 款 RN App 中的若干款朗儒,在一周內(nèi)的若干天發(fā)布,由若干人自行打包測(cè)試自行發(fā)布,那么這里面就有巨大的協(xié)同問題醉锄,同時(shí)還有一些效率問題乏悄,如果一個(gè)同學(xué)進(jìn)來(lái)改了 3 行接口調(diào)用代碼,他至少要有這幾個(gè)階段:
開發(fā)階段本機(jī)切新分支調(diào)試
測(cè)試階段打一個(gè)連接測(cè)試環(huán)境的包測(cè)試有效性
測(cè)試完再打一個(gè)連接正式環(huán)境的本地包測(cè)正確性
最后再打一個(gè)連接正式環(huán)境的用來(lái)熱更新的包進(jìn)行發(fā)布
那么多人之間都各自來(lái)做這個(gè)發(fā)布恳不,就會(huì)出現(xiàn)一些發(fā)布沖突的協(xié)同問題檩小,如果把發(fā)布權(quán)限全回收到某一個(gè)人,協(xié)同貌似能解決烟勋,但是會(huì)帶來(lái)效率問題规求,大家要讓這個(gè)發(fā)布人頻繁打包,或者打好的包卵惦,反復(fù)傳給發(fā)布人颓哮,發(fā)布人的時(shí)間線就被他人的開發(fā)進(jìn)程給打斷了,變成了一個(gè)打包員鸵荠,關(guān)于這個(gè)我專門做了一張圖:
[圖片上傳失敗...(image-f61455-1555230920415)]
這里面的一個(gè)圓點(diǎn)冕茅,就代表一個(gè)編譯后的包,比如 A 打出來(lái)的不需要 Debug 的連接正式環(huán)境的需要熱更新的 iOS 的 ipa 包蛹找,那么 A 的這個(gè)包姨伤,跟 B 打出來(lái)的不需要 Debug 的連接正式環(huán)境的需要熱更新的 iOS 的 ipa 包,即便是在同一個(gè)倉(cāng)庫(kù)的同一個(gè)分支庸疾,也不能保證 100% 一模一樣的包乍楚,原因在于,這些本地打的包届慈,還會(huì)受到 Node/NPM 版本(語(yǔ)義化)徒溪,XCode 版本,原生熱更新版本控制等等因素影響金顿,導(dǎo)致這個(gè)包自身很容易出問題臊泌,甚至是一些人肉引發(fā)的分支和人工上傳等等的影響,也會(huì)導(dǎo)致這個(gè)包發(fā)布出問題揍拆,舉一個(gè)我們真實(shí)發(fā)生過的故障渠概,A 打完包,把包文件釘釘傳給 B嫂拴,B 在發(fā)布的時(shí)候播揪,選擇本地文件時(shí)候選錯(cuò)了一個(gè)老版本直接發(fā)布上線,導(dǎo)致線上部分用戶直接版本回退筒狠,我們后來(lái)不得已采用緊急回滾猪狈,才把影響范圍控制住。
上面大篇幅的介紹打包的這個(gè)場(chǎng)景辩恼,是小菜前端早期非常痛苦的一個(gè)場(chǎng)景雇庙,協(xié)同方式和規(guī)范無(wú)論我們?nèi)绾稳钗迳昕偸潜苊獠涣巳巳獾膯栴}谓形,一旦出問題,就是大問題大故障状共,那么這時(shí)候套耕,就必須投入基建的力量來(lái)打造一款或者一套流程工具谁帕,通過工具一勞永逸的解決這些主要的協(xié)同問題峡继,把瑣碎人肉的事情交給機(jī)器去做,機(jī)器比人做的快匈挖,也比人做的好碾牌。
我們來(lái)總結(jié)一下,團(tuán)隊(duì)跑一段時(shí)間儡循,一定會(huì)擠壓一些問題舶吗,這些問題不可以視而不見,也不可以拿業(yè)務(wù)支持第一這樣的借口來(lái)無(wú)限期推遲解決問題择膝,而是時(shí)不時(shí)評(píng)估一下誓琼,有沒有可能通過系統(tǒng)和工具,來(lái)約束一些行為肴捉,來(lái)取代一些人肉工作腹侣,進(jìn)而可以一勞永逸的解決掉一些問題,一旦決定去解決了齿穗,那么如何打造協(xié)同工具就變得順?biāo)浦哿税亮ィ驗(yàn)楣こ處熥钌瞄L(zhǎng)的干的事情之一,就是造輪子造工具窃页。
小菜前端造了哪些輪子哪些工具呢跺株,文章最開始就已經(jīng)列出來(lái)了,這里再陳述和解釋一下:
大伯伯(諧音打包包) 解決人肉打包帶來(lái)的協(xié)同問題
大表姐(代號(hào) Laurence - 來(lái)自饑餓游戲) 解決人肉發(fā)布脖卖、人工維護(hù)版本乒省,問題追溯定位的效率問題
姑奶奶 解決去多個(gè)三方平臺(tái)查看異常日志和 Bug 反饋指派的人肉效率問題
大舅子 解決前后端耦合在 Restful/Mock/冗余的接口 的合作效率問題
RGB 解決純數(shù)字報(bào)表分析頁(yè)面訪問數(shù)據(jù)和用戶行為的效率問題
堂哥工作臺(tái) 解決組員與 Leader 日?qǐng)?bào)周報(bào)難回憶帶來(lái)的書寫效率和后期回顧問題
小菜圖書館 解決小菜書架上面借書還書靠人肉記錄維護(hù)的效率問題
...
其中的大舅子這個(gè)單獨(dú)拿出來(lái)說一下,現(xiàn)在前后端常見的合作方式是基于 restful API 的接口合作畦木,前后端經(jīng)過一輪接口評(píng)審作儿,后端再為前端寫 Mock 數(shù)據(jù),可能還會(huì)加上一個(gè) Proxy 服務(wù)馋劈,最終前端本地的頁(yè)面上攻锰,做 Mock 環(huán)境、測(cè)試環(huán)境和正式環(huán)境的切換妓雾,這種方式最大的問題有 2 個(gè):
前端比較依賴于后端的接口定義娶吞,后端為前端 Mock 做完后,前端才方便的進(jìn)行頁(yè)面中的數(shù)據(jù)替換和邏輯判斷械姻,有等待成本
前端復(fù)雜多變的頁(yè)面會(huì)影響到后端的接口復(fù)雜度和體積妒蛇,頁(yè)面上的字段增減机断,都會(huì)反映到接口的字段增減,接口本身變得不穩(wěn)定绣夺,會(huì)帶來(lái)很多隱患點(diǎn)吏奸,比如接口體積越來(lái)越臃腫,或者接口有多個(gè)版本陶耍,一旦接口文檔更新沒跟上奋蔚,會(huì)導(dǎo)致后期的同一個(gè)接口的不同版本之間,增加調(diào)用出錯(cuò)概率等等
當(dāng)然業(yè)界也有各種各樣規(guī)避這些問題的策略烈钞,可能是文檔建設(shè)泊碑,可能是流程約束,小菜早期毯欣,哪怕到現(xiàn)在馒过,也是在使用這種方式合作的,直到現(xiàn)在我們有了大舅子酗钞,前后端合作的方式開始進(jìn)化腹忽,大舅子系統(tǒng)架構(gòu)圖如下:
[圖片上傳失敗...(image-88a913-1555230920415)]
大舅子目前的架構(gòu)是放到網(wǎng)關(guān)下面,網(wǎng)關(guān)層做一些鑒權(quán)和安全的處理砚作,向下把一個(gè) GraphQL 的請(qǐng)求轉(zhuǎn)發(fā)給大舅子窘奏,大舅子上面根據(jù)這個(gè) Query Type 對(duì)應(yīng)的 Resolver 去調(diào)用下層的服務(wù)接口,下層可能是另外一個(gè) GraphQL 服務(wù)偎巢,也可能是微服務(wù)蔼夜,也可能是數(shù)據(jù)庫(kù),兼容度很高压昼,無(wú)論是哪一種求冷,大舅子的角色扮演就是配置和聚合:配置客戶端上頁(yè)面對(duì)應(yīng)的數(shù)據(jù)類型,嵌套關(guān)系和數(shù)據(jù)結(jié)構(gòu)窍霞,向下連接和聚合不同的數(shù)據(jù)源匠题。
內(nèi)部的開發(fā)正式環(huán)境關(guān)系圖如下:
[圖片上傳失敗...(image-82fa1f-1555230920415)]
這個(gè)事情并不新鮮,多年前但金,Nodejs 就在扮演數(shù)據(jù)聚合層的角色韭山,把多個(gè) API 聚合成一個(gè) API,或者打散一些 API冷溃,聚合成新的 API钱磅,但本質(zhì)上依然是向客戶端提供 API,這種 API 依然是面向頁(yè)面似枕,可以看做是頁(yè)面驅(qū)動(dòng)的 API盖淡,大舅子因?yàn)檎麄€(gè)建模基礎(chǔ)是 GraphQL凿歼,所以頁(yè)面和數(shù)據(jù)結(jié)合的權(quán)利褪迟,交給了客戶端自己去做冗恨,它需要什么數(shù)據(jù),就在客戶端聲明什么數(shù)據(jù)結(jié)構(gòu)味赃,帶來(lái)的好處很多掀抹,這里列舉兩條我認(rèn)為有價(jià)值的:
前端可以不再局限于接口評(píng)審階段,可以繼續(xù)往前提到數(shù)據(jù)庫(kù)/表結(jié)構(gòu)評(píng)審階段進(jìn)入開發(fā)流程心俗,在表結(jié)構(gòu)評(píng)審期就能拿到字段定義與含義傲武,從而再大舅子上提前定義前端自己的 Type 和 Resolver
后端不再耽誤自己的時(shí)間為前端提供 Mock,也不再受頁(yè)面 API 的約束另凌,可以下沉精力專心做下層業(yè)務(wù)領(lǐng)域能努力的建設(shè)谱轨,下沉的領(lǐng)域能力多大戒幔,那么端上可使用和組合的能力就有多大
從此吠谢,塵歸塵,土歸土诗茎,前后因?yàn)轫?yè)面數(shù)據(jù)控制權(quán)的分離而解耦工坊,也因?yàn)閿?shù)據(jù)能力的回收而同時(shí)貼近業(yè)務(wù),前端也被倒逼去了解業(yè)務(wù)敢订,不再僅僅是界面和產(chǎn)品交互驅(qū)動(dòng)王污,現(xiàn)在大舅子還在早期的迭代階段,關(guān)于它的好處和優(yōu)化的空間還非常非常大楚午,今天不做深入討論昭齐,我們來(lái)總結(jié)一下:
小菜前端已經(jīng)從工具基建中受益,因?yàn)楣ぞ邘?lái)了協(xié)同和效率的優(yōu)化只是結(jié)果之一矾柜,最重要的收獲還有兩個(gè):
解放了小菜前端團(tuán)隊(duì)以及技術(shù)團(tuán)隊(duì)的人肉時(shí)間阱驾,可以有精力做其他事情
通過基建工具研發(fā)培養(yǎng)了小菜前端分析問題和解決問題的能力,同時(shí)沉淀了一些不錯(cuò)的技術(shù)方案
那么小菜的成長(zhǎng)和沉淀怪蔑,我們接下來(lái)就可以來(lái)總結(jié)一下了里覆。
<a name="bvopca"></a>
四、技術(shù)成長(zhǎng)和沉淀
技術(shù)成長(zhǎng)就是工程師的能力變化缆瓣,我在 4 月份給大家做了一個(gè) 10 個(gè)月前后的能力評(píng)估喧枷,這 10 個(gè)月,是小菜前端 3 年來(lái)基建密度和團(tuán)隊(duì)內(nèi)調(diào)整最大的幾個(gè)月弓坞,也是團(tuán)隊(duì)整體戰(zhàn)斗力提升最大的幾個(gè)月隧甚,本文的所有分析、策略和實(shí)際的解決辦法渡冻,也都是在這幾個(gè)月里面進(jìn)行實(shí)施的戚扳,挑了幾個(gè)同學(xué),挑了幾個(gè)主要的能力維度菩帝,我們感受下他們的技術(shù)成長(zhǎng)咖城,白色的 * 代表 10 個(gè)月之前的能力值茬腿,2 顆星代表可以熟練的開發(fā),三顆星代表基本精通或擅長(zhǎng)宜雀,四顆星是比較精通切平。
[圖片上傳失敗...(image-eec793-1555230920415)]
可以看到每個(gè)人都有不同程度不同層面的成長(zhǎng),有的全面開花辐董,有的某些領(lǐng)域內(nèi)快速積累悴品,也要同學(xué)技術(shù)成長(zhǎng)不多,但是協(xié)作能力工程能力有很大提升简烘,其實(shí)還少了一個(gè)維度苔严,就是參與業(yè)務(wù)拿到的結(jié)果或者說業(yè)務(wù)能力,圖上放不下了孤澎,稍后會(huì)做分析和補(bǔ)充调炬,我們?cè)賮?lái)看下這些同學(xué)做的事情:
[圖片上傳失敗...(image-cf8cf1-1555230920415)]
如果仔細(xì)比照一下衍慎,我們很容易得出三個(gè)結(jié)論:
整個(gè)技術(shù)團(tuán)隊(duì)綜合技術(shù)能力有大幅度的提升
承擔(dān)職責(zé)越多的同學(xué)能力成長(zhǎng)越多越快(如組員 A)
承擔(dān)繁重基建和工具開發(fā)的同學(xué)比承擔(dān)業(yè)務(wù)開發(fā)的同學(xué)技術(shù)成長(zhǎng)更多(如組員 E)
業(yè)務(wù)能力沒有放到圖上,這是要補(bǔ)充的第四個(gè)結(jié)論
- 承擔(dān)業(yè)務(wù)越多的同學(xué),項(xiàng)目管理能力/溝通能力/業(yè)務(wù)理解能力也越好
以上是人才成長(zhǎng)泼返,那么沉淀下來(lái)的內(nèi)容一共是三部分:
通用的工具技術(shù)解決方案
通用的技術(shù)模塊和業(yè)務(wù)組件庫(kù)
團(tuán)隊(duì)整體的問題解決套路(分析解決問題的思維方式)
通用的技術(shù)解決方案可以不斷的快速?gòu)?fù)用鹉勒,比如我們宋小福用新架構(gòu)前后調(diào)整優(yōu)化有 1 個(gè)月够挂,把這同一套架構(gòu)放到麥大蔬上 2 周就夠了顷啼,再次遷移到新項(xiàng)目宋大倉(cāng)里面只需要 1 周就搞定了。
通用的技術(shù)模塊和業(yè)務(wù)組件庫(kù)七兜,則是我們的組件三步走策略丸凭,首先是某個(gè)業(yè)務(wù)產(chǎn)品線下面的組件模板,比如 篩選組件或者列表組件腕铸,能在這個(gè)業(yè)務(wù)場(chǎng)景下的產(chǎn)品形態(tài)中通用惜犀,如果它可以跨產(chǎn)品線,那么就會(huì)躍升為 App 內(nèi)通用組件恬惯,如果它還能繼續(xù)抽象具有可重用性向拆,那么就可以躍升為跨 App 的通用業(yè)務(wù)組件,比如熱更新組件酪耳,地理位置定位組件浓恳,登錄組件,異常提示彈窗組件等等碗暗。
團(tuán)隊(duì)整體的問題解決套路颈将,這個(gè)是我們最大的收獲,再直白一點(diǎn)言疗,就是如何更快更好更有創(chuàng)造性的做事晴圾,這種思維方式,解決問題的套路噪奄,本質(zhì)上是可以在團(tuán)隊(duì)內(nèi)不斷傳承的死姚,無(wú)論我們后面遇到什么樣的業(yè)務(wù)和團(tuán)隊(duì)問題人乓,我們用這一套場(chǎng)景-技術(shù)-長(zhǎng)短期投入產(chǎn)出比評(píng)估的路子,都能用較輕的方式把問題解決掉都毒,這個(gè)對(duì)于我們培養(yǎng)新人有很大的幫助色罚。
<a name="g4p2rl"></a>
五、對(duì)未來(lái)的展望
小菜三年走過來(lái)账劲,前端團(tuán)隊(duì)從早期的技術(shù)和人員不穩(wěn)定戳护,到現(xiàn)在趨于穩(wěn)定,站在公司的角度瀑焦,最大的收獲就是培養(yǎng)和磨煉了一批有創(chuàng)業(yè)熱情腌且,有擔(dān)當(dāng)勇氣,有技術(shù)底蘊(yùn)的一群人榛瓮,這一群人抱團(tuán)在一起铺董,可以在所謂大前端這個(gè)框框內(nèi)玩出更多的花樣,支持到更多的業(yè)務(wù)場(chǎng)景榆芦。
站在今天看明天柄粹,雖然有很多東西對(duì)我們來(lái)說依然是未知的喘鸟,但我們不再像過去一樣臨場(chǎng)發(fā)怯匆绣,手忙腳亂,取而代之的是無(wú)論多大多難的業(yè)務(wù)類型什黑,我們都可以坐下來(lái)利用這幫人的智慧匯聚出一個(gè)最優(yōu)選擇崎淳,胸有成竹的去做技術(shù)探索和工程嘗試,在跟公司一起成長(zhǎng)變大的過程中愕把,站在今天看明天拣凹,雖然有很多東西對(duì)我們來(lái)說依然是未知的,但我們不再像過去一樣臨場(chǎng)發(fā)怯恨豁,手忙腳亂嚣镜,取而代之的是無(wú)論多大多難的業(yè)務(wù)類型,我們都可以坐下來(lái)利用這幫人的智慧匯聚出一個(gè)最優(yōu)選擇橘蜜,胸有成竹的去做技術(shù)探索和工程嘗試菊匿,在跟公司一起成長(zhǎng)變大的過程中,小菜前端也一定會(huì)沉淀出來(lái)更有實(shí)踐價(jià)值计福,更有效率的技術(shù)方案跌捆,而這些就是我們將來(lái)可推廣復(fù)用的寶貴技術(shù)資產(chǎn),當(dāng)然除了寶貴的技術(shù)資產(chǎn)象颖,最最最重要的還有我們這群人佩厚,可以開心有趣有挑戰(zhàn)性的 Coding,想進(jìn)一步了解我們團(tuán)隊(duì)的可以移步這里说订。