【问题标题】:How to migrate ugly and undocumented VB6 Code to .NET如何将丑陋且未记录的 VB6 代码迁移到 .NET
【发布时间】:2010-01-20 14:20:39
【问题描述】:

我知道已经有关于 VB6 迁移的问题,但是我项目的代码库在这里带来了一些新问题。

我不得不说代码质量、结构和架构简直就是一场噩梦。 有2个大项目: Nr.1 有 40 个表单、40 个模块和一些类文件,这个 EXE 是一种“基础系统”。 Nr.2 有 80 个表格,20 个模块和一些类文件,这个 EXE 调用函数形成了“基础系统”。 然后还有大约 10 个其他带有 GUI 的项目(每个 1-3 个表单)和另外 90 个非 GUI 项目,其中大部分是 EXE 文件,一些 DLL。 DLL 是用 C、C++ 和 VB6 编写的。

代码自 10 年以来不断发展,并且一次主要由 1 个(糟糕的)开发人员编写。

  • 具有 500 行(甚至更多)的函数非常常见。
  • 90% 的 GUI 组件被命名为 text1、command2(1)、……
  • 复制和粘贴到处都是 e. G。复制了一个包含 5000 行代码的 EXE 项目(没有 GUI),副本中唯一的变化是每个邮件而不是 FTP 发送文件(同一项目还有 2 个另外的副本)。
  • 我曾经有一个小表单(15 个字段),我应该在其中解决一个小问题(通常最多半小时),每次我更改某些内容时,它要么不起作用,要么产生新的错误形式。 2 天后,我决定彻底重写表格,从旧表格中的约 20 条 SQL 语句中,只有 2 条在新表格中幸存下来。
  • 甚至不要在代码中询问 cmets ...

几个月前我接手了这个项目,我是唯一的维护者。变更请求和错误持续(但很少)流,我们从客户那里获得维护预算,以保持软件运行并根据法律要求“保持最新”。

我的选项

1) 从头开始​​重写 - 在这种情况下,我可以用 Java 编写它以实现可移植性。 这里的问题是除了一些(旧的)用户帮助之外,没有文档,所以丑陋的代码就是“文档”。有一个人有高层知道软件应该怎么做。此外,很难说服管理层这样做,即使从长远来看可以节省大量成本,也存在政治问题。我也不能一次做一个(vb)项目,因为数据库结构并不比代码好,即也必须从头开始。所以我只能一次更改整个软件。

2) 将代码迁移到 VB.NET / C# 首先迁移主要项目,我已经对其进行了测试,并从 Project Nr.1 中获得了大约 2000 个升级 cmets,其中大部分内容如 Screen.MousePointer 已更改,具有变体返回值的函数等。 我的想法是在转换之后,为 DB 抽象创建类,更改代码以使用这些类并进行重构,迁移和更改其他项目,当所有代码都使用 DB 类时,更改 DB 结构。

3) 无论如何我必须在 VB6 中更改某些内容时重构代码(我已经部分地这样做了),并在某些时候重构其余部分。这样更容易看到原始功能,因为它是原始代码,当出现错误时,很明显它们不可能是迁移的结果。 当代码被重构时(我假设它也会小 50-75%),将它迁移到 .NET 会更容易。然后更改 DB 结构(然后进行另一轮重构……)。

将来会有一些更大的更改(使其与 Win7 兼容,以及影响大部分代码的另一个大 CR),所以会有一个很好的机会来做这些更改,我将有无论如何都要通过很多代码。

我的问题是谁有迁移糟糕、丑陋的代码的经验/提示?您会建议哪些选项?

【问题讨论】:

  • jobs.stackoverflow.com ;-)
  • 我使用选项 2 做了一个 25,000 多行的 Excel 插件。

标签: .net vb6 vb6-migration


【解决方案1】:

我不得不经历同样的事情(没有文档和可怕代码的大型 VB6 应用程序。)。您可以采取的唯一安全合理的路线是第 3 条。要改进某些东西,您必须首先了解它。如果您选择路线 1 或 2,您肯定会遇到可怕的混乱。

