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

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

產品的移動化,這將是咱們展開這篇文章的背景,咱們會先了解小菜的產品託管在哪些端上,而後感覺這些端帶來的挑戰,最後是咱們面對這些挑戰所採起的策略,以及整個小菜前端團隊歷練後的技術成長和沉澱,和咱們對於本身的一個評估和對將來的展望,本文將採用最通俗易懂的方式陳述,會略有繁瑣,但力求對技術新人也足夠友好。前端

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

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

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

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

  • ERP 後臺管理系統

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

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

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

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

關於報表系統後文還有介紹,咱們再爲前端增長一個服務的產品場景,就是微信生態內產品,好比公衆號或者小程序,它的技術棧和運行環境跟原生 App 和 PC 都不一樣,雖然小程序能夠帶來更多的業務可能性,也會對前端帶來更大的挑戰。git

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

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

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

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

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

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

image.png | left | 747x545

2、多端帶來的挑戰

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

古典互聯網時代,由於要兼容 IE678 而痛苦不堪,Hack 黑魔法經驗基本表明前端水平,現在互聯網早已移動化,咱們理想中的移動端開發,看上去是能夠大膽使用新語法特性,只須要作好尺寸兼容就行了,但事實並不是如此,不只在移動端的瀏覽器不是如此,在移動端開發 RN App 也是如此,這是咱們某一款 App 一段時間內,所收集上來的手機廠商分佈:

image.png | left | 747x493

能夠發現 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 生鮮公司的前端技術棧和人才梯隊,如今咱們進入到本文的重點。

3、如何應對井噴的挑戰

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 行接口調用代碼,他至少要有這幾個階段:

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

那麼多人之間都各自來作這個發佈,就會出現一些發佈衝突的協同問題,若是把發佈權限全回收到某一我的,協同貌似能解決,可是會帶來效率問題,你們要讓這個發佈人頻繁打包,或者打好的包,反覆傳給發佈人,發佈人的時間線就被他人的開發進程給打斷了,變成了一個打包員,關於這個我專門作了一張圖:

image.png | left | 747x523

這裏面的一個圓點,就表明一個編譯後的包,好比 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 作完後,前端才方便的進行頁面中的數據替換和邏輯判斷,有等待成本
  • 前端複雜多變的頁面會影響到後端的接口複雜度和體積,頁面上的字段增減,都會反映到接口的字段增減,接口自己變得不穩定,會帶來不少隱患點,好比接口體積愈來愈臃腫,或者接口有多個版本,一旦接口文檔更新沒跟上,會致使後期的同一個接口的不一樣版本之間,增長調用出錯機率等等

固然業界也有各類各樣規避這些問題的策略,多是文檔建設,多是流程約束,小菜早期,哪怕到如今,也是在使用這種方式合做的,直到如今咱們有了大舅子,先後端合做的方式開始進化,大舅子系統架構圖以下:

image.png | left | 747x429

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

內部的開發正式環境關係圖以下:

image.png | left | 747x636

這個事情並不新鮮,多年前,Nodejs 就在扮演數據聚合層的角色,把多個 API 聚合成一個 API,或者打散一些 API,聚合成新的 API,但本質上依然是向客戶端提供 API,這種 API 依然是面向頁面,能夠看作是頁面驅動的 API,大舅子由於整個建模基礎是 GraphQL,因此頁面和數據結合的權利,交給了客戶端本身去作,它須要什麼數據,就在客戶端聲明什麼數據結構,帶來的好處不少,這裏列舉兩條我認爲有價值的:

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

今後,塵歸塵,土歸土,先後由於頁面數據控制權的分離而解耦,也由於數據能力的回收而同時貼近業務,前端也被倒逼去了解業務,再也不僅僅是界面和產品交互驅動,如今大舅子還在早期的迭代階段,關於它的好處和優化的空間還很是很是大,今天不作深刻討論,咱們來總結一下:

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

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

那麼小菜的成長和沉澱,咱們接下來就能夠來總結一下了。

4、技術成長和沉澱

技術成長就是工程師的能力變化,我在 4 月份給你們作了一個 10 個月先後的能力評估,這 10 個月,是小菜前端 3 年來基建密度和團隊內調整最大的幾個月,也是團隊總體戰鬥力提高最大的幾個月,本文的全部分析、策略和實際的解決辦法,也都是在這幾個月裏面進行實施的,挑了幾個同窗,挑了幾個主要的能力維度,咱們感覺下他們的技術成長,白色的 * 表明 10 個月以前的能力值,2 顆星表明能夠熟練的開發,三顆星表明基本精通或擅長,四顆星是比較精通。

image.png | left | 747x343

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

image.png | left | 747x420

若是仔細比照一下,咱們很容易得出三個結論:

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

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

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

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

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

通用的技術解決方案能夠不斷的快速複用,好比咱們宋小福用新架構先後調整優化有 1 個月,把這同一套架構放到麥大蔬上 2 周就夠了,再次遷移到新項目宋大倉裏面只須要 1 周就搞定了。

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

團隊總體的問題解決套路,這個是咱們最大的收穫,再直白一點,就是如何更快更好更有創造性的作事,這種思惟方式,解決問題的套路,本質上是能夠在團隊內不斷傳承的,不管咱們後面遇到什麼樣的業務和團隊問題,咱們用這一套場景-技術-長短時間投入產出比評估的路子,都能用較輕的方式把問題解決掉,這個對於咱們培養新人有很大的幫助。

5、對將來的展望

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

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

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

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

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

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

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

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

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

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

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

相關文章
相關標籤/搜索