艾莉亚的猫 Time is limited, To be a better man

不要删除数据

Oren Eini(又名Ayende Rahien)建议开发者尽量避免数据库的软删除操作,读者可能因此认为硬删除是合理的选择。作为对Ayende文章的回应,Udi Dahan强烈建议完全避免数据删除。

所谓软删除主张在表中增加一个IsDeleted列以保持数据完整。如果某一行设置了IsDeleted标志列,那么这一行就被认为是已删除的。Ayende觉得这种方法“简单、容易理解、容易实现、容易沟通”,但“往往是错的”。问题在于:

删除一行或一个实体几乎总不是简单的事件。它不仅影响模型中的数据,还会影响模型的外观。所以我们才要有外键去确保不会出现“订单行”没有对应的父“订单”的情况。而这个例子只能算是最简单的情况。……

当采用软删除的时候,不管我们是否情愿,都很容易出现数据受损,比如谁都不在意的一个小调整,就可能使“客户”的“最新订单”指向一条已经软删除的订单。

如果开发者接到的要求就是从数据库中删除数据,要是不建议用软删除,那就只能硬删除了。为了保证数据一致性,开发者除了删除直接有关的数据行,还应该级联地删除相关数据。可Udi Dahan提醒读者注意,真实的世界并不是级联的:

假设市场部决定从商品目录中删除一样商品,那是不是说所有包含了该商品的旧订单都要一并消失?再级联下去,这些订单对应的所有发票是不是也该删除?这么一步步删下去,我们公司的损益报表是不是应该重做了?

没天理了。

问题似乎出在对“删除”这词的解读上。Dahan给出了这样的例子:

我说的“删除”其实是指这产品“停售”了。我们以后不再卖这种产品,清掉库存以后不再进货。以后顾客搜索商品或者翻阅目录的时候不会再看见这种商品,但管仓库的人暂时还得继续管理它们。“删除”是个贪方便的说法。

他接着举了一些站在用户角度的正确解读:

订单不是被删除的,是被“取消”的。订单取消得太晚,还会产生花费。

员工不是被删除的,是被“解雇”的(也可能是退休了)。还有相应的补偿金要处理。

职位不是被删除的,是被“填补”的(或者招聘申请被撤回)。

在上面这些例子中,我们的着眼点应该放在用户希望完成的任务上,而非发生在某个 实体身上的技术动作。几乎在所有的情况下,需要考虑的实体总不止一个。

为了代替IsDeleted标志,Dahan建议用一个代表相关数据状态的字段:有效、停用、取消、弃置等等。用户可以借助这样一个状态字段回顾过去的数据,作为决策的依据。

删除数据除了破坏数据一致性,还有其它负面的后果。Dahan建议把所有数据都留在数据库里:“别删除。就是别 删除。”

日志分析脚本

最近看到一个很nice的脚本,写的很牛逼,功能也比较强大,已被Oschina收录 考虑后续能不能稍加修改,工作中使用起来

获取方式: git clone https://github.com/alex8866/lpp

主要功能如下

  • 脚本合适用来监视大型日志文件(根据扫描频率将日志增量的部分进行分析)

  • 将监视的错误信息发送到指定邮件列表

  • 设置监视频率

  • 将错误信息发送到指定tty

  • 自动指定脚本从何时开始监视,何时结束监视

  • 指定错误发生时脚本所有执行的操作( -c ./command )

  • 配色功能

  • 日志分析以及生成日志报告(这个还真没有发现)

  • 指定所要监控的报错信息(可根据自己需求修改awk.example文件)

我也只是大体上看懂,有些细节也没有很深入的看,mark 一下

脚本中的一些实现方法值得学习和借鉴,为了能更好的理解,挑选几处重要的地方做一下注释

微服务系列文章

csdn看到的一个微服务系列的译文

lmy86263的博客

Introduction to Microservices

Using an API Gateway

Inter-Process Communication in a Microservices Architecture

