敏捷中国十八年目睹之怪现状(节选)

原文: https://mp.weixin.qq.com/s/AKGT056I3JnH2iKh9r07GA

……略……


3.十八年后,行业的基本功扎实了吗?

有这么好的政策在这儿,十八年以后,我们行业的基本功补齐了吗?我们行业的基本功扎实了吗?
我觉得这个事情不能用非常抽象的方式来讲,我来讲几个真实的“鬼故事”。

需求管理?
比如说需求管理我可以讲个故事。2009 年、2010 年的时候,我当时在很著名的某家通信企业指导一个项目,当时跟华为的两个系统工程师去客户那调研需求。去之前这两位工程师说:“你不知道,我们这个客户是妖怪,没事儿就骂我们,动不动就改需求,特别的可怕。”我说我去看一下吧,了解一下这个妖怪的客户都是怎么回事儿。
约到客户上午 9 点钟开始调研需求,我们几个人走过去,这两位系统工程师上去:“你好,现在你有什么需求,请告诉我们。”后来我看《人民的名义》那个片,我就联想起这两位系统工程师调研需求的场景,他走到那儿把手一伸:“请开始你的表演。”然后客户就开始讲,一上午三个小时,客户大概讲了 2 小时 58 分钟,两个系统工程师讲了可能不到 10 句话,包括“你好”、“请开始你的表演”、“谢谢”。
然后需求调研就完了,中午的时间写会议纪要,写完以后给客户发出去,20 分钟以后客户打电话过来开始骂人,整个办公室都听见了:“你们做的是什么需求调研?我一早上给你讲了 3 个小时,讲了 5 个要点,你邮件纪要发过来只有 3 个要点,你浪费我一早上时间逗我玩吗?”
这个就是我们行业里面很领先的企业调研需求的方式。类似的行为我后来看到过很多次,大家去“调研需求”到底是干什么?就是走去:“客户爸爸你好,请问你有什么需求,请你告诉我。”这样调研需求,需要什么技能、需要什么专业能力?什么都不需要。这个就是人类本能好吗?“我想知道一件事,请你告诉我可以吗?”这个 6 岁小孩也会。从这些现象里,我后来总结出来一个概念叫做“全凭本能工作”。我们这个行业里有很多本来应该是专业人士做的专业工作,实际上是全凭本能在做,看不到专业的能力。

项目管理?
说完需求管理我们再来说项目管理。我们这个行业的项目管理到底是怎么做?你找一个项目经理来问,你的项目管理是怎么做的?他能跟你讲很多大道理。但你到软件开发的现场里面去,到项目组里面待个两星期,你看看项目管理到底怎么发生的。真实的情况经常是这样:
项目经理走过来问:“你这个任务哪天可以完成?”
开发:“下个礼拜一吧。”
项目经理:“下个礼拜一?这个时间太长,礼拜五能不能完成?”
开发:“不行,这工作量太大了。“
项目经理:“就礼拜五,我们礼拜五就上线了。“
开发:“好吧,礼拜五就礼拜五,我加个班,挑战一下!“
是不是我们真正的项目管理就是这样发生的?你说这个项目管理,到底管理什么?真实项目里的工作量评估是怎么估的?
开发说:“做这个要 5 天。“
项目经理:“凭什么要 5 天,明明 2 天就做完了。“
开发:“那 3 天吧。“
这是项目管理吗?这是卖白菜。

配置管理?
然后我们再来说配置管理。我以前做一个持续集成的咨询项目,我先非常自信地把代码库 check out 出来,然后我去打一杯咖啡回来再看看。打完咖啡,发现还没有 check out 完,那我再去开个会。开完会回来看看,还没有 check out 完,那我再去吃个午饭。吃完饭回来看看,还没有 check out 完,我就纳闷了。
我:你们这个代码库怎么这么久还没有 check out 完呢?
客户开发:你自己在 check out?,我们都不这么干,我们都是从别人那里拿一个移动硬盘拷过过来。
我:你代码库多大?
客户开发:代码库有 5 个 G……
**后来我拿一个移动硬盘把代码拷过来一看,这个代码库有 5 个 G,上面有一千多个分支。这就是 CMM 五级的企业的配置管理水平。**很多故事我都不好意思说,鬼故事讲出来吓死人。

质量管理?
接着我们再说说质量保障。为什么现在行业里面大家搞迭代,周期都是两个礼拜一个版本,成了行业共识?因为都是一帮测试小姑娘跟着屁股后面做人肉测试,你怎么敢继续缩短呢?你缩短到一个礼拜发一个版本,然后小姑娘就得每个礼拜天天加班。这就是我们这个行业里的质量保障水平。
所以,像我这种工作时间长的人就非常好奇。我 2001 年就看见了当时搞 CMM 的时候,有很多的培训公司讲课,然后政府又有补贴,通过 CMM 的公司非常多。那这个事情到底是怎么跑偏的?为什么大家搞了十几年的 CMM,到现在行业里面的能力是这样的,各个公司都是全凭本能在工作?前两天有一个群里有人说:“我们公司的研发管理做减法,不写文档了,做完减法之后我们非常敏捷。”我说你们从来就没有研发管理,做的什么减法呢?你们有一堆文档,但是文档跟真正发生的研发根本就是两码事,实际上的研发就是大学实验室的工作方法,大家全凭本能在工作。

4.软件工程是如何跑偏的?

那么软件工程到底是什么时候跑偏的呢?我去年写《敏捷中国史》的时候看了很多的材料,然后发现很多的事情是从根子上跑偏的。一开始,很多专家把软件的生产和制造业相关联。但是非常有趣,尽管这些中国软件工程专家经常讲制造业,但是他们对制造业根本不懂,他们根本不知道这个制造业是怎么发展。
1995 年左右,美国里海大学亚科卡学院受国防部的委托,做了一个叫做《21 世纪制造业挑战》的研究,这个研究报告里讲 21 世纪的制造业有什么特征?是需要高度的定制化、高度的柔性,需要减小批量。听着像什么?像敏捷。而我们国家的软件工程专家们根本不了解制造业的这些新发展。他们在脑子里面自己想象了一个“制造业”,然后说我们的软件工程应该像制造业。他们想象的制造业是少数的精英在上面做设计、下面有大量的软件蓝领把精英的设计一模一样的写出来就完了。
基于这么一个模型,他们就开始搞培训,要求程序员踏踏实实搞工作,不要去想别的,不要去跟需求方打交道,这就是软件蓝领。而同一时期,美国的制造业在说:不应该严格区分设计和制造,不应该限制员工思考的空间。这些专家想象的制造业,跟制造业的发展方向根本南辕北辙。


……略……


7.十八年来唯一真正抓基本功的方法

18 年来,行业里有很多的方法来来去去,真正可以抓软件开发的基本功、真正可以提升软件团队的能力的方法,我觉得就只有极限编程。CMM 提出的这些核心能力,只有极限编程真正提供了。
在这里插入图片描述
一件事应该怎么做,你在书上看到一个说法,和你真正在工作上能做这件事,是相差很大的。
在这里插入图片描述
再比如项目管理,极限编程会告诉你迭代怎么去管,根据什么来看项目的进度。当然项目管理这一部分,我认为 Scrum 也是很好的,非常有效地告诉大家项目管理的方法。
在这里插入图片描述
再说配置管理。到底什么是配置管理?其实配置管理落到根本上就是持续集成。有持续集成,你就有有效的配置管理;没有有效的持续集成,就是没有配置管理,就是这么简单的事情。没有持续集成,你可以说在纸面上有很多配置管理的流程,但真到了需要软件的时候你怎么办?你只能依赖一个配置管理员来手工打包。越是你着急需要打包软件的时候,这个人就越出错、越是打不出包来。好不容易打出来的包一测有问题,然后大家一起加班。所以我说配置管理很简单,你有持续集成、每天可以有一个候选版本通过持续集成打出来,你就有配置管理;出不来,你就没有配置管理。

在这里插入图片描述
那为了让持续集成有效,最后的最后一切都会落到重构和单元测试上面。是不是拥有高覆盖率的、可靠的、运行快速的单元测试,这是一个决定性的分水岭。而高覆盖率的、可靠的、运行快速的单元测试集,得到这个东西最有效的办法,就是测试驱动开发,就是你必须先写测试、再写实现,你才可能得到这么一个有效的测试集。有很多人跟我讲,我们先赶紧写完了实现,回头再去补单元测试。“写完实现再去补单元测试”,这个鬼故事,我每年都听十几次,你们谁见它真正发生的?我们经常听到这个对话:

