<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          再見(jiàn),整潔代碼

          共 4533字,需瀏覽 10分鐘

           ·

          2021-02-01 22:24


          轉(zhuǎn)自:https://overreacted.io/zh-hans/goodbye-clean-code/

          那是一個(gè)深夜。

          我的同事們剛剛提交了過(guò)去整整一周所寫的代碼。我們正在開(kāi)發(fā)一個(gè)基于 Canvas 的圖形編輯器,他們負(fù)責(zé)實(shí)現(xiàn)各種“形狀”(比如:矩形、橢圓形)的縮放功能,縮放行為由拖拽“形狀”邊緣上的操作柄來(lái)實(shí)現(xiàn)。

          代碼運(yùn)行正常。

          但是代碼有些重復(fù)。每個(gè)“形狀”(如:矩形、橢圓形)各自擁有若干操作柄,從不同方向拖拽操作柄都會(huì)對(duì)“形狀”的位置和尺寸產(chǎn)生相應(yīng)的影響。如果用戶按住“Shift”鍵,我們還需要保持住“形狀”的寬高比不變。這里涉及到一些數(shù)學(xué)計(jì)算。

          代碼看起來(lái)是這樣的:

          let?Rectangle?=?{
          ??resizeTopLeft(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeTopRight(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeBottomLeft(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeBottomRight(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          };

          let?Oval?=?{
          ??resizeLeft(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeRight(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeTop(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeBottom(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          };

          let?Header?=?{
          ??resizeLeft(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeRight(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},??
          }

          let?TextBlock?=?{
          ??resizeTopLeft(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeTopRight(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeBottomLeft(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          ??resizeBottomRight(position,?size,?preserveAspect,?dx,?dy)?{
          ????//?10?repetitive?lines?of?math
          ??},
          };

          這種重復(fù)的數(shù)學(xué)計(jì)算邏輯,對(duì)我來(lái)說(shuō),真的難受。

          這不是“整潔”的代碼。

          多數(shù)的重復(fù)都在于“方向”上的相似,舉個(gè)例子,Oval.resizeLeft()Header.resizeLeft() 就很類似。這是因?yàn)椋鼈兌际窃谔幚硗献ё髠?cè)操作柄的問(wèn)題。

          另一個(gè)原因在于“形狀”所擁有的方法上的相似,例如,Oval.resizeLeft()Oval 上的其它方法是類似的。這是因?yàn)椋鼈兌际窃谔幚怼皺E圓形”上的問(wèn)題。更進(jìn)一步,Rectangle, Header 以及 TextBlock 都有相似的地方,因?yàn)槲谋究蚨际恰熬匦巍薄?/p>

          我有個(gè)辦法。

          我們可以通過(guò)對(duì)代碼邏輯進(jìn)行分組,來(lái)實(shí)現(xiàn)“去除全部重復(fù)”的目的:

          let?Directions?=?{
          ??top(...)?{
          ????//?5?unique?lines?of?math
          ??},
          ??left(...)?{
          ????//?5?unique?lines?of?math
          ??},
          ??bottom(...)?{
          ????//?5?unique?lines?of?math
          ??},
          ??right(...)?{
          ????//?5?unique?lines?of?math
          ??},
          };

          let?Shapes?=?{
          ??Oval(...)?{
          ????//?5?unique?lines?of?math
          ??},
          ??Rectangle(...)?{
          ????//?5?unique?lines?of?math
          ??},
          }

          然后,像這樣來(lái)組合它們:

          let?{top,?bottom,?left,?right}?=?Directions;

          function?createHandle(directions)?{
          ??//?20?lines?of?code
          }

          let?fourCorners?=?[
          ??createHandle([top,?left]),
          ??createHandle([top,?right]),
          ??createHandle([bottom,?left]),
          ??createHandle([bottom,?right]),
          ];
          let?fourSides?=?[
          ??createHandle([top]),
          ??createHandle([left]),
          ??createHandle([right]),
          ??createHandle([bottom]),
          ];
          let?twoSides?=?[
          ??createHandle([left]),
          ??createHandle([right]),
          ];

          function?createBox(shape,?handles)?{
          ??//?20?lines?of?code
          }

          let?Rectangle?=?createBox(Shapes.Rectangle,?fourCorners);
          let?Oval?=?createBox(Shapes.Oval,?fourSides);
          let?Header?=?createBox(Shapes.Rectangle,?twoSides);
          let?TextBox?=?createBox(Shapes.Rectangle,?fourCorners);

          代碼量減少到 1 / 2,并且,重復(fù)代碼不復(fù)存在!這真是“整潔”啊。如果我們希望改變具體某個(gè)“方向”上的或“形狀”上的行為,只需要修改一處,而非多處。

          已經(jīng)很晚了(我很疲憊了),我提交我重構(gòu)后的代碼,然后就躺下了,并對(duì)自己“幫助同事整潔代碼”而感到心滿意足。

          第二天上午

          … 事情并非我想的那樣。

          我的上級(jí)單獨(dú)找到了我,委婉地要求我撤銷昨天的那些修改。我感到很不可思議,舊代碼那么差勁,而我的是多么“整潔”啊!

          我那時(shí)只好謹(jǐn)遵照守;但是后來(lái),歷經(jīng)數(shù)年,我才明白他們的要求是對(duì)的。

          那是一個(gè)職業(yè)階段

          對(duì)“整潔代碼”的沉迷、好于“消除重復(fù)代碼”,是我們大多數(shù)開(kāi)發(fā)者都會(huì)經(jīng)歷的階段。當(dāng)我們對(duì)自己的代碼沒(méi)有信心,自我價(jià)值感和專業(yè)榮譽(yù)感往往會(huì)使我們與一些可測(cè)量的東西靠攏,一組嚴(yán)格的 lint 規(guī)則、一套命名規(guī)范、一種文件結(jié)構(gòu)、無(wú)重復(fù)性指標(biāo),等等。

          你不可能讓“重復(fù)代碼”自動(dòng)被消除,但是確實(shí)可以借助“實(shí)踐經(jīng)驗(yàn)”使它更可行。你往往可以看到,每次修改后的代碼量是變得更多或更少。結(jié)果就是,消除重復(fù)代碼看起來(lái)提高了代碼的某些客觀的可測(cè)量指標(biāo)。然而,糟糕的是,這擾亂了人們的自我認(rèn)知,他們會(huì)對(duì)自己說(shuō):“我是那種會(huì)寫出整潔代碼的人”,而這其實(shí)跟其它的自我欺騙行為沒(méi)什么兩樣。

          一旦學(xué)會(huì)了如何“抽象”,我們似乎就會(huì)更進(jìn)一步,每次看到重復(fù)的代碼,我們甚至能夠從“無(wú)”中發(fā)現(xiàn)可“抽象”的東西。編碼數(shù)年以后,我們已經(jīng)厲害得隨處都能看到重復(fù)的代碼,我們同時(shí)獲得了一項(xiàng)新的超能力:抽象。進(jìn)而,如果有人告訴我們“抽象是好的”,我們便對(duì)此更加篤信。于是我們開(kāi)始去批判那些不崇尚”整潔代碼”的人。

          我現(xiàn)在明白,我的那次“重構(gòu)行為”確實(shí)是一場(chǎng)災(zāi)難(譯者:夸張了吧~),從兩個(gè)方面來(lái)說(shuō):

          • 首先,我沒(méi)有告訴代碼的作者。我在沒(méi)有他們參入的情況下,重寫并提交了代碼。即便,那確是一次對(duì)代碼的“改善”(我現(xiàn)在不以為然了),它也十分可怕。一個(gè)健康的工程團(tuán)隊(duì)需要不斷地“建立彼此的信任”。不經(jīng)討論而擅自重寫同事的代碼,是對(duì)高效協(xié)作能力的徹底否定。
          • 其次,一切都需要權(quán)衡。為了減少重復(fù),我的代碼難于應(yīng)付需求變更,而這并不值得。例如,我們后邊需要為不同“形狀”上的各個(gè)操作柄添加特殊的行為邏輯。為了應(yīng)付這些,我的“抽象”無(wú)疑使修改困難了數(shù)倍,反觀那原本“骯臟的”代碼,它則能夠輕松處理。

          我的意思是你應(yīng)該寫“臟”的代碼嗎?不,我建議你深入思考一下“整潔”與“骯臟”分別意指何物。你有對(duì)于批判、正確、美和優(yōu)雅的直覺(jué)嗎?你如何能確定地說(shuō)你的這次工程成果達(dá)到了那些質(zhì)量指標(biāo)?它們?nèi)绾未_切地影響到代碼的產(chǎn)生與維護(hù)?

          我當(dāng)時(shí)確然對(duì)于這些問(wèn)題沒(méi)有進(jìn)行過(guò)深入思考;我當(dāng)時(shí)考慮的是代碼“看起來(lái)”如何,而不是代碼該如何隨著不斷流動(dòng)的團(tuán)隊(duì)而演進(jìn)。

          寫代碼是一場(chǎng)旅行。回想一下,你編寫第一行代碼時(shí)的情形,到現(xiàn)在你所處的狀態(tài)。我相信,當(dāng)突然發(fā)現(xiàn)“抽取出一個(gè)函數(shù)”或“重構(gòu)一個(gè)類的定義”是如何使問(wèn)題由復(fù)雜變得簡(jiǎn)單的時(shí)候,你必定是開(kāi)心的。一旦對(duì)自己的作品產(chǎn)生了自豪感,你就會(huì)熱切地去追求代碼的整潔。對(duì)此,你可以保持一段時(shí)間。

          但是不要止乎此,不要成為一個(gè)整潔代碼的狂熱分子。整潔代碼并不是目的,它只是讓我們從所面對(duì)系統(tǒng)的異常復(fù)雜性中解脫出來(lái)的方法。在你不是很明確一個(gè)改動(dòng)會(huì)如何影響到整個(gè)代碼庫(kù)時(shí),這信念可以作為一種安全防護(hù)機(jī)制。但是在未知的海洋里,你需要一個(gè)指南針。

          那就讓整潔代碼指引你吧,然后忘了它

          點(diǎn)贊和在看就是最大的支持??

          瀏覽 41
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  在线视频日韩欧美 | 无码一区二区三区四区五区六区 | 影音先锋无码一区 | 水蜜桃网站| 麻豆91久久久 |