1 引言
近期,我所在的组织(软件研发单位)开始了轰轰烈烈的由传统的管理方式向敏捷转型工作。我们希望通过敏捷,提高研发效率和产品质量。但是,随着时间的推移,发现敏捷并非良药,上上下下对敏捷的热情逐渐消退,敏捷正逐渐走向"灭亡"。
是敏捷对提高效率没有帮助吗?是敏捷在传统企业里面水土不服吗?怎样才能在做好敏捷呢?
本文试图从实际出发,结合系统思考,来反思我们的敏捷。希望这个反思过程,能够给准备进入敏捷,或者正在敏捷中纠结的团队提供参考。
2 敏捷之初――增强环路
图1 敏捷之初――增强环路
敏捷开始之初,领导热情高涨,敏捷推行风风火火,是一个典型的增强环路。(该模型的具体信息,可以参考《第五项修炼》)。
敏捷试点,培训,敏捷推广――敏捷活动"全面"铺开。
开发和测试不打架了,沟通效率明显提升,里程碑的压力被迭代活动稀释了――团队自组织程度提高明显。
需要特别强调的是,在敏捷活动中,管理实践和技术实践会有很多具体的问题。这些问题会制约敏捷活动的进行,不在本环路中体现,后续有机会再开帖子讨论。
3 敏捷之中――成长上限
虽然敏捷有诸多好处,但是,我需要很遗憾的告诉大家,跟所有的增强环路一样,一定有一个平衡环路制约增强环路的成长空间。如图2所示。在敏捷到一定程度时。团队自组织程度提高,工作过程中诸如详细设计、同行评审、内部故障等等表现形式和传统的软件管理大相径庭。对传统管理带来了威胁:
1) 基层组织自我管理――管理层架空了;
2) 敏捷详细设计等研发过程不能在传统的系统中登记――管理过程对象隐形了。
和大多数公司一样,作者所在的组织的管理层,对传统管理持保守态度。他们希望管理可控,他们希望管理架构不要做大的变化;他们也希望敏捷做的越来越好,甚至希望能在冬天里燃气一把火――这在某种程度上加速了敏捷活动在组织中的消亡。因为成长上限模型决定了这一结果:当平衡环路发挥较强作用时,加速推动增强环路,不但不会取得很好的效果,甚至有可能引起增强环路反转。
图2 敏捷之中――成长上限
现实的系统往往是很复杂的。作者所在的组织。在敏捷推行到一定程度时,平衡环路发挥作用,同时内部力量继续猛烈的推动增强环路。敏捷活动中出现了三种情况:
1) 有追求型――想尽一切办法,延缓甚至解除平衡环路对团队自组织程度的制约
2) 因势利导型――一方面降低对传统管理的威胁,一方面推动敏捷,稳打稳扎
3) 放弃型――不搞敏捷了,爱咋咋地
下面我们用三个小节详细展开。
图3 有追求型
有追求型的敏捷团队这样的特点:
有一个强势的团队领导者,拥抱敏捷,对敏捷理解很深,可以跟管理层叫板。
通过强势的敏捷团队领导者的操作,传统管理层的威胁对团队自组织程度的影响大大延迟。敏捷活动这个增强环路可以在相当长一段时间,获得成长空间。
在有追求型的团队里面。还有一些要素需要注意
1) 需要优秀的敏捷实践指导。这样可以及时解决敏捷实践中的管理和技术问题(例如TDD),提高团队的敏捷积极性。
2) 一个合适的项目。那种工期紧,现场问题多就算了。合适项目最好是只用一种编程语言,没有太大工期和现场压力的技术型项目。
3) 几个技术骨干。如果全部是技术骨干,对其他项目会有较大影响。如果全部是新手,肯定也是玩不转的。
4) 对敏捷中的实际问题,不回避。敏捷是一种能力,需要通过实践,踏踏实实做出来,敏捷来不得半点忽悠。
很可惜,作者所在的团队不是有追求型团队。对于有幸在传统自组织中,进入到有追求型团队的兄弟,希望好好把握,在不久的将来,能够得到敏捷的精髓,进而诞生推动更多有追求的敏捷团队诞生。
在因势利导型的团队中,没有一个强势领导。换言之,就是对敏捷活动的支持力度跟上面是一致的。如果自组织团队程度影响到传统管理,他会毫不犹豫的和传统管理站在一起。
在因势利导型团队里面,一般会有两种手段来推进敏捷。
方式1:做好传统管理要求的事情
方式2:延迟传统管理对团队自组织程度的影响
上图:
图4 因势利导型
在方式一中,我们把传统管理要求的平时、设计做好,使得管理层可以"看到"传统管理的对象,从而降低对传统管理的威胁,给敏捷活动创作空间。
在方式二中,我们将传统管理的威胁,通过多层管理过滤和旁路模式(分给其他团队)的方式,延迟传统管理的威胁。这种方式,和有追求型的敏捷团队最大的区别在于延迟的力度或者时间。在本类型中,这个延迟相对来说,是比较"脆弱"的。
放弃型团队是这样一种状况:管理层驱动,团队在没有做好准备的时候"被敏捷";团队领导和团队成员缺乏对敏捷的深入理解和认同。当敏捷活动遇到困难或者团队自组织程度收到传统管理的威胁时,团队敏捷积极性急剧下降,最后就是不了了之。
在这样的团队,基本上就是浪费时间,唯一的收获可能就是对敏捷的"恶感"。
从成长上限模型可知,通过杠杆解发力,可以事半功倍的解决问题。在敏捷活动中,杠杆解即"管理层的目标",如图5所示。
图5杠杆解
需要说明的是,所谓的杠杆解对应的管理层,一般不是公司老总,而是能够对敏捷的组织形式,资源分配,考核等有决策权的管理者。
当然,不是说敏捷跟公司老总没有关系。实际上,敏捷跟公司老总有关系,关系在哪儿呢?在于企业文化。我个人认为,敏捷是有适合的企业文化的。传统的指令型(老大绝对正确性)企业,搞敏捷是有很大风险的。如果敏捷决策管理者对敏捷理解正确,那么,一切可能会朝着OK的方向进行。否则,就有很大可能产生巨大的浪费,甚至造成公司挂掉。
因此,在一个组织里面,要搞好敏捷,首先要搞定管理者。
我们假设大部分企业都是指令型企业(这可能是中国软件研发的普遍状况)。那么在敏捷开始之初,一定要仔细考评敏捷管理决策者对敏捷的理解。如何考评呢:
1) 读过《人件》,《人月神话》
2) 理解敏捷宣言,敏捷的原则
3) 理解敏捷实践,包括实践的普遍性和特殊性。敏捷的技术实践,在特殊性方面表现的尤为突出。如果一个组织有多重技术架构,那么,就会需要对应的技术实践。甚至,有些产品可能压根就做不了某些技术实践,比如TDD。
4) 理解敏捷的组织,评价
5) 理解敏捷适应的环境(高级要求)。不是每一个产品都适合敏捷。
用户名:david_bj 文章数:21 评论数:7 最近机房刚上了一批机器(有100台左右),需要使用Nagios对这一批机器进行监控。领导要求两天时间完成所有主机的监控。从原来的经验来看,两天时间肯定完成不了。那怎么办?按照之前的想法,肯定是在nagios配置文件逐一添加每台客户端的监控信息,工作量巨大。突然,想到一个想法,是否可以通过脚本来实现批量对主机进行监控,也就是运维自动化。 写脚本,最重要的就是思路。思路压倒一切,经过思考最终决定就这么做了。先贴出来一张网路拓扑图: 整个过程可以分为三部分。 cmdb端:主要用来实现对数据的收集,采用两个API,一个是提供给客户机的API。用于将客户端的数据上传的cmdb服务器;另外一个API是nagios通过此API可以得到要监控主机的信息,然后对该信息进行整理,做成nagios监控模板。 Client端:通过Python脚本收集本机器要监控的软硬件信息,然后通过cmdb端提供的API接口将数据上传到cmdb端的数据库。 Nagios端:通过cmdb端提供的API接口实现对cmdb收集到的信息进行抓取,然后将数据写入到模板,最后copy到naigos指定的objects目录,最终实现对客户机的监控。 这三部分最重要的应该是CMDB端。接下来通过安装django和编写API接口实现cmdb可以正常工作。可以将cmdb端分为三个步骤来完成: 安装django 配置django 编写API接口 首先来进行安装django: 在安装django之前首先应该安装python(版本建议2.7.) 创建项目和应用: 配置django: 1.修改setting.py DATABASES = {'ENGIN':'django.db.backends.sqlite','name':path.join('CMDB.db')} #使用的数据库及数据库名 INSTALLED_APPS =(hostinfoINSTALLED_APPS = ('hostinfo') INSTALLED_APPS = ('hostinfo') #应用的名称 2.修改urls.py url(r'^api/gethost\.json$','hostinfo.views.gethosts'), #nagios客户端访问API接口地址 url(r'^api/clooect$','hostinfo.views.collect'), #客户端访问API进行上传数据的API url(r'^admin/',include(admin.site.urls)), #django后台管理登入url from django.contrib import admin admin.autodiscover() 3.修改项目hostinfo下的views.py 代码如下: 4.修改model.py 文件 代码如下: 5.修改admin.py文件
访问量:4715:974:248:2 注册日期:2011-12-21 1.下载django软件包 可以到django官方网站下载最新django软件包(https://www.djangoproject.com). 2.解压缩并安装软件包 tar -zxvf Django-1.5.1.tar.gz cd Django-1.5.1 python setup.py install
1.创建一个项目 python startproject simplecmdb 2.创建一个应用 python startapp hostinfo
# Create your views here. #包含以下模块 from django.shortcuts import render_to_response from django.http import HttpResponse from models import Host, HostGroup #包含json模块 try: import json except ImportError,e: import simplejson as json #用来接收客户端服务器发送过来的数据 def collect(request): req = request if req.POST: vendor = req.POST.get('Product_Name') sn = req.POST.get('Serial_Number') product = req.POST.get('Manufacturer') cpu_model = req.POST.get('Model_Name') cpu_num = req.POST.get('Cpu_Cores') cpu_vendor = req.POST.get('Vendor_Id') memory_part_number = req.POST.get('Part_Number') memory_manufacturer = req.POST.get('Manufacturer') memory_size = req.POST.get('Size') device_model = req.POST.get('Device_Model') device_version = req.POST.get('Firmware_Version') device_sn = req.POST.get('Serial_Number') device_size = req.POST.get('User_Capacity') osver = req.POST.get('os_version') hostname = req.POST.get('os_name') os_release = req.POST.get('os_release') ipaddrs = req.POST.get('Ipaddr') mac = req.POST.get('Device') link = req.POST.get('Link') mask = req.POST.get('Mask') device = req.POST.get('Device') host = Host() host.hostname = hostname host.product = product host.cpu_num = cpu_num host.cpu_model = cpu_model host.cpu_vendor = cpu_vendor host.memory_part_number = memory_part_number host.memory_manufacturer = memory_manufacturer host.memory_size = memory_size host.device_model = device_model host.device_version = device_version host.device_sn = device_sn host.device_size = device_size host.osver = osver host.os_release = os_release host.vendor = vendor host.sn = sn host.ipaddr = ipaddrs host.save() #将客户端传过来的数据通过POST接收,存入数据库 return HttpResponse('OK') #如果插入成功,返回'ok' else: return HttpResponse('no post data') #提供给NAGIOS 的API def gethosts(req): d = [] hostgroups = HostGroup.objects.all() for hg in hostgroups: ret_hg = {'hostgroup':hg.name,'members':[]} members = hg.members.all() for h in members: ret_h = {'hostname':h.hostname, #API接口返回的数据 'ipaddr':h.ipaddr } ret_hg['members'].append(ret_h) d.append(ret_hg) ret = {'status':0,'data':d,'message':'ok'} return HttpResponse(json.dumps(ret))
from django.db import models # Create your models here. #插入数据库的Host表,主要存储客户端主机的信息 class Host(models.Model): """store host information""" vendor = models.CharField(max_length=30,null=True) sn = models.CharField(max_length=30,null=True) product = models.CharField(max_length=30,null=True) cpu_model = models.CharField(max_length=50,null=True) cpu_num = models.CharField(max_length=2,null=True) cpu_vendor = models.CharField(max_length=30,null=True) memory_part_number = models.CharField(max_length=30,null=True) memory_manufacturer = models.CharField(max_length=30,null=True) memory_size = models.CharField(max_length=20,null=True) device_model = models.CharField(max_length=30,null=True) device_version = models.CharField(max_length=30,null=True) device_sn = models.CharField(max_length=30,null=True) device_size = models.CharField(max_length=30,null=True) osver = models.CharField(max_length=30,null=True) hostname = models.CharField(max_length=30,null=True) os_release = models.CharField(max_length=30,null=True) ipaddr = models.IPAddressField(max_length=15) def __unicode__(self): return self.hostname #主机组表,用来对主机进行分组 class HostGroup(models.Model): name = models.CharField(max_length=30) members = models.ManyToManyField(Host)
#from models import Host, IPaddr from models import Host, HostGroup from django.contrib import admin #设置在django在admin后天显示的名称 class HostAdmin(admin.ModelAdmin): list_display = ['vendor', 'sn', 'product', 'cpu_model', 'cpu_num', 'cpu_vendor', 'memory_part_number', 'memory_manufacturer', 'memory_size', 'device_model', 'device_version', 'device_sn', 'device_size', 'osver', 'hostname', 'os_release' ] #在django后台amdin显示的组名称 class HostGroupAdmi
没有评论:
发表评论