在项目之间共享微小代码段的最佳实践


102

我一直在工作中严格遵循DRY原则;每次我由于懒惰而重复编写代码时,都会在以后需要在两个地方维护该代码时再次出现。

但是我经常写一些小的方法(可能是10到15行代码),这些方法需要在两个不能互相引用的项目中重用。该方法可能与网络/字符串/ MVVM等有关,并且是一种通用的有用方法,并不特定于它最初所在的项目。

重用此代码的标准方法是为可重用代码创建一个独立的项目,并在需要时引用该项目。问题在于,我们最终遇到了两种不理想的情况之一:

  1. 我们最终得到了数以百计的小项目-每个小项目都包含我们需要重用的小类/方法。.DLL仅需少量代码就可以创建一个全新的应用程序吗?
  2. 我们最终完成了一个项目,其中包含越来越多的不相关方法和类。这种方法是我曾经工作过的公司所做的。他们有一个名为的项目base.common,其中包含用于我上面提到的事情的文件夹:联网,字符串处理,MVVM等。它非常方便,但是不必要地将其与所有不需要的无关代码一起拖到它。

所以我的问题是:

软件团队如何最好地在项目之间重用少量代码?

我特别感兴趣的是,如果有人在一家在这方面有政策的公司工作,或者像我本人那样亲自遇到了这个难题。


注意:我对“项目”,“解决方案”和“参考”一词的使用来自Visual Studio .NET开发的背景。但是我敢肯定,这个问题与语言和平台无关。


21
+1,尽管我认为使用.NET的人中有些幽默的元素,它担心通过DLL引用拖入无关的代码。
JDB

2
@ColeJohnson .NET本身就是一个巨大的参考!可能比我自己制作的dll大得多。
乔治鲍威尔,

2
我明白了。但是,.NET的JIT编译器仅将所需的方法加载到RAM中(当它们被调用时)
Cole Johnson

1
真正。尽管您仍然必须将整个.NET框架分发给想要使用您的产品的任何人,但是大型项目和复杂的解决方案更难以管理。
乔治鲍威尔,

Answers:


75

如果它们确实是可重用的方法/类,则可以将它们编写到少量的“瑞士军刀”库中。我们在公司经常这样做;我们称它们为框架库:

  • Framework.Data -用于处理数据库查询的实用程序。
  • Framework.ESB -与我们的企业服务总线进行交互的标准方法
  • Framework.Logging -统一日志系统
  • Framework.Services -与Web服务交互的实用程序
  • Framework.Strings -用于高级字符串处理/模糊字符串搜索等的实用程序
  • ...

总共大约有十二个库。您可以按自己认为合适的方式分发代码,因此不必最终花费数百美元或将所有内容都转储到一个大型程序集中。我发现这种方法很合适,因为只需要我们的一些项目,Framework.Data而只需要几个项目Framework.Strings,因此消费者只能选择框架中与他们的特定项目相关的部分。

如果它们实际上只是片段,而不是可以轻松地重用的实际方法/类,则可以尝试将它们作为代码片段分发到IDE中(例如Visual Studio代码片段)。我过去与之合作的团队拥有一个通用的代码片段库,这使每个人都可以更轻松地遵循我们的标准编码惯例以及内部代码。


4
+1这也是我的方法。有兴趣知道您如何决定从两个或多个方面决定将处理内容的代码放在何处。例如IPAddressToString。以及是否允许这些库互相使用。例如,服务和数据可能会从日志记录中受益匪浅……
Marjan Venema 2013年

5
@MarjanVenema对于跨领域代码,取决于哪些消费者会发现该方法更有用。对于IPAddressToString,处理网络协议的消费者可能必须使用它,但是对字符串有很多摆弄的消费者可能根本不关心IP地址。那可能最终会出现在网络软件包中,而不是Framework.Strings
pswg

@MarjanVenema我们尝试避免相互依赖。我们的服务和数据框架以这样的方式编写:它们自己不进行任何日志记录,但是使消费者更容易编写适当的日志记录代码。允许框架库相互引用,但只能通过扩展进行引用-例如,Framework.Logging.Gibraltar是日志系统的特定附加组件。
pswg

5
+1您可以使用这些框架库并将它们部署到内部的NuGet存储库(就像网络文件夹一样简单),并且您有很好的管理方式。
史蒂文·埃弗斯

2
@SteveEvers我现在正在实际进行设置。:P
pswg

21

我出于很多原因不同意接受的答案。

以我的经验,当我看到“杂类”库(如已接受的答案)时,它们是重新发明轮子的借口(或者不是在这里发明(NIH))-比违反“ 不要重复自己”(DRY)更大的罪过。

有时违反DRY可能是一个合理的折衷方案,它比引入紧密耦合更好。与良好的面向对象设计相比,重用是次要问题。一点重复(我的意思是说,少用三个规则)比意大利面条代码库更容易理解。

许多通用库的方法树立了一个不好的榜样。这会导致程序集的粒度过细,而太多的程序集则很糟糕。我最近将内部图书馆从24个减少到6个。它将编译时间从几分钟缩短到了约20秒。Visual Studio的加载速度也较慢,而对更多程序集的响应则较慢。库过多会导致代码应存放在哪里。希望使用更少,更简单的规则。

为什么.Net Framework中的内容不够好?该框架很大。很多次,我都看到代码重新实现了那里已经存在的东西。确实要确保您的框架填补了.Net框架中的空白,并且出于美观原因而没有存在(例如“我在这里不喜欢.Net框架”或某些过早的优化

在体系结构中引入另一层会花费大量的复杂性。为什么该层存在?我已经看到了错误的重用,这意味着代码是建立在内部框架之上的。直接在标准库之上实现它会更加高效。

使用标准化技术(例如.Net框架和流行的第三方/开放源代码库)所带来的好处通常超过了自己构建它的相对技术收益。更容易找到知道这些技术的人才,您现有的开发人员将在学习方面投入更多的资金。

我的建议:

  • 不要共享此代码。
  • 如果创建一个具有凝聚力的新库,请不要使用泥泞的设计模式
  • 尽可能重用现有的第三方库。
  • 最好使用较少的程序集,并使用更简单的规则来确定代码应驻留的位置。

1
使用开源库(如果有)的附带好处-如果您提出了一些改进,可以将其共享给社区!例如,.Net MS发行了EnterpriseLibrary(现在为Open Source),其中提供了一套非常好的用于常见方案的工具,在那儿找到可以改进的地方,嘿!大家受益!
glenatron 2013年

2
在这里,我并没有真正不同意接受的答案:-)。“程序集更少,规则更简单,代码应该存放在哪里”与公认的答案并不矛盾。答案还主张仅使用看起来合理的尽可能多的不同程序集。
sleske 2013年

五年后的microService指导也聚集在此的做法:medium.com/standard-bank/...
戴夫·希利尔

11

对于少量代码(例如,一个没有依赖性的类),我们倾向于将代码复制并粘贴到项目中。这听起来像是违反了DRY,但我承认有时可能如此。但是从长远来看,由于一些原因,它比拥有某种大规模的,多头的公地项目要好得多。

首先,方便使用代码会更简单,尤其是在构建和调试内容时。

其次,您总是希望对该项目的通用代码进行一些调整。如果您拥有源的本地副本,则可以进行调整并每天进行调整。如果有一个共享库,那么您可能要对该库进行调整,然后确保您不会破坏所有其他应用程序或造成版本控制噩梦。

因此,如果对于它自己的名称空间而言不够强大,我们倾向于将其推入项目中的相应位,然后将其命名为一天。


5
我不同意这种方法。我感谢管理小代码所带来的维护问题,但我认为可以像@psw所建议的那样,从所有代码中创建一些通用库。在代码中进行细微调整的重复副本会带来麻烦。将进行假设,错误修复将丢失。
Andrew T Finnell 2013年

