日韩无码专区无码一级三级片|91人人爱网站中日韩无码电影|厨房大战丰满熟妇|AV高清无码在线免费观看|另类AV日韩少妇熟女|中文日本大黄一级黄色片|色情在线视频免费|亚洲成人特黄a片|黄片wwwav色图欧美|欧亚乱色一区二区三区

RELATEED CONSULTING
相關(guān)咨詢
選擇下列產(chǎn)品馬上在線溝通
服務(wù)時(shí)間:8:30-17:00
你可能遇到了下面的問題
關(guān)閉右側(cè)工具欄

新聞中心

這里有您想知道的互聯(lián)網(wǎng)營(yíng)銷解決方案
如何重構(gòu)一些可怕的代碼

最近,我不得不重構(gòu)一些處于粗糙狀態(tài)的代碼:

創(chuàng)新互聯(lián)網(wǎng)站建設(shè)提供從項(xiàng)目策劃、軟件開發(fā),軟件安全維護(hù)、網(wǎng)站優(yōu)化(SEO)、網(wǎng)站分析、效果評(píng)估等整套的建站服務(wù),主營(yíng)業(yè)務(wù)為網(wǎng)站設(shè)計(jì)制作、成都做網(wǎng)站,重慶App定制開發(fā)以傳統(tǒng)方式定制建設(shè)網(wǎng)站,并提供域名空間備案等一條龍服務(wù),秉承以專業(yè)、用心的態(tài)度為用戶提供真誠(chéng)的服務(wù)。創(chuàng)新互聯(lián)深信只要達(dá)到每一位用戶的要求,就會(huì)得到認(rèn)可,從而選擇與我們長(zhǎng)期合作。這樣,我們也可以走得更遠(yuǎn)!

 
 
 
 
  1. function endpoint(service, version = '') { 
  2.   let protocol 
  3.   let domain 
  4.  
  5.   if (service === 'webclient') { 
  6.     protocol = __CLIENT_PROTOCOL__ 
  7.     domain = `${__ENV__}-${service}.${__DOMAIN__}` 
  8.     if (__SERVER__) { 
  9.       protocol = 'http' 
  10.     } else if (__ENV__ === 'production') { 
  11.       domain = `www.${__DOMAIN__}` 
  12.     } 
  13.   } else { 
  14.     if (__ENV__ !== 'local') { 
  15.       if (__SERVER__) { 
  16.         protocol = 'http' 
  17.         domain = `${__ENV__}-${service}` 
  18.         domain += `.${__DOMAIN__}` 
  19.       } else { 
  20.         protocol = __CLIENT_PROTOCOL__ 
  21.         domain = `${__ENV__}-api.${__DOMAIN__}` 
  22.         if (service !== 'core') { 
  23.           domain += `/${service}` 
  24.         } 
  25.         if (version) { 
  26.           domain += `/${version}` 
  27.         } 
  28.       } 
  29.     } else { 
  30.       protocol = 'http' 
  31.  
  32.       if (service === 'core') { 
  33.         if (__CLIENT__) { 
  34.           domain = `api.${__DOMAIN__}` 
  35.         } else { 
  36.           domain = `api.${__DOMAIN__}:80` 
  37.         } 
  38.       } else { 
  39.         if (__CLIENT__) { 
  40.           domain = `api.${__DOMAIN__}/${service}/${version}` 
  41.         } else { 
  42.           domain = `api.${__DOMAIN__}:80/${service}/${version}` 
  43.         } 
  44.       } 
  45.     } 
  46.   } 
  47.  
  48.   const url = `${protocol}://${domain}` 
  49.  
  50.   return url 
  51.  
  52. export default endpoint 

上面的邏輯確定端點(diǎn)的URL,它取決于多種因素:您使用的服務(wù),在服務(wù)器或客戶端上呈現(xiàn)的服務(wù),在生產(chǎn)環(huán)境或測(cè)試環(huán)境中使用的服務(wù)等。

一段代碼變得如此混亂的原因之一是,當(dāng)我們忘記重復(fù)比錯(cuò)誤的抽象要便宜得多時(shí)。

好消息是,您可以應(yīng)用幾種簡(jiǎn)單的技術(shù)來(lái)簡(jiǎn)化嵌套的if-else語(yǔ)句。 壞消息是,這段代碼對(duì)應(yīng)用程序至關(guān)重要,因?yàn)樗姓?qǐng)求都在調(diào)用它。 哦,它也沒有經(jīng)過測(cè)試!

