前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >如何写出不可替代的代码?

如何写出不可替代的代码?

作者头像
用户3806669
发布2022-11-11 16:36:42
4970
发布2022-11-11 16:36:42
举报
文章被收录于专栏:前端三元同学前端三元同学

前言

本文是学习《重构:改善既有代码的设计》后的一些心得,希望能用趣味的方式结合一些实例带领大家一起学习,提升自身代码质量。

想必最近的互联网裁员消息大家也有所耳闻,那么我们怎么才能够在这样的大环境下苟住自身呢?经过我的总结,我认为大家都不具备不可替代性。

什么叫不可替代性呢,通俗点来说就是,这活除了你别人都干不了。达到这种境界无异于两种情况,一种是自身过于优秀,优秀到没人能取代(该情况过少,希望大家能正视己身)。

另一种方法则是,制作出专属于你的代码!!下面我们来一起学习,怎样写出专属于你,不可被替代的代码!

以下不可替代写法皆为反面教材!!!

一、神秘命名(Mysterious Name)

命名让人猜不透,摸不准!

不可替代写法:

代码语言:javascript
复制
const getPNum = (number) => {
  ......
}

无论是函数命名还是入参命名,相信都很难有人能参透你的深意,在别人接手你的代码时,必定会来向你请教,这在老板眼里你的价值将更为突出。

正常写法:

代码语言:javascript
复制
const getPhoneCode = (phoneNumber) => {
  ......
}

从函数的驼峰命名我们可以很轻易猜出是获取手机验证码,入参也能猜出是手机号码的意思,这样的代码太通俗易懂了,显然达不到我们的效果。

二、重复代码(Duplicated Code)&& 过长函数(Long Function)

重复编写大量相同代码,内容过多的函数,使代码变得臃肿难以维护

不可替代写法:

代码语言:javascript
复制
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);
}

大量重复的代码让人瞬间产生疲劳感,完全不搭边的代码顺序混淆人的双眼,如果再加上一些神秘命名,必将让代码更上一个台阶。

正常写法:

代码语言:javascript
复制
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)
}

重复代码都被提炼到单独的函数模块中,用reduce免去了重复的代码相加,并且代码顺序也被移动至有关联的地方,这样的代码换做刚学前端的小白恐怕也能看懂,这样明显不能凸显自身的独特。

三、过长参数列表(Long Parameter List)

函数或组件的参数过多,影响代码可读性,某些环境甚至会对性能造成影响

不可替代写法:

代码语言:javascript
复制
const getList = (id, name, age, address, sex) => {
  ...
}

正常写法:

代码语言:javascript
复制
const getList = (data) => {
  const { id, name, age, address, sex } = data;
  ...
}

将入参放置到一个对象中,再到函数里通过解构的方式进行调用。这样的方式太过简洁,过少的入参凸显不出你这个函数的重要性。

四、全局数据

将数据全部挂载到全局,导致内存不及时被释放以及全局污染

不可替代写法:

代码语言:javascript
复制
const id = 1;
const data1 = request.get('/userInfo', id)
const data2 = request.get('/userState', id)

const getUserInfo = () => {
  ...
}

const getUserState = () => {
  ...
}

所有变量放入全局,把后续开发者的路变窄,不敢随意去更改变量,此刻再加上神秘命名,相信没有人能够取代你的位置。

正常写法:

代码语言:javascript
复制
const id = 1;

const getUserInfo = () => {
  const data = request.get('/userInfo', id)
  ...
}

const getUserState = () => {
  const data = request.get('/userState', id)
  ...
}

id作为多处用到变量,写到全局,剩下的局部变量都写在各自函数中,即不会引起全局污染,也不会担心命名重复的问题。在各自的作用域中作用也清晰明了。

五、发散式变化(Divergent Change)

将需要做的事分散到各个地方,每次修改需要修改对应函数,修改不当会导致另一个依赖此函数的功能崩塌

不可替代写法:

代码语言:javascript
复制
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: 计算totalPrice
      const price = ...;
      return price;
    }else if(item.type === 'frozenList'){
      // todo: 计算frozenPrice
      const price = ...;
      return price;
    }
  }
  
  printName(list.totalList);
  printName(list.frozenList);
  return calcPrice(list.totalList) - calcPrice(list.frozenList)
}

将方法写成公用方法,在每次修改或者新增时候都需要去修改对应的方法。无法知道每个价格对应着哪些操作,当增加一个新的价格类型时,需要同时去多个函数中添加对应的判断逻辑。一不注意就会忘加漏加形成bug。测试绩效max!

正常写法:

代码语言:javascript
复制
const getPrice = (list) => {
  const totalPrice = (item) => {
    // todo: 计算totalPrice
    const price = ...
    console.log('totalName', item.name);
    console.log('price', price);
  }
  
  const frozenPrice = (item) => {
    // todo: 计算frozenPrice
    const price = ...
    console.log('frozenName', item.name);
    console.log('price', price);
  }
  
  return totalPrice(list.totalList) - frozenPrice(list.frozenList)
}

每个价格对应需要的操作都被提炼到单独的函数,专注于负责自己的事,如果价格计算方式需要改变,可以更加直观的修改。若需要添加新的价格品种,也将会更好添加。

六、霰弹式修改(Shotgun Surgery)

多处共用一个属性,不设置全局变量管理,每次修改需要修改大量代码

不可替代写法:

代码语言:javascript
复制
getList(globalModel.id)
getUserInfo(globalModel.id)
getUserAmount(globalModel.id)

当需求改变,需要在多处进行修改,这样的工作量倍增,会让你的工作力max!

正常写法:

代码语言:javascript
复制
const id = globalModel.id;
    
getList(id)
getUserInfo(id)
getUserAmount(id)

同一个属性被多处使用,使用一个变量进行存储,当需求发生改变(例如globalModel.id变为globalModel.userId),只需要修改一处便能完成,大大节省时间。

七、依恋情结(Feature Envy)

大量引入其他函数或模块方法,导致代码耦合度极高,动一处则牵扯全身

不可替代写法:

代码语言:javascript
复制
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);
  }
}

所有的计算函数全部使用其他类里的方法,形成大量依赖。你要出事我跟着一起死,我就是要用你的,我就是玩~

正常写法:

代码语言:javascript
复制
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);
  }
}

类里所有使用的方法都在本身完成,所有的问题都在自身解决,形成闭环。

八、数据泥团(Data Clumps)

众多数据糅合在一起,当其中某一项数据失去意义时,其他项数据也失去意义。

不可替代写法:

代码语言:javascript
复制
const lastName = "卢"
const firstName = "本伟"
const name = `${lastName}${firstName}`

发现当其中某个变量失去意义的时候,另一个变量也失去意义,一损俱损。

正常写法:

代码语言:javascript
复制
const person = {
  lastName: "卢",
  firstName: "本伟"
}
const name = `${person.lastName}${person.firstName}`

有强联系的数据,应为它们产生一个新对象。

九、基本类型偏执(Primitive Obsession)

认为基本类型一定更加简单,偏执的使用大量的基本类型而不去定义应有的结构

不可替代写法:

代码语言:javascript
复制
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")

偏执地使用字符串基本类型定义money,表面是Price的类,但在里面充斥着大量的money的数据处理。

正常写法:

代码语言:javascript
复制
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中存在着大量的数据处理,应为期单独建立个对象来作为它的类型。

十、重复的switch(Repeated Switches)

大量使用重复逻辑的switch,这样的代码是臃肿且脆弱的。

不可替代写法:

代码语言:javascript
复制
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,若想增加一个判断项,需找到所有switch项进行修改,一不注意则会遗漏,引发bug

正常写法:

代码语言:javascript
复制
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;
  }
}

每一个分支项专注于自身的变化,修改时不会担心某处遗漏。

原文地址: https://juejin.cn/post/7126888773647876110#heading-

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-08-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 前端三元同学 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 前言
  • 一、神秘命名(Mysterious Name)
  • 二、重复代码(Duplicated Code)&& 过长函数(Long Function)
  • 三、过长参数列表(Long Parameter List)
  • 四、全局数据
  • 五、发散式变化(Divergent Change)
  • 六、霰弹式修改(Shotgun Surgery)
  • 七、依恋情结(Feature Envy)
  • 八、数据泥团(Data Clumps)
  • 九、基本类型偏执(Primitive Obsession)
  • 十、重复的switch(Repeated Switches)
相关产品与服务
验证码
腾讯云新一代行为验证码(Captcha),基于十道安全栅栏, 为网页、App、小程序开发者打造立体、全面的人机验证。最大程度保护注册登录、活动秒杀、点赞发帖、数据保护等各大场景下业务安全的同时,提供更精细化的用户体验。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档