本文最初發布于 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 搜索),我發現有幾個項目似乎在做類似的事情:
下面是讀者指出的一些項目:
如果你了解到其他類似的項目,歡迎和我聯系,我非常樂意聽到更多這樣的項目!
有趣的想象顯然,這個概念并不是什麼突破性的東西,但我認為,對于我們使用的工具,這是一個有趣的思考方式,重要的是,我們如何做得更好。一定有更好的方法存在,設想下它們可能的樣子會很有趣。
,更多精彩资讯请关注tft每日頭條,我们将持续为您更新最新资讯!