1. 程式人生 > >《軟體開發者路線圖——從學徒到高手》讀書筆記

《軟體開發者路線圖——從學徒到高手》讀書筆記

# 第 1 章 --- 略 # 第 2 章 空杯心態 --- ### 1、多種語言 第一門語言學得越好,下一門語言學起來就越容易。 > 鄙人大二學的 JAVA,後來再去學 JS 就感覺好簡單(雖然 js 的坑真的多)。 **每一種語言都為你提供了使用不同模式來解決問題的機會**。在逐漸超越第一門語言的過程中,你應該尋找機會去學習一些採用迥然不同的方法來解決問題的語言。愜意於面嚮物件語言的學徒應該探究一下函式式( functional)程式語言。暢然於動態型別的學徒應該鑽研一下靜態型別。安逸於伺服器端程式設計的學徒應該考查一下使用者介面設計。 > 我的目標就是全棧丫。 **你不應該“嫁”給任何特定技術**,而應該有足夠寬的技術背影和經驗基礎,使自己能針對特定的情景選擇好的解決方案。 > 我是很討厭討論什麼語言最好的,每個使用場景都有最適合它的語言。 ### 2、初學者心態 通常,每一步都該有進門的感覺。這是**初學者的心——一種正在“成為”的狀態**。——鈴木俊隆,《Zen Mind,Beginner's Mind》(禪者的初心) 正如 Yoda 在電影《The Empire Strikes Back》(星球大戰 2:帝國反擊戰)中所說的:“**你必須忘記已經學到的東西**。”(You must unlearn what you have learned) 有多少次你擔心被人覺得愚蠢而沒有嘗試新東西?有多少回你擔心被人認為幼稚而壓抑了主動性?……心理學家 Abraham Maslow 發現,**那些能把潛力發揮到顯著水平的人身上都有一種孩童般的品質**。 Ashleigh Montagu 使用術語“嬰兒化”( neotany)(來自詞語" neonate",新生兒的意思)。 發生在朋友或自己身上的一些事,我們認為愚蠢,緊鎖雙眉;但同樣的事如果發生在世界著名的天才身上,我們只會覺得古怪,一笑置之;永遠不要忘記:**可以隨便犯蠢的自由很可能是開啟天才成功之門的鑰匙**。 > 這就是 大智若愚 吧。 在新知識有機會滲入到大腦之前,你必須設法避免將新舊知識混合在一起,並以初學者的心態著手解決新問題。這可能意味著短期內生產率會降低一些,以期在掌握新方法之後能獲得技能水平的飛躍。 學習新東西是痛苦的,特別當你在頂著壓力而且幾乎沒有人指導的情況下學習。儘管如此,正如運動員必須忍受艱苦訓練後的肌肉痛楚,軟體開發者需要忍受學習新東西后的神智錯亂。 ### 3、新人 **儘管你缺乏經驗(而且恰恰因為你缺乏經驗),你會為團隊帶來一些獨特的品質,包括富有感染力的激情**。不要讓任何人壓抑了你對軟體工藝的興奮——它是一種寶貴的財富,它將加速你的學習。作為軟體開發者,你將不可避免地成為團隊一部分,並在此基礎上展開工作。在任何組織結構中,都會有一種遵循規範的趨向,對新人而言尤其如此。大多數團隊都不會對技術有過熱的激情。可以肯定,他們都專注於交付下一個專案,或者改善軟體開發週期中的某些讓他們頭痛的方面。因此,**充滿激情的學徒常常會屈服於“做人要低調”的外界壓力。他們要麼完全壓抑自己的熱情,要麼僅在日常工作之餘才讓它表現出來。在相對完善的團隊中釋放激情當然是有風險的。** 如果團隊士氣較低或者團隊不歡迎新人,你可能在背後遭遇白眼。對那些認為競爭力比學習能力更重要的人來說,毫無疑問,你會給他們留下不好的印象,特別當你暴露出自己無知的時候。跟任何模式一樣,這一模式也不應被盲目運用。團隊動態( team dynamics)永遠都是需要考慮的因素。**如果你發現自己處在一個無法接受你激情的團隊中,那麼你將需要想些辦法來養護自己的激情。** > 作者的觀察真的細緻,我之前也有類似的感悟,不過在中國,剛進入公司的新人,真的有激情,也儘量低調點,對自己大家都好。 > 不過這讓我想到另一個新詞:奮鬥逼。(這個是貶義,當然跟上面提到的有激情不一樣) **思想的多樣性應看作集體智慧的關鍵因素。**對航空母艦艦隊集體心理的一次有趣的研究顯示:要安全地操縱一艘戰鬥機不斷從它上面起降的巨船,需要複雜的、相互配合的行動,而新人在這類行動中扮演重要角色。**研究者發現,一個由不同經驗水準的人組成的團隊更加健康。如果把不同的經驗水平關聯到一起,比如當腦子裡沒有任何“想當然”的新手與認為自己已縱觀全貌的老前輩們更加頻繁地打交道時,大家對問題的理解都會加深。** > 確實,一個健康的團體還是參差多型的好。 **隨著你慢慢過渡到熟練工的角色,你將變得越來越不依賴於這些技能,慢慢地別人開始基於你的名聲、你以前參與過的專案,以及你能帶給團隊的更深層品質來僱傭你。** > 古有:始於顏值,陷於才華,忠於人品。 > 今有:始於技能,陷於名聲,忠於品質。 專家技能是我們走的這條漫漫長路的副產品,但不是目的地。 > 追求卓越,成功就會主動找上你。—— 《三傻》電影 ### 4、無知 如果你想讓他們安心,那也應該通過你的學習能力,而不是通過假裝知道自己並不知道的東西。這樣,你的**名聲將建立在你的學習能力上**,而不是你已經知道的事情上。**暴露無知,最簡單的方法就是問問題。** 選出一種技能、工具或技術,**積極地填補跟它有關的知識空白**。採用一種對你最有效的方法來做這件事。對於某些人,最好的方法可能是閱讀能接觸到的所有文獻和 FAQ,來獲得**知識概覽**。其他人則可能覺得直接動手構造一個“質脆玩具”才是理解一樣東西的最有效途徑。不管哪種方法適合你,都不要忘了問問周圍的“同道中人”和指導者,看是否有人已經掌握了這項技能並願意分享所學。有時其他人也可能在學習這項技能,跟他們一起工作你會獲得更快的進步。到某個時刻,你將在這個新領域達到令人滿意的能力水準,這時你就可以做決定了,是繼續深入挖掘下去更有成效呢,還是應將注意力轉到其他的技能空白上。每天只有 24 小時,你無法將每項技能都研磨到很高水平,因此你必須學會在它們中間做必要的權衡。 它不只是征服先前未知的高峰,還要一步一步地走出一條新的道路。 # 第 3 章 走過漫漫長路 --- ### 1、技重於藝 **我願意將程式設計說成一種`技藝`,技藝本身也是一種藝術,但它不是`美術`。技藝的意思是:使用可能帶有裝飾性的手法來製作有用的物件。美術的意思則是製作東西純粹為了使之美麗**。——Richard Stallman 在"Art and Programming"(藝術與程式設計) 作為技師,你的首要工作是構建能滿足他人需要的東西,而不是沉迷於藝術展現。畢竟,**世上不該有捱餓的技師。** 如果你捱餓了,因為你太像一個藝術家,你創造的東西太美以致在現實中無法交付,那你就是離開了技藝。 我們為客戶構建的東西“可以”是美的,但“必須”是有用的。 其中的一部分就是培養在必要時犧牲美麗來換取效用的能力。 **功用和美好並不對立**,而是相輔相成。 ### 2、持續動力 **”做你喜愛的事,錢自然會來。”** > 我喜歡睡覺…… “如果你認為一樣東西有趣,你就能學到有趣的東西。” 上帝只讓一小部分人開開心心地通過自己喜愛的工作謀生。感謝上帝,讓我成為其中之一。 **受到來自消費者至上主義者和速成社會的塞壬歌聲的誘惑,我們有時會選擇一種只會帶來成功表象和滿意幻影的行動過程。**—— George Leonard,《 Mastery》(精通) 大多數人把提升到管理職位等同於成功。 > 遠離幻象。 聰穎而且努力的學徒千萬不要對自己的成功自鳴得意。在軟體開發領域,超越平庸是很容易的,因為**有太多的人只超出平均曲線一點點就開始滿足了。**你必須去追尋那些技藝精湛、學徒甚至無法想象其水平的其他團隊、組織、熟練工和師傅,向他們學習,以此來抗爭趨於平庸的傾向。 ### 3、另闢蹊徑 不要因為他們沒有走在你所走的路上,就認為他們已經迷失了。 即使永遠地離開原來的道路,在這一路上你所形成的價值和原則也將一直陪伴著你。 > 一切經歷皆有用。 遺憾的是,傳統的軟體組織不一定會如此歡迎。他們常常把這些彎路看作職業生涯中的缺口,因此你必須為此做正當的解釋。他們會期望你能給出一個符合他們價值系統的合理解釋, > 你很難想象一個程式設計師職業生涯中途出現跑出去當了幾年廚子給面試官帶來的壞印象。 ### 4、學徒與師傅 > 不知而不知其不知者,愚者也——避之! 不知而知其不知者,惑者也——授之! 知之而不知其知之者,寐者也——醒之! 知之而知其知之者,覺者也——從之! —— Isabel Burton( 1831— 1896)女士在《 The Life of Captain Sir Richard F. Burton》( Richard F. Burton 上尉的一生)一書中引用的阿拉伯諺語 學徒向技師學習,技師也向學徒們學習。激情洋溢的初學者不僅能恢復技師的活力,還能從外界帶來新的思想來挑戰更有經驗的技師。精心挑選的學徒甚至能使師傅變得更有成效。 俗話說:“一個人教的時候,兩個人在學。” > 所以從辯證的角度來看,學徒也是師傅的師傅。 頂多,你可以說這個人技能水平比你高。但這並不足以證明她技藝精通。**一個人走在了你的前面並不能證明她是個師傅。** 在那一天到來之前,發現精通技藝的最好方法只能是考察一個人和她的學徒們的工作質量。 僅僅是天才並不能成就精通,但如果一個人可以培訓他人,使之達到或超越自己的才華,那就是一種證據,證明此人有師傅的潛力。 > 能把別人教的很厲害的人,自己一定也很厲害。 # 第 4 章 準確的自我評估 --- ### 1、只求最差 寧為獅尾,不為狐頭! > 還有另一句相反的:寧做雞頭,不做鳳尾。 **讓周圍多些水平比你更高的開發者。找一個更強大的團隊,在那裡讓自己成為最弱的成員並擁有成長的空間。** 記住,被一位潛在的指導者拒絕或者認為你奇怪的概率並不高,而潛在的回報卻是巨大的。即使那人沒興趣收你為全職學徒,邀請她出來共進午餐也會是很有價值的時間和金錢投資。 > 多多請教。 這類任務包括維護構建系統,產品支援,響應維護需求,bug 修正,程式碼複查,消除技術債務(technical debt),搭建專案 wiki,更新文件,為其他人的想法充當傳聲筒,等等。通常,你會關注風險更低的系統邊緣部分,而不是常常帶有大量依賴性和極高複雜度的核心。Jean Lave 和 Etienne Wenger 觀察了不同行業中的學徒,發現“在工作流程中,新手的任務往往被置於分支的末尾,而不是一連串工作片段的中間”(《Situated Learning》(情景化學習),第 110 頁)。**這類邊緣任務會使團隊受益,對作為學徒的你也有好處,因為這些雜務在學校的課程中常常被略過了,做一做能填補知識中的漏洞**。當你成為熟練工時,這種體驗還是能帶來幫助,因為很多帶你的師傅都明白:有個人去做單調的工作是多麼重要。畢竟,如果沒人打掃地面,那麼富有魅力的工作也無法做出來,因為團隊已深陷髒亂之中。 被你的團隊拖延了幾個月的最邋遢的任務是什麼?它應該是所有人都抱怨,卻沒有人願意解決的那個。你去解決它。**不要捂著鼻子強迫自己去做;看自己能否找到一種超出人們預期併為自己帶來樂趣的方式,創造性地解決這個問題**。 ### 2、自我評估 他們的同名論文中指出的:**技藝不精的人常常不知道自己技藝不精。再者,越是技藝不精,你越不善於評估自己和他人的技能。** 他們希望,如果曾經有一支人數和經驗水平都差不多的團隊在過去能完成一件差不多的事情,那麼今天的團隊或許也能完成。不幸的是,軟體開發中的技能水平範圍很廣,在我們當中,最優秀的那些人可以稀鬆平常地做出大多數人認為不可能的事情。此外,**多數程式設計師都認為自己的水平超出平均。悲慘的事實是:由於下圖所示的不規則的技能水平分佈,大多數程式設計師實際上是低於平均水平的**。這聽起來有點反直覺,但你可以設想這樣一個比方:現在我們兩個人, Dave 和 Ade 坐在桌子邊上,然後 Bill Gates 過來加入我們,突然之間坐在桌子旁的“大多數”人的薪水都低於平均水平了。也就是說,在程式設計技能曲線上處於極遠端的那些人傾斜了整個分佈。 ### 3、天賦與性格 **天賦常常被誤解。它並不是超常的智力,而是一種性格。** # 第 5 章 恆久學習 --- ### 1、不斷實踐 “一個人一旦停止了實踐,她對技藝的精通就馬上開始消退。”每一個不寫程式的日子,你都是在不斷遠離熟練工的目標。“ 我們所知道的大師,不會僅為了做得更好而讓自己專注於某項技能。實際情況是:他們熱愛實踐——並且正因為熱愛實踐所以才做得更好。事情總是相輔相成的,做得越好,他們就越喜歡反覆不斷實施這些基本的實踐活動。——George Leonard,《Mastery》(精通) “刻意實踐”(deliberate practice)。 ### 2、質脆玩具 **我們都可以從編寫隨意的“玩具”程式中受益,編寫玩具程式時,我們會設定一些人為的限制,從而將自己的能力推到極限。**——Donald Knuth,《The Art of Computer Programming》(中譯本及雙語本《計算機程式設計藝術》,機械工業出版社) **如果來自失敗的經驗可以與來自成功的經驗一樣多,那麼你需要一個相對私有的空間來尋求失敗**。在拋球雜技中,拋三隻球的表演者,如果從來沒拋過五隻球,那他就永遠不會取得進步。而那些連續幾個小時去揀落下的球直到揀得背疼的人,最終卻能把技藝練好。同樣的經驗也適用於軟體領域。正如拋三隻球的表演者不會在正式的表演中拋五隻球,軟體開發者也需要一個安全的地方來犯錯誤。 “質脆玩具”模式的其他例子包括像 Tetris 和 Tic-Tac-Toe 這樣的遊戲(**我們的一位前同事有一種習慣:每學習一門新語言,就用它來編一個遊戲**)、部落格軟體和 IRC 客戶端。問題的本質在於構建玩具包含了對新事物的學習,而且提供機會讓你在特殊的環境中加深對手中工具的理解,這個環境不僅安全(因為你是唯一或者最重要的使用者),而且,即使跟最強大的商業產品比起來,你仍有餘地來更好地服務自己作為一名使用者的需求。 你還是要記住:它們只是玩具,而且正因為這一點**它們應該是有趣的**。如果它們沒什麼意思,那麼當最初的熱乎勁過去之後,它們將成為塵封的舊物,而你則將自己的精力關注到你真正樂於構建的東西上去了。 > 我之前也想過並做過,我稱之為 demo。 ### 3、開源專案 在研究一個開源專案時,要養成下載最新版程式碼的習慣(最好從它們的原始碼控制系統下載),這樣你可以查閱它的歷史,跟蹤未來的發展。看一下程式碼庫的結構,想一想為什麼程式碼是那樣組織的。看一看開發者組織程式碼模組的方式是否有一定的道理,拿它跟自己可能使用的方式比較一下。試著重構程式碼,從而理解為什麼它的編碼者做了那樣的決定,同時想想如果你是那個編碼的人,寫出的程式碼將是什麼樣子。這不僅能讓你更好地理解這些專案;還確保你能構建這些專案。如果你發現了做一件事的更好方法,你就完全可以為這個專案貢獻程式碼了。在研究程式碼的過程中,你會不可避免地看到一些自己完全不同意的決策。問問自己,是否專案的開發者可能知道一些你不知道的東西,或者相反。考慮一下有沒有可能這是一個歷史遺留設計,需要重構一下;並考慮:為相關特性做個玩具實現是否有助於澄清問題。 最終你將獲得一個**工具盒**,裡面都是從其他人的程式碼中收集來的各種奇技。這會磨鍊你更迅速、更快捷地解決小問題的能力。你將能處理別人認為不可能解決的問題,因為他們接觸不到你的工具盒。看一看 Linus Torvalds 編寫的 Git 分散式原始碼控制系統的程式碼,或者任何 Daniel J. Bernstein(眾所周知的 djb)編寫的程式碼。像 Linus 和 djb 這樣的程式設計師偶爾會用到我們大多數人甚至從未聽說過的資料結構和演算法。他們並不是魔術師——跟大多數人相比,他們不過是花時間構造了更大更好的工具盒。開源的優勢就在於你可以隨意觀看他們的工具盒,而且可以把他們的工具變成你自己的。軟體開發領域的問題之一是缺少教師。**不過多虧了諸如 sourceforge. net 和 GitHub 這些站點上開源專案的繁榮,你可以從全世界程式設計師社群中那些相對有代表性的程式碼範例中學習**。 在《Programmers at Work》一書中, **Bill Gates 說:“對程式設計能力最精細的測試就是給程式設計師大約 30 頁的程式碼,看他能多快地通讀並理解它。” 他意識到了一種很重要的東西。那些能直接從原始碼中快速汲取知識的人很快就能成為更好的程式設計師,因為他們的老師就是世界上的每一位程式設計師寫下的一行行程式碼**。要學習模式、慣用法和最佳實踐,最好的方法就是閱讀開原始碼。看看其他人是如何寫程式碼的。這是一種保持自己不落伍的優秀方法,而且是免費的。—— Chris Wanstrath 在 2008 Ruby 大會上的主講內容[ 挑選一個演算法精深的開源專案,如 Subversion、 Git 或 Mercurial 這樣的原始碼控制系統。瀏覽專案的原始碼,記下讓你覺得**新奇的演算法、資料結構和設計理念**。然後**寫一篇部落格**,描述一下專案的架構,著重突出自己學到的新思想。你能在日常工作中找到可運用同樣思想的場合嗎? ### 4、個人實踐圖 只要你工作的時間足夠長,人們就會開始稱你為“老手”,但這不應該是你的目標。所有的經驗都表明你已經有能力在這個行業生存。但它顯示不出你所學到的知識量,僅僅是你所花費的時間。在我們行業的某些領域,有時很容易將**同樣的時間經歷重複 10 次卻沒有取得能力上的實質進步。事實上,這有時會變成“`反經驗`”(anti-experience)**,即這樣一種現象:**每一次新的時間經歷僅僅強化了你所養成的壞習慣**。這就是為什麼**你的目標應該是達到技能嫻熟,而非“有經驗”**。技能水平的提高,是你在研究、適應及改善工作習慣方面所付出努力的唯一有效的證明。 一種可用於明確表達這種反思的技巧是使用“**個人實踐圖**”(Personal Practices Map)。 為你的工作習慣畫一張“個人實踐圖”。重點關注一段時間內沒有改變的那些實踐之間的關聯。問自己,如果你發現當中的某種實踐實際上對生產率起反作用,你的圖該做怎樣的修改。仔細檢查其中的某一種實踐,看看是否存在達到同樣目標的其他方法。它未必是更好的方法;只要不同就夠了。然後問自己,如果你採用其中一種不同的實踐,這張圖又會怎樣變化。 ### 5、記錄所學 **儘量避免落入寫下經驗之後就忘記它們的陷阱。你的筆記、部落格或 wiki 應該是一個託兒所,而不是一座墳墓——經驗應該從這次記錄中降生,而不是到那裡去滅亡。定期讀一讀以前寫的東西,你就能保證這一點。試著在每次重讀這些資料時都找到新的關聯**。這種創造性的復讀過程能讓你基於新的資料重新評估舊的決策,或者堅定正在搖擺的信念。這兩種結果都不錯,只要你別停滯就行。重讀你的筆記,你可以不斷變換自己的過去和現在,從而造就你的未來。 Ade 使用了同一種 wiki 的兩個例項,一個用於記錄私人的想法,另一個記錄那些想要與別人分享的想法。在擁有公開記錄的同時再保留一套私人記錄,這意味著你可以同時利用兩個世界的優勢。 ### 6、分享所學 要在學徒期的早期就養成定期分享所學經驗的習慣。形式可以是撰寫部落格,或者跟你的“同道中人”一起開展“便當會議”。也可以在技術會議上做演講,或者為你正在學習的各類技術技巧編寫教程。 ### 7、學會失敗 **我覺得一個學徒不應該過早地致力於不犯錯誤,而應該儘早找出如何確定錯誤的辦法。一旦學徒能確定他們的錯誤,從錯誤中學習就容易得多了。** ### 8、追根溯源 找出是誰第一次提出了那種思想,弄明白他們當初想要解決的問題。這樣的上下文通常在思想四處傳播的過程中由於各種轉譯而丟失了。 # 第 6 章 安排你的課程 --- ### 1、閱讀 **任何一本書,你能從中獲得的最有價值的東西就是一列值得閱讀的其他書目**。時間長了,你會發現某些書不斷地從“參考書目”( bibliography)中跳出來,你應把那些書移到閱讀列表的頂部。其他書會下沉。由於閱讀列表實際上是個優先順序佇列(priority queue),最終你會發現有的書已經在佇列中下沉得太深,你可能永遠也不會再讀它們了。 開始時挑一本寬泛的書,讓自己對目標主題有大致的瞭解;然後選擇一些內容具體的書,從而掌握該主題中自己感興趣的方面。 **在合適的時間讀合適的書會有更好的效果。** 即使每兩個月讀一本程式設計相關的好書,也就是每週 35 頁左右,用不了多久,你就會對我們的行業有深入的理解,並使自己不同於周圍的人。——Steve McConnell,《Code Complete》 關注於經典作品也有風險:你對它們投入過多的精力,而完全不顧那些能提高日常技能的、更加註重實效的知識和資訊。**在你的閱讀列表中,要確保經典名著和現代的、更注重實效的圖書和文章混合出現。** 在實踐中,演算法問題不會在大專案剛開始的時候就出現。然後,當突然之間程式設計師不知道如何繼續下去或者目前的程式顯然不恰當時,它們就作為子問題出現了。——Steven S.Skiena,《The Algorithm Design Manual》(演算法設計手冊)情景分析 **要真正理解任何思想,你都需要重建它第一次被表達時的上下文。** ### 2、常用工具 Ade 很早就採用了名叫 Subversion 的集中式原始碼控制系統。隨著 Subversion 更加流行,會有客戶請 Ade 為他們的專案提供幫助,因為他是這方面的專家。儘管如此, Ade 卻從一開始就在關注分散式原始碼控制系統這一新品種的出現。[ 1] 當 Subversion 變得過時,它在 Ade 工具箱中的位置將早已被 Git[ 2] 或 Mercurial[ 3] 所取代。**放棄熟悉而又好用的工具是一種讓人痛苦的過程**,但也是一種需要學會的技能。我們可以保證:**你在學徒期使用的工具到你變成熟練工時肯定會變得過時。最終,你所鍾愛的所有工具都將變成垃