阅读更多

1顶
0踩

非技术

原创新闻 代码重构的实战经验和那些坑

2016-05-10 15:25 by 副主编 mengyidan1988 评论(1) 有6045人浏览
引用

2012年冬,我在一家创业公司的小团队里搞软件开发。彼时我们有一位真实的企业客户,且软件的第一版也已发布。开发按进度完工,在发布时我欣喜若狂,也非常骄傲,看着系统服务于每天几百万的独立用户,并发送出数千万条短信真是太令人满意了。到了第二年夏天,公司拿到了真实收入,我的职位变成了开发主管,公司又招了些新人,正待蓬勃发展,一切都很美好。然后我们做了一个巨大的决策失误:决定重写软件——从头开始。

为什么我们觉得有必要从头重写软件呢?
在第一次编写系统代码时,我们的时间表十分紧迫,必须与时间赛跑,在计划时间内赶完进度。因此无论是设计讨论,还是审查会议都没花太长时间——我们没有时间浪费在这上面——只能匆匆完成一个功能、快速测试,然后赶着去做下一个。我们与别的公司共享办公空间,我还记得其他公司的软件开发都会花很长时间做设计、讨论架构,再花上数周讨论设计模型。

除了设计仓促,原本的系统写得不差,总体来说架构也不错。其中有些意大利面条式的代码,是公司之前做概念验证时留下的,因为这些代码能用,再加上工期紧张,当时我们没有去碰。但后来我们不考虑执行优化改进,却决定要从头重写代码的原因在于:
  • 老旧代码很糟糕,很难维护;
  • “单一整体式的java架构”对我们的未来发展不利,无法支持有6千万移动用户以及多站点部署的大型运行商;
  • 我想要尝试炫酷的新技术,比如Apache Cassandra、虚拟化技术、二进制协议、SOA等等。

结果很不幸:我们说服了全公司以及董事会,实现了愿望。

代码重写之旅
正式的开发时间是从2012年春天开始的,我们将2013年1月末设定为发布时间。由于计划太过庞大,我们需要更多的人,于是在印度聘请了顾问与几个远程开发者。但是,我们没有充分预期到维护原本系统、进行新的开发工作与理解客户需求这些并行起来的工作量。

还记得我在文章最开始说过,我们有一个真实客户么?这位客户是南美最大的移动运营商之一。在我们开发的系统投入使用后,他们开始对变更和新功能提出要求,因此我们只能继续更新原来的系统。但是,由于这个系统将会被废弃,在更新时我们总有些敷衍了事,尽可能找借口拒绝了客户许多的新功能需求。结果导致了工期拖延,没能在原定的deadline完成进度。事实上,我们的进度拖延了整整8个月。

不过我们还是先说说结果吧:当项目终于完工时,新系统看起来非常棒,满足所有需求。我们做了负载测试,结果显示新系统能很容易地支持超过1亿的用户,配置集中,查看图表的UI工具也很美观,是时候废弃旧系统,改换新系统了……

但是客户拒绝了升级的请求:原本的系统已经获得了广泛应用,他们的用户已经开始依赖旧系统了,他们完全不想冒风险。长话短说,浪费了几个月之后我们收效甚微。该项目正式宣告失败。

何时需要重写代码
Joel Spolsky强烈反对重写代码,他建议大家都不要这样做。不过我不是特别认同:有时候逐步优化与重构非常困难,唯一读懂代码的方式就是重写。此外软件开发人员喜欢编写代码,创造新东西——阅读别人写的代码,尝试理解他们的代码与“思维抽象”会很无聊。不过,优秀的程序员也是优秀的维护者。

如果你想要重写代码,一定要出于正确的理由,并有着合适的计划。比如:

有时候在发布新版很久之后,老旧代码仍需维护,维护两个版本的代码需要耗费大量工作,在开始重写前请根据项目规模评估所需的时间与资源。

想想其他失去的机会,并比较任务的优先级。

重写大型系统比小型系统风险更高,考虑一下能否逐步重写。我们同时执行了以下几项工作:切换到新的数据库、使用“SOA”架构、更换为二进制协议,其实本可以逐步执行这些更换。

考虑开发者的偏见。在开发者想要学习新技术或新语言的时候,他们会想要使用这些来重写某些代码。不过我不反对这样做,这也是良好环境与文化的标志,但应当将它与风险和机遇做比较。

Michael Meadows对何时有需要进行“大型”重写有着很好的看法

