摘要:代碼寫得是否整潔是客觀的,是的人或后期維護(hù)的人覺得好才是真的好。三代碼設(shè)計原則要想寫出優(yōu)雅整潔的代碼,就要遵循特定的設(shè)計原則。
歡迎關(guān)注我的公眾號睿Talk,獲取我最新的文章:
最近在做一些項目重構(gòu)的工作,看了不少臟亂差的代碼,身心疲憊。本文將討論如何編寫整潔的代碼,不求高效運(yùn)行,只求可讀性強(qiáng),便于維護(hù)。
二、為什么要寫簡潔的代碼作為一個合格的程序員,寫出簡潔的代碼是基本的職業(yè)素養(yǎng)。相信絕大部分的程序員都不會故意寫惡心代碼的,無論是對自己或者對別人都沒有任何好處。那么,是什么阻礙我們寫出優(yōu)秀代碼呢?有下面這么幾種可能性:
時間緊任務(wù)重,沒那么多時間考慮代碼設(shè)計
偷懶圖方便,不過腦子機(jī)械式的寫代碼
注意力只集中在功能的實現(xiàn),不考慮后期的維護(hù)成本
知識儲備不夠,不知道怎樣寫出優(yōu)雅的代碼
出來混遲早要還的,無論是上述哪種原因,混亂代碼一旦被寫出來,代碼作者肯定是要為其買單的,只是買單的方式會各有不同??赡苁呛笃诰S護(hù)的時候邊改邊抽自己,也可能是別人改代碼的時候邊改邊罵你傻x。
那么,代碼寫好了會有什么好處呢?起碼有以下幾方面:
后期維護(hù)更高效,無論是改 bug 還是新增功能,無論是自己改還是別人改
后期更少的加班
思考如何編寫整潔代碼的過程中,技術(shù)能力會隨之提高
寫出優(yōu)雅的代碼,會更有成就感,更熱愛自己的工作
別人看到這么優(yōu)雅的代碼,會贊不絕口,個人影響力會放大
既然有這么多好處,那到底怎么評判代碼寫得好不好呢?是自己覺得好就是好嗎?顯然不是。代碼寫得是否整潔是客觀的,是 code review 的人或后期維護(hù)的人覺得好才是真的好。所以加強(qiáng) code review 也是倒逼寫出優(yōu)秀代碼的一種方式。
個人認(rèn)為代碼的優(yōu)秀程度分以下幾個層次:
程序能正常運(yùn)行
異常情況有應(yīng)對方法
簡單明了,易于后期維護(hù)
團(tuán)隊成員間能高效協(xié)作
能高性能運(yùn)行
層次越高,難度越大,挑戰(zhàn)越大。作為一個有追求的程序員,我們應(yīng)該不斷突破自己的邊界,追求卓越,更上一層樓。
三、代碼設(shè)計原則要想寫出優(yōu)雅整潔的代碼,就要遵循特定的設(shè)計原則。透徹理解這些原則后,還要結(jié)合具體的項目落地,不斷的練習(xí)和重構(gòu)。下面總結(jié)出的一些通用原則供參考。
KISS(keep it simple, stupid)
業(yè)務(wù)邏輯要直截了當(dāng),不要引入各種依賴,多層次調(diào)用。以 React 為例,常見的錯誤是將props在state里存一份,計算的時候再從state中取。這樣帶來的問題是要時刻監(jiān)聽props的變化,然后再同步到state中。這完全是多此一舉,直接用props進(jìn)行計算即可。
// bad componentWillReceiveProps(nextProps) { this.setState({num: nextProps.num}); } render() { return({this.state.num * 2}); } /***************************/ // good render() { return({this.props.num * 2}); }
DRY (don’t repeat yourself)
不用做機(jī)械式的復(fù)制粘貼,要鍛煉自己抽象的能力,盡量將通用的邏輯抽象出來,方便日后重用。
Open/Closed (open to extension but closed to modification)
代碼要對擴(kuò)展開放,對修改封閉。盡量做到在不修改原有代碼的基礎(chǔ)上,增加新的功能。React 的容器組件和展示組件分離用的就是這種思想。當(dāng)數(shù)據(jù)來源不同的時候,只需要修改或新增容器組件,展示組件維持不變。
function Comp() { ... } class ContainerComp extends PureComponent { async componentDidMount() { const data = await fetchData(); this.setState({data}); } render() { return (); } }
從架構(gòu)層面說,微內(nèi)核架構(gòu)也是遵循這一設(shè)計原則。它能保證核心模塊不變的情況下,通過插件機(jī)制為系統(tǒng)賦予新的能力。我們常用的 Webpack 就是一個很好的例子,它通過引入 loader 和 plugin 的機(jī)制,極大的擴(kuò)展了其文件處理的能力。
Composition > Inheritance
首先說一下類這個概念。本質(zhì)上來說,定義類就是為了代碼的復(fù)用,對于需要同時創(chuàng)建多個對象實例的情況下,這種設(shè)計模式是非常有效的。比如說連接池中就需要同時存在多個連接對象,方便資源復(fù)用。而對于前端來說,絕大部分的業(yè)務(wù)場景都是單例,這種情況下通過定義工具函數(shù),或者直接使用對象字面量會更加高效。工具函數(shù)盡量使用純函數(shù),使代碼更易于理解,不用考慮副作用。這里說的僅限于業(yè)務(wù)代碼的范疇,如果是框架型的項目,場景會復(fù)雜得多,類會更有用武之地。
既然類都不需要用了,繼承就更無從談起了。繼承的問題是多級繼承之后,定位問題會非常困難,要一級一級往上找才能找到錯誤出處。而組合就沒有這種問題,因為多個功能都是平級的,哪里出問題一眼就能看出來。比較一下下面 2 種風(fēng)格的代碼:
繼承的寫法:
class Parent extends PureComponent { componentDidMount() { this.fetchData(this.url); } fetchData(url) { ... } render() { const data = this.calcData(); return ({data} ); } } class Child extends Parent { constructor(props) { super(props); this.url = "http://api"; } calcData() { ... } }組合的寫法:
class Parent extends PureComponent { componentDidMount() { this.fetchData(this.props.url); } fetchData(url) { ... } render() { const data = this.props.calcData(this.state); return ({data} ); } } class Child extends PureComponent { calcData(state) { ... } render() {} } 哪種更易于理解呢?
Single Responsibility
遵循單一職責(zé)的代碼如果設(shè)計得好,組合起來的代碼就會非常的清爽。舉一個注冊的場景,可以劃分為下面幾個職責(zé):
UI 展示
輸入合法性判斷
網(wǎng)絡(luò)請求
聚合層
偽代碼如下:
// UI.js export default function UI() { ... } // api.js export function regist(name, email) { ... } // validate.js export function validateName(name) { ... } export function validateEmail(email) { ... } // Regist.js export default class Regist extends PureComponent { ... onSubmit = async () => { const {name, email} = this.state; if (validateName(name) && validateEmail(email)) { const resp = await regist(name, email); ... } } render() {} } 可以看到聚合層的代碼非常簡潔,哪里出問題了就到相應(yīng)的地方改就好了,即使是多人協(xié)作,也不容易出問題。
Separation of Concerns
關(guān)注點分離原則跟單一職責(zé)原則有點類似,但更強(qiáng)調(diào)的是系統(tǒng)架構(gòu)層面的設(shè)計。典型的例子就是 MVC 模式,Model、View、Control 三層之間都有明確的職責(zé)劃分,做到了高內(nèi)聚低耦合。
React 的源碼設(shè)計也是基于這一原則,分為ReactElement, ReactCompositeComponent 和 ReactDomComponent 三層。ReactElement 負(fù)責(zé)描述頁面的 DOM 結(jié)構(gòu),也就是著名的 Virtual DOM;ReactCompositeComponent 處理的是組件生命周期、組件 Diff 和更新等邏輯;而ReactDomComponent是真正進(jìn)行 DOM 操作的類。三層之間分工明確,緊密協(xié)作,共同組成了一個強(qiáng)大的前端框架。
Clean Code > Clever Code
提倡簡潔易懂的代碼,而不是晦澀難懂的“聰明”代碼,如下面這種:
let a, b=3, t = (a=2, b<1) ? (console.log("Y"),"yes") : (console.log("N"),"no");單一代碼文件不超過 200 行
文件一旦超過 200 行,說明邏輯已經(jīng)有點復(fù)雜了,要想辦法抽離出一些純函數(shù)工具方法,讓主線邏輯更加清晰。工具方法可以放在另外的文件里面,減少讀代碼的心理壓力。有一點需要說明一下,并不是所有的文件都不能超過 200 行,像工具方法這種,都是各自獨立的邏輯,寫多少行都無所謂。需要控制的是緊密關(guān)聯(lián)的業(yè)務(wù)代碼的行數(shù)。
四、前端代碼如何拆分上面提到要合理的拆分代碼,那到底怎么拆呢?對于前端組件代碼,有下面一些拆分點以供參考:
UI
展現(xiàn)邏輯
事件處理
業(yè)務(wù)邏輯
網(wǎng)絡(luò)請求
配置類純JSON對象
工具類純函數(shù)
需要說明的是展現(xiàn)邏輯和業(yè)務(wù)邏輯是兩回事,最好不要混在一起寫。比如組件的顯示隱藏是展現(xiàn)邏輯,而數(shù)據(jù)的校驗就是業(yè)務(wù)邏輯。
五、總結(jié)本文討論了書寫整潔代碼的必要性和重要性,結(jié)合實例列出了一些設(shè)計原則,還給出了組件代碼拆分的方式。程序員的職業(yè)生涯是一個自我修煉的過程,時刻關(guān)注代碼質(zhì)量,是提高技術(shù)水平的重要一環(huán)。
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/105330.html
相關(guān)文章
代碼整潔之道
摘要:在代碼整潔之道,提出一種軟件質(zhì)量,可持續(xù)開發(fā)不僅在于項目架構(gòu)設(shè)計,還與代碼質(zhì)量密切相關(guān),代碼的整潔度和質(zhì)量成正比,一份整潔的代碼在質(zhì)量上是可靠的,為團(tuán)隊開發(fā),后期維護(hù),重構(gòu)奠定了良好的基礎(chǔ)。 現(xiàn)在的軟件系統(tǒng)開發(fā)難度主要在于其復(fù)雜度和規(guī)模,客戶需求也不再像Winston Royce瀑布模型期望那樣在系統(tǒng)編碼前完成所有的設(shè)計滿足用戶軟件需求。在這個信息爆炸技術(shù)日新月異的時代,需求總是在不停...
代碼整潔之道 - 有意義的命名
摘要:我們這里再介紹一下,朱重八家族的名字,都很有特點。取這樣的名字不是因為朱家是搞數(shù)學(xué)的,而是因為在元朝,老百姓如果不能上學(xué)和當(dāng)官就沒有名字,只能以父母年齡相加或者出生的日期命名。所以說命名不僅僅是一種科學(xué),更是一種藝術(shù)。 在小朱元璋出生一個月后,父母為他取了一個名字(元時慣例):朱重八,這個名字也可以叫做朱八八。我們這里再介紹一下,朱重八家族的名字,都很有特點。朱重八高祖名字:朱百六;朱...
代碼整潔之道 - 有意義的命名
摘要:我們這里再介紹一下,朱重八家族的名字,都很有特點。取這樣的名字不是因為朱家是搞數(shù)學(xué)的,而是因為在元朝,老百姓如果不能上學(xué)和當(dāng)官就沒有名字,只能以父母年齡相加或者出生的日期命名。所以說命名不僅僅是一種科學(xué),更是一種藝術(shù)。 在小朱元璋出生一個月后,父母為他取了一個名字(元時慣例):朱重八,這個名字也可以叫做朱八八。我們這里再介紹一下,朱重八家族的名字,都很有特點。朱重八高祖名字:朱百六;朱...
架構(gòu)整潔之道(二)——兩個價值的故事
摘要:每個軟件系統(tǒng)都提供兩個價值給利益相關(guān)者表現(xiàn)和結(jié)構(gòu)。來自利益相關(guān)者的觀點,開發(fā)者僅僅只提供了一些形態(tài)上的粗略改變,來自開發(fā)者的觀點,老板的需求越來越難。記住,作為一個開發(fā)者,你就是利益相關(guān)者,你需要維護(hù)的軟件里有你的利益。 每個軟件系統(tǒng)都提供兩個價值給利益相關(guān)者:表現(xiàn)和結(jié)構(gòu)。軟件開發(fā)者應(yīng)的確保這兩個價值盡量高負(fù)責(zé)。然而很不幸,程序員很多只關(guān)心其中一個而忽略另一個,甚至更不幸,他們可能關(guān)注...
發(fā)表評論
0條評論
閱讀 1839·2021-11-25 09:43
閱讀 1354·2021-11-22 15:08
閱讀 3764·2021-11-22 09:34
閱讀 3240·2021-09-04 16:40
閱讀 3054·2021-09-04 16:40
閱讀 556·2019-08-30 15:54
閱讀 1346·2019-08-29 17:19
閱讀 1765·2019-08-28 18:13