当前位置: 首页 > 科技观察

我们来谈谈:如何重构一个大型软件系统

时间:2023-03-16 15:24:07 科技观察

1。为什么要重构在互联网行业,每一个新员工加入一个新的公司,都要学习一个新的软件系统。如果公司的代码很规范,架构设计的很合理,那么新员工上手会很快。当然,你的螺丝钉作用很明显。另一方面,如果像“屎山”一样面对祖传代码,就会怨声载道,学起来会很痛苦。从质量上来说,我把软件大致分为以下几种:第一种:他们对稳定性和标准化的要求非常高,所以代码中有很多异常的判断和检查,代码看起来非常冗余。典型代表就是华为的电信级产品。第二种:写的很随意,风格多样,代表例子是开源项目。第三种:也是最差的。员工在PM(产品经理)的高压下,日夜加班被赶出去。他们没有设计风格,能跑多久就跑多久,追求最快的实现。重构也应该成为互联网公司开发工作的一部分。当一个软件系统需要重构时,一定是由于以下原因之一:比如二次开发越来越难,新员工上手越来越难,每个模块只懂由特定的人;现有架构已不能满足要求;模块耦合非常严重,导致不同开发团队之间相互依赖,严重阻碍了开发进度。1.1二次开发难度越来越大,新员工上手成本越来越高。模块之间耦合严重,类之间的调用关系形成双向依赖。运行过程中出现大量if/else分支,分支太多,圈复杂度超出表格,根本看不清楚。当我们要增加一个新的功能时,即使功能很小,涉及的链条也很长,涉及到大量的外围功能和需要改动的文件。1.2日渐衰败的软件架构无法满足日益增长的功能需求软件系统从最初的demo开始,不断完善,一点一点地增加新的功能,以适应不同的应用场景。比如滴滴软件一开始只需要连接司机和乘客,调度系统负责派单,所以用户规模比较小;后来用户规模激增,需要扩容服务器数量,又涉及到负载均衡、消息中间件、高并发等需求;之后,添加各种服务类型,如乘车、私家车、豪车等,然后是各种红包、优惠券等。1.3模块耦合严重,云微服务的前提是模块可以解耦.这不仅是云迁移的需求,也能提升研发团队的整体开发效率。更重要的是,为了实现服务编排,任何一个子服务都提供灵活的资源,最大限度地提高集群的资源利用率,也就是说可以更好地实现弹性伸缩和容错。1.4考虑了新功能。代码重构的传统观念是“不引入任何新功能”。在我看来,代码重构和新特性开发相结合更有利于最大化重构的效果。2、重构设计的指导原则重构也是软件架构设计的一种,我这里称之为“重构设计”。首先,你需要知道重构的目标是什么。比如专注于满足二次开发,或者专注于模块解耦,或者兼容各种硬件平台、编程语言等。其次,你需要对软件的基本架构和软件设计风格有一个清晰的认识。以下是一些必要的技能:2.1.Unix编程艺术模块原则:使用简洁的接口组装简单的组件:设计时考虑拼接和组合分离原则:策略与机制分离,接口与引擎分离简单原则:简单设计,低复杂度,低吝啬原则:不写除非没有其他办法,否则大型程序。透明原则:设计可见,便于审查和调试健壮性原则:健壮性来自透明和简洁,silenceit原则:当异常发生时,立即退出并给出足够的错误信息。经济原则:花一分在机器上,不如花一秒在程序员身上。原理:避免手工hack,尽量写程序生成程序。先有一个圈,先学走先行后多样性原则:永远不要相信所谓的“单向”断言扩展原则:设计时着眼于未来,未来总是比预期的快2.2、设计模式+SOLID23设计模式,你不一定要完全了解如何写代码,但你必须知道每种设计模式背后的设计思想是什么。有一段时间,我尝试在我的代码中应用各种设计模式,但代码最终看起来是多余的和不必要的。从个人经验来看,很少有业务代码中使用设计模式的场合。最常用的是工厂、适配器、责任链等,作用不是很大。设计模式真正适用的场合是更高层次的,比如模块间设计等等。单一职责、开闭原则、里氏代换、得墨忒尔定律、接口隔离、依赖倒置。2.3.对领域驱动设计(DDD)有一定的了解,但是自己没有实践过。一般是模块解耦分层的思路:API(外部访问层)、Domain(领域层)、Repository(数据源访问代理层)和基础设施层(DB、Redis、HTTP、RPC等)2.4,逐行代码的重构方法,参考MartinFowler的经典《重构:改善代码的设计》,比如如何处理长函数,长参数,数据泥球等。在这里,我也说说我个人的建议:比如,垂直的调用关系变成水平的,减少函数调用栈的深度;不要过度封装。相信用户可以找到底层类的实现接口;逻辑上相关的代码应尽可能物理地放在一起;对于一个小的特定功能,涉及的链条越短越好;面向接口编程;在访问A表数据的类中不能有访问B表数据的函数;对于模块对外暴露的接口部分,在数据类型的选择上,数据类型的选择要尽可能的广泛(接口要考虑通用性);写操作接口应该接收尽可能少的参数;读取操作接口,返回尽可能多的参数;减少不必要的类和数据结构等2.5.微服务2.6。CloudNative毫无疑问,云是未来数字世界的基础设施。2.7.插件的想法比如convention/injection插件,事件插件,slot插件等等。好了这里就不一一列举了,因为根据哈佛大学心理学博士Miller的研究,对于每一类产品,用户最多只能记住七类品牌。这里我也会列出七大重构原则~3.重构设计文档如何写以面向对象语言为例,这里我分为几个步骤:老系统的类间调用关系图vs新系统的类间调用关系图老系统的整体架构图vs新系统总体架构图旧系统操作流程图vs.新系统操作流程图模块一一拆解:先画重构前的外观,再画重构后的外观。添加到现有系统考虑对旧系统的影响:兼容性问题考虑实施的可行性:如何平衡重构的成本和收益4.实施重构的具体步骤一般有两种方式:新建分支(不推荐)创建一个新的分支目录(推荐),这样可以保证原来老的一套代码可以用。这里有两种方式:做减法(先把旧代码跑一遍,再把多余的代码一点点删掉,或者refactor具体的子模块)——推荐,因为如果真的没有开发时间,一些未完成的模块也可以使用以前的旧代码。做加法(从每个子功能上重构,相当于重新构建这个软件系统)——不推荐,因为时间成本不可控只有了解具体的业务,才能设计出优雅的软件系统。