作者介绍:胡键,超过15年软件研发经验,先后任职于中兴和SAP,现专注于工业物联网创业,任上海圭步CTO。具有丰富的产品研发和项目实施经验,擅长围绕设备资产和生产管理提供物联网端到端解决方案。他同时还是CSM和活跃的社区活动组织者,在西安组织过多场HiBlock区块链技术社区活动并做分享。
作为技术人员,对于“技术选型”一词应该不太陌生。简单的说,技术选型就是技术决策,只要你在团队中稍微有点地位,独立承担某项任务,就会面临选择,需要做出相应的决策。当然,这种细粒度地决策级别不是我要讨论的重点。在本文中,我想分享一下我对于公司层面技术选型地观点和看法,更确切得说是面向创业公司的技术选型。为何要重点突出“创业公司”呢?很简单,因为到目前为止,我一直走在创业的路上。
好了,言归正传。在重点去谈创业公司如何做技术选型之前,咱们先来看看技术选型的一般性原则。
技术选型的通用原则
选择并不像看上去那么美好,没有选择和选择太多都会让人痛苦,尤其是在当今技术大爆炸和开源项目满天飞的今天,“选择麻痹”应该是最让技术决策者头痛的毛病。要缓解它,就必须建立起我们自己的技术选型标准,或者说原则。
在经历了这些年多次“艰难的抉择”之后,我总结出了适合我个人的技术选型原则。
原则1:能否简化开发任务?
这条原则显而易见,如果选择的技术无法帮助我们高效地达成目标,似乎没有理由去选择它。注意这里的关键词:简化。完成开发任务的手段并不是唯一的,在众多手段中间我们只关心哪个能够让我们生活得更容易。
同时,这里还要避免一个不那么显而易见的陷阱:虽然简化了手头的任务,但带来了其他方面的复杂性。比如,引入Kafka确实带来了一系列的好处:流量削峰、简化了任务分配和服务异步化等等,但由此也带来了一系列其他的复杂性,比如:运维的复杂性和事务的复杂性。那么,作为决策者就要评估是否需要这样一个复杂的方案,是否采用简单地方案就能完成目标,如:日志表 + 定时任务。
原则2:是否符合组织内的主流技术路线?
大多数组织都会有一个主流的技术路线,技术团队如果采用的技术五花八门,会大大增加技术管理的成本。技术路线,是在进行技术选型时必须要面对的问题,尽可能地选择符合公司技术路线的技术或工具,这样有助于工作的快速推进。
当然,凡事无绝对,当可见的好处远大于学习新技术的成本和风险时,在可控范围内冒险一试未尝不可。但需要提醒的是,除非是极端情况,这种情形其实并不多见。因为当前丰富的开源工具已经提供了充分的选择,在大多数情况下时能够让人找到既满足自己要求同时又符合组织技术路线的工具。这里我假设贵公司的技术路线并不是那种剑走偏锋类型。
原则3:是否普及程度高或者学习曲线平缓?
普及程度高,有利于很快找到合适的人直接上手开干;学习曲线平缓则有利于在缺人时快速将现有人员切换到现有赛道。一般来讲,普及程度高的技术或工具,大都没有陡峭的学习曲线。反过来就不一定了,比如我公司一直使用的Grails,在国内的普及程度就远低于所谓的SSH或SSM。但其学习曲线一点都不高,而且开发效率数倍于前者。
这条原则直接着眼于技术选型对于人员管理的影响,满足这两点的技术或工具都将大大降低人员管理的成本,对于招聘和人员流动都有积极的影响。
原则4:能否得到有效地支持?
这里的支持可以来自于两方面:外部和内部。能够方便地获得外部支持一方面说明了项目的普及程度,另一方面也反映了项目的活跃程度。前者的好处在上面已有说明,至于后者,则说明项目在与时俱进,对于新出现的使用场景大概率有较好的支持。
即使有很好的外部支持,也不意味着就应该放弃内部支持能力的建立。原因很简单,随着使用的深入和业务的发展,迟早会遇到自己公司特有的需求,而这个需求还没有广泛到从外部就可以直接获得很好地支持。此时,只能借助自己的力量把坑填平,这样才不至于以往的技术投资打水漂。
从获得支持的角度来讲,这条原则相当于对于上一条原则的补充说明。
原则5:是否有助于规范开发流程?
这一条原则的可能并不是那么明显,在此我想表达的观点是:要么有助于建立开发流程或套路,要么对现有的流程有支持。
还是以前面提到的Grails为例,典型的Grails应用开发主要就是:
- 开发Domain Class
- 开发Service
- 开发Controller
- 开发View
通过将应用本身拆解成这样的关键组件,从某种程度上来讲既规范了开发内容和流程,同时也可以让开发者快速地抓住要点,建立大局观,迅速进入状态。
另一个例子则是以太坊Dapp开发框架Truffle,其对于咱们习以为常的开发流程提供了直接支持:
- 创建项目
- 创建合约
- 构建合约
- (自动化)测试合约
- (自动化)部署合约
正是由于这样的支持,使得Truffle成为以太坊开发的不二之选。
架构和工具的选择差异
最后,作为第一部分的结束,我简单谈谈架构选择和工具选择的差异。这里,我不会教条的去大谈特谈架构和工具差异,因为这类带学术性质的讨论本来就不是我的喜好。
在我看来,架构更多地落在方向层面,而工具则着眼于执行层面的细节。既然如此,那么两者的选择顺序和差异就一目了然了:先定架构再选工具,而架构的选择由场景决定。比如,面对高性能要求的场景,我们首先要做的是选择哪一种架构模型:Actor还是STM;在定下来Actor之后,再选择用AKKA,还是Erlang,或是Vert.x,又或是GPars?
创业公司如何进行技术选型?
技术选型工作并不会因为创业公司就变得轻松,相反,由于创业公司本身的不确定性和阶段性,反而有其独有的特点,在不同阶段对于上述原则的优先程度和取舍也会有所变化。在本文的第二部分,我将针对处于不同阶段的创业公司给出我自己的技术选型标准和建议。
草创期
处于草创阶段的创业公司技术队伍一般不会超过10人,在这个阶段,公司最主要的目标就是尽快将核心业务快速上线,让其接受市场的考验。作为技术领导,我们通常会面临:
- 现有的人手永远难以满足不断增长的业务需求。这句话有几层含义:
- 招人难,这是行业内永恒的主题,但对于小公司尤其突出。
- 留人难,小公司资源有限,当员工觉得在此处自我修炼的任务完成,很自然会去寻找更大的平台。
- 变化快,相比起成熟的业务,草创阶段一切都处于摸索阶段,随时都会调整方向和策略,由此导致需求的变化速度极快。
- 上线压力大,不太可能让你先开发个半年再上线。更常见的方式可能是以月甚至以周或天的方式持续迭代,发布产品。
- 对于质量的要求只要达到基本可用即可,但要求队伍具备快速地填坑能力。
- 请注意,这里指的质量基本可用并非是指低质量,而是指某些非功能性的质量要求并非那么高,比如高性能、高可用等等。只要基本得到满足即可,并不要求你在这个阶段就造一个淘宝或京东。
鉴于以上的基本事实,对照前面的原则,可以很容易地排出优先级:
- 为了能让开发速度赶上需求增长速度,显然要求:
- 能够简化开发,帮助快速开发
- 普及程度高或学习曲线不那么陡峭,从而降低人员管理的成本
- 为了能支持快速迭代,自然需要:
- 有助于规范开发流程,对业界广为人知的工程实践有直接的支持
- 为了能让团队快速填坑,那么希望:
- 能够有效地获得支持,有助于快速填坑
这里,我来说说为何当初选择Grails作为我司的主要开发工具,而不是市面上烂大街的SSH或SSM。
- 简化开发,Grails在这个层面提供了数倍甚至10倍于后者的开发效率,究其原因:
- 无处不在的CoC(惯例优于配置),对于常见的编程实践以惯例的方式引入,基本消除了繁琐配置的需求。
- 提供了各类高效的开发部件,极大程度降低了开发人员的要求,即使是小白,按照手册进行开发,也能快速开发一个像模像样的应用。由于已经将常见的最佳实践内置,按照这种模式开发出来的应用天然就对常见的开发问题免疫,较之SSH或SSM之类已经处于不同的层次。比如:乐观锁、SQL注入、XSS攻击等等。
- 丰富的插件可以快速获得框架本身不具备或者不提供的能力,如Spring Security插件和Spring Security REST插件可以快速地让API应用支持JWT和权限验证。
- 普及程度或学习曲线,Grails在国内的知名度远逊于其在国外的知名度要拜国内的培训班所赐。
- 从历史渊源来讲,Grails本身就构建于Spring之上,同时曾经也被SpringSource收购,作为其工具链的一员。(注:Spring幕后的公司Pivotal于2015年终止了对于Grails的资助,但Grails目前依旧处于良好的发展势头。前不久,Grails团队又推出了新一代开发框架Micronaut。)
- Groovy语法对于Java开发者来讲几乎可以做到无痛迁移。
- 对于规范开发,Grails同样也不落人后:
- Grails应用有很明显的规范套路,参见上述原则5的描述。
- Grails支持常见的开发实践,如:自动化测试和DB Migration,可以很方便的跟Jenkins之类的CI/CD工具集成。
- 从获得支持方面,看看StackOverflow、相应的邮件组和它的Github仓库即可。
由于时间对草创阶段的公司来讲是最稀缺资源,我强烈建议作为技术领导的你在此方面花些时间和精力。我个人喜欢通过引入好的工具来获得额外时间,即使它显得稍微有点偏门,也无所谓。因为好的工具通常:
- 可以降低对于开发人员的要求,从而节约招人时间和缩短因人员流动而引起的效率减缓时间。
- 快速实现业务需求,从而赢得比竞争对手更多的时间。
- 将你的优势构建于前人的智慧之上,避免了潜在未知的问题,提前消除了入坑和爬坑的时间。
不客气的说,选择一个平庸的工具固然没什么大错,但你可能最多获得平庸的结果和效率。
发展期
假如熬过了草创阶段,那么发展良好的你将迎来最具考验的阶段,发展期。此阶段,人员不会超过50人,同时还要两线作战:
- 保障线上业务的正常运转
- 按时交付层出不穷的新任务
这样的考验对于任何技术团队来讲都是艰巨的,因为在这个历史时期,虽然看似人手有所增加,但具有以下特点:
- 人数虽多,但整体来讲质量还难以与那些大厂匹敌,面对两线作战难免会出现顾此失彼,成天救火的局面。
- 在草创阶段锻炼出来的技术骨干经验并不老道,缺乏硬仗的经验,你仍然需要花很大的精力来处理技术层面的事情。
- 人数的增多,导致了沟通成本的增加,如果没有好的、显式的开发流程做支撑,就很难撑过当下复杂的局面。
另一方面,从业务角度来讲,给技术也带来的新的要求和挑战:
- 更高的质量要求,原本不那么重要的非功能属性会变得越来越突出,比如:高性能、存储的扩展性等等。
- 要求边开飞机边换引擎,在保障线上业务正常运行的同时,偿还技术债。
- 需求产生的速度非但不会减缓,反而会承上升趋势,因为公司的接触面变大了。
在这样的背景之下,作为技术决策者,可以按照这样的优先次序去考虑技术选型:
- 有助于规范开发流程
- 有助于简化开发任务
- 高普及度和平缓的学习曲线
- 能有效地获得支持
并且,在这个阶段架构选型将会至关重要,否则难以达到业务所要求的质量目标。这在前一个阶段通常是不存在的,在我看来,草创阶段最重要的设计莫过于数据库设计。至于其他,都可以商量。
同样的,我将以我司的工业物联网接入层的架构变迁来说明一下。
在草创阶段,我们的接入层由以下几部分组成:
- Socket Server,负责在线设备连接管理,解析数据包、保存数据和报警等功能。
- 元数据存放于Postgresql
- 实时数据存放于MongoDB
随着设备接入数量的增加,这种设计开始捉襟见肘,架构改造势在必行。经过一系列的改造阶段,最终的架构变成:
- Socket Server,只负责设备连接管理
- Processor,它负责接收Socket Server传来的TCP包,将其解析成最终的数据格式,同时负责报警
- Ghost,它负责将Processor解析出来的数据存储起来
- 元数据依据存放于Postgresql
- 实时数据存放于HBase
其中,Socket Server、Processor、Ghost通过Kafka串联起来,后一阶段的处理负责从Kafka相应的Topic中拿到前一阶段处理好的数据,处理完毕之后再放入相应的Topic,交给后续的处理器处理。
或许有人会说这就是标准的流处理场景,不如干脆直接用相应的框架算了。没错,我的确曾经动过采用类似Storm或Spark的念头,但考虑到其带来的复杂性和团队对它们并不熟悉,最终采用上面的土方法应对了。到目前为止,它还稳定的运行着。这里还有一个背景:我们所面对的是大型工业设备,属于To B场景,从业务角度讲,设备上云的速度不太可能一夜就暴涨上万台。因此,采用以上的架构足以应付相当长一段时间内的机器数量增长。
其他技术考量:
- Socket Server、Processor和Ghost本身就采用高性能的框架Vert.x来编写,性能非常高
- 采用Kafka而非直接讲上述三个组成一个集群,然后利用Vert.x的Cluster Eventbus进行交互,则是利用Kafka日志持久性的特点,避免service挂了之后,丢消息。
- 分拆带来的一个附加好处就是可以方便的按需部署各个服务,因为Socket Server和Ghost相比起Processor来讲,并不易变,将变化率不同的组件分拆之后,可以更好地维护各个组件。
- 弃用MongoDB,转投HBase则是由于MongoDB的存储扩展性相比起HBase要差很多,而且运维成本也很高。
作为承前启后的发展期,架构选型是其关键所在,稍有差池,在草创阶段积攒下的优势就有可能灰飞烟灭。确定下架构之后,至于选择自建或是符合要求的云服务,这种选择题就好做多了。
成熟期
恭喜你,达到此阶段的创业公司可谓是有所小成,打过硬仗的技术团队的实力也进一步得到增强(不论从人数上来讲,还是从素质上来讲)。相比起草创阶段的流寇,发展阶段的山贼,现在的队伍可以算得上是一只正规军了。
业务上,开始慢慢稳定,形成了固有的套路和做法,即使有新需求,也并非像以前一样没有参考和不稳定。另一方面,技术上的积淀也越来越多,不论显式地或隐式的,公司已经有了自己的技术路线和规范。同时,在战火里成长起来的骨干也都能独当一面,你不再需要去做低层次的技术决策。
想必各位已经猜到,作为技术领导的你,此阶段地当务之急当是建立技术规范,明确技术路线和要求。有条件的还可以组建架构师委员会,甚至进一步将团队分拆成基础框架和业务应用两部分,将低层次的技术决策下派给相应的技术带头人。此阶段,最重要的原则莫过于:是否符合组织内主流技术路线和是否有助于规范化开发流程。
很遗憾,虽然我很想像前两节那样举一些个人实际的例子来佐证,但由于我所处的公司尚未达到此阶段,故只能在此纸上谈兵。至于例子,只好作罢。
总结
技术选型是技术领导日常工作的一部分,但就不同阶段的公司而言,技术选型的标准并非一成不变的。针对公司不同阶段的关注的重点,本文简单谈及了相应的标准和原则,同时结合自身给出了相应的实例。
说到底,技术要为业务服务,技术选型不能是技术人的自嗨,更不能是“面向简历”的决策结果。只有把握了这个最终原则,我们才能真正客观的看待当前的技术问题,相对客观的履行作为公司技术带头大哥的职责。
最后,虽然全文以“公司”为名,但其实只要将公司两字换成其他,比如“业务线”,其实也未尝不可。比如,成熟公司内部的创新,其整个过程与创业公司的发展其实非常类似,这种情况下,只要大领导支持,当然也可以采用相对激进的做法进行小范围内的“不符合公司当前主流技术路线”的技术选型。