请记住始终牢记您的最终目标是完全迁移到 .NET。在重构时,请考虑 VB6s 糟糕的 OO 支持在 VB.NET 或 C# 中的样子。如果可能的话,改变你的代码以使迁移更容易。

您可能需要考虑将许多核心功能转移到 .NET DLL 中,并通过 COM 将其公开给 VB6。这将从您的 VB6 中删除大量可笑的代码,并有望留下大部分业务逻辑。

您需要记住的最重要的事情是不要成为牛仔。

  1. 为模块编写测试。
  2. 重构一个模块。
  3. 测试模块。
  4. 发布您的应用。
  5. 转到 1

【讨论】:

  • 冒着引发宗教战争的风险,我可能建议添加步骤 0:编写测试并将 4 更改为 GOTO 0
  • 跛脚列表功能不支持0。
  • 我已经在这样做了(将每个项目中作为代码副本存在的 ini 和注册表处理移动到 dll,将 FileExists() 函数的代码与 FileSystemObject.FileExists 交换,等等)但是我在那里看到了一个大块:数据库。我不能那样改变数据库结构。数据库调用主要是简单的调用,但它们无处不在。对此有任何提示吗?作为预告片:有代码循环遍历文件夹并向它找到的每个访问数据库发送查询,以查找一些值...
  • 天哪,摆脱所有内联 SQL 调用是我们转换的关键。我们实际上用 C# 编写了一个 Core 库,并向 VB6 公开了一个 COM 接口。然后我们就可以通过 Core 抽象出数据库调用。
  • 我也做过同样的事情。单元测试是最重要的(我使用了 VBUnit)。每次我需要进行更改时,我最终确定了一种“梳理应用程序”的模式,每次都解决一种类型的问题。我会在每个模块而不是整个模块中重构某些任务(比如说,创建一个可以重置字体的函数,或者其他什么。如果我必须这样做一次,然后我会在应用程序中搜索以查找任何其他代码更改了字体,所以现在所有字体更改都将通过我的新功能)我最终对应用程序有了很好的了解,
【解决方案2】:

代码一定要迁移吗?如果它没有,仍然可以达到它的目的,并且可以维护一半,只需别管它,继续前进

在数小时、数周和数月的代码迁移之后,您将代码迁移到新语言的动力很快就会消退——尤其是在您提到的规模上。

从概念上讲,代码迁移的想法是一个绝妙的想法。很可能,这是一个可怕的混乱,你会讨厌这样做的生活。

想一想,你现在在修复缺陷时讨厌你的生活吗?为迁移项目升级 100 倍。

只要有效,大多数企业就不会真正关心引擎盖下的内容。请记住,他们不是开发人员,不在乎修复它是多么痛苦(因为他们不是这样做的人)并激励企业花费数万美元带来代码是最新的,根本没有任何商业意义。

【讨论】:

  • 我不同意重构然后迁移到 C# 是我们做过的最好的事情。
  • 我认为您的意思是“概率”而不是“现实”。好点+1,尽管Chaos Pandion指出这可能完全错误。
  • 我现在同意你的主要观点。代码迁移项目是一项巨大的承诺,但如果您不一次承担太多任务并始终致力于一致的迁移过程,那么所有人(包括非编码人员)都可以看到结果。
  • 是的,在修复缺陷时,我确实讨厌我现在的生活。通常需要一个小时才能找到发生错误的正确位置(vb6 中的错误处理是可怕的,并且仅是迁移的原因)。当我看到函数(发生错误的地方)以 3 页的变量声明开始时,我更加讨厌我的生活。好的,当我发现错误时,通常很容易纠正它。但是后来我花了很长时间才找到复制相同错误的 other 地方。然后我必须非常小心如何在不破坏其他现有代码的情况下解决问题。
  • 听起来您对业务逻辑的理解不是很透彻?如果它是由 10 位不同的开发人员在 10 年内编写的,那么谁会有适当的知识来指导您完成迁移?这就是整个问题。
