做者簡介linux
近鐵Jeff Dean, 餓了麼物流研發部搬磚工, 崇拜各類大牛, 因爲Jeff Dean的做品深而廣, 本文特地專一於小而美的Linus Torvalds 第二做品:Git, 但願從中汲取養分, 向大師致敬。git
文介紹Git核心優勢和實現思路,重點引伸出對業務系統設計與開發的啓示; 因爲篇幅有限,本文不詳細介紹Git命令的具體執行細節,若是須要了解執行Git命令時,底層具體發生了什麼, 請移步Git官方文檔第十章 Git Internals。程序員
Git做爲一個前無古人,極可能後無來者的內容地址跟蹤器 , 席捲各大公司,深受全部程序員喜好(以爲Git難用的除外), 確定有他的過人之處。github
先搬出互聯網技術關鍵詞標配:redis
分佈式、去中心化、可靠性、容錯性、可用性、數據一致性、性能是一個功能, 而不是一個優化等。算法
Git都知足有木有! Linus用兩週就實現自舉的Git十幾年後依然健壯如初。 假如我寫一個接口或設計一個微服務或寫一個小工具, 自帶擴展技能,歷來不掛,QPS暴增也無需推翻重構,外部依賴抖動時自動降級,數據量增大而沒有拖垮性能, 能與Git有不少共同點,豈不頗有成就感?編程
分佈式:1)多人同一個分支不一樣地點不一樣時間並行開發;2)單人本地多分支並行開發。api
性能: 速度要快。慢是Linus Torvalds本人沒法接受的,由於linux內核天天有成百上千次提交。緩存
安全與信任: 便可靠性, 我push上去的代碼pull下來必定仍是個人代碼, 沒有丟失或被惡意篡改過。安全
插播一條語錄: Bad programmers worry about the code. Good programmers worry about data structures and their relationships. - by Linus Torvarlds. (通常的程序員只關心代碼,而優秀的軟件工程師更關心數據結構以及他們之間的關係。)
Linus本人寫C語言比較多,我的認爲這裏的data structures and their relationships 若是脫離C語言 的特定背景,能夠泛指技術對場景或業務邏輯的抽象, 好比: 面向對象建模,領域驅動, 甚至更宏觀的架構設計或微服務怎樣劃分。
根據我的經驗,若是系統設計的好, 代碼稍微寫low一點,整個系統的表現也不會太差, 並且代碼的坑比較容易填; 反之,再漂亮的代碼也很難填上系統設計的坑, 只能面臨重構。
對於Git內部結構能夠簡單的理解爲: Git內部是一棵 樹, 每一個節點都是一個指針(key), 這個指針(key)可能表明一個文件,或一次commit或一個分支起點或一次merge或一個tag, key對應的value就是內容, 若是key是表明一個文件, value就是文件內容; 若是key是表明一次commit, value是一顆子樹, 包含這次commit對整個項目的snapshot。
平時不少git操做均可以近似理解爲: 在樹上執行遍歷查找O(lg(n)),切換指針O(1),而後根據指針取文件內容O(1))。 這些操做速度都是很快的,只有在網絡交互,文件壓縮與解壓和計算diff時,人肉能夠感知到有時間等待。
對於Git,近期發生變化的數據屬於熱數據,Git假設這些數據會被頻繁訪問或使用到。其餘數據爲歷史數據。 對於熱數據, 即便發生微小變化,Git也會全量冗餘存儲,提升訪問效率。 當熱數據文件數量達到必定值時,會觸發打包壓縮邏輯, delta差別存儲,節省空間。
對於不一樣的存儲介質,例如db, redis, mq, 選用不一樣的存儲邏輯或策略,以達到訪問效率與存儲空間的平衡。
Git對文件內容和項目總體snapshot都使用hash值表示,hash值與內容一一對應, 若是文件內容被篡改或硬盤損壞 致使數據丟失,hash值校驗都會失敗。 此時Git設計時已經假設:
在分佈式環境下,設計系統或接口,可否保持容錯性,自帶降級,建議多向本身提出假設:
先找出兩個分支的公共祖先, 而後兩個分支分別與公共祖先diff,指出有衝突的地方。 Git merge並無試圖智能的去解決衝突,只是指出衝突,而後將merge交給最合適最高效的人去解決: 即引發衝突的開發者。
通常的代碼, 用if else 判斷邊界值:
void remove_list_entry(entry) {
prev = NULL;
walk = head;
// Walk the list
while (walk != entry){
prev = walk;
walk = walk->next;
}
//Remove the entry by updating the
//head or the previous entry
if(!prev)
head = entry->next;
else
prev->next = entry->next;
}
複製代碼
好的代碼, 換一種寫法,使正常處理邏輯能夠兼容邊界值:
void remove_list_entry(entry) {
//The "indirect" pointer points to the
// *address* of the thing we'll update
indirect = &head;
//Walk the list,looking for the thing that
//points to the entry we want to remove
while ((*indirect) != entry)
indirect = &(*indirect)->next;
// .. and just remove it
*indirect = entry->next
}
複製代碼
平時編碼中對邊界值的處理是否優雅?
如今一個變量的傳遞會通過多種編程語言和中間件,中間過程通常有序列化和反序列化, 給空對象賦默認值等邏輯, 怎樣保證明際結果與預想的徹底一致? 邊界值處理很差,一是代碼很差維護,二是容易引入Bug。 平常碰到的邊界值有: null, int默認值0等。
(以下爲Linus Torvalds語錄,僅供娛樂。 Linus Torvalds以噴人聞名,網絡上不少人指責他人品不行, 不多有人評價他的技術水平,多是沒有能力評價吧。)
閱讀博客還不過癮?
歡迎你們掃二維碼經過添加羣助手,加入交流羣,討論和博客有關的技術問題,還能夠和博主有更多互動
博客轉載、線下活動及合做等問題請郵件至 shadowfly_zyl@hotmail.com 進行溝通