去耦
最终,这是在一天结束时在最基本的设计级别上与我解耦,而没有我们的编译器和链接器特性的细微差别。我的意思是,您可以执行以下操作:使每个标头仅定义一个类,使用pimpls,将声明向前声明为只需要声明而不定义的类型,甚至可以使用仅包含正向声明(例如:)的标头,<iosfwd>
每个源文件一个标头,根据要声明/定义的事物的类型一致地组织系统,等等。
减少“编译时依赖性”的技术
而且其中一些技术可以提供很多帮助,但是您可能会筋疲力尽,但仍然发现系统中的平均源文件需要两页的序言, #include
如果您过多地关注在头级别上减少编译时依赖性而又不减少接口设计中的逻辑依赖性,那么这些指令就可以在飞速增长的构建时间上做一些有意义的事情,尽管严格来讲,这可能不被认为是“意大利面条头”仍然会说,这在实践中会转化为类似的不利于生产力的问题。归根结底,如果您的编译单元仍然需要一堆可见的信息才能执行任何操作,那么它将转化为增加的构建时间,并增加了您在使开发人员时可能不得不回头并不得不更改事情的原因。感觉就像是他们在试图完成日常编码的过程中对系统的冲击一样。它'
例如,您可以使每个子系统提供一个非常抽象的头文件和接口。但是,如果子系统之间没有相互分离,那么依赖于其他子系统接口的依赖关系图(看起来像是一团糟)才能正常工作,那么子系统接口又会变得类似于意大利面条。
将声明转发到外部类型
在我尝试用所有技术来获得以前的代码库所需的所有技术中,它们花了两个小时来构建,而开发人员有时却等了两天才轮到我们构建服务器上的CI(您几乎可以想象那些构建机器就像是疲惫的野兽般疯狂地尝试着)以便在开发人员进行更改时跟上并失败),对我来说最令人头疼的是向前声明其他标头中定义的类型。而且,我确实设法在经过很长一段时间后逐步将代码库缩减至40分钟左右,同时尝试减少“标头意大利面”,这是事后看来最有问题的做法(因为这使我忽略了设计,而隧道着眼于标头之间的相互依赖性)则正向声明其他标头中定义的类型。
如果您想象一个Foo.hpp
标题如下:
#include "Bar.hpp"
并且它仅Bar
在标头中使用要求声明的方式,而不是定义。那么似乎可以轻松地声明class Bar;
以避免Bar
在标头中显示该定义。除了在实践中,通常您会发现Foo.hpp
仍然仍然Bar
需要定义仍然要使用的大多数编译单元,而这些额外的负担是必须将Bar.hpp
自身包括在之上Foo.hpp
,否则您会遇到另一种确实有帮助的场景,即99 %的编译单元可以在不包含的情况下工作Bar.hpp
,除非这样会引发一个更根本的设计问题(或者至少在今天我认为应该如此),即为什么他们甚至需要查看的声明Bar
以及为什么Foo
甚至需要费心去了解它是否与大多数用例无关(为什么一个设计要负担另一个几乎从未使用过的依赖?)。
因为从概念上讲,我们还没有真正Foo
脱离Bar
。我们已经做到了,因此的标头Foo
不需要太多有关的标头的信息Bar
,而且还不及真正使这两者完全独立的设计那么重要。
嵌入式脚本
这确实适用于大规模代码库,但我发现另一种非常有用的技术是至少在系统的最高级部分使用嵌入式脚本语言。我发现我可以一天嵌入Lua,并且可以统一调用我们系统中的所有命令(谢天谢地,这些命令是抽象的)。不幸的是,我遇到了一个障碍,在那儿开发人员不信任另一种语言的介绍,而且最奇怪的是,他们以表演为最大怀疑。尽管我可以理解其他问题,但是如果我们仅在用户单击按钮时(例如,他们自己不执行大量循环的情况下)仅利用脚本来调用命令,则性能应该不是问题。担心按钮点击响应时间的纳秒级差异?)。
例
同时,在用尽减少大型代码库中的编译时间的技术之后,我见过的最有效的方法是架构,这些架构真正减少了系统中任何一项工作所需的信息量,而不仅仅是从编译器中解耦一个头到另一个头从角度来看,但要求这些接口的用户做他们需要做的事情,同时要知道(从人和编译器的角度来看,真正的去耦超出了编译器的依赖性)。
ECS只是一个示例(我不建议您使用一个示例),但是遇到它向您展示了您可以拥有一些真正的史诗级代码库,这些代码库仍然可以令人惊讶地快速构建,同时愉快地使用模板和许多其他优点,因为ECS通过自然,创建了一个高度分离的架构,其中系统仅需要了解ECS数据库,通常只有少数组件类型(有时只有一个)可以完成其任务:
设计,设计,设计
随着代码库的增长,增长和增长,这种在人类概念层面上分离的体系结构设计在最小化编译时间方面比我上面探讨的任何技术更有效,因为这种增长不会转化为您的平均水平编译单元乘以编译和链接时所需的工作量信息(任何需要您的普通开发人员包括大量工作来做任何事情的系统,都需要他们,而不仅仅是编译器知道很多信息来做任何事情)。它还比减少构建时间和使标头解开具有更多的好处,因为这还意味着您的开发人员除了对系统进行某些处理外,不需要立即了解其他知识。
例如,如果您可以聘请专业的物理开发人员为您的AAA游戏开发一个物理引擎,该引擎跨越数百万个LOC,并且他可以很快上手,同时了解诸如类型和接口之类的绝对最低限度的信息。以及您的系统概念,那么这自然将转化为减少他和编译器构建物理引擎所需的信息量,同样也转化为构建时间的减少,同时通常意味着没有类似意大利面条的内容系统中的任何地方。这就是我建议优先考虑的所有其他技术:如何设计系统。如果您精疲力尽,则其他技巧将锦上添花,否则,