系统对象替换策略
我们目前正着手用 Linq 替换 C# 应用程序中的 ADO.NET 堆栈。
由于应用程序不是使用数据抽象层构建的,因此应用程序的几乎每一层都存在 ADO 调用,以至于划分任何一个对象并尝试将其转换为 Linq 意味着您会陷入兔子洞的迷宫。
我要问的是,应对这种大规模系统性变化的策略或方法,同时确保适当的测试和最小的“放弃工具”缓冲期(立即搁置更改,并在稍后再回来处理)。
我们尝试过以下操作:
- 使用新代码创建每个对象的镜像对象 = 必须维护 2 个代码库,直到完全转换
- 用 ADO_ 为 ADO 函数的所有函数名称添加前缀,并使用原始名称创建 Linq 版本
- 有一个系统范围的 FLAG表示是使用 ADO 还是 Linq 并用 if (FLAG) { ADO } else { Linq } = 必须在转换后返回并删除所有 ADO 引用来包装每个 ADO 调用
到目前为止,每个建议都值得畏缩。
你们有什么建议?
注意:我从标题中删除了“(ADO to Link)”,因为我正在寻找更通用的答案和实践,而不仅仅限于此处用作示例的 ADO 到 Linq 转换。
We are currently embarking on replacing the ADO.NET stack in our C# application with Linq.
Because the application was not architected with a data abstraction layer, there are ADO calls throughout just about every layer of the application to such a degree that compartmentalizing any one object and trying to convert it to Linq means that you run down a labyrinth of rabbit holes.
What I am asking, are stategies or approaches to tackling such wholesale systemic changes while ensuring proper testing and a minimal 'drop tools' wind-down period (shelf making changes at a moments notice and come back to it at a later date).
We have toyed with the following :
- Create a mirror object of each object with the new code = have to maintain 2 code bases until full conversion
- Prefix all function names of ADO functions with ADO_ and create Linq versions with original name
- Have a system wide FLAG to denote whether to use ADO or Linq and wrap every ADO call with if (FLAG) { ADO } else { Linq } = have to go back after conversion and remove all ADO refs
Every suggestion so far is cringe-worthy.
What do you guys/gals suggest?
NOTE: I removed '(ADO to Link)' from the title because I am looking for more generic answers and practices and not just limited to the ADO to Linq conversion used as an example here.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
在进行任何更改之前,您确实应该进行自动化单元测试。事实上,对于至少 80% 未被单元测试覆盖的代码,您不应该进行任何更改。
在现实世界中,单元测试通常不存在。另一方面,在没有单元测试的情况下进行任何重构可能会完全搞砸您的代码,使管理层更不可能允许您将来进行更改。该怎么办?
使用 ReSharper 这样的工具,您可以首先应用一些“更安全”的重构。小心地,您没有理由不能成功地重复使用“提取方法”将 ADO.NET 代码移动到单独的方法中,如果它还不是静态的,则“使方法静态”,然后“移动方法”或“使方法非静态”将方法移至单独的类中。
一旦您将代码移出,您就可以开始编写一些自动化测试。在这个阶段,它们不需要是严格意义上的“单元测试”。特别是,应该允许这些测试与数据库一起工作。
当您只剩下不容易进行单元测试的代码时,您可以非常仔细开始使该代码更易于测试。您可以执行诸如将静态方法集转换为新类的实例方法之类的操作。您还可以开始引入依赖项注入,以便更轻松地使用模拟对象进行测试。但这里要非常小心 - 您正在修改没有自动化测试的代码,并且您将使用实际上可能会破坏内容的重构。
一旦您对代码进行了充分的测试,那么您就可以重新组织代码以使其更有意义,然后根据需要对其进行修改以使其使用 LINQ。
You should really have automated unit tests before making any changes. In fact, you should make no changes for code that isn't covered by unit tests at least 80%.
In the real world, unit tests often do not exist. On the other hand, doing any refactoring without unit tests can totally screw up your code, making Management even less likely to permit you to make changes in the future. What to do?
Using a tool like ReSharper, you can begin by applying some of the "safer" refactorings. With care, there's no reason you can't be successful in repeatedly using "Extract Method" to move your ADO.NET code into separate methods, "Make Method Static" if it wasn't already static, then either "Move Method" or "Make Method Non-Static" to move the method into a separate class.
Once you've got the code moved out, you can begin to write some automated tests. At this stage, they don't need to be "unit tests" in the strict sense of the word. In particular, these tests should be allowed to work with the database.
When you're left only with code that can't easily be unit tested, you can then, very carefully start making that code more testable. You can do things like turn sets of static methods into instance methods of new classes. You can also begin to introduce dependency injection, to make it easier to test using mock objects. But be very careful here - you're modifying code which has no automated tests, and you'll be using refactorings that can actually break stuff.
Once you've got the code adequately tested, then you can reorganize the code to make better sense, and then modify it to make it use LINQ if you like.
您仍然可以利用最初为 Linq2SQL 解决方案创建的所有存储过程/函数。使用类似于 Micheal Feather 的
使用遗留代码
中所表达的策略,您可以在应用程序区域周围创建边界并在这些边界内进行更新。我过去使用的策略是维护/忽略数据库及其对象。然后,我慢慢地迭代不同的 ADO 调用并替换为 Linq2SQL 调用,直到整个应用程序都使用 Linq2SQL。然后,我发现将之前公开并传递数据集/数据表的 ADO 调用转换为更合适的实体变得更加容易。
另一种方法(对于 DataSet/DataTable 重型解决方案)是保留 ADO 调用,并使用扩展方法
AsQueryable()
和/或OfType()
将 ds/dt 项转换为适当的实体,然后将这些更改聚合为更具内聚性的 DAL。You can still leverage all of your stored procedures/functions originally created for your solution with Linq2SQL. Using something like the strategies expressed in Micheal Feather's
Working with Legacy Code
you could create boundaries around regions of the application and update within those boundaries.The strategy I have used in the past is maintain/ignore the database and its objects. I then slowly iterate through the different ADO calls and replace with Linq2SQL calls until the entire application is using Linq2SQL. I then find it easier to transform the previous ADO calls that exposed and passed DataSets/DataTables into more appropriate entities.
Another approach (for DataSet/DataTable heavy solutions) is to keep the ADO calls in place and instead use the extension methods
AsQueryable()
and/orOfType<T>()
to transform the ds/dt items into appropriate entities, then aggregate these changes into a more cohesive DAL.