原文地址: http://michael-j.net/2017/09/24/%E7%BC%96%E7%A8%8B%E5%BF%83%E6%99%BA-%E4%B8%80-%E2%80%94%E2%80%94%E4%BB%A3%E7%A0%81%E6%9E%B6%E6%9E%84%E4%B8%8E%E ...
原文地址: http://michael-j.net/2017/09/24/%E7%BC%96%E7%A8%8B%E5%BF%83%E6%99%BA-%E4%B8%80-%E2%80%94%E2%80%94%E4%BB%A3%E7%A0%81%E6%9E%B6%E6%9E%84%E4%B8%8E%E7%B3%BB%E7%BB%9F%E6%9E%B6%E6%9E%84/
寫在開頭的話
想寫這個系列文章很久了,但是對於一個重度的拖延症患者來說,決定寫一個系列文章還是頗有挑戰。最開始,只想寫一兩片文章分享一下自己對於編程的感悟。但隨著時間越拖越久,發現想寫的東西越來越多。直到今天,居然發現我的博客的To-Do-List(目前我在使用WunderList
,很好用的一個To-Do-List工具)文章數達到了10篇,終於說服自己動筆了。
“編程心智”這個詞這段時間一直縈繞在我的腦海中,我覺得這個詞最能表達我想分享了內容了。我希望通過這個系列文章分享自己對於代碼、編程、架構以及軟體工程的理解與感悟,另外,還有隱藏在代碼後面的程式員心智。所有文章僅代表個人觀點,沒有是非對錯的標準。如果你對文章中的觀點不認同,還請給我留言,不同的聲音對於進步有著極大的促進。
選擇“代碼架構與系統架構”作為第一篇文章是因為我發現很多人對“架構”的誤解很深,而且國內關於“代碼架構”的分享和書籍鳳毛麟角,似乎只有流弊的“系統架構”才能成為談資。我不太能理解這個現象,好像大部分人都完全不用操心“如何寫好代碼”這回事,似乎只要有一個看上去比較“完美”的系統架構就能解決所有的事情。但根據我的實際經驗,現實情況往往不是這樣,有時候甚至相反。有些項目的系統架構圖畫的非常“漂亮”,引入了很多新潮的技術,每個組件都劃分的很清楚,系統之間如何通信,模塊之間如何引用等等都一目瞭然。但是當你去看項目的真實代碼時,完全是另外一番景象。至於為什麼會這樣,我想很大一部分原因是“系統架構圖”已經淪為了一種滿足KPI考核手段,而通常你的老闆不會深入地去理解你的代碼,更不要說指出其中的問題了。
系統架構
相信很多人對系統架構都不陌生,只要是從事軟體開發領域的人,或多或少都接觸過系統架構。系統架構最直觀的表現就是系統架構圖,下圖就是一張系統架構圖,摘自李智慧老師大型網站技術架構:核心原理與案例分析。
系統架構是一個比較大的概念,從技術角度來看,它往往以部署架構圖的形式出現(上圖就是);而換到業務視圖,它又以另外一種形式出現,如下圖。
不論是部署架構圖還是業務架構圖,它們都反映了系統與系統之間的一種關聯關係,從更加巨集觀的角度反映系統在全局中的作用和定位。如果你是某個系統的開發者或者負責人,那麼你的系統會在系統架構圖中以一個方框出現。通過系統架構圖,你的老闆和同事能很直觀地瞭解到你的系統在全局中的位置以及你服務的層次。這樣做有好處的,它降低了技術人員之間以及技術和業務人員之間地溝通成本。
實際上,關於系統採用什麼樣的中間件、何種資料庫和緩存、選用哪種服務框架等等,甚至今年非常火的微服務架構,這些統統都屬於系統架構的範疇。關於系統架構方面的書籍和文章已經非常多了,而且國內的分享也主要集中於此,我就不再這方面展開了。
代碼架構
相比於系統架構,代碼架構對很多人可能就陌生許多。我剛剛去Google一下,發現甚至沒有關於“代碼架構”的權威定義。那麼什麼是代碼架構呢?打個比方,如果你的系統在系統架構圖中只是一個方框,那麼代碼架構就是介紹這個方框是如何組成和實現的。代碼架構的關註點在一個工程(Project)內部,它描述了你的整個工程代碼是如何組織和實現的。簡而言之,系統架構是巨集觀層面的體現,而代碼架構是微觀層面的體現。
在我的博客中有很多關於DDD的文章,而DDD本身就是一種代碼架構。除此之外,還有MVC、CQRS、Event Souring等等。那麼,設計模式是否也可以成為代碼架構呢?在某種程度上是的,因為它可以指導你如何組織代碼的實現,如何在代碼層面解耦,但是,光光通過設計模式你無法組織起你的整個工程代碼,所以從嚴格意義上講,設計模式並不是一種代碼架構。代碼架構也可以通過圖文的形式表現,不過這完全取決於你採用何種代碼架構。下圖是我目前負責的一個系統的代碼架構,這個系統的核心在於策略語言(Policy)。
熟悉DDD的人一眼就可以看出來這是DDD種的經典六邊形架構(題外話,至今我不太明白為什麼是六邊形)。如果你的工程採用MVC或者CQRS架構進行組織,可能會畫出完全不一樣的架構圖。我很慶幸,在我正式的職業編程生涯的早期接觸到了DDD這種編程思想,它對我的編程生涯影響很大,讓我少走了很多彎路。如果你還沒有接觸過DDD,我希望你能立馬買一本Eric Evans
的領域驅動設計:軟體核心複雜性應對之道,細細研讀此書,字裡行間都體現著作者對軟體開發的深刻理解。
為什麼我說代碼架構是如此的重要?是因為其奠定了大型系統的基石。我認為衡量一個優秀的程式員的能力之一就包含其對複雜問題的解決能力。現實的問題往往比理論複雜很多,很多時候需要妥協、折中、權衡和取捨,如何在這些取捨之中不影響到軟體的核心,這需要大量的經驗。當然,這是有規律可循的,那就是代碼架構。
好的代碼架構會幫助你理解你的業務,哪些部分是你系統的核心,哪些部分只是技術層面的實現。換句話說,好的代碼架構不光能知道你如何去組織你的代碼,還能加深你對系統的理解。反過來,隨著你對系統理解的不斷深入,你又能更好的調整你的代碼以適應新的變化。是不是所有的項目都需要代碼架構呢?這取決於你的問題域。如果你的項目僅僅是一個Hello World
程式,又或者是一個數據採集腳步,那麼使用代碼架構來組織代碼可能沒什麼作用,反而使得你的代碼變得更加複雜和臃腫。那麼什麼情況下你需要使用代碼架構呢?我認為只要滿足以下兩個條件就行。
-
你有一個相對固定的業務場景。固定意味著你要處理的問題域是有邊界的,比如訂單系統、庫存系統、用戶中心等等,它們所要處理的問題是比較集中和固定的。
-
你要解決的問題相對比較複雜。這看上去本身就比較矛盾,因為“複雜”本身就是相對的。這裡的複雜的意義在於,你要處理的問題領域本身就具有複雜性。也許起初問題本身並不複雜,但隨著時間的推移,系統要處理的問題也越來越複雜了,這要求你對問題有一定的前瞻性。
事實上,上面兩個條件是很容易滿足,之所以還列出來因為在實際的開發過程中,我確實遇到過在以上兩點犯錯的情況。這主要出現在剛剛開始正式編程生涯的畢業生,他們對業務和要做的事理解程度不夠,如果有經驗豐富的程式員帶的話,可以避免走一些彎路。正是因為上訴條件門檻較低,所以代碼架構的應用場景非常廣泛。有可能你現在的項目就在使用MVC架構,只是你沒有意思到。我建議程式員能有意識地去瞭解你的代碼架構,深入的思考一下目前的代碼組織方式是最為合理的嗎?
小結
說了這麼多,希望自己把代碼架構和系統架構的核心點說明白了。兩者都非常地重要,但是應用的場景各不相同,兩者結合使用才能讓你做出一個高質量的系統。相比於系統架構,代碼架構往往被人們所遺留,但這並不代表其不重要。依我之見,代碼架構的應用場景更為廣泛,因為大部分的公司和項目其實並不需要一個複雜和“高大上”的系統架構,而與我們日常交互最多的就是一行一行的代碼。深入的瞭解你的項目代碼是如何組織對程式員來說是十分重要的,好的代碼架構能起到事半功倍的效果。最後,個人建議將代碼架構納入到KPI的評判之中,最為直觀的表現就是“技術債務”。好的代碼架構會把項目的技術債務維持在一個比較低的水平;相反,糟糕的代碼結構會讓項目的“技術債務”越滾越大,最終到了不可收拾的程度。不過,技術債務如何量化,以及是否需要量化,目前這方面有著很多不同的身影,但是,能意識到這個問題的存在,至少,我們在向高水平的軟體開發者邁出了一大步。
寫在最後的話
編程心智這個系列我會持續地更新,但更新時間就不確定了。前面也說了,我是一個重度的拖延症患者,而且,最近項目的事情很多,一個接著一個。我會努力做到一個月一篇的。