2012年十月月 发布的文章

由一个软件库存问题想到的

近期产品线出现这样一个“怪现象”:许多已经完成编码并具备提交给测试组的版本没有测试人员对应。测试部那边给出的策略是:按版本优先级从高到低依次测 试。这样一来一些重要版本需要到3个月甚至更长时间之后才能开始测试。可以肯定这种现象是生产环节的一个问题,但用什么理论去解释和分析这个问题呢?我想 到了“库存” – 软件库存。

Joel说软件》的那个Joel曾写过一篇名为《软件库存》的文章,也正是看了那篇文章后,我才第一次了解到软件库存这个概念。库存似乎是传统制造业中 的一个概念,但软件开发其实也是广义产品生产的一种,虽然有其特殊性,因此有些产品制造方面的理论是可以应用于软件生产过程中的,软件库存就是其中之一。

传统制造业的库存较为容易理解,零件、原材料、半成品以及未卖出去的最终产品这些都可以理解为库存。而软件生产中的库存都包含哪些内容和环节呢?一旦形成库存,利弊又有哪些呢?

* 未纳入开发的需求/特性

这里所说的需求/特性是经过决策后将来要开发的且能带来价值的,而不是为了大而全而滥芋充数的那种。这类需求/特性可理解为已经采购并存放在库中尚未投入 生产的原料库存。这类库存如果变得很大,则很可能说明产品市场场景甚好,但也可能是现有的生产能力出现了不足;如果这块库存过小或没有,则会导致后期开工 不足,或者说产品的持续成长前景黯淡,市场对其的需求也不乐观了,组织对此情况应做出迅速反应。

* 已经开发完毕但未经测试的半成品

开发人员开始投入,根据需求/特性疯狂编码、单元测试,生产出未经专业测试的半成品。这些半成品因其中潜在的许多缺陷而不能作为最终商品投放市场,因此无 法收回成本并赚取利润。一旦这个环节形成库存,则说明后续质量验证环节的生产能力与软件开发环节的生产能力出现了不匹配,这将导致版本中的问题不能尽快地 暴露,使得问题流向其他版本或其他系统中,直到测试开始后才能发现,后续要花费更多的工作量做关联的修正。这也是我所在产品线所遇到的棘手问题,唯一的方 法就是提高质量验证环节的生产能力,至于如何提高,因地制宜,这里不表。而较小的库存或这个环节无库存,也会导致后续质量验证环节的开工不足,或衔接出现 节奏性的问题。

* 未上市或未卖出的成品

当产品顺利通过质量检测部门的测试后,便可正式发布,变成最终产品- 成品,交付到最终用户那里。但如果这个环节出现库存,问题将变得严重得多。要么是前期市场估计过于乐观,要么是行销人员不给力,要么则是生产过剩,没有做 好库存管理等等。如果这个环节库存过小,则最终客户依旧无法及时得到产品,不利于保持客户粘性,客户很可能退而求其次,选择其他厂商的产品了。

以上简要分析既提到了不能忽视库存的存在,也说到了无库存的危害。传统制造行业一直在追求着一种“零库存”的概念,所谓“零库存”,是指物料(包括原材 料、半成品和产成品等) 在采购、生产、销售、配送等一个或几个经营环节中,不以仓库存储的形式存在,而均是处于周转的状态。它并不是指以仓库储存形式的某种或某 些物品的储存数量真正为零,而是通过实施特定的库存控制策略,实现库存量的最小化。在软件生产领域也可借鉴这一概念,在各个环节努力维持合理且适当的库 存,这对整个生产过程是大有裨益的。

可以看出“零库存”的一个精要就是及时收回产品的投资,获得利润,保持生产过程的持续有效进行。这让我想到了当今软件过程的演化:从最初的瀑布过程到目前 流行的迭代和敏捷等过程,以及流行的持续交付等概念,它们似乎都是在追求“零库存”,追求快速回流价值。或者说库存理论潜在地催生了敏捷、持续交付等概念 的迅速发展,并让人们看到其中的裨益所在。

也谈Go语言声明语法

一直在从事C语言服务端应用开发,对C的变量声明语法早已烂熟于胸,同时也深知复杂的C变量声明十分晦涩难解。记得若干年前还特意花了一些时间研究理解复 杂C变量声明的方法,记忆中这些方法包括:《C专家编程》中提到的“优先级”规则、right-left规则以及顺时针/螺旋形规则等,幸运地是我们日常 开发中少有使用极为复杂的变量声明(如void (*signal (int signo, void (*func) (int)))(int);),但C语言中这一难点却是事实存在的。