Service Discovery in a Microservices Architecture

Event-Driven Data Management for Microservices

Choosing a Microservices Deployment Strategy

Refactoring a Monolith into Microservices

实现shell脚本中的转圈、进度条等一些效果

要将shell脚本做的好玩好看,核心就是echo的使用问题,还有就是一些实现上的小技巧,从网上学习整理了一些做个备份。

一、Echo

  • 开始shell光标闪烁

echo -e "\033[5m . \033[0m"

二、转圈效果

#!/bin/bash
function waiting()
{
    i=0
    while [ $i -le 100 ]
    do
        for j in '\\' '|' '/' '-'
        do
            printf "\t\t\t\t%c%c%c%c%c test waiting %c%c%c%c%c\r" \
            "$j" "$j" "$j" "$j" "$j" "$j" "$j" "$j" "$j" "$j"
            sleep 0.1
        done
        let i=i+4
    done
}
waiting

三、进度条效果

  • 通过符号#填充[ ]完成进度
#!/bin/bash
i=0
str=""
arry=("\\" "|" "/" "-")
while [ $i -le 100 ]
do
    let index=i%4
    printf "[%-100s] %d %c\r" "$str" "$i" "${arry[$index]}"
    sleep 0.1
    let i=i+1
    str+="#"
done
echo ""
  • 每个阶段有不同颜色区分进度
#!/bin/bash
i=0
str=""
arry=("\\" "|" "/" "-")
while [ $i -le 100 ]
do
    let index=i%4
    if [ $i -le 20 ]; then
        let color=44
        let bg=34
    elif [ $i -le 45 ]; then
        let color=43
        let bg=33
    elif [ $i -le 75 ]; then
        let color=41
        let bg=31
    else
        let color=42
        let bg=32
    fi
    printf "\033[${color};${bg}m%-s\033[0m %d %c\r" "$str" "$i" "${arry[$index]}"
    usleep 30000
    let i=i+1
    str+="#"
done
echo ""
  • 按照百分比显示进度

printf %3d为显示百分比预留了3位,循环条件i每次递增5主要是为了减少进度条显示的长度

i每次递增5,取模之后的index值还是依次循环,保证了转圈圈的方向和频率

改用其他数字,转圈的显示效果没有add=4n+1时的好

#!/bin/bash
i=0
str=""
arry=("|" "/" "-" "\\")
while [ $i -le 100 ]
do
    let index=i%4
    printf "%3d%% %c%-20s%c\r" "$i" "${arry[$index]}" "$str" "${arry[$index]}"
    sleep 0.2
    let i=i+5
    str+="*"
done
echo ""
  • 进度条递进填充

ssty size获取终端X轴和Y轴长度

total=total_stdx-2head 用来控制整个进度条的长度,左右各预留了head长度

per和remain相加永远是total大小

y;xH设置光标位置,${total_stdy};0H设置光标在终端的左下角

%${n}s指定了宽度为n个字符,%${per}s+%${remain}s的总宽是total不变的

设置两个不同颜色的宽度区域,用来显示进度变化,参数赋值空字符串

#!/bin/bash

total_stdy="$(($(stty size|cut -d' ' -f1)))"
total_stdx="$(($(stty size|cut -d' ' -f2)))"

