热门标签 | HotTags
当前位置:  开发笔记 > 后端 > 正文

重构,让人快乐让人苦

重构,是编写代码必须要面对的一项操作,同时也应该是程序员乐于实践的一项内容。不论是逻辑实现还是设计过程,乃至整个分层结构,我们都可能面临并且实施重构。这篇文章不会告诉您什么是重构,如何去优美的重构等等的理论,只想和大家分享一些感受,并且探讨一些问题。最近的两周,我一直对我们团队的一个子业务框架做重构的工作,很多地方让我

重构,是编写代码必须要面对的一项操作,同时也应该是程序员乐于实践的一项内容。不论是逻辑实现还是设计过程,乃至整个分层结构,我们都可能面临并且实施重构。这篇文章不会告诉您什么是重构,如何去优美的重构等等的理论,只想和大家分享一些感受,并且探讨一些问题。最近的两周,我一直对我们团队的一个子业务框架做重构的工作,很多地方让我感到很痛苦,于是便有了这篇文章。

牵一发而动全身的根源在哪里

当我打开解决方案,查看代码的时候,我们会发现很多问题,比如冗余的代码,性能低下的逻辑实现等等,但是当我着手去改造的时候,潜意识告诉我整个似乎不能动,牵扯的面太广了。更改一个小地方,上下一串都要做相应的调整,这当然不是我想要看到的。大范围的调整会直接影响系统的稳定性,带来潜在的危险,同时会增加测试团队的负担;在版本控制方面会造成线上和线下版本在同一内容的巨大差异,版本更新的时候拿什么来保证一套几乎全新的代码替换线上系统是正确的选择呢?因为很多问题只有在最真实的环境才能被暴露出来。

这样的修改,修改成本无疑是巨大的,因为我们期望修改的只是那一小块代码而已。大范围的代码调整,同时也伴随着单元测试代码的调整。测试团队如果因此来重新走测试用例,那么付出的辛苦可想而知。

我要做的是重构而不是重写,造成这种现象的原因在哪里呢?

整个解决方案具有相对完整的分层结构,DAO层、实体层、业务逻辑层。实体层也对数据实体和业务实体做了分别定义。但是进行业务实现的时候我们并没有进行有效的隔离和代码的职责划分。

很多代码在处理业务逻辑的时候直接调用DAO,然后使用返回的数据组织业务实体。当我们的业务实体需要按照领域划分为两个或者更多的层次的时候,结果会变得更为糟糕,因为我们需要以底层的业务实体为输入从而输出上层的实体。当你以一个顺序工作流的方式完成一整套操作的时候,也许感觉很有成就感,整个过程天衣无缝,完美无缺。但是当我们尝试改变其中的某些内容的话,噩梦就开始了,实体的改变势必会引起逻辑的改变,但是这种改变是有连锁反应的。

业务实现的过程很多时候就是不同层次间的实体的转化过程,那么实现过程中单单考虑解除依赖不能收到很好的效果,从业务逻辑的职责出发,划分出清晰的业务层次,再以实体转变的结合点来考虑分解才能达到良好的效果。

独立的领域层尤为重要

各种经典的MVC架构的实现,常常让人产生误解,认为那样做就已经完美了。事实上,一个业务的框架的重点不是增、删、改、查,我更倾向于将DAO从业务框架中分离出去(最后我也是这样做的),整个系统应该提供统一的DAO服务,子业务框架要专注于业务的实现。

当我们尝试将一整套业务实体独立出来的时候,我们认为已经做了很好的业务理解,但是这是只见树木不见森林的想法。在某些系统中,领域的实现只占代码总量的很少一个比例,但是其重要性往往却是相反的一个比例。当我们选择将领域代码和其他代码混合在一起的时候,意味着我们的分层结构也随之混乱。

"用标准的架构模式来完成与上层的松散关联。将所有与领域相关的代码都集中在一层,并且将它与用户界面层、应用层和基础结构层的代码分离。领域对象可以将重点放在表达领域模型上,不需要关系它们自己的显示、存储和管理应用任务等。这样使模型发展得足够丰富和清晰"。在清楚了整个领域模型之后,再考虑选择合适的模式来解决分层问题,我觉得是合理的做法。

