SQL 编程中的 DRY 原则,你用吗?
点击蓝色“有关SQL”关注我哟
加个“星标”,天天与10000人一起快乐成长
在朋友圈发了 9张整齐的网线图,引来大家一阵热议。
其实,老读者都知道,我有过短暂的网工经历。说的好听点,就是网络工程师,说的接地气点,就是一名网管。
作为一名网管,我深知最可怕的事情,是线路。对于强迫症来说,线路的凌乱,有时候比电脑病毒还难搞。我当时负责200多台机器,每次维修,拆机装机,最头疼的事,装完之后,周边一堆线。
有RJ45的水晶铜线(暴露年龄了),有换下来的电源线,还有整机移动过后,交叉在一起的鼠标键盘线。如果机架服务器拆装,连带着交换机,上百根线在你面前晃来晃去,眼都晕。忙起来,真是想死的心,都有了。
评论中,搞笑的是,朋友评论说,“代码也可以写成这样”
哦,我仔细想了下,好像也是。编程中有条 DRY 原则,不知道大家熟悉不?就是 Don't Repeat Yourself.
用中文来说,大概就是不要重复造轮子,不要复制黏贴代码。可真正要细究起来,好像我们平时往往会忽略这些原则。
比如我这有个例子:
CREATE PROCEDURE dbo.GetDetail
@Debits NUMERIC(18,2)
, @Credits NUMERIC(18,2)
, @Fees NUMERIC(18,2)
, @Balance NUMERIC(18,2)
AS
BEGIN
PRINT 'Debits: ' + '+ ' +CONVERT(VARCHAR,@Debits)
PRINT 'Credits: ' + '+ ' +CONVERT(VARCHAR,@Credits)
IF @Fees < 0
PRINT 'Fees: ' + '-' + CONVERT(VARCHAR,@Fees * -1 )
ELSE
PRINT 'Fees: ' + '+ ' + CONVERT(VARCHAR,@Fees)
IF @Balance < 0
PRINT 'Balance: ' + '-'+CONVERT(VARCHAR,@Balance * -1 )
ELSE
PRINT 'Balance: ' + '+ ' + CONVERT(VARCHAR,@Balance)
END
GO
可能你觉得这很正常,平时就这么用的。用了十来年了,没出过什么错。就跟这样两张图一样,达到的功能都一样:
其实,有时候我们做得不够好,往往是没有见过真正做得好的。
CREATE PROCEDURE dbo.GetDetailDRY
@Debits NUMERIC(18,2)
, @Credits NUMERIC(18,2)
, @Fees NUMERIC(18,2)
, @Balance NUMERIC(18,2)
AS
BEGIN
EXEC dbo.PrintFormatter
@Prefix = 'Debits '
,@Value = @Debits
EXEC PrintFormatter
@Prefix = 'Credits '
,@Value = @Credits
EXEC PrintFormatter
@Prefix = 'Fees '
,@Value = @Fees
EXEC PrintFormatter
@Prefix = 'Balance '
,@Value = @Balance
END
GO
## 格式化数字
CREATE Function dbo.FormatValue
(
@Value NUMERIC(18,2)
)
RETURNS VARCHAR(18)
AS
BEGIN
DECLARE @RTN VARCHAR(18)
IF @Value < 0
SET @RTN = '- ' + CONVERT(VARCHAR(18),@VALUE *-1)
ELSE
SET @RTN = ' + ' + CONVERT(VARCHAR(18),@VALUE)
RETURN @RTN
END
GO
## 自定义前缀
CREATE PROCEDURE dbo.PrintFormatter
@Prefix VARCHAR(20),
@Value Numeric(18,2)
AS
BEGIN
PRINT @Prefix + ': ' + dbo.FormatValue(@Value )
END
GO
这里两个“劳力”,就是用来帮助隐藏“线头”的。
再举个注释的例子。不知道大家平时注释怎么写的,但我知道在注释里写逻辑和硬编码是常有的事情:
/* ++++++++++++++++++
逻辑:
每张退票算 20 元;
如果账户透支超过 3 天,每天产生 10 元的费用;
如果账户余额超过 2000 元,则减少 50% 的费用
++++++++++++++++++++*/
CREATE PROCEDURE fees
@a NUMERIC(18,2),
@b NUMERIC(18,2),
@c NUMERIC(18,2)
AS
BEGIN
DECLARE @Fee NUMERIC(18,2) = 0
IF @a > 0 SET @Fee = @Fee + 20 * @a
IF @b > 3 SET @Fee = @Fee + @b * 10
IF @c > 2000 SET @Fee = @Fee / 2
PRINT @Fee
END
GO
代码里,注释和逻辑,是一模一样的。我们只不过用注释,解释清楚了 a,b,c 到底代表什么意思。
但随着营销活动,或者缴费规则的改变,逻辑会立马变得不一样。于是可能每天产生的滞纳金从 10 元变成了 20元,余额必须超过 5000 元,才半折。
IF @a > 0 SET @Fee = @Fee + 20 * @a
IF @b > 3 SET @Fee = @Fee + @b * 20
IF @c > 5000 SET @Fee = @Fee / 2
但注释依然没变,可能忘记修改了。所以换个人来看,就晕菜了,什么鬼逻辑?
所以,注释依然要遵从 DRY, 如果不能保证与代码一致,那么硬编码的注释,宁可不写。
那么怎么完善这段代码呢?加上有意义的命名:
CREATE PROCEDURE CalculateFees
@ReturnedCheckCount NUMERIC(18,2),
@OverDueDate NUMERIC(18,2),
@Balance NUMERIC(18,2)
AS
BEGIN
DECLARE @Fee NUMERIC(18,2) = 0
IF @ReturnedCheckCount > 0 SET @Fee = @Fee + 20 * @ReturnedCheckCount
IF @OverDueDate > 3 SET @Fee = @Fee + @OverDueDate * 10
IF @Balance > 2000 SET @Fee = @Fee / 2
PRINT @Fee
END
GO
是不是瞬间觉得,学好英语,是必要的?
DRY,这些看起来很细微的原则,有什么用呢?可能仅仅让你不会被接手的程序员,问候家里长辈而已。但我认为,这是一项值得尊重的技巧。
往期精彩: