令人尴尬的是,在几十年前的团队环境中,我引入了一个名为“ common”的通用库。我当时还不太了解那种松散协调的团队环境在短短几个月内会发生什么变化。
当我介绍它时,我想我已经说清楚了,也记录了它是出于我们都同意的事情,我们发现它每天都有用,它打算成为一个极简主义的库,并且该库除了标准库,以便在新项目中尽可能容易地进行部署。当时我的想法是,它只是对标准库的少量扩展,对于我们在特定领域每天发现的有用的东西。
它开始得很好。我们从common/math*
日常使用的例程数学库()开始,因为我们从事的是计算机图形学,而计算机图形学经常是线性代数的繁重工作。因为我们经常与C语言代码interoping,我们商定了一些有用的实用功能,如find_index
它不同于std::find
在C ++中,它将返回序列中找到的元素的索引,而不是迭代器,该迭代器模仿了我们的C函数的工作方式(这种事情)-有点折衷,但极简且广泛使用,足以使每个人都熟悉和实用,并且即时熟悉是我认为要尝试做出“常见”或“标准”事物的一个非常重要的标准,因为如果它确实是“常见”,则由于它的广泛性,它应该具有那种熟悉的质量采用和日常使用。
但是随着时间的流逝,人们开始添加自己个人使用的东西时,图书馆的设计意图突然消失了,他们只是认为自己可能对其他人有用,却找不到其他人使用它。后来有人开始为通用GL相关例程添加依赖OpenGL的函数。进一步,我们采用了Qt,人们开始添加依赖于Qt的代码,因此,公共库已经依赖于两个外部库。有时,有人添加了依赖于我们特定于应用程序的着色器库的通用着色器例程,到那时,如果不引入Qt,OGL和我们特定于应用程序的着色器库并编写代码,您甚至无法将其部署到新项目中项目的重要构建脚本。因此变成了折衷的,相互依存的混乱。
但是我还发现,通过辩论应该进入和不应该进入该库的内容,如果您没有设定严格的规则来确定“共同”是什么,那么被认为是“共同”的内容很容易变成一个非常主观的想法每个人每天都会发现有用的东西。对标准的松动并迅速从每个人的东西降解觉得有用的每天的东西在一个单一的开发者发现有用可能有被别人有益的可能性,而在这一点上库退化为一个折衷的混乱真快。
但是,此外,当您达到这一点时,一些开发人员可以出于不喜欢编程语言的简单原因开始添加内容。他们可能不喜欢for循环或函数调用的语法,这时库开始充斥着与语言的基本语法不符的内容,替换了几行简单的代码,这些代码实际上并没有将任何逻辑都复制到一个简短的外来代码行中,只有引入此类速记的开发人员才熟悉。然后,这样的开发人员可能会开始向使用此类速记实现的通用库添加更多功能,在这一点上,公共库的重要部分与这些奇特的速记方式交织在一起,对于介绍它的开发人员而言,它们看起来似乎很漂亮和直观,但它们却丑陋而陌生,其他人很难理解。在这一点上,我认为您知道,做出真正“普通”的东西的任何希望都将丢失,因为“普通”和“陌生”是相反的想法。
因此,至少在一个松散协调的团队环境中,那里有各种各样的蠕虫罐,其库的野心与“常用的东西”一样广泛和笼统。尽管根本的问题可能是首先是松散的协调,但至少有多个旨在实现更单一目的的库(例如旨在提供数学例程的库,而没有别的什么),就其功能而言,降级的幅度可能不会很大设计纯度和依赖性作为“公共”库。因此,回想一下,我认为最好是在库中使用更清晰的设计意图。多年来,我还发现目的狭窄和适用范围狭窄是根本不同的想法。
同样,我也承认至少有点不切实际,对美学的关注可能有点过分,但是我倾向于以图书馆最薄弱的环节来判断我对图书馆质量(甚至是“美”)的看法的方式更多它的最强功效,就像您向我展示世界上最美味的食物,但是在同一盘子上放一些腐烂的东西,闻起来真的很难闻,我倾向于拒绝整个盘子。而且,如果您在这方面像我一样,并且做一些可以引起各种添加的事情,称为“常见”,那么您可能会发现自己看上去像板块,侧面有些腐烂。因此,同样地,我认为以某种方式对图书馆进行组织,命名和记录是一件好事。随着时间的推移邀请越来越多的人加入。这甚至可以应用于您的个人创作,因为我当然在这里和那里创造了一些烂东西,如果不加到最大的盘子里,它的“污点”要少得多。如果仅凭纯粹的优点,即开始耦合所有内容变得不那么方便,将事物分离到很小的,非常单一的库中也倾向于更好地解耦代码。
多年来,重复数据删除技术已深深扎根于我,但我觉得这次应该尝试一下。
在您的情况下,我可能建议您着手简化重复数据删除技术。我并不是说要复制并粘贴经过大量测试的,容易出错的代码的大片段,或类似的东西,也不是复制大量可能在将来需要进行更改的非平凡代码。
但是,尤其是如果您有创建“通用”库的心态,我认为您希望创建一个广泛应用,高度可重用的库,也许理想情况下,您发现今天的库与现在十年后的库一样有用,那么有时您甚至可能需要重复一些操作来达到这种难以捉摸的质量。因为复制实际上可能充当一种去耦机制。就像您要将视频播放器与MP3播放器分开一样,那么您至少必须复制一些东西,例如电池和硬盘驱动器。他们无法共享这些东西,否则它们将不可分割地耦合在一起,无法彼此独立使用,届时人们可能不再对设备感兴趣,如果他们只想播放MP3。但是,在将这两个设备分开后的一段时间,您可能会发现MP3播放器可以受益于与视频播放器不同的电池设计或更小的硬盘驱动器,这时您不再需要复制任何东西。最初以复制开始,以允许该相互依赖的设备拆分为两个独立的独立设备,后来可能会产生完全不再冗余的设计和实现。
值得从使用库的角度考虑事物。您是否真的想使用一个最小化代码重复的库?您可能不会这样做,因为这样做自然会依赖于其他库。那些其他库可能会依赖其他库来避免重复其代码,依此类推,直到您可能需要导入/链接50个不同的库以仅获得一些基本功能(如加载和播放音频文件),这变得非常笨拙。同时,如果这样的音频库故意选择在这里和那里复制某些内容以实现其独立性,那么它在新项目中的使用将变得非常容易,并且有可能不需要更新频率就几乎可以了,因为它会由于需要更改其依赖的外部库,因此可能需要更改,而这些库可能正在试图实现比音频库所需的更通用的目的。
因此,有时值得故意选择重复一点(有意识地,从不懒惰-实际上是出于勤奋),以使库解耦并使其独立,因为通过这种独立性,它实现了更广泛的实际适用性和甚至稳定(不再有传入耦合)。如果您想设计最可重复使用的库,它将使您从一个项目持续到下一个项目并持续多年,那么除了将其范围缩小到最小之外,我实际上建议考虑在此处进行一些重复。并且自然地编写单元测试,并确保它确实经过了全面的测试,并且可以可靠地执行。这仅适用于您真正想花一些时间来概括到远远超出单个项目的范围的库。