在.NET应用程序之间共享代码的最有效方法是什么?


15

在我们的工作中,我们有几个不同的.net应用程序,它们共享许多基本功能。我们已经使用干净的n层体系结构构建了这些应用程序,但是到了那一刻,我们意识到我们已经在不同的时间重新实现了相同的功能。显然这违反了DRY,我们希望对此进行更正。我们已经使用Nuget成功实现了通用粘合代码(连接IoC,日志记录,设置),但是我们也希望在所有应用程序之间共享数据和业务层。想法是,UI仅处理其实际需要的业务层部分。

起初这似乎是一个直截了当的问题,但是持续的开发可能会带来一些陷阱,我们不确定如何进行。假设我们建立了一个业务层来全部统治。为简便起见,我将其称为“基金会”。我们将我们的应用程序移植为使用Foundation,并且一切都很好。该基金会通过nuget分发给轻量级UI层,我们看起来很好。但是随后我们开始向应用程序中添加功能,并且遇到了麻烦。

假设我们正在开发Project A,并且添加了一项需要更改Foundation的新功能。我们对基础(Foundation-A)进行更改,并将它们作为不稳定的程序包推送到nuget提要。项目A获得了最新的nuget包,一切都很好。同时,另一位开发人员正在开发ProjectB。他从源代码控制中获得了最新的Foundation,但从一个稳定的分支中获取了最新的Foundation,因此它没有Project A的更改。他进行了更改并创建了Foundation-B。一切都很好。但是随后我们发现,Foundation-A和Foundation-B实施功能实际上可以共享代码,因此我们将它们组合在一起。同时,Foundation-C本身也有自己的变化。最终,Foundation-B可以投入生产,因此我们将其推出。但是然后我们需要更新生产A,B,

这似乎可行,但是我们担心使用不同的数据库模式,并使Foundation信息库的各个分支以及Project A,B和C信息库之间的所有内容保持同步。似乎可能需要大量的手动工作,这可能会出现错误。我希望这尽可能自动化。

这是我们使用的堆栈:C#,具有持续集成功能的TFS,Nuget。我们的应用程序是所有类型的ASP.NET应用程序。如果这会使事情变得更容易,我们愿意研究不同的SCM。

我正在寻找使Nuget对我们不同的源代码分支保持理智的方法。我们不想意外地将开发代码推入生产环境,因为我们引用了错误的Nuget包。


另外,如果这不是一个像这样的讨论的好论坛,有人可以建议一个更好的论坛吗?
2013年

Answers:


9

我们对基础(Foundation-A)进行更改,然后将它们作为不稳定的程序包推送到nuget提要。

这是您的问题开始的地方...不要那样做。

对Foundation v1.0所做的任何更改本应对Foundation的所有使用者都是有价值的,否则它不属于Foundation。因此,在创建nuget软件包时,请将其作为Foundation的正式稳定版本(即v1.1)执行,或者完全不执行。

项目B应当像往常一样构建其Foundation增强功能,但是(以良好的源代码管理方式)应该在将稳定的Foundation(v1.2)推向nuget之前合并到主干更改(v1.1)中。

可以使用Foundation增强功能的其他项目可以在适当时升级其nuget引用,或者在需要时坚持使用旧版本。

我同意@Giedrius ; 在我看来,这似乎是更多的源代码控制/分支问题,如果正确处理Foundation的分支/合并,则包管理问题将变得毫无意义。


是的,这很有意义。问题在于实际应用中。在对Foundation for v1.1进行更新时,您要在开发时使用Project B中的那些更改。如果您共享代码的方式是通过nuget,则您的选择是:1)发布新的nuget程序包,或2)手动复制dll。这些似乎都不是不错的选择。
2013年

通过拥有有效的测试套件,可以缓解其中的某些问题,但是在添加功能时仍然会来回走动。
2013年

@Josh是的,对Foundation的更新应该是完整且可测试的,而与Project B的使用方式无关(因为它们将进入共享库),因此“发布新的nuget程序包”是很自然的方法。在nuget中的稳定包之前,不要在Project B中导入和使用Foundation v.Next。这需要一点纪律,但是比做其他事情要好得多。
埃里克·金

1
我完全理解您在说什么,但我认为这不是很现实。在开发功能时,即使您已对所有业务逻辑和数据访问层进行了完整的测试,在将其推向生产之前都需要进行修改。也许您意识到您需要向业务逻辑中添加另一个属性,或者产品所有者返回进行了更改或澄清。也许您的一些简化假设是错误的。这些都是无时无刻不在发生的事情。如果您仅限于锁定基本逻辑的释放,那么确实似乎非常有限。
2013年

