type
status
date
Apr 22, 2025 02:02 AM
slug
summary
tags
category
icon
password
💡
软件工程已经发展了数十年,虽然我们的开发工具和技术栈发生了翻天覆地的变化,但软件开发的本质——人与人之间的协作沟通与管理——始终未曾改变。

核心观点

由于人员的分工,大型编程项目碰到的管理问题和小项目区别很大
关键在于:维持产品自身的概念完整性

要解决什么问题

过去几十年的大型系统开发就,他们中大多数开发出了可运行的系统——不过,其中只有非常少数的项目满足了目标、时间进度和预算的要求。

程序设计工作的特点

报纸上经常会出现这样的新闻,讲述两个程序员如何在经改造的简陋车库中,编出了超过大型团队工作量的重要程序。接着,每个编程人员准备相信这样的神话,因为他知道自己能以超过产业化团队的1000代码行/年的生产率来开发任何程序。 为什么不是所有的产业化队伍都会被这种专注的二人组合所替代?我们必须看一下产出的是什么。
notion image

作为回报,编程者期望得到什么样的快乐

  1. 一种创建事物的纯粹快乐,特别是自己进行设计。
  1. 来自于开发对其他人有用的东西。期望其他人使用我们的劳动成果,并能对他们有所帮助。
  1. 架构与系统设计:将相互啮合的零部件组装在一起,看到它们精妙地运行,得到预先所希望的结果。
  1. 学习的乐趣,来自于这项工作的非重复特性。解决问题的人可以从中学习新的事物:有时是实践上的,有时是理论上的,或者兼而有之。

那么代价是?

  1. 无法追求完美:受限于资源、时间节点。
  1. 由他人来设定目标,供给资源,提供信息。编程人员很少能控制工作环境和工作目标。用管理的术语来说,个人的权威和他所承担的责任是不相配的。
  1. 设计是有趣的,但寻找琐碎的bug却只是一项重复性的活动。
  1. 当投入了大量辛苦的劳动,产品在即将完成或者终于完成的时候,却已显得陈旧过时。

软件工程中的根本问题和次要问题

所有软件活动包括根本任务——打造由抽象软件实体构成的复杂概念结构,次要任务——使用编程语言表达这些抽象实体,在空间和时间限制内将它们映射成机器语言。

进度管理

💡
当人们听到某个项目的进度发生了灾难性偏离时,可能会认为项目一定是遭受了一系列重大灾难。然而,通常灾祸来自白蚁的肆虐,而不是龙卷风的侵袭。同样,项目进度经常以一种难以察觉,但是残酷无情的方式慢慢落后。实际上,重大灾害是比较容易处理的,它往往和重大的压力、彻底的重组、新技术的出现有关,整个项目组通常可以应付自如。 但是一天一天的进度落后是难以识别、不容易防范和难以弥补的。昨天,某个关键人员生病了,无法召开某个会议。今天,由于雷击打坏了供电变压器,所有机器无法启动。明天,因为工厂供货延迟了一周,测试无法进行。下雪、应急任务、私人问题、管理人员检查——这个列表可以不断地延长。每件事都只会将某项活动延迟半天或者一天,但是整个进度开始落后了,尽管每次只有一点点。
💡
在众多软件项目中,缺乏合理的时间进度是造成项目滞后的最主要原因,它比其他所有因素加起来的影响还大。导致这种普遍性灾难的原因是什么呢?
  1. 对估算技术缺乏有效的研究,更加严肃地说,它反映了一种一切都将运作良好的幻觉。
  1. 采用的估算技术隐含地假设人和月可以互换,错误地将进度与工作量相互混淆。
  1. 由于对自己的估算缺乏信心,项管通常不会有耐心持续地进行估算这项工作。
  1. 对进度缺少跟踪和监督。
  1. 当意识到进度的偏移时,下意识(以及传统)的反应是增加人力。

按计划完成项目的概率为零

在单个的任务中,“一切都将运转正常”的假设在时间进度上具有可实现性。因为所遇的延迟是一个概率分布曲线,“不会延迟”仅具有有限的概率,所以现实情况可能会像计划安排的那样顺利。然而大型的编程工作,或多或少包含了很多任务,某些任务间还具有前后的次序,从而一切正常的概率变得非常小,甚至接近于无。

人力资源和时间资源不能等价转换

