速来报名!AICon北京站鸿蒙专场~ 了解详情
写点什么

如何将你的代码可视化?

Alex Ellis

  • 2022-03-03
  • 本文字数:3252 字

    阅读完需:约 11 分钟

如何将你的代码可视化?

本文最初发布于 Alex Ellis 的个人博客。


有一天,我正在阅读关于个人电脑和桌面 GUI 发展的内容,我就想,我们都已经非常习惯个人电脑“桌面“这个类比。我们把文件放在文件夹里,并把它们放在桌面上。这个过程有很多物理动作发生。

人类非常善于理解空间,尤其是在记忆物理空间的时候,这让我联想到了我们通常如何将代码可视化。在思考和可视化代码的时候,有没有什么好的方法可以利用这一点?

如何可视化代码?


这让我想到了我往往如何可视化代码,有点难以描述。我认为,它通常以不同的方式存在于我的脑海中,这取决于抽象和特殊性水平,而且同时存在若干不同方式的组合。根据需要,我可以很好地在它们之间切换,特别是当我对代码库非常熟悉的时候。例如,当我想象各种微服务之间的交互时,在每个服务的周围画个大方框是很有帮助的,把每个服务视为一个大的工作单元,彼此之间通过 RPC 交互。



一个简单的面向微服务的汽车租赁服务架构图,以及代表一条执行路径的分布式跟踪。


另一方面,如果对于计算机如何读取我给它的东西,我想知道微末的细节,那么把所有东西放大到物理内存表示是有帮助的。



我曾经做过的一个 Google Sheets 页的截图,上面有内存地址和汇编指令。这对于非常仔细地了解整个过程很有帮助。


幸运的是,我把大部分时间都花在了中间的某个地方,在阅读实际的代码(比汇编高级),把大块的代码作为一个个大的单元来思考,和研究架构图及系统间通信之间做一些平衡。即使是代码本身也已经有了很多物理关系;想想目录路径、命名空间、行缩进以及代码行的线性排序。

这些可视化的效果如何?


对于这个问题,我考虑了一些不同的可视化技术,每一种技术都有不同的应用场景。考虑一下下面这个不完全的清单:


  • 架构图

  • 依赖图

  • 分布式跟踪

  • 序列图

  • 类图

  • 打印语句

  • 火焰图

  • 阅读源代码


怎么对它们进行比较呢?首先,似乎有一个天然的抽象等级轴线,从低级的代码阅读到高级的架构图。似乎还有一些其他的轴线,我们也可以对它们进行排序。


也许我们可以根据它们在多大程度上代表了更大的系统来对它们进行排名?架构图在这方面做得很好,但火焰图只能代表单个执行路径。也许是变化的频率?这是一个有趣的问题,虽然源代码经常变,但架构图(有望)保持稳定。


让我们想一下,可视化如何很好地表示整个系统实际的代码执行情况呢?在这种情况下,高级的架构图得分也许不会很高,因为它抽象掉了服务框内的许多细节。分布式跟踪可以做得更好,不过具体程度取决于有多少个跟踪点。类图虽然有助于可视化类之间的关系,但可能并不表示实际的路径。火焰图可以显示清晰的执行路径,但只能显示单条代码路径,而不能为更大的系统提供可见性。


画到图上可能会像下面这样,不过上面的这些点表示为一个范围可能更好:



这让我思考,右上角的部分会是什么样子。一个能让我们洞察细节的、有用的可视化该是什么样子?有没有一种方法可以在较低的层次上,将整个系统的路径可视化?

如果我们也使用空间会是什么样子?


看图的感觉仍然像看地图。在那一刻,你把在代码中看到的东西在空间上转化为图表,就像你在一个不熟悉的地方用地图确定方向。就像电脑上的东西,我们用了桌面隐喻一样,我想知道是否有另一种方式将代码可视化为实际存在的东西,以便让翻译过程变得更容易。


如果我们用“玩具型可视化(toy visualization)”在物理空间中表示代码,会怎么样?


看下面这个基本的例子,我们有一个 Counter 类,它有一个私有的 count_ 变量并提供了各种访问方法。也许它会在一个简单的 main 函数中被访问,做一些计数。



#include <iostream>
class Counter {public: void reset() { count_ = 0; } int get() { return count_; } void incr() { ++count_; } void set_count(int x) { count_ = x; }private: int count_;};
int main() { Counter counter; counter.reset(); counter.incr(); counter.incr(); std::cout << counter.get();}
复制代码


