成為一名優(yōu)秀的程序員,就是讓你自己接受不斷學(xué)習(xí)的生活(活到老,學(xué)到老)。包括新功能、新語言、新工具、新框架等優(yōu)秀的源頭——學(xué)習(xí)永不停息。但是,其實(shí)計(jì)算機(jī)科學(xué)也是一個(gè)令人驚訝的傳統(tǒng)領(lǐng)域,這是基于久經(jīng)考驗(yàn)的原則得出來的。我們已經(jīng)添加了面向?qū)ο?、現(xiàn)代硬件以及人工智能。然而,盡管發(fā)生了這么多的變化,許多上一代人提出來的見解在今天仍然適用(這點(diǎn)和我們現(xiàn)在的名言警句類似)。 在這篇文章中,我剖析了一些我最喜歡的關(guān)于計(jì)算機(jī)科學(xué)的引用。我設(shè)置的唯一條件就是,每個(gè)優(yōu)秀的引用必須至少有20年的歷史。因?yàn)楣爬系募夹g(shù)很快就會(huì)變得毫無用處,而我們編程祖先的古老戒律卻有更強(qiáng)的持久力。 1. 關(guān)于Indirection
這里有一個(gè)很少被開發(fā)者愿意解釋卻又經(jīng)常被復(fù)用的compsci的引用。但這是我最喜歡的編程真理之一,因?yàn)樗|及了編碼的核心。 開始考慮Indirection的最簡單的方法是想像層次。例如,假設(shè)您有一個(gè)小項(xiàng)目,需要將組件A放入組件B: 兩個(gè)都是標(biāo)準(zhǔn)的組件,因此你不能破壞他們并更改他們的工作方式。你可以構(gòu)建一個(gè)全新的組件,但這需要大量的工作和不必要的重復(fù)。一個(gè)更好的方式就是這兩個(gè)部分之間添加一層——一個(gè)適合于兩個(gè)組件并在它們之間進(jìn)行轉(zhuǎn)化的適配器。(其實(shí)就是設(shè)計(jì)模式中的適配器模式) 現(xiàn)在,如果Indirection僅僅是添加一個(gè)新層來講不兼容的部分組合在一起,這將是很好的,也確實(shí)很有用。但是圍繞問題進(jìn)行構(gòu)建來解決問題的想法是一個(gè)從底層一直延伸到頂層的概念。當(dāng)你試圖將新的數(shù)據(jù)模型適配到舊的用戶接口時(shí),你就會(huì)看到它;當(dāng)你試圖將遺留應(yīng)用安裝到一個(gè)新的web后端服務(wù)器時(shí),你就會(huì)看到它;當(dāng)你需要綁定更好級(jí)別的特性(如日志和緩存)或協(xié)調(diào)更高級(jí)別的服務(wù)(如消息傳遞和事務(wù))時(shí),你就會(huì)看到它;在金字塔的頂端,你將會(huì)接觸到像機(jī)器學(xué)習(xí)(當(dāng)你不能為你需要的行為編碼時(shí),再寫一層代碼來幫你找出它)這樣的少數(shù)主題。 很多人會(huì)告訴你,編程就是用一種即使電腦小白也能理解的語言寫出明確的指令。但是大衛(wèi)·惠勒的名言揭示了更好的見解:好的編程是要爬上抽象的階梯才能到達(dá)最通用的解決方案。 相關(guān)引用: 間接是強(qiáng)大的,但是復(fù)雜性是有代價(jià)的。人們很少引用惠勒關(guān)于間接的后續(xù)評論:
從那時(shí)起,這一真理就一直讓程序員在商業(yè)上如日中天。 2. 關(guān)于簡單
不少明智的程序員警告我們不要使代碼過于復(fù)雜。但很少有人能比荷蘭計(jì)算機(jī)科學(xué)先驅(qū) Edsger Dijkstra 更清楚地說明復(fù)雜性的成本。 這里的見解是:你不會(huì)選擇簡單作為送給未來的禮物。你不做因?yàn)槟谄诖龣C(jī)會(huì)重用您的代碼,或者因?yàn)槟M诖a評審時(shí)讓它看起來更整潔,或者是因?yàn)槟胧蛊涓子谛薷模ūM管所有這些好處都是寶貴的!)。您這樣做因?yàn)楹唵问且粋€(gè)先決條件。如果沒有簡單性,就永遠(yuǎn)不可能有可以信賴的可靠代碼來開展業(yè)務(wù)或處理您的數(shù)據(jù)。 要接受Dijkstra的觀點(diǎn),我們需要重新定義“好代碼”的含義。不是最短的代碼。它不一定是最快的代碼。絕對不是最聰明的代碼。可以信任的代碼。 相關(guān)引用: 保持代碼簡單的最佳方法之一就是記住少即是多。Dijkstra 提供了一個(gè)可幫助我們牢記這一點(diǎn)的指標(biāo):
3. 關(guān)于可讀性和重寫
乍一看,這個(gè)引用來自軟件傳奇和StackOverflow共同創(chuàng)建者Joel Spolsky似乎是正確的,但看似膚淺。是的,代碼可能很密集,簡短而又冗長。這不僅僅是別人的代碼。如果您看一年前的工作,您可能需要一些時(shí)間來整理一下您曾經(jīng)非常了解的邏輯。 但是Spolsky 的洞察力卻有所不同。您無法閱讀的代碼的危險(xiǎn)不僅僅是顯而易見(很難對其進(jìn)行更改和改進(jìn))。相反,更大的危險(xiǎn)是復(fù)雜的代碼似乎比實(shí)際情況更糟。其實(shí),嘗試了解別人已經(jīng)寫好的代碼是如此之好,以至于您可能會(huì)被吸引犯 Spolsky所說的最嚴(yán)重的錯(cuò)誤-決定從頭開重寫該代碼始。 并不是說重寫不能改善系統(tǒng)的體系結(jié)構(gòu)。他們絕對可以。但這些改進(jìn)付出了巨大的代價(jià)。他們重置測試和調(diào)試錯(cuò)誤的時(shí)間固定,兩項(xiàng)活動(dòng)比單純的編碼要花更長的時(shí)間。重寫很誘人因?yàn)樗鼈兪擒浖_發(fā)中最常見的偏見之一:我們低估了做概念上簡單的事情的努力。這就是為什么最終的5%項(xiàng)目需要50%的時(shí)間。簡單的事情可能會(huì)非常耗時(shí)!和解決您已經(jīng)解決的問題相比似乎沒有比這容易的了。 因此,如果您不應(yīng)該重寫所有內(nèi)容以使其完美,那么有什么更好的解決方案?答案是讓每個(gè)開發(fā)人員都參與恒定大小的重構(gòu)。這個(gè)為您提供小的,連續(xù)的代碼改進(jìn)-真正有回報(bào),并且風(fēng)險(xiǎn)很小。您可以在編碼的過程中提高可讀性。 相關(guān)引用: 如果您仍然不確定可讀性的重要性,Martin Fowler可以幫助您解決這一問題角度來看:
換句話說,程序員的工作不僅是寫代碼,更在于做有意義的事情。 4. 關(guān)于重復(fù)
每個(gè)自重的程序員都知道重復(fù)是萬惡之源。如果您在不同的地方寫相同的東西,你在做額外的工作,測試和調(diào)試。更糟糕的是,您正在引入不一致-例如,如果代碼的一部分已更新,而其他類似的代碼沒有同步更新。程序不一致使您的程序存在偏差,而您存在偏差的程序不再是可行的解決方案。 但是,重復(fù)代碼并不是造成嚴(yán)重破壞的唯一地方。這個(gè)版本的著名的“請勿重復(fù)自己”(DRY)規(guī)則將無重復(fù)原則擴(kuò)展為覆蓋其他可能隱藏矛盾之處。我們不再談?wù)摯a重復(fù)。我們也在談?wù)撓到y(tǒng)中的重復(fù)-系統(tǒng)具有代碼知識(shí)的許多不同方式。它們包括:
所有這些層都可以彼此重疊。而當(dāng)他們這樣做時(shí),他們就有可能引入同一現(xiàn)實(shí)的不同版本。例如,如果文檔描述一種工作方式,但應(yīng)用程序遵循另一種方式?誰擁有真相?如果數(shù)據(jù)庫表與代碼中的數(shù)據(jù)模型不匹配怎么辦?或者注釋描述了算法的操作,與實(shí)際的實(shí)施方式不符?每個(gè)系統(tǒng)都需要一個(gè)單一的、權(quán)威的,其他一切都必須高度統(tǒng)一。 順便說一下,競爭版本的真相不僅是小規(guī)模項(xiàng)目中的問題或設(shè)計(jì)不良的代碼。最好的例子之一是隨著XHTML和HTML5之間的斗爭。一個(gè)陣營認(rèn)為規(guī)范是官方事實(shí),需要對瀏覽器進(jìn)行更正以遵循它。另一派聲稱瀏覽器行為是事實(shí)上的標(biāo)準(zhǔn),因?yàn)檫@就是當(dāng)設(shè)計(jì)師們寫網(wǎng)頁時(shí)已經(jīng)想到了。最后,瀏覽器版本的真相獲勝。從這一點(diǎn)上來說,HTML5的瀏覽器就是這么做的 -包括快捷鍵,他們允許和他們接受的錯(cuò)誤. 相關(guān)引用: 代碼和注釋彼此矛盾的可能性引發(fā)了關(guān)于注釋是否弊大于利的激烈辯論。極限編程的支持者公開懷疑:
5. 關(guān)于難題
乍一看,這句話似乎很有趣,但卻是普通的編程笑話。聽起來很困難的內(nèi)容(緩存無效)與聽起來很輕松(為事物命名)的事物可以立即關(guān)聯(lián)。每一個(gè)程序員投入了數(shù)小時(shí)的工作來解決一個(gè)荒謬的瑣碎問題,例如參數(shù)傳遞順序錯(cuò)誤或大小寫不一致的變量(感謝JavaScript)。只要人類需要與機(jī)器合作完成任務(wù),編程將成為高級(jí)系統(tǒng)規(guī)劃和瑣碎輸入錯(cuò)誤的混搭。 但是,如果您再看一看Phil Karlton的引用,還有更多需要解決的問題。命名事情并不難,因?yàn)槌绦騿T的生活經(jīng)常因小小的頭痛而毀了。這也是因?yàn)槊麊栴}實(shí)際上是每個(gè)程序員最關(guān)心的重要工作:軟件設(shè)計(jì)。換句話說,您如何編寫清晰的代碼,干凈,一致嗎? 有很多方法可以使命名錯(cuò)誤。我們都看到過以變量命名的數(shù)據(jù)類型(myString,obj),縮寫(用于產(chǎn)品目錄的pc),一些瑣碎的實(shí)現(xiàn)細(xì)節(jié)(swappable_name,formUserInput),甚至什么都沒有(ret_value,tempArray)。容易陷入基于以下方式命名變量的陷阱您當(dāng)時(shí)正在使用它做什么,而不是其中包含什么。布爾值是特別棘手的-當(dāng) progress 標(biāo)記進(jìn)度開始,表明您需要在用戶界面中顯示進(jìn)度信息,或完全標(biāo)記某些內(nèi)容不同? 但是變量名僅僅是開始。命名類提出了如何將代碼分成獨(dú)立部分的問題。命名 public 成員將影響您的工作方式顯示允許應(yīng)用程序的一部分與另一部分交互的界面。鎖定這些名稱不僅描述了一段代碼可以做什么,而且確定它將做什么。 相關(guān)引用:
結(jié)語很高興,你和我一樣堅(jiān)持看到了最后,是不是對自己編程過程中有很多想改變的地方呢?比如簡單行,可讀性,DRY原則,是不是讓你銘記在心,還有最后說的緩存失效很難,命名很簡單的錯(cuò)覺。 |
|