【问题标题】:What is the best strategy to do decoupling assemblies [closed]解耦组件的最佳策略是什么[关闭]
【发布时间】:2017-05-26 14:22:28
【问题描述】:

我在新公司遇到了遗留代码库的问题。

基本上,他们有 2 个大代码库/项目或程序集,我会说程序集 A 和程序集 B。此外,我们有程序集测试 A 和程序集测试 B。

我在这里遇到的问题是程序集测试 A 正在使用程序集测试 B 中的一些类。程序集测试 B 正在使用程序集测试 A 中的一些类。但没有完成,程序集测试 A 正在使用程序集 B 中的一些类。真的很恶心,我知道。这就是现在技术上的原因,我们有 2 个独立的项目,但实际上我们将它们放在一个包中。那么你可以想象,每次我们部署 A 时,我们都必须部署 B。

我的任务是将这些程序集解耦或将它们拆分为 2 个单独的程序集/项目,以便将来部署和测试等等。

我制定了一个缓慢的策略,但它可以确保我们仍然保证功能。我最初的策略是,我将在测试程序集 A 中慢慢删除程序集 B 的依赖项,并通过测试程序集 A 使测试通过。这意味着我正在从程序集 A 中删除程序集 B 的依赖项。下一步对程序集执行相同的方式B,最后我们将完成 2 个单独的组件。

对我来说,我相信这不是一件容易的事,但我不介意去做。但是,我需要您对我的初始策略提出意见或建议。我不想冒险在那种项目的中间回到起点。

那么你们能否就这项任务给我任何诚实的意见或建议?

我非常感谢。

谢谢

【问题讨论】:

  • 听起来很乱。我更喜欢看一个依赖关系图,但这不是重点。你听说过技术债吗?该代码作为很多技术债务。您是否听说过有人从信用卡中取钱来支付另一张信用卡?这是我唯一的想法。您可以通过复制代码来分离项目,然后您必须通过重构已经分离的项目中的任何不必要的代码或任何内部代码重复来付费。
  • 听起来您需要第三个项目“TestCommon”。
  • @Theraot 当您提到技术债务时,您是绝对正确的。我也很喜欢通过信用卡付款的例子(Y):D。老实说,我知道我将在两个程序集中都有重复的代码,但它们位于两个不同的域中,所以我希望它应该没问题。这真是乱七八糟的代码库。然而,它就是这样,我们应该让它变得更好。我将尝试找到依赖关系图并让您知道,但我认为您可以想象现在的问题是什么。你还有其他建议吗?干杯。
  • @Bradley:这就是我现在的想法,但可能是下一步。我认为最简单和最重要的步骤(纠正我错了)是先拆分它们,当我熟悉代码库时,我可以找到一些常见的东西并将它们放入 Test Common。你怎么看?干杯
  • 是的,很明显您需要建议和指导,但这里的情况:您就 SO 提出了非常广泛的基于意见的问题。 softwareengineering.stackexchange.com 上的主题可能更多(或者可能已经在那里讨论过很多次 - 确保搜索并检查他们的帮助 -> 在将问题移到那里之前先游览)

标签: c# .net unit-testing


【解决方案1】:

老实说,我觉得描述有点混乱。所以,我会一点一点的来。

基本上,他们有 2 个大型代码库/项目或程序集,我会说程序集 A 和程序集 B。

此外,我们还有组装测试 A 和组装测试 B。

我假设Test A 依赖于A 并且Test B 依赖于B

测试 A 正在使用程序集测试 B 中的一些类

测试 B 正在使用来自程序集测试 A 的一些类

测试 A 正在使用程序集 B 中的一些类


好的,我可以推断出这张图:

  • AB 是接收器(如果您愿意,可以离开)。理论上,您可以单独部署它们。我猜你部署Test AATest BB 会导致问题。快速修复:不要部署测试。

  • 有一个循环:Test A -> Test B -> Test A

最初我对Test A -> Test B -> B, Test A -> B 做了一些评论,我正在抓挠,它与这种情况无关。


循环依赖Test A -> Test B -> Test A 是主要关注点。如何解决它是一个经济学问题。

我在 cmets 中说您可能允许重复代码,稍后您必须对其进行重构。 这只是我想到的第一件事。 这样做会增加技术债务,但可以让您在更短的时间内归档分离。如果您需要现在分离项目,我会说您这样做。如果有时间,你可以更加务实。

要修复循环依赖,您需要了解Test A 不需要Test B,而Test A 只需要Test B子集。同样Test B 只需要Test A子集

此外,我们可以说Test ATest B 都需要这个子集。借用Bradley Uffner's comment我会打电话给TestCommon

您可以从创建一个空的TestCommon 程序集开始,将依赖项添加到Test ATest B 并开始在那里移动代码。最终,您将能够删除从 Test ATest B 以及从 Test BTest A 的依赖关系。 TestCommon 内部有可能继续存在循环依赖(没有详细的依赖关系图,我无法判断)。无论如何,提取TestCommon 将使代码更易于维护和重用。


提取TestCommon 将导致以下结果:

到这里:

全图:

更好。现在您可以部署Test BB(和TestCommon)而不会出现重大问题。但是,您仍然需要使用 Test A 部署 B,因为它直接引用它。

有一个从Test AB 的链接。我将假设更多细微差别的情况,这是Test A 使用 B 的地方(稍后我将探讨其他情况)。按照我们提取TestCommon 的方法,我们需要引入另一个程序集。我会称它为Utility(我不知道里面有什么,只是Test A 需要它),并允许你从这里开始:

到这里:


至此,我们已经成功分离项目。我们可以在完整的图表中看到,可以在没有Test BB 的情况下部署Test AA,反之亦然。

全图:

部署A:

部署 B:


¿Utility 是什么?

请记住,Utility 最初是 B 的一部分。这是B 的一部分,我们需要使Test A 工作。虽然我对Utility 了解不多。然而,我知道我不知道的......

A.我不知道Test A 是使用还是测试Utility,我假设它使用它。

B.不知道Test B是使用还是测试Utility

C.不知道B是否需要Utility

让我们探索可能的情况:

  1. Test A 使用UtilityTest B 使用UtilityB 需要Utility

    Utility 必须是一些适合性代码,每个人都可以使用它来使事情变得更容易。 Utility 中的缺陷将是两个项目中的缺陷。在新的Test Utility 中对其进行测试。

  2. Test A 使用UtilityTest B 使用UtilityB 不需要Utility

    Utility 仅用于测试。合并到TestCommon

  3. Test A 使用UtilityTest B 测试UtilityB 需要Utility

    这是所有情况的更多细微差别......

    BTest A 仍然需要此代码...此代码服务于两个主控器 Test AB。这没有错。你可以保持原样。

    未来您可能希望对其中一个项目的 Utility 进行更改,但该更改会在另一个项目中引入错误。

    目前Utility 的测试在Test B 中,A 的工作人员可能并不担心。因此,将Test UtilityTest B 分开是一个好主意。

    如果将来Test AB 的要求差异太大,他们将需要两种不同的解决方案(此时您可以将它们合并到各自的项目中)。

  4. Test A 使用UtilityTest B 测试UtilityB 不需要Utility

    删除BUtility 的依赖,并将Utility 的测试从Test B 中分离到一个新的Test Utility 中。

  5. Test A testsUtility, Test B 使用Utility, B 需要Utility

    Test A 不应测试来自B 的代码。将该代码迁移到Test B,并将依赖关系从Test A 删除到Utility。您现在可以将Utility 合并回B

  6. Test A 测试UtilityTest B 使用UtilityB 不需要Utility

    删除BUtility 的依赖关系,并将Utility 的测试从Test A 中分离到一个新的Test Utility 中。

  7. Test A 测试UtilityTest B 测试UtilityB 需要Utility

    Utility 的测试分为两部分。提取它们并将它们放入新的Test Utility

  8. Test A 测试UtilityTest B 测试UtilityB 不需要Utility

    Utility 未被使用。您可以将其连同其测试一起删除。


最后说明:我使用yUML 制作了图表。

【讨论】:

  • 我相信这将是正确的解决方案。我将与我的同事讨论它是如何工作的,因为我对该系统有一点了解,但我相信这是正确的方法。非常感谢您的回答,这有助于我了解如何在 SO 上做出好的回答和提问。我非常感谢
  • 另外,我们在重构那些杂乱的代码时会有很大的冲突风险。如您所知,它们是工作代码,因此每天都会更新代码,因此合并时会引起大问题?即使我将在 2 # git 存储库上工作
  • @NinjaCoder 很高兴能得到帮助。只要您提交您所做的,就可以使用存储库恢复它,所以不要害怕编写代码。您可能还需要考虑增加测试的覆盖率。此外,如果您的团队没有它,请查看他们是否可以获得某种形式的持续集成,在每次提交时运行测试。这样,如果您的提交导致破坏了一些意想不到的事情,您将尽快知道。修复缺陷所需的时间越长,成本就越高,因此负担得起的持续集成解决方案是一项不错的投资。
  • 我对代码做了更多的调查,我可能会发现TestB使用A程序集的原因。原因是他们是集成测试,然后在一个程序集中,有几个服务用于与数据库通信。在 B 组装中,我们需要使用该服务来执行测试。
  • 你可以想象我们有帖子和子帖子,两个帖子实体都存储在数据库的同一张表中。所以 A 类有一些数据库服务来获取父帖子,B 类有一些服务来获取子帖子,因此我们将 TestDataHelper 类留在了 TestB 内部,而 TestDataHelper 类同时使用了 A 类和 B 类。它产生了很强的依赖关系。跨度>
猜你喜欢
  • 1970-01-01
  • 2010-10-25
  • 1970-01-01
  • 2010-10-09
  • 2016-11-27
  • 1970-01-01
  • 2010-09-29
  • 2021-11-20
  • 1970-01-01
相关资源
最近更新 更多