<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          好代碼和壞代碼

          共 5263字,需瀏覽 11分鐘

           ·

          2022-04-11 11:28


          本文節(jié)選自《代碼的藝術:用工程思維驅動軟件開發(fā)》

          要寫出好代碼,首先需要提升品位。

          很多軟件工程師寫不好代碼,在評審他人的代碼時也看不出問題,就是因為缺乏對好代碼標準的認識。

          現(xiàn)在還有太多的軟件工程師認為,代碼只要可以正確執(zhí)行就可以了。這是一種非常低的評價標準,很多重要的方面都被忽視了。

          好代碼的特性


          好代碼具有以下特性。

          1. 魯棒(Solid and Robust)

          代碼不僅要被正確執(zhí)行,我們還要考慮對各種錯誤情況的處理,比如各種系統(tǒng)調用和函數(shù)調用的異常情況,系統(tǒng)相關組件的異常和錯誤。

          對很多產(chǎn)品級的程序來說,異常和錯誤處理的邏輯占了很大比例。

          2. 高效(Fast)

          程序的運行應使用盡量少的資源。資源不僅僅包括CPU,還可能包括存儲、I/O等。

          設計高效的程序,會運用到數(shù)據(jù)結構和算法方面的知識,同時要考慮到程序運行時的各種約束條件。

          3. 簡潔(Maintainable and Simple)

          代碼的邏輯要盡量簡明易懂,代碼要具有很好的可維護性。對于同樣的目標,能夠使用簡單清楚的方法達成,就不要使用復雜晦澀的方法。

          “大道至簡”,能否把復雜的問題用簡單的方式實現(xiàn)出來,這是一種編程水平的體現(xiàn)。

          4. 簡短(Small)

          在某種意義上,代碼的復雜度和維護成本是和代碼的規(guī)模直接相關的。在實現(xiàn)同樣功能的時候,要盡量將代碼寫得簡短一些。

          簡潔高于簡短。這里要注意,某些人為了能把代碼寫得簡短,使用了一些晦澀難懂的描述方式,降低了代碼的可讀性。這種方式是不可取的。

          5. 可測試(Testable)

          代碼的正確性要通過測試來保證,尤其是在敏捷的場景下,更需要依賴可自動回歸執(zhí)行的測試用例。

          在代碼的設計中,要考慮如何使代碼可測、易測。一個比較好的實踐是使用TDD(Test-Driven Development,測試驅動開發(fā))的方法,這樣在編寫測試用例的時候會很快發(fā)現(xiàn)代碼在可測試性方面的問題。

          6. 共享(Re-Usable)

          大量的程序實際上都使用了類似的框架或邏輯。由于目前開源代碼的大量普及,很多功能并不需要重復開發(fā),只進行引用和使用即可。

          在一個組織內(nèi)部,應鼓勵共享和重用代碼,這樣可以有效降低代碼研發(fā)的成本,并提升代碼的質量。

          實現(xiàn)代碼的共享,不僅需要在意識方面提升,還需要具有相關的能力(如編寫獨立、高質量的代碼庫)及相關基礎設施的支持(如代碼搜索、代碼引用機制)。

          7. 可移植(Portable)

          某些程序需要在多種操作系統(tǒng)下運行,在這種情況下,代碼的可移植性成為一種必需的能力。

          要讓代碼具有可移植性,需要對所運行的各種操作系統(tǒng)底層有充分的理解和統(tǒng)一抽象。一般會使用一個適配層來屏蔽操作系統(tǒng)底層的差異。

          一些編程語言也提供了多操作系統(tǒng)的可移植性,如很多基于Python語言、Java語言、Go語言編寫的程序,都可以跨平臺運行。

          8. 可觀測(Observable)?/ 可監(jiān)控(Monitorable)

          面對目前大量存在的在線服務(Online Service)程序,需要具備對程序的運行狀態(tài)進行細致而持續(xù)監(jiān)控的能力。

          這要求在程序設計時就提供相關的機制,包括程序狀態(tài)的收集、保存和對外輸出。

          9. 可運維(Operational)

          可運維已經(jīng)成為軟件研發(fā)活動的重要組成部分,可運維重點關注成本、效率和穩(wěn)定性三個方面。

          程序的可運維性和程序的設計、編寫緊密相關,如果在程序設計階段就沒有考慮可運維性,那么程序運行的運維目標則難以達成。

          10. 可擴展(Scalable and?Extensible)

          可擴展包含“容量可擴展”(Scalable)和“功能可擴展”(Extensible)兩方面。

          在互聯(lián)網(wǎng)公司的系統(tǒng)設計中,“容量可擴展”是重要的設計目標之一。系統(tǒng)要盡量支持通過增加資源來實現(xiàn)容量的線性提高。

          快速響應需求的變化,是互聯(lián)網(wǎng)公司的另外一個重要挑戰(zhàn)??煽紤]使用插件式的程序設計方式,以容納未來可能新增的功能,也可考慮使用類似Protocol Buffer 這樣的工具,支持對協(xié)議新增字段。

          以上十條標準,如果要記住,可能有些困難。我們可以把它們歸納為四個方面,見表1。

          表1??對一流代碼特性的匯總分類

          壞代碼的例子


          關于好代碼,上面介紹了一些特性,本節(jié)也給出壞代碼(Bad Code)的幾個例子。關于壞代碼,本書沒有做系統(tǒng)性總結,只是希望通過以下這些例子的展示讓讀者對壞代碼有直觀的感覺。

          1.?不好的函數(shù)名稱(Bad Function Name)

          如do(),這樣的函數(shù)名稱沒有多少信息量;又如myFunc(),這樣的函數(shù)名稱,個人色彩過于強烈,也沒有足夠的信息量。

          2.?不好的變量名稱(Bad Variable Name)

          如a、b、c、i、j、k、temp,這樣的變量名稱在很多教科書中經(jīng)常出現(xiàn),很多人在上學期間寫代碼時也會經(jīng)常這樣用。如果作為局部變量,這樣的名稱有時是可以接受的;但如果作為作用域稍微大的變量,這樣的名稱就非常不可取了。

          3.?沒有注釋(No Comments)

          有寫注釋習慣的軟件工程師很少,很多軟件工程師認為寫注釋是浪費時間,是“額外”的工作。但是沒有注釋的代碼,閱讀的成本會比較高。

          4.?函數(shù)不是單一目的(The Function has No Single Purpose)

          如LoadFromFileAndCalculate()。這個例子是我編造的,但現(xiàn)實中這樣的函數(shù)其實不少。很多函數(shù)在首次寫出來的時候,就很難表述清楚其用途;還有一些函數(shù)隨著功能的擴展,變得越來越龐雜,也就慢慢地說不清它的目的了。

          這方面的問題可能很多人都沒有充分地認識到——非單一目的的函數(shù)難以維護,也難以復用。

          5.?不好的排版(Bad Layout)

          不少人認為,程序可以正常執(zhí)行就行了,所以一些軟件工程師不重視對代碼的排版,認為這僅僅是一種“形式”。

          沒有排好版的程序,在閱讀效率方面會帶來嚴重問題。這里舉一個極端的例子:對于C語言來說,“;”可作為語句的分割符,而“縮進”和“換行”對于編譯器來說是無用的,所以完全可以把一段C語言程序都“壓縮”在一行內(nèi)。這樣的程序是可以運行的,但是對人來說,可讀性非常差。這樣的程序肯定是我們非常不希望看到的。

          6.?無法測試(None Testable)

          程序的正確性要依賴測試來保證(雖然測試并不能保證程序完全無錯)。無法或不好為之編寫測試用例的程序,是很難有質量保證的。


          好代碼從哪里來


          上一節(jié)說明了好代碼的特性,本節(jié)來分析好代碼是如何產(chǎn)出的。

          ? 好代碼不止于編碼

          好代碼從哪里來?

          對于這個問題,很多讀者肯定會說:“好代碼肯定是寫出來的呀?!?/span>

          我曾做過多次調研,發(fā)現(xiàn)很多軟件工程師日常所讀的書確實是和“寫代碼”緊密相關的。

          但是,這里要告訴讀者的是,代碼不只是“寫”出來的。在很多年前,我所讀的軟件工程方面的教科書就告訴我,編碼的時間一般只占一個項目所花時間的 10%。我曾說過一句比較有趣的話:

          “如果一個從業(yè)者告訴你,他的大部分時間都在寫代碼,那么他大概率不是一個高級軟件工程師。”

          那么,軟件工程師的時間都花到哪里去了呢?軟件工程師的時間應該花在哪里呢?

          好的代碼是多個工作環(huán)節(jié)的綜合結果。

          (1)在編碼前,需要做好需求分析和系統(tǒng)設計。而這兩項工作是經(jīng)常被大量軟件工程師忽略或輕視的環(huán)節(jié)。

          (2)在編碼時,需要編寫代碼和編寫單元測試。對于“編寫代碼”,讀者都了解;而對于“編寫單元測試”,有些軟件工程師就不認同了,甚至還有人誤以為單元測試是由測試工程師來編寫的。

          (3)在編碼后,要做集成測試、上線,以及持續(xù)運營/迭代改進。這幾件事情都是要花費不少精力的,比如上線,不僅僅要做程序部署,而且要考慮程序是如何被監(jiān)控的。有時,為了一段程序的上線,設計和實施監(jiān)控的方案要花費好幾天才能完成。

          因此,一個好的系統(tǒng)或產(chǎn)品是以上這些環(huán)節(jié)持續(xù)循環(huán)執(zhí)行的結果。

          ? 需求分析和系統(tǒng)設計

          1.?幾種常見的錯誤現(xiàn)象

          相對于編碼工作,需求分析和系統(tǒng)設計是兩個經(jīng)常被忽視的環(huán)節(jié)。在現(xiàn)實工作中,我們經(jīng)常會看到以下這些現(xiàn)象。

          (1)很多人錯誤地認為,寫代碼才是最重要的事情。不少軟件工程師如果一天沒有寫出幾行代碼,就會認為工作沒有進展;很多管理者也會以代碼的產(chǎn)出量作為衡量工作結果的主要標準,催促軟件工程師盡早開始寫代碼。

          (2)有太多的從業(yè)者,在沒有搞清楚項目目標之前就已經(jīng)開始編碼了。在很多時候,項目目標都是通過并不準確的口頭溝通來確定的。例如:

          “需要做什么?”

          “就按照×××網(wǎng)站的做一個吧?!?/span>

          (3)有太多的從業(yè)者,在代碼編寫基本完成后,才發(fā)現(xiàn)設計思路是有問題的。他們在很多項目上花費很少(甚至沒有花費)時間進行系統(tǒng)設計,對于在設計中所隱藏的問題并沒有仔細思考和求證?;谶@樣的設計投入和設計質量,項目出現(xiàn)設計失誤也是很難避免的。而面對一個已經(jīng)完成了基本編碼的項目,如果要“動大手術”來修改它,相信每個有過類似經(jīng)歷的人都一定深知那種感受——越改越亂,越改越著急。

          以上這幾種情況,很多讀者是不是都有過類似經(jīng)歷?

          2.?研發(fā)前期多投入,收益更大

          關于軟件研發(fā),首先我們需要建立一個非常重要的觀念。

          在研發(fā)前期(需求分析和系統(tǒng)設計)多投入資源,相對于把資源都投入在研發(fā)后期(編碼、測試等),其收益更大。

          這是為什么呢?

          要回答這個問題,需要從軟件研發(fā)全生命周期的角度來考量軟件研發(fā)的成本。除編碼外,軟件測試、上線、調試等都需要很高成本。如果我們把需求搞錯了,那么與錯誤需求有關的設計、編碼、測試、上線等成本就都浪費了;如果我們把設計搞錯了,那么與錯誤設計相關的編碼、測試、上線的成本也就浪費了。

          如果仔細考量那些低效的項目,會發(fā)現(xiàn)有非常多的類似于上面提到的“浪費”的地方。軟件工程師似乎都很忙,但是在錯誤方向上所做的所有努力并不會產(chǎn)生任何價值,而大部分的加班實際上是在做錯誤的事情,或者是為了補救錯誤而努力。在這種情況下,將更多的資源和注意力向研發(fā)前期傾斜會立刻收到良好的效果。

          3.?修改代碼和修改文檔,哪個成本更高

          很多軟件工程師不愿意做需求分析和系統(tǒng)設計,是因為對“寫文檔”有著根深蒂固的偏見。這里問大家一個問題,如果大家對這個問題能給出正確的回答,那么在“寫文檔”的意識方面,一定會有很大的轉變。

          任何人都不是神仙,無法一次就把所有事情做對。對于一段程序來說,它一定要經(jīng)過一定周期的修改和迭代。這時有兩種選擇:

          選擇一:修改文檔。在設計文檔時完成迭代調整,待沒有大問題后再開始編碼。

          選擇二:修改代碼。只有粗略的設計文檔,或者沒有設計文檔,直接開始編碼,所有的迭代調整都在代碼上完成。

          請大家判斷,修改代碼和修改文檔,哪個成本更高?

          在之前的一些分享交流會上,對于這個問題,有人會說,修改文檔的成本更高。因為在修改文檔后還要修改代碼,多了一道手續(xù)。而直接修改代碼,只需要做一次,這樣更直接。

          這個回答說明了回答者沒有充分理解“先寫文檔,后寫代碼”的設計方法。如果沒有充分重視設計文檔的工作,在輸出的設計文檔質量不高的情況下就開始編碼,確實會出現(xiàn)以上提到的問題。但是,如果在設計文檔階段就已經(jīng)做了充分考慮,會減少對代碼的迭代和反復。

          對于同樣的設計修改,“修改代碼”的成本遠高于“修改文檔”。這是因為,在設計文檔中只會涉及主要的邏輯,那些細小的、顯而易見的邏輯不會在設計文檔中出現(xiàn)。在修改設計文檔時,也只會影響到這些主要邏輯。而如果在代碼中做修改,不僅會涉及這些主要邏輯,而且會涉及那些在文檔中不會出現(xiàn)的細小邏輯。對于一段程序來說,任何一個邏輯出現(xiàn)問題,程序都是無法正常運行的。

          4.?需求分析和系統(tǒng)設計之間的差別

          很多讀者無法清楚地區(qū)分“需求分析”和“系統(tǒng)設計”之間的差別,于是會發(fā)現(xiàn),在寫出的文檔中,有些需求分析文檔里出現(xiàn)了系統(tǒng)設計的內(nèi)容,而有些系統(tǒng)設計文檔里又混雜了需求分析的內(nèi)容。

          我們用幾句話可以非常明確地給出二者的差異。

          (1)需求分析:定義系統(tǒng)/軟件的黑盒的行為,它是從外部(External)看到的,在說明“是什么”(What)。

          (2)系統(tǒng)設計:設計系統(tǒng)/軟件的白盒的機制,它是從內(nèi)部(Internal)看到的,要說明“怎么做”(How)和“為什么”(Why)。

          比如,對一輛汽車來說,首先使用者從外部可以看到車廂、車輪,坐在車里可以看到方向盤、剎車踏板、油門踏板等;操作方向盤可以改變汽車的行駛方向,腳踩剎車踏板、油門踏板可用于減速和加速。以上這些是對汽車的“需求分析”。

          然后,我們想象汽車外殼和內(nèi)部變成了透明的,可以看到汽車內(nèi)部的發(fā)動機、變速箱、傳動桿、與剎車相關的內(nèi)部裝置等。而這些對駕駛者來說是不可見的,它們是對汽車的“系統(tǒng)設計”。




          本公眾號全部博文已整理成一個目錄,請在公眾號里回復「m」獲?。?/span>

          推薦閱讀:

          在央企當程序員是一種怎樣的體驗?

          Linux 進程編程入門

          計算機網(wǎng)絡層次劃分及協(xié)議了解


          5T技術資源大放送!包括但不限于:C/C++,Linux,Python,Java,PHP,人工智能,單片機,樹莓派,等等。在公眾號內(nèi)回復「1024」,即可免費獲取!

          瀏覽 74
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          評論
          圖片
          表情
          推薦
          點贊
          評論
          收藏
          分享

          手機掃一掃分享

          分享
          舉報
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  77777色婷婷 | 亚洲色图欧洲 | 亚洲色情电影网 | 国产精品欧美一级 | 日精品|