在对业务和领域没有充分理解的时候不要下手

在重构过程中,发现很多业务实体的定义不着边际,很多概念只是对数据实体的拓展,结果出来的东西和数据实体的逻辑关系截然不同。对数据调取的逻辑没有充分理解,那么组织业务实体的时候很容易出现不恰当的数据访问方式,比如循环访问数据库。

如果整个领域模型的建立和划分都是错误的话,我们仍然能实现所需要的功能,但是如果对这样的代码进行重构无疑等于推倒重来。

现在看来,当我们为了实现功能而急匆匆的不择手段的时候,为将来的维护和升级埋下了隐患。当我们想要将公用的数据调取和业务逻辑实现从各个子项目中抽象出来变成基类、接口、Helper或者Service的时候,我发现不同子项目的开发者对业务和领域的理解有着很大的差异,因而在实现方式和实体定义上都有很大的不同。这个时候我们又注意到组织实体的逻辑并没有单独的分离出来,抽取的工作遇到了难题。也许我们可以分离出代理,然后使用Adapter来适应原有的实体组织逻辑,又或许我们应该废除不合理的实体定义,也意味着废除了相应的实现逻辑。

如果我选择将不合理的实体替换为正确的实体定义将面临巨大的挑战,也许从数据调取到最终的逻辑都要调整。当然全面调整的原因是我们没有实现很好的隔离。

迷茫,面对一个几千行的Method

这是我无法容忍的情况,整个子业务的实现几个大方法全搞定了,每个方法里无数个"Region"和"End Region"。这样的情况就别谈什么分离和设计了。最起码的,当你在用"Region"和"End Region"的时候,就应该意识到这里可以分离出一个方法来。

大方法带来很多弊端。它的可维护性差,可阅读性差,和系统的分层结构不融合,不能进行有效的单元测试。当然对大方法的重构并不像代码本身那么发杂,如果它的逻辑足够清晰的话。但是如果一个思维足够清晰的程序员又怎么会写出这样的代码,所以对这样的代码进行重构,面临一个很大的问题就是那些在不同逻辑里重用的局部变量。当然更重要的问题是理不清头绪。

光去抱怨是没什么意义的,这样的方法出现的原因是什么呢?一个是开发者没有很好的理解业务框架的结构和目的,二是对程序设计的基本思想理解的不够好,三是对业务逻辑本身理解的不够清晰。对于这样的实现去重构,除了从业务角度出发,抽丝剥茧,慢慢的剥离,还有什么好办法呢?推倒重来吗?

重构,要随时进行

当有一份代码觉得不合适,而没有及时重构的话,那么整个解决方案就可能变成垃圾场。后续的开发人员会以存在即合理的想法来看待这些垃圾代码。尤其是新加入的成员,只能模仿别人在怎么做。从测试驱动的开发理念看,程序开发是一个不断重构的迭代过程。很多人将重构看成是一件大事,一听到重构就害怕起来,尤其是测试团队。当然这里不能否认,不恰当的重构会给测试团队造成很大的麻烦。

集中重构是极其错误的思想。不要想着等某些开发任务结束了,有时间了再集中精力来重构代码。当系统相对稳定之后,重构要付出的代价可能是整个团队无法接受的。对分层架构的重构应该是建立架构的最初一段时间,不断的调整达到最优。当项目进行一段之后,再来调整整体结构无疑是让人无法接受的。

重构要避免过度设计

最后要说的是,重构要围绕一个适度的目标来进行,要考虑代价,同时不代表模式应用的越多越好。相反的,在重构过程中,要时时考虑是否把简答的事情想复杂了。

目前我重构的代码中,还没有这样的问题,这里也就不啰嗦了。

说了这么多,我还是想听听各位的看法和感受,如何进行有效的重构,如何在编程的最开始的阶段就避免很多重构障碍的产生?

本文地址:http://www.nowamagic.net/librarys/veda/detail/979,欢迎访问原出处。