技术上

  • 组件的耦合度很高,无法单独对某个组件进行修改。重新设计单个组件会导致一连串的变化,不仅会影响到相邻的组件,甚至间接影响到所有的组件。
  • 技术堆栈太过复杂,未来状态设计需要变更很多的基础架构。出于这个原因执行完全重写十分必要,逐步重新设计在这种情况下没有优势。
  • 重新设计单个组件无论如何都会导致对该组件的重写,在现有设计中没有可以插入新功能的地方。这种情况下逐步重新设计没有优势。


政策上
  • 赞助商无法理解逐步重新设计需要对项目进行长期投入。不可避免的是:大多数公司对于在逐步重新设计上继续耗费预算没有兴趣。在完全重写代码时,这种现象也很难避免,但赞助商更愿意继续投入,因为他们不想用着半成品的新系统与部分过时的旧系统。
  • 系统用户更习惯使用“原本的界面”:在这种情况下,政策上不会允许修改系统的重要部分(前端)。但如果完全从头开始重写,则会绕过这个问题。用户还会坚持使用“相同的界面”,但这次你反击的理由更为充足。要记得:逐步重新设计的总成本总是要高于完整重写代码,但一般来说对企业的影响更小一些。在我看来,如果重写理由充足,公司又有超级优秀的开发者,那么就开工吧。

放弃正在开发的项目很危险:浪费大量的时间和金钱重复实现已有功能,同时还会放弃实现新功能的机会,有可能激怒客户并导致工作计划推迟。如果你正在重写代码,那是你的权力,不过请确保这么做的理由正确,同时了解风险也做了相关计划。
1
0
评论 共 1 条 请登录后发表评论
1 楼 Caelebs 2016-05-11 11:14

    [*]
        

发表评论

您还没有登录,请您登录后再发表评论