所以,這就是我重構(gòu)的方式…

1. 給該代碼100%的測(cè)試覆蓋率

我沒有執(zhí)行重構(gòu)代碼的任務(wù),所以打電話了。 但是我不知道要花多少時(shí)間(我本該用來(lái)交付其他東西的時(shí)間)。

重構(gòu)本身并不總是合理的。 但是,很難想象有人會(huì)抱怨增加測(cè)試范圍,尤其是在涵蓋如此關(guān)鍵的功能的情況下。 因此,我決定從此開始,不僅是為了讓我對(duì)重構(gòu)充滿信心,而且因?yàn)楫?dāng)我完成測(cè)試時(shí),我將更好地了解重構(gòu)的難度,并且我可以進(jìn)行/不進(jìn)行。 去打電話。

如今,我們大多數(shù)人都在Gousto中實(shí)踐TDD,但是代碼庫(kù)的這一特定部分是幾年前的,它的重要性和狀態(tài)阻礙了我和其他人在過去對(duì)其進(jìn)行重構(gòu)。

TDD的主要好處是無(wú)需擔(dān)心,也無(wú)需花費(fèi)成本即可進(jìn)行重構(gòu)-羅伯特·馬丁(Robert C. Martin,鮑勃叔叔)

我還想確保覆蓋率是100%,所以我使用了Jest標(biāo)志–coverage,它提供了以下輸出:

 
 
 
 
  1. -------------------|----------|----------|----------|----------|-------------------| 
  2. File               |  % Stmts | % Branch |  % Funcs |  % Lines | Uncovered Line #s | 
  3. -------------------|----------|----------|----------|----------|-------------------| 
  4.   ...              |      ... |      ... |      ... |      ... |                ...| 
  5.   endpoint.js      |      100 |      100 |      100 |      100 |                   | 
  6.   ...              |      ... |      ... |      ... |      ... |                ...| 
  7. -------------------|----------|----------|----------|----------|-------------------| 
  8. Test Suites: 1 passed, 1 total 
  9. Tests:       12 passed, 12 total 

2. 提取功能

現(xiàn)在我們有了測(cè)試,有了更多的信心,我們可以開始拆分代碼。 讓我們從頭開始。 我們看到,根據(jù)服務(wù),環(huán)境,客戶端/服務(wù)器端……為協(xié)議分配了不同的值,然后將其添加到函數(shù)末尾的其余url中。

 
 
 
 
  1. const url = `${protocol}://${domain}` 

