让我们制作一张应对依存关系的地图
首先我想介绍今年我做的源代码或者说是项目的审查工具。
我个人觉得还加了一些有趣的功能,希望能给大家带来一些启发!
顺便说一句,既然有这个机会,我想借用“本番环境出错的人日历”的受欢迎之处,以类似“开发小错日历”的方式继续下去。
介绍工具我先介绍一下成果物。
我开发了一个名为 ddeps 的工具,用于显示D语言模块之间的依赖关系图。
这个软件的主要功能是”可视化依赖关系”,但是还有一个相当不寻常的功能,可以”显示两个版本之间的依赖关系差异”。
如果你感兴趣的话,源代码和文件已经整理在下面,请随意查看。还有样例在底部。
-
- http://code.dlang.org/packages/ddeps
- https://github.com/lempiji/ddeps
这到底有什么用途呢?
开发背景
每天的开发我们以相对不错的人数,开发了规模相对不错的产品。
模块数量超过了数千个,我从未计算过总共有多少行,但整体来说,它是一座巨塔,看不到整体的程度。
模块数量超过了数千个,我从未计算过总共有多少行,但整体来说,它是一座巨塔,看不到整体的程度。
然而,我们的前辈预见到了这一点,根据各个部门的职责划分了不同的层次,并设计了松散耦合的结构。多亏了这样的设计,我们日常的开发并不像寒冬里在体育课上被冷风抽打一样困难,甚至在繁忙的时候也能感觉到一片宁静。
我曾经想到过:“睡眠是通过规划来保证的。”
嗯,那个睡眠被Minecraft打碎了。
常见功能增强在软件产品中,有一些重要的组成部分,例如库、实用程序、基础程序、内部框架等,尽管它们可能有不同的称呼。
也许起初只是一个小小的请求,但是随着传言游戏的进行,关于是否能够加强类似重要的部件的话题就像山一样涌现出来。每一次都是一个重大事件呢。
作为一名从事软件工程的人员,尽管有许多重要的强化事项,但我首先考虑的是“快速编写易于用户使用、高效维护的程序,回家后在Minecraft里想做点什么?”来工作。
回想起来的话,我觉得我们好像谈过类似的话题,就是“如果按照正常的设计做的话,就可以在这里插入这样一种功能,只需要组合已有的功能就行”,但也可能只是我自己的想象。
只要下定决心一次性做完,无论如何都可以把事情处理得妥妥当当。通过检查和审阅,一定会没问题的。请相信猫猫。
努力修正、审核,构建和测试都没有问题。
因此,顺利完成了这次增强。
真的吗? de ma?)
某天察觉到了什么过了一段时间,有一天决定进行产品的完整制作。
很幸运地,运行时已经进行了主要版本升级,我们有机会享受到加速优化和使用新功能的好处。我一定要做这件事,因为它看起来很有趣。
噢,顺便说一下,开发工具是 Visual Studio,但并不是只需要打开解决方案、点击构建按钮就结束了。
因为有成千上万个”解决方案”。不可能一个一个地打开并构建,这个工作显然需要完全自动化才能解决,这一点在 D 语言小伙伴看来是显而易见的。
首先,编写一个简单的脚本来确定构建顺序,创建一个依赖关系图,使用拓扑排序方法进行重新排序,这样就可以确定构建顺序。听起来有些热带风情呢。
然后执行脚本,造成堆栈溢出。什么???
没错,其实图表存在着相互依赖的循环问题。先人们的设计到底是为了什么呢?
尽管眼前有一个看起来很有趣的玩具,但却无法构建重要的程序,真的好伤心,简直快哭了:;(∩´﹏`∩);:
需要时的肌肉当我们冷静下来思考一下,其实根本不需要进行某种排序,只要枚举依赖关系就能生成图形。Graphviz简直太神奇了。
当我们查看图表时,我们会发现被认为是最底层库之一的一个组件,在逻辑上引用了一层较高的部件。由于这些部件的命运就是如果有一个地方出了问题,它们将被顺序引用,所以它们中间会围绕着大约6个部件形成一个循环依赖的完整循环。这是怎么回事?
嗯,我們查到後發現這是最近的事情,完全是我們自己招惹的,所以我們決定在這問題解決之前自我約束,晚上不再玩Minecraft。
但是一旦了解情况,就有办法来处理,因为人们说肌肉能解决所有问题。
由于我缺乏肌肉,所以我想出了一个凡人版的解决方案,大致有五个步骤。
-
- 首先,在底层模块中删除对上层模块的错误引用。
-
- 删除引用后,将出现错误的实现一次性清空。
-
- (幸运的是,没有出现必须清空的地方,比如函数返回值,但如果出现的话,可能需要进一步的步骤)
-
- 确认此时能够进行构建,并暂时保存。
-
- ※从这一点开始逐步恢复,所以保存很重要
-
- 将在第2步中删除的功能从上层组件中剥离并移至底层模块,使其被上层组件引用。
- 重新引用底层模块中提取出的组件,并恢复已经清空的实现。
完成任务后重新输出图表,确保所有循环依赖都已解决,任务完成。
重构很有趣。
據我所知,這樣你晚上可以睡得很好,還可以解禁Minecraft,期待每天都能夠享受使用最新功能進行開發的愉快時光!(雖然已經過了幾年,看起來還沒有到來,但我相信一定會到來!)
回顾和应对循环参照通常发生在设计有问题时的两个部件之间。
然而,由于有6个或者7个不同的方面相互交织,因此这个问题相当困难和罕见,要想理解它,需要广泛的、长期的参与。
尽管我们经历了各种困难,但终于成功地完成了版本升级。但是为了构建脚本发生了一些变动,还需要与其他人交流一下,导致我们争论了将近两天。从那时开始,为了完成修复工作,构建进度的消耗变得非常惨烈。
作为反思,我意识到了两点:无法与人类无法看到的东西进行战斗,而人类总是会利用已经存在的东西。然后我意识到需要将模块和功能的依赖关系可视化,使其始终可见。看一下图表就能一目了然,这在判断工作是否完成上也很有用。
这次制作的ddeps工具最终完成了,用于输出这样的依存分析图。(终于回来了)
观察依赖关系因此,接下来是工具功能的介绍。
相信您看到输出的图形后,大致上能够理解我的心情。
输出示例
基本形式首先,我尝试将它整合到自己开发的名为 rx 的库中,以下是结果。
为了使用Reactive Extensions(响应式扩展)在D语言中编写代码,有25个模块可供使用。我认为这是一个中等规模的dub包。
由于去年开始进行了大规模的增强措施,我们在制作图表时尝试提取了版本之间的差异,以增强视觉效果。

你能感受到图层有点分开的感觉吗?
因为有很多线条,所以看起来有点乱,但是线条的断裂几乎没有,还算比较整洁的。
当细心地观察时,我们还能知道标准库的使用情况,并且差异部分会被着色标注。
当查看评论时,可以参考这个。
-
- 何を追加したのか
- 何を消したのか
在远处观看,也能大致了解。
去除标准库
由于D的标准库通常以std或者core开头,因此这个例子是排除了那些范围的。我们也提供了工具来过滤这些范围。
与之前的例子相比,这个例子更加清晰,噪音也更少,所以我认为这个更容易阅读,适合用于介绍库的升级版本之类的。
试着添加一个奇怪的引用来源进行尝试首先,为了取样示例,我们列举相对较为整洁的状态。
我会尝试从最底层的层次引用与其完全无关的上层层次。
随意往下伸展了一下,但本来右边或左边那些线条就有些崩溃的迹象。
这种现象通常发生在进行了一些不合理的设计时,这时候一般表示有什么地方出了问题。
在下面拉伸的地方,可以稍微察觉到循环引用。
然而,即使循环参照,布局也可能不会有太大变化。
在这种情况下,由于有颜色,所以可以理解,但是从底部右侧向上的箭头增加了一个。
由于在Graphviz的布局中,原本就有大量的箭头指向的模块非常难以移动,所以这有点遗憾,但这是一种正常现象。
这种情况下,关键在于”箭头的方向”,上箭头是一个警示标志。
我认为只要找到”像刺入圆形模块底部的箭头头尖”的样子,很快就能找到。
尝试将其应用于适当的库中
我們將應用在 dub 套件中相對較著名並且規模相對較大的 “mir-algorithm” 庫。
-
mir-algorithm
http://code.dlang.org/packages/mir-algorithm
顺便一提,这是一个提供了一些张量和数值计算算法的软件包。
最近有很多涉及引用计数模块增加和废弃模块整理的变动,因此可以用来了解相关概述的目的。
有些从下往上的箭头也零零散散地存在,但附近新增的部分形成了一个好看的块状,所以很容易理解。
不像之前那样左右弯曲得不太自然的线条,估计是由于规模适中、设计精美。
有一种模糊感觉好像能感受到图层,但线条太多了,密度也太大了……(是个问题)
概念如果你看一下这个图表,大概就能结束了,但在创建这个工具时,我有三个目标概念,我将它们总结如下。
-
「結果を見ることで綺麗な依存関係を作れるようにする」
-
「広く知られたメタ知識を活用して初見でもわかるようにする」
「ライブラリ作成を面白くする」
首先最重要的是通过图表来直观地了解“设计的优劣”,从“外观的美观”上入手,这是我最初的想法。
最初的假设是“如果设计精美,即使转化为图表也能保持美观”,确实,当设计得当时,依赖关系会整体流畅,模块和层次结构也变得更加清晰可见。
此外,在表示图表元素的差异时,我基本上直接借鉴了GitHub代码差异所采用的颜色表示方法。当元素增加时,使用绿色,减少时使用红色。这种方法利用了大家都隐约掌握的”元知识”,使得表示更加清晰易懂,我觉得比我想象的要好。可能还有许多类似的工具我不知道。
我打算在README中整理安装步骤,将其注册为dub包,以便更容易地使用。(看起来还是需要增强功能,以减少一些命令。)
我认为将其应用于手头的库时会立即呈现出图表的开发体验非常有趣,我希望能够继续使用类似的概念来开发能够对程序进行分析的工具。
思考方式使用D语言编译器的依赖关系输出功能来准备文件,使用工具生成用于Graphviz的dot文件,然后使用Graphviz将其转化为图形,这是基本的流程。
D語言的編譯器主要有DMD、LDC、GDC三種,只需在DMD/LDC中指定一個叫做-deps的旗標就可以輸出這個依賴關係。我個人稱這個文件為”deps文件”。
※GDC也有一個叫做-fmake-deps的旗標,但其運作情況未經過確認。
-
コンパイラスイッチの説明
https://dlang.org/dmd-windows.html#switch-deps
最初我打算通过静态分析来解决,但是一旦注意到这个文件的存在,只需要稍微调整算法,就能在不到一天的时间内完成。
另外,差分展示參考了網頁常見的快照測試,但需要保存前一個圖表,因此將deps文件副本命名為deps-lock文件放在一邊。
接下來的差分計算是單元測試以及專注的結果。(整个程式共計600行不到,包含測試)
因此,如果将工具配置和数据流程绘制成图表,大致是这个样子。
使用方法需要做的三项任务是:输出依赖关系、更新锁定文件和生成差分图。
在事先安装并设置好Graphviz的路径后,为了简化后续命令,将以下配置写入dub.json文件。
请在其中一处diff注释的地方设置为–focus=rx,并将其设置为配置库的顶层模块名称。
"configurations": [
{
"name": "default"
},
{
"name": "diff",
"postGenerateCommands": [
"dub build -c makedeps",
"dub fetch ddeps",
"dub run ddeps -- --focus=rx -o deps.dot",
"dot -Tsvg -odeps.svg deps.dot"
]
},
{
"name": "diff-update",
"postGenerateCommands": [
"dub fetch ddeps",
"dub run ddeps -- --update"
]
},
{
"name": "makedeps",
"dflags": ["-deps=deps.txt"]
}
]
只需要一个选项来用
-
首次构建时使用 `dub build -c makedeps` 生成依赖关系文件,并使用 `dub build -c diff-update` 生成 lock 文件。
使用 `dub build -c diff` 生成并查看图形。
如果需要更改模块组成或依赖关系,则进行相应的修改,并返回到步骤2。
一切就绪后,使用 `dub build -c diff-update` 更新 lock 文件。
这种感觉。
总结
-
大規模になるほど循環依存の問題が見つかったときは大変
-
人間見えないものとは戦えない
特に循環依存に関しては「発生の瞬間に気づけない」こともある
人間あるものは何でも使おうとする
便利なものは1か所に置きたくなるけど心を鬼にして小さく分けよう
D言語にはコンパイラ組み込みの便利機能が色々ある(-depsフラグ)
Graphvizは神
最后尽管还有许多改进的地方,但个人认为今年是我最满意的工具。(因为仍然可以玩得很开心)
因为这次使用了熟悉的语言,所以能够充分享受到使用标准库进行有序集合的差分计算等的好处。果然熟悉一切事物都会使人变得更强大呢!
希望在这种依赖关系分析工具的帮助下,能让眼前的项目保持愉快的维护,并助力追求更好的设计!
我觉得制作工具和编程都很有趣,希望使用D语言能更加有趣!!!

与之前的例子相比,这个例子更加清晰,噪音也更少,所以我认为这个更容易阅读,适合用于介绍库的升级版本之类的。
试着添加一个奇怪的引用来源进行尝试首先,为了取样示例,我们列举相对较为整洁的状态。
我会尝试从最底层的层次引用与其完全无关的上层层次。
随意往下伸展了一下,但本来右边或左边那些线条就有些崩溃的迹象。
这种现象通常发生在进行了一些不合理的设计时,这时候一般表示有什么地方出了问题。
在下面拉伸的地方,可以稍微察觉到循环引用。
然而,即使循环参照,布局也可能不会有太大变化。
在这种情况下,由于有颜色,所以可以理解,但是从底部右侧向上的箭头增加了一个。
由于在Graphviz的布局中,原本就有大量的箭头指向的模块非常难以移动,所以这有点遗憾,但这是一种正常现象。
这种情况下,关键在于”箭头的方向”,上箭头是一个警示标志。
我认为只要找到”像刺入圆形模块底部的箭头头尖”的样子,很快就能找到。
尝试将其应用于适当的库中
我們將應用在 dub 套件中相對較著名並且規模相對較大的 “mir-algorithm” 庫。
-
mir-algorithm
http://code.dlang.org/packages/mir-algorithm
顺便一提,这是一个提供了一些张量和数值计算算法的软件包。
最近有很多涉及引用计数模块增加和废弃模块整理的变动,因此可以用来了解相关概述的目的。
有些从下往上的箭头也零零散散地存在,但附近新增的部分形成了一个好看的块状,所以很容易理解。
不像之前那样左右弯曲得不太自然的线条,估计是由于规模适中、设计精美。
有一种模糊感觉好像能感受到图层,但线条太多了,密度也太大了……(是个问题)
概念如果你看一下这个图表,大概就能结束了,但在创建这个工具时,我有三个目标概念,我将它们总结如下。
-
「結果を見ることで綺麗な依存関係を作れるようにする」
-
「広く知られたメタ知識を活用して初見でもわかるようにする」
「ライブラリ作成を面白くする」
首先最重要的是通过图表来直观地了解“设计的优劣”,从“外观的美观”上入手,这是我最初的想法。
最初的假设是“如果设计精美,即使转化为图表也能保持美观”,确实,当设计得当时,依赖关系会整体流畅,模块和层次结构也变得更加清晰可见。
此外,在表示图表元素的差异时,我基本上直接借鉴了GitHub代码差异所采用的颜色表示方法。当元素增加时,使用绿色,减少时使用红色。这种方法利用了大家都隐约掌握的”元知识”,使得表示更加清晰易懂,我觉得比我想象的要好。可能还有许多类似的工具我不知道。
我打算在README中整理安装步骤,将其注册为dub包,以便更容易地使用。(看起来还是需要增强功能,以减少一些命令。)
我认为将其应用于手头的库时会立即呈现出图表的开发体验非常有趣,我希望能够继续使用类似的概念来开发能够对程序进行分析的工具。
思考方式使用D语言编译器的依赖关系输出功能来准备文件,使用工具生成用于Graphviz的dot文件,然后使用Graphviz将其转化为图形,这是基本的流程。
D語言的編譯器主要有DMD、LDC、GDC三種,只需在DMD/LDC中指定一個叫做-deps的旗標就可以輸出這個依賴關係。我個人稱這個文件為”deps文件”。
※GDC也有一個叫做-fmake-deps的旗標,但其運作情況未經過確認。
-
コンパイラスイッチの説明
https://dlang.org/dmd-windows.html#switch-deps
最初我打算通过静态分析来解决,但是一旦注意到这个文件的存在,只需要稍微调整算法,就能在不到一天的时间内完成。
另外,差分展示參考了網頁常見的快照測試,但需要保存前一個圖表,因此將deps文件副本命名為deps-lock文件放在一邊。
接下來的差分計算是單元測試以及專注的結果。(整个程式共計600行不到,包含測試)
因此,如果将工具配置和数据流程绘制成图表,大致是这个样子。
使用方法需要做的三项任务是:输出依赖关系、更新锁定文件和生成差分图。
在事先安装并设置好Graphviz的路径后,为了简化后续命令,将以下配置写入dub.json文件。
请在其中一处diff注释的地方设置为–focus=rx,并将其设置为配置库的顶层模块名称。
"configurations": [
{
"name": "default"
},
{
"name": "diff",
"postGenerateCommands": [
"dub build -c makedeps",
"dub fetch ddeps",
"dub run ddeps -- --focus=rx -o deps.dot",
"dot -Tsvg -odeps.svg deps.dot"
]
},
{
"name": "diff-update",
"postGenerateCommands": [
"dub fetch ddeps",
"dub run ddeps -- --update"
]
},
{
"name": "makedeps",
"dflags": ["-deps=deps.txt"]
}
]
只需要一个选项来用
-
首次构建时使用 `dub build -c makedeps` 生成依赖关系文件,并使用 `dub build -c diff-update` 生成 lock 文件。
使用 `dub build -c diff` 生成并查看图形。
如果需要更改模块组成或依赖关系,则进行相应的修改,并返回到步骤2。
一切就绪后,使用 `dub build -c diff-update` 更新 lock 文件。
这种感觉。
总结
-
大規模になるほど循環依存の問題が見つかったときは大変
-
人間見えないものとは戦えない
特に循環依存に関しては「発生の瞬間に気づけない」こともある
人間あるものは何でも使おうとする
便利なものは1か所に置きたくなるけど心を鬼にして小さく分けよう
D言語にはコンパイラ組み込みの便利機能が色々ある(-depsフラグ)
Graphvizは神
最后尽管还有许多改进的地方,但个人认为今年是我最满意的工具。(因为仍然可以玩得很开心)
因为这次使用了熟悉的语言,所以能够充分享受到使用标准库进行有序集合的差分计算等的好处。果然熟悉一切事物都会使人变得更强大呢!
希望在这种依赖关系分析工具的帮助下,能让眼前的项目保持愉快的维护,并助力追求更好的设计!
我觉得制作工具和编程都很有趣,希望使用D语言能更加有趣!!!


这种现象通常发生在进行了一些不合理的设计时,这时候一般表示有什么地方出了问题。
在下面拉伸的地方,可以稍微察觉到循环引用。
然而,即使循环参照,布局也可能不会有太大变化。

由于在Graphviz的布局中,原本就有大量的箭头指向的模块非常难以移动,所以这有点遗憾,但这是一种正常现象。
这种情况下,关键在于”箭头的方向”,上箭头是一个警示标志。
我认为只要找到”像刺入圆形模块底部的箭头头尖”的样子,很快就能找到。
尝试将其应用于适当的库中
我們將應用在 dub 套件中相對較著名並且規模相對較大的 “mir-algorithm” 庫。
-
mir-algorithm
- mir-algorithm
http://code.dlang.org/packages/mir-algorithm
顺便一提,这是一个提供了一些张量和数值计算算法的软件包。
最近有很多涉及引用计数模块增加和废弃模块整理的变动,因此可以用来了解相关概述的目的。

不像之前那样左右弯曲得不太自然的线条,估计是由于规模适中、设计精美。
有一种模糊感觉好像能感受到图层,但线条太多了,密度也太大了……(是个问题)
概念如果你看一下这个图表,大概就能结束了,但在创建这个工具时,我有三个目标概念,我将它们总结如下。
-
「結果を見ることで綺麗な依存関係を作れるようにする」
- 「結果を見ることで綺麗な依存関係を作れるようにする」
-
- 「広く知られたメタ知識を活用して初見でもわかるようにする」
- 「ライブラリ作成を面白くする」
首先最重要的是通过图表来直观地了解“设计的优劣”,从“外观的美观”上入手,这是我最初的想法。
最初的假设是“如果设计精美,即使转化为图表也能保持美观”,确实,当设计得当时,依赖关系会整体流畅,模块和层次结构也变得更加清晰可见。
此外,在表示图表元素的差异时,我基本上直接借鉴了GitHub代码差异所采用的颜色表示方法。当元素增加时,使用绿色,减少时使用红色。这种方法利用了大家都隐约掌握的”元知识”,使得表示更加清晰易懂,我觉得比我想象的要好。可能还有许多类似的工具我不知道。
我打算在README中整理安装步骤,将其注册为dub包,以便更容易地使用。(看起来还是需要增强功能,以减少一些命令。)
我认为将其应用于手头的库时会立即呈现出图表的开发体验非常有趣,我希望能够继续使用类似的概念来开发能够对程序进行分析的工具。
思考方式使用D语言编译器的依赖关系输出功能来准备文件,使用工具生成用于Graphviz的dot文件,然后使用Graphviz将其转化为图形,这是基本的流程。
D語言的編譯器主要有DMD、LDC、GDC三種,只需在DMD/LDC中指定一個叫做-deps的旗標就可以輸出這個依賴關係。我個人稱這個文件為”deps文件”。
※GDC也有一個叫做-fmake-deps的旗標,但其運作情況未經過確認。
-
- コンパイラスイッチの説明
https://dlang.org/dmd-windows.html#switch-deps
最初我打算通过静态分析来解决,但是一旦注意到这个文件的存在,只需要稍微调整算法,就能在不到一天的时间内完成。
另外,差分展示參考了網頁常見的快照測試,但需要保存前一個圖表,因此將deps文件副本命名為deps-lock文件放在一邊。
接下來的差分計算是單元測試以及專注的結果。(整个程式共計600行不到,包含測試)
因此,如果将工具配置和数据流程绘制成图表,大致是这个样子。

使用方法需要做的三项任务是:输出依赖关系、更新锁定文件和生成差分图。
在事先安装并设置好Graphviz的路径后,为了简化后续命令,将以下配置写入dub.json文件。
请在其中一处diff注释的地方设置为–focus=rx,并将其设置为配置库的顶层模块名称。
"configurations": [
{
"name": "default"
},
{
"name": "diff",
"postGenerateCommands": [
"dub build -c makedeps",
"dub fetch ddeps",
"dub run ddeps -- --focus=rx -o deps.dot",
"dot -Tsvg -odeps.svg deps.dot"
]
},
{
"name": "diff-update",
"postGenerateCommands": [
"dub fetch ddeps",
"dub run ddeps -- --update"
]
},
{
"name": "makedeps",
"dflags": ["-deps=deps.txt"]
}
]
只需要一个选项来用
-
- 首次构建时使用 `dub build -c makedeps` 生成依赖关系文件,并使用 `dub build -c diff-update` 生成 lock 文件。
使用 `dub build -c diff` 生成并查看图形。
如果需要更改模块组成或依赖关系,则进行相应的修改,并返回到步骤2。
一切就绪后,使用 `dub build -c diff-update` 更新 lock 文件。
这种感觉。
总结
-
大規模になるほど循環依存の問題が見つかったときは大変
- 大規模になるほど循環依存の問題が見つかったときは大変
-
- 人間見えないものとは戦えない
特に循環依存に関しては「発生の瞬間に気づけない」こともある
人間あるものは何でも使おうとする
便利なものは1か所に置きたくなるけど心を鬼にして小さく分けよう
D言語にはコンパイラ組み込みの便利機能が色々ある(-depsフラグ)
Graphvizは神
最后尽管还有许多改进的地方,但个人认为今年是我最满意的工具。(因为仍然可以玩得很开心)
因为这次使用了熟悉的语言,所以能够充分享受到使用标准库进行有序集合的差分计算等的好处。果然熟悉一切事物都会使人变得更强大呢!
希望在这种依赖关系分析工具的帮助下,能让眼前的项目保持愉快的维护,并助力追求更好的设计!
我觉得制作工具和编程都很有趣,希望使用D语言能更加有趣!!!