重构的方式
我有一个以数据为中心的应用程序,是用Python和PyQt写的。我打算进行一些重构,真正把用户界面(UI)和核心部分分开,主要是因为现在还没有真正的测试,这显然需要改变。
现在已经有一些分离的做法,我觉得我做了一些正确的事情,但远远不够完美。这里有两个例子,来说明我在意的地方:
当用户右键点击一个数据对象的表示时,弹出的上下文菜单是由这个数据对象创建的,尽管这个数据对象(基本上是数据库一行的ORM表示)显然和用户界面没有关系。
当写入数据库的操作失败时(比如因为数据库记录被其他用户锁定),会弹出经典的“重试/放弃”消息框给用户。这个对话框是由数据提供者创建的,尽管提供者显然不应该有任何用户界面功能。实际上,提供者可以抛出一个异常或者以其他方式表示失败,然后用户界面可以捕捉到这个信息并做出相应的处理。
* 我用“提供者”这个词来指代基本上代表数据库表的对象,它在数据对象和数据库引擎之间进行调解;我不确定这是否是通常所说的“提供者”。
我没有测试方面的经验,所以不容易“感觉到”可测试性的问题,但在我开始进行测试之前,必须先进行一些重组。
这里没有复杂的业务逻辑(主要就是增、查、改,没错,连删都没有),而且这将更多是重组而不是重写,所以我并不太担心会引入回归错误,就像在这个问题中讨论的那样。
我的计划是开始重构,考虑到用户界面部分可以很容易地被替换成,比如说,一个网页前端或者文本界面,而不是Qt界面。另一方面,Qt本身仍然会被核心部分使用,因为在很多地方使用了信号/槽机制,比如数据对象会发出一个changed
信号来表示,嗯,你知道的。
所以,我的问题是:这样的做法是否可行,以提高可测试性和可维护性?还有其他的建议吗,特别是考虑到Python的情况?
4 个回答
如果你还没看过,建议你读一下迈克尔·费瑟斯的《有效处理遗留代码》。这本书正好讲了这种情况,并提供了很多处理这类问题的技巧。
他提到的一个关键点是,在你开始重构代码之前,尽量先写一些测试。因为这段代码不适合做单元测试,所以可以尝试写一些端到端的测试。我记得Qt有自己的测试框架,可以用来测试图形界面,所以你可以写一些测试,去操作图形界面,使用一个已知的数据库,并验证结果。随着你逐步清理代码,你可以用单元测试来替代或补充这些端到端的测试。
我之前做过大型旧代码的重构,目标是把用户界面和后台分开。这过程既有趣又有成就感。
/赞 ;)
不管你怎么称呼这种模式,或者它是不是MVC的一部分,拥有一个非常清晰的API层是非常重要的。如果可能的话,你可以通过一个调度器来处理所有的用户界面请求,这样你就能更好地控制用户界面和逻辑之间的沟通,比如实现缓存、身份验证等功能。
为了更好地理解:
[QT Frontend]
[CLIs] <=======> [Dispatcher] <=> [API] <==> [Core/Model]
[SOAP/XMPRPC/Json]
[API Test Suite]
这样做的话
- 更容易添加测试套件来测试你的API。
- 也让添加更多用户界面变得统一且简单。
- API文档:比如说你想通过某个RPC接口来记录和展示API,生成API文档会更简单。如果有人不认同API文档的重要性,可以看看Twitter的API和它的成功。
- 你可以快速把API层导入到Python环境中,进行尝试。
API设计可以在你开始编写API层代码之前就进行。根据应用的不同,你可能会想使用像zinterfaces这样的工具包。这是我在写非常小的应用时也会采用的一种通用方法,而且从来没有失败过。
建议你看看
这种方法的一个明显优势是,当你有了API层和新的用户界面后,你可以回过头去修复或重构旧代码,可能会以更小的步骤进行。
另一个建议是准备好你的测试套件。可以参考interstar在在旧应用中实施单元测试的第一步任务中的建议。