线下越重,线上须要越轻,这个轻指的是轻便轻巧和简洁易用,经过前面几章小菜技术与产品历史介绍,咱们了解到 B2B 生鲜领域在线下是如此之重,那么在交易场景线上化的过程当中,端的移动化就势在必行,试想一下,让菜市场摊位老板人手一台笔记本点开网页选购支付,让采购销售抱着电脑去拜访客户,一边聊蔬菜行情,一边打开笔记本进行记录,有没有一种回到世纪初的感受。javascript
产品的移动化,这将是咱们展开这篇文章的背景,咱们会先了解小菜的产品托管在哪些端上,而后感觉这些端带来的挑战,最后是咱们面对这些挑战所采起的策略,以及整个小菜前端团队历练后的技术成长和沉淀,和咱们对于本身的一个评估和对将来的展望,本文将采用最通俗易懂的方式陈述,会略有繁琐,但力求对技术新人也足够友好。前端
小菜早期围绕着蔬菜销地以客户集单批发的模式摸爬滚打几年,从上游的蔬菜供应商到下游批发市场的摊位老板,在这个长长的链路中,咱们诞生了这样几款线上产品来服务于不一样的人群和场景,以前文章中也有介绍,这里再汇总一下,共 7 款 App:vue
前 6 款 App 都是基于 ReactNative 开发的 iOS/Android App,最后一个是微信小程序,它们涵盖了公司几乎全部的协同场景和工做流,其余涉及审核、数据观测和过程管理的部分,则会进入到咱们 PC 端产品中,也就是:java
生鲜的 toB 场景,角色众多,链路冗长,这种延伸到产地农民,延伸到小 B 交易的管理系统必定会角色杂,权限多,操做重,业务复杂度所带来的页面复杂度不是通常的小系统可比拟。node
到目前为止,咱们已经看到小菜的 7 个移动端 App,以及一个复杂的后台管理系统,这些都跟前端工程师息息相关,除了这些,还有 2 个重要的内部产品,就是:react
其中大表哥(谐音:搭 Excel 表格)由前端工程师独立研发和维护的数据报表系统,单拎出来这个系统,是由于在 B2B 公司,尤为涉及到供应链的长链路场景中,真实业务数据的及时反馈对于每个执行团队都相当重要,没有这些数据抓手,就失去了多维度数据观测,都很难快速的作出正确的运营决策和业务调整,甚至很难发现业务中出现的漏洞和问题,好比不正常的非自助下单(也就是销售帮忙下单)的比例。ios
关于报表系统后文还有介绍,咱们再为前端增长一个服务的产品场景,就是微信生态内产品,好比公众号或者小程序,它的技术栈和运行环境跟原生 App 和 PC 都不一样,虽然小程序能够带来更多的业务可能性,也会对前端带来更大的挑战。git
咱们把这些端合并一下,小菜前端要服务的端或场景:github
端上所有开花,这也应了我以前在掘金 JTalk 上小菜对于长链路流通交易分享的一个观点:链路足够长,每一个节点上均可以长出产品。那这些端产品都是与业务有强关联的,还有更多技术基建的和服务于团队内的产品,好比:数据库
这些是服务于团队内部的工具链,所有由小菜前端自行维护。到这里咱们发现,在小菜这样一家创业公司内,前端要服务的端和场景的确较多,但这些产品和工具的背后,整个前端组也就 10 我的而已(咱们固然也求才若渴),可是人虽少,效率不能自我妥协,因此咱们能服务到这些端,也正是基于端的多样性和数量,咱们称本身:宋小菜大前端。
先上小菜端上若干产品和工具的技术栈图,帮助你们理解咱们的技术理念:
古典互联网时代,由于要兼容 IE678 而痛苦不堪,Hack 黑魔法经验基本表明前端水平,现在互联网早已移动化,咱们理想中的移动端开发,看上去是能够大胆使用新语法特性,只须要作好尺寸兼容就行了,但事实并不是如此,不只在移动端的浏览器不是如此,在移动端开发 RN App 也是如此,这是咱们某一款 App 一段时间内,所收集上来的手机厂商分布:
能够发现 Android 的碎片化很是严重,每个厂商下面有不一样时期推出的不一样型号的手机,这些手机有着不一样版本的操做系统,不一样的分辨率和用电策略,不一样的后台进程管理方式和用户权限,要让一款 App 在哪怕头部 40% 的手机上兼容,都是一件艰难的事情,这个客观物理现状叠加下面的社区现状,App 质量保证这件事情会变得雪上加霜。
回到本文的开头,咱们在长链路的 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 选型背后的技术栈稳定性则成为悬在头上的一把铡刀,你不知道何时会咔嚓一声。
咱们知道有一个词叫作主观能动性,表示没有条件创造条件也能够上,这个词的主体就是人,聊完移动端设备现状和社区现状后,咱们来聊聊人的问题。RN 在国内真正开始普及使用,是从 2015 年开始,也就意味着,到 2018 年,一个 RN 工程师也就只有 3 年的工做经验,而 RN 的 “Learn once, write anywhere” 也刺激着一切 Care 人员开支, Care 产品研发投入性价比的公司纷纷跳水研究 RN,争抢 RN 人才,RN 是前端中的移动前端,前端有多抢手,那么 RN 工程师就比它还要抢手。
这致使基本上 RN 工程师,很难靠外部招聘,只能靠内部培养,这也是小菜前端的成长历程,咱们有 2 名资深 RN 工程师,一个是从服务端 Java,一个是从原生 Android 开发转过来的。若是 RN 人手不足,产品支持的力度和速度就必定会遇到瓶颈,这就是咱们曾经面临的问题,就是人才现状,外招数量不足,内培速度有限,RN 工程师的数量和能力就时不时成为公司业务扩张的瓶颈。
做为工程师,咱们有很强的自尊心和不容挑战的代码洁癖,但在一个创业公司里面,甚至大公司的一个创业团队里面,咱们须要对接一些关键的业务节点,冲刺一些特定的时间窗口,而且要及时响应多变的业务,和业务背后多变的产品形态,这都会带来很是密集的需求队列。
这些密集的需求队列对咱们的代码实现质量有很是高的挑战,一个组件用 5 分钟思考如何抽象和用 50 分钟思考,实现后的稳定性、兼容性都是不一样的,如何保证产品定期交付上线,会是摆在咱们面前一个很是关键的命题,而这个难题以外,还有一个更难的命题等着咱们,那就是如何保证交付不延期的同时,还能保证交付质量。
要知道,若是一个项目代码赶的太毛糙,后期维护起来的成本会是巨大的,甚至只能用更高的成本重构重写。本质上,再次重构就必定是公司在为早期的猛冲买单,为这些技术债买单,如何不去买单或者如何用最小的成本买单,这跟咱们早期的业务密集程度,交付周期,质量把控有很大的关系。
综上,移动端碎片化所带来的兼容难度,RN 框架的局限性,版本间差别带来的不稳定性,技术社区资源的匮乏和前端团队技术能力掣肘,再叠加上高密度的业务排期,让前端开发这个原本很酷的事情,变得晴雨不定。
这些避不开的现实,是绕不过去的坎儿,是搭建团队必须搞定的基础,咱们想要把 B2B 生鲜的线上线下场景经过端产品关联起来,想要经过前端团队的用户侧输出从而让这些产品落地,就必须面对这些现实挑战,而应对这些挑战,首先必须搞清楚有哪些挑战,搞清楚挑战之后,咱们就会认识到,首当其冲的事情,是去搭建 B2B 生鲜公司的前端技术栈和人才梯队,如今咱们进入到本文的重点。
创业公司的技术团队,本质上就是人和事,用合适的人搞定特定的事,人才的瓶颈就是这家公司产品落地速度和上线质量的瓶颈,所以人是第一位的,对于前端团队来讲,如何一步步造成有综合战斗力的团队,取决于搭建什么层次的前端梯队,若是全部人一视同仁,培养一样的能力栈,发挥一样的兴趣向,跟进一样的业务线,那么这个梯队的扁平就会带来致命的团队瓶颈:能力可复制但不能互补,能力可递进但很难跨越,不能互补和很难跨越会致使团队内的技术路线过于单一,技术思惟趋于固化,至于技术储备的丰富性和技术沟通带来的碰撞就更有限,最终致使人作事愈来愈机械化,甚至失去最初的技术初心。
那么小菜前端到底如何搭建,仍是要从公司的人员、业务和技术现状出发,因为端的碎片化和技术框架的不稳定性,就必须在质量保障上投入巨大的人力保证产品可用,而人才能力局限性和数量的匮乏,就跟产品的质量保证成为了自然的矛盾,不可协调,代码撺太快,线上每天都是 Bug,代码撺太慢,产品节奏跟不上,至于跟工程师每天宣讲要当心当心再当心,能起到的做用也不大,由于工程师自己的能力也是良莠不齐的,因此就必须把团队先拆成两部分,一部分作基建支持,一部分作业务支持,基建支持的同窗研发整个团队的工具脚手架、抽象和打磨团队的基础通用组件、长期维护项目的通用架构,这些投入都会反哺到业务支持的同窗,业务的同窗能够放心大胆的基于基建的成果作上层业务开发,稳定的工程基础有了保障,上层的业务代码作质量保障难度就大大下降了。
除了分出来人作基建,作业务,还须要有核心的技术骨干,作技术前瞻性的研究,为团队 3 个月后,半年后,甚至 1 年后的技术方向,作必要的调研、测试和实验性开发,由于对于刀耕火种的早期技术团队,从原始人到迈向外太空跨空间做战,这中间还差着不少个关键的技术迭代节点,这些关键的技术迭代节点,一部分是靠外招技术专家和资深的工程师来输血发力,还有一大部分是须要靠团队内部长期的积累沉淀,也就是人才内部培养。
咱们总结一下:
基建、架构、业务这三个角色并非相互独立,而是互有重合各有侧重,一个业务的同窗,可能也同时在负责基建的事情,一个基建的同窗,可能也同时在参与架构的设计,在小菜就有同窗以架构和基建为主,业务也时不时的参与开发,架构和基建必须依托于业务场景来作,不能脱离了场景,否则会输出畸形的难以落地的技术方案。
上面是人员的分工,还有三个重要的保障,这里不作引伸,只列举一下:
小菜的前端是大前端,对人的要求是:一专多精多能,至少在某个领域内朝着专家方向走,同时要慢慢精通多项技能,最后是具有多个特定技术栈的开发能力,好比 ReactNative,在小菜就是一个必须具有的开发能力,不要求每个同窗都成为 RN 专家或者精通,但要具有业务开发的能力,通俗点描述,就是能用 RN 开发业务产品。
最后一点,就是资源流转,架构的同窗,基建的同窗和业务的同窗的梯次关系是从下到上,越下越接近技术本质,越上越接近业务结果,越向下须要越好的技术实力,越向上须要越好的业务理解能力,这两个能力都是核心能力,须要让团队成员沿着梯队关系慢慢流动起来,业务中技术能力好的同窗能够有机会沉下来作作基建,长期埋头基建的同窗能够有机会上去作作业务,业务理解不错技术沉淀又好的同窗能够继续沉下去参与架构,这样团队内部的同窗均可以有多样性的技术场景和业务场景,一旦有同窗请假、陷在别的业务不能抽调,立刻就有同窗能够补位进来开发,不会影响到产品上线节点。
关于团队如何搭建,目前小菜是走到了这个算是 v1.0 的阶段,将来还有更多挑战,也会带来更多的基于公司现状的新调整,不管如何变迁,方法论咱们先沉下来:
以人为过程,以事为结果,人事之间要有动态的机制造成互惠互补的关系,只有这样,团队才会初心不变,激情常在。
技术选型是一个行业老话题了,方法论也有不少,在小菜咱们遵循的是:技术方向性预研大踏步,业务基建型开发小碎步,前者尽量激进,后者尽量保守,好比 数据报表系统,咱们激进的采用 GraphQL 来解决 SQL => 页面 Dom 的链路问题,在宋小福 App 上面,咱们就求稳的采用 v0.48 的 ReactNative 版本,而不是用当时较新的 v50+ 版本。
在作技术选型以前,还有一些比较重要的基础性问题须要搞定,那就是团队技术动做的一致性,这个一致主要包含两点:
这两点若是不一致,会给技术选型后的落地带来内耗成本,千万不可大意。
再回到技术选型自己,抛开激进保守的大踏步和小碎步,咱们须要回到技术本质和工程师的本质来看待如何选的命题,技术的本质是效率,工程师的本质是兴趣,若是这一套技术选型不能带来效率,若是工程师广泛不感兴趣,那么一般这一个选型咱们不会采纳,我以为这一个主观一些的标准,你们能够参考,但这里面也要权衡好历史包袱、维护成本,上手难度等这些客观现实,若是一个新技术会带来革命性的效率提高,那么即便有上手难度和维护成本,咱们也会果断入坑,好比 GraphQL 对于数据报表对于解放先后端有大幅度的提高,咱们会果断入坑大力推行,若是一个技术对于团队是锦上添花,那么咱们会慎重选用,好比 TypeScript,能够给工程稳定性带来了较大的保障,但咱们只选择在热更新这种 RN SDK 和 Server 端的去集成,而不是一会儿推广到整个团队项目中铺开用,这里面就会考虑到实际获得的好处,以及历史包袱和上手难度,反复权衡后并无带来更大的价值,因此这两类场景的推行和不大力推行,就又不会太依赖于工程师的喜爱兴趣。
那么咱们技术选型后的结果是如何呢?
文章最开始的那张图,里面就是咱们的技术栈,这里再作一下总结:
这些相对求稳,不求稳的部分,如小程序开发,咱们会使用 mpvue,也会用原生,还会集成进去 GraphQL,同时一些涉及到数据爬取和视频图像识别,咱们也会集成 Python/C++/TenserFLow 等等,不过这些每每是前瞻性的技术尝试,会让团队的同窗适当分配精力持续研究。
小菜的主要产品类型,尤为是对外的产品,主要是 RN App,并且数量较多,那么 RN 项目的合理架构就变得尤为重要,咱们这里探讨下小菜前端在 RN App 上面的沉淀,涉及到原生层面的技术细节太多,这里暂不作讨论。
首先,咱们在构建 RN 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 ,如今这个路由组件已经独立出来了。咱们在开发时就是使用的这个组件做为路由管理组件,只不过是在其基础上作了一些定制 ,使得使用更加简单,部分跳转动做更加符合咱们的产品场景,推荐你们使用这个组件。固然,除去这个组件还有不少其余的组件可供选择:
react-navigation
进行深度定制的 react-native-router-flux路由管理做为整个 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 错误上报等)保证以外,很大程度上还要依赖于原生层面的处理,因此团队里面要有同窗的精力能够投在原生研究上面,至于开发便捷,咱们尽可能将复杂重要或者简单繁琐的操做在构建工程时就作掉,这样也能够大幅度提升咱们的开发效率,下降开发者之间的合做沟通成本。
效率协同每每不分家,效率宽泛一点,就是又快又好,协同宽泛一点,就是顺滑无内耗,并且效率协同在不一样的场景下,必定有不一样的表现,因此效率协同必定要具体到某一个场景才有意义,好比:
咱们要发布 6 款 RN App 中的若干款,在一周内的若干天发布,由若干人自行打包测试自行发布,那么这里面就有巨大的协同问题,同时还有一些效率问题,若是一个同窗进来改了 3 行接口调用代码,他至少要有这几个阶段:
那么多人之间都各自来作这个发布,就会出现一些发布冲突的协同问题,若是把发布权限全回收到某一我的,协同貌似能解决,可是会带来效率问题,你们要让这个发布人频繁打包,或者打好的包,反复传给发布人,发布人的时间线就被他人的开发进程给打断了,变成了一个打包员,关于这个我专门作了一张图:
这里面的一个圆点,就表明一个编译后的包,好比 A 打出来的不须要 Debug 的链接正式环境的须要热更新的 iOS 的 ipa 包,那么 A 的这个包,跟 B 打出来的不须要 Debug 的链接正式环境的须要热更新的 iOS 的 ipa 包,即使是在同一个仓库的同一个分支,也不能保证 100% 如出一辙的包,缘由在于,这些本地打的包,还会受到 Node/NPM 版本(语义化),XCode 版本,原生热更新版本控制等等因素影响,致使这个包自身很容易出问题,甚至是一些人肉引起的分支和人工上传等等的影响,也会致使这个包发布出问题,举一个咱们真实发生过的故障,A 打完包,把包文件钉钉传给 B,B 在发布的时候,选择本地文件时候选错了一个老版本直接发布上线,致使线上部分用户直接版本回退,咱们后来不得已采用紧急回滚,才把影响范围控制住。
上面大篇幅的介绍打包的这个场景,是小菜前端早期很是痛苦的一个场景,协同方式和规范不管咱们如何三令五申老是避免不了人肉的问题,一旦出问题,就是大问题大故障,那么这时候,就必须投入基建的力量来打造一款或者一套流程工具,经过工具一劳永逸的解决这些主要的协同问题,把琐碎人肉的事情交给机器去作,机器比人作的快,也比人作的好。
咱们来总结一下,团队跑一段时间,必定会挤压一些问题,这些问题不能够视而不见,也不能够拿业务支持第一这样的借口来无限期推迟解决问题,而是时不时评估一下,有没有可能经过系统和工具,来约束一些行为,来取代一些人肉工做,进而能够一劳永逸的解决掉一些问题,一旦决定去解决了,那么如何打造协同工具就变得顺水推舟了,由于工程师最擅长的干的事情之一,就是造轮子造工具。
小菜前端造了哪些轮子哪些工具呢,文章最开始就已经列出来了,这里再陈述和解释一下:
其中的大舅子这个单独拿出来讲一下,如今先后端常见的合做方式是基于 restful API 的接口合做,先后端通过一轮接口评审,后端再为前端写 Mock 数据,可能还会加上一个 Proxy 服务,最终前端本地的页面上,作 Mock 环境、测试环境和正式环境的切换,这种方式最大的问题有 2 个:
固然业界也有各类各样规避这些问题的策略,多是文档建设,多是流程约束,小菜早期,哪怕到如今,也是在使用这种方式合做的,直到如今咱们有了大舅子,先后端合做的方式开始进化,大舅子系统架构图以下:
大舅子目前的架构是放到网关下面,网关层作一些鉴权和安全的处理,向下把一个 GraphQL 的请求转发给大舅子,大舅子上面根据这个 Query Type 对应的 Resolver 去调用下层的服务接口,下层多是另一个 GraphQL 服务,也多是微服务,也多是数据库,兼容度很高,不管是哪种,大舅子的角色扮演就是配置和聚合:配置客户端上页面对应的数据类型,嵌套关系和数据结构,向下链接和聚合不一样的数据源。
内部的开发正式环境关系图以下:
这个事情并不新鲜,多年前,Nodejs 就在扮演数据聚合层的角色,把多个 API 聚合成一个 API,或者打散一些 API,聚合成新的 API,但本质上依然是向客户端提供 API,这种 API 依然是面向页面,能够看作是页面驱动的 API,大舅子由于整个建模基础是 GraphQL,因此页面和数据结合的权利,交给了客户端本身去作,它须要什么数据,就在客户端声明什么数据结构,带来的好处不少,这里列举两条我认为有价值的:
今后,尘归尘,土归土,先后由于页面数据控制权的分离而解耦,也由于数据能力的回收而同时贴近业务,前端也被倒逼去了解业务,再也不仅仅是界面和产品交互驱动,如今大舅子还在早期的迭代阶段,关于它的好处和优化的空间还很是很是大,今天不作深刻讨论,咱们来总结一下:
小菜前端已经从工具基建中受益,由于工具带来了协同和效率的优化只是结果之一,最重要的收获还有两个:
那么小菜的成长和沉淀,咱们接下来就能够来总结一下了。
技术成长就是工程师的能力变化,我在 4 月份给你们作了一个 10 个月先后的能力评估,这 10 个月,是小菜前端 3 年来基建密度和团队内调整最大的几个月,也是团队总体战斗力提高最大的几个月,本文的全部分析、策略和实际的解决办法,也都是在这几个月里面进行实施的,挑了几个同窗,挑了几个主要的能力维度,咱们感觉下他们的技术成长,白色的 * 表明 10 个月以前的能力值,2 颗星表明能够熟练的开发,三颗星表明基本精通或擅长,四颗星是比较精通。
能够看到每一个人都有不一样程度不一样层面的成长,有的全面开花,有的某些领域内快速积累,也要同窗技术成长很少,可是协做能力工程能力有很大提高,其实还少了一个维度,就是参与业务拿到的结果或者说业务能力,图上放不下了,稍后会作分析和补充,咱们再来看下这些同窗作的事情:
若是仔细比照一下,咱们很容易得出三个结论:
业务能力没有放到图上,这是要补充的第四个结论
以上是人才成长,那么沉淀下来的内容一共是三部分:
通用的技术解决方案能够不断的快速复用,好比咱们宋小福用新架构先后调整优化有 1 个月,把这同一套架构放到麦大蔬上 2 周就够了,再次迁移到新项目宋大仓里面只须要 1 周就搞定了。
通用的技术模块和业务组件库,则是咱们的组件三步走策略,首先是某个业务产品线下面的组件模板,好比 筛选组件或者列表组件,能在这个业务场景下的产品形态中通用,若是它能够跨产品线,那么就会跃升为 App 内通用组件,若是它还能继续抽象具备可重用性,那么就能够跃升为跨 App 的通用业务组件,好比热更新组件,地理位置定位组件,登陆组件,异常提示弹窗组件等等。
团队总体的问题解决套路,这个是咱们最大的收获,再直白一点,就是如何更快更好更有创造性的作事,这种思惟方式,解决问题的套路,本质上是能够在团队内不断传承的,不管咱们后面遇到什么样的业务和团队问题,咱们用这一套场景-技术-长短时间投入产出比评估的路子,都能用较轻的方式把问题解决掉,这个对于咱们培养新人有很大的帮助。
小菜三年走过来,前端团队从早期的技术和人员不稳定,到如今趋于稳定,站在公司的角度,最大的收获就是培养和磨炼了一批有创业热情,有担当勇气,有技术底蕴的一群人,这一群人抱团在一块儿,能够在所谓大前端这个框框内玩出更多的花样,支持到更多的业务场景。
站在今天看明天,虽然有不少东西对咱们来讲依然是未知的,但咱们再也不像过去同样临场发怯,手忙脚乱,取而代之的是不管多大多难的业务类型,咱们均可以坐下来利用这帮人的智慧汇聚出一个最优选择,成竹在胸的去作技术探索和工程尝试,在跟公司一块儿成长变大的过程当中,小菜前端也必定会沉淀出来更有实践价值,更有效率的技术方案,而这些就是咱们未来可推广复用的宝贵技术资产,固然除了宝贵的技术资产,最最最重要的还有咱们这群人,能够开心有趣有挑战性的 Coding,想进一步了解咱们团队的能够 移步这里。 关于如何搭建高效率的生鲜B2B平台,由于包含的内容较多,也很复杂,没法再一篇文章中给你们讲清楚,本篇文章只是抛砖引玉,下面将分为多篇文章从行业现状、业务现状、产品概述、技术团队搭建、服务端技术平台搭建、前端开发等多个维度来说述,咱们将三年多在B2B领域沉淀的核心产品和技术平台公开,但愿更多行业的人能深刻了解,少走一些弯路,但愿对你们有帮助,本系列文章分布以下(会继续更新):
一、《如何搭建高效率的生鲜 B2B 平台(B2B 技术共享第一篇)》
二、《宋小菜如何切入生鲜 B2B 市场(B2B 技术共享第二篇)》
三、《生鲜 B2B 平台的产品体系如何迭代(B2B 技术共享第三篇)》
四、《生鲜 B2B 如何搭建高效的技术团队(B2B 技术共享第四篇)》
五、《如何从 0 到 1 搭建生鲜 B2B 的技术体系(B2B 技术共享第五篇)》
六、《宋小菜技术如何应对生鲜 B2B 业务的快速变化(B2B 技术共享第六篇)》
七、《生鲜 B2B 技术平台的前端团队该如何搭建(B2B 技术共享第七篇)》