将现有凌乱的Web应用程序迁移到优雅的MVC的最佳方法是什么?
我大约一个月前加入了一家新公司。该公司规模很小,并且具有很强的"启动"感觉。我作为Java开发人员正在其他3个人的团队中工作。该公司主要向企业/商务人士出售服务,以用于彼此沟通。
我一直(并将要进行的工作)的主要内容之一是销售该服务的公司的主要网站,现有用户登录以检查其服务并支付账单,新用户可以注册进行试用,目前,这是一个部署在Tomcat上的JSP应用程序,可以通过公司本身编写的持久层访问数据库。
我在这里遇到的一遍又一遍,越来越多的挫败感(我对整体工作很满意,所以这不是"哦,不,我不喜欢我的工作"式的帖子)是缺少更大的设计或者此Web应用程序的体系结构。该应用程序由几十个JSP页面组成,几乎没有Servlet,Beans或者任何其他类型的框架中存在的逻辑。许多JSP页面是数千行代码,它们在其他JSP页面中是jsp:include,业务逻辑与HTML混合在一起,常用的代码片段(例如获得Web服务连接)被剪切并粘贴了。比重用等等。换句话说,应用程序是一团糟。
公司内部有一些谣言,试图重新设计该站点,以使其更好地适合MVC。我认为开发人员和高层人士已经开始意识到,这种意大利面条式代码的当前模式是不可持续的,或者很难扩展以为用户添加更多功能。高层和开发人员对完全重新编写事物持谨慎态度(有充分的理由,因为这将意味着数周或者数月的工作来重新编写现有功能),但是我们已经(缓慢地)重新讨论了一些将网站的某些区域写入新框架。
使应用程序和代码库朝这个方向发展的最佳策略是什么?作为开发人员,我怎样才能真正帮助并迅速地完成这一任务,而又不会像一个新手一样突然进入工作岗位并告诉每个人他们所写的东西是废话呢?遇到这种事情时,我们是否在自己的工作经历中使用了行之有效的策略或者经验?
解决方案
回答
我们最好的选择可能是在进行过程中慢慢重构它。几乎没有我们拥有从头开始完全需要的资源,而其中却包含了许多业务规则。当我们花数月时间开发一款比替换的错误多的错误的应用程序时,管理层真的很讨厌它。
如果我们有机会从头开始构建任何单独的应用程序,请使用此处的所有最佳实践并使用它来证明它们的有效性。如果可以的话,将这些想法逐渐合并到旧的应用程序中。
回答
以我的经验,应用程序的"优雅"通常与数据库设计息息相关。如果我们具有出色的数据库设计,包括定义良好的存储过程接口,那么无论使用哪种平台,都倾向于遵循良好的应用程序代码。如果数据库设计不佳,那么无论我们使用哪种平台,都将很难构建优雅的应用程序代码,因为我们将不断补偿数据库。
当然,优缺点之间有很多余地,但是我的观点是,如果我们想要好的应用程序代码,请首先确保数据库能够正常使用。
回答
在仅处于维护模式的应用程序中很难做到这一点,因为很难说服管理者重写已经在"工作"的东西是值得做的。我首先将MVC的原理应用于我们能够处理的任何新代码(即,将业务逻辑移至类似于模型的事物,将所有布局/视图代码放在一个位置)
随着我们在MVC中使用新代码的经验不断积累,我们可以开始看到一些机会来巧妙地更改现有代码,从而使它们也保持一致。这可能是一个非常缓慢的过程,但是如果我们可以证明这样做的好处,那么我们将能够说服其他人并使整个团队参与其中。
回答
我同意缓慢的重构方法;例如,采用复制粘贴的代码并将其提取到适当的Java范例中(也许是一个类?或者更好的是,使用现有的库?)。如果代码确实干净整洁,但仍然缺乏整体架构策略,那么我们将可以轻松地使事情适合整体架构。
回答
最好的方法是打印出代码,将其粉碎,然后扔掉。甚至不要回收纸张。
我们已经用1000多个行的JSP编写了一个应用程序。它可能有一个令人敬畏的领域模型(如果它甚至根本没有一个),并且不仅是带有业务逻辑的MIX演示,它还会将其混合并放置在那里并持续搅拌数小时。没有办法将糟糕的代码移到MVC Controller类中并且仍然做正确的事,我们最终只会得到一个带有贫乏域模型的MVC应用程序,或者拥有诸如数据库调用之类的东西的MVC应用程序在Controller代码中,我们仍然失败。
我们可以尝试一个做正确的事情的新应用,然后让两个应用相互通信,但这本身就是新的复杂性。同样,如果我们从头开始,我们可能会做与要做的工作量相同的工作,但是我们可能会更轻松地尝试说服老板,这是一种更好的方法。
回答
首先,拿起迈克尔·费瑟(Michael Feather)的《有效使用旧版代码》的副本。然后确定如何最好地测试现有代码。最糟糕的情况是,我们只能进行一些高级回归测试(或者根本不进行任何测试),如果幸运的话,还会有单元测试。然后是希望缓慢稳定重构的情况,同时添加新的业务功能。
回答
迭代重构。还要寻找可以在新框架中完全完成的新功能,以显示新框架的价值。
回答
我的建议是找到不需要导入其他JSP或者导入很少的稀有页面。将每个导入的JSP视为一个黑匣子,然后重构它们周围的这些页面(反复测试每个更改,并确保它可以工作,然后再继续)。清理完这些内容后,我们可以继续查找包含越来越多导入的页面,直到最终重构了导入。
重构时,请注意尝试访问未分配给页面的资源的部分,并尝试将其带给控制器。例如,任何访问数据库的内容都应该在控制器内部,让JSP处理该控制器通过转发提供给它的信息的显示。这样,我们将为每个页面开发几个servlet或者类似servlet的东西。我建议使用基于前控制器的框架进行此重构(根据个人经验,我建议使用Spring及其Controller接口),以便每个控制器不是单独的Servlet,而是委托给适当映射的单个Servlet。
对于控制器,最好一次全部执行数据库命中,而不是尝试将它们零散地进行。用户通常可以容忍页面加载,但是如果将所有数据库数据都提供给呈现代码,而不是呈现代码挂起并且在尝试读取其他代码时不将数据提供给客户端,则页面输出会更快。数据库中的一条数据。
我感到痛苦,并祝我们在这项工作中取得好运。现在,当我们必须维护滥用Spring Webflow的应用程序时,这又是另一回事了:)