【解决方案3】:

经历过类似将14岁的代码迁移到VS2008

这里有一些提示:

  1. 删除对第 3 方组件的依赖。
  2. 考虑分阶段迁移,例如使用反向互操作。
  3. 颜色和字体需要手工处理。
  4. 在迁移到 .NET 后注意数组中未初始化的对象
  5. 将错误更改为 Try Catch
  6. 在需要时使用 Microsoft.VisualBasic.Compatibility.VB6 命名空间。
  7. 在所有代码都转换为 .NET 之前,尽量减少重构
  8. 注意 VB6 代码中的非零基数组。
  9. 在 VB6 中重构(最小化)您的代码,以便它可以通过代码转换向导。
  10. 注意基于 1 的 VB6 控件,例如列表视图
  11. 使用同步锁来避免线程问题。
  12. 如果您要手动重构 sub,请注意数据类型大小的变化,尤其是在使用文件 IO 时。

有一家公司可以帮助您完成整个过程(尽管我们没有使用它们) http://www.vbmigration.com/

【讨论】:

  • 我真的建议在自动迁移之前进行重构。首先理解和减少代码库是一个好主意。这两项任务仍然是必需的,现在增加了新环境的复杂性。很难判断错误的根源是什么——最初的“设计”还是迁移。
  • 自动迁移只会将您的问题转移到其他语言。
  • 虽然对数组索引大喊大叫 - 如果你不小心,雷区
  • 我们发现,如果有人在迁移的同时重构某些东西,那么很多遗留问题都会被破坏,尽管有时这是不可避免的。尤其是代码中难以理解的部分,“重构”有时会造成问题。我们首先移动所有内容,然后针对 .NET 进行重构,以避免功能丢失。
  • 我们还在一个代码库上移动了超过 100k LOC,每天都有新功能进入。转换项目一直在追赶。这就是为什么我们将重构保持在最低限度,直到我们可以正确切换为止。
【解决方案4】:

查看 M. Feathers 的 "Working Effectively with Legacy Code"——它讨论了增强、重构和迁移以及未经测试的代码的缺陷。