因此,我們可以將確定協(xié)議的代碼抽象為自己的函數(shù),只需調(diào)用一次即可:

 
 
 
 
  1. import endpoint from 'config/endpoint' 
  2.  
  3. describe('endpoint.js', () => { 
  4.   global.__DOMAIN__ = 'gousto.local' 
  5.   let service 
  6.  
  7.   describe('when the service is "webclient"', () => { 
  8.     beforeEach(() => { 
  9.       service = 'webclient' 
  10.     }) 
  11.  
  12.     describe('and being in the server side', () => { 
  13.       beforeEach(() => { 
  14.         global.__SERVER__ = true 
  15.         global.__ENV__ = 'whateverenv' 
  16.       }) 
  17.  
  18.       test('an http address with the corresponding ENV, SERVICE and DOMAIN is returned', () => { 
  19.         const url = endpoint(service) 
  20.         expect(url).toBe(`http://${__ENV__}-${service}.${__DOMAIN__}`) 
  21.       }) 
  22.     }) 
  23.  
  24.     describe('and not being in the server side', () => { 
  25.       ... 
  26.       describe('and the environment is production', () => { 
  27.         ... 
  28.         test('an https address with "www" and without the service, but with the DOMAIN is returned', () => {...}) 
  29.       }) 
  30.  
  31.       describe('and the environment is not production', () => { 
  32.         ... 
  33.         test('an https address with the corresponding ENV, SERVICE and DOMAIN is returned', () => {...}) 
  34.       }) 
  35.     }) 
  36.   }) 
  37.  
  38.   describe('when the service is not "webclient"', () => { 
  39.     ... 
  40.     describe('and the env is not "local"', () => { 
  41.       ... 
  42.       describe('and being in the server side', () => { 
  43.         ... 
  44.         test('an http address with the corresponding ENV, SERVICE and DOMAIN is returned', () => {...}) 
  45.       }) 
  46.  
  47.       describe('and not being in the server side', () => { 
  48.         ... 
  49.         describe('and the service is core', () => { 
  50.           ... 
  51.           test('an https API address with the corresponding ENV and DOMAIN is returned', () => {...}) 
  52.  
  53.           describe('and a version was passed', () => { 
  54.             test('an https API address with the corresponding ENV, DOMAIN, SERVICE and VERSION is returned', () => {...}) 
  55.           }) 
  56.         }) 
  57.  
  58.         describe('and a version was passed', () => { 
  59.           test('an https API address with the corresponding ENV, DOMAIN, SERVICE and VERSION is returned', () => {...}) 
  60.         }) 
  61.  
  62.         describe('and a version was not passed', () => { 
  63.           test('an https API address with the corresponding ENV, DOMAIN and SERVICE is returned', () => {...}) 
  64.         }) 
  65.       }) 
  66.     }) 
  67.  
  68.     describe('and the env is "local"', () => { 
  69.       ... 
  70.       describe('and the service is core', () => { 
  71.         ... 
  72.         describe('and being in the client side', () => { 
  73.           ... 
  74.           test('an http API address with the corresponding DOMAIN is returned', () => {...}) 
  75.         }) 
  76.  
  77.         describe('and not being in the client side', () => { 
  78.           ... 
  79.           test('an http API address with the corresponding DOMAIN and port 80 is returned', () => {...}) 
  80.         }) 
  81.       }) 
  82.  
  83.       describe('and the service is not core', () => { 
  84.         ... 
  85.         describe('and being in the client side', () => { 
  86.           ... 
  87.           test('an http API address with the corresponding DOMAIN, SERVICE and VERSION is returned', () => {...}) 
  88.         }) 
  89.  
  90.         describe('and not being in the client side', () => { 
  91.           ... 
  92.           test('an http API address with the corresponding DOMAIN, port 80, SERVICE and VERSION is returned', () => {...}) 
  93.         }) 
  94.       }) 
  95.     }) 
  96.   }) 
  97. }) 

我們可以對(duì)URL的其余部分執(zhí)行與getProtocol()相同的操作。 提取的功能越多,if-else的地獄就越容易簡(jiǎn)化,提取剩余的內(nèi)容就越容易。 因此,我的建議是從最小的復(fù)雜度入手,因?yàn)檫@將使其余的操作更為簡(jiǎn)單。

提取這些函數(shù)并不復(fù)雜,但這是因?yàn)槲覍f-else的噩夢(mèng)翻譯成了它們。 因此,我們沒有大的混亂,但有一些小混亂。 不能接受 讓我們來(lái)照顧它。

3. 簡(jiǎn)化

除了關(guān)注點(diǎn)分離之外,將url的不同部分提取為不同功能的優(yōu)點(diǎn)是可以進(jìn)一步簡(jiǎn)化條件。 之前,URL的某些部分限制了簡(jiǎn)化,因?yàn)樗鼈冃枰獫M足多個(gè)條件。 現(xiàn)在,它們是分開的,所以我們不必為此擔(dān)心。

您可以只是出于對(duì)它的關(guān)注而進(jìn)行簡(jiǎn)化……或者您可以使用真值表來(lái)提供幫助。

對(duì)于getProtocol(),一種真值表如下所示:

但可以簡(jiǎn)化一下("-"表示該值無(wú)關(guān)緊要):

