关于 java:将现有的凌乱 webapp 迁移到优雅的 MVC 的最佳方法是什么?

关于 java:将现有的凌乱 webapp 迁移到优雅的 MVC 的最佳方法是什么?

What is the best way to migrate an existing messy webapp to elegant MVC?

大约一个月前,我加入了一家新公司。公司规模比较小,有很强的"创业"感。我在一个由 3 人组成的团队中担任 Java 开发人员。该公司主要向企业/业务类型的人出售用于相互交流的服务。

我过去和将来的主要工作之一是公司的主要网站 - 从中??出售服务,现有用户登录以检查他们的服务并支付账单,新用户可以注册用于试用等。目前这是一个部署在 Tomcat 上的 JSP 应用程序,可以通过公司自己编写的持久层访问数据库。

我在这里遇到了反复且越来越多的挫败感(而且我对这份工作总体上很满意,所以这不是一个"哦,不,我不喜欢我的工作"类型的帖子)是这个 Web 应用程序缺乏任何更大的设计或架构。该应用程序由几十个 JSP 页面组成,几乎不存在 Servlet 或 Beans 或任何其他类型的框架中的逻辑。许多 JSP 页面是数千行代码,它们 jsp:include 其他 JSP 页面,业务逻辑与 HTML 混合,经常使用的代码Fragments(例如获取 Web 服务连接)被剪切和粘贴而不是重用等。换句话说,应用程序是一团糟。

公司内部曾传出一些谣言,试图重新设计这个网站,以使其更适合 MVC;我认为开发人员和高层开始意识到这种当前的意大利面条代码模式是不可持续的,或者很容易扩展为用户添加更多功能。高层和开发人员对完全重写事物持谨慎态度(有充分的理由,因为这意味着重写现有功能需要数周或数月的工作),但我们已经讨论过(慢慢地)重新编写- 将网站的某些区域写入新框架。

有哪些最佳策略可以让应用程序和代码库朝着这个方向发展?作为一名开发人员,我如何才能真正帮助快速推进这项工作,而不是看起来像一个刚入职并告诉所有人他们写的东西都是废话的混蛋?当您遇到此类事情时,您在自己的工作经历中是否使用过任何行之有效的策略或经验?


你最好的选择可能是在你进行的过程中慢慢地重构它。很少有人拥有从头开始完全从头开始的资源,其中隐藏着如此多的业务规则。当您花费数月时间开发一款错误比您替换的应用程序更多的应用程序时,管理层真的很讨厌它。

如果您有机会从头开始构建任何单独的应用程序,请使用那里的所有最佳做法并用它来证明它们的有效性。尽可能将这些想法逐渐融入旧应用程序中。


首先拿起一份 Michael Feather 的《有效地使用旧代码》。然后确定如何最好地测试现有代码。最坏的情况是你只被一些高级回归测试(或根本没有)困住,如果你幸运的话,会有单元测试。然后是一个缓慢稳定重构的案例,希望同时添加新的业务功能。


我同意缓慢的重构方法;例如,将复制粘贴的代码提取到适当的 Java 范式中(也许是一个类?或者更好的是,使用现有的库?)。当您的代码非常干净简洁,但仍然缺乏整体架构策略时,您将能够更轻松地使事物适应整体架构。


这在仅处于维护模式的应用程序中更难做到,因为很难让管理层相信重写已经"工作"的东西是值得的。我将首先将 MVC 的原则应用于您能够处理的任何新代码(即将业务逻辑移动到类似于模型的东西,将所有布局/视图代码放在一个地方)

随着您在 MVC 中获得使用新代码的经验,您可以开始看到巧妙地更改现有代码以使其符合要求的机会。这可能是一个非常缓慢的过程,但如果您能展示这种方式的好处,那么您将能够说服其他人并让整个团队参与进来。


根据我的经验,应用程序的"优雅"通常更多地与数据库设计有关。如果您拥有出色的数据库设计,包括定义良好的存储过程接口,那么无论您使用什么平台,都倾向于遵循良好的应用程序代码。如果您的数据库设计不佳,那么无论您使用什么平台,都将很难构建优雅的应用程序代码,因为您将不断地对数据库进行补偿。

当然,好与坏之间有很大的差距,但我的观点是,如果你想要好的应用程序代码,首先要确保你的数据库符合标准。


我的建议是找到不需要导入其他 JSP 或很少导入的稀有页面。将每个导入的 JSP 视为一个黑盒,并围绕它们重构这些页面(迭代地测试每个更改并确保它在继续之前有效)。清理完这些后,您可以继续查找具有越来越多导入的页面,直到最终重构了导入。

重构时,请注意尝试访问未提供给页面的资源的部分,并尝试将其带到控制器中。例如,任何访问数据库的东西都应该在控制器内部,让 JSP 处理控制器通过转发提供给它的信息的显示。通过这种方式,您将为每个页面开发多个 servlet,或类似 servlet 的东西。我建议使用基于前端控制器的框架进行此重构(根据个人经验,我推荐 Spring 及其 Controller 接口),以便每个控制器不是单独的 Servlet,而是委托给适当映射的单个 servlet。

对于控制器,最好一次完成所有数据库命中,而不是零碎尝试。用户可以并且通常确实可以容忍页面加载,但是如果将所有数据库数据都提供给渲染代码而不是渲染代码挂起并且在客户端尝试读取另一个数据时不向客户端提供数据,则页面输出会快得多来自数据库的一条数据。

我能感受到你的痛苦,并祝你在这项工作中好运。现在,当您必须维护一个滥用 Spring Webflow 的应用程序时,那就是另一回事了 :)


迭代重构。还要寻找可以完全在新框架中完成的新功能,以此来展示新框架的价值。


最好的方法是将代码打印出来,揉成一团,然后扔掉。甚至不要回收纸张。

您有一个用 1,000 行长的 JSP 编写的应用程序。它可能有一个糟糕透顶的领域模型(如果它甚至有的话),并且不只是将表示与业务逻辑混合在一起,它还混合了它并坐在那里并持续搅拌数小时。没有办法取出蹩脚的代码并移动到 MVC 控制器类中并且仍然做正确的事情,您最终会得到一个具有贫血域模型或具有诸如数据库之类的东西的 MVC 应用程序调用控制器代码,你仍然失败。

您可以尝试一个做正确事情的新应用程序,然后让这两个应用程序相互通信,但这本身就是新的复杂性。此外,如果您刚从头开始,您可能会做同样多的工作,但您可能会更容易说服老板相信这是一种更好的方法。


推荐阅读