关于代码版本管理的思考和建议

      众所周知,良好的系统研发应该有延续性和一致性,因此不少公司很是注意代码版本控制,并逐渐慢慢的迭代本身的产品。前端

  具体到天然资源行业来讲,我司纯粹的产品销售较少,项目开发较多,不一样的地区,不一样的客户对于同一个功能的理解能够千差万别。即便是产品销售也一样面对相对强势的无可避免的增长一些个性化功能。程序员

  长期以来,公司事业部研发指望统一代码版本的愿望与具体各个项目之间个性化需求致使的代码变动(数据库结构变动)之间矛盾越演愈烈。最终造成了底层框架尽可能不改,新增功能经过扩展来改,业务相关沉淀到前端或数据库函数(视图,存储过程)去改的微妙平衡。spring

  可是这个平衡是很脆弱的,有较大的风险。数据库

  1. 首先,前端页面,脚本,数据库结构没有经过代码版本管理器进行管理,很容易出现页面,脚本,数据库表结构冲突的问题。一旦冲突虽然影响范围局限在项目当地,可是对公司的产品质量口碑影响较大。
  2. 扩展的新功能,绝大多数控制权在具体的研发手中,很难把控代码质量,进行代码审核,员工因各类缘由离职后,也不利于公司对代码的回收管理。
  3. 虽然采起了主框架,前端,扩展的分离,可是主框架更新时总部研发依然要当心翼翼,尽可能避免任何与通用功能无关的逻辑写入,而事实证实,除非紧锁代码权限,只让极少数人修改相关代码,不然这一点基本不能作到。

  如上所述,对于代码版本控制的讨论在咱们公司已经举行了不少次,绝大多数讨论都是从管理层面出发,聚焦于代码权限控制,代码分支控制等等。今天我想从技术角度谈一谈代码版本控制。安全

  从技术角度怎么作代码版本控制?如何解决通用版本与各个地区相同功能不一样表现形式之间的代码冲突?其实C#的asp.net框架和Java的spring框架已经告诉了咱们答案:基于接口开发。架构

  就拿日志来讲,不管是asp.net仍是spring都为咱们提供了官方默认的日志类,可是若是这些日志类没法知足咱们的需求怎么办?咱们彻底能够基于官方接口本身实现一个特殊的,基于个性化业务需求的日志类,而后把这个独一无二的日志类经过依赖注入注册到框架中,替换和接管原来的通用日志类。核心框架内部由于所有是基于接口实现的操做,因此什么都不须要修改。而实现这一点最关键的一步就是核心框架中,不一样的组件之间,不一样的类之间经过LoggerFactory生成的ILogger去执行日志记录,而具体到底使用官方的通用日志类实现ILogger仍是第三方的特殊日志框架如Log4都无所谓。
经过这种方式,asp.net和spring作到了核心框架和业务代码的剥离以及各自的独立发展。简略的架构描述以下:

  回到咱们的天然资源以及自身的产品(至少我目前了解到的政务,不动产登记以及权籍系统),为何感受代码版本控制很难,本质上是将通用业务模块与框架牢牢的耦合在一块儿了。简略的架构描述以下:
框架

  这种架构的优势是:框架即产品,开箱即用。它的缺点也很是明显:只要是和具体业务相关的改动都很不灵活(包括业务代码,甚至包括部分工做流代码),而且地区扩展中的代码只能扩展全新的方法,一旦设计到旧方法的改造,仍是只能回来修改框架,而为了减小对框架的污染只能依赖关键核心员工修改,效率较低,响应也不快。
  对于改造工做量,我认为无需担忧,要想使用这种模式来控制版本控制,也不是必定要全面的重构代码,大动干戈的改造,咱们彻底能够一个模块一个模块的逐步的进行改造。
以不动产农房改造的户籍信息为例:
  最初的农房批量生成附记由于逻辑相对复杂,没有按照管理在前端或数据库完成,而是写在了核心代码库BDC2的HjxxDomainService领域类中。
asp.net

  可是批量附记属于业务性很是强的内容,每个地区的不动产可能都有本身的要求,如衡阳提出要求在家庭成员下添加预编不动产单元号,房屋来源等等内容。这些内容的数据库字段甚至是衡阳特有的,根本没法在通用版本里面直接添加 。
  遇到这种状况,要求衡阳本身经过扩展另外重写一套批量生成附记进而致使有两套极其相似的大段代码,要么经过核心程序员在通用版本中增长很是麻烦的版本判断分支语句。不论采用哪种方式都很是不利于代码的版本控制和维护。
  若是咱们采用先前描述的框架对应接口,附带一个通用实现,不一样地区有本身的对应实现,那么咱们就能够简单的经过增长类文件的形式完成衡阳修改。甚至在个性化类还在利用大部分通用类方法时能够引入一个通用方法代替实现。粗略架构图以下:函数

  具体到农房批量生成附记,UML类图改造以下:
优化

  核心代码改造点以下:

  1. 将外部控制器要操做的核心领域类从通用的HjxxDomainService,修改成抽象的AbstractHjxxDomainService。

  2. HengyangHjxxDoMainService经过通用的CommonHjxxDomainService实现无需特殊化处理的方法,减小重复代码。

  3. CommonHjxxDomainService(原HjxxDomainService)继承AbstractHjxxDomainService和IplGenerateFj(视状况复杂度能够不要),其他不作修改。

  4. 在AbstractHjxxDomainService中增长一个具体实现工厂(后期能够优化成依赖注入的形式)

  5. 外部控制器中涉及到农房批量注记时将前端传入的方法名传入工厂,调用生成对应业务类并执行动做

  经过以上5步改造,咱们就不动产的农房业务的户籍信息领域模块单独拆分了一套通用版本和一套衡阳版本,其中衡阳版本除了批量生成附记,其余模块本质上仍是用的通用版本方法,只不过已经具有了继续扩展独立的可能性。改动量小,安全,且切实可行的可以解决版本控制问题。由于既然可以拆分红单独的文件,那么必定能够继续拆分红单独的动态库,而后在工厂方法中经过反射的方式动态寻找,加载和绑定。
  遇到全新的方法时,咱们也能够从容的选择多种方式,若是是在现有工程中修改,则修改抽象类(接口),而后首先实现通用版本,对其余地区版本直接调用通用版本方法。固然这样对代码破坏性比较大,咱们彻底能够不要改动现有类库中的抽象类和接口,经过扩展的方式在原类上增长新的方法和接口(以C#语言为例)。

相关文章
相关标签/搜索