简介: 本文对过去十年 CBU 在研发方式和技术架构上的探索做一个简要的回顾总结,以及对未来的展望。
前言
CBU作为集团内最早成立的几个BU之一,有着多年丰富的业务沉淀,而CBU的技术也伴随着业务一起不断地演进和成长着。从PC时代的WebX到如今的Serverless,CBU的研发体系经历了多次变革,在不同的阶段中有着不同的特点。笔者所在的团队近年来一直在负责前台场景研发体系升级相关的工作,在这期间也对过往模式的演变进行了大量的回顾和分析,希望能够通过本文对过去十年中CBU在研发方式和技术架构上的尝试和探索做一个简要的回顾和总结,重新审视我们所走过的路,同时也对未来的方向做一些探讨和展望。
青铜时代(2010~2013)
10年前的互联网,移动终端还没有兴起,绝大多数的产品都是为PC用户所服务的。在这种背景下,采用B/S结构是一种毋庸置疑的选择,因此当我们回顾这个时代的技术时,最先能想到的自然是那些和WEB、浏览器关系最密切的关键词:比如WebX、jQuery、Velocity等等。
在这个阶段,业务流量并不巨大,系统的性能瓶颈基本集中在数据库的读写上,大部分的应用仍然采用单体式的架构,从前台页面到后台逻辑都封装在同一个应用中,而在应用内部,往往是采用MVC的分层思想对不同功能的模块进行划分。彼时CBU的前台应用架构也基本是这个思路,页面通过Velocity模板进行开发,后台业务逻辑则封装成应用中单例的Service实现,中间通过一个类似Controller的粘合层进行连接,将后端的数据字段转换成前端模版中所使用的变量:
这种模式的优点是,由于所有的模块都在同一个应用中,非常便于集中管理,当一个开发同学非常熟悉整个应用结构时,他便可以非常快速地完成一整个需求的开发。但缺点也同样明显:随着业务的发展,前台逻辑变得越来越复杂,需求必须要拆解成前后端分离的方式,让专人做专事,而前台代码被耦合在应用中,使得前后端分离开发变得异常困难;除此之外,前台逻辑的变化往往是非常频繁的,如果每次修改一个页面元素都要发布整个应用,不仅研发效率会十分低下,还会影响线上业务的稳定性。
为了解决上述问题,当时CBU的同学们充分利用了Java的动态类加载机制以及Groovy脚本语言,以一种特殊的方式实现了前后端分离开发和快速迭代,这里我们以商品详情场景为例解释一下其机制和原理。
首先,一张页面被拆分成若干个组件,每个组件都会对应一个bundle,这个bundle中包含了前台的vm模板,js代码,以及一个Groovy脚本。在实际研发时,需要先通过一个映射表达式声明该组件所需要消费的后台模型或字段,然后通过Groovy脚本(相当于Controller层)将其转换为vm模板中的变量,接着便可以开发前台的vm模板和js逻辑。开发完毕后,通过一个定制的发布系统,便可以把对应的bundle发布到前台应用中,由应用内部的JVM动态加载Groovy脚本以及vm模板,完成需求功能的上线。下图便是一个使用这套研发体系开发需求的实际例子:
这套研发体系通过JVM动态加载的能力,将面向前台的View层和Controller层逻辑抽离出来,使其能够进行独立开发和动态发布,从而实现了前后台逻辑之间的解耦,提升研发效率。只要后台逻辑没有大的变更,很多需求都可以通过bundle快速开发上线。不过在实际运行时,所有的逻辑仍然是在同一个应用中执行的,这在一定程度上会带来一些安全隐患。除此之外,这套研发体系也是非常定制化的,bundle的发布系统实现非常沉重,并且对应的前台应用有强绑定关系,这就意味着很难将它快速地复制到另一个业务场景中复用(CBU最终只有商品和店铺两个业务落地了类似的模式)。
尽管存在着一定的问题,但即便以现在的眼光来审视,也不得不承认这套研发体系有着非常超前的设计思路。尤其是通过引入bundle这一概念,使业务迭代开发变得十分聚焦。在本文的后续章节中我们会看到这一思路最终将伴随着云原生技术革命,再一次回到我们的视野当中。
蒸汽时代(2014~2018)
这一阶段,互联网行业的形态发生了非常巨大的变化。随着智能手机的流行和普及,移动互联网迅速崛起,各种各样的业务都开始向移动端发力。集团发动ALL IN无线的战役,大量的业务和产品需要快速向移动端迁移。同时,随着智能手机市场的不断下沉,加上其“随时随地”都能使用的特性,互联网业务此时所需要应对的流量挑战和PC时代将不再是同一个数量级。
在技术侧我们也能看到与上述现象所匹配的变革。一方面,由于流量的激增和系统复杂度的增加,传统的单体式应用无法再支撑业务的发展,随着Docker这一关键技术的出现,服务端应用的分布式拆分和微服务化成为不可阻挡的趋势。另一方面,由于移动端崛起,前台展示突破了PC键鼠交互以及浏览器能力的限制,用户对于产品体验和交互的要求势必会变得更高,这促使研发人员进一步细分化为负责底层业务逻辑的服务端研发和负责前台展现交互的前端、客户端研发:React的出现敲响了传统WEB技术的丧钟,开发独立APP成为拓展业务的不二选择,前端技术和客户端技术在这一阶段开始飞速发展。
这样的背景下,单体式应用和MVC架构逐渐死去,前后端分离的架构模式和Restful API登上历史舞台,每个细分领域的技术栈都在飞速成长,大型软件的开发流程从此将会面对更加复杂的协作和研发模式。
回到CBU本身,这一阶段技术上最重要的任务就是将原本PC上的业务快速地迁移到无线终端上去,因此成立了专门的无线团队,开始重点打造手机阿里APP。整体思路非常简单明了,原有的业务体系和逻辑保持不变,进行微服务化改造,以RPC形式对外提供核心业务能力;架构上增设无线服务层,面向APP进行业务逻辑的适配和封装,通过集团统一对外网关提供Restful API给客户端及前端开发人员使用。这样就可以在基本不影响已有业务体系的条件下,让APP上的业务快速跑起来。无线服务端在这里所扮演的角色非常类似MVC架构模式中的Controller层:通过RPC与底层基础业务交互,然后叠加面向无线侧的特殊业务逻辑,最终对数据结构进行一定的处理和封装,通过集团对外的无线网关透出给前台客户端使用:
在此模式下,无线服务端和客户端研发人员扮演着十分重要的角色,他们的研发和协作模式将最终决定APP的迭代速度以及质量。接踵而至的新挑战催促着CBU的工程师们对已有的研发体系进行全面的升级,而最终他们给出了十分精彩的答案:轻服务和场景搭建两大技术应运而生,接下来我们会看到,这两者结合所产生的奇妙化学反应,将会给前台场景的研发模式带来一次重大的突破。
轻服务平台
如上文所述,在ALL IN 无线的时代,无线服务端的研发同学们需要在已有的基础业务接口上进行大量的改造和封装,为无线APP端提供服务接口。而在微服务架构下,服务端要对外透出接口,一般需要在应用内编写RPC服务,然后通过集团的无线网关将对应的RPC服务暴露成集团APP可以调用的HTTP接口:这种方式下一个服务从开发到上线往往需要数天时间。而为了保证客户端功能的快速迭代,避免业务受到发版节奏的影响,很多简单逻辑往往会被上行至服务端处理,这就对无线服务端的迭代速度和灵活性提出了一个非常高的要求。既有的技术生产力不能满足业务诉求,那就势必要进行创新,于是便诞生了能够支撑快速敏捷开发的轻服务平台,代号为MBOX。以今天的视角来看,这一平台践行的便是当下非常火热的Serverless理念,并为服务端同学提供了FaaS(Function as a Service,函数即服务)的能力。
MBOX平台依然采用了动态类加载机制来实现代码的热更新,并结合字节码技术提供了一个JVM内的“安全容器”,把Java语言的动态化特性运用到了极致,其架构理念和实现原理如下图所示:
通过配套的研发平台和发布系统,开发者可以将自己编写的一个类动态加载进线上应用的MBOX容器中,并创建一个单例对象;各种常见中间件如RPC和缓存能力,都可以通过注解进行声明注入并使用;而服务一经发布,便可以通过指定的Gateway访问到。这种无需配置、开箱即用、快速上线的轻服务迭代方式,非常适用于当时无线服务端所面对的开发场景:对现有的业务RPC服务进行组合编排,再加上一些面向APP端的简单处理逻辑,使用MBOX便可以在几小时内完成从开发到上线的整个流程,生产力得到了极大的提升。
场景搭建
早在PC时代CBU就已经建设了页面搭建相关的技术产品,而在无线端,这一命题实现起来却要复杂许多。首先,客户端的页面并非像前端一样,由标准的浏览器所承载,iOS和Andorid双端从底层的系统机制到上层的组件实现都完全不同,要想实现统一的页面搭建,势必需要抹平这层差异。其次,场景搭建并不是简单的堆砌组件,还需要考虑每个组件背后的数据源:来自各种应用的服务接口必须和组件解耦,而不能在组件内部通过Native逻辑实现,否则将会导致组件完全丧失复用性,并且使业务迭代更加依赖发版。
为解决上述问题,各端的工程师付出了诸多努力。首先是制定多端差异的抹平和融合方案,该方案从各端组件化渲染方案进行抽象,统一了一套相对抽象、可扩展的协议,包含页面协议、布局协议和组件协议三大部分。页面协议指定了当前页面的基本信息、页面主体结构、埋点信息、渲染方式;布局协议指定了该布局下所有组件的布局方式,同时以布局容器可支持组件abtest、组件分流、组件个性化等投放方式;组件协议细化到组件的基础属性、渲染方式,除此之外,还会定义组件的数据绑定行为、数据请求方式、数据取数方式,从而将组件UI和数据解耦,提升组件复用性和可维护性。
Android、iOS双端分别面向这套标准协议,对端上的多种渲染方案和Native能力进行封装,提供了统一的搭建容器实现,抹平了多端渲染的差异。
在此基础上,前台的开发/运营就可以通过搭建和配置化的方式,构建出前台页面的渲染协议(页面协议+布局协议+组件协议),该协议最终被上行至服务端的“渲染网关”节点,由其来收口所有搭建场景中协议的下发。除了协议下发之外,渲染网关还收口了所有组件的取数逻辑,通过一个通用的数据网关接口来统一前台组件的取数方式,让整个搭建体系变得更加简洁和标准。
构建完整的场景搭建体系是一项浩大的工程,其中包含着无数研发人员的智慧结晶,受限于篇幅本文不再过多展开,想要了解更多的朋友可以参考我们之前的系列文章:
- 《CBU场景运营建设实践与探索》
- 《CBU端容器标准化方案》
敏捷研发体系
在场景搭建体系中,渲染网关对外封装了统一的取数接口,前台的组件将会通过这个接口直接消费后台的服务端数据源,也就是一套重后端的方案(主要逻辑在服务端实现),因此在实际落地当中,往往需要为每个组件独立开发一个专属的数据源,这些数据源基本是对已有的RPC服务进行简单调用,然后封装一些前台相关的逻辑,因此使用轻服务来解决再合适不过了。于是两者相互结合形成了一套非常敏捷的研发体系:前端开发者开发UI组件,后台开发者通过MBOX编写一个轻服务,快速适配生成数据源,两者通过搭建进行简单的配置化绑定,一个页面就完成了,十分高效。正是这样敏捷的研发体系,帮助CBU快速地开拓了无线战场。
营销会场类页面是应用这一研发体系的典型场景,我们以某行业导购会场为例来体验其研发流程:
在这种研发体系下,前端和客户端研发人员可以专注于开发自己的组件,而服务端研发人员则可以使用轻服务的方式快速为对应组件适配封装对应的数据源接口(或者是编写传统的RPC服务),得益于搭建平台对组件和数据源的标准抽象,双方的研发流程可以互相解耦,让整个研发体验变得更加专注和高效。而采用这种前后端分离的模式之后,各端的技术能力和架构将得到更加聚焦的打磨,因此我们在之后将看到前台组件和后台数据源的研发模式都会出现新的突破。
总之,新的研发体系大大提升了前台场景的研发效能,这离不开背后的两大关键技术突破 —— 场景搭建体系和轻服务平台。而在此之中,又蕴含着无数工程师智慧和汗水的结晶,是他们面对未知时的勇气和坚持探索的热情成就了这些伟大的技术产品,并为CBU研发体系的演进之路立起了一座新的里程碑。
向开拓道路的先驱者们致敬。
摩登时代(2019~2020)
故事还在继续。最近两年,移动互联网已经进入下半场,随着时间的推移,既有业务模式演变的越来越复杂,同时也越来越成熟,而在此基础上,又有着诸多新的赛道被开拓,越来越多的竞争对手走上了跑道。我们看到了航母级APP在一次次的打磨和历练中竣工并启航远征,各种新的业务场景像停靠在甲板上的一架架舰载机,随时准备以极快的速度起飞。总的来说,已有业务完成了野蛮生长,逐渐步入需要更多精细化打磨的阶段,而更多新兴的业务场景则需要通过借助既有的沉淀,用比以前更快的速度跑起来。
而在技术侧,职能细分化使得各端的技术栈在过去几年里都得到了相当大的突破:在前台展示方面,无论是前端还是客户端,组件化研发都已经成为基本共识,并且技术方案也高度成熟,甚至出现一些能够根据UI智能还原生成组件的技术。而在后端和运维方面,随着Kubernetes一统容器编排,云原生理念被迅速引爆,大量的底层运维和中间件能力被再一次下沉,以FaaS为代表的Serverless技术手段带来了生产力的极大提升,让上层人员能够更加关注业务逻辑。对于大部分的普通业务场景,前后端技术都已经实现了一定程度的开放化:前端可以通过Serverless能力来快速编写服务端接口,后端也可以通过低代码和可视化方案开发前端组件,这都象征着对应技术栈的高度成熟化。
在上一个阶段中,我们通过搭建体系+轻服务的方式,打造出了一套能够敏捷迭代的高效研发体系,帮助CBU快速完成了无线业务的布局,但在“野蛮生长”过后,也开始逐渐暴露出一些问题,其中最为重要的是以下几点:
- FaaS服务带来了非常快的迭代速度,也造成了服务的快速膨胀,导致整体业务逻辑非常的分散,同时也进一步加剧了系统的复杂度。
- 轻服务平台的底层架构仍然是基于JVM实现,无法实现精细化的资源隔离和弹性伸缩,随着使用范围的不断扩大,性能和稳定性问题日益凸显。
- 现有的研发体系虽然灵活度很高,但是有一定的上手和学习成本,并且各个平台之间的割裂感非常明显,仅仅是通过一些约定连接在一起。
针对于以上问题,我们进行了大量的讨论和分析(详细可见前文《CBU Serverless 研发体系 FY20 S2 建设总结》),并贴合实际业务诉求和业界技术的发展情况,制定出了以下的策略:
- 按照领域驱动设计的思路,对服务进行分层,从而有效梳理整体系统结构,同时对各类数据源进行标准化的定义和描述,制定统一规范来治理复杂度。
- 轻服务平台底层架构进行升级,对接集团Serverless基建,全面拥抱云原生,释放技术红利。
- 以搭建体系为核心,对现有的工程能力和研发平台进行系统化整合,打造一套面向前台场景的标准化解决方案,让后续类似场景的研发变得易理解、易上手、易维护。
下面笔者将分别为大家介绍每一个策略的具体实现方案。
MBOX + FunctionCompute:打造真正的云原生FaaS解决方案
前文提到过,CBU在很早的时候就开始大规模应用落地轻服务平台MBOX,经过几年的沉淀,这种FaaS形式的服务已经几乎渗透进我们的每一条业务线,带来了显著的研发提效,MBOX这一技术产品也在经过多次打磨后变得越来越成熟。
与此同时,我们也一直在关注着业界和集团内对于Serverless架构的最新落地方案,期望能够将Runtime层的实现从JVM容器升级为真正的Serverless容器,实现更安全的资源隔离和弹性伸缩能力。这个财年,我们和阿里云函数计算(Function Compute,下文简称FC)团队的同学并展开了合作,经过近一个季度的打磨和试错,完成了MBOX平台与FC函数运行时的整合,为服务端的研发同学打造出了一套将大量历史经验和最新技术方案相结合的标准FaaS解决方案。
在这套方案中,最大的变革来自中间件能力的下沉,得益于各种中间件能力的sidecar化,上层的业务应用可以变得十分轻量,从而具备了快速部署和弹性伸缩的条件。在此基础之上,FC团队结合集团的基建,提供了成熟的函数运行时容器,支持函数级别的资源隔离和弹性伸缩,实现真正的Serverless能力。最终,我们将经过多年沉淀的MBOX编码方式和新的中间件调用方式进行了高度整合和优化,面向研发人员提供一套非常高效的业务FaaS编程框架和配套的预览调试插件,真正做到开箱即用的研发体验。整体方案架构如下图所示:
和传统的应用相比,这套函数应用方案十分轻量,可以实现快速迭代,同时还可以享受Serverless的红利,无需关心资源运维。而相比于原有的MBOX轻服务方案,又有着更高的扩展性和安全性。
建设规范化的数据源体系
在前后端分离的研发模式下,通常将为前台组件提供数据的服务接口统称为“数据源”,在之前的研发体系中,任何形式的服务接口都可以注册成为组件的数据源,并没有任何的规范或者标准,最终随着时间的流逝,体系中的数据源数量飞速增长,难以维护。经过分析后,我们认为出现这种现象的主要原因有以下几点:
- 大量一次性数据源的产生。我们可以看到,前台组件往往无法直接消费现有服务,那么只能通过服务端消费已有服务进行二次封装的方式来提供数据源。这种数据源基本都是为组件所定制,根本没有复用性可言,但又会大量存在和膨胀。
- 数据源没有做好分层,通用的底层服务和面向组件的一次性数据源散落在一起,在这种模式下,研发人员通常不会有意识地对自己的业务服务进行收拢和沉淀,往往是即用即写(甚至复制粘贴),最终整个体系下的数据源变得越来越混乱和难以管理。
- 超过90%的数据源都没有文档和说明,对于使用方来说,往往只能通过口口相传的方式来了解自己想要的服务究竟可以“找谁获取”,这种完全依靠经验的研发协作方式效率是非常低下的,沟通成本极高。
- 数据源的研发体验十分糟糕。要消费已有数据源,通常是编写一个FaaS脚本,要么通过传统应用再封装生成一个新服务再通过网关暴露。这两种方式的研发体验都泛善可陈,前者因为是泛化调用所以没法使用编码提示,后者则需要面对引入二方库带来的冲突和缓慢的部署速度,再加上没有文档,研发同学在开发代码时的体验可想而知。
为了解决上述问题,我们在现有的混沌局面之上建立了一套新的分层标准和规范,并提供了一系列新的工具和能力切面,逐渐形成了一套全新的数据源体系,并命名为“奇点”,下面我们来看一下奇点是如何解决以上问题,又带来了那些新的能力:
第一步,对数据源进行分层和标准化。
通过对历史经验的归纳总结,我们将各类数据源进行了分层,并对每一层的数据源进行了标准化的抽象:
值得一提的是,我们将原来很多专门为前台组件适配数据逻辑的轻服务脚本从数据源中剔除了出去,单独抽象了“字段映射”的脚本层,避免这些一次性的服务污染整个数据源体系。
我们为开发者提供了一系列的插件,可以从服务端的代码定义中抽取出这些数据源的定义并进行标准化封装,然后注册至奇点的后台数据库。随着底层开发同学的逐步接入,我们便可以慢慢建立起一个更加清晰和标准的数据源体系。
第二步,增加能力切面,让所有数据源变得可理解、可编码。
在第一步的基础上,我们还要彻底解决数据源的使用问题,首先要让数据源变得可理解,目前奇点通过javadoc扫描源代码注释的方式抽取所有服务的出入参定义及说明,并适配成标准的swagger开源协议,导入到RAP平台(由阿里开源的API文档平台)形成文档,在此基础上我们还会通过特定方式采集服务的一些真实样例,这样任何人都可以快速理解一个数据源的具体含义和使用方式,彻底改变之前口口相传的低效协作方式。
接着还要进一步简化和规范数据源的使用方式,这里先说说面向服务端侧,奇点提供了一套通用的调用桩SDK,通过引入该SDK,只要知道数据源在奇点平台中的签名(即唯一标识符)就可以快速创建一个调用桩,并可以通过该调用桩进行泛化调用,完全不需要感知底层服务的类型,也无需引入任何其他依赖。考虑到泛化调用方式在开发时无法实现代码提示,体验比较糟糕,我们还制作了一套IDE中的辅助插件,这个插件通过扫描源码时所记录的出入参字段结构,可以在指定的工程中生成对应的DTO类定义,再加上一些序列化转换逻辑,实际开发人员便可以实现非泛化的调用,就像使用本地定义好的服务一样顺畅,而这种方式由于没有引入任何二方包,所以不会产生任何项目依赖冲突问题,因此研发效率不会受到任何影响。
总之,通过为所有接入的数据源提供文档、样例、调用桩和字段结构这四个通用的能力切面,奇点做到了让所有的数据源变得可理解、可编码、可观测。随着不断推广和业务场景的覆盖,这将有助于在研发人员内形成一个良性循环,从而长期维持新的体系秩序。
第三步,改变前台组件消费数据源的方式。
一直以来我们都通过封装服务接口的方式为前台组件提供数据源,这样会不知不觉中产生大量的一次性服务。这些服务通常都没有什么复杂逻辑,只是消费一些现有的数据源然后做简单的字段映射。经过思考我们最终将这类服务从奇点的数据源体系中剔除出来,单独抽象为字段映射的脚本(使用FaaS实现)。前台组件最终将不再直接消费数据源,而是通过一份标准协议,声明其所需要的数据源和用于处理这些数据源的映射脚本,通过映射脚本来消费数据源。
这份标准协议可以通过搭建平台自动生成,通过这种方式我们将大量的一次性逻辑单独抽离了出来,避免它们对数据源体系产生干扰,起到架构中防腐层的作用。
总之,在建设完奇点这一套新的架构体系后,我们终于“守得云开见月明”,打造出了一套清晰可用的数据源体系,至此我们已经基本解决了之前研发体系中的绝大多数问题,是时候对它们进行一定的整合,来产出面向前台场景的标准研发解决方案了。
前台场景研发标准解决方案
可以看到,经过多年的积累和打磨,CBU的前台场景研发体系已经非常成熟了,整体看来,它是由几个关联性很高的子平台所构成:组件平台(前端、客户端用于开发和注册组件的平台)、搭建平台、FaaS平台、和数据源平台(奇点)。在过往的研发流程中,这些平台之间是通过一系列的约定进行联动的,而这些约定往往是“经验”性质的,对于没有使用经验的同学而言,理解和上手的门槛还是有一点高的,且各个平台之间存在着比较强的割裂感,在整个研发流程中开发人员需要在多个平台之间反复操作和跳转,带来了很多不变。
在攻克了原有体系中存在的诸多问题之后,我们决定将这套新的前台场景研发体系进行标准化,以搭建平台为中心,通过绑定关联的方式、打通其他各个子平台的功能,将研发流程集中串联在一起,把搭建平台打造成场景研发的核心“工作台”,沉淀出一套标准的前台场景研发解决方案。
在这套标准的解决方案中,一个前台场景由一张搭建页面(包含多个组件)、一个FaaS函数应用(由标准的脚手架生成)和一系列的数据源组成,在初始化阶段中,可以将三者进行绑定关联形成一个完整的场景工程。
完成初始化后即可进入实际的研发阶段,这个过程中前台研发专注于组件的实现,后台则负责在FaaS应用内部引用各种奇点数据源(或新增)实现业务逻辑,再通过字段映射脚本为指定组件进行UI层的封装适配,双方都可以做到Only Focus on Business的研发体验。
研发阶段完成后,即可在搭建平台上进行配置和联调,由于各个子平台已经完成高度串联,因此在搭建平台上可以直接完成组件、数据源和字段映射的绑定及实时预览,甚至可以通过打印数据链路来排查可能存在的问题,节省配置和联调所用的时间,也降低出错的成本。最后再进行测试和发布,一个前台场景便可上线。
以我们目前已经落地的无线商品详情页场景为例,在此标准解决方案下,研发流程如下图所示:
非常有趣的是,仔细观察这套方案的实际开发阶段,其中一个组件模块所包含的内容:组件UI + 映射脚本 + 业务数据源 ,这一组合正是10年前bundle思想的延续。但相比于当时,新的这套方案更加标准化、更加易于使用,能够快速地被应用于各种前台场景。另外我们也可以看到,随着各端技术栈的成熟,单一业务模块的研发流程又再次被高度集中化,这其中大部分的研发工作都已经十分简化,例如组件的低代码开发、无需关心运维的函数即服务,或许这些工作以后又将脱离具体的岗位划分,整合成一个新的“全栈”工程师角色,如此一来,单个需求研发的沟通成本将会进一步降低,研发效能或许会再次迈上一个新的台阶(当然,这只是一个YY性质的推测,欢迎大家拍砖交流)。
结语
至此,我们已经一路走过整整十年的历程,感慨过往峥嵘岁月的同时,我们也在努力创造新的辉煌。研发体系的演进之路不会有终点,未来我们仍将继续探索。感谢一起前行的同路人们,也欢迎更多有识之士加入我们,一起铸就下一个新的时代!
作者:远岩
原文链接
本文为阿里云原创内容,未经允许不得转载