2
-1(答案)。让每个人都有自己的程序版本的副本当然更容易。这就是80年代开发软件的方式。从那以后,我了解到,长期来看,这会导致混乱。做正确的事并拥有一个公共图书馆比较困难,因为人们将不得不就他们的工作进行更多的交流。好吧,他们应该。
Michael Durrant

3
+1-我认为值得一提的是,即使您不想经常使用这种方法。一些代码片段更像是设计模式-您将重用em,但是在各处(可能以不同的语言)都稍有不同,并且可能需要更改它们。而且,广泛使用的库是不灵活的,因为对其API的更改存在很大风险。最后,采用这种方法作为后备方法,可以通过将实验性内容保留更长的时间来提高共享库的质量。
Eamon Nerbonne

6

您描述的第二种解决方案还不错。在.NET中,即使您只使用一个单一类,也要引用GAC中的程序集。“拖动无关的代码”并不是您可能认为的问题。在这种情况下,至关重要的是,至少要在不同的命名空间中将相关的方法和类保持整洁的组织。此外,应采用API设计的良好做法,以防止此解决方案变得混乱。

如果涉及到很少的代码,我认为以下方法是对常见项目的很好补充:允许它们在不同的解决方案中重复。像最佳做法一样对待它们:记录并与团队沟通。


1
除了对于非标准库而言,这意味着仅由于一次(或很少)使用就必须装运大型程序集。这对于标准的东西来说不是问题,因为无论如何都可以使用,但是如果可以很好地拆分它,我绝对会避免运送大型但大部分未使用的程序集。

6

我只曾在“企业”环境中工作过,在这种情况下,这种事情一直是一个问题,并且每次它都成为被采用的第二种选择时。在大多数情况下,它都可以正常工作,因为应用程序占用空间没有任何限制。

但是,在上周与一家正在运行自己的Nuget服务器的初创公司在一起时,我倾向于建议将其作为可行的替代方案。当然,我希望出现的问题将与发现能力有关。

如果项目是适当的粒度,并且名称空间是明智的,那么我可以看到这已成为流行的方法。


在什么意义上,您希望它们不会被发现?我们以这种方式使用大量且不断增长的nuget包。我们面临的最大问题是管理版本控制和依赖关系。
pdr 2013年

是啊。那些也一样。关于可发现性的问题,我的意思是,给定足够数量的具有特定功能的小包装,可能很难对每个小包装进行分类(查找)。例如,您的团队如何得知哪些软件包包含各种功能?(此处显示nuget搜索的无知)
Kofi Sarfo

哦,我明白了。是的,您绝对可以在说明中放入您喜欢的任何内容,并且可以进行搜索,但是我认为我们对软件包进行了很好的分组,这似乎并不是问题。
pdr 2013年

@sarfeast如果您可以共享指向任何Nuget服务器的链接,并对其进行一些介绍,那就太好了。
汉斯·彼得·斯特尔2013年

6

我最近想到了这一点,我想到的是一个庞大的通用方法库,到目前为止已经提到过,但有一点曲折。该库项目允许您在编译时配置其中包含的部分,类似于BusyBox项目。通过这种方法,您可以拥有一个厨房水槽样式的库回购,但是只能抓住编译时所需的工具。


5

GitHub有一个非常有用的工具来保存代码片段https://gist.github.com/

它将您的代码段存储为git存储库,您可以将其保留为私有,或用于与其他人共享代码段。


3

视团队/项目/公司的规模而定,这将是一件相当困难的事情,除非它已经以某种方式内置到您的环境中,并且您发现的每个解决方案(如果实施)都会花费一些钱。(这可能会使您更加安全,但将无法轻松进行测量)。您必须检查它是否值得。同样要记住,可重用的解决方案趋于变得抽象,并且通常会适合许多情况,但并非最优。

无论如何,如果您想对不止一个人产生的代码执行此操作,那么首先,您需要所有人的意识和合作。这包括开发人员和管理人员。