我們只有兩個(gè)可能的值:http和https,因此我們可以采用較少行(https)的值,檢查條件,然后返回另一個(gè)(http)。

 
 
 
 
  1. const getProtocol = (service, isServerSide, environment) => { 
  2.   if (service === 'webclient' && !isServerSide) { 
  3.     return 'https' 
  4.   } 
  5.    
  6.   if (service !== 'webclient' && !isServerSide && environment !== 'local') { 
  7.    return 'https'  
  8.   } 
  9.    
  10.   return 'http' 

這已經(jīng)比上一節(jié)中的要好。 但是我們?nèi)匀豢梢宰龈? 檢查前兩個(gè)條件,您可能會(huì)發(fā)現(xiàn)只有在我們不在服務(wù)器端時(shí)才獲得https。 因此,我們可以為http編寫第一個(gè)條件,并在函數(shù)的其余部分中擺脫isServerSide:

 
 
 
 
  1. const getProtocol = (service, isServerSide, environment) => { 
  2.   if (isServerSide) { 
  3.     return 'http' 
  4.   } 
  5.    
  6.   if (service === 'webclient') { 
  7.     return 'https' 
  8.   } 
  9.    
  10.   if (service !== 'webclient' && environment !== 'local') { 
  11.    return 'https'  
  12.   } 
  13.    
  14.   return 'http' 

不過,我們可以做得更好。 現(xiàn)在我們可以合并第二個(gè)和第三個(gè)條件,因?yàn)樗鼈冚^小:

 
 
 
 
  1. const getProtocol = (service, isServerSide, environment) => { 
  2.   ... 
  3.   if (service === 'webclient' ||  
  4.       (service !== 'webclient' && environment !== 'local')) { 
  5.     return 'https' 
  6.   } 
  7.   ... 

但是,請(qǐng)保持……這種狀況有點(diǎn)愚蠢,不是嗎? 如果服務(wù)是webclient,則條件為true。 否則……轉(zhuǎn)到OR的第二部分,為什么我們需要檢查服務(wù)是否不是webclient? 如果我們?cè)贠R的右側(cè),那么我們確定它不是webclient。 最終結(jié)果看起來(lái)很整潔,特別是與第2部分中的原始結(jié)果相比。提取功能:

 
 
 
 
  1. const getProtocol = (service, isServerSide, environment) => { 
  2.   if (isServerSide) { 
  3.     return 'http' 
  4.   } 
  5.  
  6.   if (service === 'webclient' || environment !== 'local') { 
  7.     return 'https' 
  8.   } 
  9.  
  10.   return 'http' 

結(jié)果

多虧了功能的提取,我們最終有了一個(gè)endpoint()函數(shù),這是我寫的榮幸。

 
 
 
 
  1. ... 
  2.  
  3. function endpoint(service, version = '') { 
  4.   const protocol = getProtocol(service, __SERVER__, __ENV__) 
  5.   const subdomain = getSubdomain(service, __SERVER__, __ENV__) 
  6.   const path = getPath(service, __SERVER__, __ENV__, version) 
  7.   const port = getPort(service, __ENV__, __CLIENT__) 
  8.  
  9.   return `${protocol}://${subdomain}.${__DOMAIN__}${port}${path}` 
  10.  
  11. export default endpoint 

上面代碼的get函數(shù)很小,足以被理解而不會(huì)動(dòng)您的大腦。 并非所有人都像我想要的那樣簡(jiǎn)單,但是它們比原始代碼要好得多。 您可以在這里看到文件的外觀。

最后,您應(yīng)該始終嘗試遵循以下規(guī)則:讓代碼比發(fā)現(xiàn)的要好。 盡管贊美?不要這么做

> GitHub comment in the PR

> A team mate making my day

現(xiàn)在輪到您了,您是否有任何想法使它變得更簡(jiǎn)單(無(wú)需更改在其余應(yīng)用程序中的使用方式)? 您對(duì)重構(gòu)的處理方式會(huì)有所不同嗎?


當(dāng)前標(biāo)題:如何重構(gòu)一些可怕的代碼
標(biāo)題路徑:http://www.5511xx.com/article/ccsiosp.html