青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

隨筆-341  評論-2670  文章-0  trackbacks-0

上次有人來要求我寫一篇文章談談什么代碼才是好代碼,是誰我已經(jīng)忘記了,好像是AutoHotkey還是啥的專欄的作者。撇開那些奇怪的條款不談,靠譜的 代碼有一個共同的特點,就是DRY。DRY就是Don't Repeat Yourself,其實已經(jīng)被人談了好多年了,但是幾乎所有人都會忘記。

什么是DRY(Don't Repeat Yourself)

DRY 并不是指你不能復制代碼這么簡單的。不能repeat的其實是信息,不是代碼。要分析一段代碼里面的什么東西時信息,就跟給物理題做受力分析一樣,想每次 都做對其實不太容易。但是一份代碼總是要不斷的修補的,所以在這之前大家要先做好TDD,也就是Test Driven Development。這里我對自己的要求是覆蓋率要高達95%,不管用什么手段,總之95%的代碼的輸出都要受到檢驗。當有了足夠多的測試做后盾的時 候,不管你以后發(fā)生了什么,譬如說你發(fā)現(xiàn)你Repeat了什么東西要改,你才能放心大膽的去改。而且從長遠的角度來看,做好TDD可以將開發(fā)出相同質(zhì)量的代碼的時間縮短到30%左右(這是我自己的經(jīng)驗值) 。

什么是信息

信息這個詞不太好用語言下定義,不過我可以舉個例子。譬如說你要把一個配置文件里面的字符串按照分隔符分解成幾個字符串,你大概就會寫出這樣的代碼:

// name;parent;description
void ReadConfig(const wchar_t* config)
{
    auto p 
= wcschr(config, L';');                            // 1
    if(!p) throw ArgumentException(L"Illegal config string"); // 2
    DoName(wstring(config, p));                               // 3
    auto q = wcschr(p + 1, L';');                             // 4
    if(!q) throw ArgumentException(L"Illegal config string"); // 5
    DoParent(wstring(p + 1, q);                               // 6
    auto r = wcschr(q + 1, L';');                             // 7
    if(r) throw ArgumentException(L"Illegal config string");  // 8
    DoDescription(q + 1);                                     // 9
}

這段短短的代碼重復了多少信息?

  • 分隔符用的是分號(1、4、7)
  • 第二/三個片段的第一個字符位于第一/二個分號的后面(4、6、7、9)
  • 格式檢查(2、5、8)
  • 異常內(nèi)容(2、5、8)

除了DRY以外還有一個問題,就是處理description的方法跟name和parent不一樣,因為他后面再也沒有分號了。

那這段代碼要怎么改呢?有些人可能會想到,那把重復的代碼抽取出一個函數(shù)就好了:

wstring Parse(const wchar_t& config, bool end)
{
    auto next 
= wcschr(config, L';');
    ArgumentException up(L
"Illegal config string");
    
if (next)
    {
        
if (end) throw up;
        wstring result(config, next);
        config 
= next + 1;
        
return result;
    }
    
else
    {
        
if (!end) throw up;
        wstring result(config);
        config 
+= result.size();
        
return result;
    }
}

// name;parent;description
void ReadConfig(const wchar_t* config)
{
    DoName(Parse(config, 
false));
    DoParent(Parse(config, 
false));
    DoDescription(Parse(config, 
true));
}

是不是看起來還很別扭,好像把代碼修改了之后只把事情搞得更亂了,而且就算config對了我們也會創(chuàng)建那個up變量,就僅僅是為了不 重復代碼。而且這份代碼還散發(fā)出了一些不好的味道,因為對于Name、Parent和Description的處理方法還是不能統(tǒng)一,Parse里面針對 end變量的處理看起來也是很重復,但實際上這是無法在這樣設計的前提下消除的。所以這個代碼也是不好的,充其量只是比第一份代碼強一點點。

實 際上,代碼之所以要寫的好,之所以不能repeat東西,是因為產(chǎn)品狗總是要改需求,不改代碼你就要死,改代碼你就要加班,所以為了減少修改代碼的痛苦, 我們不能repeat任何信息。舉個例子,有一天產(chǎn)品狗說,要把分隔符從分號改成空格!一下子就要改兩個地方了。description后面要加tag! 這樣你處理description的方法又要改了因為他是以空格結尾不是0結尾。

因此針對這個片段,我們需要把它改成這樣:

vector<wstring> SplitString(const wchar_t* config, wchar_t delimiter)
{
    vector
<wstring> fragments;
    
while(auto next = wcschr(config, delimiter))
    {
        fragments.push_back(wstring(config, next));
        config 
= next + 1;
    }
    fragments.push_back(wstring(config));
    
return fragments; // C++11就是好!
}

void ReadConfig(const wchar_t* config)
{
    auto fragments 
= SplitString(config, L';');
    
if(fragments.size() != 3)
    {
        
throw ArgumentException(L"Illegal config string");
    }
    DoName(fragments[
0]);
    DoParent(fragments[
1]);
    DoDescription(fragments[
2]);
}

我們可以發(fā)現(xiàn),分號(L';')在這里只出現(xiàn)了一次,異常內(nèi)容也只出現(xiàn)了一次,而且處理name、parent和 description的代碼也沒有什么區(qū)別了,檢查錯誤也更簡單了。你在這里還給你的Library增加了一個SplitString函數(shù),說不定在以 后什么地方就用上了,比Parse這種專門的函數(shù)要強很多倍。

大家可以發(fā)現(xiàn),在這里重復的東西并不僅僅是復制了代碼,而是由于你把 同一個信息散播在了代碼的各個部分導致了有很多相近的代碼也散播在各個地方,而且還不是那么好通過抽成函數(shù)的方法來解決。因為在這種情況下,就算你把重復 的代碼抽成了Parse函數(shù),你把函數(shù)調(diào)用了幾次實際上也等于重復了信息。因此正確的方法就是把做事情的方法變一下,寫成SplitString。這個 SplitString函數(shù)并不是通過把重復的代碼簡單的抽取成函數(shù)而做出來的。去掉重復的信息會讓你的代碼的結構發(fā)生本質(zhì)的變化

這個問題其實也有很多變體:

  • 不能有Magic Number。L';'出現(xiàn)了很多遍,其實就是個Magic Number。所以我們要給他個名字,譬如說delimiter。
  • 不要復制代碼。這個應該不用我講了。
  • 解耦要做成正交的。SplitString雖然不是直接沖著讀config來寫的,但是它反映了一個在其它地方也會遇到的常見的問題。如果用Parse的那個版本,顯然只是看起來解決了問題而已,并沒有給你帶來任何額外的效益。

信息一旦被你repeat了,你的代碼就會不同程度的出現(xiàn)各種腐爛或者破窗,上面那三條其實只是我能想到的比較常見的表現(xiàn)形式。這件事情也告訴我們,當高手告訴你什么什么不能做的時候,得想一想背后的原因,不然跟封建迷信有什么區(qū)別。

posted on 2014-07-15 06:44 陳梓瀚(vczh) 閱讀(15901) 評論(9)  編輯 收藏 引用 所屬分類: 啟示

評論:
# re: 靠譜的代碼和DRY[未登錄] 2014-07-16 04:23 | 煙圈
vally vally god   回復  更多評論
  
# re: 靠譜的代碼和DRY[未登錄] 2014-07-18 02:02 | korall
提供機制優(yōu)先于提供功能  回復  更多評論
  
# re: 靠譜的代碼和DRY 2014-07-20 10:33 | cymheart
當需求不同時,實現(xiàn)同樣功能的代碼算法也可能是不同的。
如果需求上一開始就強調(diào)config文件中哪些字符會變動,算法設計上肯定要做到對應。如果需求不明,也只能簡單的用博主所說的第一段代碼了。

  回復  更多評論
  
# re: 靠譜的代碼和DRY 2014-08-10 19:33 | 飛奔吧少年
各種都真不錯!  回復  更多評論
  
# re: 靠譜的代碼和DRY 2014-08-10 19:34 | 飛奔吧少年
主頁真不錯!  回復  更多評論
  
# re: 靠譜的代碼和DRY 2014-08-31 22:51 | 清醒瘋子利炳根
反復看了幾遍,看明白了:)集中在一個地方調(diào)用處理,優(yōu)于分散在不同的地方來調(diào)用。

不單單是把代碼抽取出來建立子程,子程里的實現(xiàn)也要不重復:)

第三個例程的代碼,確實要比第二個那樣的把子程作為參數(shù)調(diào)用的,好很多  回復  更多評論
  
# re: 靠譜的代碼和DRY 2015-01-13 06:08 | 男人沒錢
DRY的說法很靠譜,我的看法是“做任何事情之前,先減少心智負載”,就是把那些可以簡化掉的行為變成一個接口,以后來了類似的需求,只需要往這個接口里一扔就好了。希望vczh多給我們普及一些簡單易懂的東西。。  回復  更多評論
  
# re: 靠譜的代碼和DRY 2015-03-01 02:51 | ivy
感覺是借用了vb的概念呀  回復  更多評論
  
# re: 靠譜的代碼和DRY 2015-03-05 22:38 | sptt
感同身受~  回復  更多評論
  
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            一区二区三区视频在线播放| 日韩一区二区电影网| 午夜精品区一区二区三| 亚洲高清不卡一区| 欧美 日韩 国产精品免费观看| 午夜视频一区| 久久久激情视频| 欧美成人精品一区二区三区| 葵司免费一区二区三区四区五区| 久久视频在线免费观看| 老司机免费视频久久| 欧美成人精品h版在线观看| 欧美国产国产综合| 91久久香蕉国产日韩欧美9色 | 亚洲午夜精品一区二区三区他趣 | 伊人狠狠色j香婷婷综合| 激情六月婷婷久久| 91久久精品日日躁夜夜躁欧美| 日韩视频一区二区三区在线播放 | 亚洲精品在线看| 亚洲免费在线播放| 久久理论片午夜琪琪电影网| 久久亚洲欧美| 亚洲毛片在线观看.| 狂野欧美性猛交xxxx巴西| 亚洲国产精品电影| 在线日本欧美| 美国十次成人| 欧美网站在线| 激情国产一区| 亚洲一区影音先锋| 久久久综合网站| 亚洲美女中文字幕| 欧美一区激情视频在线观看| 欧美福利一区二区三区| 欧美一区二区三区精品电影| 久久婷婷国产麻豆91天堂| 欧美日韩xxxxx| 黄色一区二区三区四区| aa级大片欧美| 欧美a级一区| 午夜精品区一区二区三| 欧美日韩色婷婷| 亚洲国产美女精品久久久久∴| 性欧美video另类hd性玩具| 亚洲高清不卡一区| 久久视频在线免费观看| 国产日韩欧美综合| 亚洲午夜精品一区二区三区他趣| 嫩模写真一区二区三区三州| 亚洲免费在线看| 国产精品九九久久久久久久| 最新日韩精品| 欧美va亚洲va日韩∨a综合色| 亚洲亚洲精品在线观看| 欧美日本高清一区| 亚洲精品在线观| 91久久精品视频| 蜜臀久久99精品久久久久久9 | 欧美区二区三区| 亚洲高清视频在线| 麻豆成人精品| 一区二区三区久久精品| 欧美成人一区二区| 久久国内精品自在自线400部| 欧美日韩精品欧美日韩精品| 91久久精品国产91久久| 欧美成人一区二区三区在线观看 | 一区二区视频欧美| 久久久久久久综合色一本| 亚洲视频专区在线| 亚洲精品国产精品国自产在线| 欧美伊久线香蕉线新在线| 国产日本欧洲亚洲| 欧美在线观看一区| 欧美一区二区三区婷婷月色| 国内在线观看一区二区三区| 久久嫩草精品久久久精品| 久久精品国产99国产精品| 午夜影视日本亚洲欧洲精品| 欧美精品不卡| 亚洲欧美另类在线| 香蕉国产精品偷在线观看不卡| 国产原创一区二区| 亚洲国产mv| 欧美亚洲不卡| 久久久久久**毛片大全| 欧美 日韩 国产一区二区在线视频| 日韩亚洲综合在线| 亚洲一区二区黄色| 一色屋精品视频在线观看网站| 亚洲国产精品va在线看黑人| 欧美视频手机在线| 久久久久久一区二区| 久久理论片午夜琪琪电影网| 亚洲另类一区二区| 一区二区高清视频| 国产亚洲综合性久久久影院| 久久亚洲国产成人| 欧美午夜免费影院| 欧美在线观看网址综合| 久久久久久电影| 亚洲久久一区| 亚洲天堂av图片| 国产在线精品成人一区二区三区| 亚洲黄色三级| 欧美精品在线一区| 亚洲欧美bt| 欧美一区二区在线播放| 在线观看视频一区二区| 亚洲精品日韩综合观看成人91| 久久夜色精品国产| 欧美在线免费一级片| 久久久免费观看视频| 99精品国产高清一区二区 | 欧美精品一区三区| 亚洲欧美日韩国产一区二区| 一本久久综合亚洲鲁鲁| 国产亚洲一区二区三区在线播放 | 欧美三日本三级少妇三99| 亚洲欧美视频在线观看| 久久久久久穴| 亚洲欧美电影在线观看| 欧美精品亚洲一区二区在线播放| 午夜精品影院在线观看| 久久久精品免费视频| 中文高清一区| 免费视频最近日韩| 欧美在线亚洲| 久久精品人人做人人爽| 久久精品亚洲一区二区| 欧美精品亚洲精品| 久久亚洲一区二区三区四区| 欧美日韩成人综合| 欧美aⅴ一区二区三区视频| 国产精品家庭影院| 亚洲日本中文字幕免费在线不卡| 欧美日韩在线免费视频| 久久激情五月丁香伊人| 亚洲一区二区三区在线播放| 久久婷婷久久| 久久综合伊人| 国产午夜精品久久| 亚洲午夜av在线| 亚洲免费观看高清完整版在线观看| 亚洲综合国产| 一区二区三区国产精华| 亚洲午夜在线视频| 久久久久久91香蕉国产| 欧美一区二区三区啪啪| 欧美日韩综合| 国产精品美女在线观看| 亚洲电影欧美电影有声小说| 亚洲第一免费播放区| 国产在线观看精品一区二区三区 | 亚洲激情午夜| 亚洲精品精选| 美国成人直播| 欧美在线视频观看| 一区二区在线看| 久久黄金**| 免费日韩av| 亚洲国产精品电影| 老司机精品视频网站| 亚洲一区二区三区中文字幕| 国产欧美日韩视频一区二区三区| 一区二区三区日韩欧美| 亚洲一区视频在线观看视频| 欧美视频成人| 亚洲综合999| 久久福利视频导航| 国产日韩免费| 久久久欧美精品| 欧美韩日亚洲| 欧美一区二区精品在线| 国产一区二区三区网站| 欧美一级视频精品观看| 久久久久久久久久久一区| 尤物九九久久国产精品的特点| 免费高清在线一区| 亚洲高清久久| 欧美另类videos死尸| 亚洲欧美美女| 久久一区中文字幕| 亚洲日本视频| 中文一区二区| 久久久久天天天天| 亚洲精品1区| 欧美日韩成人激情| 欧美亚洲视频| 亚洲国产网站| 欧美一区二区免费观在线| 伊人狠狠色j香婷婷综合| 久久综合久久综合久久综合| 亚洲美女黄网| 久久视频国产精品免费视频在线| 亚洲国产成人久久| 国产精品福利片| 亚洲一区美女视频在线观看免费| 欧美激情一区二区三区|