对于我这样的习惯了C变量声明语法的程序员来说,Go的变量声明语法显得极端另类,完全与C语言反其道而行之,心中不由产生一丝厌恶。但随着对Go学习和 使用的深入,我逐渐发现Go的这种声明语法在不经意间解决了复杂声明的理解问题,你无需学习什么"优先级"规则,也无需理会什么“right-left” 规则,你只需按从左到右的顺序阅读代码,再复杂的变量声明也可以很轻易地理解。

Go语言为何要采用这种倒序语法呢?Go的设计者Rob Pike的一篇介绍Go声明语法的文章给出了答案,其中谈到了Go声明语法的设计考量。Go的设计者从C体系之外的语言获得启发:将变量名放在签名,类型说明放在后 面。这样更接近于自然语言,例如:

x: int
p: pointer to int
a: array[3] of int

b: slice of int

在此基础上,Go的设计者用*、[]等符号替换掉上面的冒号和部分关键字使得声明变得短小,也就形成了Go的声明语法:

var x int
var p *int
var a [3]int

var b []int

我们只需从左向右的顺序阅读代码,即可清晰的理解声明的含义,而不需要像C声明语法那样左右符号都要兼顾,螺旋理解。这里面的*、[n]和[]的含义如下:

*some_type:读作 pointer to some_type
[n]some_type: 读作 array[n] of some_type
[]some_type: 读作 slice of some_type

下面我们通过Go与C的对比来进一步理解Go的声明语法。

简单变量声明

                                           Golang
int x;      <–>      var x int //x has the type int
float x;    <–>      var x float64 //x has the type float64
char c;     <–>      var c byte
//x has the type byte

指针变量声明

C                                            Golang
int *x;     <–>      var x *int //x is a pointer to int
int **p;    <–>      var p **int //p is a pointer to pointer to int 

数组/切片变量声明

C                                            Golang
int a[5];     <-->    var a [5]int //a is an array[5] of int
int a[5][3];  <-->    var a [5][3]int  //a is an array[5] of array[3] of int

                                            var s []int //s is a slice of int(C语言中无slice类型)

函数类型变量声明

C                                            Golang
int (*x)(int, int) 类似于   var x func(int, int) int // x has the type "func(int, int) int"
     

Go中函数为first-class类型,其类型的变量等同于C中的函数指针。

复合声明(复杂声明)

C                                            Golang
int *x[5];   <-->       var x [5]*int //x is an array[5] of pointer to int
int (*x[5])(int, int)   类似于  var x [5]func(int, int) int // x is an array[5] of "func(int, int) int" 

                                                var f func(func(int,int) int, int) func(int, int) int //f has the type "func(func(int,int) int, int) func(int, int) int",这是一个函数类型变量,这个函数类型接收三个参数(其中一个参数是func(int, int)函数类型),并返回另外一个函数类型(func(int, int) int)。

void (*signal (int signo, void (*Afunc) (int))) 类似于  var signal func(signo int, Afunc func(int))

有了上面的例子,signal就无需再作解释了,Go的声明语法可以让我们可以很容易的理解复杂的变量声明。但从可读性角度来看较长的声明依旧不利于代码理解。因此我们还是应该通过type定义一些新类型的方式尽量缩短变量声明的长度,例如:

type Handler func(int)
type SignalHandler func(signo int, handler Handler)
var signal SignalHandler

欢迎使用邮件订阅我的博客

输入邮箱订阅本站,只要有新文章发布,就会第一时间发送邮件通知你哦!

这里是 Tony Bai的个人Blog,欢迎访问、订阅和留言! 订阅Feed请点击上面图片

如果您觉得这里的文章对您有帮助,请扫描上方二维码进行捐赠 ,加油后的Tony Bai将会为您呈现更多精彩的文章,谢谢!

如果您希望通过微信捐赠,请用微信客户端扫描下方赞赏码:

如果您希望通过比特币或以太币捐赠,可以扫描下方二维码:

比特币:

以太币:

如果您喜欢通过微信浏览本站内容,可以扫描下方二维码,订阅本站官方微信订阅号“iamtonybai”;点击二维码,可直达本人官方微博主页^_^:
本站Powered by Digital Ocean VPS。
选择Digital Ocean VPS主机,即可获得10美元现金充值,可 免费使用两个月哟! 著名主机提供商Linode 10$优惠码:linode10,在 这里注册即可免费获 得。阿里云推荐码: 1WFZ0V立享9折!


View Tony Bai's profile on LinkedIn

文章

评论

  • 正在加载...

分类

标签

归档



View My Stats