领导:单元测试很重要,我们要写单元测试。

开发:好好好,等我改完这个版本我就补单元测试。

改完了这个版本就有空了吗?有空了还有下一个版本呢。你在写代码的时候根本没有考虑怎么单元测试,为什么你认为写完实现代码以后就可以补上测试了?你补不上。你会对着一大堆草率堆上去的代码长叹一口气,因为你一开始写代码的时候就没考虑代码的可测试性。

这件事情我觉得非常有趣:软件工程的教科书里面都写着,单元测试是软件开发的重要环节。所有人都认同单元测试的价值,但是谁也不做。然后到了实践里面,大家说我写完这个版本我就补单元测试,然后这个版本完了之后没有补,然后下一个版本来了之后又说,我写完这个版本就补单元测试,下一个版本做完也没有补。这种现象使我对于人类作为一个整体的学习能力非常担忧,因为大家没有从历史中学习的能力:补单元测试这个事情是从来没有发生过的,所以未来它也不会发生,这才是合理的。你根本就不应该相信“我做完这个版本补单元测试”这种话。

所以一切的一切最后都会归结到有没有有效的单元测试集。得到有效的单元测试集最直接的办法,叫做测试驱动开发。我翻译《重构》第二版的时候跟另一个译者林从羽开玩笑说,你告诉任何一个敏捷实施当中遇到的问题,我都可以告诉你这个问题是因为没有做好 TDD。

8.Scrum 为何僵尸化?

比如说前段时间有人发明了一个词叫“僵尸 Scrum”,什么意思?**大家早上开晨会的时候都低着头无精打采的:“我昨天在做这个任务,我今天继续做这个任务,我没有什么问题。”就跟一群僵尸一样的,毫无生气。**你们都见过这个现象吧?为什么会有僵尸 Scrum?因为每个人的任务、每个人负责的代码,是一块一块隔开的,谁跟谁都没有关系。那为什么要把开发一个个隔开呢?因为谁也不敢改别人的代码,别人的代码看也看不懂,看懂也不敢改,改了也不知道有没有引入 Bug。为什么别人的代码看不懂、不敢改、改了不知道有没有破坏功能?因为没有单元测试嘛!为什么没有单元测试?因为你没有 TDD 嘛!

这就是个例子。我半开玩笑说,你告诉我任何一个跟敏捷实施相关的问题,我都能给你推导出来,是因为你没有 TDD。但是这个逻辑太绕,太曲折,很难跟人讲通。我昨天在一个敏捷群里面又跟人吵架。我说我的标准非常简单,有 TDD 的敏捷就是好敏捷,没有 TDD 的敏捷就是伪敏捷。再多的逻辑我都懒得跟他们讲了。郭德纲有一个话,说一个外行跑去跟火箭科学家说你们火箭的燃料不行,得烧煤,还得是精煤,水洗的不行,那科学家要是拿正眼看他一眼都输了——我就输了,那群里的“敏捷专家”连代码都不会写,我还跟他讲 TDD。

9.持续交互、研发云、微服务、DevOps…

再往后就有了很多新的方法,持续交互、研发云、微服务、DevOps…,每一波我都经历过。每一波新方法流行,就会有客户来问我对这个有什么看法。每一次他们来找我问的时候,我发现他们要解决的都是同一个问题。这个问题就是软件开发的质量很差、速度很慢。然后就开始想各种办法绕过这个问题。

比如说微服务流行那年,大家想的是:如果说开发一个单体应用质量很差、开发很慢,那我们是不是可以把单体应用拆分成若干个微服务,每个人负责一小块微服务,然后就可以对质量的要求没有那么高?最后发现,还是不行。一波一波的浪潮过去,看多了之后,我终于明白一个很简单的道理。最后决定开发的质量和效率的是什么?**是持续集成,是持续集成里面运行的测试集的效率和质量。你可以得到一个高效率、高质量的测试集,你就能做好软件。**没有高效率、高质量的测试集,软件开发的效率和质量就不会好。

于是我们又回到这儿来了。大家一波一波的尝试解决同一个问题,但是从来不去解决这个问题的核心,都在绕着问题走,都在想可以用什么样的流程和工具去解决问题,就是不敢直面核心的问题:我的人基本功不行,我们不会 TDD。一次一次去绕,一次一次绕不开。《敏捷宣言》第一句怎么说?人和交互重于流程和工具。但是搞敏捷的公司在做什么?十几年了,一次一次想用流程和工具解决人和交互不行的问题。

以前我做咨询的时候,我必须要为了项目的需要、为了公司收入的需要去配合这些客户,跟他们一起想办法,用流程和工具稍微缓解一下问题。现在我不做咨询了,我终于可以说实话了:这个核心问题绕不开,没有办法。软件开发的质量和效率不行的问题,它就是一个人和交互的问题:“人”就是个人能力的问题,“交互”就是团队能力的问题。人的能力和团队的能力不提升,基本功没有扎实,用什么样的工具都解决不了这个问题。

9.没有基本功,什么花哨套路都白搭

软件做不好,就是因为不知道怎么开发。没有基本功,什么花哨的套路都玩不了,玩到最后你都会面临同样的一个问题:我今天在这儿改一行代码,我怎么知道改完以后整个系统到底是不是好的?怎么回答这个问题,是决定性的分水岭。如果你没有一套完备、可靠、快速的测试集,那么回答这个问题唯一的办法就是改完这行代码然后叫测试部的小姑娘来回归测试。但是测试部的小姑娘她会很反感老是这么人肉回归,她就会打我。她打了我之后,我下一次不敢随便找她了,于是我就多攒一堆修改再去找她:“姐姐,给我一起回归一下呗。”现实就是这样的,软件开发的周期就是这么被拖长的。没有 TDD,你就解决不了这个问题。所以软件开发的核心问题,不管讲 DevOps 也好,讲持续交付也好,最终都得回到极限编程这里来。

之前有大概几年的时间,我对这个信念产生了怀疑:我说极限编程是不是太难了?是不是不适合这个行业?其实细想想这个说法也挺不好的。当我说“是不是极限编程不适合这个行业”的时候,我心里面想的是:在座的各位智商是不是有点不足,所以你们掌握不了极限编程?但我觉得实际情况不是这样。我觉得大家都是有这个能力的。所以我重新坚定了信念。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
如果要将该代码应用于读取类似于“此风不可长”的成语及其拼音、释义等信息,需要进行一些修改,以适应不同的格式。 以下是一个可能的实现: ```java import java.io.*; import java.util.*; public class ChengYuReader { private static final String CHENGYU_FULL_FILE = "chengyu.txt"; // 成语列表文件路径 public static List<ChengYu> readChengYuList() throws IOException { List<ChengYu> fullChengYuList = new ArrayList<>(); try (BufferedReader fullReader = new BufferedReader(new FileReader(CHENGYU_FULL_FILE))) { String line; while ((line = fullReader.readLine()) != null) { String[] fields = parseLine(line); if (fields != null) { String chengYu = fields[0]; String chengYuPinYin = fields[1]; String chengYuShiYi = fields[2]; ChengYu cy = new ChengYu(chengYu, chengYuPinYin, chengYuShiYi, ChengYu.DifficultyLevel.MEDIUM); fullChengYuList.add(cy); } } } return fullChengYuList; } private static String[] parseLine(String line) { // 以“拼音:”或“释义:”作为分隔符,将一行文本分割为多个字段 String[] fields = line.split("拼音:|释义:"); if (fields.length < 2) { return null; } // 提取成语、拼音和释义字段 String chengYu = fields[0].trim(); String chengYuPinYin = fields[1].trim(); String chengYuShiYi = ""; if (fields.length > 2) { chengYuShiYi = fields[2].trim(); } // 返回成语、拼音和释义字段作为一个字符串数组 return new String[]{chengYu, chengYuPinYin, chengYuShiYi}; } } ``` 此代码假设成语列表文件中每行以“拼音:”或“释义:”作为分隔符,将成语、拼音和释义三个字段分割开来。然后,提取这三个字段并封装成一个 `ChengYu` 对象,并添加到 `fullChengYuList` 中。如果一行文本无法解析为一个有效的成语信息,则返回 null。 需要注意的是,此代码也假设成语列表文件中每个成语的格式都是相同的,如果不同,需要相应地修改代码。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值