推荐阅读
  • 本文讲述了一位80后的普通男性程序员,尽管没有高学历,但通过不断的努力和学习,在IT行业中逐渐找到了自己的位置。从最初的仓库管理员到现在的多技能开发者,他的职业生涯充满了挑战与机遇。 ... [详细]
  • 本文详细介绍了 Java 网站开发的相关资源和步骤,包括常用网站、开发环境和框架选择。 ... [详细]
  • 在运行于MS SQL Server 2005的.NET 2.0 Web应用中,我偶尔会遇到令人头疼的SQL死锁问题。过去,我们主要通过调整查询来解决这些问题,但这既耗时又不可靠。我希望能找到一种确定性的查询模式,确保从设计上彻底避免SQL死锁。 ... [详细]
  • 本文通过古代物物交换的例子引出货币的诞生,进而探讨现代社会中虚拟货币的便利性,并将其类比为面向接口编程的核心思想。 ... [详细]
  • 本文介绍了 Go 语言中的高性能、可扩展、轻量级 Web 框架 Echo。Echo 框架简单易用,仅需几行代码即可启动一个高性能 HTTP 服务。 ... [详细]
  • 本文介绍了多种开源数据库及其核心数据结构和算法,包括MySQL的B+树、MVCC和WAL,MongoDB的tokuDB和cola,boltDB的追加仅树和mmap,levelDB的LSM树,以及内存缓存中的一致性哈希。 ... [详细]
  • 本文详细介绍了Java代码分层的基本概念和常见分层模式,特别是MVC模式。同时探讨了不同项目需求下的分层策略,帮助读者更好地理解和应用Java分层思想。 ... [详细]
  • ECharts 官方提供了丰富的图表示例,但实际项目中往往需要从后端动态获取数据。本文将详细介绍如何从后端获取数据并将其转换为 ECharts 所需的 JSON 格式,以实现动态饼图的展示。 ... [详细]
  • 本文将带你快速了解 SpringMVC 框架的基本使用方法,通过实现一个简单的 Controller 并在浏览器中访问,展示 SpringMVC 的强大与简便。 ... [详细]
  • Ext JS MVC系列一:环境搭建与框架概览
    本文主要介绍了如何在项目中使用Ext JS 4作为前端框架,并详细讲解了Ext JS 4的MVC开发模式。文章将从项目目录结构、相关CSS和JS文件的引用以及MVC框架的整体认识三个方面进行总结。 ... [详细]
  • 本文详细介绍了数据库并发控制的基本概念、重要性和具体实现方法。并发控制是确保多个事务在同时操作数据库时保持数据一致性的关键机制。文章涵盖了锁机制、多版本并发控制(MVCC)、乐观并发控制和悲观并发控制等内容。 ... [详细]
  • 本文总结了一些开发中常见的问题及其解决方案,包括特性过滤器的使用、NuGet程序集版本冲突、线程存储、溢出检查、ThreadPool的最大线程数设置、Redis使用中的问题以及Task.Result和Task.GetAwaiter().GetResult()的区别。 ... [详细]
  • 在JavaWeb开发中,文件上传是一个常见的需求。无论是通过表单还是其他方式上传文件,都必须使用POST请求。前端部分通常采用HTML表单来实现文件选择和提交功能。后端则利用Apache Commons FileUpload库来处理上传的文件,该库提供了强大的文件解析和存储能力,能够高效地处理各种文件类型。此外,为了提高系统的安全性和稳定性,还需要对上传文件的大小、格式等进行严格的校验和限制。 ... [详细]
  • 在什么情况下MySQL的可重复读隔离级别会导致幻读现象? ... [详细]
  • 系统数据实体验证异常:多个实体验证失败的错误处理与分析
    在使用MVC和EF框架进行数据保存时,遇到了 `System.Data.Entity.Validation.DbEntityValidationException` 错误,表明存在一个或多个实体验证失败的情况。本文详细分析了该错误的成因,并提出了有效的处理方法,包括检查实体属性的约束条件、调试日志的使用以及优化数据验证逻辑,以确保数据的一致性和完整性。 ... [详细]
author-avatar
416703721
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有