<story><title>Show HN: Visualize the entropy of a codebase with a 3D force-directed graph</title><url>https://github.com/gabotechs/dep-tree</url><text>Hi HN! I&amp;#x27;m Gabriel, the author of dep-tree (&lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;gabotechs&amp;#x2F;dep-tree&quot;&gt;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;gabotechs&amp;#x2F;dep-tree&lt;/a&gt;), and I wanted to show off this tool and explain why it&amp;#x27;s being really useful at my current org for dealing with code complexity.&lt;p&gt;I work at a startup where business evolves really fast, and requirements change frequently, so it&amp;#x27;s easy to end up with big piles of code stacked together without a clear structure, specially with tight deadlines. I made dep-tree [1] to help us maintain a clean code architecture and a logical separation of concerns between parts of the application, which is accomplished by: (1) Visualizing the source files and the dependencies between them using a 3D force-directed graph; and (2) Enforcing some dependency rules that allow&amp;#x2F;forbid dependencies between different parts of the application.&lt;p&gt;The 3D force-directed graph visualization works like this: - It takes an entrypoint to the codebase, usually the main executable file or a library&amp;#x27;s entrypoint (index.js, main.py, etc...) - It recursively crawls import statements gathering other source files that are being depended upon - It creates a directed graph out of that, where nodes are source files and edges are the dependencies between them - It renders this graph in the browser using a 3D force-directed layout, where attraction&amp;#x2F;repulsion forces will be applied to each node depending on which other nodes it is connected to.&lt;p&gt;With this, properly decoupled codebases will tend to form clusters of nodes, representing logical parts that live together and are clearly separated from other parts, and tightly coupled codebases will be rendered without clear clustering or without a clear structural pattern in the node placement.&lt;p&gt;Some examples of this visualization for well-known codebases are:&lt;p&gt;TypeScript:  &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FTypeScript&amp;amp;entrypoint=src%2Ftypescript%2Ftypescript.ts&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;React: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Ffacebook%2Freact&amp;amp;entrypoint=packages%2Freact-dom%2Findex.js&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;Svelte: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Fsveltejs%2Fsvelte&amp;amp;entrypoint=packages%2Fsvelte%2Fsrc%2Fcompiler%2Findex.js&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;Langchain: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Flangchain-ai%2Flangchain&amp;amp;entrypoint=libs%2Flangchain%2Flangchain%2F__init__.py&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;Numpy: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Fnumpy%2Fnumpy&amp;amp;entrypoint=numpy%2F__init__.py&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;Deno: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Fdenoland%2Fdeno&amp;amp;entrypoint=cli%2Fmain.rs&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;The visualizations are cool, but it&amp;#x27;s just the first step. The dependency rules checking capabilities is what makes the tool actually useful in a daily basis and what keeps us using it every day in our CI pipelines for enforcing decoupling. More info about this feature is available in the repo: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;gabotechs&amp;#x2F;dep-tree?tab=readme-ov-file#check&quot;&gt;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;gabotechs&amp;#x2F;dep-tree?tab=readme-ov-file#che...&lt;/a&gt;. The code is fully open-source.</text></story><parent_chain></parent_chain><comment><author>ytjohn</author><text>This is really cool. And as OP pointed out, I really like the pipeline integration. Like when linting catches function-level complexity, but in a cross functional way. I prefer to think of programs in layers where the top layers can import lower layers, but never the other way (and also very cautious on horizontal imports). Something like this would help track that. Unfortunately, I&amp;#x27;d really need to support Go. I find it interesting the the code is written in Go, but doesn&amp;#x27;t support Go. But I will watch this project.&lt;p&gt;From the visualization perspective, it reminds me a lot of Gource.  Gource is a cool visualization showing contributions to a repo. You see individual contributors buzzing around updating files on per-commit and per-merge.&lt;p&gt;&lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;acaudwell&amp;#x2F;Gource&quot;&gt;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;acaudwell&amp;#x2F;Gource&lt;/a&gt;</text></comment>
<story><title>Show HN: Visualize the entropy of a codebase with a 3D force-directed graph</title><url>https://github.com/gabotechs/dep-tree</url><text>Hi HN! I&amp;#x27;m Gabriel, the author of dep-tree (&lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;gabotechs&amp;#x2F;dep-tree&quot;&gt;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;gabotechs&amp;#x2F;dep-tree&lt;/a&gt;), and I wanted to show off this tool and explain why it&amp;#x27;s being really useful at my current org for dealing with code complexity.&lt;p&gt;I work at a startup where business evolves really fast, and requirements change frequently, so it&amp;#x27;s easy to end up with big piles of code stacked together without a clear structure, specially with tight deadlines. I made dep-tree [1] to help us maintain a clean code architecture and a logical separation of concerns between parts of the application, which is accomplished by: (1) Visualizing the source files and the dependencies between them using a 3D force-directed graph; and (2) Enforcing some dependency rules that allow&amp;#x2F;forbid dependencies between different parts of the application.&lt;p&gt;The 3D force-directed graph visualization works like this: - It takes an entrypoint to the codebase, usually the main executable file or a library&amp;#x27;s entrypoint (index.js, main.py, etc...) - It recursively crawls import statements gathering other source files that are being depended upon - It creates a directed graph out of that, where nodes are source files and edges are the dependencies between them - It renders this graph in the browser using a 3D force-directed layout, where attraction&amp;#x2F;repulsion forces will be applied to each node depending on which other nodes it is connected to.&lt;p&gt;With this, properly decoupled codebases will tend to form clusters of nodes, representing logical parts that live together and are clearly separated from other parts, and tightly coupled codebases will be rendered without clear clustering or without a clear structural pattern in the node placement.&lt;p&gt;Some examples of this visualization for well-known codebases are:&lt;p&gt;TypeScript:  &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Fmicrosoft%2FTypeScript&amp;amp;entrypoint=src%2Ftypescript%2Ftypescript.ts&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;React: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Ffacebook%2Freact&amp;amp;entrypoint=packages%2Freact-dom%2Findex.js&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;Svelte: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Fsveltejs%2Fsvelte&amp;amp;entrypoint=packages%2Fsvelte%2Fsrc%2Fcompiler%2Findex.js&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;Langchain: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Flangchain-ai%2Flangchain&amp;amp;entrypoint=libs%2Flangchain%2Flangchain%2F__init__.py&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;Numpy: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Fnumpy%2Fnumpy&amp;amp;entrypoint=numpy%2F__init__.py&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;Deno: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2Fgithub.com%2Fdenoland%2Fdeno&amp;amp;entrypoint=cli%2Fmain.rs&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;dep-tree-explorer.vercel.app&amp;#x2F;api?repo=https%3A%2F%2F...&lt;/a&gt;&lt;p&gt;The visualizations are cool, but it&amp;#x27;s just the first step. The dependency rules checking capabilities is what makes the tool actually useful in a daily basis and what keeps us using it every day in our CI pipelines for enforcing decoupling. More info about this feature is available in the repo: &lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;gabotechs&amp;#x2F;dep-tree?tab=readme-ov-file#check&quot;&gt;https:&amp;#x2F;&amp;#x2F;github.com&amp;#x2F;gabotechs&amp;#x2F;dep-tree?tab=readme-ov-file#che...&lt;/a&gt;. The code is fully open-source.</text></story><parent_chain></parent_chain><comment><author>sam_bristow</author><text>A tangentially related tool you can use to look at a repo over time is Git of Theseus[1]. It shows things like &amp;quot;what percentage of the code in this repo survives 6 months.&lt;p&gt;[1]&lt;a href=&quot;https:&amp;#x2F;&amp;#x2F;erikbern.com&amp;#x2F;2016&amp;#x2F;12&amp;#x2F;05&amp;#x2F;the-half-life-of-code.html&quot; rel=&quot;nofollow&quot;&gt;https:&amp;#x2F;&amp;#x2F;erikbern.com&amp;#x2F;2016&amp;#x2F;12&amp;#x2F;05&amp;#x2F;the-half-life-of-code.html&lt;/a&gt;</text></comment>