1. <strong id="7actg"></strong>
    2. <table id="7actg"></table>

    3. <address id="7actg"></address>
      <address id="7actg"></address>
      1. <object id="7actg"><tt id="7actg"></tt></object>

        在大型項(xiàng)目中,如何去構(gòu)建高質(zhì)量的前端工程

        共 4711字,需瀏覽 10分鐘

         ·

        2021-01-04 03:58

        作者:ES2049

        來(lái)源:https://juejin.cn/post/6907178915664986120


        在過(guò)去,與大多數(shù)工程師一樣,我認(rèn)為前端代碼的設(shè)計(jì)水平大多與工程師的能力有直接關(guān)系。但隨著接手了幾個(gè)多人協(xié)作的大型前端項(xiàng)目,我開(kāi)始意識(shí)到,這種認(rèn)知對(duì)短生命周期的小型項(xiàng)目可能適用,但對(duì)真正的大型項(xiàng)目,僅靠提升工程師質(zhì)量有時(shí)并不能直接提升代碼的質(zhì)量。

        本文將結(jié)合自己的一些實(shí)際經(jīng)驗(yàn),來(lái)闡述自己的一個(gè)觀點(diǎn):構(gòu)建大型高質(zhì)量前端工程,合理的代碼約束與正確的團(tuán)隊(duì)運(yùn)轉(zhuǎn)機(jī)制可能更為重要。

        什么是高質(zhì)量的工程代碼?

        高質(zhì)量的工程代碼,?并不等價(jià)于性能最優(yōu),技術(shù)最新,復(fù)用性最強(qiáng)的技術(shù)選型?;仡檸啄昵暗那岸祟I(lǐng)域:JQuery 時(shí)代,雖然要手動(dòng)操作 DOM,但其實(shí)在那時(shí), Google Closure 和 Ext.js 團(tuán)隊(duì)就已經(jīng)提供了完整的組件化概念,甚至 Ext.js 還提供了組件冒泡這樣的創(chuàng)新事件機(jī)制。那時(shí)用 Zepto 維護(hù)的代碼,編碼速度甚至比現(xiàn)在寫(xiě)一些 React 項(xiàng)目還要快。不同的技術(shù)只是工具,怎么用工具,能把工具用到什么程度,最終取決于開(kāi)發(fā)者自身,所以高質(zhì)量的工程代碼,更多應(yīng)該從業(yè)務(wù)和工程的角度考慮問(wèn)題,而非技術(shù)選型。

        舉個(gè)例子,當(dāng)整個(gè)公司都在使用 React 開(kāi)發(fā)時(shí),雖然我們知道 Vue 使用可能會(huì)更簡(jiǎn)單便捷,但我們一定不會(huì)去用,因?yàn)檫@個(gè)時(shí)候,雖然看起來(lái)寫(xiě)代碼更簡(jiǎn)單了,但其他人在 React 方向沉淀的經(jīng)驗(yàn),你無(wú)法復(fù)用,額外還需要整個(gè)團(tuán)隊(duì)去學(xué)習(xí)一套全新的技術(shù),這樣的工程設(shè)計(jì),在這個(gè)背景下,顯然是不合理的。

        Thenewstack 做過(guò) 2019 年的開(kāi)發(fā)者數(shù)據(jù)統(tǒng)計(jì),開(kāi)發(fā)者 32% 的時(shí)間用于業(yè)務(wù)開(kāi)發(fā),19% 的時(shí)間在維護(hù)代碼,也就是工程師真正能投入到研發(fā)中的時(shí)間也只有工作時(shí)間的一半。對(duì)于開(kāi)發(fā)者來(lái)說(shuō),這個(gè)時(shí)候通過(guò)合理的代碼設(shè)計(jì),提升代碼的可擴(kuò)展性,可維護(hù)性,?降低開(kāi)發(fā)和維護(hù)代碼的時(shí)間,才是最強(qiáng)的訴求。

        所以,高質(zhì)量的工程代碼應(yīng)該是結(jié)合業(yè)務(wù)與團(tuán)隊(duì)情況,真正能夠提升研發(fā)效率,降低項(xiàng)目維護(hù)成本的代碼。

        誰(shuí)決定了工程代碼的質(zhì)量?

        這里可以用木桶理論來(lái)類(lèi)比:木桶中的水位,不取決于最高的木板,而取決于最低的木板。同理,前端工程的質(zhì)量,不取決于團(tuán)隊(duì)的平均能力,而取決于團(tuán)隊(duì)經(jīng)驗(yàn)較少的技術(shù)同學(xué)的能力。在工作壓力比較大的情況下,這些同學(xué)由于經(jīng)驗(yàn)不足,短期又要完成需求,所以很多時(shí)候,并沒(méi)有考慮過(guò)工程上的問(wèn)題,而是直接面向?qū)崿F(xiàn)功能編程,基本上我們現(xiàn)在面對(duì)的難以維護(hù)的代碼,都是在這種條件下產(chǎn)生的。

        我們當(dāng)然可以寄希望于經(jīng)驗(yàn)較少的同學(xué)通過(guò)不斷的成長(zhǎng)來(lái)提升項(xiàng)目的工程質(zhì)量,但實(shí)踐下來(lái),這并不可行。原因在于,工程能力的積累需要大量的編碼經(jīng)驗(yàn),缺少實(shí)踐經(jīng)驗(yàn)的問(wèn)題并不是短期就能夠迅速解決的,任何好的工程師都是在不斷犯錯(cuò)學(xué)習(xí)的過(guò)程中成長(zhǎng)起來(lái)的。同時(shí),工程開(kāi)發(fā)過(guò)程中很可能會(huì)遭遇人員變動(dòng),一個(gè)團(tuán)隊(duì)的成員不可能永遠(yuǎn)全部都是能力很強(qiáng)的。

        image.png

        那么我們就需要換一個(gè)策略來(lái)保障我們的代碼質(zhì)量,我們可以換個(gè)角度思考:是否可以通過(guò)一些規(guī)則,流程,編碼上的約束,讓編碼能力不同的工程師,盡量寫(xiě)出質(zhì)量相對(duì)較高的一致性代碼。

        通過(guò)約束提升工程質(zhì)量

        約束讓事情變得更簡(jiǎn)單

        工作沒(méi)有約束,工作中我們就難以形成共識(shí),也無(wú)法判斷工作做的好與壞。寫(xiě)代碼也是一樣的,沒(méi)有約束,那么我們也無(wú)法判斷代碼是否合理。在流行的庫(kù)和框架中,其實(shí)到處都是約束的影子,這里拿 Redux 和 React 的設(shè)計(jì)來(lái)舉例:

        image.png

        Redux 給出了單一數(shù)據(jù)源,State 只讀,使用純函數(shù)來(lái)執(zhí)行修改這三個(gè)基本原則,同時(shí)要求通過(guò) Action 的方式觸發(fā)Reducer 的執(zhí)行,這是 Redux 的約束;React 也給出了單向數(shù)據(jù)流這樣的約束概念。

        框架之所以是能夠復(fù)用,能夠得到推廣,就是因?yàn)樗鼈冞M(jìn)行了封裝,僅僅提供有限的約束能力供大家使用,這樣大家才能形成一致的理念,編寫(xiě)互相能夠讀得懂的代碼。理解了這一點(diǎn),我們?cè)賮?lái)看業(yè)務(wù)工程的代碼,實(shí)際上要提高開(kāi)發(fā)效率和擴(kuò)展性,無(wú)非也是要提供合理的約束。

        工程代碼的約束,更多帶有一定的工程屬性,如:

        • 規(guī)定相同的請(qǐng)求地址只允許在 API 層出現(xiàn)一次(項(xiàng)目接口數(shù)目多,可減少代碼冗余)
        • 不使用超過(guò) 100 行以上的 Hook 代碼(強(qiáng)化邏輯拆分,避免過(guò)度復(fù)雜的邏輯)
        • 在復(fù)用性和可維護(hù)性上做選擇時(shí),優(yōu)先選擇可維護(hù)性(避免錯(cuò)誤封裝,封裝代碼中耦合大量邏輯判斷)
        • 業(yè)務(wù)代碼注釋覆蓋率必須超過(guò) 10%(提升代碼可讀性,方便自動(dòng)化生成文檔)
        • 項(xiàng)目中跨組件通信必須通過(guò) Redux (降低組件傳值代碼的團(tuán)隊(duì)理解成本)
        • 相同功能的 npm 包不允許安裝多個(gè)(避免無(wú)用依賴(lài)安裝,造成維護(hù)成本增加)

        這些業(yè)務(wù)的約束,并不等同于 Eslint,不同的業(yè)務(wù)對(duì)代碼的要求有可能千差萬(wàn)別,所以業(yè)務(wù)上的約束,需要研發(fā)人員充分的溝通交流,碰撞探討,以及堅(jiān)決執(zhí)行。不同團(tuán)隊(duì)的同學(xué),可能討論出的結(jié)果完全不同,但約束的結(jié)論是什么本身不重要,重要的是形成一致的開(kāi)發(fā)共識(shí)。

        通過(guò)機(jī)制實(shí)現(xiàn)約束的落地

        約束本身并不難制定,對(duì)于工程側(cè)的設(shè)計(jì),工程師通過(guò)討論比較容易形成博奕后的結(jié)論。但機(jī)制的落地是相對(duì)困難的一環(huán)。這里分享幾個(gè)可執(zhí)行的保障機(jī)制:

        • CodeReview(每次CR,除了對(duì)業(yè)務(wù)進(jìn)行邏輯分析,也需要將是否遵循約束作為審核的一環(huán))
        • 通過(guò)工具自動(dòng)生成部分代碼(比如使用腳手架生成工程代碼中的某個(gè)模塊,類(lèi)似 AngularCLI 中 ng g component header 這樣的指令,就可以幫你約束組件創(chuàng)建的代碼結(jié)構(gòu))
        • 配置化生成代碼(通過(guò)配置,生成邏輯或者表單代碼,建立配置項(xiàng)標(biāo)準(zhǔn))
        • 零代碼 / PaaS 平臺(tái)(通過(guò)平臺(tái)生成代碼,直接將用戶(hù)與編碼隔離,由平臺(tái)保障生成代碼的質(zhì)量)
        • 負(fù)責(zé)人機(jī)制(約束落地直接與績(jī)效相關(guān)聯(lián),成為跟進(jìn)明確指標(biāo))
        • 沉淀文檔(通過(guò)文檔,沉淀約束機(jī)制)

        通過(guò)這樣的一些機(jī)制,保障約束有效的落地,那么我們就可以抹平團(tuán)隊(duì)成員技術(shù)能力的差異,形成一致性的編碼風(fēng)格。雖然這種約束下的代碼并不一定是最優(yōu)雅的代碼,但至少工程質(zhì)量不會(huì)差。所以這里我認(rèn)為,約束實(shí)際上幫助我們保障的是工程質(zhì)量的下限,那么接著我們來(lái)談如何通過(guò)技術(shù)創(chuàng)新,提升工程質(zhì)量的上限。

        在約束之上尋求創(chuàng)新

        大家可能會(huì)有這樣的問(wèn)題:“項(xiàng)目的約束,會(huì)不會(huì)限制技術(shù)的創(chuàng)新”。針對(duì)短生命周期的小型項(xiàng)目,這可能是對(duì)的,這種項(xiàng)目,使用更多的新技術(shù)進(jìn)行探索突破可能會(huì)帶來(lái)更多的團(tuán)隊(duì)技術(shù)儲(chǔ)備;但對(duì)于大型項(xiàng)目來(lái)說(shuō),我們每天所做的代碼設(shè)計(jì)決策,都可能會(huì)影響到明天業(yè)務(wù)系統(tǒng)的發(fā)展進(jìn)程,任何技術(shù)升級(jí)都一定要慎重,這時(shí)候,我們不應(yīng)該把約束當(dāng)作創(chuàng)新的阻礙,而應(yīng)該把約束當(dāng)作創(chuàng)新的練兵場(chǎng)。

        如果你在大型項(xiàng)目中,想突破約束,使用新技術(shù),進(jìn)行技術(shù)革新,那么一定意味著你要做到以下幾件事情:

        1. 對(duì)過(guò)去約束限制的背景有充分了解:背景沒(méi)有改變,新技術(shù)是否能解決約束所解決的問(wèn)題,同時(shí)不會(huì)帶來(lái)新的問(wèn)題
        2. 能夠充分表述新技術(shù)所能夠帶來(lái)的價(jià)值:在形成共識(shí)的問(wèn)題上,新技術(shù)是否能對(duì)性能,穩(wěn)定性,體驗(yàn),研發(fā)效率,業(yè)務(wù)提效有明顯作用
        3. 能夠給出技術(shù)升級(jí)的整體方案:在確認(rèn)要進(jìn)行技術(shù)升級(jí)時(shí),你是否考慮到歷史技術(shù)方案如何優(yōu)雅的實(shí)現(xiàn)替換
        4. 能夠說(shuō)服團(tuán)隊(duì)認(rèn)可新的技術(shù)升級(jí)方案:在當(dāng)前已有技術(shù)的基礎(chǔ)上,你是否能說(shuō)服團(tuán)隊(duì)成員和你一同推進(jìn)技術(shù)創(chuàng)新
        5. 能夠帶領(lǐng)團(tuán)隊(duì)或者自己將技術(shù)方案落地:你是否具備能力將新技術(shù)或者創(chuàng)新點(diǎn)完成落地

        很多時(shí)候,我們做的技術(shù)創(chuàng)新,其實(shí)只是技術(shù)棧的更新,并沒(méi)有為團(tuán)隊(duì)和業(yè)務(wù)側(cè)帶來(lái)任何的價(jià)值,但當(dāng)我們想清楚這些問(wèn)題,能夠有信服力的證明新技術(shù)或者創(chuàng)新點(diǎn)是有價(jià)值的時(shí)候,關(guān)于系統(tǒng)的升級(jí)可能才是真正有價(jià)值的。

        在約束上的創(chuàng)新,可以讓工程師結(jié)合業(yè)務(wù)有更多的思考,產(chǎn)出真正有價(jià)值的創(chuàng)新。而這些有質(zhì)量的思考和創(chuàng)新,決定了工程質(zhì)量的上限,?同時(shí)也會(huì)培養(yǎng)出更多優(yōu)秀的工程師。

        如何提升已有工程質(zhì)量?

        對(duì)于一個(gè)全新的大型項(xiàng)目,我們可以通過(guò)上述的方式,分階段進(jìn)行架構(gòu)設(shè)計(jì)和優(yōu)化。但是,大多數(shù)情況下,我們接手的項(xiàng)目,可能在接手時(shí)就會(huì)發(fā)現(xiàn)其工程質(zhì)量較低,那么我們應(yīng)該如何對(duì)已有代碼進(jìn)行改良呢?

        判斷你的系統(tǒng)是否需要改良

        一個(gè)系統(tǒng)的生命周期,可以總結(jié)為三個(gè)階段:

        • 發(fā)展期:業(yè)務(wù)發(fā)展迅速
        • 穩(wěn)定期:業(yè)務(wù)情況穩(wěn)定
        • 衰退期:業(yè)務(wù)逐漸關(guān)停并轉(zhuǎn)

        對(duì)于發(fā)展期的系統(tǒng)和穩(wěn)定期的系統(tǒng)來(lái)說(shuō),合理的工程設(shè)計(jì)未來(lái)能帶來(lái)的性能,穩(wěn)定性等方面的收益十分明顯,這個(gè)時(shí)候,我們可以考慮對(duì)系統(tǒng)進(jìn)行技術(shù)升級(jí)。而對(duì)于衰退期的系統(tǒng),雖然短期開(kāi)發(fā)維護(hù)效率不高,但無(wú)法看到未來(lái)系統(tǒng)的發(fā)展?jié)摿Γ@時(shí)候,繼續(xù)維護(hù)老系統(tǒng)可能是一個(gè)更好的選擇。并不是每一個(gè)系統(tǒng)都必須要改良,精益求精固然好,但是否要做還是要回歸到對(duì)業(yè)務(wù)價(jià)值的判斷上。

        如何進(jìn)行工程改進(jìn)

        大型項(xiàng)目的工程改良,可以分為兩種方式,自上而下,和自下而上。對(duì)于大型項(xiàng)目來(lái)說(shuō),自上而下的全部重構(gòu),成本很大,除非你對(duì)系統(tǒng)特別了解,否則并不推薦采用這種方法。相反,目前的主流框架,React, Vue 都是可以對(duì)局部 DOM 進(jìn)行托管的,所以自下而上的逐步升級(jí)可能是更好的策略,這種方法有兩個(gè)優(yōu)勢(shì):成本低,風(fēng)險(xiǎn)小。舉個(gè)自己工程中的例子,我們需要把 JQuery 升級(jí)至 React,采用了這種方式,逐層向上的對(duì) JQuery 中的 Backbone 代碼進(jìn)行替換:

        export?default?View.extend({
        ??componentName:?'AuctionDetailContainer',
        ??initialize(options)?{
        ????const?{?dataSchemaV1,?pageSchema?}?=?options;
        ????this.ref?=?React.createRef();
        ????this.dataSchemaV1?=?dataSchemaV1;
        ????this.children?=?pageSchema.getChildren()[0];
        ????this.attributes?=?pageSchema.getAttributes()?||?{};
        ??},

        ??render()?{
        ????ReactDOM.render((
        ??????<AuctionDetailContainerWithRef
        ????????ref={this.ref}
        ????????taskFields={this.dataSchemaV1}
        ????????attributes={this.attributes}
        ????????crossTableData={this.children}
        ??????/>

        ????),?this.$el[0]);
        ????return?this;
        ??},

        });

        每一次替換,我們只要測(cè)試替換部分的邏輯即可,不會(huì)影響外部的其他邏輯,這樣逐層替換,在保障穩(wěn)定性和系統(tǒng)升級(jí)的雙向要求下,做到了很好的平衡。同時(shí),在接手新項(xiàng)目的時(shí)候,這種升級(jí)的方法還可以逐步幫你梳理清楚業(yè)務(wù)的邏輯,了解業(yè)務(wù)。

        在這樣的逐步替換過(guò)程中,結(jié)合之前說(shuō)到的編碼約束,我們就可以將系統(tǒng)的代碼質(zhì)量逐步完成提升。而之后,則可以通過(guò)創(chuàng)新的方式,進(jìn)一步對(duì)項(xiàng)目?jī)?yōu)化完善,從而完成整個(gè)重構(gòu)過(guò)程。

        在這個(gè)過(guò)程中,有一些工具也可以幫助到我們,舉幾個(gè)例子:

        • CommintLint + SemVer 語(yǔ)義化版本號(hào)控制規(guī)范:幫助團(tuán)隊(duì)明確重構(gòu)可能帶來(lái)的風(fēng)險(xiǎn),節(jié)約溝通成本
        • 前端自動(dòng)化測(cè)試工具:通過(guò)單元測(cè)試保障工程質(zhì)量,降低回歸錯(cuò)誤產(chǎn)生概率
        • Chrome Coverage:代碼執(zhí)行情況分析工具,幫助你找到無(wú)用代碼,梳理項(xiàng)目邏輯

        結(jié)語(yǔ)

        本文涉及到的具體編碼內(nèi)容不多,希望從另一個(gè)方面能夠給你帶來(lái)一些工程測(cè)的啟發(fā)和思考,一些觀點(diǎn)沖突也歡迎大家溝通討論。

        The End

        點(diǎn)個(gè)『在看』支持下?

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

        手機(jī)掃一掃分享

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

        手機(jī)掃一掃分享

        分享
        舉報(bào)
        1. <strong id="7actg"></strong>
        2. <table id="7actg"></table>

        3. <address id="7actg"></address>
          <address id="7actg"></address>
          1. <object id="7actg"><tt id="7actg"></tt></object>
            成人毛片18女人毛片免费看3D动漫 | 91五月天 | 亚洲熟女一区二区 | 麻豆操逼| 一级特黄女人18毛片免费视频 | 成人7777| 销魂美女一级A片免费看 | 韩国黄色三级视频 | 欲色无码| 一级国产交换配乱婬hd视频 |