golang 标准库间依赖的可视化展示

简介

国庆看完 << Go 语言圣经 >>,总想做点什么,来加深下印象.以可视化的方式展示 golang 标准库之间的依赖,可能是一个比较好的切入点.做之前,简单搜了下相关的内容,网上也要讨论,但是没有发现直接能拿过来用的.标准库之间,是必然存在依赖关系的,不同库被依赖的程度必然是不一样的.但究竟有多大差别呢?

以下内容,数据源自真实环境的 golang 1.9 版本的标准库.所以,本文不仅是一篇可视化相关的讨论文章,更是提供了一个可以直接探究 golang 标准库间依赖关系的快速梳理工具.

数据准备

标准库各个包之间的相互关系,可以直接通过命令获取,然后简单变换为一个标准的 JSON 对象:

go list -json  std

示例输出:

{
    "Dir": "/usr/local/go/src/archive/tar",
    "ImportPath": "archive/tar",
    "Name": "tar",
    "Doc": "Package tar implements access to tar archives.",
    "Target": "/usr/local/go/pkg/darwin_amd64/archive/tar.a",
    "Goroot": true,
    "Standard": true,
    "StaleReason": "standard package in Go release distribution",
    "Root": "/usr/local/go",
    "GoFiles": [
        "common.go",
        "format.go",
        "reader.go",
        "stat_atimespec.go",
        "stat_unix.go",
        "strconv.go",
        "writer.go"
    ],
    "IgnoredGoFiles": [
        "stat_atim.go"
    ],
    "Imports": [
        "bytes",
        "errors",
        "fmt",
        "io",
        "io/ioutil",
        "math",
        "os",
        "path",
        "sort",
        "strconv",
        "strings",
        "syscall",
        "time"
    ],
    "Deps": [
        "bytes",
        "errors",
        "fmt",
        "internal/cpu",
        "internal/poll",
        "internal/race",
        "io",
        "io/ioutil",
        "math",
        "os",
        "path",
        "path/filepath",
        "reflect",
        "runtime",
        "runtime/internal/atomic",
        "runtime/internal/sys",
        "sort",
        "strconv",
        "strings",
        "sync",
        "sync/atomic",
        "syscall",
        "time",
        "unicode",
        "unicode/utf8",
        "unsafe"
    ],
    "TestGoFiles": [
        "reader_test.go",
        "strconv_test.go",
        "tar_test.go",
        "writer_test.go"
    ],
    "TestImports": [
        "bytes",
        "crypto/md5",
        "fmt",
        "internal/testenv",
        "io",
        "io/ioutil",
        "math",
        "os",
        "path",
        "path/filepath",
        "reflect",
        "sort",
        "strings",
        "testing",
        "testing/iotest",
        "time"
    ],
    "XTestGoFiles": [
        "example_test.go"
    ],
    "XTestImports": [
        "archive/tar",
        "bytes",
        "fmt",
        "io",
        "log",
        "os"
    ]
}

梳理过的数据源,参见: https://raw.githubusercontent.com/ios122/graph-go/master/data.js

可视化原理

主要涉及一下内容:

  • 可视化显示,使用的是 echarts
  • 使用原始数据的 ImportPath 而不是 Name,来作为每个数据节点的唯一id.这样是因为 golang 本身的包命名规范决定的.
  • 使用原始数据的 Imports 字段,来确定标准库包与包之间的相互依赖关系.golang是不允许循环依赖的,所以一些循环依赖相关的问题,不需要考虑.
  • 节点的大小,和包被其他包引入的次数成正相关.这样做,被依赖越多的包,图上最终显示时,就会越大.常用包和不常用包,一目了然.

数据整理

就是把原始数据,处理成 echarts 需要的数据,这里简要说下最核心的思路:

  • echarts 显示相关的代码,很大程度上参考了 graph-npm
  • 节点坐标和颜色,采用随机坐标和颜色,以去除节点和包之间的联系.我认为这样处理,能更纯粹地观察标准库包与包之间的联系.
  • 需要一个 edges 来记录包与包之间的依赖关系.在每次遍历 Imports 时,动态写入.
  • 需要一个 nodes 来记录包自身的一些信息,但是其 size 参数,需要计算过所有依赖关系后再填入.
  • 使用 nodedSize 来记录每个包被依赖的次数,为了提升效率,它是一个字典Map.
 /* 将原始数据,转换为图标友好的数据. 
    ImportPath 作为唯一 id 和 标签;
    Imports 用于计算依赖关系;
    节点的大小,取决于被依赖的次数;
    */
function transData(datas){
    /* 存储依赖路径信息. */
    let edges = []

    /* 存储基础节点信息. */
    let nodes = []

    /* 节点尺寸.初始是1, 每被引入一次再加1. */
    let nodedSize = {}

    /* 尺寸单位1. */
    let unitSize = 1.5

    datas.map((data)=>{
        let itemId = data.ImportPath

        nodes.push({
            "label": itemId,
            "attributes": {},
            "id": itemId,
            "size": 1
        })

        if(data.Imports){
            data.Imports.map((importItem)=>{
                edges.push({
                    "sourceID": importItem,
                    "attributes": {},
                    "targetID": itemId,
                    "size": unitSize
                })

                if(nodedSize[importItem]){
                    nodedSize[importItem] = nodedSize[importItem] + unitSize
                }else{
                    nodedSize[importItem] = unitSize
                }
            })
        }
    })

    /* 尺寸数据合并到节点上. */
    nodes.map((item)=>{
        let itemId = item.id
        if(nodedSize[itemId]){
            item.size = nodedSize[itemId]
        }
    })

    return {
        nodes,edges
    }
}

效果与源码

相关链接

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏sunseekers

哪些你知道或不知道的css,在这里或许都齐全 css编码技巧 css小技巧

暑假实习的时候带我的师傅,告诉我要注重基础,底层实现原理。才能在日新月异的技术行业站住脚跟,以不变应万变,万丈高楼平地起,所以我们应该不断的去学习,去交流。交流...

401
来自专栏瓜大三哥

优化策略之PowerOptimization

opt_design[-retarget][-propconst][-sweep][-bram_power_opt][-remap]

311
来自专栏老司机的简书

CoreText实现图文混排之尺寸估算及文本选择

回头看看,距离CoreText系列首发过去一年也多了,看到第一篇文章即将超越1.3W的点击量老司机也是压力越来越大,毕竟作为瞎逼逼杰出代表的老司机偶尔也要正经一...

512
来自专栏华章科技

升值加薪Excel神助攻,数据透视表堪称神器!

VLOOKUP、数据透视表、条件格式…你用这几个技巧做,80%的工作需求都能解决。今天特意整理了这些操作技巧,拯救同在“表海”中挣扎的你,让你的工作效率超乎想...

582
来自专栏Golang语言社区

golang 标准库间依赖的可视化展示

简介 ? 预览 国庆看完 《Go 语言圣经》,总想做点什么,来加深下印象.以可视化的方式展示 golang 标准库之间的依赖,可能是一个比较好的切入点.做之前,...

3407
来自专栏IMWeb前端团队

这个问题你应该很熟悉,然后懵逼,然后放弃

今天早晨决定写这篇博文,但是晚上回家的时候,突然一道闪电从脑海劈过,于是临时决定将这个熟悉然后到懵逼最后到放弃的问题分为两部分。第一部分为抛出问题,诚邀各路英雄...

1680
来自专栏wOw的Android小站

[Tensorflow] 使用SSD-MobileNet训练模型

因为Android Demo里的模型是已经训练好的,模型保存的label都是固定的,所以我们在使用的时候会发现还有很多东西它识别不出来。那么我们就需要用它来训练...

8931
来自专栏ShaoYL

iOS-UI控件之UIImageView

3458
来自专栏hrscy

在unity中使用三种简单的方式实现实时时钟动画

在 unity 中,材质是用来给一个对象的细节,所以我们可以决定它会看起来像什么。在大多数情况下,材料将以纹理为参数。

1592
来自专栏PPV课数据科学社区

【译文】数据可视化的10个关键术语①

Format 交互方式 Interactive visualisations allow you to modify, manipulate and expl...

3294

扫码关注云+社区