重构最丑陋代码的 5 个简单方法

2025-06-07

重构最丑陋代码的 5 个简单方法

当你开始一个新项目时,编写干净的代码可能是一个挑战。尝试在不破坏任何现有应用程序的情况下清理代码,类似于以下情况:

我担任技术主管已有数年,期间见识过不少需要维护,甚至更糟的是需要扩展的意大利面条式代码。经过无数个令人沮丧的痛苦时光,以及十几只小黄鸭的折腾,我总结出了一些技巧和窍门,即使是最丑陋的代码库,也能轻松重构。

我整理了 5 个快速取胜的列表,您可以将它们应用于任何代码库,或者在开始新项目时牢记在心。

每次胜利都会从一个糟糕的代码示例开始,然后是一个好的代码示例,并解释发生了什么变化。

1)没有不变的方法

如果一个方法无论传入什么都总是返回相同的结果,那么它几乎可以说是无用的。
正如您在示例 invariant-method-bad.ts 中所见,getName 总是返回相同的“NO NAME FOUND”消息。
我们在 invariant-method-good.ts 方法中修复了这个问题,只需返回我们一开始就想要的结果即可。

public getName(): string {
let result = "NO NAME FOUND";
if(this.name) {
result = this.name;
}
return "NO NAME FOUND";
}
public getName(): string {
let result = "NO NAME FOUND";
if(this.name) {
result = this.name;
}
return result;
}
public getName(): string {
let result = "NO NAME FOUND";
if(this.name) {
result = this.name;
}
return "NO NAME FOUND";
}
public getName(): string {
let result = "NO NAME FOUND";
if(this.name) {
result = this.name;
}
return result;
}

代码审查期间的我

2)没有神奇的数字或字符串

魔法数字和字符串是硬编码的值,你可以在代码中随处找到它们。如果不小心处理,你最终会在整个代码库中重复使用完全相同的值,这将使修改、调试和测试代码成为一场噩梦。
正如你在下方 magic-strings-bad.ts 文件中看到的,我们的方法中有一个硬编码的字符串。在它下面的文件 magic-strings-good.ts 中,我们通过将其重构为私有的只读类变量来解决这个问题。

public getName(): string {
let result = "NO NAME FOUND";
if(this.name) {
result = this.name;
}
return result;
}
export class User {
private readonly NAME_DEFAULT = "NO NAME FOUND";
private name;
public getName(): string {
let result = this.NAME_DEFAULT;
if(this.name) {
result = this.name;
}
return result;
}
}
public getName(): string {
let result = "NO NAME FOUND";
if(this.name) {
result = this.name;
}
return result;
}
export class User {
private readonly NAME_DEFAULT = "NO NAME FOUND";
private name;
public getName(): string {
let result = this.NAME_DEFAULT;
if(this.name) {
result = this.name;
}
return result;
}
}

关于魔法数字和字符串,一个好问题是“我应该把它们放在哪里?”。以下是我决定如何放置它们的方法:

  1. 这个值只存在于一个文件中吗?👉文件顶部的一个常量
  2. 该值是否跨多个文件使用?👉 一个特定的枚举类,按逻辑对常量进行分组
  3. 应用程序启动时使用的值(例如 API URL、超时阈值……)👉 属性文件

嘘,我一直在发关于代码的推文。如果你对如何提升开发技能有疑问,可以关注我@mlevkov。

3)将默认条款保留在最后

switch 语句可以包含 default 子句来处理意外值。考虑到您很可能在代码库上进行协作,遵循约定以方便沟通非常重要。
参考下面的示例,只需将 default 子句移到最底部,就能为您的同事省去很多麻烦。

