<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經轉移至github,大家請訪問 http://qaseven.github.io/

    提高代碼質量系列之一—盡可能少寫注釋

    關于<<提高代碼質量系列>>
      這是我新開的一個系列,旨在記錄我對整個編碼規范,代碼風格,語法習慣,架構設計的一些思考,感悟和總結.
      前言
      不知道大家會不會覺得我的標題很噱頭,不是一般應該提倡寫注釋的么?首先我得解釋下,我這句話有兩個意思!
      1,絕非提倡不寫注釋,而是不要寫不必要的注釋.
      2,命名規范的作用大于注釋
      好吧,這么一說,其實還是有點噱頭的感覺的,因為我這篇文其實重心更放在強調命名規范和設計規范上面,良好的規范,讓你的代碼有自釋性,省去了注釋的步驟.
      還要強調下的是:這個觀點絕非我自己主觀臆斷,憑空瞎想出來的. 而是實實在在由項目開發里面總結出來的.
      為什么我有這個想法呢?請繼續看我的蛋疼經歷.
      正文
      先上段奇葩代碼
    /// <summary>
    ///     根據產品ID獲取產品列表
    /// </summary>
    /// <param name="columnID">關鍵字</param>
    public DataTable GetColumnInfoByColumnID(int columnID)
    {
    return DALColumn.GetColumnInfoByColumnID(columnID);
    }
    /// <summary>
    ///     根據產品名稱獲取產品列表
    /// </summary>
    /// <param name="columnID">關鍵字</param>
    public DataTable GetColumnInfoByColumnID(string columnName)
    {
    return DALColumn.GetColumnInfoByColumnID(columnName);
    }
      這是我現在維護的一個老項目了,經手的人比較多,代碼寫的比較垃圾,我們先不吐槽這種純粹是脫褲子放屁的所謂三層和明明返回的是dataTable又扯什么info,就說這兩個函數,tm功能應該是不一樣的吧,為啥名字一模一樣?這是在鬧哪樣?
      其實,造成這種情況的原因,我們都知道,就是某類程序員的ctrl c+v大法,這兩個函數底層邏輯比較相似,懶得重構,直接copy了改改多快!copy就copy吧,好歹名字改一下啊!也許這位前輩會說,我不是寫了注釋了嗎,看到注釋,不就知道這個函數是干嘛的了?但問題是,其他調用的人,首先看到的,肯定是函數名啊,GetColumnInfoByColumnID,多直觀 通過id來查找唄.雖然這里有兩個比較違和的地方,一是參數默認名字是columnName,二是參數類型不是int而是string,但反正這項目的代碼不規范,如果調用的人也夠粗心,那么,一個隱晦的bug,就這么產生了.
      如果改下名字,叫 GetTableByColumnName,這種錯誤發生的概率無疑會減少很多了,
      Ps:其實現在ide功能這么強大,只要你確定沒有反射調用這個函數的地方,完全可以使用全局重命名的方法,一步到位.
      看到這里讀者朋友們可能會說,這是命名不規范嘛,和寫不寫注釋有什么關系呢?
      我們可以假想一種這樣的情況,同樣是拷貝代碼,拷貝者改了函數名,這個名字語義清晰,表意清楚, 但他卻忘記改注釋了,結果函數是新的函數簽名,函數的注釋卻是其他一段莫名其妙的注釋.
      或者再假想一種情況.
      原來的一個函數,名字和注釋是對應的,隨便舉個例子,叫GetTypeByColumnId吧,注釋為"通過產品id取得產品類型"
      一切ok,是吧! 但是現在邏輯變了,比如說Type和產品無關了,需要通過生產批次來確定,于是一個代碼維護者,將函數重寫了一下功能ok,滿足新需求!!同時他比上個人好一點,他記得改函數名,然后他改為了GetTypeBySerialId,這名字也很ok,一切也都看起來很好.但偏偏他漏掉了注釋,但代碼仍然運行的很ok,畢竟注釋可不受.net的元數據的支持,ide也不可能知道你這里犯了這么一個錯誤是吧!
      然后,接下來的場景大家很容易就可以聯想到,
      如果是細心的調用者:
      尼瑪!函數注釋讓我傳"產品id",但函數名和參數默認名字又是"SerialId"(流水號),這尼瑪鬧哪樣?
      如果是粗心的調用者呢?兩種情況唄:
      1.看了函數名字和默認參數名字 ,沒注意到注釋,ok,算這個粗心的小伙伴幸運,
      2.看了注釋,然后這小伙伴不認識SerialId這個單詞的意思. 然后,一個悲傷的故事就這么發生了!!
      其實我以上舉例的一些函數,都是功能比較具體,業務比較單純,也容易用幾個單詞描述.對于這些函數,我個人的意見是,完全不需要去寫注釋,
    有以下幾個原因:
      1.浪費精力去寫,
      2.調用的人需要把一段話讀兩遍(函數名和注釋)
      3.寫了還需要人去維護,(改了代碼,得同步去改注釋)
      4.如果強類型的參數傳遞不匹配,ide或者resharper插件會馬上指出你的錯誤,但如果注釋和代碼不匹配,則除了通過人力CodeReview,沒有其他任何辦法去找出這種錯誤.
      其中尤其是4,完全就是埋在項目中的地雷,除非你踩到了,不然很難排查.
      當然,如果是反之,邏輯復雜,甚至有調用的前置約束,那肯定該寫注釋還是得寫了.
      同時,這里還提一個觀點,注釋比代碼更有價值,因為代碼畢竟大部分還是在講怎么做(how do),而注釋是講做什么(do what)?抽象程度更高,對于比較復雜的代碼,如果有注釋,調用者一般都會優先去閱讀注釋,而不是去閱讀代碼,所以:輕易不寫注釋,但如果你寫了,請一定要對你的注釋負責,它比代碼更需要你的細心呵護!!
      好吧,我會說這篇文最大的作用,其實是可以讓我吐槽發泄一下么?
      我感覺自己現在就是在這種地雷坑里,天天過著提醒吊膽的日子.
      以上例子皆非我刻意編造,來源于工作中的真實經歷,只是稍作修飾,隱去了和業務有關的信息.
      根據回復的補充:
      相信很多博友有這樣的經歷,這個函數好復雜呀!我必須寫注釋啊,不然一段時間之后,我自己都看不明白了,
      有些時候是確實很復雜,但也有時候是設計的問題,這時候,寫注釋其實是一種逃避了.逃避你需要繼續深入思考這個函數的業務和功能的設計是否合理.
      其實我這標題還有第三個意思:
      在盡可能少寫注釋的前提下,如果一個函數的注釋仍然超過了2處,那么我認為這個函數的設計是有問題的.
      這個函數是否太大,是否是反模式里面提到的萬應靈或屠龍術?
      所以有時候說的 "因為業務復雜,很難用幾個單詞去描述,所以很難命名",就是如此.
      你的業務抽象粒度是否太大?導致一個業務模塊承擔了過多的業務.
      你是否把幾個流程放在了一個節點上?導致引入了額外的邏輯判斷甚至是多余的邏輯分支.
      如果是這樣,你想用幾個單詞來描述這么復雜的邏輯,當然是不可能了.
      這點我會在后續的重構系列里面談談我自己的理解.
      補充下自己的理解.
      我始終認為好的設計,大部分情況下,函數名就足以解釋它的功能,如果你遇到了兩三個單詞不能解釋函數功能的情況----說明你該分解函數了!
      比如一個大函數,OutPutMetaData,輸入是源數據路徑,使用的模板 返回解析之后的元數據
      流程大概是 采集數據->分析數據->匹配模板->生成MetaData
      代碼是大約1-2k行,如果寫在一個函數里面,當然也似可以的,但你想用注釋解釋清楚,必須在每個流程的關鍵節點寫注釋,遇到數據有前后關聯關系的,還得思維反復跳來跳去.
      但如果寫成下面這種模式的代碼,基本就像是閱讀英文說明(注釋),一樣閱讀代碼了
    public MetaData OutPutMetaData(string sourcePath, MetaTemplate template)
    {
    var metaDataFactory = new MetaDataFactory();
    if (!metaDataFactory.CheckInput(sourcePath))
    {
    throw new ErrorSourceException();
    }
    if (!metaDataFactory.TransformSourceData(template))
    {
    throw new ErrorFormatException();
    }
    return metaDataFactory.CreateMetaData();
    }
      這樣寫雖然多了很多的類和方法,還要額外定義一些中間數據的實體類型和自定義異常,但是經過合理的封裝和命名之后,整個結構非常清晰,定位錯誤和修改流程也方便.
      代碼閱讀速度基本和描述語句(注釋)的閱讀速度相當, 這就是代碼即注釋.
      最后總結:
      其實我認為最關鍵是要形成自己的編碼規范,這個"規范"不僅僅指的是狹義的命名規則和代碼格式,縮進,文件組織結構等.更關鍵的是,要形成一套有邏輯性,能自洽,有良性導向的一套思維模式,并時刻堅持遵守它,思考它,改進它.
      這套思維模式你可以自由的去擴展,只要不偏離它的中心思想.比如我給自己擴展的一些要求:
      1.函數一律使用動賓結構,如InitFactory,而不用FactoryInit,其實這兩者沒什么優劣,僅僅只是讓自己習慣,以后思考和閱讀自己代碼的時候,能更快的帶入過去的自己的思維,更快的理解自己的代碼,同時找api也能節約一點時間.
      2.html標簽樣式id小寫開頭,class大寫開頭,同理,其實也沒啥原因,就是個習慣.
      3.描述一個事物的時候要區分是what it is(名詞,形容詞)還是what it can do(動詞,動名詞,動賓短語)比如doClose, 是某個事物的動作,closing,和 closed則代表它的狀態
      再就是結構設計上的一些感覺了,這個比較抽象,不好用文字很準確的描述,大致意思就是我會從一些緯度對功能進行切分,access business viewModel show interaction 等,不一定都能分的非常清楚,也不強求一個區分度很高的邊際,但至少要有個模糊的定位.
      如果能長期堅持下來,以后閱讀自己的代碼是非常容易的,即使是沒有(少量)注釋.
      Ps:錘煉自己的這套思維模式的方法也很簡單,也就三點
      多看優秀代碼,自己動手多寫,多思考總結.

    posted on 2014-11-21 10:55 順其自然EVO 閱讀(258) 評論(0)  編輯  收藏 所屬分類: 測試學習專欄

    <2014年11月>
    2627282930311
    2345678
    9101112131415
    16171819202122
    23242526272829
    30123456

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲人成片在线观看| 亚洲最大激情中文字幕| 亚洲av乱码一区二区三区| 114级毛片免费观看| 亚洲黄色在线观看| 91短视频在线免费观看| 亚洲电影一区二区| 精品国产免费人成电影在线观看| 亚洲AV美女一区二区三区| 日本免费一区二区三区| 亚洲剧场午夜在线观看| 女人18一级毛片免费观看| 久久久久亚洲精品无码网址色欲| 免费无遮挡无码永久在线观看视频| 亚洲国产精品无码第一区二区三区| 国产精品另类激情久久久免费 | 久久亚洲精品AB无码播放| 男女午夜24式免费视频| 亚洲精品国产啊女成拍色拍| 免费a级毛片高清视频不卡| 亚洲国产成人精品无码区花野真一 | 18禁网站免费无遮挡无码中文| 2020国产精品亚洲综合网| 国产又大又粗又硬又长免费| 一级毛片大全免费播放下载 | 亚洲精品WWW久久久久久| 国内精品99亚洲免费高清| 亚洲视频免费观看| 日本高清免费不卡在线| 国产免费一区二区三区免费视频 | 国产精品成人无码免费| 国产真人无码作爱视频免费| 亚洲成人午夜电影| 亚洲国产精品碰碰| 99re免费在线视频| 国产亚洲精品仙踪林在线播放| 亚洲色成人中文字幕网站| 国产精品久久久久久久久久免费 | 国产一精品一aⅴ一免费| 亚洲免费人成在线视频观看| 国产成+人+综合+亚洲专|