如果我们把代码的不同部分表示为三维结构,会怎么样?如果我们把 Counter 类表示为一个大房间,墙上写着咒语,会怎么样?你可以想象代码的可能路径,变量和它们所代表的事物之间的联系,就像下图中的粉红线:



我们可以从中看到什么?首先,作为私有变量,count_ 的用法显然没有什么不当,因为没有任何粉红线从它那里离开房间。公共方法也很清楚,它们与房间外的事物有粉红色的连接。

更有趣的是,这个房间与另一个房间相连,会是什么样子?main 函数可以是另一个房间,其符咒线也做了相应的连接:



现在,我们可以跨房间对话了;在 main 函数调用 counter.reset() 的地方,我们可以有一个从调用者 main 到被调用者 Counter 类的连接。你甚至可以想象有一个调试器单步遍历这个过程,观察这条线路上的参数和返回值。想象一下,我们可以放大不同的区域来查看本地状态和数值,然后沿着调用路径返回到活动区域。


这有用吗?


像这样的东西有用吗?我不确定。用这样的方式走查一个熟悉的代码库会很有趣,特别是当你能在 3D 表示(或是 VR 环境)中做空间探索,并可以根据需要缩小和放大时。当第一次探索一个新的代码库,查看事物之间的连接关系时,不知道它是否会特别有用。不过,我确实处理过一些代码库,如果这样看会非常吓人。我很想看看这样看会有什么不同,每新引入一个类,这儿那儿就会引入新的连接。


话虽如此,我认为在制作这样的东西时,你至少会遇到以下问题:


  • 复杂的代码很难推理。把意大利面代码中的意大利面可视化可谓大快人心,但是对于非常复杂的代码来说,这样做不知道会有多繁琐?

  • 如何表示出像线程同时执行这样的东西?

  • 如何表示是引用传递而不是值传递?

  • 如何表示异步工作?如何表示递归?房间一直嵌套下去?

  • 如何防止里面的东西变得陈旧和过时?至少,这个需要能够自动生成。


问题


有几个考量因素使这个问题变得棘手。一个是物理位置的变化比代码的变化耗时通常长得多。使用熟悉的物理位置作为记忆宫殿,一部分原因是它在你的记忆中每次出现都是一样的。如果你在记忆一副扑克牌,你可以把梅花 A 暂时存放在橱柜门后面,下次你需要存放扑克牌时,橱柜门仍然在那。


如果你的代码库经常变化,反映事物空间布局的地图就可能会发生变化,不管这些地图是 3D 生成的还是纯意识的。这就像回到一个你曾经熟悉的地方,想象一下,不只是地标变了,路也改道了。即使我们天生具有记忆空间事物的天赋,如果那个空间发生了变化,如果我们不得不重新学习,我们还能从空间可视化受益吗?


看看这样的东西对于探索一个新代码库(就像使用地图探索一座新的城市),以及随着时间推移再次回到该代码库(就像离开很长时间后回到自己的家乡),有多大帮助,这会很有趣。

代码可视化项目


我对这一领域的数据可视化不是很熟悉(其他领域的也不熟悉),但经过简单的搜索(也就是 30 分钟的 Google 搜索),我发现有几个项目似乎在做类似的事情:


  • SoftVis3D:其中的“代码城市”视图提供了项目层次结构的可视化。

  • Code Park:一款新的 3D 代码可视化工具(2017),“在类似三维游戏的环境中可视化代码库”,其中,代码被表示为 "代码室",代码在墙上(现在读到这个,感觉和我的想法非常类似)。

  • 使用 3D-Flythrough 实现代码结构可视化(2016),提供空间隐喻和第一人称代码探索。

  • Primitive:一家 VR 合作初创公司,拥有矩阵式的“沉浸式开发环境”,包括“面向 3D 视觉分析软件的新工具”。


下面是读者指出的一些项目:


  • AppMap:一个自动化代码分析工具,包括依赖关系图和跟踪视图。

  • plurid:一个用于在三维可探索结构中可视化和调试代码的框架。

  • fsn(文件管理器):一个实验性的应用程序,支持以 3D 方式查看文件系统(出现在 Jurassic Park 中)。


如果你了解到其他类似的项目,欢迎和我联系,我非常乐意听到更多这样的项目!

有趣的想象


显然,这个概念并不是什么突破性的东西,但我认为,对于我们使用的工具,这是一个有趣的思考方式,重要的是,我们如何做得更好。一定有更好的方法存在,设想下它们可能的样子会很有趣。


查看英文原文:


https://alexanderell.is/posts/visualizing-code/?