【讨论】:

    【解决方案5】:

    您在提出这个问题方面做得很好。谢谢提问!感谢 stackoverflow 社区(像往常一样)发布深思熟虑的回复。

    如果这是一个相当大的代码库,并且听起来像是(50-100 个相互关联的 VBP,200-500K LOC),那么您应该考虑投资迁移工具。考虑这个类比:如果您有大量数据要转换,即使源数据很脏并且与所需格式非常不同,您也会使用工具。如果有人建议您应该重新输入数据,或者甚至进行粗略转换然后手动修复它,您会认为他们是疯了。同样拥有 120 个表单,该应用程序听起来像是提供了相当多的业务功能。该业务功能已经出现了多年的使用,无论喜欢与否,VB6 代码代表了该功能的完整、正式和经过生产测试的规范,以及关于应用程序如何在幕后工作的无数技术事实。 “从头开始”重新收集、重新编码和重新测试所有这些功能/技术要求是非常昂贵和困难的。为了管理项目的成本和风险,您必须“兑现”遗留代码。问题是:如何做到这一点并确保迁移后的拥有成本更低。

    挑战与代码库的大小无关,而是与适应和利用 .NET 所需的重新设计细节有关。您需要确定使 VB6 代码“丑陋”的具体因素,为什么它“丑陋”,以及您必须/应该/想要如何在 .NET 中以不同的方式做这些事情。一旦您开始制定这些重新设计要求,您就可以开始在转换过程中实施它们,以便它们出现在您的 .NET 代码中。我们提倡的一般方法称为“工具辅助重写”,具体做法如下:

    1. 运行翻译
    2. 构建/审查/测试生成的代码以识别/优化所需的代码改进
    3. 如果生成的代码“足够好”,则转到 .NET 中完成工作
    4. 重新配置翻译器以实现所需的改进(如果适用)
    5. 转到 1

    工具的输出不需要“完美”(软件永远不会......)它只需要“足够好”。第 3 步中提到的“足够好”是一个关键问题。从本质上讲,它意味着代码质量——就被验证为功能正确和符合您的标准而言——是这样的,即开发团队知道完成迁移需要什么,然后继续运行/维护应用程序——而且它们是相信他们可以在给定的时间和资源限制内做到这一点。对于一个非常大的代码库,“足够好”就是“非常好”,因为尝试完成并随后维护低质量的迁移太昂贵且风险太大。一般来说,代码越大,预算越小,您的迁移过程必须越高效。

    还有一些关于“在 .NET 中完成工作”的想法:在 .NET 中拥有格式良好的代码是一个重要的里程碑。 .NET 社区提供了很好的重构、分析和单元测试工具,可以帮助您加快完成迁移的工作。您将在此过程的早期使用 Visual Studio 来试验和改进重新设计,以及调试/测试应用程序。能够在 .NET 中使用整个代码库并在迁移工作的早期使用 Visual Studio 是工具辅助方法的关键优势(也是关键部分)。

    当然,要做到这一点,您需要能够投资一个专门为支持工具辅助重写而设计的迁移工具集。 Great Migrations 的工具是我所知道的唯一此类工具。

    免责声明:我为 Great Migrations 工作。我们的网站上有更多信息 - 包括有关如何使用该工具帮助将超过 1M LOC 的 VB6 迁移到重新设计的 C# 的案例研究,以及详细描述产品和方法的 gmStudio 用户手册。

    【讨论】:

    • 感谢 ChaosPandion。是的,它是一个插件,我相信我写的每一个字。我每天都使用这项技术来完成我的工作,它的运行效果让我深受启发。我认为社区了解这项技术很重要。
    • 另一方面,10k loc 版本现在免费!读完这篇文章后我注意到了这一点:prweb.com/releases/2014/02/prweb11619510.htm
    【解决方案6】:

    根据您对这个项目的描述,听起来您可以同时重构和迁移。您显然将采用大量冗余代码并对其进行整合;作为整合的一部分,您可能还可以在 .NET 中重写它(即冗余代码)。

    这不适用于 UI 内容。但它适用于数据库和业务逻辑的东西。例如,我没有看到您的代码,但我敢打赌,您的应用程序中的大多数组合框都由创建 ADO 记录集并循环遍历的方法(可能复制并粘贴到 Form_Load)填充他们。这可以重构为 .NET 数据访问类并轻松集成到现有表单中。它还可能允许您将缓存的神奇世界引入此应用程序,这将是很好的,因为这可能会导致明显的性能改进。

    可见的改进很重要。除非您的管理层完全认同这样做的必要性,否则这是一项非常高风险的工作。如果您发现自己告诉您的管理层,由于重构中的问题,给定 CR 的实施时间将比他们预期的要长,这是非常糟糕的。即使你有完全的支持,你也不希望出现这种情况,但如果你的支持是部分的,那就更糟了。可见的改进将大大缓解这种情况。

    此外,关于重构遗留代码问题的文献也越来越多。你需要在它之上。在深入研究之前,您了解的越多,您的体验就会越好。我自己没有读过 Michael Feathers 的书,但如果我处于你的位置,我会做的第一件事。

    【讨论】:

      【解决方案7】:

      参与过多个迁移项目后,首先要做的是明确您的迁移目标是什么。这些可能因组织而异,但它们有助于在实际迁移项目期间确定优先级。它还有助于更好地评估收益与风险和成本。

      正如其他人所提到的,重要的是要认识到迁移过程不会自动提高代码质量。因此,如果您的主要目标是重构(仅此而已),那么您应该意识到,可能需要数周或数月才能获得功能等效的代码(取决于代码大小和迁移复杂性)。

      话虽如此,除了单元测试套件之外,.NET 确实有一些非常好的重构和代码分析工具。可以定制像 ArtinSoft 的 Visual Basic Upgrade Companion 这样的自动转换工具,以强制执行编码标准或在转换过程中显着改进代码。这与 ReSharper 等其他代码修改工具相结合将大大加快您向 .NET 的过渡。

      根据我的经验,只要您知道其中涉及手动工作,迁移项目就是一个易于管理的项目。商业工具具有评估模式,可以帮助量化迁移工作,并让您了解迁移中可能面临的挑战。

      如果您更喜欢低风险和低成本的解决方案,我会坚持重构代码,着眼于最终迁移。我有客户对这种方法有效。因此,当需要迁移他们的代码时,已经解决了几件事。

      基本上,任何新的自定义控件都应该用 .NET 编写并作为 ActiveX 控件公开以供 VB6 应用程序使用。同样,新的 DLL 函数应该放在可以通过 COM 使用的 .NET 程序集中。这样,当需要迁移时,您就不必担心这些控件或库。

      【讨论】:

        【解决方案8】:

        与我做过的一些东西相比,它听起来很小。尽管如此,还有另一种方法可以与上面 PeanutPower 所示的方法结合使用。

        答案是构建一个框架,允许您一次剪切程序的各个部分并逐个转换。

        例如插入一个数据库适配器“层”来处理对数据库的所有调用,然后一个接一个地删除 SQL 之外的每一个,并将其替换为对 db 层的调用。旧呼叫仍将直接进行,而新呼叫通过该层。最终所有调用都将通过该层,您可以更改后端数据库。

        您可以对代码的任何其他部分执行相同操作,方法是扩展框架“层”以涵盖该功能。

        将其从 VB6 转移到 VB.NET(例如)的关键是使用 Interop 库 - 这是一篇文章:http://support.microsoft.com/kb/817248

        另一个,很久以后的想法:获取 MZ-Tools 并使用他们的分析工具来查找冗余代码并将其删除。我设法消除了公司旧产品中大约 5% 到 10% 的代码。

        【讨论】:

          【解决方案9】:

          不要从头开始重写。听起来这将花费您很长时间,并且您很可能会在代码中引入新(旧)错误。

          我会考虑缓慢而简单地重构代码。从小处着手。令人惊讶的是,您可以多快地将代码重构为更易于管理的东西。并且您应该能够在您执行的每个折射块结束时保持代码“工作”。

          更新: 值得注意的是,自动迁移只会将您的问题转移到另一种语言。

          【讨论】:

          • 我看到/理解的代码越多,我就越相信真正的功能非常小。我到处都看到相同或几乎相同的代码。我在一个 VB 项目中发现了一个函数(在字符串末尾剪切反斜杠),它存在 3 次,名称相同,代码相同。我找到了用于登录 dll 的代码,对其进行了更改,但没有任何效果,并在其中一个主 EXE 中找到了该代码的副本。我发现一些 SQL 语句在每个第二个项目中都有微小的变化。我可以无休止地继续这个列表。
          • 你知道以前的开发者住在哪里吗?...放开猎犬!!或更严重的是 - 只是陷入代码并开始删除不做任何事情的代码块。开始合理化野兽并让它重新得到控制。祝你好运。
          • 确实,“自动迁移只会将您的问题转移到不同的语言”,但在 .NET 中重构也容易得多,您可以访问 Linq、哈希表、泛型等。数千行代码简单地放弃,但在你让代码处于工作状态之前,这大部分是不可能的。
          • 我同意 PeanutPower,我还要补充一点,迁移到 VB.Net 消除了对 Microsoft 在未来版本的 Windows 中支持 VB6 的担忧,并且它为您提供了更多用于自动测试的工具 - 可靠的自动测试在任何重构工作恕我直言之前是必不可少的。当您处理“(低)变更请求流”时,可以逐步添加它们
          • 使用 VBUC 工具将 vb6 转换为 C# .Net
          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2012-03-31
          • 1970-01-01
          • 2011-02-03
          相关资源
          最近更新 更多