import { Track } from "../models/Track";
export class BackgroundImage {
dimension: string;
url: string;
}
export class BackgroundImageService {
getBackgroundArt(track: Track): BackgroundImage {
switch(track.getGenre()) {
default:
return null;
case "hiphop":
const hipHopImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
return hipHopImage;
case "jazz":
const jazzImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
return jazzImage;
case "rap":
const rapImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
return rapImage;
case "country":
const countryImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
return countryImage;
}
}
}
getBackgroundArt(track: Track): BackgroundImage {
switch(track.getGenre()) {
case "hiphop":
const hipHopImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
return hipHopImage;
case "jazz":
const jazzImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
return jazzImage;
case "rap":
const rapImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
return rapImage;
case "country":
const countryImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
return countryImage;
default:
return null;
}
}
import { Track } from "../models/Track";
export class BackgroundImage {
dimension: string;
url: string;
}
export class BackgroundImageService {
getBackgroundArt(track: Track): BackgroundImage {
switch(track.getGenre()) {
default:
return null;
case "hiphop":
const hipHopImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
return hipHopImage;
case "jazz":
const jazzImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
return jazzImage;
case "rap":
const rapImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
return rapImage;
case "country":
const countryImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
return countryImage;
}
}
}
getBackgroundArt(track: Track): BackgroundImage {
switch(track.getGenre()) {
case "hiphop":
const hipHopImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
return hipHopImage;
case "jazz":
const jazzImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
return jazzImage;
case "rap":
const rapImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
return rapImage;
case "country":
const countryImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
return countryImage;
default:
return null;
}
}

4)清理冗余变量

当你完全不需要实例化变量时,请务必留意。冗余变量会占用内存,使代码变得混乱,并使调试和添加新功能变得更加困难。尽量保持代码简洁。在下面的示例中,我们显然不需要每次都创建 BackgroundImage 的实例,只需为每种情况赋值即可。

getBackgroundArt(track: Track): BackgroundImage {
switch(track.getGenre()) {
case "hiphop":
const hipHopImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
return hipHopImage;
case "jazz":
const jazzImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
return jazzImage;
case "rap":
const rapImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
return rapImage;
case "country":
const countryImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
return countryImage;
default:
const defaultImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/PDX_a_82obo'};
return defaultImage;
}
}
getBackgroundArt(track: Track): BackgroundImage {
let backgroundImage: BackgroundImage;
switch(track.getGenre()) {
case "hiphop":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
break;
case "jazz":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
break;
case "rap":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
break;
case "country":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
break;
default:
backgroundImage = {dimension: 'small', url : 'https://unsplash.com/photos/PDX_a_82obo'};
}
return backgroundImage;
}
getBackgroundArt(track: Track): BackgroundImage {
switch(track.getGenre()) {
case "hiphop":
const hipHopImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
return hipHopImage;
case "jazz":
const jazzImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
return jazzImage;
case "rap":
const rapImage : BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
return rapImage;
case "country":
const countryImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
return countryImage;
default:
const defaultImage: BackgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/PDX_a_82obo'};
return defaultImage;
}
}
getBackgroundArt(track: Track): BackgroundImage {
let backgroundImage: BackgroundImage;
switch(track.getGenre()) {
case "hiphop":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
break;
case "jazz":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
break;
case "rap":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
break;
case "country":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
break;
default:
backgroundImage = {dimension: 'small', url : 'https://unsplash.com/photos/PDX_a_82obo'};
}
return backgroundImage;
}

5)忘记 else,如果可以就返回

保持代码简洁的一个重要概念是圈复杂度。圈复杂度本质上就是代码中嵌套了多少个循环、条件或函数调用。极高的圈复杂度几乎会让代码难以理解。如果代码失控,你肯定需要一堆橡皮鸭子来应对。
让我们将上面的例子简化一下,将 switch 语句简化为一系列简洁的 if 语句。