2022-03-03 15:315442

评论 2 条评论

发布
用户头像
推荐低代码服务编排库 Commander
https://xie.infoq.cn/article/1adf7327403affd58aadb67a4
2022-03-26 09:09
回复
别扯淡,没有开源的东西
2022-04-13 14:03
回复
没有更多了
发现更多内容

OpenHarmony3.0如何轻松连接华为云IoT设备接入平台

华为云开发者联盟

后端 物联网 华为云 企业号九月金秋榜

字节一面:服务端挂了,客户端的 TCP 连接还在吗?

Java全栈架构师

程序员 面试 TCP 计算机网络 秋招

日志易正式加入华为云云商店联营模式,并受邀参与首届828 B2B企业节

IT资讯搬运工

华为 华为云

软件测试 | 测试开发 | Web服务端推送技术介绍

测吧(北京)科技有限公司

Web 软件测试

程序员交接代码中被植入了恶意删除操作,太狠了!

程序员小毕

Java 程序员 面试 程序人生 码农

BI系统的分布式部署原理和技术实现

葡萄城技术团队

分布式 BI 部署 可视化数据

负载均衡

阿柠xn

负载均衡 运维 MQ 9月月更

堡垒机定义、由来以及价值简单说明-行云管家

行云管家

网络安全 数据安全 堡垒机 行云管家

软件测试 | 测试开发 | java远程连接ssh的实现

测吧(北京)科技有限公司

java;

NFT软件开发:什么是数字藏品?

开源直播系统源码

NFT 数字藏品 数字藏品系统软件开发 数字藏品开发

JDBC系列——JDBC编程六步

胖虎不秃头

MySQL 数据库 9月月更

大咖说 | 无影携手实在智能助力企业“数智化”转型

大咖说

无影 实在智能

如何设计一个高并发系统?这篇文章全部给你讲清楚了

Java永远的神

程序员 面试 后端 高并发 架构师

CodeLab:一款让你体验丝滑般的云化JupyterLab

华为云开发者联盟

人工智能 华为云 企业号九月金秋榜

Python 自动化测试(五): Pytest 结合 Allure 生成测试报告

测吧(北京)科技有限公司

Python 自动化测试 pytest

GaussDB(for Redis)双活容灾支持4大应用场景,全新守护业务安全

华为云开发者联盟

数据库 后端 企业号九月金秋榜

软件测试 | 测试开发 | HttpRunner初体验

测吧(北京)科技有限公司

软件测试 测试

软件测试 | 测试开发 | 免安装免配置环境的免费 ios 调试工具 sib 来啦

测吧(北京)科技有限公司

ios 测试

面试官:如何组装一个注册中心?

Java永远的神

编程 程序员 面试 微服务 注册中心

软件测试 | 测试开发 | 如何利用 xUnit 框架对测试用例进行维护?

测吧(北京)科技有限公司

软件测试

备战2023秋招,应届生应做好哪些准备

C++后台开发

应届生 C++后台开发 校招 秋招 C++开发

探索编译软件栈新范式;高端GPU禁售的影响;陈天奇DL系统免费课程|AI系统前沿动态

OneFlow

内容合集

MySQL系列——连接查询、子查询、union合并、limit

胖虎不秃头

MySQL 数据库 9月月更

一文带你了解K8S 容器编排(下)

霍格沃兹测试开发学社

软件测试 | 测试开发 | Pytest 测试框架,零基础也能轻松 hold 住

测吧(北京)科技有限公司

软件测试 测试

利器 | 接口自动化测试框架 RESTAssured 实践(三):对 Response 结果导出

霍格沃兹测试开发学社

软件测试 自动化测试 测试开发

MySQL系列——数据库表、查询、排序、数据处理函数

胖虎不秃头

MySQL 数据库 9月月更

Apache Hudi X Apache Kyuubi,中国移动云湖仓一体的探索与实践

网易数帆

大数据 Kyuubi Hudi LakeHouse 湖仓一体

只懂黑盒测试也能学会的代码覆盖率及精准化测试

霍格沃兹测试开发学社

软件测试 自动化测试 测试开发

DevStream 社区贡献者英雄榜上线啦!

玩转Devop和研发效能DevStream/DevLake

开源 DevOps 开源社区 DevStream 开源运营

从 Linux 内核角度探秘 JDK NIO 文件读写本质

bin的技术小屋

Linux jdk nio Linux Kenel 文件I/O

如何将你的代码可视化?_架构_闫园园_InfoQ精选文章