head="Progress bar: "
total=$[${total_stdx} - ${#head}*2]

i=0
loop=100
while [ $i -lt $loop ]
do
    let i=i+1
    
    per=$[${i}*${total}/${loop}]
    remain=$[${total} - ${per}]
    printf "\r\e[${total_stdy};0H${head}\e[42m%${per}s\e[47m%${remain}s\e[00m" "" ""
    sleep 0.1
done

echo ""

软件工程的事实与谬误

55个事实

管理

1.1人员

事实1:在软件开发中,最重要的因素不是程序员采用的工具和技术,而是程序员自身的质量

事实2:对“个体差异”的研究表明,最好的程序员要比最差的程序员强28倍之多。即使他们的报酬不同,优秀程序员也是软件业中最廉价的劳动力。

事实3:给延期的项目增加人手会使项目进一步延期。

事实4:工作环境对工作效率和产品质量具有深刻影响。

1.2工具和技术

事实5:夸大宣传是软件的瘟疫。多数软件工具对于效率和质量的提高幅度仅为5%~35%。但是总有人反复说提高幅度是“数量级”的

事实6:在学习新工具或者新技术的初期,程序员的工作效率和产品质量都会下降。只有克服了学习曲线以后,才可能得到实质性的效益。只有满足下面两个条件,采用新工具或新技术才有意义:(a)新东西确实有用;(b)要想获得真正的收益,必须耐心等待。

事实7:软件开发者对于工具说的多,评估的少,买的多,用的少。

1.3估算

事实8:项目失控的两个最主要的原因之一是糟糕的估算(另一个原因见事实23)

事实9:许多估算是在软件生命周期开始时完成的。后来,我们才认识到在需求定义之前,即理解问题之前进行项目估算是不正确的;也就是说,估算时机是错误的。

事实10:许多软件项目都是由高层管理人员或者营销人员来估算,而不是由真正构建软件的人或者他们的主管来进行估算。因此,估算软件的人员是错误的。

事实11:软件估算很少根据项目进度进行调整。因此,这些估算通常是错误的人在错误的时间得出的错误的结果。

事实12:因为估算的数据如此糟糕,所以在软件项目不能达到估算目标时,不应该再考虑估算。但是无论如何,每个人都在考虑它。

事实13:在管理者和程序员之间存在隔阂。对于一个未满足估算目标的项目的调查表明:从管理者看来这是一个失败的项目,而在技术人员看来确实最成功的项目。

事实14:对于可行性调研的回答几乎总是“可行”。

1.4复用

事实15:小规模的复用(子程序库)开始于50多年以前,这个问题已经得到很好的解决。

事实16:虽然每个人都认为大规模复用(组件)非常重要、非常急需,但是这个问题至今还没有基本解决。

事实17:大规模复用最好适用于相关的系统,也就是依赖于具体应用领域,这样就限制了它的应用范围。

事实18:有关复用问题,有两个“三倍原则”:(a)构建可复用的组件比使用组件难三倍;(b)在将组件收录到复用库并成为通用组件之前,应该在三个不同的应用中尝试应用该组件。

事实19:修改复用的代码特别容易引起错误。如果一个组件中超过20%~25%的代码需要修改,那么重新实现的效率会更高。

  • 由此引出的另外一个事实是:修改经过打包的商业性软件系统通常是错误的。

事实20:设计模式复用是解决代码复用中固有问题的一种方法。

1.5复杂性

事实21:问题的复杂性每增加25%,解决方案的复杂性就增加100%。这不是一个可改变的条件(即使人们都努力降低复杂性),而是客观存在的。

事实22:80%的软件工作是智力活动。相当大的比例是创造性地活动。很少是文书性的工作。

生命周期

2.1需求

事实23:导致项目失控的两个最常见原因之一是不稳定的需求(另一个见事实8所说的项目估算失误)。

事实24:在产品完成时修订需求错误的代价最大,在开发早期修订需求错误的代价最小。

事实25:遗漏需求是最难修订的需求错误。

  • 该事实的一个必然结论是:最持久的软件错误是遗漏逻辑错误,它可以逃过软件测试过程,进入发布的产品中。遗漏需求会导致遗漏逻辑。

2.2设计

事实26:从需求转入设计时,因为制定方案过程的复杂性,会激增出大量的衍生需求(针对一种特定设计方案的需求)。设计需求是原始需求的50倍之多。

事实27:对于一个软件问题,通常不存在唯一的最佳设计方案。

事实28:设计是一个复杂的、迭代的过程。最初的设计方案可能是错误的,当然也不是最优的。

事实29:从设计到编码阶段时,设计者按照自己掌握的水平,已经将问题分解为“原语”。如果编程者和设计者不是同一个人,二者的“原语”不吻合,就会出问题。

事实30:COBOL是一种非常糟糕的语言,但是其他的(用于商业数据处理的)语言也同样糟糕。

事实31:错误消除是软件生命周期中最耗时的阶段。

事实32:普通程序员认为已经彻底测试过的软件其实只执行了55%~60%的逻辑路径。采用覆盖分析器等自动工具,可以将上述比例提高到85%~90%。几乎不可能测试软件中100%的逻辑路径。

事实33:即使测试覆盖有可能达到100%,这种测试也不够。大约35%的错误是源于逻辑路径的缺失,还有40%的错误源于执行特定的路径组合。不可能实现100%的覆盖。

事实34:没有工具就无法做好错误消除工作。人们常用调试器,很少使用覆盖分析器等其他工具。

事实35:自动测试很少,也就是说有些测试可以也应该自动化,但是有许多测试任务不能自动完成。

事实36:程序员在程序中嵌入测试代码、目标代码中的编译参数等方法,都是测试工具的重要补充。

事实37:在运行第一个测试用例之前进行严格审查可以消除软件产品中多大90%的错误。

事实38:虽然严格审查有很多优点,但是不能也不应该代替测试。

事实39:通常认为,事后评审对于了解客户的满意度和改进过程都很重要。但是很多软件公司不开展事后评审。

事实40:同行评审涉及技术和社会两方面问题,忽视任何一方面都回产生严重的灾难。

2.7维护

事实41:维护开支通常占软件成本的40%~80%(平均为60%)。因此,维护可能是软件生命周期中最重要的阶段。

  • 由此引出的一个必然结论:古老的硬件会被抛弃,古老的软件每天都在使用。

事实42:增强功能大约占软件维护成本的60%,错误更正仅占17%。因此,软件维护的主体是在旧软件中加入新功能,而不是更正错误。

事实43:维护是解决方案,而不是解决问题。

事实44:比较软件开发和软件维护中的工作,除了维护中“理解现有的产品”这项工作之外,其他工作都一样。这项工作占据了大约30%的维护时间,是主要的维护活动。因此可以说维护比开发更难。

事实45:更好的软件工程开发导致更多而不是更少的维护。

3 质量

3.1质量

事实46:质量是一组属性的集合。

事实47:软件质量不是用户满意、满足需求、满足成本和时间表目标,或者可靠性。

3.2可靠性

事实48:绝大多数程序员都会犯某些错误。

事实49:错误通常聚集在一起。

事实50:没有唯一最好的消除软件错误的方法。

事实51:总会有残存的错误。我们的目标应该是消除严重错误,或者使之最少。

3.3效率

事实52:效率主要来自于优秀的设计,而不是优秀的编码。

事实53:高级语言(High-order language,HOL)代码配合适当的编译器优化,大约可以达到汇编语言90%的效率。对于一些复杂的现代体系结构,效率更高。

事实54:在空间和时间之间存在折中。通常,改进一方面会降低另一方面。

4 研究

事实55:许多软件研究者不是做调查,而是鼓吹。因此,(a)有些概念比鼓吹的糟糕、更少;(b)缺少有助于确定这些概念真是价值的评估性研究。

5+5谬误

管理

谬误1:你不能管理自己无法度量的东西。

谬误2:可以管理软件产品的质量。

5.1人员

谬误3:可以,也应该“忘我”地编程。

5.2工具和技术

谬误4:工具和技术是通用的。

谬误5:软件需要更多的方法论。

5.3估算

谬误6:要估算成本和时间表,应首先估算代码行数。

生命周期

6.1测试

谬误7:随机测试输入是优化测试的好方法。

谬误8:“假如有了足够多的关注,所有的bug都显而易见。”

6.2维护

谬误9:估计将来的维护成本和做出产品更新的决策需要参考过去的成本数据。

谬误10:教别人编程的方法是教别人写程序。