如何寫出不可替代的代碼?
前言
本文是學(xué)習(xí)《重構(gòu):改善既有代碼的設(shè)計(jì)》后的一些心得,希望能用趣味的方式結(jié)合一些實(shí)例帶領(lǐng)大家一起學(xué)習(xí),提升自身代碼質(zhì)量。
想必最近的互聯(lián)網(wǎng)裁員消息大家也有所耳聞,那么我們怎么才能夠在這樣的大環(huán)境下茍住自身呢?經(jīng)過我的總結(jié),我認(rèn)為大家都不具備不可替代性。
什么叫不可替代性呢,通俗點(diǎn)來說就是,這活除了你別人都干不了。達(dá)到這種境界無異于兩種情況,一種是自身過于優(yōu)秀,優(yōu)秀到?jīng)]人能取代(該情況過少,希望大家能正視己身)。
另一種方法則是,制作出專屬于你的代碼!!下面我們來一起學(xué)習(xí),怎樣寫出專屬于你,不可被替代的代碼!
以下不可替代寫法皆為反面教材!!!
一、神秘命名(Mysterious Name)
命名讓人猜不透,摸不準(zhǔn)!
不可替代寫法:
const getPNum = (number) => {
......
}
無論是函數(shù)命名還是入?yún)⒚嘈哦己茈y有人能參透你的深意,在別人接手你的代碼時(shí),必定會來向你請教,這在老板眼里你的價(jià)值將更為突出。
正常寫法:
const getPhoneCode = (phoneNumber) => {
......
}
從函數(shù)的駝峰命名我們可以很輕易猜出是獲取手機(jī)驗(yàn)證碼,入?yún)⒁材懿鲁鍪鞘謾C(jī)號碼的意思,這樣的代碼太通俗易懂了,顯然達(dá)不到我們的效果。
二、重復(fù)代碼(Duplicated Code)&& 過長函數(shù)(Long Function)
重復(fù)編寫大量相同代碼,內(nèi)容過多的函數(shù),使代碼變得臃腫難以維護(hù)
不可替代寫法:
const showUserInfo = () => {
let totalAmount = 0;
const userInfo = request.get('/userInfo', 'admin')
const userAmountList = request.get('/userAmountList', 'admin')
console.log('name', userInfo.name);
console.log('age', userInfo.age);
console.log('sex', userInfo.sex);
console.log('address', userInfo.address);
for(let i of userAmountList) {
totalAmount += i.amount
}
console.log('總金額', totalAmount);
}
大量重復(fù)的代碼讓人瞬間產(chǎn)生疲勞感,完全不搭邊的代碼順序混淆人的雙眼,如果再加上一些神秘命名,必將讓代碼更上一個(gè)臺階。
正常寫法:
const showUserInfo = () => {
const printUserDetail = (userInfo) => {
const { name, age, sex, address } = userInfo;
console.log('name', name);
console.log('age', age);
console.log('sex', sex);
console.log('address', address);
const printTotalAmount = (userAmountList) => {
const totalAmount = userList.reduce((pre, cur) => pre + cur.amount, 0)
console.log('總金額', totalAmount);
}
// 獲取用戶信息
const userInfo = request.get('/userInfo', 'admin')
printUserDetail(userInfo)
// 獲取用戶金額列表
const userAmountList = request.get('/userAmountList', 'admin')
printTotalAmount(userAmountList)
}
重復(fù)代碼都被提煉到單獨(dú)的函數(shù)模塊中,用reduce免去了重復(fù)的代碼相加,并且代碼順序也被移動至有關(guān)聯(lián)的地方,這樣的代碼換做剛學(xué)前端的小白恐怕也能看懂,這樣明顯不能凸顯自身的獨(dú)特。
三、過長參數(shù)列表(Long Parameter List)
函數(shù)或組件的參數(shù)過多,影響代碼可讀性,某些環(huán)境甚至?xí)π阅茉斐捎绊?/p>
不可替代寫法:
const getList = (id, name, age, address, sex) => {
...
}
正常寫法:
const getList = (data) => {
const { id, name, age, address, sex } = data;
...
}
將入?yún)⒎胖玫揭粋€(gè)對象中,再到函數(shù)里通過解構(gòu)的方式進(jìn)行調(diào)用。這樣的方式太過簡潔,過少的入?yún)⑼癸@不出你這個(gè)函數(shù)的重要性。
四、全局?jǐn)?shù)據(jù)
將數(shù)據(jù)全部掛載到全局,導(dǎo)致內(nèi)存不及時(shí)被釋放以及全局污染
不可替代寫法:
const id = 1;
const data1 = request.get('/userInfo', id)
const data2 = request.get('/userState', id)
const getUserInfo = () => {
...
}
const getUserState = () => {
...
}
所有變量放入全局,把后續(xù)開發(fā)者的路變窄,不敢隨意去更改變量,此刻再加上神秘命名,相信沒有人能夠取代你的位置。
正常寫法:
const id = 1;
const getUserInfo = () => {
const data = request.get('/userInfo', id)
...
}
const getUserState = () => {
const data = request.get('/userState', id)
...
}
id作為多處用到變量,寫到全局,剩下的局部變量都寫在各自函數(shù)中,即不會引起全局污染,也不會擔(dān)心命名重復(fù)的問題。在各自的作用域中作用也清晰明了。
五、發(fā)散式變化(Divergent Change)
將需要做的事分散到各個(gè)地方,每次修改需要修改對應(yīng)函數(shù),修改不當(dāng)會導(dǎo)致另一個(gè)依賴此函數(shù)的功能崩塌
不可替代寫法:
const getPrice = (list) => {
const printName = (item) => {
if(item.type === 'totalList') {
console.log('totalName', item.name);
}else if(item.type === 'frozenList'){
console.log('frozenName', item.name);
}
}
const calcPrice = (item) => {
if(item.type === 'totalList') {
// todo: 計(jì)算totalPrice
const price = ...;
return price;
}else if(item.type === 'frozenList'){
// todo: 計(jì)算frozenPrice
const price = ...;
return price;
}
}
printName(list.totalList);
printName(list.frozenList);
return calcPrice(list.totalList) - calcPrice(list.frozenList)
}
將方法寫成公用方法,在每次修改或者新增時(shí)候都需要去修改對應(yīng)的方法。無法知道每個(gè)價(jià)格對應(yīng)著哪些操作,當(dāng)增加一個(gè)新的價(jià)格類型時(shí),需要同時(shí)去多個(gè)函數(shù)中添加對應(yīng)的判斷邏輯。一不注意就會忘加漏加形成bug。測試績效max!
正常寫法:
const getPrice = (list) => {
const totalPrice = (item) => {
// todo: 計(jì)算totalPrice
const price = ...
console.log('totalName', item.name);
console.log('price', price);
}
const frozenPrice = (item) => {
// todo: 計(jì)算frozenPrice
const price = ...
console.log('frozenName', item.name);
console.log('price', price);
}
return totalPrice(list.totalList) - frozenPrice(list.frozenList)
}
每個(gè)價(jià)格對應(yīng)需要的操作都被提煉到單獨(dú)的函數(shù),專注于負(fù)責(zé)自己的事,如果價(jià)格計(jì)算方式需要改變,可以更加直觀的修改。若需要添加新的價(jià)格品種,也將會更好添加。
六、霰彈式修改(Shotgun Surgery)
多處共用一個(gè)屬性,不設(shè)置全局變量管理,每次修改需要修改大量代碼
不可替代寫法:
getList(globalModel.id)
getUserInfo(globalModel.id)
getUserAmount(globalModel.id)
當(dāng)需求改變,需要在多處進(jìn)行修改,這樣的工作量倍增,會讓你的工作力max!
正常寫法:
const id = globalModel.id;
getList(id)
getUserInfo(id)
getUserAmount(id)
同一個(gè)屬性被多處使用,使用一個(gè)變量進(jìn)行存儲,當(dāng)需求發(fā)生改變(例如globalModel.id變?yōu)間lobalModel.userId),只需要修改一處便能完成,大大節(jié)省時(shí)間。
七、依戀情結(jié)(Feature Envy)
大量引入其他函數(shù)或模塊方法,導(dǎo)致代碼耦合度極高,動一處則牽扯全身
不可替代寫法:
class Price {
constructor() {}
add(...num) {
return num.reduce((pre, cur) => pre + cur, 0);
}
dataFilter(value) {
return parseInt(value.substring(0, value.length - 2)) * 100;
}
}
class Amount {
constructor() {}
getAmount(amountList) {
const _amountList = amountList.map(item => {
return new Price().dataFilter(item);
});
return new Price().add(..._amountList);
}
}
所有的計(jì)算函數(shù)全部使用其他類里的方法,形成大量依賴。你要出事我跟著一起死,我就是要用你的,我就是玩~
正常寫法:
class Amount {
constructor() {}
add(...num) {
return num.reduce((pre, cur) => pre + cur, 0);
}
dataFilter(value) {
return parseInt(value.substring(0, value.length - 2)) * 100;
}
getAmount(amountList) {
const _amountList = amountList.map(item => {
return this.dataFilter(item);
});
return this.add(..._amountList);
}
}
類里所有使用的方法都在本身完成,所有的問題都在自身解決,形成閉環(huán)。
八、數(shù)據(jù)泥團(tuán)(Data Clumps)
眾多數(shù)據(jù)糅合在一起,當(dāng)其中某一項(xiàng)數(shù)據(jù)失去意義時(shí),其他項(xiàng)數(shù)據(jù)也失去意義。
不可替代寫法:
const lastName = "盧"
const firstName = "本偉"
const name = `${lastName}${firstName}`
發(fā)現(xiàn)當(dāng)其中某個(gè)變量失去意義的時(shí)候,另一個(gè)變量也失去意義,一損俱損。
正常寫法:
const person = {
lastName: "盧",
firstName: "本偉"
}
const name = `${person.lastName}${person.firstName}`
有強(qiáng)聯(lián)系的數(shù)據(jù),應(yīng)為它們產(chǎn)生一個(gè)新對象。
九、基本類型偏執(zhí)(Primitive Obsession)
認(rèn)為基本類型一定更加簡單,偏執(zhí)的使用大量的基本類型而不去定義應(yīng)有的結(jié)構(gòu)
不可替代寫法:
class Price {
constructor(name, money) {
this.name = name;
this.money = money;
}
get name() {
return name;
}
get count() {
return parseFloat(this.money.slice(1));
}
get current() {
return this.money.slice(0, 1);
}
get unit() {
switch (this.money.slice(0, 1)) {
case '¥':
return 'CNY';
case '$':
return 'USD';
case 'k':
return 'HKD';
}
}
calcPrice() {
// todo: 金額換算
}
}
const myPrice = new Price("罐頭", "$30")
偏執(zhí)地使用字符串基本類型定義money,表面是Price的類,但在里面充斥著大量的money的數(shù)據(jù)處理。
正常寫法:
class Money {
constructor(value) {
this.value = value;
}
get count() {
return parseFloat(this.value.slice(1));
}
get current() {
return this.value.slice(0, 1);
}
get unit() {
switch (this.value.slice(0, 1)) {
case '¥':
return 'CNY';
case '$':
return 'USD';
case 'k':
return 'HKD';
}
}
}
class Price {
constructor(name, money) {
this.name = name;
this.money = new Money(money);
}
get name() {
return name;
}
calcPrice() {
// todo: 金額換算
}
}
const myPrice = new Price("罐頭", "$20")
money中存在著大量的數(shù)據(jù)處理,應(yīng)為期單獨(dú)建立個(gè)對象來作為它的類型。
十、重復(fù)的switch(Repeated Switches)
大量使用重復(fù)邏輯的switch,這樣的代碼是臃腫且脆弱的。
不可替代寫法:
class Money {
constructor(value) {
this.value = value;
}
get count() {
return parseFloat(this.value.slice(1));
}
get current() {
return this.value.slice(0, 1);
}
get unit() {
switch (this.current) {
case '¥':
return 'CNY';
case '$':
return 'USD';
case 'k':
return 'HKD';
}
}
get suffix() {
switch (this.current) {
case '¥':
return '元';
case '$':
return '美元';
case 'k':
return '港幣';
}
}
get currentCount() {
switch (this.current) {
case '¥':
return this.count;
case '$':
return this.count * 7;
case 'k':
return this.count * 0.8;
}
}
}
大量相同邏輯的switch,若想增加一個(gè)判斷項(xiàng),需找到所有switch項(xiàng)進(jìn)行修改,一不注意則會遺漏,引發(fā)bug
正常寫法:
class Money {
constructor(value) {
this.value = value;
}
get count() {
return parseFloat(this.value.slice(1));
}
get current() {
return this.value.slice(0, 1);
}
}
class cnyMoney extends Money {
constructor(props) {
super(props);
}
get unit() {
return 'CNY';
}
get suffix() {
return '元';
}
get currentCount() {
return this.count;
}
}
class usdMoney extends Money {
constructor(props) {
super(props);
}
get unit() {
return 'USD';
}
get suffix() {
return '美元';
}
get currentCount() {
return this.count * 7;
}
}
class hkdMoney extends Money {
constructor(props) {
super(props);
}
get unit() {
return 'HKD';
}
get suffix() {
return '港幣';
}
get currentCount() {
return this.count * 0.8;
}
}
每一個(gè)分支項(xiàng)專注于自身的變化,修改時(shí)不會擔(dān)心某處遺漏。
原文地址: https://juejin.cn/post/7126888773647876110#heading-
