1. 项目背景
快速响应客户需7求是企业成功的关键之一。在现代竞争激烈的市场中,客户需求不断变化,企业需要快速响应这些需求以保持竞争优势。常见的快速响应并满足客户通常有如下方案:
采用敏捷开发方法:敏捷开发方法强调迭代、快速响应和持续改进,可以帮助开发团队更快速地开发和交付软件。
自动化测试和部署:自动化测试和部署可以帮助开发团队更快速地检测和解决问题,并将软件快速部署到生产环境中。
使用现代化的开发工具和技术:使用现代化的开发工具和技术,如云计算、容器化、微服务等,可以帮助开发团队更快速地开发和部署软件。
灵活的软件架构:采用灵活的软件架构,可以帮助开发团队更快速地进行功能扩展和改进。
以上方法是工程、基础建设和架构设计等方面的最佳实践,但是即便如此,开发的工作量也是以人/日计算,而且需要重新部署上线。有没有一种不需要部署,只需要配置即可实现的设计和方法呢。
2. 预期目标
快速响应满足客户需求,快速开发上线,设计一个系统,使频繁变更的需求,更改上线按小时级计算。一般一个需求,需要设计开发、测试、发布上线等流程,整个过程至少需要1-2天,而且频繁上线,且发布上线一般要选择在晚上,等用户使用低峰期,因此我们希望能达到以下目标:预期实现从需求提出,到发布上线,按小时计算,可快速完成需求开发、上线、交付。
3. 技术选型
为了实现预期目标,笔者做了深入的技术调研,动态语言可以实现这一目标。动态语言可以实现热加载,从而免去了部署的麻烦。热加载是指在应用程序运行过程中,可以动态地加载新的代码或修改已有代码,而无需停止或重新启动应用程序。
热加载还可以带来如下好处:
- 快速迭代:开发人员可以在运行时修改代码,无需停止应用程序,从而快速迭代和测试新功能。
- 减少停机时间:热加载可以减少停机时间,从而提高应用程序的可用性。
- 简化部署:热加载可以免去部署的麻烦,从而简化部署和维护工作。
总的来说,热加载可以提高开发效率、减少停机时间和简化部署工作。
热加载主要有如下实现方式:
1)使用JEXL动态执行表达式:
• 优点:可以动态执行Java代码,调用Java Function(Function需先传入JexlContext)
◆缺点:只能执行一个“表达式”,而不是Function,所以有很多语法局限,不是真正执行一个Function
2) 使用Java动态编译:
• 优点:功能强大,能够真正实现完整的动态执行功能,能够动态调用全部系统功能和IO操作。
◆ 缺点:虽然功能强大,可以编译.java文件,但是还是很难在运行时替换框架级的类文件。此外,因为能动态调用全部系统功能和IO操作,但与一般代码环境没有隔离,这可能会成为项目中非常严重的安全隐患。
3)使用Java ScriptEngine:
• 优点:可以执行完整的JS方法,并且获取返回值;在虚拟的Context中执行,无法调用系统操作和IO操作,非常安全;可以有多种优化方式,可以预编译,编译后可以复用,效率接近原生Java;所有实现ScriptEngine接口的语言都可以使用,并不仅限于JS,如Groovy,Ruby等语言都可以动态执行。
◆ 缺点:无法调用系统和IO操作 ,也不能使用相关js库,只能使用js的标准语法。
►在如何快速响应客户需求,快速变化的技术选型时,我们先后对以上几种技术进行了需求和技术调研分析得出如下:
1)JEXL动态执行表达式,功能简单,支持有限,不满足日常需求。
2)动态编码需要热部署与热加载,这个在之前的单机时代还可以,现在是微服务,云服务的时代,大量机器热部署和热加载成本高昂且代价巨大。
3)ScriptEngine,可以动态的执行脚本语言,同时无法调用系统操作和IO操作,非常安全,这个给我们带来了巨大的便利,我们选择了 JavaScript 作为可以动态执行的脚本语言,主要还有以下原因:
JavaScript 足够简单和强大,可以满足我们的需求。
JavaScript 作为互联网时代的主流语言,为广大技术人员必备技能,易于使用。
开发使用环境简单,一个文本编辑器就可以写代码,一个浏览器就可以调试,非常方便。
以下是一个简单的 Java ScriptEngine 示例:
在这个示例中,我们使用 ScriptEngineManager 创建了一个 JavaScript 的 ScriptEngine,并执行了一段简单的 JavaScript 代码,输出了变量 z 的值。
除了执行 JavaScript 代码,ScriptEngine 还可以将 Java 对象传递给 JavaScript 代码,从而实现 Java 和 JavaScript 之间的数据交互。以下是一个示例:
例中,我们将 Java 对象 name 和 age 传递给了 JavaScript 代码,并在 JavaScript 中输出了一个字符串。
从以上示例可以看出,ScriptEngine功能强大,不仅支持简单的计算,而且可以支持复杂的业务计算,完全可以满足我们日常的需求开发。
4. 设计优势
选定ScriptEngine后下一步是如何实现快速响应,实现日常需求。是否能实现片段代码的可配置化,配置完后可以直接运行,免发布上线。是否有必要实现代码的可配置化,可配置化主要有如下优势:
可配置化代码可以灵活、快速地响应客户的需求。通过将软件系统的各个模块进行拆分,将其变成可配置的组件,然后根据客户的需求,选择合适的组件进行组合,就可以快速地定制出符合客户需求的软件系统。
可配置化代码的优点在于它可以大大提高软件开发的灵活性和效率。比如,当客户提出新的需求时,只需要在已有的组件库中选择相应的组件进行组合,就可以快速地完成新功能的开发。这种方式大大缩短了软件开发的周期,同时也降低了开发成本。
可配置化代码还可以提高软件系统的可维护性和可扩展性。由于各个模块都是独立的可配置组件,因此可以很容易地进行单独的维护和升级。同时,由于组件是可配置的,因此可以很容易地进行扩展和替换,以适应不同的需求。
总之,可配置化代码是一种非常灵活,高效的技术手段,可以帮助我们快速响应客户需求,提高软件开发效率和质量。
下面,笔者从汽车之家的几个项目,实践了代码可配置化:
对接二手车经销商车源数据,二手车经销商车源数据格式各不相同,要求快速接入,快速上线展示。
导出车源信息到第三方网站展示,做推广。第三方网站要求的格式也各异,而且导出格式也经常变化,如何快速响应变化,满足客户需求上线。
5. 系统设计
系统设计要考虑基于变和不变,变化频度比较大的计算模块通过JS脚本运行,不变的部分,即整体部分通过Java设计编写,JS脚本可通过数据库存储,以方便进行更新。 每次将待运算的数据通过接口传给程序,程序通过调用JS代码计算,得出计算结果,存入数据库,具体设计如下。
图1 利用ScriptEngine 动态计算过程
6. 系统设计以及脚本的编写
6.1脚本设计准则以及适用场景
当需要针对一个场景需求频繁变化,规则随时调整,上线要求时间短,有明显的根据输入参数,返回结果时,比较适合动态脚本的引入。
以笔者第一个项目库存导入为例,其场景如下:
A. 经销商会定期上传库存文件,各个经销商的库存文件格式各不相同。
B. 经销商会不定时调整自己库存的格式,比如增加一个字段、减少一个字段、字段格式变化等。
C. 整体汽车参数基本不变,能覆盖所有经销商提供库存文件的格式。
7. 具体场景实施
此场景比较适合动态脚本解析库存,以下是项目引用JS代码片段截图:
JS脚本保存数据库,可以随时动态灵活的新增,更新,避免上线。数据库配置如下:
库存导出的JS代码片段:
库存导出配置示例:
初始化ScriptEngine 引擎代码如下:
调用JS代码解析库存示例代码如下:
根据以上代码截图,以及流程图,可以总结得出,整体流程如下:
1)建立经销商账号。
2)根据经销商库存文件编写 JS 解析脚本,保存入数据库。
3)根据经销商的账号,找经销商配置的导入Rule (javascript 代码)。
4)把经销商传入的库存文件数据传入 ScriptEngine 执行 JS 解析脚本,获得标准库存数据。
8. 实现效果和收益
1)库存导入JS动态脚本上线后,库存导入需求效率提高400%,由原来的 2人/日, 提高至 0.5人/日。
2)库存导出JS动态脚本上线后,库存导入需求效率提高600%,由原来的 3人/日, 提高至 0.5人/日。
3)在线评分系统JS动态脚本上线后,库存导入需求效率提高600%,由原来的 3人/日, 提高至 0.5人/日。
4. 极大的提高了经销商库存接入,导出效率,和库存导出效率,给客户带来了非常好的体验。
9. 总结
以上是我们实践中根据业务的实际需求,经过深入的调研和分析后做出的技术方案和实践,并取得了很不错的效果。这样的场景以后还有很多,本文给快速响应客户需求,高效完成实际工作提供一种思路和方法。相信随着技术的发展也许会有更好的方案和技术,我们不断探索,不断追求进步,欢迎有兴趣的同学一起探讨和学习。
作者简介
陈培锋
■ 经销商事业部-经销商技术部-新产品技术团队。
■ 2019年加入汽车之家,负责智慧诊断产品研发,热衷于以客户价值为本,解决客户痛点,做给客户带来价值产品。