一次早晨的 QQ 技術答疑,意外記錄下資深工程師「肖舸」對初學者的幾輪引導。對話雖短,卻濃縮了從「寫出能跑的代碼」到「寫出可維護、可賺錢的產品代碼」的核心心法。本文整理對話精華,提煉五大職業化設計原則。
malloc() 首次調用時才初始化 std::vector<Block*> blocks,而非建構函數。肖舸:我們對於類嵌套的成員對象,一般都是用指標,然後顯式在函數中去 new。實做中幾乎不會聲明成員對象實體,因為會引發非常多的額外問題。我們習慣於自己控制一切,很少使用 C++ 默認的建構和析構動作。
std::unique_ptr/std::shared_ptr + std::make_unique,兼具顯式控制與异常安全。肖舸:定義 API 名稱時,應盡可能符合「常識」。
MemFree(&p)要求傳指標的指標雖能置 NULL,但違背free(p)慣例,極易誤用。
| 反模式 | 職業化做法 | 理由 |
|---|---|---|
MemFree(void**) | MemFree(void*) + 文檔規範「釋放後調用者自行置 NULL」 | 符合 C/C++ 生態慣性,降低認知負荷 |
malloc/free 命名不一致 | m_alloc / m_free 或 mem_alloc / mem_free | 前綴統一,IDE 自動補全友好 |
肖舸:根據現代分布式計算理論,動態類查詢在實際中會有很多辦法規避掉……建議不要鑽這個牛角尖,費力氣很大,對於賺錢沒幫助。
對話中提到的「字串實例化」需求,最終被導向「配置驅動 + 靜態工廠映射表」或「微服務註冊發現」,而非 C++ 模板元程式重造輪子。
肖舸:情願多浪費電腦資源,不要浪費程式員的腦力。你絞盡腦汁節約了 3~4 個中間變量,大約節約了 12~16 Bytes。現在的電腦,記憶體起步就是 2G,有意義嗎?反而,如果中間有一個隱蔽的 bug,查錯誤可能要半個月,你半個月的工資能再買台電腦了。
devices.[has(child)?this:void]?.[*.contains(module)?void:module] 這類「一行寫兩層循環」的語法糖,除錯時幾乎無法打斷點、無法觀察中間值。bool cpu_ok = (usage < 85); if (cpu_ok) ... 比 if (usage < 85) ... 更能表達業務意圖。肖舸:永遠不要相信編譯器,它不知道你的需求。把動作拆細,你就會發現很多優化要點。……如果集合夠大,比如幾萬個,你這麼寫,怎麼知道編譯器內部使用什麼演算法來實現查找?如果我來控制,我可以配搭兩個 Hash,一步到位實現高速檢索。
// 網友版:隱式雙層循環,演算法不透明
devices.filter(...).map(...)
// 肖舸版:顯式雙 Hash,O(1) 查找
unordered_map by_id;
unordered_map> by_module;
// 精確控制資料結構與存取路徑
| 學院派/初階特徵 | 職業化/資深特徵 |
|---|---|
| 追求語法花俏、一行解決問題 | 大白話、多寫幾行、人人可讀 |
| 依賴隱式機制 (建構順序、RAII 魔法、編譯器優化) | 顯式控制生命週期、資料結構、演算法 |
| 為了技術而技術 (動態反射、模板元程式、COW 字串) | 為了業務價值選技術、算經濟帳、可替代方案 |
| 單線程思維、記憶體稀缺假設 | 預設併發、硬體豐富、人力稀缺 |
對話結尾,網友說:「在技術上,在賺錢上,都好好消化消化。」這或許是從「碼農」走向「工程師」的關鍵一步。
來源:肖舸的 blog