陈 晖 柏立悦 史国芳 洪小敏 李 冬
(浙江中控技术股份有限公司)
在文献[1]《影响工业软件开发周期稳定性的根因分析》中提到,新手在面对复杂开发环境时表现出的不稳定性使得项目经理很难对其工作效率进行准确地评估,因此开发周期也变得不稳定。所以笔者针对这个问题,探讨了多个应对方案及其可行性,并最终筛选出一种相对最优的应对方案。
想要消除新手开发者应对复杂开发环境时表现出的不稳定因素,没有简单且有效的方法,因为一个人的业务水平是无法零成本或低成本地提高的,但也可以从侧面提出几种方法来缓解这种矛盾。
招聘有多年经验的高水平员工进行开发,显然会使软件项目的不稳定因素降到最低,但也有较大的不可行性,具体如下:
a.成本过高。全部招聘高水平资深员工,会使得软件项目的整体成本大幅提升。
b.人才缺口。我国的IT产业相比发达国家起步较晚,IT人才也只有在近几年才呈现井喷式发展,IT人才的平均年龄相对欧美国家偏年轻化,其中35岁以上的资深开发人员仅占6.7%[2]。
c.人才断档。如果没有年轻员工加入,那么团队的技术和业务知识就无法得到传承,团队的抗风险能力将变得很弱。
因此,全面招聘高水平人才的方法可行性较低。
企业培训是普遍存在的,例如华为,相对一般企业通常15天的培训期,华为则把新员工的培训周期拉长到180天,但其培训内容主要集中在破冰、企业文化介绍、职业生涯规划及团队协作等方面,并没有集中在软件开发技术本身。
事实上,企业目前很少存在短时间内对新员工进行高强度培训的情况,以大幅提升其专业技能的做法,原因如下:
a.新员工存在不稳定性。50%~60%的新员工在入职后的前7个月内会出现工作变动,造成的损失可达员工年收入的150%~250%。
b.高强度的培训效果不佳。没有和具体项目开发经历相结合,灌输式的培训很难达到巩固知识的效果。
c.没有明显的收益。除了培训成本外,业务水平的提高也会使员工对薪资的期望值有所提升,对企业的成本控制来说是不利的。这也是限制企业加大培训投入的现实因素。
因此,通过加大培训力度,在短时间内大幅提升员工的技术能力,该方法的可行性也不高。
在科技日益发达的今天,生产力工具呈现丰富多彩的趋势,如电脑代替纸笔、机器人代替工人,而自动化公司为生产企业提供DCS(集散控制系统)也是一种先进而强有力的生产力工具。程序员也作为一种生产力,软件开发是一种生产劳动,而Visual Studio等开发软件则是他们的生产力工具。
显然,提供一种好的生产力工具可以大幅提升生产力。就软件开发而言,好的生产力工具有如下几个特点:
a.降低开发者的门槛。例如C语言的出现使得编程逻辑变得更简洁清晰,大型程序的编写也成为了可能。STL的出现则是让很多初级开发者可以更关注业务逻辑,而不会在数据结构和算法方面耗费精力却频频犯错。如今互联网流行的各种开发框架,如最新的Spring Cloud家族就包含了数十种不同的开发组件,它们可以从不同的角度来简化一些复杂功能的开发[3],这样就使一些非顶尖的开发人员也能够参与到大型系统的开发过程中。
b.减少重复劳动。对于技术专家来说,一些高频出现但并没有技术瓶颈的代码,并不是他们想要关心的。在大中型公司,甚至会成立专门的公用构建模块(Common Building Blocks,CBB)部门来解决这些问题,比如提供一些基础模块,包括网络库、数据库中间件等,甚至还有一些业务重合度高的业务模块,如用户管理、工作流等。
c.创建容错环境。一个新手对代码规范、开发流程的接受和掌握都有一个过程,尤其是像C++这样机制较为复杂的语言,会有很多隐藏的陷阱;而资深开发人员犯错的几率相对会小很多,但难免也有疏忽的时候。所以创建一个容错环境,辅助开发人员避免一些低级错误和能力不足导致的错误,那么开发效率的稳定性势必会得到保障。常见手段有很多,例如C/C++代码静态检查工具可以帮助检查缓冲区溢出、空指针等多种异常错误[4],大幅减少评审成本并提高代码质量[5]。
可以肯定的是,提供不同形式的生产力工具确实能较好地保障软件的开发效率,具体程度依赖于生产力工具的功能是否足够强大以及与实际应用场景的匹配度。
因此可以得出,升级生产力工具这种方案,与前面两种方案相比更具有可行性。下面将讨论如何选用合适的生产力工具来保障软件开发效率的稳定性。
在选择合适的生产力工具之前,应先分析所开发产品的现状。
产品的应用特点应优先考虑整个企业范围内,或者至少是部门级,这样改进措施才具有推广性。下面以浙江中控技术股份有限公司(以下简称中控)为例,详述分析思路。
2.1.1 产品线的特点
以中控的主流产品DCS及其衍生产品为例进行说明,产品线具有如下几个特点:
a.项目主导型。出于对工厂数据安全和生产安全的考虑,通常以安装包的形式提供给客户,然后在每个工厂的机房或中控室里进行安装,即软件大多是在封闭空间中运行的。
b.部署和维护简易化。这并不是表明自动化软件比消费类软件更为易用,相反地,它们比很多消费类软件在功能逻辑上要复杂很多,如为了满足数千个工厂的差异化需求,需要开放出大量的设置和参数,因此需要专业的工程人员进行部署和维护。为了降低工程门槛,缩减工程成本,那么就要求部署和维护都能尽量做到简单化。
c.系统结构复杂。一般互联网企业的服务器通常只具备两种核心功能,即计算和存储。例如现在流行的云存储和云计算,就是对这两种功能的大型化、集中化,简单来说是一对多的关系(一个服务器对多个客户端)。而DCS则更为复杂:多个客户端对应多个服务器,并且和多种异构系统对接以形成完整的功能。例如DCS的底层通过控制器连接着数百种不同的软硬件,又通过OPC等协议将自身的数据传送给其他系统。所以在DCS中并没有清晰的后端的概念,体现的是各个部件之间多对多交互的关系。
d.负载稳定。出于生产安全的考虑,一般工业现场的硬件都在性能和容量上有所冗余。且因为生产人员和生产计划是基本固定的,除了扩大生产等额外因素外,一般来说系统的负载是稳定的。那么在选择生产力工具的时候就可以不用过多考虑这一点。
2.1.2 单个产品的特点
分析完整个产品线的特点后,再把范围缩小到单个产品。以中控的增值软件——高级报警管理系统(Advanced Alarm System,AAS)为例,AAS属于DCS的增值产品,它从多个角度分析DCS的报警信息,指出报警组态的待优化之处,以保证生产安全。该产品的特点与DCS有很多相似之处,除了:系统结构比DCS简单,可以把它视为广义的DCS的一个组件,或者其系统部件的剥离;安全性要求比DCS低,因此一般以快速迭代的方式推出新功能、对接新的系统,以快速响应客户需求。
主流编程语言。编程语言决定了技术走向,例如阿里巴巴主攻Java,而腾讯则深耕C++,中控AAS1.0的编程语言为C++,与中控的主流保持一致。
组件/框架。在确定了主流编程语言之后,还需指出企业是否采用了一些组件和开发框架。组件和框架的来源有多种,包括自研、开源和商业购买。中控AAS1.0采用单服务器、单进程的C/S架构,使用到的部分组件和框架如下:
a.网络模块。中控自研,运用范围广,主要负责网络数据的收发,但不负责数据内容的封装与解析。
b.数据库中间件。中控自研,负责适配不同种类的数据库,如FireBird、Sqlite、Oracle及Microsoft SQL Server等。
c.RapidJson。开源库,负责网络数据的封包与解包。
一个生产力工具体系的优点和不足有多个方面。接下来以AAS1.0为例,探讨生产力工具的哪些缺失和不完善会使得影响开发效率的不稳定因素被放大,甚至严重影响开发进度和质量(表1)。
表1 AAS1.0生产力工具存在的问题
从上述分析可以看出,影响AAS1.0开发效率和质量的问题较多,且是多方面的。其中非业务代码的占比较大,说明优化空间较大,因为非业务相关的代码在理论上是有提取、封装成通用框架的可能性的。经过封装和测试后,该部分代码的稳定性就可以得到极大的保障,使得影响开发周期稳定性的因素大幅减少。
不管采用何种改进方案,都至少应满足如下要求:
a.包含组件化规范,从框架层面去解耦合,从而使所有人的代码质量有一定保障;
b.网络性能高,不再为相关功能的优化而投入大量精力;
c.有用户管理/登录机制;
d.支持远程调用,省去调用分发代码;
e.支持异步调用,避免新手为了实现异步而处理各种线程方面的问题;
f.支持本地和远程统一形式调用,省去本地存根和远程代理的定义工作;
g.支持消息订阅/发布;
h.支持数据序列化自动生成,省去封包、解包代码;
i.支持文件传输机制,避免新手写出蹩脚而不好维护的相关代码;
j.在Json的使用上要简洁易懂。
表2列举了可能可以解决这些问题的改进方案。
表2 可能的改进方案
表2中列出了作者考虑到的几种改进方案,接下来仍然以中控AAS项目为例,根据自己产品和技术的特点以及对每种方案的优缺点的可接受度来进行选择:
a.AAS定位于增值软件,需要快速推出产品进入市场,并快速迭代以适应不同领域的客户。因此,全自研C++框架的开发周期和成本显然是不可接受的。
b.全部采用第三方的框架,需要考虑第三方框架的迭代更新和版权变更带来的风险,以及融合成本、学习成本。
c.全面转向Java,有极大的风险。因为历史遗留代码将完全不能重用,并且开发人员也需要进行大量更换。这在以C/C++为主的工控领域来说可行性很低。
d.转向其他生态圈则更不可行。
e.最后的混合型方案则综合了第1种和第2种方案的优势,同时削弱了其缺点。而且统一封装会使得组件的迭代更新不会对产品产生大面积的影响。而在不同语言之间难混合的缺点,可以结合工业软件的场景,把语言依然限定在以C++为主来进行规避。
因此,综合比较,采用自研和第三方混合并进行统一封装是可行性最高、风险最小的改进方案。可以借鉴Spring Cloud的“全家桶”模式:选取一些第三方框架,然后用C++实现一个统一的框架,这个框架封装了所有的第三方框架,并通过自研补充第三方框架缺失的功能,使得整体风格尽量统一。
以上做法在理论上是可行的,但是如果这个框架的功能完全比照Spring Cloud,则会出现特性过多、开发成本过高的问题。而笔者强调要结合自身产品的特点和场景,因此可以把自己所需的特性和Spring Cloud做一个对比再做取舍,Spring Cloud与C++综合框架的对比详见表3。
表3 Spring Cloud和C++综合框架的对比
从表3可以看出,中控的产品,特别是AAS,对很多特性并无强烈的需求,因此在C++版本的综合框架中可以只包含少部分最核心最基本的组件。这些组件有些是引入第三方框架进行封装,有些则是自己实现。这相当于实现了一个精简版本的C++“全家桶”框架,这个综合框架中的组件数量不多,但是配合使用可以发挥1+1>2的效果。因此,在开发过程中,开发人员的关注点和工作量就会大幅减少,开发效率的稳定性就可以相应地大幅提高。
因此,利用自研框架和第三方框架形成C++版本的综合框架可以结合各方面优势,成本低,可行性高,是一种适合中控AAS项目用来改进生产力工具的较优方案。
笔者列举了几种消除开发周期不稳定因素的方法并进行比较,最终得出改进生产力工具是相对可行的方法。然后列举了几种改进生产力工具的方案,并最终得出适合中控AAS项目的最佳改进方案。其他企业也可以借鉴类似思路,分析自己产品的特点和应用场景,以此来确定一种适合自己的生产力工具的改进方案来提高开发周期的稳定性。