Fork me on GitHub
一次重构

记我的一次重构——希望对新人有所帮助

看过博客园里几篇关于重构的文章,感觉都不怎么实在。下面我来谈谈自己的一次重构经历,希望对新人能有所帮助。

 

ALinq 这个产品维护了将近五年的时间,最近对它进行了一次重构。为什么要重构?主要是为了适应业务的发展需要。产品是服务于业务,而重构是服务于产品,归根到底,重构是服务于业务。所以我一直强调,好的架构不是想出来的,而是做来的,经验积累下来的。很多时候业务的发展,往往会超出你出初的预期,所以在产品的前期想设计出一个完美的架构是不可能的事。

 

这次的重构,出现了很多问题,一直陆续推出了好几个版本,才开始稳定下来,还好我的用户都是些忠实的用户,用ALinq好几年了,一直耐着性子,一个版本一个版本地安装,然后试用,真心感谢他们。

 

重构的代价,其实还是挺大的,所以在重构之前,尽可能多做一些工作,使得付出的成本能尽可能地降到最低。重构前要做工作有下面几个方面:

 

1、测试用例。这个是一定要的,并且,测试用例要全面。对于ALinq来说,就是单元测试+文档了。在重构完成后,先跑单元测试,然后再按着文档的描述,进行操作。界面的操作是很难写单元测试,即使可以,付出代价也太大了,远大于人工测试。

 

2、划分各个功能模块,每个模块的职责,也就是要做些什么。

 

3、提炼接口,这是必须的。

 

下面我们进一步谈谈为什么要进行重构,为了让大家能够更理解这次的重构,先来介绍简单一下产品的功能以及产品的发展线路。

 

现有功能

 

先来看一下图一,图一展示的功能主要有显示用户的授权信息、检查产品的更新,显示产品的信息。图二展示的功能有,将修改后的模型更新到数据库,将修改后的数据库更新到模型,就是模型与数据库的同步,如图三所示。

 

发展线路

 

1、增强用户的体验。主要有:

 

  1. 检查更新,然后再到网站下载,接着卸载旧版本,接着再装新的版本。我希望将来是一点菜单,就把一系列的动作全部完成。
  2. 授权信息,简单点说就是输入注册码。现在是,由于产品是一年内免费更新的,如果这一年内,产品升级了,或者验证码的算法改了,那么就得重新发送一次验证码到用户的邮箱,并且,用户还得保管好注册码,如果万一不记得了,还得找客服(客服就是我了,当然作者也是我)重新要回注册码。我希望是用户一点菜单,然后输入邮箱就可以自动取回相应版本的注册码,如果再输入密码,就能从网上下载注册码,然后自动完成注册。
  3. 向客户推送一些使用技巧的提示,或者文章。这是新的功能,菜单上没有。

 

关于用户体验要做的改进,现在想到的,暂时就是这些,当然,不限于这些。

 

2、数据库与模型的同步,这方面的功能现在太弱了。准备加强建模以及建库的功能,对于建模功能,未来有可能向PowerDesigner的方面发展。而建库的功能,就是能直接在界面上很方便对数据库进行修改。

 

那么现在面临的问题是什么呢?这部份代码是夹杂在视图模块里面的。而视图模块这部份的功能,是很稳定的了。视图模块,指的是把表从数据库里拖出来,生成实体类,或者从工具栏里,拖个图标出来,生成实体。如果不进行重构,易变的代码和稳定的代码交织在一起,那么易变代码的修改,势必会影响到已经相对稳定的模块。我对重构的理解是把变和不变的分开,对架构的理解是封装变化。

 

那么为什么会造成这种结果?

 

1、业务的发展

 

2、没能预期到业务的发展

 

话说,几年前的东西,怎么可能预测今天要弄些啥呢,哥是人,不是神。

 

到这里,明白为什么要重构了,以及重构的意义了吧。重构,不是你捧着本书,对着上面的教条,看哪不顺眼,就来耍耍。架构,不是你看了设计模式的书,然后依样画葫芦就弄得出来的了,而是必须依据业务的发展。是否重构,必须站在业务的层面去看待,而不仅是代码层面。如果系统很稳定,业务也很稳定,一般情况下是没有重构的必要的,哪怕代码写得再烂。

 

架构其实就是经验的积累,然后加上思考。当你的经验积累到一定的程度,架构自然就会有了。所以,建议刚入门程序员,应该多花时间代码的阅读、算法上。可别让那些重构、模式的书都误导了,随便看看就行了,不要花太多的时间。

 

如果我的这篇文章让你对重构有个更深的认识,那么我的目的也就达到了,谢谢阅读。读完请勿忘点击“推荐”,再次感谢。^_^

 

 

 

 

(图一)

 

 

 

 

(图二)

 

 

 

 

 

 

 

 

(图三)

 

 性能问题的分析定位方法

之前写过一篇性能测试新手误区(五):这是性能问题么,主要讲一个有效的性能问题应该是什么样的,其中提到了定位的问题。但是那篇文章只说了WHAT,并没有说HOW,只说tester要有明确的定位,却没提如何才能定位。实际工作中,我也总是接到这种问题,所以还是要写一篇关于方法的文章,来说说HOW TO DO。

以一个典型的WEB系统来举例,性能问题一般体现在客户端请求后的响应时间上。在性能测试过程中,即压力增大到某个程度后,响应时间指标迅速增长。但如那篇文章所说,这只能叫做一个现象,测试人员需要找到问题所在,HOW TO DO?

首先要搞清楚,客户端从发出请求直到看到最终结果,共经历了哪些过程。如果绘制出一张完整的路径图,我们的问题必将定位到这张图中的某一点上。下面是我画的一个常见的WEB系统请求的流转过程。

请求路径

客户发出一个请求,这个请求首先会到达中间件的监听端口,专门的监听线程负责接待它,并将它分配给一个空闲的HTTP处理线程。HTTP线程根据请求内容,去执行相应的程序代码,这里会涉及程序的内部资源,比如专用的线程、一些队列等,程序的内部也许还有多个组件,依然可以拆分。再往后,从中间件维护的数据库连接池中取出一个空闲连接,通过它来与数据库进行交互。数据库收到查询请求后,同样需要找到一个可用的执行线程,然后才能执行具体的SQL,这里又会牵扯到很多数据库的内部资源,如锁、缓存等等。

可以看到,从用户点击鼠标发出请求,到显示器上展现出结果,实际是经过了很多处理过程的,这里的每一个节点出现问题,都会导致我们最终看到的“响应慢”现象出现(这里不考虑操作系统层面、网络层面等一些外层的因素)。

理解了这个过程,只需采取一些科学的方法即可逐渐逼近问题根源,那就是层层剥离、不断排除。从实际经验来看,数据库端最容易出问题,那么首先就要对其进行验证。数据库的性能一般是直接体现在SQL的执行效率上,我们可以捕获到出现问题时所有执行过的SQL,看其耗时是否正常。如果判断数据库端没有问题,那么再来到中间件端,这里又可分为应用服务器本身和我们自己的程序,可以先看看最容易验证的部分,应用服务器本身通常维护了一些线程池,很容易可以观察到它们的使用情况,如果这里没有发现异常,那么问题很可能就出现在我们程序的代码内部。如果在某一点上发现了异常现象,不要急于断定这里就是问题根源,而是要同时观察与之相邻节点的表现,一个节点的故障通常也会导致另一节点的异常。

一个很有效的排查手段就是日志,在每一个节点上输出接收到的请求和处理结果的日志,通常都会很容易的发现问题。

大致思路就是这样,总结起来其实很简单。一是要理解请求处理的完整流程,二是通过科学合理的方法去分析。

最后推荐个比较典型的问题排查过程供大家体会,超级奇怪的“黑色10秒钟”。我自己也有一些这种很有代表性的分析过程,有时间整理好也贴上来。

posted on 2013-06-03 16:43  HackerVirus  阅读(156)  评论(0编辑  收藏  举报