SQL 编程中的 DRY 原则,你用吗?

有关SQL

共 1787字,需浏览 4分钟

 ·

2020-10-15 12:31

点击蓝色“有关SQL”关注我哟

加个“星标”,天天与10000人一起快乐成长


在朋友圈发了 9张整齐的网线图,引来大家一阵热议。

image

其实,老读者都知道,我有过短暂的网工经历。说的好听点,就是网络工程师,说的接地气点,就是一名网管。

作为一名网管,我深知最可怕的事情,是线路。对于强迫症来说,线路的凌乱,有时候比电脑病毒还难搞。我当时负责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 

可能你觉得这很正常,平时就这么用的。用了十来年了,没出过什么错。就跟这样两张图一样,达到的功能都一样:

image
image

其实,有时候我们做得不够好,往往是没有见过真正做得好的。

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,这些看起来很细微的原则,有什么用呢?可能仅仅让你不会被接手的程序员,问候家里长辈而已。但我认为,这是一项值得尊重的技巧。



--完--





往期精彩:


本号精华合集(二)

如何写好 5000 行的 SQL 代码

如何提高阅读 SQL 源代码的快感

我在面试数据库工程师候选人时,常问的一些题

零基础 SQL 数据库小白,从入门到精通的学习路线与书单









浏览 24
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报