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

重构,让人快乐让人苦

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

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

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

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

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

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

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

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

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

独立的领域层尤为重要

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

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

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

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

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

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

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

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

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

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

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

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

重构,要随时进行

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

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

重构要避免过度设计

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

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

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

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


推荐阅读
  • Java项目分层架构设计与实践
    本文探讨了Java项目中应用分层的最佳实践,不仅介绍了常见的三层架构(Controller、Service、DAO),还深入分析了各层的职责划分及优化建议。通过合理的分层设计,可以提高代码的可维护性、扩展性和团队协作效率。 ... [详细]
  • 深入解析SpringMVC核心组件:DispatcherServlet的工作原理
    本文详细探讨了SpringMVC的核心组件——DispatcherServlet的运作机制,旨在帮助有一定Java和Spring基础的开发人员理解HTTP请求是如何被映射到Controller并执行的。文章将解答以下问题:1. HTTP请求如何映射到Controller;2. Controller是如何被执行的。 ... [详细]
  • SpringMVC RestTemplate的几种请求调用(转)
    SpringMVCRestTemplate的几种请求调用(转),Go语言社区,Golang程序员人脉社 ... [详细]
  • 程序员妻子吐槽:丈夫北漂8年终薪3万,存款情况令人意外
    一位程序员的妻子在网上分享了她丈夫在北京工作八年的经历,月薪仅3万元,存款情况却出乎意料。本文探讨了高学历人才在大城市的职场现状及生活压力。 ... [详细]
  • 本文探讨了在 ASP.NET MVC 5 中实现松耦合组件的方法。通过分离关注点,应用程序的各个组件可以更加独立且易于维护和测试。文中详细介绍了依赖项注入(DI)及其在实现松耦合中的作用。 ... [详细]
  • 深入理解ASP.NET MVC中的_ViewStart.cshtml
    本文介绍了_ViewStart.cshtml文件在ASP.NET MVC 3.0及以上版本中的作用和使用方法。该文件位于Views目录下,主要用于统一配置视图布局和其他全局设置。 ... [详细]
  • FineUI 是一款基于 jQuery 的专业级控件库,专为 ASP.NET WebForms 和 MVC 开发设计。它提供了丰富的用户界面组件,简化了复杂 Web 应用程序的开发过程。 ... [详细]
  • Struts与Spring框架的集成指南
    本文详细介绍了如何将Struts和Spring两个流行的Java Web开发框架进行整合,涵盖从环境配置到代码实现的具体步骤。 ... [详细]
  • 本文作者分享了在阿里巴巴获得实习offer的经历,包括五轮面试的详细内容和经验总结。其中四轮为技术面试,一轮为HR面试,涵盖了大量的Java技术和项目实践经验。 ... [详细]
  • 深入理解Vue.js:从入门到精通
    本文详细介绍了Vue.js的基础知识、安装方法、核心概念及实战案例,帮助开发者全面掌握这一流行的前端框架。 ... [详细]
  • Redux入门指南
    本文介绍Redux的基本概念和工作原理,帮助初学者理解如何使用Redux管理应用程序的状态。Redux是一个用于JavaScript应用的状态管理库,特别适用于React项目。 ... [详细]
  • 本文详细介绍了MySQL数据库中的Bin Log和Redo Log,阐述了它们在日志记录机制、应用场景以及数据恢复方面的区别。通过对比分析,帮助读者更好地理解这两种日志文件的作用和特性。 ... [详细]
  • ssm框架整合及工程分层1.先创建一个新的project1.1配置pom.xml ... [详细]
  • Spring Boot 中静态资源映射详解
    本文深入探讨了 Spring Boot 如何简化 Web 应用中的静态资源管理,包括默认的静态资源映射规则、WebJars 的使用以及静态首页的处理方法。通过本文,您将了解如何高效地管理和引用静态资源。 ... [详细]
  • 本文介绍了一个基于 Java SpringMVC 和 SSM 框架的综合系统,涵盖了操作日志记录、文件管理、头像编辑、权限控制、以及多种技术集成如 Shiro、Redis 等,旨在提供一个高效且功能丰富的开发平台。 ... [详细]
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社区 版权所有