François Chollet:關於軟體工程的幾個注意事項
作者:François Chollet
編譯:Bot
編者按:昨天,Keras作者、Google深度學習François Chollet又發表了一篇新文章。他把裡面的內容稱為“自我提醒清單”,這是他多年來目睹、親身經歷的軟體工程師經驗總結。雖然在實際操作中,不少人會被公司管理層的各種要求逼上歧途,但凡事重在不忘初心。值此秋招之際,論智也把這篇佳作分享給大家。
關於開發過程
- 程式碼不僅僅意味著執行,它也是團隊人員之間的一種溝通方式,是向他人描述問題解決方案的一種方式。程式碼的可閱讀性不應是軟體工程師的優點,它該是所有人的基礎能力。這包括清楚地分解程式碼,選擇不言自明的變數名,以及插入註釋來描述隱含的任何內容。
- pull request的時候,不要糾結程式碼能怎麼幫你營銷自己,多想想它可以為讀者和社群做什麼。你必須不惜一切避免“招搖的貢獻”,如果這麼做對你的產品毫無用處,就不要去畫蛇添足。
- 個人品位也適用於程式碼。它是一種約束,如果你追求程式碼的簡潔優雅,你就會規範自己的編碼過程。因此,要始終對簡潔性保持偏愛。
- 學會拒絕——別人提出需求不等於你就應該照他們的想法去做。他們每提出一個新功能,它的成本就會超出最初的實施範圍:維護成本,文件成本和使用者的認知成本。所以要一直問自己:我們真的應該這樣做嗎?通常情況下,這個問題的回答是否定的。
- 當你答應按照使用者請求開發新功能塊(use case)時,記住,只按字面理解開發新功能是不夠的。使用者只關心自己用的特定功能塊,但你必須站在全域性性和原則性的視角下去看待這項更新,一般情況下,這意味著擴充套件現有功能。
- 向持續整合和所有程式碼的單元測試全覆蓋“投資”。時刻確保自己處於優質程式設計環境中,如果這點都做不到,先關注怎麼準備正確裝置。
- 如果沒有做計劃,沒關係。你可以多多嘗試,看看結果如何。要儘早發現錯誤選擇,確保自己最終能發現一種可行的方法。
- 好的軟體可以化難為易。問題看起來可以很複雜,但這並不意味著它的解決方案一定是複雜的、難以實現的。有時工程師們會忽視簡單易用但不怎麼明顯的解決方案,轉而投向另外一些複雜的、有副作用的方法(我們用機器學習吧!寫個APP吧!加上區塊鏈吧!)。在編寫任何程式碼之前,請確保你選擇的解決方案不能更簡單,牢記程式設計首要原則:Keep It Simple。
- 避免隱含規則。如果你自己開發了一些隱含規則,請確保它們是共享的,可以被其他開發者明確理解,或是可以自動化。當你想出了一些頻繁出現的、類似演算法的東西,你應該設法將其形式化為一個文件化的流程,以便其他團隊成員從中受益。此外,你也應該設法尋找一些工具,使這個方法的任何部分都能被自動化(如debug)。
- 這麼做會有什麼影響?這才是你在程式設計過程中應該考慮的事,而不是收入怎麼樣,會帶來什麼個人成長。除了正在監控的指標之外,你的軟體對全球使用者的總體影響是什麼?是否存在預期之外的不良副作用?在保留實用性的同時,你能做什麼改善?

關於API設計
- 你設計的API會有使用者,所以時刻關注使用者體驗。每當你做出一個決定,你都應該關注使用者的感受,關注他們中的每一個人,無論是他們是初學者還是資深開發人員。
- 降低使用者在使用你的API時的認知負荷。自動化一切可自動化的內容,最大限度地減少使用者所需的操作和選擇量,不要暴露不重要的選項,設計簡單一致的工作流程,以反映簡單一致的心智模型。
- 簡單的事應該是簡單的,複雜的事應該是有可能性的。不要為了利基功能塊把簡單問題複雜化,即便是最低限度。
- 如果工作流的認知負荷足夠低,那麼使用者應該能在一次或兩次親身事件後就掌握整個流程(無需查閱教程或文件)。
- 設計一個符合領域專家和從業者心智模型的API。有這個領域經驗但沒有API經驗的人應該能通過閱讀最少的文件直觀地理解你的API,比如檢視程式碼示例、查詢可用物件和它們的簽名。
- 在沒有任何關於底層實現的上下文的情況下,引數的含義應該是直觀的、易於理解的。使用者指定的引數應該和他們的需求有關,而不是和程式碼中的實現細節有關。API就是解決問題的工具,它不需要涉及軟體如何在後臺執行。
- 最強大的心智模型是模組化和層次化的:既注重高級別的簡潔性,又兼顧精確性,包含需要了解詳細資訊。同樣的,一個好的API也應該是模組化和層次化的:易於連線,又具有相當的表現力。它內部應該保持平衡,在較少物件上具有複雜簽名,並且在簡單簽名上具有更多物件。
- 你的API會不可避免地反映你的實現選擇,特別是資料結構。為了實現直觀的API,你選擇的資料結構必須適合對應的領域——這也是符合專家心智模型的一個方面。
- 設計一個端到端的工作流程,而不是一系列atomic features。大多數開發人員在設計API時,遵循的思路是“應該提供哪些功能?讓我們為他們配置選項”。這並不合適,相反地,你應該問問自己“這個工具有哪些功能塊?”“對於每個功能塊,使用者操作的最佳順序是什麼?”“為了支援整個工作流程,最方便的API是哪個?”API中的Atomic options應該能滿足高階工作流程中出現的明確需求——所以,切記不要出現“人們也許需要它”的東西。
- 在使用者使用API的過程中,錯誤資訊是對他們操作的一種重要反饋。互動性和反饋是使用者體驗不可或缺的一部分,因此,設計它們時務必深思熟慮。
- 程式碼即通訊,命名很重要——無論是專案還是變數,名稱反映了你對問題的看法。在設計過程中,你不應使用過於通用的名稱(如x, variable, parameter),也不要用過長、有特指含義的術語,或是會產生不必要誤解的詞(如master/slave)。遵循命名一致性,這意味著內部命名的一致性(如dim/axis)以及和問題內容保持一致。在確定名稱前,參考其他API的命名方式是一種好辦法。
- 文件是API使用者體驗的核心,它不是附加元件。在文件寫作上花費一點精力,你也許會收穫意料之外的驚喜。
- 影象是生動的,言語是蒼白的:你的文件不應該只是介紹軟體如何工作,它應該顯示如何使用它。比如顯示端到端工作流的程式碼示例,顯示API的每個常見用例和關鍵功能的程式碼示例。

關於職業發展
- 職業發展並不是指你管理的人數,而是指你的工作所產生的影響,它能否對世界造成些許改變。
- 軟體開發需要團隊合作,其中人際關係與技術能力同樣重要。當你在職業道路上前行時,請保持團隊間聯絡,做好團隊中的一員。
- 技術永遠不會是中立的。如果你的工作對世界產生了影響,那麼這種影響就會存在道德取向。在軟體產品中看似無害的技術選擇會導致技術獲取條件的調整,它決定著誰將受益、誰將受害:技術選擇也是道德選擇。因此,在道德設計上請始終謹慎而明確地表達你的價值觀,並把你的價值觀融入創作中。永遠不要想“我只是搞技術,它是中立的”,因為你構建它的方式決定了它將被如何使用。
- 自我導向——為你工作和環境提供指引——它是生活滿意度的關鍵。幫助身邊的人建立起屬於他們的自我導向,並確保你的職業選擇能夠讓你成為更好的自己。
- 構建這個世界需要的東西,而不僅僅是你個人的小希望。很多時候,技術人員過著單純的生活,只專注於滿足產品的特定需求。但你應該嘗試去尋求擴大生活體驗的機會,讓自己更好地瞭解世界的需求。
- 在面對長期問題時,你在做任何選擇之前都應該進行長遠打算,並把價值觀置於短期自身利益和情緒之上,例如貪婪或恐懼。明確你的價值觀,並讓它指導你。
- 當發現自己和他人產生矛盾時,停一停,反思一下雙方是否有著相同的價值觀和共同目標,請提醒自己,大家是戮力同心的。
- 生產力由決策力和工作重心決定。這需要 a)良好的直覺,它來自經驗,以便你可以在知之甚少的情況下做出儘可能靠譜的決定; b)能敏銳地意識到什麼時候該謹慎行事,保持觀望,因為一個錯誤決策的成本可能會比延期的成本更高。在不同環境中,時間至上和質量至上的決策權衡可能會帶來很大的差異。
- 更快地決策意味著你在職業生涯中可以做出更多決策,這能鍛鍊你的“直覺”。經驗是提高生產力的關鍵,而更高的生產力可以為你提供更多經驗,這是一個良性迴圈。
- 如果你感覺自己不具備“直覺”,那麼請把經驗抽象成理論。你可以在整個職業生涯中建立一系列可靠且真實的原則:原則是形式化的直覺,它所適應的情景比原始的模式識別(需要大量直接的、類似的經驗)更廣泛。
