最近项目组里有一个bug,虽然我们大家都没有因为他而享受到“深夜静静改bug”的“乐趣”,但他也着实郁闷了我们一番。还好我们的Mr S同学已经将他拿下,在这篇blog,将记录下我看到这个bug时的思考:
bug描述:我们既存的一个连接池出现了泄漏问题。
bug原因:
我们有下面这么一个函数
void freeConnection(String type, ConnectionAdapter con);
因为我们有两个连接池,一个叫做Derby,一个叫做demo,使用一个字符串指明链接要网哪里还。然而问题来了,以前的一位同事,写下了下面这样的代码:
String dbConnType = "derby"
......
db.freeConnection("dbConnType", conn);
是的,因为根本不存在dbConnType这么一个连接池。所以运行一段时间之后,我们的的连接池里面没有了链接。
bug改修:
那么这个bug该怎么改呢? 拿掉那个变量的双引号?我想不是的。好的办法我认为有几个,最后一个是前面几个的递进,但他们思考的角度都是让接口更友善,让使用更方便:
1. 从freeConnection的角度思考,在freeConnection里面加卫语句。
既然我们能确定我们的代码中只有两个pool,那么当freeConnection在接受到"derby"和"demo"这两个参数以为的参数的时候,他就应该报告他的调用者,说:“嗨,你使用我使用错了。” 比如我们可以抛出一个IllegalArgumentException。
2. 从freeConnection的调用者的角度思考。改变freeConnection的调用参数。
这个问题的一个很隐晦的地方在于,使用了字符串来标识,我们要释放拿个池的链接。而程序中又充值着这样的使用方法。
db.freeConnection("derby", conn); //想加引号,因为想直接释放derby这个池
db.freeConnection("dbConnType", conn); //不想加引号,无用了,但是编译器没有帮我们区分过来。
这两个用法本身就很容易混,那么从freeConnection函数的使用者看来,完全有理由呼吁一个更友善的接口,比如像下面这样
ConnectionManager{
...
public static final ConnectionPool DERBY_POOL = ...
public static final ConnectionPool DEMO_POOL = ...
...
}
void freeConnection( ConnectionPool pool , ConnectionAdapter con);
这样做的好处是,利用类型保证了参数不会被误传,但是这样做的同时也暴露了很多东西,引来了其他的一些不可取之处。比如带着一个没用的参数,还是一个链接池,在代码各处跑来跑去,这么麻烦我们当初还为什么要写ConnectionManager
3. 综上,所以有了方法三:freeConnection方法的接口其实根本就应该是这样的;
freeConnection(Connection conn);
是的,总之是用户传递错误了参数,那么与其像上面那样,帮助用户传递正确的参数,到不如压根就不要求用户传递这个参数。而且,既然你有意要做一个ConnectionManage,那么关于这个池那个池的,本身就应该封装在你的里面,Don't make user think了。
恩,事情说完了。 保证质量是多方面的,不是很努力的测就可以解决的问题,先撇开测试调试的技巧之类,其势必也受质量等其他因素的制约。好的设计从哪里来呢?好的设计应该即是程序员推敲的结果,又是他们的直觉使然。