<input id="0qass"><u id="0qass"></u></input>
  • <input id="0qass"><u id="0qass"></u></input>
  • <menu id="0qass"><u id="0qass"></u></menu>

    生鮮 B2B 技術平臺的前端團隊該如何搭建(B2B 技術共享第七篇)

    線下越重,線上需要越輕,這個輕指的是輕便輕巧和簡潔易用,通過前面幾章小菜技術與產品歷史介紹,我們了解到 B2B 生鮮領域在線下是如此之重,那么在交易場景線上化的過程中,端的移動化就勢在必行,試想一下,讓菜市場攤位老板人手一臺筆記本點開網頁選購支付,讓采購銷售抱著電腦去拜訪客戶,一邊聊蔬菜行情,一邊打開筆記本進行記錄,有沒有一種回到世紀初的感覺。

    產品的移動化,這將是我們展開這篇文章的背景,我們會先了解小菜的產品托管在哪些端上,然后感受這些端帶來的挑戰,最后是我們面對這些挑戰所采取的策略,以及整個小菜前端團隊歷練后的技術成長和沉淀,和我們對于自己的一個評估和對未來的展望,本文將采用最通俗易懂的方式陳述,會略有繁瑣,但力求對技術新人也足夠友好。

    一、小菜大前端的端有哪些

    小菜早期圍繞著蔬菜銷地以客戶集單批發的模式摸爬滾打幾年,從上游的蔬菜供應商到下游批發市場的攤位老板,在這個長長的鏈路中,我們誕生了這樣幾款線上產品來服務于不同的人群和場景,之前文章中也有介紹,這里再匯總一下,共 7 款 App:

    • 宋小菜 服務于銷地批發老板的下單工具
    • 宋小福 服務于小菜內部銷售團隊的 CRM 銷售管理與客戶管理工具
    • 宋小倉 連接司機-物流-采購-銷售的蔬菜在途位置監控工具
    • 采秘 服務于小菜內部采購團隊的蔬菜品類采購工具
    • 麥大蔬 服務于上游蔬菜供應商的大宗農產品交易平臺
    • 宋大倉 服務于上游囤貨配資的進出庫管理平臺
    • 行情寶 服務于產銷兩地的行情采集和預測工具

    前 6 款 App 都是基于 ReactNative 開發的 iOS/Android App,最后一個是微信小程序,它們涵蓋了公司幾乎所有的協同場景和工作流,其他涉及審核、數據觀測和過程管理的部分,則會進入到我們 PC 端產品中,也就是:

    • ERP 后臺管理系統

    生鮮的 toB 場景,角色眾多,鏈路冗長,這種延伸到產地農民,延伸到小 B 交易的管理系統一定會角色雜,權限多,操作重,業務復雜度所帶來的頁面復雜度不是一般的小系統可比擬。

    到目前為止,我們已經看到小菜的 7 個移動端 App,以及一個復雜的后臺管理系統,這些都跟前端工程師息息相關,除了這些,還有 2 個重要的內部產品,就是:

    • 大表哥 數據報表系統
    • 大瓜子 市調模板配置系統

    其中大表哥(諧音:搭 Excel 表格)由前端工程師獨立研發和維護的數據報表系統,單拎出來這個系統,是因為在 B2B 公司,尤其涉及到供應鏈的長鏈路場景中,真實業務數據的及時反饋對于每一個執行團隊都至關重要,沒有這些數據抓手,就失去了多維度數據觀測,都很難快速的做出正確的運營決策和業務調整,甚至很難發現業務中出現的漏洞和問題,比如不正常的非自助下單(也就是銷售幫忙下單)的比例。

    關于報表系統后文還有介紹,我們再為前端增加一個服務的產品場景,就是微信生態內產品,比如公眾號或者小程序,它的技術棧和運行環境跟原生 App 和 PC 都不同,雖然小程序可以帶來更多的業務可能性,也會對前端帶來更大的挑戰。

    我們把這些端合并一下,小菜前端要服務的端或場景:

    • 移動端(iOS/Android App/小程序)
    • PC 端(ERP)
    • 工具端(大表哥數據報表)

    端上全部開花,這也應了我之前在掘金 JTalk 上小菜對于長鏈路流通交易分享的一個觀點:鏈路足夠長,每個節點上都可以長出產品。那這些端產品都是與業務有強關聯的,還有更多技術基建的和服務于團隊內的產品,比如:

    • 大伯伯(諧音打包包) 實現 App 選倉庫選分支選環境配置的自主打包與推包系統
    • 大表姐(來自饑餓游戲,寓意開工沒有回頭箭) 實現 6 款 App 解包差分后下發熱更新包的發布系統
    • 姑奶奶 ?線上異常匯集分析與與 Bug 定級指派系統
    • 大舅子 向下調用微服務接口向上提供 GraphQL 查詢能力的數據聚合服務
    • RGB 用戶使用 App 的 PV/UV,以及業務數據監控相關的可視化平臺
    • 110 解決端異常收集與報警需求
    • 堂哥工作臺 團隊記錄資源分配與 redmine 同步的自動化周報系統
    • ITms 解決內部 App 安裝測試的配置生成和預裝服務
    • ...

    這些是服務于團隊內部的工具鏈,全部由小菜前端自行維護。到這里我們發現,在小菜這樣一家創業公司內,前端要服務的端和場景的確較多,但這些產品和工具的背后,整個前端組也就 10 個人而已(我們當然也求才若渴),但是人雖少,效率不能自我妥協,所以我們能服務到這些端,也正是基于端的多樣性和數量,我們稱自己:宋小菜大前端。

    先上小菜端上若干產品和工具的技術棧圖,幫助大家理解我們的技術理念:


    fe9c3cf9d488893e80cb4e5f306ed6c4024a88bd

    二、多端帶來的挑戰

    1. 【物理現狀】移動端的碎片化

    古典互聯網時代,因為要兼容 IE678 而痛苦不堪,Hack 黑魔法經驗基本代表前端水平,如今互聯網早已移動化,我們理想中的移動端開發,看上去是可以大膽使用新語法特性,只需要做好尺寸兼容就好了,但事實并非如此,不僅在移動端的瀏覽器不是如此,在移動端開發 RN App 也是如此,這是我們某一款 App 一段時間內,所收集上來的手機廠商分布:

    68a0fe308e7cacba2ab97a0e7a4f2cfecdb96748

    可以發現 Android 的碎片化非常嚴重,每一個廠商下面有不同時期推出的不同型號的手機,這些手機有著不同版本的操作系統,不同的分辨率和用電策略,不同的后臺進程管理方式和用戶權限,要讓一款 App 在哪怕頭部 40% 的手機上兼容,都是一件艱難的事情,這個客觀物理現狀疊加下面的社區現狀,App 質量保證這件事情會變得雪上加霜。

    2. 【社區現狀】技術框架的不穩定性

    回到本文的開頭,我們在長鏈路的 B2B 生鮮場景中,為了更快更輕,開發出 7 款 App,而且將來隨著業務場景的拓展會誕生更多獨立 App 甚至是集大成的 App,所以技術選型不太可能選擇原生的 Java/Object-C 開發,尤其對于創業公司,6 款 App 得需要多少名原生開發工程師才能搞定,高頻繁重的業務變化又怎樣靠堆人來保證?

    想清楚這些,一開始我們就調研 ReactNative,并最終全部從原生切換到了 RN,通過跑過來的這 3 年來看,使用 RN 為公司節約了大量的人力成本同時,也盡可能的滿足到幾乎所有的需要快速迭代的業務場景,又快又輕,成為宋小菜大前端團隊做事的一個典型特征。

    但換一個角度看,就是帶來的問題,又快又輕的背后是 RN 版本的飛速迭代,截止到目前,也就是 2018 年 6 月份,RN 還沒有推出一個官方的正式的長期維護的穩定版本,什么意思?就是 RN 目前依然處在不穩定的研發周期內,我們依然站在刀尖起舞,用不穩定的 RN 版本試圖開發穩定的應用,三年走過來,我們在 RN 的框架里,多少次面對舊版本局限性和新版本不穩定性都進退不得,舊版本的 Bug 可能會在新版本中修復,新版本引進則會來新版本自己的問題。

    除了 RN 自身版本,還有第二個問題,圍繞著 RN 有很多業界優秀的組件,但這些社區組件甚至官方組件,都不一定能及時跟進最新的 RN 版本,同時還能兼容到較老的 RN 版本,所以 RN 升級導致的組件不兼容性,會引發你 Fork 修改組件的沖動,但這樣會帶來額外的開發成本和版本維護成本,取舍會成為版本升降的終極問題。

    在國內開發,還有第三個問題,就是中文文檔缺乏,社區資源匱乏,參考文獻陳舊,可拿來主義的開源工程方案甚至社區線上線下會議分享都很缺乏,一個不小心就會踩坑,這就是 RN 社區的現狀,我們在刀尖浪花上獨步,App 選型背后的技術棧穩定性則成為懸在頭上的一把鍘刀,你不知道什么時候會咔嚓一聲。

    3. 【人才現狀】人員能力的長短不齊

    我們知道有一個詞叫做主觀能動性,表示沒有條件創造條件也可以上,這個詞的主體就是人,聊完移動端設備現狀和社區現狀后,我們來聊聊人的問題。RN 在國內真正開始普及使用,是從 2015 年開始,也就意味著,到 2018 年,一個 RN 工程師也就只有 3 年的工作經驗,而 RN 的 “Learn once, write anywhere” 也刺激著一切 Care 人員開支, Care 產品研發投入性價比的公司紛紛跳水研究 RN,爭搶 RN 人才,RN 是前端中的移動前端,前端有多搶手,那么 RN 工程師就比它還要搶手。

    這導致基本上 RN 工程師,很難靠外部招聘,只能靠內部培養,這也是小菜前端的成長歷程,我們有 2 名資深 RN 工程師,一個是從服務端 Java,一個是從原生 Android 開發轉過來的。如果 RN 人手不足,產品支持的力度和速度就一定會遇到瓶頸,這就是我們曾經面臨的問題,就是人才現狀,外招數量不足,內培速度有限,RN 工程師的數量和能力就時不時成為公司業務擴張的瓶頸。

    4. 【公司現狀】高密集業務的交付質量

    作為工程師,我們有很強的自尊心和不容挑戰的代碼潔癖,但在一個創業公司里面,甚至大公司的一個創業團隊里面,我們需要對接一些關鍵的業務節點,沖刺一些特定的時間窗口,并且要及時響應多變的業務,和業務背后多變的產品形態,這都會帶來非常密集的需求隊列。

    這些密集的需求隊列對我們的代碼實現質量有非常高的挑戰,一個組件用 5 分鐘思考如何抽象和用 50 分鐘思考,實現后的穩定性、兼容性都是不同的,如何保證產品按期交付上線,會是擺在我們面前一個非常關鍵的命題,而這個難題之外,還有一個更難的命題等著我們,那就是如何保證交付不延期的同時,還能保證交付質量。

    要知道,如果一個項目代碼趕的太毛糙,后期維護起來的成本會是巨大的,甚至只能用更高的成本重構重寫。本質上,再次重構就一定是公司在為早期的猛沖買單,為這些技術債買單,如何不去買單或者如何用最小的成本買單,這跟我們早期的業務密集程度,交付周期,質量把控有很大的關系。

    綜上,移動端碎片化所帶來的兼容難度,RN 框架的局限性,版本間差異帶來的不穩定性,技術社區資源的匱乏和前端團隊技術能力掣肘,再疊加上高密度的業務排期,讓前端開發這個本來很酷的事情,變得晴雨不定。

    這些避不開的現實,是繞不過去的坎兒,是搭建團隊必須搞定的基礎,我們想要把 B2B 生鮮的線上線下場景通過端產品關聯起來,想要通過前端團隊的用戶側輸出從而讓這些產品落地,就必須面對這些現實挑戰,而應對這些挑戰,首先必須搞清楚有哪些挑戰,搞清楚挑戰以后,我們就會認識到,首當其沖的事情,是去搭建 B2B 生鮮公司的前端技術棧和人才梯隊,現在我們進入到本文的重點。

    三、如何應對井噴的挑戰

    1. 前端梯隊如何搭建

    創業公司的技術團隊,本質上就是人和事,用合適的人搞定特定的事,人才的瓶頸就是這家公司產品落地速度和上線質量的瓶頸,因此人是第一位的,對于前端團隊來說,如何一步步形成有綜合戰斗力的團隊,取決于搭建什么層次的前端梯隊,如果所有人一視同仁,培養同樣的能力棧,發揮同樣的興趣向,跟進同樣的業務線,那么這個梯隊的扁平就會帶來致命的團隊瓶頸:能力可復制但不能互補,能力可遞進但很難跨越,不能互補和很難跨越會導致團隊內的技術路線過于單一,技術思維趨于固化,至于技術儲備的豐富性和技術溝通帶來的碰撞就更有限,最終導致人做事越來越機械化,甚至失去最初的技術初心。

    那么小菜前端到底如何搭建,還是要從公司的人員、業務和技術現狀出發,由于端的碎片化和技術框架的不穩定性,就必須在質量保障上投入巨大的人力保證產品可用,而人才能力局限性和數量的匱乏,就跟產品的質量保證成為了天然的矛盾,不可協調,代碼攛太快,線上天天都是 Bug,代碼攛太慢,產品節奏跟不上,至于跟工程師天天宣講要小心小心再小心,能起到的作用也不大,因為工程師本身的能力也是參差不齊的,所以就必須把團隊先拆成兩部分,一部分做基建支持,一部分做業務支持,基建支持的同學研發整個團隊的工具腳手架、抽象和打磨團隊的基礎通用組件、長期維護項目的通用架構,這些投入都會反哺到業務支持的同學,業務的同學可以放心大膽的基于基建的成果做上層業務開發,穩定的工程基礎有了保障,上層的業務代碼做質量保障難度就大大降低了。

    除了分出來人做基建,做業務,還需要有核心的技術骨干,做技術前瞻性的研究,為團隊 3 個月后,半年后,甚至 1 年后的技術方向,做必要的調研、測試和實驗性開發,因為對于刀耕火種的早期技術團隊,從原始人到邁向外太空跨空間作戰,這中間還差著很多個關鍵的技術迭代節點,這些關鍵的技術迭代節點,一部分是靠外招技術專家和資深的工程師來輸血發力,還有一大部分是需要靠團隊內部長期的積累沉淀,也就是人才內部培養。

    我們總結一下:

    • 基建的同學負責輸出工具系統、基礎組件、流程規范,保證內部效率最大化和質量的有效保障
    • 架構的同學負責攻克技術底層難點,調研先進技術,升級團隊技術架構,沉淀技術方案,鎖定和推進團隊未來技術方向
    • 業務的同學負責產品跟進,高頻使用基建產品,并通過反饋來優化團隊的技術基礎設施,同時基于業務來抽象更多的基建需求

    基建、架構、業務這三個角色并不是相互獨立,而是互有重合各有側重,一個業務的同學,可能也同時在負責基建的事情,一個基建的同學,可能也同時在參與架構的設計,在小菜就有同學以架構和基建為主,業務也時不時的參與開發,架構和基建必須依托于業務場景來做,不能脫離了場景,不然會輸出畸形的難以落地的技術方案。

    上面是人員的分工,還有三個重要的保障,這里不做引申,只列舉一下:

    • 團隊人員的興趣棧、能力棧和業務要盡量匹配
    • 團隊人員的階段性目標、長期規劃要跟進公司的職業晉升路線和能力模型
    • 團隊要有持續性的內部技術互動分享和對外的技術理念、方法方案分享

    小菜的前端是大前端,對人的要求是:一專多精多能,至少在某個領域內朝著專家方向走,同時要慢慢精通多項技能,最后是具備多個特定技術棧的開發能力,比如 ReactNative,在小菜就是一個必須具備的開發能力,不要求每一個同學都成為 RN 專家或者精通,但要具備業務開發的能力,通俗點描述,就是能用 RN 開發業務產品。

    最后一點,就是資源流轉,架構的同學,基建的同學和業務的同學的梯次關系是從下到上,越下越接近技術本質,越上越接近業務結果,越向下需要越好的技術實力,越向上需要越好的業務理解能力,這兩個能力都是核心能力,需要讓團隊成員沿著梯隊關系慢慢流動起來,業務中技術能力好的同學可以有機會沉下來做做基建,長期埋頭基建的同學可以有機會上去做做業務,業務理解不錯技術沉淀又好的同學可以繼續沉下去參與架構,這樣團隊內部的同學都可以有多樣性的技術場景和業務場景,一旦有同學請假、陷在別的業務不能抽調,馬上就有同學可以補位進來開發,不會影響到產品上線節點。

    關于團隊如何搭建,目前小菜是走到了這個算是 v1.0 的階段,未來還有更多挑戰,也會帶來更多的基于公司現狀的新調整,無論如何變遷,方法論我們先沉下來:

    • 人才梯隊要有層次:基礎架構、基建和業務上層等
    • 人才成長要有規劃:興趣棧、能力棧和公司關系
    • 人才能力要有擴展:單人能力和互補后的團隊能力

    以人為過程,以事為結果,人事之間要有動態的機制形成互惠互補的關系,只有這樣,團隊才會初心不變,激情常在。

    2. 如何做技術選型

    技術選型是一個行業老話題了,方法論也有很多,在小菜我們遵循的是:技術方向性預研大踏步,業務基建型開發小碎步,前者盡可能激進,后者盡可能保守,比如 數據報表系統,我們激進的采用 GraphQL 來解決 SQL => 頁面 Dom 的鏈路問題,在宋小福 App 上面,我們就求穩的采用 v0.48 的 ReactNative 版本,而不是用當時較新的 v50+ 版本。

    在做技術選型之前,還有一些比較重要的基礎性問題需要搞定,那就是團隊技術動作的一致性,這個一致主要包含兩點:

    • 代碼規范共用一套
    • 倉庫合作方式共用一套

    這兩點如果不一致,會給技術選型后的落地帶來內耗成本,千萬不可大意。

    再回到技術選型本身,拋開激進保守的大踏步和小碎步,我們需要回到技術本質和工程師的本質來看待如何選的命題,技術的本質是效率,工程師的本質是興趣,如果這一套技術選型不能帶來效率,如果工程師普遍不感興趣,那么通常這一個選型我們不會采納,我覺得這一個主觀一些的標準,大家可以參考,但這里面也要權衡好歷史包袱、維護成本,上手難度等這些客觀現實,如果一個新技術會帶來革命性的效率提升,那么即使有上手難度和維護成本,我們也會果斷入坑,比如 GraphQL 對于數據報表對于解放前后端有大幅度的提升,我們會果斷入坑大力推行,如果一個技術對于團隊是錦上添花,那么我們會慎重選用,比如 TypeScript,可以給工程穩定性帶來了較大的保障,但我們只選擇在熱更新這種 RN SDK 和 Server 端的去集成,而不是一下子推廣到整個團隊項目中鋪開用,這里面就會考慮到實際得到的好處,以及歷史包袱和上手難度,反復權衡后并沒有帶來更大的價值,所以這兩類場景的推行和不大力推行,就又不會太依賴于工程師的喜好興趣。

    那么我們技術選型后的結果是如何呢?

    文章最開始的那張圖,里面就是我們的技術棧,這里再做一下總結:

    • 工具類:強依賴 Node,多而雜的其他技術,如:MongoDB/Redis/MySQL/Shell/Python
    • 業務類:強依賴 React/ReactNative,適度集成其他技術,如: Redux/GraphQL/Apollo
    • 框架類:除了 React 全家桶會謹慎選擇,Node 端框架則相對寬松:Koa/Thinkjs/Eggjs

    這些相對求穩,不求穩的部分,如小程序開發,我們會使用 mpvue,也會用原生,還會集成進去 GraphQL,同時一些涉及到數據爬取和視頻圖像識別,我們也會集成 Python/C++/TenserFLow 等等,不過這些往往是前瞻性的技術嘗試,會讓團隊的同學適當分配精力持續研究。

    3. RN 的 App 工程如何架構

    小菜的主要產品類型,尤其是對外的產品,主要是 RN App,而且數量較多,那么 RN 項目的合理架構就變得尤其重要,我們這里探討下小菜前端在 RN App 上面的沉淀,涉及到原生層面的技術細節太多,這里暫不做討論。

    首先,我們在構建 RN App 工程時需要關注這幾個關鍵要素:

    • 配置管理
    • 靜態文件管理
    • 網絡請求
    • 組件管理
    • 路由管理
    • 數據緩存
    • App 的熱更新
    • 數據搜集

    __配置管理__是指可以靈活合理的管理 App 的內部環境,主要包括:

    • App 本身的一些配置
    • 所使用三方插件的配置

    我們在構建工程時盡量將所有的配置抽象統一放置在一個地方,這樣便于查找和修改,但是由于大多數配置都統一放在同一個地方,那么就難免有部分文件要使用某個配置時其引用路徑比較長,比如:



    import { pluginAConfig } from '../../../../../config'

    這樣就造成了閱讀性很差且代碼不美觀,因此我們可以使用 Facebook 的? fbjs ?模塊提供的一個功能 providesModule ?:

    //config.js
    /**
     * config for all
     * @providesModule config 
     * 使用 providesModule 將 config 暴露出去
     **/
    import pluginAConfig from './plugin_a_config'
    
    export default {
        pluginAConfig
    }
    
    // 然后在其他文件中調用
    // A.js
    import { pluginAConfig } from 'config'
    

    這樣就能很方便地在 App 的任意一處使用 config 了,但是我們要避免濫用 providesMoudle ,因為使用了 providesMoudle 進行聲明的模塊的源碼,想要在編輯器中使用跳轉到定義的方式去查看比較困難,不利于團隊多人合作。

    __靜態資源__泛指會被多次調用的圖片或 icon,我們一般在 RN 使用圖片時是直接引用的:


    import { Image } from 'react-native'
    
    render(){
      return (
        <Image source={{uri: './logo.png'}} />
      )
    }

    當圖片需要在多處使用時,我們可能會將這些可能會被反復使用的圖片統一管理到? assets ?文件夾中,統一管理和使用,但是當需要使用圖片資源的文件嵌套較深時,引用圖片就變得麻煩:


    render(){
      return (
        <Image source={{uri: '../../../../assets/logo.png'}} />
      )
    }

    這個問題與配置管理的問題一樣,可以首先將圖片資源按照類型進行分類,比如 assets 文件夾下有 button/icon/img/splash/svg 等,每一個類型的結構如下:

    - icon/
     - asset/
     - index.js

    其中? asset ?文件夾保存我們的圖片資源,在? index.js ?中對圖片進行引用并暴露為模塊:


    // 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} />
     ?)
    }
    

    這樣,我們就能很方便地將分散在項目各處的圖片資源統一到一個地方進行管理了,使用起來也非常方便。

    __網絡請求__這塊,react-native 使用 whatwg-fetch,我們也可以選在其他的三方包如 axios 來做網絡請求,但有我們在開發中遇到過一個問題,那就是我們明明已經在代碼里已經修改了 cookie, 但是每次請求可能還是會帶上之前的 cookie 從而造成一些困擾,所以這里推薦一個實用的組件 Networking :


    import { NativeModules } from 'react-native'
    const { Networking } = NativeModules
    
    // 手動清除已緩存 Cookie,這樣就能解決上述的問題了
    Networking.clearCookies(callBack)
    
    

    當然,Networking 的功能不止于此,還有很多其他有趣的功能可以發掘,可以直接用它來包裝自己的網絡請求工具,還支持 abort ,可以參考 源碼 來具體把玩。

    使用 RN 開發 App 本身效率就比較高,如果想要繼續進階就要考慮組件化開發,一旦涉及到組件化開發,就不可避免地會涉及到組件管理的問題,這里的__組件管理__比較寬泛,它實際上應該指的是:

    • 組件規范
    • 組件類型劃分
    • 組件開發標準

    組件規范指的是 UI 設計規范,我們可以與設計同學交流規定好一套特定的規范,然后將通用的樣式屬性(如主題顏色,按鈕輪廓,返回按鍵,Tab 基礎樣式等)定義出來,便于所有的組件開發者在開發時使用,而不是開發者各自為政在開發時重復寫樣式文件,這里推薦一個比較好用的用于樣式定義的三方插件 react-native-extended-stylesheet ,我們可以使用這個插件定義我們的通用屬性:


    // 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....
    

    這樣,我們就能在開發的任意插件或者 App 中直接使用這些基礎屬性,當某些屬性需要修改時只需要更新 mystyle 組件即可,還可以衍生出主題切換等功能,使得開發更加靈活。

    關于組件類型我們會拋開三方組件以及原生組件,因為一旦涉及到這兩者,需要寫的東西就太多了,我們將組件按使用范圍分為通用組件和業務組件兩大類。

    首先什么是業務組件?即我們在開發某個業務產品常用到的組件,這個組件綁定了與業務相關的一些特殊屬性,除了這個業務開發以外,其他地方都不適用,但是在開發這個業務時多個頁面會頻繁地使用到,所以我們有必要將其抽象出來,方便使用。

    什么是通用組件?即可以在 App 范圍內使用甚至于跨 App 使用的組件,這里可以對這個類別進行細分,我們將能跨 App 使用的組件上傳到了自己的搭建的私有 npm 倉庫,方便我們的 App 開發者使用,同時,具有 App 自己特色的組件則放到工程中統一管理,同樣適用 providesModules 暴露出去。

    制定一整套組件開發標準的是很重要的,因為很多組件開發可能是多人維護的,有一套既定的規范就可以降低維護成本,組件使用的說明文檔的完善也同樣重要。

    開發 App 就不可避免地會遇到如何管理頁面以及處理頁面跳轉等問題,也就是__路由管理__問題,自從 Facebook 取消了 RN 本身自帶的 Navigator 以后,許多依賴于這個組件的開發者不得不將目光投向百花齊放的社區三方組件,FB 隨后推薦大家使用的是 react-community 推出的 react-navigation?,現在這個路由組件已經獨立出來了。我們在開發時就是使用的這個組件作為路由管理組件,只不過是在其基礎上做了一些定制 ,使得使用更加簡單,部分跳轉動作更加符合我們的產品場景,推薦大家使用這個組件。當然,除去這個組件還有很多其他的組件可供選擇:

    路由管理作為整個 App 的骨架,它是這幾個部分中最重要的一部分,合理地定制和使用路由管理可以極大地簡化我們的開發復雜度。

    一般情況下需要緩存的數據基本上就可能是我們會在 App 很多地方都會使用到的全局數據,如用戶信息,App 設置(非應用層面的設置)等,RN 提供一個 AsyncStorage 存儲引擎,通常的使用方式是對這個數據引擎進行包裝后暴露出符合我們要求的讀寫接口。這里推薦另外一種使用方式:

    既然需要緩存的數據可能是會在 App 很多地方使用到的全局數據,那么我們可以將這些全局數據使用 redux 來進行管理,而利器 redux-persist 則能讓我們很優雅地讀寫我們的緩存數據。

    同時,如果對 react-navigation 進行合理的定制,接管其路由管理,那么我們還能實現保存用戶退出 App 之前最后瀏覽的頁面的狀態,用戶在下次打開 App 依然可以從之前瀏覽的地方繼續使用 App,當然,這個功能要謹慎使用!

    App 的版本更新,RN 除了傳統的 App 更新外還有一個熱更新的可選項(傳統 App 更新也有熱更新,其原理就不太一樣了),社區大多數人都推薦使用 codepush 來進行熱更新,至于其后端解決方案 貌似已經有了一個 code-push-server ,我們是使用自己的熱更新方案,其原理就是在不更新原生代碼的基礎上更新 JS 代碼和靜態資源文件。

    搜集的 App 使用數據(包括異常數據)并對此分析,根據分析來定位問題是保證 App 質量的有效手段之一。你可以選擇自己搭建一套數據搜集服務,包括客戶端 SDK 和服務端搜集服務,或者選擇市場上已有的工具,目前較為成熟的收據搜集工具比較多,如友盟,mixpanel, countly 等等,在此不作贅述。

    總結一下,一個 RN App 架構應該要保證 App 的運行穩定以及開發的便捷。運行穩定這一方面,除了從 JS 層面(如單元測試,JS 錯誤上報等)保證之外,很大程度上還要依賴于原生層面的處理,所以團隊里面要有同學的精力可以投在原生研究上面,至于開發便捷,我們盡量將復雜重要或者簡單繁瑣的操作在構建工程時就做掉,這樣也可以大幅度提高我們的開發效率,降低開發者之間的合作溝通成本。

    4. 效率協同工具如何打造

    效率協同往往不分家,效率寬泛一點,就是又快又好,協同寬泛一點,就是順滑無內耗,而且效率協同在不同的場景下,一定有不同的表現,所以效率協同一定要具體到某一個場景才有意義,比如:

    我們要發布 6 款 RN App 中的若干款,在一周內的若干天發布,由若干人自行打包測試自行發布,那么這里面就有巨大的協同問題,同時還有一些效率問題,如果一個同學進來改了 3 行接口調用代碼,他至少要有這幾個階段:

    • 開發階段本機切新分支調試
    • 測試階段打一個連接測試環境的包測試有效性
    • 測試完再打一個連接正式環境的本地包測正確性
    • 最后再打一個連接正式環境的用來熱更新的包進行發布

    那么多人之間都各自來做這個發布,就會出現一些發布沖突的協同問題,如果把發布權限全回收到某一個人,協同貌似能解決,但是會帶來效率問題,大家要讓這個發布人頻繁打包,或者打好的包,反復傳給發布人,發布人的時間線就被他人的開發進程給打斷了,變成了一個打包員,關于這個我專門做了一張圖:


    f17a037c8da60476a7e2f9e6554f610f6fe2e7e9

    這里面的一個圓點,就代表一個編譯后的包,比如 A 打出來的不需要 Debug 的連接正式環境的需要熱更新的 iOS 的 ipa 包,那么 A 的這個包,跟 B 打出來的不需要 Debug 的連接正式環境的需要熱更新的 iOS 的 ipa 包,即便是在同一個倉庫的同一個分支,也不能保證 100% 一模一樣的包,原因在于,這些本地打的包,還會受到 Node/NPM 版本(語義化),XCode 版本,原生熱更新版本控制等等因素影響,導致這個包自身很容易出問題,甚至是一些人肉引發的分支和人工上傳等等的影響,也會導致這個包發布出問題,舉一個我們真實發生過的故障,A 打完包,把包文件釘釘傳給 B,B 在發布的時候,選擇本地文件時候選錯了一個老版本直接發布上線,導致線上部分用戶直接版本回退,我們后來不得已采用緊急回滾,才把影響范圍控制住。

    上面大篇幅的介紹打包的這個場景,是小菜前端早期非常痛苦的一個場景,協同方式和規范無論我們如何三令五申總是避免不了人肉的問題,一旦出問題,就是大問題大故障,那么這時候,就必須投入基建的力量來打造一款或者一套流程工具,通過工具一勞永逸的解決這些主要的協同問題,把瑣碎人肉的事情交給機器去做,機器比人做的快,也比人做的好。

    我們來總結一下,團隊跑一段時間,一定會擠壓一些問題,這些問題不可以視而不見,也不可以拿業務支持第一這樣的借口來無限期推遲解決問題,而是時不時評估一下,有沒有可能通過系統和工具,來約束一些行為,來取代一些人肉工作,進而可以一勞永逸的解決掉一些問題,一旦決定去解決了,那么如何打造協同工具就變得順水推舟了,因為工程師最擅長的干的事情之一,就是造輪子造工具。

    小菜前端造了哪些輪子哪些工具呢,文章最開始就已經列出來了,這里再陳述和解釋一下:

    • 大伯伯(諧音打包包) 解決人肉打包帶來的協同問題
    • 大表姐(代號 Laurence - 來自饑餓游戲) 解決人肉發布、人工維護版本,問題追溯定位的效率問題
    • 姑奶奶 解決去多個三方平臺查看異常日志和 Bug 反饋指派的人肉效率問題
    • 大舅子 解決前后端耦合在 Restful/Mock/冗余的接口 的合作效率問題
    • RGB 解決純數字報表分析頁面訪問數據和用戶行為的效率問題
    • 堂哥工作臺 解決組員與 Leader 日報周報難回憶帶來的書寫效率和后期回顧問題
    • 小菜圖書館 解決小菜書架上面借書還書靠人肉記錄維護的效率問題
    • ...

    其中的大舅子這個單獨拿出來說一下,現在前后端常見的合作方式是基于 restful API 的接口合作,前后端經過一輪接口評審,后端再為前端寫 Mock 數據,可能還會加上一個 Proxy 服務,最終前端本地的頁面上,做 Mock 環境、測試環境和正式環境的切換,這種方式最大的問題有 2 個:

    • 前端比較依賴于后端的接口定義,后端為前端 Mock 做完后,前端才方便的進行頁面中的數據替換和邏輯判斷,有等待成本
    • 前端復雜多變的頁面會影響到后端的接口復雜度和體積,頁面上的字段增減,都會反映到接口的字段增減,接口本身變得不穩定,會帶來很多隱患點,比如接口體積越來越臃腫,或者接口有多個版本,一旦接口文檔更新沒跟上,會導致后期的同一個接口的不同版本之間,增加調用出錯概率等等

    當然業界也有各種各樣規避這些問題的策略,可能是文檔建設,可能是流程約束,小菜早期,哪怕到現在,也是在使用這種方式合作的,直到現在我們有了大舅子,前后端合作的方式開始進化,大舅子系統架構圖如下:


    54104c870c86d9dfe64ca21ab239be5d89636143

    大舅子目前的架構是放到網關下面,網關層做一些鑒權和安全的處理,向下把一個 GraphQL 的請求轉發給大舅子,大舅子上面根據這個 Query Type 對應的 Resolver 去調用下層的服務接口,下層可能是另外一個 GraphQL 服務,也可能是微服務,也可能是數據庫,兼容度很高,無論是哪一種,大舅子的角色扮演就是配置和聚合:配置客戶端上頁面對應的數據類型,嵌套關系和數據結構,向下連接和聚合不同的數據源。

    內部的開發正式環境關系圖如下:

    cd03cd7e9811f135e1821968a92aeca758ed882c

    這個事情并不新鮮,多年前,Nodejs 就在扮演數據聚合層的角色,把多個 API 聚合成一個 API,或者打散一些 API,聚合成新的 API,但本質上依然是向客戶端提供 API,這種 API 依然是面向頁面,可以看做是頁面驅動的 API,大舅子因為整個建?;A是 GraphQL,所以頁面和數據結合的權利,交給了客戶端自己去做,它需要什么數據,就在客戶端聲明什么數據結構,帶來的好處很多,這里列舉兩條我認為有價值的:

    • 前端可以不再局限于接口評審階段,可以繼續往前提到數據庫/表結構評審階段進入開發流程,在表結構評審期就能拿到字段定義與含義,從而再大舅子上提前定義前端自己的 Type 和 Resolver
    • 后端不再耽誤自己的時間為前端提供 Mock,也不再受頁面 API 的約束,可以下沉精力專心做下層業務領域能努力的建設,下沉的領域能力多大,那么端上可使用和組合的能力就有多大

    從此,塵歸塵,土歸土,前后因為頁面數據控制權的分離而解耦,也因為數據能力的回收而同時貼近業務,前端也被倒逼去了解業務,不再僅僅是界面和產品交互驅動,現在大舅子還在早期的迭代階段,關于它的好處和優化的空間還非常非常大,今天不做深入討論,我們來總結一下:

    小菜前端已經從工具基建中受益,因為工具帶來了協同和效率的優化只是結果之一,最重要的收獲還有兩個:

    • 解放了小菜前端團隊以及技術團隊的人肉時間,可以有精力做其他事情
    • 通過基建工具研發培養了小菜前端分析問題和解決問題的能力,同時沉淀了一些不錯的技術方案

    那么小菜的成長和沉淀,我們接下來就可以來總結一下了。

    四、技術成長和沉淀

    技術成長就是工程師的能力變化,我在 4 月份給大家做了一個 10 個月前后的能力評估,這 10 個月,是小菜前端 3 年來基建密度和團隊內調整最大的幾個月,也是團隊整體戰斗力提升最大的幾個月,本文的所有分析、策略和實際的解決辦法,也都是在這幾個月里面進行實施的,挑了幾個同學,挑了幾個主要的能力維度,我們感受下他們的技術成長,白色的 * 代表 10 個月之前的能力值,2 顆星代表可以熟練的開發,三顆星代表基本精通或擅長,四顆星是比較精通。

    6cc4b09811513e9c7e97ba7bb9f4b6b6d4b5f48a
    可以看到每個人都有不同程度不同層面的成長,有的全面開花,有的某些領域內快速積累,也要同學技術成長不多,但是協作能力工程能力有很大提升,其實還少了一個維度,就是參與業務拿到的結果或者說業務能力,圖上放不下了,稍后會做分析和補充,我們再來看下這些同學做的事情:

    6eb02eafba98155b595de9f66e2adb82900d3b77

    如果仔細比照一下,我們很容易得出三個結論:

    • 整個技術團隊綜合技術能力有大幅度的提升
    • 承擔職責越多的同學能力成長越多越快(如組員 A)
    • 承擔繁重基建和工具開發的同學比承擔業務開發的同學技術成長更多(如組員 E)

    業務能力沒有放到圖上,這是要補充的第四個結論

    • 承擔業務越多的同學,項目管理能力/溝通能力/業務理解能力也越好

    以上是人才成長,那么沉淀下來的內容一共是三部分:

    • 通用的工具技術解決方案
    • 通用的技術模塊和業務組件庫
    • 團隊整體的問題解決套路(分析解決問題的思維方式)

    通用的技術解決方案可以不斷的快速復用,比如我們宋小福用新架構前后調整優化有 1 個月,把這同一套架構放到麥大蔬上 2 周就夠了,再次遷移到新項目宋大倉里面只需要 1 周就搞定了。

    通用的技術模塊和業務組件庫,則是我們的組件三步走策略,首先是某個業務產品線下面的組件模板,比如 篩選組件或者列表組件,能在這個業務場景下的產品形態中通用,如果它可以跨產品線,那么就會躍升為 App 內通用組件,如果它還能繼續抽象具有可重用性,那么就可以躍升為跨 App 的通用業務組件,比如熱更新組件,地理位置定位組件,登錄組件,異常提示彈窗組件等等。

    團隊整體的問題解決套路,這個是我們最大的收獲,再直白一點,就是如何更快更好更有創造性的做事,這種思維方式,解決問題的套路,本質上是可以在團隊內不斷傳承的,無論我們后面遇到什么樣的業務和團隊問題,我們用這一套場景-技術-長短期投入產出比評估的路子,都能用較輕的方式把問題解決掉,這個對于我們培養新人有很大的幫助。

    五、對未來的展望

    小菜三年走過來,前端團隊從早期的技術和人員不穩定,到現在趨于穩定,站在公司的角度,最大的收獲就是培養和磨煉了一批有創業熱情,有擔當勇氣,有技術底蘊的一群人,這一群人抱團在一起,可以在所謂大前端這個框框內玩出更多的花樣,支持到更多的業務場景。

    站在今天看明天,雖然有很多東西對我們來說依然是未知的,但我們不再像過去一樣臨場發怯,手忙腳亂,取而代之的是無論多大多難的業務類型,我們都可以坐下來利用這幫人的智慧匯聚出一個最優選擇,胸有成竹的去做技術探索和工程嘗試,在跟公司一起成長變大的過程中,小菜前端也一定會沉淀出來更有實踐價值,更有效率的技術方案,而這些就是我們將來可推廣復用的寶貴技術資產,當然除了寶貴的技術資產,最最最重要的還有我們這群人,可以開心有趣有挑戰性的 Coding,想進一步了解我們團隊的可以 移步這里。 關于如何搭建高效率的生鮮B2B平臺,因為包含的內容較多,也很復雜,無法再一篇文章中給大家講清楚,本篇文章只是拋磚引玉,下面將分為多篇文章從行業現狀、業務現狀、產品概述、技術團隊搭建、服務端技術平臺搭建、前端開發等多個維度來講述,我們將三年多在B2B領域沉淀的核心產品和技術平臺公開,希望更多行業的人能深入了解,少走一些彎路,希望對大家有幫助,本系列文章分布如下(會繼續更新):

    1、《如何搭建高效率的生鮮 B2B 平臺(B2B 技術共享第一篇)》

    2、《宋小菜如何切入生鮮 B2B 市場(B2B 技術共享第二篇)》

    3、《生鮮 B2B 平臺的產品體系如何迭代(B2B 技術共享第三篇)》

    4、《生鮮 B2B 如何搭建高效的技術團隊(B2B 技術共享第四篇)》

    5、《如何從 0 到 1 搭建生鮮 B2B 的技術體系(B2B 技術共享第五篇)》

    6、《宋小菜技術如何應對生鮮 B2B 業務的快速變化(B2B 技術共享第六篇)》

    7、《生鮮 B2B 技術平臺的前端團隊該如何搭建(B2B 技術共享第七篇)》

    8、《宋小菜有關“能力”的設計和思考(B2B 技術共享第八篇)》

    9、《服務拆分的設計和思考(B2B 技術共享第九篇)》



    原文發布時間為:2018年06月09日
    原文作者:宋小菜技術
    本文來源:? 掘金? 如需轉載請聯系原作者


    • 0
      點贊
    • 0
      評論
    • 0
      收藏
    • 一鍵三連
      一鍵三連
    • 掃一掃,分享海報

    表情包
    插入表情
    評論將由博主篩選后顯示,對所有人可見 | 還能輸入1000個字符
    ??2021 CSDN 皮膚主題: 大白 設計師:CSDN官方博客 返回首頁
    實付
    使用余額支付
    點擊重新獲取
    掃碼支付
    錢包余額 0

    抵扣說明:

    1.余額是錢包充值的虛擬貨幣,按照1:1的比例進行支付金額的抵扣。
    2.余額無法直接購買下載,可以購買VIP、C幣套餐、付費專欄及課程。

    余額充值
    多乐彩