getBackgroundArt(track: Track): BackgroundImage {
let backgroundImage: BackgroundImage;
switch(track.getGenre()) {
case "hiphop":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
break;
case "jazz":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
break;
case "rap":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
break;
case "country":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
break;
default:
backgroundImage = {dimension: 'small', url : 'https://unsplash.com/photos/PDX_a_82obo'};
}
return backgroundImage;
}
getBackgroundArt(track: Track): BackgroundImage {
let backgroundImage: BackgroundImage;
if(!track.getGenre()) {
backgroundImage = {dimension: BackgroundImageDimensions.small, url : this.DEFAULT_BACKGROUND_IMAGE_URL};
} else if (track.getGenre() == "hiphop") {
backgroundImage = {dimension: BackgroundImageDimensions.small, url: this.HIPHOP_BACKGROUND_IMAGE_URL};
} else if(track.getGenre() == "jazz") {
backgroundImage = {dimension: BackgroundImageDimensions.small, url: this.JAZZ_BACKGROUND_IMAGE_URL};
} else if(track.getGenre() == "rap") {
backgroundImage = {dimension: BackgroundImageDimensions.small, url: this.RAP_BACKGROUND_IMAGE_URL};
} else if(track.getGenre() == "country") {
backgroundImage = {dimension: BackgroundImageDimensions.small, url: this.COUNTRY_BACKGROUND_IMAGE_URL};
}
return backgroundImage;
}
getBackgroundArt(track: Track): BackgroundImage {
let backgroundImage: BackgroundImage = {dimension: BackgroundImageDimensions.small, url : this.DEFAULT_BACKGROUND_IMAGE_URL};
if (track.getGenre() == "hiphop") {
return {dimension: BackgroundImageDimensions.small, url: this.HIPHOP_BACKGROUND_IMAGE_URL};
}
if(track.getGenre() == "jazz") {
return {dimension: BackgroundImageDimensions.small, url: this.JAZZ_BACKGROUND_IMAGE_URL};
}
if(track.getGenre() == "rap") {
return {dimension: BackgroundImageDimensions.small, url: this.RAP_BACKGROUND_IMAGE_URL};
}
if(track.getGenre() == "country") {
return {dimension: BackgroundImageDimensions.small, url: this.COUNTRY_BACKGROUND_IMAGE_URL};
}
return backgroundImage;
}
getBackgroundArt(track: Track): BackgroundImage {
let backgroundImage: BackgroundImage;
switch(track.getGenre()) {
case "hiphop":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/Qcl98B8Bk3I'};
break;
case "jazz":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/dBWvUqBoOU8'};
break;
case "rap":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/auq_QbyIA34'};
break;
case "country":
backgroundImage = {dimension: 'small', 'url': 'https://unsplash.com/photos/RnFgs90NEHY'};
break;
default:
backgroundImage = {dimension: 'small', url : 'https://unsplash.com/photos/PDX_a_82obo'};
}
return backgroundImage;
}
getBackgroundArt(track: Track): BackgroundImage {
let backgroundImage: BackgroundImage;
if(!track.getGenre()) {
backgroundImage = {dimension: BackgroundImageDimensions.small, url : this.DEFAULT_BACKGROUND_IMAGE_URL};
} else if (track.getGenre() == "hiphop") {
backgroundImage = {dimension: BackgroundImageDimensions.small, url: this.HIPHOP_BACKGROUND_IMAGE_URL};
} else if(track.getGenre() == "jazz") {
backgroundImage = {dimension: BackgroundImageDimensions.small, url: this.JAZZ_BACKGROUND_IMAGE_URL};
} else if(track.getGenre() == "rap") {
backgroundImage = {dimension: BackgroundImageDimensions.small, url: this.RAP_BACKGROUND_IMAGE_URL};
} else if(track.getGenre() == "country") {
backgroundImage = {dimension: BackgroundImageDimensions.small, url: this.COUNTRY_BACKGROUND_IMAGE_URL};
}
return backgroundImage;
}
getBackgroundArt(track: Track): BackgroundImage {
let backgroundImage: BackgroundImage = {dimension: BackgroundImageDimensions.small, url : this.DEFAULT_BACKGROUND_IMAGE_URL};
if (track.getGenre() == "hiphop") {
return {dimension: BackgroundImageDimensions.small, url: this.HIPHOP_BACKGROUND_IMAGE_URL};
}
if(track.getGenre() == "jazz") {
return {dimension: BackgroundImageDimensions.small, url: this.JAZZ_BACKGROUND_IMAGE_URL};
}
if(track.getGenre() == "rap") {
return {dimension: BackgroundImageDimensions.small, url: this.RAP_BACKGROUND_IMAGE_URL};
}
if(track.getGenre() == "country") {
return {dimension: BackgroundImageDimensions.small, url: this.COUNTRY_BACKGROUND_IMAGE_URL};
}
return backgroundImage;
}

最后一个例子让逻辑流程变得非常简单。你不需要规划其他流程,一切都非常直接,更容易理解。

以上就是 5 个简单的技巧,您可以将其应用于几乎任何代码库。

如果你想提高你的编码技能,我正在编写一个剧本,其中包括:

  1. 30 多种常见代码异味及其解决方法

  2. 15+ 设计模式实践及其应用方法

  3. 20 多个常见的 JS 错误及其预防方法

尽早获得Javascript 剧本

文章来源:https://dev.to/mlevkov/5-easy-wins-to-refactor-even-the-ugliest-code-14lb
PREV
前端开发人员满意吗?recommended_chrome_browser
NEXT
5 个让 JavaScript 代码更简洁的小妙招🧹