重構老項目所悟


重構老項目所悟

0x01

6月份的那個時候,剛進ThoughtWorks不久,工作上也沒有太多的事情,然后就天真的以為在騷窩的節奏應該一直就是這樣的吧,所以,便給接下來的幾個月定了一些小目標,其中就包括整理github已提交代碼,因為github上的東西真的太老了。可沒想到接下來的幾個項目以及北京Nodejs社區的事情讓我基本沒啥時間來做這些小目標了..

前兩天,正好前端入門級的朋友來找我取經,我就在我的repo里面找了一個能跑起來且適合他的項目推薦給他。雖然我將這個項目給他了,可這樣的項目拿出去我是會臉紅的,所以改造開始了..

0x02

首先,我加上了README。README基本的功能是告訴來訪者這個項目做了什么,以及如何工作的。當然一個比較完善的README一般會包括如下部分:

  • Installation
  • Example/Usage/Quickstart/Getting Started
  • Features
  • FAQ
  • API References/Docs/Community
  • Tests
  • contributing
  • contributors
  • License

差不多就這些了,然后剩下的一般是專屬該項目的部分了。

gitignore

有了README之后,發現這個項目還沒有.gitignore!gitignore可是保證項目干凈的利器啊,於是立馬給加上了。gitignore怎么用,已經寫過一篇文大概介紹了,有興趣可以看看。這里,我再說說,項目里面,一般什么東西是不應該被push的。中心思想就是,項目的外部依賴庫都是不應該被push到repository的。為什么呢?因為這種外部依賴庫都是與我們項目沒有關系的獨立庫,我們可以把它們看作是工具庫里面的一種工具,我們的項目只是使用了該工具,但是這個工具的源代碼跟咱們項目的源代碼是不應該在一個代碼倉庫的。正好,我這次重構的項目就是一個很好的例子。在這個項目里面的dist文件夾里面有着Bootstrap和jQuery的源碼,他們是應該被提交到這里的。那么我們應該怎么做呢?方法比較多,這里介紹兩個。第一個,我們現在的npm庫很強大了,基本該有的都有了,Bootstrap和jQuery都有,我們可以通過npm安裝它們,然后在需要用到的地方引用。第二,不想用npm,當然也可以用bower這樣的工具來下載,這東西主要就是Web端的包管理工具,bower install 下載的package默認會安裝在bower_components文件夾下面,當然我們也可以通過.bowerrc文件來指定安裝的目錄。不過,在npm一統天下的今天,bower使用的場景真是越來越少了。ok,我們來總結一下哪些文件是gitignore的常客吧。

  • node_modules

這個就不多做解釋了,里面都是外部依賴庫

  • dist/build

這個一般是打包之后的資源文件夾,對於前端項目來說,這個文件夾內的東西一般是可以直接丟到Nginx里被代理了。

  • coverage

這個一般是在運行項目測試覆蓋率的時候生成的文件夾,在里面我們能看到整個項目和各個文件的測試覆蓋率。

  • log/*.log

這里一般是項目運行時記錄的日志文件

  • typings

該文件夾為我們在使用typescript的時候所需要的各種類型的聲明的地方。

0x03

接下來就是源代碼了。代碼,在可用的前提下首先應該是整潔干凈的,這樣才會讓自己寫的舒心,讓他人看的省心。所以,我清理了注釋代碼,無效的文件以及debug的console。接下來,就是代碼質量了。畢竟過去快兩年了,看當年的東西覺得到處都是問題。

我們先來看一段代碼,

 1 function judge_exist_barcode(item, promote) {
 2   var judge_bar;
 3   _.each(promote, function (pro) {
 4     judge_bar = _.find(pro.barcodes, function (p) {
 5       if (p == item.barcode) {
 6         return p;
 7       }
 8     });
 9   });
10   return judge_bar != undefined
11 }

 

問題挺多的,咱一個一個的看。

函數名

首先,這個函數的名字是judge_exist_barcode,然后看到返回值是一個Boolean值,再結合兩個參數可以判斷出這個方法的主要功能是要判斷傳入的參數的barcode是否能在另一個對象中找到。當一個函數的返回值或者變量的值的類型是Boolean的時候,我們一般傾向於用 ishasshould等詞來開頭,因為這樣更表意,比如,如果把這里的judge如果換成has是不是就更好了。最后我們在根據函數的功能給它取一個新的名字,has_promotional_barcode,這個名字是不是就棒多了啊 :)

邏輯

這里的代碼邏輯比較簡單,一眼就能看出來是做了什么。首先,promote是一個可迭代對象,使用underscore的each方法遍歷promote,然后在promote的每一個子對象的barcodes中查找是否有和傳入參數對象item的barcode相等的值,如果有,就給預先定義好的一個標識judge_bar賦值。那么,一句話總結一下這個功能,查詢item對象的barcode是否有在promote的子對象的barcodes中出現。清楚了邏輯之后,再看看代碼,便知道這個judge_bar變量名是一定有問題的,然后再看看each和find方法,能夠看出作為新手對underscore/lodash提供的接口不夠了解。

ps: 所以,這里我建議,剛接觸這個工具庫的朋友可以先把他們的文檔快速、完整的瀏覽一遍,大概知道了它提供了哪些工具方法,這樣在工作中遇到也能夠快速查文檔來使用。這里我推薦使用Lodash,為什么呢?因為lodash在一定程度上有更優秀的性能,提供更多的工具和更快的更新,如果你想了解更多,可以自己嘗試測試他們,或者來這里找找答案。

查詢一個值是否存在於另一個對象中我們可以用.some或者.includes,前者是對可迭代對象的子對象進行匹配校驗,用於對象之類的匹配或者key值校驗,支持identity function;后者也是對可迭代對象的子元素進行校驗,不支持identity,用於value值校驗。再加上我們對context的理解,原代碼就能夠重構成這樣

1 function has_promotional_barcode(item, promotions) {
2   return _.some(promotions, function (promotion) {
3       return _.include(promotion.barcodes, item.barcode);
4   });
5 }

 

首先,行數的縮減是最直觀的感受,其次,語義上沒有損失,可以像閱讀課文一樣容易的來理解。那么,重構到這里就結束了嗎?

0x04

重構其實才剛剛開始。正確的重構方式,應該是先為現有代碼加上測試。這樣,我們才能夠安心的去重構,不必擔心因為自己的重構而導致代碼的行為與之前的有不一致情況。所以,前面提到過的TDD,不就可以抓起來了嘛 :)

ps: 新年新氣象[Yeah!]


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM