敏捷教练与管理3.0

我们的团队具有亲身经历的多年敏捷实战经验,完整体验过从开发工程师、SM直至研发经理的不同角色与挑战。
另外,我们推崇管理3.0思维,以复杂性思维来应对敏捷时代进行管理的不确定性。
在这个充满变化的时代,我们希望通过外部教练与内部变革领导者共舞,帮助企业建立应对变化的敏捷性,从价值入手,改善交付速度,提高质量和效率。

软件产品及其团队是一个复杂网络系统,唯有通过不断地检视与调整,缩短反馈周期,加速进化。
作为敏捷教练,我们将与客户共同成长。除了将业界先进实践经验带给客户形成一些改变,我们更愿意和重视利用教练和引导技术,结合上下文,让蜕变在客户身上发生。改变只是表面和一时的,而蜕变意味着理念与价值观的革新,意味着当教练离场时,团队仍会继续自我进化,不断改进。

另外,我们知道,进化在自然界并非连续发生的。根据“间断平衡”论,每个系统都处于某种稳定态,具有抗扰动的能力。要想形成蜕变,需要借助足够的外力让系统脱离稳态的惯性,重组系统参数,直至进入新的平衡。这里的外力不仅仅是外部教练的指导,更多来自企业内在变革的动力,特别是管理者的支持。敏捷管理者的职责不再是设计组织,而是创造一个容许失败的多样性环境,让敏捷团队自行生长出来。毕竟,“人是环境的产物”。

Read More

Scrum Gathering 2014 组织者见闻

今年有幸受到路宁等社区朋友的举荐,以及炫姐姐的邀请,加入到麦兜团队,担任话题内容的总体制作人,负责第二天整天以及第三天上午的内容。
虽然在社区做了几年的活动,但在大会担任制作人,而且是负责所有的话题track,还是第一次。足见大家对我的信任。

Read More

Scope-Question-Assumption需求梳理会(需求澄清预习PK)

SQA-workshop

关于需求的讨论

最近在辅导敏捷团队和教授Scrum课程中,发现团队提出的很多的问题现象可以归结为迭代前需求梳理(Refinement/Grooming)讨论不充分所导致。
根据自己多年亲身实践的敏捷经验,如果在迭代的计划会议上,团队来不及做到澄清和一致理解需求,而是在迭代过程中再进行需求澄清,那么往往导致“迭代紧张、测试不充分、估算不准确、精神面貌不良”等表面现象。
因此,对需求的充分理解应该是迭代的入口条件,应该成为Definition of Done (也有同学喜欢称之DoR, 笔者认为DoR也是DoD的一部分) 的一部分,来确保迭代能够健康地开始。
然后,更深入的根源则是团队不了解如何进行一场高效充分的讨论

敏捷是一种辅助实现交付价值的手段,不应该过于繁重。下面就根据@申导 早年在诺基亚西门子通信工作时所学到的一种简洁讨论法:Scope-Question-Assumption(简称SQA)讨论会。

Read More

高绩效Scrum团队的4个特征

作者:Bill Li 李国彪

最近的课程碰到了很多ScrumMaster和Product Owner对于打造高效能团队(效率和效果并重)的困惑和疑问,这也促发我们对这个问题再次的关注、思考及总结。简而言之,我们觉得团队的打造方向就是四个重点特征:纪律性;主动性;合作性;创新性

Read More

Docker初探

工作步骤

Docker所用的虚拟镜像的基线版本都是Ubuntu系统。
当运行docker run xxx之后,

  1. Docker客户端连接到Docker守护进程
  2. 如果本地没找到xxx镜像的话,Docker守护进程就从Docker Hub仓库中拉下(pull) xxx镜像
  3. Docker守护进程根据xxx镜像创建一个新的容器(container), 从其中来执行程序并产生输出内容
  4. Docker守护进程将输出内容流到(stream)Docker客户端,然后发送到终端

常用命令

官网入门教程的几个常用命令

docker version
docker search tutorial
docker pull learn/tutorial
docker run learn/tutorial echo "hello world"
docker run learn/tutorial apt-get install -y ping
docker ps -l
docker commit 698 learn/ping
docker run learn/ping ping google.com
docker ps
docker inspect efe
docker images
docker push learn/ping

Read More

在Windows上采用IIS来运行Django

给客户做一个内部软件项目,客户愿意配合敏捷、精益创业的思维,快速交付之后再不断通过用户反馈来调整。
于是就采用基于Python语言v2.7的Django框架V1.4来进行开发。
花了些日子,初具雏形。双方约定先部署,让内部员工开始试用。然后客户把目标服务器交给我了。

