一個程序員的讀書筆記--關(guān)于程序設(shè)計的反思
剛開始編程的時候是在高中,那個時候計算機課上老師教的是pascal。一種典型的面相過程的語言。那個時候懵懵懂懂的認為:程序還是一個蠻神奇的東西,敲幾個英文字符進去,就能夠有反饋。即使這個反饋只是非常簡單的輸出了一個“Hello World!”。
而大學開始比較系統(tǒng)的學習計算機這個東西。但是現(xiàn)在回想起來,貌似沒有系統(tǒng)的學過程序設(shè)計這個東西啊。即使上了很多叫做《XXX程序設(shè)計》的課程之后,對于程序設(shè)計這個東西還是有種霧里看花的感覺。而且學的都是像匯編了,C了這樣的一些比較底層的語言。主要是語法吧,設(shè)計層面的東西真的很少。造成很長一段時間內(nèi),我對程序設(shè)計的認知停留在高中pascal的水平,程序設(shè)計就是你輸入個東西,然后設(shè)計一系列串行的邏輯,然后等著輸出。
后來上了一個叫做《C++面向?qū)ο笤O(shè)計》的課,在上課之前以為這是一個高大上的課程,結(jié)果到最后老師把c++講成了一個好用的c,比c優(yōu)秀的地方主要就是在加了一些支持面向?qū)ο蟮恼Z法?,F(xiàn)在回想一下,那些叫做《XXX程序設(shè)計》的課程,基本上都是一些語言課程,貌似和程序“設(shè)計”這個東西有點不著邊際。而也能夠讓我,對于“面向?qū)ο?rdquo;或者“面相過程”構(gòu)建起基本的概念。
我在寫程序的時候,更多還是停留在pascal那個層次中。串行的邏輯。那個時候的夢想就是能夠讀完knuth四卷本的《The Art of program》還有他為這本書寫的輔導書《基本數(shù)學》。因為大家在程序=數(shù)據(jù)結(jié)構(gòu)+算法的世界觀中,這幾本書如同圣經(jīng)。最后花了大概四五年吧,只讀了第一卷的300多頁。好吧,貌似我不是一個很虔誠的信徒。
有幸的是,大二開始跟著一個老師給他們當碼農(nóng),敲代碼。就這樣稀里糊涂,斷斷續(xù)續(xù)的以一個碼農(nóng)的角色在他們的項目中敲敲打打。那時作為一個新手,得到最多的就是“埋汰”。他們看著你寫的c或者c++代碼,說這個太不優(yōu)雅了。當時,我就想:靠,就是一串代碼,又不是什么畫,還能用優(yōu)雅來形容啊。之后,他們開始說一些設(shè)計模式了之類如同天書的東西。大三下班學期的時候,有個哥們在搞magic linux的安裝程序的重構(gòu)。我就聽著他天天在和我白活寫第一版安裝程序的是如何如何牛逼哄哄的。模塊劃分的多么多么清晰,模塊間通信竟然都是用的xml。設(shè)計的可擴展性多么多么好,模塊間高耦合地內(nèi)聚了。。。。當時就覺得,靠,真的很牛逼啊。用現(xiàn)在的一個詞就是:不覺明歷。不過當然,得向牛逼的人學習。于是買了本c++版的《設(shè)計模式》,就是最經(jīng)典的那本。記得那個時候,讀起來,略覺生澀。很多概念都是囫圇吞棗的咽下去了。在以后的編程中,也能偶爾用用什么觀察者了,單例了之類的模式。偶爾,能夠針對一些問題提出一些看似非常符合設(shè)計模式的“設(shè)計”。
在接觸到設(shè)計模式并能夠稍微懂點的時間內(nèi),以為面向?qū)ο筮@個東西的主要內(nèi)容就是“設(shè)計模式”了吧。你看用了設(shè)計模式之后,腿也不酸了,要也不疼了,一口氣能上十層樓了。寫代碼也開始有點那種玄乎的“優(yōu)雅”的感覺了。切以為自己在碼農(nóng)這個職業(yè)上已經(jīng)算是入門了。直到有一天看了一本叫做《敏捷開發(fā)》的書,才猛然間驚醒。他媽的,在設(shè)計模式之上還有六大原則:單一職責、里氏替換、開閉原則、迪米特法則、接口隔離原則、依賴倒置原則。原來設(shè)計模式被設(shè)計出來的時候也是按照一定的指導原則的,那就是六大原則。好吧,現(xiàn)在我的面向?qū)ο蟪绦蛟O(shè)計的思想庫中又多了一批非常不錯的概念:六大原則。而且驚喜的發(fā)現(xiàn),隨著對這六個原則尤其是單一職責原則的深入理解。自己開始,能夠慢慢跳出原先那種刻意去使用設(shè)計模式的牢籠。開始去關(guān)注程序設(shè)計本身,或者說具體情況相關(guān)的東西。而不是為了設(shè)計去設(shè)計。這個時候,才開始慢慢的體會到其實程序設(shè)計這個東西真的并不是簡單的邏輯羅列,而是思想的結(jié)晶。是必須經(jīng)過深思熟慮之后,才能完成的事情。不再一聽到別人高談闊論高內(nèi)聚低耦合,就不覺明歷,開始嘗試著去思考他們所謂的高內(nèi)聚低耦合到底是個什么東西,用這個標準來評判一個面相對象的設(shè)計是否合適。這個面相過程的遺留品在面向?qū)ο蟮脑O(shè)計范疇內(nèi)到底能夠發(fā)揮多大的作用。漸漸的發(fā)現(xiàn),其實高內(nèi)聚低耦合和單一職責與迪米特法則是那么的貌離神合。講的都是我們一段代碼的職責一定要純粹,而且越純粹越好。不要染指其他代碼的職責。登陸的代碼就負責登陸,不需要管界面上的事情。界面上的代碼就負責展示內(nèi)容就好,不要負責業(yè)務(wù)邏輯。當能夠清晰的指出系統(tǒng)中每個模塊,每個類,甚至是每個函數(shù)那“單純”的職責的時候,那么整個系統(tǒng)應(yīng)該說是優(yōu)雅的了吧。
而這個時候,進行分析與設(shè)計的時候總是有種捉襟見肘的感覺,一個類的設(shè)計,甚至一個方法的定義與實現(xiàn)沒有什么規(guī)矩可言。有些時候從上面說的六大原則和設(shè)計模式入手,大概構(gòu)想出了軟件的模樣。但是到了一些編碼細節(jié)上的時候,總是有種力不從心的感覺。簡而言之,就是看手氣寫代碼。最終是否能夠真實的還原自己的設(shè)計,完全是個靠經(jīng)驗吃飯的事情。而比較悲劇的是,作為一個編程經(jīng)驗沒有十年二十年的人來說,這似乎有點不太靠譜。作為一個數(shù)學系的學生,那種定理情節(jié)油然而生。難道就沒有類似與定理一樣的東西能夠幫助我有效的還原設(shè)計,定義一個類,定義一個方法。于是又開始了狂看書的路程。
c++之父Bjarne Stroustrup的《The Design and Evolution Of C++》中一句話給了我方向:c++語言在眾多語言的角逐中能夠勝出,本質(zhì)上是一種哲學思想的勝利。乍一看可能認為是面向?qū)ο笤趯嵺`中戰(zhàn)勝了面相過程開始主導軟件開發(fā)語言。但是,當去仔細品味的時候,發(fā)現(xiàn)這種哲學思想是一種實用主義的思想。他以目標為導向,以最終效果為評判標準。中間所做的一切努力,都是為了達到最后的目標。就像面向?qū)ο笳Q生的時候,正是軟件規(guī)模不斷擴大,軟件復雜性已經(jīng)超出了人類可控制的范圍。人們急需要一種能夠合理的控制整個軟件復雜性的方法,于是就有了面向?qū)ο?。而復雜性控制這個概念是來自于軟件工程的東西。頓時你就覺得腦海中的很多概念開始高度重合面相對象、軟件工程、復雜性控制、面相過程。。。。。。。定理沒找到,反倒是燉了一鍋佛跳墻。七葷八素里面什么都有。
偶然的機會在WIKI上看到了一個詞——工具理性。才有點開始懵懵懂懂的覺得看到了一點曙光。原來一個Code Monkey廢了半天勁塞進腦瓜里的所有東西,都是工具而已。編程語言是工具;面向?qū)ο笤O(shè)計是工具;敏捷工程是工具。。。。我們只是合適的使用這些工具來完成目標而已?;腥淮笪?,其實根本就沒必要糾結(jié)于在編碼的時候用的是面向?qū)ο筮€是什么,沒有必要糾結(jié)用沒用設(shè)計模式,沒有必要糾結(jié)開發(fā)過程到底敏捷不敏捷。。。只要能夠?qū)崿F(xiàn)最終的目標就好了。只是實現(xiàn)目標的這個過程還是依舊曲折。如何選擇工具,并且如何有效的使用工具依舊是一個很重要的問題。但是已經(jīng)有了一個大概的能夠指引以后學習方向的思想——了解目標、了解工具,懂得如何合理而且有效的使用工具,并且Keep it simple。發(fā)現(xiàn)在程序設(shè)計這個事情上,真正難的不是你寫出了些什么東西,而是你沒有寫什么東西。難的不是你進行復雜的設(shè)計與編碼,而是盡可能少的設(shè)計和盡可能少的編碼。這有點像國畫中的留白,那些真正簡單的東西才是最復雜的東西。能夠把設(shè)計最到最簡才是真正的功力。一個Redis才幾千行代碼,sqlite也不過3w行左右的代碼。這兩個東西做的事情不可為不復雜,但是設(shè)計的人之功力可見一斑。
最后用一幅畫與大家共勉: