写代码就像打扫房子。俗话说,不扫一屋,可以扫天下。如果单个模块的代码不能很好地管理,如何实现一个完整的软件系统?今天我们就来说说一个代码模块的代码是如何一步步变质,连程序员都不愿意去维护的。然后是重构,还是丢弃并替换为新模块?代码有一定的循环,这个没有错。为什么有的代码运行几十年依然运行良好,而现在很多互联网公司的代码一年要重构好几次?成立2年的互联网公司做一个支付系统可以做4-5年。一代,每次重构的成本是多少?如何在不增加大量学习和维护成本的情况下,让原有代码的生命周期更长,一次开发,使用更长时间?大多数程序员没有多少机会从0开始构建新程序,更多的时候是接手别人写的代码。最好有代码交接,往往因为各种因素,这些因素你都知道,没有产品文档,没有设计文档,没有程序说明,??甚至可能程序中没有注释。那么,程序员的更新换代是极快的。互联网时代,一个公司的程序员平均资历只有一年多,程序交由下一个维护者。很可能你手中程序的各种问题都能满足基本的功能需求,但是代码内部的各种问题却让程序员总是有重构的冲动。今天不想讲重构,但是从根源上来说,为什么程序会变成这样呢?什么是程序的腐败?什么是软件的质量?分级标准是软件外部质量与软件内部质量的统一。外在质量指的是外在表现是否正常,内在质量指的是后续开发有没有坑,也就是我这里说的这个软件有没有腐败。内部质量标准是:可维护性、灵活性、可移植性、可重用性、可测试性、可理解性(摘自代码百科全书)。任何不符合上述标准的行为都可以称为代码损坏。形象理解就是一个苹果从里面烂了,烂到本该负责内部代码的程序员拒绝维护。实际代码损坏示例:代码混乱,没有代码规范不应该连接数据库的模块模块间混淆:模块内调用混乱,例如C#代码使用了EntityFramework,在代码中跳过EntityFramework,直接使用直接数据库连接修改数据。框架与别人不一致,不统一:包管理有的用gradle管理,有的用maven。有的后台用.Net,有的用Node,有的用Java。使用HttpClient和使用Feign连接其他应用模块在设计上有些不一致:有的代码使用统一的错误定义CommonException,有的使用原生Exception。微服务模块有资源层接口,定义了访问路径。资源Impl和服务接口提供具体的数据接口,serviceImpl提供具体数据获取的实现。在具体的编码中,大量的业务逻辑被写入到资源的实现中。过于复杂的抽象无法方便地更改:一开始设计的Job系统,上面有2-3张图片,下面是动态生成的问题。代码层面对这种设计进行了非常详细的抽象。产品突然提出某个职位的图片比较特殊,要求展示10张图片,于是对抽象图片部分做了一个if-else处理...无用代码,废弃接口没有说明原因codecorruption,nocodewouldbeinit腐败从commit开始,腐败是渐进的,需要一个过程。我总结了一些造成代码损坏的原因:没有统一的标准,或者没有严格执行统一标准的代码规范。每个程序员都有自己的审美观。例如,即使是缩进长度也不会影响代码中的任何功能,有的像4个空格,有的像2个空格。有些人喜欢黑人编程背景,有些人喜欢白人编程背景。有的喜欢在if后面直接跟在左括号后面,有的喜欢另起一行。代码规范还是要有的,包括各种格式定义,大小写规范,命名规范等等,前端有各种lint工具(jslint,tslint)帮助规范,后台的ide也有一些方法帮助。像百度、谷歌这样的公司在建设的时候也有自研的检查工具,所以一个资深程序员开发的代码第一次提交往往需要1-2天的时间。代码规范的混乱直接导致代码可读性的降低。可读性直接影响后续的生产力。程序员天天看着不顺眼的代码,怎么可能有效率呢?统一标准的基础规范除了代码规范外,包括项目命名、通信方式、基本程序框架、后端Javaspringboot、sprintMVC、前端angular、vue、react等都需要统一,并且有统一的基础环境(eureka、elk、redis、apigateway等)。不统一的后果是各种部署、管理和编码的低效率。比如搭建一个jenkins,然后为服务A部署Maven,为服务B部署gradle,会导致编写两套编译代码。如果你写一个基本相同的集合,当然会更快。我统计过的java代码中可以统一(包括但不限于)Http调用格式的部分统一content-type:application/json,响应也统一要求这个。HttpClient标准化框架,如SpringBoot项目管理工具:Maven、Gradle项目CI、CD配置管理方式,如统一到一个配置文件application.properties环境变量配置方法、qa、stag、prod。不要让人写stage,staging,orproduction等详细的代码基础:比如标准maven目录的结构项目命名方式:com.(公司名).(开发组名).(系统名).(模块名称)例如:com.omniprimeinc.cosmetic.application.server;Restful接口设计统一:大小写,命名方式,Body的最大尺寸例如Post接口是否可以添加PathParameter和QueryParameter。Post接口是否可以没有Body。其他配套功能的统一:调用链、动态配置管理、缓存、分布式事务数据库的统一:统一数据库、数据库版本、是否可以使用存储过程等。同样重要的是数据库的统一性不扩展这里。统一规范公司统一架构刚才说的统一多是在公司层面的统一。如果大家只用springboot,还是继续用统一的后端框架,前端用angular。这时候为了方便统一,就需要有代码相关的脚手架工具,直接生成基本的统一项。这样的工具的好处是可以直接一键完成很多基础工作,完成底层的统一工作。多头维护代码损坏的一个很重要的因素是多头维护,甚至是多代维护。一个公共项目由多个开发团队维护,很难统一标准。最初的版本有一个结构,后来改成另一个结构,开发改了好几批。很多人都在谈论这件事。任何一个开发团队在接手一个老项目的时候,其实都是有学习和适应的成本的。开发商频繁更换的坏处是重复的人工成本,随之而来的是可能丢失部分之前的标准和架构规划。架构没有实现代码模块的功能设计方案,制定的标准也没有具体实现。架构定了,开发不严格执行。每天忙着写代码,架构只关心架构,不管细节。开发者天天写代码,只关注功能,不管架构和代码质量(这个质量不是指功能实现的质量,而是各种统一标准的严格执行程度)。甚至有人说,高层服务不能调用同层服务,只能调用低层服务。因为开发没有严格执行,甚至加了个数据库连接,直接取数据库。这种东西一旦打开,就如同黄河决堤,一发不可收拾。所以,我上面说的就是架构的实现很重要,让所有具体的开发参与者都可以实现同一个标准。架构需要实现相关的设计,相关的文档,以及相应的执行检查。现实中,文档从来不能解决所有问题,但它可以解决80%的问题。此外,应尽量减少开发人员的更改,以减少因替换而导致的代码损坏问题。防止代码腐败的建议:代码标准化,统一治理代码的内部质量其实很难保证,代码的执行更依赖于人治。即使是个别标准化的东西,也只能在代码层面进行测试,无法通过测试或其他方式进行。另外,虽然有一些通用的默认标准,但更多的标准是由代码负责人决定的,完全是看喜好,就像上面说的缩进长度一样。就像你的妈妈和婆婆都来你家帮你打扫卫生一样。我妈妈喜欢把厨房里所有的锅都洗干净,挂起来。婆婆喜欢找个柜子,都放在柜子里。你能做什么?没关系,确定下一套标准就行,不要经常改。架构的严格执行上面提到的标准,尤其是自定义的标准,是需要执行的。***优先是文档,其次是团队内部的共识,第三是执行。严格codereview反腐代码执行是一个重点,这个重点就是codereview。在这个时间点上,我们再次强调标准和开发的重要性,让开发知道实现,让测试监督,让架构严格把关。对于不符合的,开发需要重新学习执行标准。减少开发人员的变更如果在一个团队中统一了原有的标准,在团队中实施敏捷开发,任何一个开发都可以替代其他开发工作,那么两个人交换任务是没有问题的。如果团队不统一,这个改动会严重影响开发,代码损坏可能会变得非常大。团队之间统一标准的可能性比团队内部更难,避免团队之间项目交接的最好方法是。代码模块架构KeepitSimple&Stupid,使用一目了然的架构。在现实世界中,业务需求总是跑在技术需求之前。很可能没有关于架构相关设计的文档或解释。一旦架构师走了,原来的开发就会被取代,导致无法延续原有的标准和设计。一旦发生交接,标准的丢失和架构的改变在所难免。这就是该原则发挥作用的地方。要用傻瓜式的架构,是任何新手程序员一眼就能看懂的架构。比如使用公司统一的项目代码生成器和脚手架生成统一的代码结构,不需要程序员投入学习代码结构的成本。而共同的架构意味着后续架构师接受原设计的可能性大大增加。很早以前就提出了分层的概念。为什么MVC的概念如此流行?我认为这是因为它足够愚蠢。在数据库的架构中,repository的定义、服务接口、serviceImpl的实现也成为了一个非常通用的设计。一个经典的例子就是asp.net.MVC的程序组织结构的三个文件夹:Controllers、Models、Views直接契约,强调契约大于配置。只要是开发过这类程序的程序员,都知道从Controller看路径和RestApi入口,从Models看数据结构,从View看Html视图。不需要额外的学习成本。Maven的标准目录结构也是一个例子。(见上图)定期清洁保养就像打扫房间一样。一段时间不清理,边角处自然会有污垢。那你会定期清洗吗?还是你不理他,每次看到地上有纸团,你就绕过去而不是扔掉?定期清理维护不仅是一个维护代码的过程,更是一个重新组织和统一标准的过程,让现有的开发和架构重新达成一致,从而提高战斗力,预防代码扩张。问题?一个模糊的建议是一个Sprint可以改写size,如果再大一点,应该是微分的。有时候代码的清理和维护也应该按照这个原则来处理,不要出现太大的代码模块。因为代码模块太大,首先带来的是程序的复杂性,对于程序员的理解成本会更高。其次,模块内部的耦合度也必须增加,增加了难度。这时候需要的就是拆分出一个新的模块。总结代码损坏是程序开发中的一个经典问题。代码的内在质量降低了,但外在质量确实可以被客户接受。程序员往往会想,在业务不那么忙的时候,做一些清理,对一些模块做一些微重构。我的经验告诉你,这些都是假的。如果您设置了定期清洁和定期检查和拆分,则必须立即执行。做这些事情优先于业务需求。为什么?想象一下C++中的printf程序。里面的代码非常糟糕。变量名为p、m、k,含义不能直观理解。我们需要认真处理这个模块的代码损坏吗?其实不需要,因为printf模块的代码需求就是把输入的内容打印出来,一直这样,没有新的需求,没有新的需求意味着不需要程序员深入到里面改它的代码,不需要更改的代码,我们没有动力修复它的损坏。要经常深入解决腐败问题。代码肯定有很多业务需求,需要经常改动。不要等到它已经损坏到代码生命周期结束时才考虑维护和清理它。它需要经常修理才能更好地工作,对吧?不打算开的老爷车,发动机坏了就坏了。对于一辆经常开的二手奔驰来说,定期保养是必不可少的。