成本的确随开发产品的人数和时间的不同,有着很大的变化,进度却不是如此。
人数和时间的互换仅仅适用于以下情况:某个任务可以分解给参与人员,并且他们之间不需要相互的交流。这在系统编程中近乎不可能。
notion image
沟通所增加的负担由两个部分组成,培训和相互的交流。每个成员需要进行技术、项目目标以及总体策略上的培训。这种培训不能分解,因此这部分增加的工作量随人员的数量呈线性变化。
相互之间交流的情况更糟一些。如果任务的每个部分必须分别和其他部分单独协作,则工作量按照n(n-1)/2递增。一对一交流的情况下,三个人的工作量是两个人的三倍,四个人则是两个人的六倍。而对于需要在三四个人之间召开会议、进行协商、一同解决的问题,情况会更加恶劣。所增加的用于沟通的工作量可能会完全抵消对原有任务分解所产生的作用,此时我们会被带到图2.4的境地。
notion image
因为软件开发本质上是一项系统工作——错综复杂关系下的一种实践——沟通、交流的工作量非常大,它很快会消耗任务分解所节省下来的个人时间。从而,添加更多的人手,实际上是延长了,而不是缩短了时间进度。

进度估算

观察一下编程人员,同厨师一样,某项任务的计划进度,可能受限于顾客要求的紧迫程度,但紧迫程度无法控制实际的完成情况。就像约好在两分钟内完成一个煎蛋,看上去可能进行得非常好。但当它无法在两分钟内完成时,顾客只能选择等待或者生吃煎蛋。软件顾客的情况类似。
两种解决方案:
  1. 开发并推行生产率图表、缺陷率、估算规则等等,而整个组织最终会从这些数据的共享上获益。
  1. 在基于可靠基础的估算出现之前,项目经理需要挺直腰杆,坚持他们的估计,确信自己的经验和直觉总比从期望派生出的结果要强得多。

开发模式

notion image

瀑布开发

需求分析、需求拆解、设计、编码、测试、部署上线、运维

迭代开发

原型、第一个版本、第二个版本。。。

增量开发

第一个模块、第二个模块。。。

敏捷开发

需求进入需求池、需求排序、完成前n个需求开发、需求进入需求池、需求排序、完成前n个需求开发。。。

可抛弃原型模式

由简易接口和模块组成的可抛弃原型→若方案不可行,则快速修改方案,直到流程可以跑通→抛弃原型机,设计完整接口从头开始开发

人力资源管理

💡
假设一个项目经理已经拥有行事规范的架构师和许多编程实现人员,那么他如何确保每个人听从、理解并实现架构师的决策?

架构师的行为准则

  1. 只建议,而不能支配;
  1. 时刻准备着为所指定的说明建议一种实现的方法,同样准备接受其他任何能达到目标的方法;
  1. 对上述的建议保持低调和平静;
  1. 准备放弃坚持所作的改进建议;

文档

💡
文档是一个非常必要的工具,尽管光有文档是不够的。文档是产品的外部规格说明,它描述和规定了用户所见的每一个细节;同样的,它也是架构师主要的工作产物。
大约十个人的想法,如果想保持文字和产品之间的一致性,则必须由一个或两个人来完成将其结论转换成书面规格说明的工作。而且,将定义书写成文字,必须对很多原先并不是非常重要的问题进行判断,并得出结论。

站会、周例会和大会

组织架构

  1. 树状形式:项管组-机械/电控/视觉负责人-机械/电控/视觉队员
  1. 矩阵形式:
视觉
电控
机械
哨兵
雷达
工程
选取哪种组织架构取决于项管希望让资源流向何处

干系人管理

notion image

协作模式

  1. 可解耦的模块间协作开发:开发人员事先约定统一的接口,各自面向接口进行模块功能开发,定期对齐进度及解决技术分歧(通过会议和文档)。
  1. 不可解耦的模块开发:双方必须进行一人固定螺母另一人拧螺丝式的“携手开发”模式。这种情况应在架构设计时避免,或不交给多人完成。

规模控制

对项目经理而言,规模控制既是技术工作的一部分,也是管理工作的一部分。他必须研究用户和他们的应用,以设置将开发系统的规模。接着,把这些系统划分成若干部分,并设定每个部分的规模目标。由于规模-速度权衡方案的结果在很大的范围内变化,规模目标的设置是一件颇具技巧的事情,需要对每个可用方案有深刻的了解。聪明的项目经理还会给自己预留一些空间,在工作推行时分配。
仅对核心程序设定规模目标是不够的,必须把所有的方面都编入预算。

部署与调试

目标机器系统会需要若干操作员和一两个系统编程人员,以保证机器上的标准支持是即时更新和实时可用的。(至少一名电控配合)
实机调试要点:
  1. 明确调试目的
  1. 提前安排时间调度
  1. 量化的调试指标
仿真装置。如果目标机器是新产品,则需要一个目标机器的逻辑仿真装置。这样,在生产出新机器之前,就有辅助的调试平台可供使用。同样重要的是——即使在新机器出现之后,仿真装置仍然可以提供可靠的调试平台。(分配专人安排模拟器/调试工具开发)

自顶向下的设计模式

第一步、成体系结构设计
第二步、设计接口
第三步、各模块面向接口编程
基于Notion搭建个人博客教程Github 配置ssh over https