【舊文搬家】
本文的起源是因?yàn)樗伎家粋€(gè)問(wèn)題,什么樣的人適合做程序員。
我曾經(jīng)苦惱得思考著這個(gè)問(wèn)題,直到我在SICP上看到了答案。說(shuō)的白話(huà)一點(diǎn)就是,能像機(jī)器一樣思考的人就適合做程序員。
那么計(jì)算機(jī)這臺(tái)機(jī)器是怎么思考的呢?這里是我的答案:
我們所有的計(jì)算機(jī),都是下面這個(gè)模型,江湖人稱(chēng)“馮?諾伊曼體系”

從這個(gè)模型上我們看到了什么嗎?嗯,可能太多噪音了,看的不夠清楚,我給你們?cè)俪橄笠粚樱?/p>

現(xiàn)在清楚了吧,計(jì)算機(jī)在中間,兩邊是輸出輸出。所有的問(wèn)題都從輸入和輸出的角度去思考,這就是計(jì)算機(jī)這臺(tái)機(jī)器的思考方式。也就是說(shuō)你能做到這樣思考,你就會(huì)像機(jī)器一樣思考了。
很簡(jiǎn)單吧,但是新的問(wèn)題又產(chǎn)生了,處理自然要處理輸入產(chǎn)生輸出了。輸入,輸出是些什么呢?這就要在微觀層面理解機(jī)器是怎么思考的,這一部分叫,機(jī)器在加工什么?
SICP中又說(shuō)了,非形式的講,我們只在處理兩種東西,數(shù)據(jù)和過(guò)程,他們還不是嚴(yán)格區(qū)分的。
先不管不嚴(yán)格區(qū)分那半句,我們回看我們的模型,中間處理的部分其實(shí)就是過(guò)程,輸入和輸出其實(shí)就是數(shù)據(jù)。(在馮諾伊曼體系里,數(shù)據(jù)和過(guò)程被稱(chēng)之為數(shù)據(jù)和指令)那說(shuō)到數(shù)據(jù),我們有一門(mén)學(xué)科叫做數(shù)據(jù)結(jié)構(gòu),它很好的表達(dá)了什么是數(shù)據(jù)。我們還有面向?qū)ο?,?lèi)型系統(tǒng)之類(lèi)的知識(shí),他們都會(huì)幫助我們很好的定義數(shù)據(jù)。
各位看官估計(jì)心里犯嘀咕了,扯了這么多,還是無(wú)法想象怎么就算像機(jī)器一樣思考了???不急,下面我們拿幾個(gè)例子來(lái)學(xué)習(xí)一下。
我們來(lái)寫(xiě)一個(gè)加法函數(shù),接受兩個(gè)參數(shù)作為加數(shù)和被加數(shù),返回一個(gè)和,這個(gè)太簡(jiǎn)單了,幾乎任何一個(gè)程序員都可以在幾秒鐘內(nèi)寫(xiě)完。拆成機(jī)器的思維是什么樣呢?
加法函數(shù)
輸入:
a
b
輸出:
result
大概就長(zhǎng)這樣,輸入是a和b,輸出是一個(gè)結(jié)果,我們起名叫result。它到底表達(dá)了個(gè)啥樣的代碼呢?大概長(zhǎng)這樣:(本文所有的代碼都會(huì)采用javascript描述,但是不代表本文內(nèi)容只適合描述前端開(kāi)發(fā))
function add(a, b) {
return a + b;
}
咦?result哪去了?在你調(diào)用的地方可能會(huì)有一行代碼 var result = add(1,2);
這個(gè)表達(dá)方式不僅僅可以用來(lái)描述函數(shù)定義,用來(lái)描述表達(dá)式也是可以的。比如,如果我們把前面的輸入輸出思維描述改為加法表達(dá)式。你會(huì)發(fā)現(xiàn)其實(shí)這段描述“編譯”成代碼大概長(zhǎng)這樣:
var result = a + b;
所以不僅僅可以用來(lái)描述函數(shù)定義,還可以描述代碼塊。
但是到這里就結(jié)束了嗎?感覺(jué)好像對(duì)數(shù)據(jù)的表述不夠細(xì)致啊。確實(shí),我們忘了加類(lèi)型了。不加類(lèi)型這描述簡(jiǎn)直萬(wàn)靈丹么,反正倆參數(shù)一個(gè)返回值的都能用,這不行,我們還得把類(lèi)型加上看著才清楚點(diǎn)。加上類(lèi)型就變成了這樣:
加法函數(shù)
輸入:
a: Number
b: Number
輸出:
result: Number
這看著就好多了,是不是比剛才理解上文所講的像機(jī)器一樣思考了呢?好吧,你可能會(huì)說(shuō),這玩意有啥用啊,我有分析的這個(gè)空,我代碼都寫(xiě)完了啊。不急,我們接著往后看。
剛才那個(gè)題目有點(diǎn)太簡(jiǎn)單了,我們做一個(gè)稍微復(fù)雜的。比如下面這個(gè):寫(xiě)一個(gè)函數(shù),可以選出一個(gè)由數(shù)字組成的集合當(dāng)中所有的偶數(shù)的最大值。
這回一步做出來(lái)可能就有點(diǎn)難了,沒(méi)關(guān)系,我們可以成兩步:
- 選出集合中的偶數(shù)
- 選出偶數(shù)中的最大值
這兩步呢,按照我們之前的格式寫(xiě)一下,大概是下面這個(gè)樣子:
#1 選出集合中的偶數(shù)
輸入:
inputArray
輸出:
evenArray
#2 選出偶數(shù)中的最大值
輸入:
evenArray
輸出:
max:Number
哎呀,突然發(fā)覺(jué)不知道該怎么描述集合呢。Javascript里就用數(shù)組就好了,但是還是不知道怎么描述數(shù)組啊。這個(gè)其實(shí)很簡(jiǎn)單,這不是一個(gè)由數(shù)字組成的數(shù)組嗎?我們只要寫(xiě)成[Number]就可以了。因?yàn)槲覀兊囊粋€(gè)好習(xí)慣是一個(gè)集合里不要放兩種類(lèi)型的元素,所以就這么寫(xiě)就好了。那么加上去的話(huà),大概就長(zhǎng)這樣:
#1 選出集合中的偶數(shù)
輸入:
inputArray: [Number]
輸出:
evenArray: [Number]
#2 選出偶數(shù)中的最大值
輸入:
evenArray
輸出:
max: Number
咦,第二步的evenArray沒(méi)有寫(xiě)類(lèi)型。嗯,因?yàn)閑venArray是第一步的輸出,我就把它省了,相信大家也能看明白。
耐著性子看到這里,你估計(jì)已經(jīng)發(fā)現(xiàn)了,我還是沒(méi)有回答你這個(gè)思維方式有什么用這個(gè)問(wèn)題。我很想忽悠著你再做一道題,不過(guò)估計(jì)你堅(jiān)持不完就會(huì)轉(zhuǎn)身離開(kāi)了。那我們就這兩道題試著講一講。
第一道題,我們只是展示了這個(gè)思維,第二道題,我們才開(kāi)始使用到它的威力。盡管這道題也不復(fù)雜,但是思考過(guò)程還是展示了:
- 分解問(wèn)題
- 找到子問(wèn)題之間的關(guān)聯(lián)(通過(guò)輸入輸出關(guān)聯(lián)起來(lái))
- 找到問(wèn)題的邊界,明確假設(shè)與結(jié)果
上述三點(diǎn)看著簡(jiǎn)單,卻是思維清楚與否的關(guān)鍵。我們管這個(gè)能力叫Analytical Thinking。
思維清楚帶來(lái)的收益是什么?這些步驟可以直接轉(zhuǎn)化為工作的任務(wù)列表,而且可測(cè)試。這樣分解出來(lái)的任務(wù)列表,完成效率是極高的。我們?cè)?jīng)做過(guò)實(shí)驗(yàn),按這個(gè)思路分解過(guò)的人,比沒(méi)有分解過(guò)的人,完成效率可以高3倍以上,而且前者只學(xué)了一周的編程。
一個(gè)完全不會(huì)寫(xiě)程序的人,只要學(xué)會(huì)了這個(gè)思維,就可以開(kāi)始編程之旅了,而且威力非常巨大。
聽(tīng)起來(lái)好簡(jiǎn)單啊,有那么神嗎?不是編程的人都應(yīng)該會(huì)嗎?然而并不是的,很多人思考編程這件事情是靠感覺(jué)的。
我前幾天面了40多個(gè)外包公司外派來(lái)的人,只有5個(gè)人,可以按照輸入輸出來(lái)對(duì)問(wèn)題進(jìn)行分解。所以我覺(jué)得我還是有必要寫(xiě)點(diǎn)東西來(lái)講講這個(gè)。
除了對(duì)初學(xué)者有益之外,對(duì)Team Lead也是有益的。當(dāng)你覺(jué)得你遇到的人沒(méi)sense的時(shí)候,你可以試著讓他們這么表達(dá)一下程序。一般就會(huì)發(fā)現(xiàn)一些問(wèn)題。
題外話(huà)
題外話(huà)-1:
我們像機(jī)器一樣思考,不就都變成機(jī)器了嗎?嗯,其實(shí)不是的。所謂我們像機(jī)器一樣思考,那機(jī)器這種思考方式又是從哪里來(lái)的呢?機(jī)器的思考模型是一個(gè)叫“圖靈機(jī)”的計(jì)算模型,而圖靈機(jī)則是圖靈祖師爺模擬人思考而發(fā)明出來(lái)的。所以,其實(shí)不存在什么像機(jī)器一樣思考,只不過(guò)是學(xué)會(huì)一種人類(lèi)的思考方式而已。
考慮到圖靈只能以自己和自己周?chē)奶觳趴茖W(xué)家的作為人類(lèi)的具體實(shí)例來(lái)抽象圖靈機(jī),所以我們學(xué)習(xí)的其實(shí)不是什么機(jī)器的思考方式,而是天才的思考方式,這篇文章其實(shí)應(yīng)該叫《像天才一樣思考》。
題外話(huà)-2:
這個(gè)不就是面向過(guò)程編程嗎?如果的思考僅僅停在這里,那就是面向過(guò)程編程了。如果我們接著想下去,當(dāng)數(shù)據(jù)復(fù)雜到一定程度的時(shí)候,我們會(huì)自然的引入封裝,于是面向?qū)ο笳Q生了?;氐綌?shù)據(jù)與過(guò)程不嚴(yán)格區(qū)分那半句,當(dāng)我們?cè)噲D模糊數(shù)據(jù)和過(guò)程的界限,將過(guò)程像數(shù)據(jù)一樣納入輸入輸出的范疇,我們就走上了函數(shù)式編程之路。
題外話(huà)-3:
有人覺(jué)得練習(xí)不夠嗎?請(qǐng)留言,如果感興趣的人多,我就加緊寫(xiě)更多練習(xí)的解析。
相關(guān)文章:
像機(jī)器一樣思考(二)—— 數(shù)據(jù)的細(xì)節(jié)
像機(jī)器一樣思考(三)—— 窮盡就是力量
像機(jī)器一樣思考(四)—— 一圖抵千言
像機(jī)器一樣思考(五)—— 第一個(gè)應(yīng)用
像機(jī)器一樣思考(六) —— 腦中的重構(gòu)
像機(jī)器一樣思考(七) —— 跨應(yīng)用思考