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