本文只提供給新手程序員閱讀。程序員
多年前的一個 IBM 的老鳥曾經教過我一個 5 分鐘上手的思惟習慣,當我聽到之後,醍醐灌頂,驚人天人,一改平常的編碼風格。到如今,它還持續保持在個人平常的編碼習慣當中。算法
我不知道應該怎麼稱呼這種思惟習慣的名字,top-down,自頂而下,或者分治?無論怎麼樣,它的核心是很是清晰的:編碼的時候只思考同一個思惟層次的邏輯,在這層完成以後再思考下一層。編程
它基於這麼一個事實:咱們每一個人智力是有限的,同一個時間只能思考有限內容的東西,咱們都不是天才。因爲這個事實的存在,因此程序 bug 就會存在(廢話)。所以,思考問題的時候(編碼)不要跨抽象層級思考,在咱們有限的智力裏面現保證這個層級的邏輯正確,再思考下一個。什麼叫跨抽象層級思考,什麼叫同一個抽象層級的思考。咱們經過一個例子來看看,假設如今我要編寫程序打車去上班。函數
首先穿衣服,而後洗臉刷牙上廁所,而後下樓打車。編碼
這句話就算是一個三歲的人都能說出來。上面的描述是在同一個思惟層次,把「打車上班」這個事情分紅了幾個符合順序和操做邏輯的模塊和動做,個人大腦可以承載這些邏輯,這一套邏輯下來就可以把這件事情完成。因而我把它寫下來:code
def goWorkByCar () dressUp() wash() goDownstairs() goByCar() }
這個抽象層次的東西已經完成了,我看這個函數就知道這個操做的順序和邏輯是什麼,甚至還不用註釋。咱們有四個函數都是沒有完成的,它們的具體實現就是下一個抽象層次的東西。咱們如今下到下一層,看看 dressUp
。如今個人注意力已經不在打車上班這件事情上了,這一層的邏輯已經完成了。個人注意力在怎麼穿衣服這件事情上:bug
從櫃子裏把衣服拿出來,先穿上半身,再穿下半身。程序
符合正常的操做,不錯:call
def dressUp () clothes = takeClothesFromWardrobe() dress(clothes.up) dress(clothes.down)
咱們看看洗漱怎麼作:新手
上廁所,刷牙,洗臉
def wash () urine() brushTeeth() washFace()
下樓呢?
我要先出門,而後鎖門,而後坐電梯。
def goDownstairs () openDoorAndOut() lockTheDoor() takeTheLift()
打車呢?
用手機打車,而後坐車走人
def goByCar () car = callACarByPhone() takeTheCar(car)
...而後再用這種方式實現像 brushTeeth
和 washFace
具體的實現,想一想它們須要什麼操做。
你會發現咱們不停地在填函數,函數裏面又不停地出現新的函數須要咱們去完成。每一個函數體裏面的操做都和這個函數所要完成的目的相關,在一個函數裏面,咱們只關心這個函數須要完成的目標所須要操做。例如「打車上班」這個任務所依託的 goWorkByCar,咱們在這裏並不關心怎麼刷牙,由於它是下一層的東西,咱們只關注完成「打車上班」這個目標須要哪幾步。若是咱們刷牙、開門這些操做都放在這個函數裏面,那麼一開始就會陷入無限的細節當中而失去了主要目的的關注,並且大腦也沒法承載如此複雜多端的細節,處理很差就很容易出現 bug。
而這種思惟方式可讓咱們不停地把一個大的任務在同一個層級作分解,保證這一層的步驟和邏輯正確之後,而後再下一層分解,最後實際上是一個樹狀的結構,樹的葉子結點纔是具體的代碼算法實現。在編碼的時候,我只用我有限的腦力關注當前層級的任務,不關注上一層也不關注下一層的細節。
這樣的代碼寫出來不只 bug 少,邏輯清晰並且還很輕鬆,由於你每一層思考的東西其實都很簡單,不知不覺就把代碼寫完了。爲何不少人以爲編程很難,由於你接到一個「打車上班」的任務之後就開始腦子裏面就填滿了刷牙打車穿衣服這種不成邏輯和順序的任務,而且都把它寫到一個函數裏面去。
接到任務之後你能夠像上面同樣用人類語言描述一下若是你要解決這個任務,你須要什麼步驟。這些步驟纔是這一層任務的關注點。例如跟女友看電影:你要先看看有什麼好電影,而後再約女友,再買票。
(UPDATE:有朋友說這裏第一步應該先找女友,贊成!!必須贊成!全身贊成!每一個細胞都贊成!)
當你寫一行代碼的時候能夠常常看看你的函數名,你這行代碼和你的函數名所表明任務的是否是同一個邏輯層次的東西,不是的話,把它分出去。