8

难说|程序员的品味

 11 months ago
source link: https://bianchengnan.gitee.io//articles/talking-about-coding-of-taste/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

难说|程序员的品味

2022-03-21

|

2023-09-29

| 难说

| 热度: 1℃

代码里有很多值得商榷的写法。今天来发点牢骚。

bool bShouldModifyData = false;
if (condition1 && condition2)
{
bShouldModifyData = true;
}
else
{
bShouldModifyData = false;
}

好吧,这种写法逻辑上没问题,但是我觉得可以一行代码更好:

bool bShouldModifyData = (condition1 && condition2);
// 如果 map 中找到了 key 对应的数据,就用 map 中的数据,否则用 normalData
// if 和 else 中,只有 Method 的参数传递的不一样,其它一模一样
int normalData = 0;
auto it = map.find(key);
if (it != map.end())
{
// lots of code
result = Method(it->second);
}
else
{
// lots of code (same with if)
result = Method(normalData);
}

这样的写法在业务代码中比较多。猜测应该是写好了 if 部分的代码,else 部分的代码直接复制粘贴的。我认为上面代码最致命的问题是:如果业务逻辑发生变化,那么需要同时修改 ifelse 两个语句块中的代码。

写代码的时候有一个最基本的原则:DRY (Don’t Repeat Yourself)。可以改成下面的样子,代码量不仅少了一半儿,逻辑也更加清晰了。

// 如果 map 中找到了 key 对应的数据,就用 map 中的数据,否则用 someNormalData
// if 和 else 中,只有 Method 的参数传递的不一样,其它一模一样
int normalData = 0;

auto it = map.find(key);
auto funcParam = (it != map.end()) ? it->second : normalData;

// lots of code
result = Method(funcParam);
struct HugeStruct
{
// lots of members
};

void DoSomething(HugeStruct data)
{
// ...
}

作为一个有强迫症的 c++ 程序员,看到上面的代码,我的直觉告诉我,写这段代码的人或者是不小心,或者是其它语言转过来的。在 c++ 里,默认是值拷贝,上面的写法,在调用函数时会把 data 对应的内存在栈上拷贝一份。这会导致两个问题:1. 效率低(没必要拷贝整个结构体)。2. 可能爆栈(之前在项目中遇到过的)。

如果我们不打算修改 data 的内容,那么应该使用 const & 修饰。代码改成下面这样,既高效又安全。

void DoSomething(const HugeStruct& data)
{
// ...
}
int GetMoney(BankAccount& account)
{
return account.money;
}

通过函数名判断,上面的函数只是获取一些值,不会修改参数。但是参数只用了引用修饰,没加 const,意味着参数可能在函数内部被修改。让人迷惑。

如果不需要修改参数,那么需要加上 const。改成下面这样就没有任何歧义了。

int GetMoney(const BankAccount& account)
{
return account.money;
}

注意: 不需要对 int, char, short, double 这种基础类型加 const & 修饰。加了效率也没什么提高,反而很别扭。

class Wall
{
public:
std::vector<Hole> GetHole() { return m_holeVec; }
private:
std::vector<Hole> m_holeVec;
};

上面这段代码中规中矩。但是 GetHole() 的效率很低,可以优化一下。改成返回引用。

class Wall
{
public:
std::vector<Hole>& GetHole() { return m_holeVec; }
const std::vector<Hole>& GetHole() const { return m_holeVec; }
private:
std::vector<Hole> m_holeVec;
};

有的小伙伴儿就有疑问了,返回引用,被别人改了怎么办?当 Wall 实例是 const 的,那么会调用带 const 的函数,返回的是 const &,不会被意外修改。当 Wall 实例是非 const 的,那么会调用不带 const 的函数,返回的是引用,可以被修改。但是,这大概率是调用者所期待的。

void ReallyComplexFunction()
{
// start by xxx1 [2022-01-01]
// start by xxx2 [2022-02-01]
// start by xxx3 [2022-03-01]
// idx = 0;
// idx = 1;
// idx = 2;
idx = 0;
// end by xxx3 [2022-03-01]
// end by xxx2 [2022-02-01]
// end by xxx1 [2022-01-01]
}

上面的代码片段是非常典型的,三个同事改了三次,留下了三次改动记录,但是只是为了修改一个小小的地方。放眼望去,全是注释,真正有用的就一句话。

Taste

之前看 Linus 大神的演讲视频时,他提到了一个观点:品味对科技人员非常重要。原话如下:

I personally consider most important when it comes to technical people is this notion of taste.

我特意截取了关键视频,并做了中英文字幕,发到视频号上了。

我觉得每个人的水平,背景,阅历不同,品味有差异是正常的,甚至同一个人在不同时期的品味也不尽相同。希望您也觉得以上几个例子是反面教材。关于代码的品味,您想说些什么的呢?快来视频号留言吧。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK