我追蹤程式碼(trace code)的方式。
追蹤程式碼就是閱讀程式碼,目的是為了瞭解某個功能或系統在做什麼、運作流程、涉及程式及資料表等。
這邊介紹方法以Go為主,但其它語言也可。
開始之前
找到熟悉專案的人可省下大筆自己摸索的時間,像是資深工程師及產品經理。例如詢問功能作用、變數值來源、配置檔位置、資料庫來源及整體架構等。事先有熟稔專案程式碼的人介紹可讓自己更快速地了解架構。
找找看是否有參考文件,例如流程圖、架構圖、規格書等,這些都可以幫助對追蹤程式碼的理解。
要追蹤程式碼的專案最好是可運作/執行的,需要時才可用IDE的debug模式來協助追蹤。
進入點
第一步先找到程式進入點,進入點是指要追蹤的程式開始執行的地方,以系統來說通常是main方法,以API來說通常是一個controller/handler的函式。
筆記
人腦記憶體沒那麼大,程式碼一多往往會忘了之前走過了哪,所以透過筆記可幫助自己定位目前在程式碼中的位置。
做筆記只需記錄重要的地方,通常是方法的呼叫的敘述,或重要的判斷式等,只需記下想了解的功能的相關部分即可,旁枝末節不用紀錄。
由於程式持續進版,所以筆記會標注追蹤程式碼的commit hash或tag。
下面是我追蹤程式碼的筆記方法:
[filepath]
為原始碼在專案的檔案路徑。[line number]
為程式碼在原始碼檔的行號。[function]
為函式/方法名稱,方法前包括類別名稱,有需要時會包括傳入的參數(signature),直接從原始碼複製貼上。[statement]
為一方法中的一行程式敘述(statement),直接從原始碼複製貼上;
[filepath] // the filepath from project source root
[line number]:[function] // includes static function and class method, and signature if needed
[line number]:[statement] // a statement of the function
[line number]:// sql: select * from ...
[line number]:[statement] // a statement of the function, call another function in another file
[filepath] // indent the called function's filepath
[line number]:[function]
[line number]:[statement]
...
[line number]:// call API http://...
[line number]:[statement] // return statement
[line number]:[statement]
除了以上有需要時會在後面以註解方式說明,有時也會在[statement]的前後加上一些標註例如交易開始與結束// transaction
,for迴圈範圍// for loop
,或直接以註解說明某一行在做什麼,例如呼叫API,或一段SQL script。
下面是追蹤一隻查詢員工資料的筆記範例,你可能會覺得和IDE的程式碼差不多幹嘛多此一舉,但差別在於筆記是去蕪存菁還有註記,藉此可更清楚程式流程的脈絡。
// demo-app GET /employee/{id}
/internal/handler/employee.go
80:GetEmployeehandler.Handle
84:resp, err := h.usecase.Do(ctx, id)
/interal/application/usecase/employee/query.go
42:GetEmployeeUseCase.Do(ctx context.Context, id string)
43:emp, err := uc.employeeRepo.GetEmployeeById(ctx, id)
/internal/infra/repo/employee.go
48:EmployeeRepo.GetEmployeeById(ctx context.Context, id string)
50:// gorm: select * from employee where id = ?
125:return result.Data, nil
83:return resp, nil
90:c.JSON(http.StatusOK, &resp)
畫圖
程式追蹤完後再把筆記結果用模型繪圖工具(e.g. draw.io(diagram.net))畫成流程圖,但不是標準的sequence diagram而是自己的格式如下,基本上就是筆記的再抽象。
畫完圖的同時差不多也算是份文件了,也方便日後自己參考。寫筆記和畫圖一定會比單純看要花多點時間,但價值是有紀錄及文件的產出。
感謝分享。 其實平常也有自己筆記的方式。但看了這篇後發現自己的盲點,及更簡潔的筆記方式。
回覆刪除太神了, 感謝豬大分享, 以後挖糞就更有效率惹
回覆刪除最近在追蹤比較複雜的架構很頭痛
回覆刪除我紀錄的方法沒有很完善,寫到一半才覺得筆記很雜亂
想請問畫圖的時候有需要把重要的判斷條件寫上去嗎?還是著重呼叫的 function 流程就好?
@SAI 筆記是自由的,所以沒有限定。如果那個判斷很重要,是你現在追蹤的業務流程中的關鍵邏輯,那我就會把他畫上去,如果是無關緊要的判斷,那就可以省略。如果那個判斷邏輯影響後續呼叫的流程或實作差異很大,那我會針對該判斷的每一個usecase畫一份,雖然這樣可能會花比較多時間,但圖像會變得清晰明確。
回覆刪除@Matt 謝謝您的建議,我再拿捏一下什麼是應該要被筆記的,例如「關鍵邏輯」的定義是什麼之類的。
回覆刪除不然不小心就會全部流程都很詳細記錄xDDD