相关推荐

  • 重写代码的实战经验和那些坑

    原文: When to Rewrite from... 责编: 钱曙光,关注架构和算法领域,寻求报道或者投稿请发邮件qianshg@csdn.net,另有「CSDN 高级架构师群」,内有诸多知名互联网公司的大牛架构师,欢迎架构师加微信qshuguang20...

  • 代码重构实战

    背景 用户头像上传功能中,...代码如下 type Parms struct { Head string //客户端发送base64字符串 } func Upload(p Params){ if p.Head == ""{ return errors.New("img is empty") } str,err := Base64Deco

  • 代码重构的方法和经验_软件重构与案例分析实战高级研修班2020年11月20日北京举行...

    一、课程介绍:软件重构面临的背景都是相似的,程序员们为了快速完成需求和上线而写出了最基本的代码。然后在功能的不断扩充过程中,以打补丁的方式对代码进行扩充,中间还会面临着开发人员的变更和离职。逐渐地,...

  • 又聊代码重构

    只有开发者对代码的不断觉察和理解,才会产生重构代码的念头。因此,驱动重构的应该是开发者本身的认知,而不是线上产品的反馈或者测试的反馈。以上面的代码为例,对属性名称的重构/修改,也是基于对代码的察觉。...

  • Apache DolphinScheduler 在叽里呱啦的实战经验

    在2019年进行数仓建设时,选择一款易用、方便、高效的调度系统被摆在非常突出的位置,感谢前同事马振洋同学和杨孟霏同学的付出,最终有缘选择了DolphinScheduler的前身EasyScheduler (后面使用ES代替),版本为1.1...

  • 干货:饿了么交易系统的重构和实战

    点击上方“开发者技术前线”,选择“星标”13:21 在看真爱来自:阿里巴巴中间件: 文|盛赫叮~,您有新的饿了么订单,正在阿里云上被接单。这篇文章成型于交易系统重构...

  • 整洁代码之道——重构

    现在的软件系统开发难度主要在于其复杂度和规模,客户需求也不再像Winston Royce瀑布模型期望那样在系统编码前完成所有的设计满足用户软件需求。在这个信息爆炸技术日新月异的时代,需求总是在不断的变化,随之在...

  • 浅谈重构中踩过的坑

    浅谈重构中踩过的坑 最近重构了公司一个将近10年的核心功能模块,踩了不少坑。在做这个重构的时候好几次都觉得做不下去,好几次压力都非常大,心想着我该不会做着做着就退出编程届了吧。 不过还好,自己还是...

  • 【测试平台开发】十八、vue组件化重构前端代码

    目前重构的总进度在80%,重构完的页面没什么变化,再回顾一下。 一、为什么重构 目前项目的功能开发重点还是在接口管理这一大块,内容多,任务重,可当我着手准备继续开发新功能的时候发现了个重大的问题。 我之前...

  • Spring实战(第5版)个人项目与填坑记录

    对书本中的诸多问题进行填坑记录,给予其他同学一定地填坑帮助; 其他基本和书本一致, 没啥其他特点了(笑)。 项目规划: 边学习边搭建,但考虑到作者对自己历史代码的改动“极不负责任”,所以在完成这本书的...

  • 你为什么不敢重构代码?

    点击上方“蓝色字体”,选择“设为星标”做积极向上的前端人!来源:ES2049 / 黑石https://juejin.cn/post/6951373058544730125代码重构有两大难点...

  • SpringBoot集成Redis实战——步骤、坑点、解决方案

    当下有了相对充裕的时间,深入了解下Redis,并对集成部分进行重构与优化,过程中,发现网上很多资料都是存在谬误的,一些坑点或注意事项,也在这里一并整理出来,作为知识沉淀,也能为后来者提供一定的参考,能少走...

  • 重构中有哪些坑

    重构中有哪些坑 一、总结 一句话总结:此时重构的经历让我觉得十分痛苦,但熬过来了就觉得没什么了。忽然感叹道重构还是很有技巧性的,对于技术要求反而没有那么高。重构更多考验的是对业务的深入理解,对抽象思维...

  • spring-ai-spring-boot-autoconfigure-1.0.0-M5.jar中文文档.zip

    # 【spring-ai-spring-boot-autoconfigure-***.jar中文文档.zip】 中包含: 中文文档:【spring-ai-spring-boot-autoconfigure-***-javadoc-API文档-中文(简体)版.zip】 jar包下载地址:【spring-ai-spring-boot-autoconfigure-***.jar下载地址(官方地址+国内镜像地址).txt】 Maven依赖:【spring-ai-spring-boot-autoconfigure-***.jar Maven依赖信息(可用于项目pom.xml).txt】 Gradle依赖:【spring-ai-spring-boot-autoconfigure-***.jar Gradle依赖信息(可用于项目build.gradle).txt】 源代码下载地址:【spring-ai-spring-boot-autoconfigure-***-sources.jar下载地址(官方地址+国内镜像地址).txt】 # 本文件关键字: spring-ai-spring-boot-autoconfigure-***.jar中文文档.zip,java,spring-ai-spring-boot-autoconfigure-***.jar,org.springframework.ai,spring-ai-spring-boot-autoconfigure,***,org.springframework.ai.autoconfigure.anthropic,jar包,Maven,第三方jar包,组件,开源组件,第三方组件,Gradle,springframework,spring,ai,boot,autoconfigure,中文API文档,手册,开发手册,使用手册,参考手册 # 使用方法: 解压 【spring-ai-spring-boot-autoconfigure-***.jar中文文档.zip】,再解压其中的 【spring-ai-spring-boot-autoconfigure-***-javadoc-API文档-中文(简体)版.zip】,双击 【index.html】 文件,即可用浏览器打开、进行查看。 # 特殊说明: ·本文档为人性化翻译,精心制作,请放心使用。 ·只翻译了该翻译的内容,如:注释、说明、描述、用法讲解 等; ·不该翻译的内容保持原样,如:类名、方法名、包名、类型、关键字、代码 等。 # 温馨提示: (1)为了防止解压后路径太长导致浏览器无法打开,推荐在解压时选择“解压到当前文件夹”(放心,自带文件夹,文件不会散落一地); (2)有时,一套Java组件会有多个jar,所以在下载前,请仔细阅读本篇描述,以确保这就是你需要的文件; # Maven依赖: ``` <dependency> <groupId>org.springframework.ai</groupId> <artifactId>spring-ai-spring-boot-autoconfigure</artifactId> <version>***</version> </dependency> ``` # Gradle依赖: ``` Gradle: implementation group: 'org.springframework.ai', name: 'spring-ai-spring-boot-autoconfigure', version: '***' Gradle (Short): implementation 'org.springframework.ai:spring-ai-spring-boot-autoconfigure:***' Gradle (Kotlin): implementation("org.springframework.ai:spring-ai-spring-boot-autoconfigure:***") ``` # 含有的 Java package(包): ``` org.springframework.ai.autoconfigure.anthropic org.springframework.ai.autoconfigure.azure.openai org.springframework.ai.autoconfigure.bedrock org.springframework.ai.autoconfigure.bedrock.anthropic org.springframework.ai.autoconfigure.bedrock.anthropic3

  • 50页-道路环卫保洁服务项目管理计划方案.pdf

    在当今智慧城市的建设浪潮中,智慧环卫作为城市管理的重要组成部分,正以其独特的魅力引领着环卫行业的变革。本方案旨在通过一系列高科技手段,如物联网、大数据、云计算等,全面提升环卫作业效率与管理水平,为城市居民创造更加清洁、宜居的生活环境。 一、智慧环卫系统概述与核心亮点 智慧环卫系统是一个集机械化保洁、垃圾清运、设施管理、事件指挥调度等多功能于一体的综合性管理平台。其核心亮点在于通过高精度定位、实时监控与智能分析,实现环卫作业的精细化管理。例如,机械化保洁管理子系统能够实时监控机扫车、洒水车等作业车辆的运行状态,自动规划最优作业路线,并根据作业完成情况生成考核评价报表,极大地提高了作业效率与服务质量。同时,垃圾清运管理子系统则通过安装GPS定位设备和油量传感器,对清运车辆进行全方位监控,确保垃圾清运过程的规范与高效,有效解决了城市垃圾堆积与随意倾倒的问题。此外,系统还配备了垃圾箱满溢报警系统,通过智能感应技术,当垃圾箱内垃圾达到预设高度时自动报警,提醒作业人员及时清运,避免了因垃圾满溢而引发的居民投诉与环境污染。 二、智慧环卫系统的趣味性与知识性融合 智慧环卫系统不仅实用性强,还蕴含着丰富的趣味性与知识性。以餐厨垃圾收运管理子系统为例,该系统通过为餐厨垃圾收运车辆安装GPS定位、车载称重、视频监控等多种感知设备,实现了对餐厨垃圾收运过程的全程监控与智能管理。作业人员可以通过手机APP实时查看车辆位置、行驶轨迹及收运情况,仿佛在玩一场现实版的“垃圾追踪游戏”。同时,系统还能自动生成餐厨垃圾收运统计报表,帮助管理人员轻松掌握收运量、违规情况等关键数据,让数据管理变得既科学又有趣。此外,中转站视频监控子系统更是将趣味性与实用性完美结合,通过高清摄像头与双向语音对讲功能,实现了对中转站内外环境的实时监控与远程指挥,让管理人员足不出户就能掌控全局,仿佛拥有了一双“千里眼”和一对“顺风耳”。 三、智慧环卫系统的未来展望与社会价值 随着科技的不断进步与智慧城市建设的深入推进,智慧环卫系统将迎来更加广阔的发展前景。未来,智慧环卫系统将更加注重数据的深度挖掘与分析,通过大数据与人工智能技术,为城市环卫管理提供更加精准、高效的决策支持。同时,系统还将加强与其他城市管理系统的互联互通,实现资源共享与协同作战,共同推动城市管理的智能化、精细化水平。从社会价值来看,智慧环卫系统的推广与应用将有效提升城市环境卫生质量,改善居民生活环境,提升城市形象与竞争力。此外,系统还能通过优化作业流程、减少资源浪费等方式,为城市可持续发展贡献重要力量。可以说,智慧环卫系统不仅是城市管理的得力助手,更是推动社会进步与文明发展的重要力量。

  • 微信小程序驾校管理平台约车小程序demo完整源码下载-完整源码.zip

    微信小程序驾校管理平台约车小程序demo完整源码下载_完整源码

  • MATLAB实现含风电不确定性的电力系统低碳调度模型

    内容概要:本文详细介绍了使用MATLAB和YALMIP工具包构建的电力系统低碳调度模型。该模型主要解决风电和负荷不确定性带来的挑战,采用模糊机会约束处理风电预测误差,将复杂的非线性约束转化为混合整数线性规划问题。文中展示了如何通过分段线性化、大M法等技巧提高求解效率,并实现了包括火电、水电、风电、储能等多种能源类型的综合调度。此外,还讨论了碳排放成本、启停时间约束、爬坡率约束以及储能系统的建模方法。最终,通过结果可视化展示各成本构成及其对调度策略的影响。 适合人群:从事电力系统优化研究的专业人士,尤其是熟悉MATLAB编程并希望深入了解低碳调度模型的研究人员和技术人员。 使用场景及目标:适用于需要处理风电不确定性、优化电力系统调度的研究项目。目标是降低电力生产成本的同时减少碳排放,确保电力系统的稳定性和经济性。 其他说明:代码中包含了详细的注释和扩展提示,方便进一步修改与应用。对于大规模电力系统调度问题,提供了高效的求解策略和性能优化建议。

  • OFDM、OOK、PPM、QAM 的误码率模拟【绘制不同调制方案的误码率曲线】附Matlab代码.rar

    1.版本:matlab2014/2019a/2024a 2.附赠案例数据可直接运行matlab程序。 3.代码特点:参数化编程、参数可方便更改、代码编程思路清晰、注释明细。 4.适用对象:计算机,电子信息工程、数学等专业的大学生课程设计、期末大作业和毕业设计。

  • my lib1.SCHLIB

    my lib1.SCHLIB

Global site tag (gtag.js) - Google Analytics