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

重构,让人快乐让人苦

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

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

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

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

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

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

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

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

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

独立的领域层尤为重要

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

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

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

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

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

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

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

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

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

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

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

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

重构,要随时进行

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

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

重构要避免过度设计

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

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

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

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


推荐阅读
  • 本文介绍了一种处理AJAX操作授权过期的全局方式,以解决Asp.net MVC中Session过期异常的问题。同时还介绍了基于WebImage的图片上传工具类。详细内容请参考链接:https://www.cnblogs.com/starluck/p/8284949.html ... [详细]
  • MySQL中的MVVC多版本并发控制机制的应用及实现
    本文介绍了MySQL中MVCC的应用及实现机制。MVCC是一种提高并发性能的技术,通过对事务内读取的内存进行处理,避免写操作堵塞读操作的并发问题。与其他数据库系统的MVCC实现机制不尽相同,MySQL的MVCC是在undolog中实现的。通过undolog可以找回数据的历史版本,提供给用户读取或在回滚时覆盖数据页上的数据。MySQL的大多数事务型存储引擎都实现了MVCC,但各自的实现机制有所不同。 ... [详细]
  • 本文讲述了作者从最初对软件工程的选择迷茫到逐渐喜欢并坚持学习的经历。作者在大学期间通过学习专业课和参与项目开发,不断挑战自己并取得成就感。虽然曾考虑过转专业和复读,但最终决定坚持学习软件工程,并为自己的未来努力奋斗。作者还提到了大学生活与自己最初的预期不同,但对此并没有太多抱怨。 ... [详细]
  • wpf+mvvm代码组织结构及实现方式
    本文介绍了wpf+mvvm代码组织结构的由来和实现方式。作者回顾了自己大学时期接触wpf开发和mvvm模式的经历,认为mvvm模式使得开发更加专注于业务且高效。与此同时,作者指出mvvm模式相较于mvc模式的优势。文章还提到了当没有mvvm时处理数据和UI交互的例子,以及前后端分离和组件化的概念。作者希望能够只关注原始数据结构,将数据交给UI自行改变,从而解放劳动力,避免加班。 ... [详细]
  • Android中高级面试必知必会,积累总结
    本文介绍了Android中高级面试的必知必会内容,并总结了相关经验。文章指出,如今的Android市场对开发人员的要求更高,需要更专业的人才。同时,文章还给出了针对Android岗位的职责和要求,并提供了简历突出的建议。 ... [详细]
  • MVC设计模式的介绍和演化过程
    本文介绍了MVC设计模式的基本概念和原理,以及在实际项目中的演化过程。通过分离视图、模型和控制器,实现了代码的解耦和重用,提高了项目的可维护性和可扩展性。详细讲解了分离视图、分离模型和分离控制器的具体步骤和规则,以及它们在项目中的应用。同时,还介绍了基础模型的封装和控制器的命名规则。该文章适合对MVC设计模式感兴趣的读者阅读和学习。 ... [详细]
  • 本文介绍了MVP架构模式及其在国庆技术博客中的应用。MVP架构模式是一种演变自MVC架构的新模式,其中View和Model之间的通信通过Presenter进行。相比MVC架构,MVP架构将交互逻辑放在Presenter内部,而View直接从Model中读取数据而不是通过Controller。本文还探讨了MVP架构在国庆技术博客中的具体应用。 ... [详细]
  • Todayatworksomeonetriedtoconvincemethat:今天在工作中有人试图说服我:{$obj->getTableInfo()}isfine ... [详细]
  • 从零基础到精通的前台学习路线
    随着互联网的发展,前台开发工程师成为市场上非常抢手的人才。本文介绍了从零基础到精通前台开发的学习路线,包括学习HTML、CSS、JavaScript等基础知识和常用工具的使用。通过循序渐进的学习,可以掌握前台开发的基本技能,并有能力找到一份月薪8000以上的工作。 ... [详细]
  • Asp.net Mvc Framework 七 (Filter及其执行顺序) 的应用示例
    本文介绍了在Asp.net Mvc中应用Filter功能进行登录判断、用户权限控制、输出缓存、防盗链、防蜘蛛、本地化设置等操作的示例,并解释了Filter的执行顺序。通过示例代码,详细说明了如何使用Filter来实现这些功能。 ... [详细]
  • 本文介绍了ASP.NET Core MVC的入门及基础使用教程,根据微软的文档学习,建议阅读英文文档以便更好理解,微软的工具化使用方便且开发速度快。通过vs2017新建项目,可以创建一个基础的ASP.NET网站,也可以实现动态网站开发。ASP.NET MVC框架及其工具简化了开发过程,包括建立业务的数据模型和控制器等步骤。 ... [详细]
  • MySQL数据库锁机制及其应用(数据库锁的概念)
    本文介绍了MySQL数据库锁机制及其应用。数据库锁是计算机协调多个进程或线程并发访问某一资源的机制,在数据库中,数据是一种供许多用户共享的资源,如何保证数据并发访问的一致性和有效性是数据库必须解决的问题。MySQL的锁机制相对简单,不同的存储引擎支持不同的锁机制,主要包括表级锁、行级锁和页面锁。本文详细介绍了MySQL表级锁的锁模式和特点,以及行级锁和页面锁的特点和应用场景。同时还讨论了锁冲突对数据库并发访问性能的影响。 ... [详细]
  • 使用J2SE模拟MVC模式开发桌面应用程序的工程包的介绍
    以我开发过的一个娱乐管理系统为例:下图为我系统的业务逻辑的MVC流程:下图为以Eclipse开发中各包的说明:转载于:https:blog ... [详细]
  • 本文讨论了在shiro java配置中加入Shiro listener后启动失败的问题。作者引入了一系列jar包,并在web.xml中配置了相关内容,但启动后却无法正常运行。文章提供了具体引入的jar包和web.xml的配置内容,并指出可能的错误原因。该问题可能与jar包版本不兼容、web.xml配置错误等有关。 ... [详细]
  • 本文讨论了在ASP中创建RazorFunctions.cshtml文件时出现的问题,即ASP.global_asax不存在于命名空间ASP中。文章提供了解决该问题的代码示例,并详细解释了代码中涉及的关键概念,如HttpContext、Request和RouteData等。通过阅读本文,读者可以了解如何解决该问题并理解相关的ASP概念。 ... [详细]
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社区 版权所有