Django对Apache或Nginx的支持会方便些(http://www.jackyshen.com/2012/08/12/running-django-gunicorn-via-nginx/)。可是,这是一台带有公网IP的托管的Windows Server2003。上面运行有IIS 6.0,并且已经有另外两个web应用在运行。为了尽量能不影响原有应用,就考虑尝试一下在Windows上采用IIS来运行Django。

于是google一把,结果发现了PyISAPIe…

Read More

精益软件开发的七种浪费

取自Shigeo Shingo的丰田精益制造。与制造业进行对比,是因为比起想象一个软件,我们更容易想象制造一辆汽车。

制造 软件开发
在制品库存 部分完成的工作
过度生产 额外功能
额外的过程 重复学习和手工动作
运输 任务交接
移动 人员任务切换
等待 延迟
缺陷 缺陷

Read More

SVN pre-commit hook

某团队希望做到Continuous Code Review, 想在每次check-in 到SVN之前,先判断特定用户群体否在commit log里面包含了”Review By: xxx”的字样。

记得以前NSN里面有人用过这个法子,记不太清了。

于是研究了一下脚本,其实SVN/GIT都提供了类似的hook, 在<your repository>/hooks 目录下,都是shell或cmd脚本(要看服务器的操作系统了),会在不同的事件时触发。

为了实现更复杂的功能或者需要跨平台,那不妨用shell或cmd去调用Python脚本咯。

Read More

网球的内心游戏--敏捷教练技术起源必读

The inner game of tennis
《网球的内心游戏》

原著:W.Timothy Gallwey (美国)

导言

每种游戏或活动都包含两个部分,外在的和内在的。外在的或表面的游戏就是和外在的对手进行对抗,并超越外在的障碍,达到一个外在的目标。以网球这种游戏为例,外在的障碍就是为战胜对手必须尽量将每个球打出好的落点和速度,同时减少失误,这样才可能取得比赛的胜利甚至赢得最后的冠军。对于掌握这种外在的游戏,很多书都提供了不少的指示:比如如何引拍,挥拍,随挥。以及眼睛、头、手腕、小臂、大臂、肩、腰、腿、髋,等等甚至脚尖各自该怎么做才能达到最佳的效果。但事实上,我们当中很多人都发现这些指令说起来容易,做起来难。

(好比学跳舞,最有效的学习方式是观察人家如何跳,然后跟着音乐去找那个感觉,第一次可能脚出错了,不要紧,慢慢地你就找到那个感觉了,先是脚的顺序对了,手也跟着动了,胯也跟着动了,接下来,就是多跳,然后熟能生美了。很少有人去看示意图,先左脚45度跨一步出去,然后右脚如何如何,这个习得过程我们基本不思考,只是用我们的身体去感知和模仿别人的身体,意识很淡,基本不用意识去指挥,音乐一响,身体自动地动就行了。译者注)

这本书想要说的是,在尝试掌握任何技能的过程中,只是重视这些外部的指令,而忽视相关的内在技能习得规律,是不可能取得满意的效果的。内在的技能习得规律我们这里暂时称为内心游戏。这种游戏发生在球员的内心,内心游戏所面对的对手是自己,障碍表现的形式是,专注力的失去,过度的紧张,不自信,习惯性自责等。简言之,就是要战胜所有妨碍我们”正常”表现的负面心理习惯。

Read More

learning-go-lang

安装

由于墙,http://golang.org 国内无法访问,其它在线教程也一样
http://tutorial.golang.org
http://go-tour-zh.appspot.com/

可以在本机运行,
先安装Go 编译器 http://code.google.com/p/go/downloads/list

然后安装教程

1
go get code.google.com/p/go-tour/gotour  

或者中文的

1
go get bitbucket.org/mikespook/go-tour-zh/gotour  

最后执行安装产生的 gotour 执行文件,即可在http://localhost:3999 打开教程。
一些练习的答案

##46 练习:斐波纳契闭包

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import "fmt"  

// fibonacci 函数会返回一个返回 int 的函数。
func fibonacci() func() int {
var a int = 1
var b int = 1

return func() int {
c := a+b
a = b
b = c
return c
}
}

func main() {
f := fibonacci()
for i := 0; i < 10; i++ {
fmt.Println(f())
}
}

##69 练习:等价二叉树

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
package main  

import (
"bitbucket.org/mikespook/go-tour-zh/tree"
"fmt"
)

type Tree struct {
Left *Tree
Value int
Right *Tree
}

// Walk 步进 tree t 将所有的值从 tree 发送到 channel ch。
func Walk(t *tree.Tree, ch chan int) {
if t != nil {
Walk(t.Left, ch)
ch <- t.Value
Walk(t.Right, ch)
}
}

// Same 检测树 t1 和 t2 是否含有相同的值。
func Same(t1, t2 *tree.Tree) bool {
ch1 := make(chan int, 10)
go Walk(t1, ch1)

ch2 := make(chan int, 10)
go Walk(t2, ch2)

for i := 0; i < 10; i++ {
if <-ch1 != <-ch2 {
return false
}
}
return true
}

func main() {
fmt.Println(Same(tree.New(1), tree.New(1)))
}

##57 练习:错误处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package main  

import (
"fmt"
)


type ErrNegativeSqrt float64

func (e ErrNegativeSqrt) Error() string {
return fmt.Sprintf("cannot Sqrt negative number: %f", e)
}

func Sqrt(f float64) (float64, error) {

if f < 0 {
return 0, ErrNegativeSqrt(f)
}

x := f
for i := 0; i < 10; i++ {
x = (x + f/x) / 2
}
return x, nil



}

func main() {
fmt.Println(Sqrt(2))
fmt.Println(Sqrt(-2))
}

##44 练习:Map

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package main  

import (
//"fmt"
"strings"
"bitbucket.org/mikespook/go-tour-zh/wc"
)

func WordCount(s string) map[string]int {
result := map[string]int {}
f := strings.Fields(s)
for _, v := range f {
result[v] += 1
}
return result
}

func main() {
wc.Test(WordCount)
}