2
经过几个月的努力,这基本上就是我们所确定的。我想我太担心正式程序了。一旦我们开始实际工作,事情就可以顺利进行了。感谢您的输入。
2014年

4

将重复的代码重构为可以以更抽象的方式应用的函数,并将其放入自己的库或框架中。使它们松散耦合并且与体系结构无关,并且您永远不会有任何问题。如果您需要灵感,请研究.NET框架如何使用接口,泛型和软件模式(如)来抽象概念Dispose()

另外,请记住,并非所有重复的代码都确实是重复的。其中一些是胶水代码或维持体系结构所必需的代码,因此不要着迷于过于干燥。


也许我不太清楚我的问题。这是关于接下来的事情。您已经完成了所有这些操作,现在您需要在不同项目之间有效地共享代码。有人说“只是使用nuget”,这听起来很不错,直到您深入细节并遇到问题-例如如何同步来自不同分支和应用程序的不同更改。
2013年

好吧,我同意埃里克·金(Eric King)的观点。应将基础代码推送为稳定版本,而不是不稳定版本。关键在于保持稳定的API:如果您知道基础方法的签名不会改变,则可以安全地将方法推入Foundation并在以后重构它们而不会破坏任何内容。
罗伯特·哈维

4

代码重用

多年以来,有几种方法可以重用代码。每种方法都有它的位置,更重要的是它的问题,但是在.NET中重用代码的可行方法是:

  1. 公共图书馆。多个地方需要的代码被放入一个公共库中,然后代码库的所有其他部分都对该代码有一个引用。原则上的缺点是,您最终将依赖该库包含大量不相关的函数,从而完成了大部分项目。从质量保证方面来看,这是一个坏主意。

  2. 通用源代码。在一个以上的位置中需要的代码被编写一次,并放在通用目录结构的源文件中。然后,所有需要此代码的项目都将此文件作为其源文件之一。这提供了代码重用,一次写入的优点是使用很多。然而。其不利之处在于,可以用该代码的不同版本来编译项目的不同部分-这可能会引入一些细微的缺陷,通过质量保证来检测和识别这些缺陷可能非常棘手。

  3. 服务。通用代码被实现为其他方面可以访问的服务。这样做的好处是,部署中将只有一个服务,并且避免了依赖性。但是,这将导致延迟和故障。这种方法在已经了解和管理高可用性和容错能力的大型分布式产品中效果很好。

管理NuGET

在这里,您有一个更有趣的问题。管理多种配置。我的建议是不要使用不同的代码版本,而是使用配置文件来管理多样化的客户群。至少要管理3层配置数据。客户从未见过的基本(内部)产品配置。客户可能会更改的默认配置选项,以及客户已更改的最后一层配置选项。通过分离这些不同的层,您将能够进行升级而不会破坏客户的配置。


1

我认为问题不在于nuget /源代码控制/分支,而在于粘到代码中。

Robert有一个很好的答案,只看整个图片,我建议考虑一下这些通用实用程序将带入每个项目的依赖项:

http://ayende.com/blog/3986/let-us-burn-all-those-pesky-util-common-libraries http://blog.jordanterrell.com/post/CommonUtility-Libraries-Dead.aspx

避免遇到麻烦的最好方法是开源粘合代码。通过这种方式,您将开始关心,不会公开任何业务逻辑,因此不会将具体的项目依赖项渗入粘合代码中,从而使其足够抽象,甚至任何人都可以重用,即使在公司外部也是如此;如果粘合代码就足够了-您还将获得社区的投入。


我不是在谈论管理粘合代码。我们已经有了解决方案并且它运作良好。我在谈论共享业务逻辑。例如,我们的应用程序用于管理组织和人员。因此,我们需要创建一个人,并且有一堆与如何创建一个人相关的业务规则,而不是多次创建它,我们想要一个包来处理从构造对象到持久化对象的所有问题,并在不同项目之间共享需要创造人才的人
乔什(Josh)2013年

0

解决方案很简单:为它创建一个单独的项目,并将其作为单独的东西进行管理:它是自己的需求,测试,惯例,文档,计划,人员等。这样,您可以确保质量很高,并且可能发生重大更改在产生问题之前先进行评估。

甚至更好:在您的组织内使其成为“开源”。因此,任何人都可以更改代码,但是只有少数选定的人具有完整的提交权限。这些人将负责确保质量和正确的功能。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.