然后,您需要确保知道要执行此操作的范围。球队?项目?部?公司?根据答案的不同,将在此类解决方案中使用的代码类型也会有所不同,调整dll的粒度也会有所不同。一旦您决定了这个人(最好是对这个想法充满热情-您呢?)就应该坐下来,开始对此进行一些调整。

但是,仅创建此类dll不足以解决问题。为了使它们有用,您需要(向用户和贡献者)进行广告宣传,并像其他任何软件一样对其进行维护,这通常意味着您需要长期负责他们。您还将需要可靠的文档,然后也将需要维护。有了一些运气和合作,您可能会得到一些最佳实践,但是根据参与团队的规模和数量,也可以轻松地将其发展成为自己的项目。为此,您仍然需要管理支持。


3

我遇到了很多问题,我更喜欢的解决方案是将代码发布到github / pubic基于Web的存储库中。它解决了很多问题-

  1. 易于访问且易于共享。cvs / svn / enterprise-repos意味着将项目检出到多个IDE工作空间中,有时仅为了引用一个小的代码段就不得不切换工作空间或计算机。
  2. 假设这些代码段不是专有的/分类的代码段,而是可公开获取的知识的变体,则将它们发布在像github这样的公共仓库中,意味着其他人会看待它,甚至可能有所作为。
  3. 以您的名字在公共领域发布某些东西会增加声誉压力。您将仔细检查并更新内容,因为它反映了您作为程序员的能力。
  4. 更新。关于在仓库中维护代码段的事情是,如果很长时间未使用代码段,它可能会过时(包含过时的api / lib)。示例-读取文件的Java代码段。您可能已经在2009年找到了实现此目的的最佳方法,但是在2014年,出现了一个新的文件api,它会改变一切。您的摘要?仍然停留在2009年。在公共存储库中,您(由于项目符号3),您的队友或普通程序员中的某些成员会更新所有内容,在此过程中,您甚至可能会得到建议以修复某些问题,您可能已经做错了很长时间了。

我会建议的一件事-无论您将代码段保存在哪里,在使用它之前,请务必先将Google内容填充起来。事情总是在变化。节省代码片段可以节省时间,也可以提高自满程度


2

我们有一个单独的项目“实用程序”,其中将所有这些小方法与测试存储在一起。

当项目需要某个实用程序时,它只需使用“添加为链接”所需的方法添加源文件。

这意味着没有添加任何运行时依赖项(除非包含的文件需要一个)。

该系统运行良好,但像其他系统一样,它需要关于实用程序的专业知识。要求高测试覆盖率对我们来说效果很好,测试也是很好的用法文档。发现对于我们来说仍然是一个未解决的问题。

该实用程序项目的一项复杂性是确定项目的可见性级别。一条经验法则是方法应该是内部的,数据结构应该是公共的。


2

我的公司使用Intranet本地Web服务。我们有一些设置为通用内部Web服务的Web服务,并且当另一个项目需要访问其中一个服务时,它会发送带有定义接口的http请求。由于它位于同一服务器场中的Intranet上,因此这些请求非常快。

显然,这仅适用于Internet应用程序(并且在同一本地网络上仅在毫秒内运行),但是它具有一些非常好的优点。


0

我最近想出了这项服务:Snip2Code(http://www.snip2code.com)。

与团队仅共享您的片段(不完全是库)是一种有趣的方式。它打破了创建其他项目中应参考的通用库的通常观点,我认为这是一个宝贵的愿景。

此外,有很多情况是使用通用库根本不适用:例如,让我们考虑一些设计模式,例如Singleton,Strategy或Observer。您可以创建库来支持这种模式,但是仍然没有100%的覆盖率。

真正需要的是拥有一种在团队中共享通用做法的工具。我尝试使用Github的要点,但我一直在寻找它们(确实很差),而且我不能只在我的团队中共享它们,而不能与其他人共享...

(免责声明:我是Snip2Code的创始人之一,我和我的联合创始人一起在同一时间以前也是以相同的心态:这就是我们决定开始这个项目的原因!!)

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.