回覆列表
  • 1 # 職場工具哥

    你這麼說,證明公司沒有程式碼編寫規範。

    如果是個體去寫,每個人都不一樣,其實還是很難維護的。

    公司應該整體建立程式碼編寫規範,大家都按一個規則寫,加好註釋,程式碼就好維護。

  • 2 # 黃先生的日常VLOG

    寫出整潔的程式碼,是每個程式設計師的追求。《clean code》指出,要想寫出好的程式碼,首先得知道什麼是骯髒程式碼、什麼是整潔程式碼;然後透過大量的刻意練習,才能真正寫出整潔的程式碼。

    WTF/min是衡量程式碼質量的唯一標準,Uncle Bob在書中稱糟糕的程式碼為沼澤(wading),這隻突出了我們是糟糕程式碼的受害者。國內有一個更適合的詞彙:屎山,雖然不是很文雅但是更加客觀,程式設計師既是受害者也是加害者。

    對於什麼是整潔的程式碼,書中給出了大師們的總結:

    Bjarne Stroustrup:優雅且高效;直截了當;減少依賴;只做好一件事

    Grady booch:簡單直接

    Dave thomas:可讀,可維護,單元測試

    Ron Jeffries:不要重複、單一職責,表達力(Expressiveness)

    其中,我最喜歡的是表達力(Expressiveness)這個描述,這個詞似乎道出了好程式碼的真諦:用簡單直接的方式描繪出程式碼的功能,不多也不少。

    命名的藝術

    坦白的說,命名是一件困難的事情,要想出一個恰到好處的命名需要一番功夫,尤其我們的母語還不是程式語言所通用的英語。不過這一切都是值得了,好的命名讓你的程式碼更直觀,更有表達力。

    好的命名應該有下面的特徵:

    名副其實

    好的變數名告訴你:是什麼東西,為什麼存在,該怎麼使用

    如果需要透過註釋來解釋變數,那麼就先得不那麼名副其實了。

    避免誤導

    不要掛羊頭賣狗肉

    不要覆蓋慣用縮略語

    這裡不得不吐槽前兩天才看到的一份程式碼,居然使用了 l 作為變數名;而且,user居然是一個list(單複數都沒學好!!)

    有意義的區分

    程式碼是寫給機器執行,也是給人閱讀的,所以概念一定要有區分度。

    使用讀的出來的單詞

    使用方便搜尋的命名

    名字長短應與其作用域大小相對應

    避免思維對映

    比如在程式碼中寫一個temp,那麼讀者就得每次看到這個單詞的時候翻譯成其真正的意義

    註釋

    有表達力的程式碼是無需註釋的。

    The proper use of comments is to compensate for our failure to express ourself in code.

    註釋的適當作用在於彌補我們用程式碼表達意圖時遇到的失敗,這聽起來讓人沮喪,但事實確實如此。The truth is in the code, 註釋只是二手資訊,二者的不同步或者不等價是註釋的最大問題。

    書中給出了一個非常形象的例子來展示:用程式碼來闡述,而非註釋

    bad

    // check to see if the employee is eligible for full benefit

    if ((employee.flags & HOURLY_FLAG) && (employee.age > 65))

    good

    if (employee.isEligibleForFullBenefits())

    因此,當想要添加註釋的時候,可以想想是否可以透過修改命名,或者修改函式(程式碼)的抽象層級來展示程式碼的意圖。

    當然,也不能因噎廢食,書中指出了以下一些情況屬於好的註釋

    法務資訊

    對意圖的註釋,為什麼要這麼做

    警示

    TODO註釋

    放大看似不合理之物的重要性

    其中個人最贊同的是第2點和第5點,做什麼很容易透過命名錶達,但為什麼要這麼做則並不直觀,特別涉及到專業知識、演算法的時候。

    另外,有些第一感覺“不那麼優雅”的程式碼,也許有其特殊願意,那麼這樣的程式碼就應該加上註釋,說明為什麼要這樣,比如為了提升關鍵路徑的效能,可能會犧牲部分程式碼的可讀性。7點建議助您寫出優雅的Java程式碼!這篇也可以看下。

    最壞的註釋就是過時或者錯誤的註釋,這對於程式碼的維護者(也許就是幾個月後的自己)是巨大的傷害,可惜除了code review,並沒有簡單易行的方法來保證程式碼與註釋的同步。

    函式

    函式的單一職責

    一個函式應該只做一件事,這件事應該能透過函式名就能清晰的展示。判斷方法很簡單:看看函式是否還能再拆出一個函式。

    函式要麼做什麼do_sth, 要麼查詢什麼query_sth。最噁心的就是函式名錶示只會query_sth, 但事實上卻會do_sth, 這使得函式產生了副作用。比如書中的例子

    public class UserValidator {

    private Cryptographer cryptographer;

    public boolean checkPassword(String userName, String password) {

    User user = UserGateway.findByName(userName);

    if (user != User.NULL) {

    String codedPhrase = user.getPhraseEncodedByPassword();

    String phrase = cryptographer.decrypt(codedPhrase, password);

    if ("Valid Password".equals(phrase)) {

    Session.initialize();

    return true;

    }

    }

    return false;

    }

    }

    函式的抽象層級

    每個函式一個抽象層次,函式中的語句都要在同一個抽象層級,不同的抽象層級不能放在一起。比如我們想把大象放進冰箱,應該是這個樣子的:

    def pushElephantIntoRefrige():

    openRefrige()

    pushElephant()

    closeRefrige()

    函數里面的三句程式碼在同一個層級(高度)描述了要完成把大象放進冰箱這件事順序相關的三個步驟。顯然,pushElephant這個步驟又可能包含很多子步驟,但是在pushElephantIntoRefrige這個層級,是無需知道太多細節的。

    當我們想透過閱讀程式碼的方式來了解一個新的專案時,一般都是採取廣度優先的策略,自上而下的閱讀程式碼,先了解整體結構,然後再深入感興趣的細節。

    如果沒有對實現細節進行良好的抽象(並凝練出一個名副其實的函式),那麼閱讀者就容易迷失在細節的汪洋裡。

    某種程度看來,這個跟金字塔原理也很像

    每一個層級都是為了論證其上一層級的觀點,同時也需要下一層級的支援;同一層級之間的多個論點又需要以某種邏輯關係排序。pushElephantIntoRefrige就是中心論點,需要多個子步驟的支援,同時這些子步驟之間也有邏輯先後順序。

    函式引數

    函式的引數越多,組合出的輸入情況就愈多,需要的測試用例也就越多,也就越容易出問題。

    輸出引數相比返回值難以理解,這點深有同感,輸出引數實在是很不直觀。從函式呼叫者的角度,一眼就能看出返回值,而很難識別輸出引數。輸出引數通常逼迫呼叫者去檢查函式簽名,這個實在不友好。

    向函式傳入Boolean(書中稱之為 Flag Argument)通常不是好主意。尤其是傳入True or False後的行為並不是一件事情的兩面,而是兩件不同的事情時。這很明顯違背了函式的單一職責約束,解決辦法很簡單,那就是用兩個函式。

    Dont repear yourself

    在函式這個層級,是最容易、最直觀實現複用的,很多IDE也難幫助我們講一段程式碼重構出一個函式。

    不過在實踐中,也會出現這樣一種情況:一段程式碼在多個方法中都有使用,但是又不完全一樣,如果抽象成一個通用函式,那麼就需要加引數、加if else區別。這樣就有點尷尬,貌似可以重構,但又不是很完美。

    造成上述問題的某種情況是因為,這段程式碼也違背了單一職責原則,做了不只一件事情,這才導致不好複用,解決辦法是進行方法的細分,才能更好複用。也可以考慮template method來處理差異的部分。

    測試

    非常慚愧的是,在我經歷的專案中,測試(尤其是單元測試)一直都沒有得到足夠的重視,也沒有試行過TDD。正因為缺失,才更感良好測試的珍貴。

    我們常說,好的程式碼需要有可讀性、可維護性、可擴充套件性,好的程式碼、架構需要不停的重構、迭代,但自動化測試是保證這一切的基礎,沒有高覆蓋率的、自動化的單元測試、迴歸測試,誰都不敢去修改程式碼,只能任其腐爛。

    即使針對核心模組寫了單元測試,一般也很隨意,認為這只是測試程式碼,配不上生產程式碼的地位,以為只要能跑通就行了。這就導致測試程式碼的可讀性、可維護性非常差,然後導致測試程式碼很難跟隨生產程式碼一起更新、演化,最後導致測試程式碼失效。所以說,髒測試 - 等同於 - 沒測試。

    因此,測試程式碼的三要素:可讀性,可讀性,可讀性。

    對於測試的原則、準則如下:

    You are not allowed to write any production code unless it is to make a failing unit test pass. 沒有測試之前不要寫任何功能程式碼

    You are not allowed to write any more of a unit test than is sufficient to fail; and compilation failures are failures. 只編寫恰好能夠體現一個失敗情況的測試程式碼

    You are not allowed to write any more production code than is sufficient to pass the one failing unit test. 只編寫恰好能透過測試的功能程式碼

    測試的FIRST準則:

    快速(Fast)測試應該夠快,儘量自動化。

    獨立(Independent) 測試應該應該獨立。不要相互依賴

    可重複(Repeatable) 測試應該在任何環境上都能重複透過。

    自我驗證(Self-Validating) 測試應該有bool輸出。不要透過檢視日誌這種低效率方式來判斷測試是否透過

    及時(Timely) 測試應該及時編寫,在其對應的生產程式碼之前編寫

  • 3 # 高山流水167448386

    這個問題好像意有所指耶?如果就是想寫出便於同事維護的程式碼,那完全可以投其所好,簡單至極便好。但人人為我,我要為大眾吧?太容易的話有損程式猿的智商!

  • 4 # 何談悅色

    個人認為,在區域性範圍內如果沒有統一的標準規範的話,就應該按行業標準規範去寫,這樣其他人維護,也有參考依據。

  • 5 # 拽拽小魔頭

    1.公司團隊需要制定統一的編碼規範

    2.編寫程式碼時,需要新增必要的註釋說明

    3.程式碼審查也挺重要的

  • 6 # 二貓呀

    這個領域我雖然沒涉及,但是我看到的大佬說的都是備註!一定要把備註寫好!一定要把備註寫好!一定要把備註寫好!既方便自己,又方便別人!

  • 7 # IT人張飛洪

    00 前言

    團隊中的每個人都會用不同的視角來“審視”你的”作品“,那麼我們如何拿出一份像藝術品一樣的專案程式碼,然後獲得同事們的稱讚呢?

    保持在專案中做到以下幾點,便可收穫殿堂級的藝術程式碼。

    以下幾點是在接手銷售轉化系統及質檢系統等幾個專案後,針對自己的不a足和團隊成員交流得出的結論。

    01 使用meaningful的變數命名

    在宣告一個變數的時候,儘可能的將其作用和充當的角色注入其中:

    宣告一個函式,使用組合動詞而非名詞:

    宣告一個集合內部包含多項內容的時候,要記得使用複數形式:

    在使用數學計算公式的時候儘量提前宣告好常量,常量的注入有助於提升你在維護程式碼階段的可讀性:

    在回撥函式或者函式宣告的形參中,儘量保持形參的語義化,避免後期維護過程中看到前面隨意宣告的i,j,k後,又要折返到原回撥處進行檢視,影響開發效率:

    (同時在使用TS的過程中也儘量避免使用any型別,使用這種型別在codeReview過程中可能會被靈魂拷問)同時在宣告boolean型別的時候要以is作為開頭:

    做到以上這些,在codeReview中就可以保持一個自信的狀態去接受同事們領導們的審閱,因為沒有犯低階錯誤可以讓檢視你程式碼的人保持心情愉悅,同時這種心情可以對你產生正反饋。

    02 每個函式只做一件事

    每個函式儘量保持其職責的單一性,不要出現一個非常強健的函式做了很多事情:

    And這種單詞本身就不是函式的一部分,他會導致新增過多的業務依賴或職責到當前的函式中,從長遠的角度看這絕對是弊大於利的。

    03 讓函式保持"純潔"

    在函式外的任何東西,任何變數都不是他的業務,所以好的函式應該和函式外的任何變數保持好隔離。

    下面這段程式碼可能只有剛入門的新手才會寫出來,但是這種混亂的邏輯在業務複雜了之後,很可能會混入‘你’的程式碼中:

    上面的例子可以改成下面這樣:

    當然在ES6的使用過程中上述問題普遍已經不存在了,但純函式的思想需要時刻謹記。

    04 模組化業務邏輯

    當你在建立了一些函式之後,發現他們在當前的業務中做了一些比較類似的行為。例如,驗證使用者登陸的使用者名稱和密碼,那麼我們最好可以將其歸類為一個模組中。

    這裡我們可以稱之為驗證模組,而不是簡單的使用一個util或者server將其集中起來就完事了:

    05 簡化條件邏輯

    如果一個業務中出現了大量的if else這種內容,想必開發人員看到會十分頭痛。

    舉個簡單的例子:

    仔細看下這裡的else其實是不需要的,我們可以透過提前返回來remove掉:

    06 enrich u Error log

    當我們瀏覽某個App或網站時,經常會在點選某個按鈕彈出“An Error Occurs”這種提示,這種提示很不友好,我們無法排查到底出現了什麼原因,使用者更是一頭霧水,但是假如在出現這種錯誤的時候將描述資訊填充的完整些,對使用者或是技術支援都會有一個很棒的使用體驗。

    例如:當用戶在表單中沒有輸入資訊:

    當用戶此時網路出現了故障:

    對開發者而言,一個詳盡的提示能讓你輕鬆定位到問題,節省了大量的時間:

    包含但不限於這幾種錯誤格式,還有showMessage等方法可以提供......

    07 利用好編輯器中的外掛

    在VSCode下開發的同學,可以透過安裝prettier來保持漂亮的程式碼。同時藉助ESLint可以讓你在開發時注重縮排、空格這些格式化的內容。

    假如在開發過程中注入了TS,那麼開啟typescript-eslint會幫助你規範自己的型別定義,塑造一個風格嚴謹的程式碼style。

    藉助這些外掛讓我們的程式碼格式化時間大大降低,從而我們可以將更多的時間放在提升程式碼質量上。

    08 總結

    以上列舉的幾個例子較為簡單。透過這些通俗易懂的例子,大家在工作中根據自己的理解舉一反三的運用起來。那便是起到了作用。

    在開發中切勿眼高手低,在編碼上做到一絲不苟,對我們技術的成長會有很大幫助。

    唯有持之以恆,幾十年如一日的訓練才能見證技術圈的匠人誕生。共勉!

  • 中秋節和大豐收的關聯?
  • 裡皮帶領國足闖進八強,換做本土教練能行嗎?對此你怎麼看?