paint-brush
破解“事半功倍”代码的程序员指南经过@turbobureaucrat
2,886 讀數
2,886 讀數

破解“事半功倍”代码的程序员指南

经过 German Tebiev19m2023/01/12
Read on Terminal Reader

太長; 讀書

程序员可以事半功倍吗?这个故事深入探讨了当前的方法及其缺陷,以及作者提出的新方法。享受阅读!
featured image - 破解“事半功倍”代码的程序员指南
German Tebiev HackerNoon profile picture
0-item

理论管理充满了祖父。我读过戴明、高德拉特、大野和德鲁克的作品。我听说过 Ackoff 和 Juran。我喜欢我读过的每一本书中的人道和细心的态度。从来都不是:“把人剥削到筋疲力尽”。彼得·德鲁克 (Peter Drucker) 在他的《管理教父》中甚至指导了我们这些 21 世纪的管理者应该做什么:


管理在 20 世纪最重要、也是真正独特的贡献是将制造业中体力劳动者的生产率提高了 50 倍。管理在 21 世纪需要做出的最重要贡献同样是提高知识工作和知识工作者的生产力。


进入 21 世纪 20 年,我们离实现软件开发领域的这一宏伟目标还有多远?我看到我们离它很远。让我们探讨一下我们在哪里,我们有什么问题,以及我们可以做些什么。

探索提高软件开发效率的广泛方法

“事半功倍的艺术”是该框架的合著者 Jeff Sutherland 所著的《 Scrum 》一书的副标题。我喜欢这个副标题,因为它强烈反映了我们在编程工作中可以变得更有效率。不过,也并非万无一失。我们在这里遇到的第一个问题是很难理解我们工作中的效率是什么。如果我们随着时间的推移变得更有效率,下面的复杂问题就是理解。


但是我们到底为什么要效率呢?好吧,这是关于用更少的努力做同样的事情,在我们生活的许多领域,更快或以更低的价格获得相同或更好的结果是很棒的。


让我们回到我们的问题。 Scrum 实践者提出故事点作为任务的衡量标准。 scrum.org 网站上有一个定义

故事点是一个相对的度量单位,由各个 Scrum 团队决定和使用,以提供完成需求的相对工作量估计。


故事点是与参考任务相关的复杂程度。你我都能感觉到我们花了多少努力来实现这个不是很困难的任务。如果我告诉你新工作需要三个故事点,我说它会比以前的工作难三倍。这是我的猜测,谁知道这会有多难。


让我们再次关注效率。如果我们在这个 sprint 中交付估计有 25 个故事点的任务,我们是否比上一个只有 15 个故事点的 sprint 更好?或者也许我们更谨慎,对同样的努力给出了更高的估计?但是我们怎么能比较呢?我们不会在工厂规模的软件工程中进行重复性工作。我们设计并实施提供服务的信息工厂。在我们的行业中是否有讨论效率的地方?

这些谈话有一个地方。至少,我们可以故意放慢速度。例如,我们可以拖延或从一项任务跳到另一项任务。如果我们能做一些效率较低的事情,就有希望相反。但是,我不认为故事点在这里是有用的测量工具。他们可以毫不费力地有意或无意地受到虐待。我们需要寻找更好的东西。

定义测量对象

在定义提高编程工作速度的方法之前,我们需要确定我们想要衡量的工作是什么。我没有看到我们可以在整个行业范围内使用的任何东西,但积极的一面是我们不需要这么广泛来提高效率。需要的是描述开发编程产品中有意义的工作步骤的内容。我们可以使用史诗、任务、功能或任何其他代表正在开发的系统的积极调整的东西。

在我目前的位置,我们使用三个不同的级别:

 User-valuable feature: ⎿ Its slice for the engineering team's convenience: ⎿ The specific task inside a slice (eg, back-end task).

我们需要调整具有以下特点:

  1. 有开始时间和完成时间;
  2. 定期发生。

所以我们这里定义的是“这件大作品”。我们将其命名为文章后续部分中的操作。并非所有操作都是相同的。我在上面的例子中展示了三种。


我们需要定期采取行动。


这个要求来自这样一个事实,即你不可能从一开始就最终变得高效,但随着时间的推移会变得更有效率。这不是所描述方法的缺点。 Scrum 以这种方式运作,丰田生产系统以这种方式运作,科学也以这种方式运作。我们需要可重复性来发现当前状态并持续改进它。


您可以以最终优化的效率做任何新事情,这完全是偶然的。动作越复杂,它的可能性就越小。提前准备会有所帮助。然而,提前准备的能力意味着动作或其子动作发生在过去,并且有关于它们的知识。没有什么可以为全新的东西做准备。另一方面,我们在生活中很难遇到完全新奇的事物。以前经验的一小部分总是与从未经历过的情况相关。


综上所述,我们有一种行为作为本质来衡量。

如何衡量一种行为?

乍一看,上一节没有添加任何内容。我们做一些类似的动作。它比用故事点、T 恤尺码或动物衡量的任务好在哪里?一个名字不是一个单一的收获。一种动作有两个时间戳,我们可以通过从完成中减去开始来衡量它的持续时间。持续时间在这里是一个很好的收获,因为它是我们日常现实语言的关键。

  • 完成史诗需要多少时间?
  • 从开始到完成我们花了 39 天。

精彩的。

我们还有什么收获吗?

我们行动的第二个要求,经常发生,给了我们太多以至于难以置信。首先,我们获得了一种动作流。以下是 Daniel Vacanti 所著的“Actionable Agile Metrics for Predictability ”一书中对流程的定义:

简单地说,流程是客户价值通过流程的移动和交付。

我们对两个时间戳的要求,一个动作的开始和完成,为我们提供了一组很好的新指标。它们来自同一本书:

进行中的工作(我们在任何给定时间处理的项目数量)、周期时间(每个项目完成我们的流程需要多长时间)和吞吐量(每单位时间完成这些项目的数量) ).

如果你认为这就是我们这里的全部,我可以引起你的兴趣。我们才刚刚开始。流动给我们的另一个宝藏是它随时间流逝留下的痕迹。这个跟踪可以让我们更好地了解系统。我们可以使用几个图表来捕捉它。其中之一是周期时间散点图。

ActionableAgile Instrument 中演示数据的周期时间散点图

它的乐趣来自于它抓住了“我们在这里做事的方式”这一事实。它不需要您的流程中的任何东西,也不需要特定的方法。您想使用循环时间散点图捕捉刷牙流程吗?去做就对了。您想要在您所在地区建造的房屋也一样吗?绝对没问题。您想跟踪开发生命周期,包括开发新功能后进行的 A/B 实验吗?请开始做。


在图片中,您还可以看到右侧标有 50%、70%、85% 和 95% 的百分位数线。他们的意思是什么?左边是天。您可以通过以下方式读取 85% 和 16 天:

对于在审查期间进入我们系统的 85% 的项目,离开它需要 16 天或更短的时间。

这是我第二次在本节中使用“系统”一词。这是什么意思?让我们为这个故事按以下方式定义它:

系统是做某种动作的东西。


上面的房屋建造系统示例中的一种动作是建造房屋。走一公里的路不算在这里的一个动作。这是一种不同的行动和另一种系统。但是,没有具体的划分,但是我们希望我们的房子是一样的,刷牙和软件开发也是一样的,有A/B测试。对于足够不同的东西,我们可以想出另一个系统。

一个更重要的收获

现在是讨论另一种效果的时候了,它可以帮助我们确保增强工作的准确性。想象一下,您有一个团队并且需要创建新软件。您将用户故事作为进度的衡量标准,作为一种行动。完成您的第一个故事后,就该进行回顾,看看我们下次可以在哪些方面做得更好。


这个逻辑中有什么东西会把我们引向陷阱吗?让我们仔细看看。


在第一个用户故事的实施过程中,主要障碍是就必要的库达成一致并安装所需的软件。这花了一些时间,而且真的很痛苦。在回顾期间,团队讨论了它有多痛苦以及我们下次如何做得更好。很明显的错误是,下一次几乎没有,您将需要就库达成一致并安装软件。图书馆通常会保留很长时间。安装软件将是新成员入职的一部分,但不会影响已经建立的团队的第二个用户故事。它非常不同,现在可以成为入职系统的一部分。


让我们看看 Donald Knuth(或 Tony Hoare )的以下编程智慧:

过早的优化是万恶之源。

我猜你遇到过这个,它告诉你在软件开发的早期阶段不要考虑性能。您可能已经以以下形式看到了这种智慧:

让它工作,让它正确,让它快速。

关于安装库的示例表明这句格言与代码和编码团队相关!我们在这里遇到了多么神秘的事!这不是什么神秘,而是系统的属性。至少有两个原因,我们应该避免在第一次尝试后直接跳入增强功能。

不立即进行增强的统计原因

一种类型的每个完整动作都有其持续时间。持续时间由两部分组成:一部分由普通原因引起,另一部分由特殊原因引起。

让我们再次参考刷牙的例子。通常,在牙刷上涂上牙膏需要几秒钟的时间。特殊情况下,需要把牙膏从柜子里拿出来,打开再用。这里整个动作需要几分钟。如果出于某种原因,我们需要考虑刷牙过程中牙刷涂层子作用的效率,那么在最初的一个之后再考虑会产生误导。初始动作包含一个额外的部分,与我们想要加速的典型动作不同。

特殊的性质导致特殊持续时间原因的出现不一致。所展示的始终是我们行动的核心,是我们改进的富有成果的目标。

约束理论不立即进入增强的原因

约束理论告诉我们什么?它告诉我们,生产某物的整体将与其生产率最低的部分一样生产。想象一下,我们有一家公司正在建造一层楼的小房子。我们每年的产能如下:

  • 6个地下室,
  • 24套墙,
  • 52个屋顶。

我们每年可以建多少栋房子?你可以回答六个,但我建议不要超过六个。我们的建筑过程是一个重要的过程:地下室→墙壁→屋顶。完成最后一个第六宫可能会落后于年底。

我们想象中的建筑系统的时间表

如果我们增加我们建造的墙壁或屋顶的数量,这会改变我们整个公司的产能吗?我们生产的会不会超过提到的“不超过六个”?不,地下室仍然限制着我们。

上面的容量数字来自这家肤浅公司的经验。在实施第一个用户故事后,我们没有这种经验。我们还没有确定我们的用户故事构建系统的约束,因为我们不知道每个子动作持续多长时间。考虑将质量保证作为我们用户故事开发过程的一部分。用户故事的测试持续四个小时。一个用户故事的开发一般需要五个工作日。假设一年有 250 个工作日。您希望最终完成 50 个用户故事还是 730 个?与房屋和地下室一样,每年最多 50 个。我们需要收集统计数据以了解我们行动的形式及其效率最低的部分。

有多少完整的动作足以开始增强?

可以肯定的是,我建议此时完成 ∞ 个完整动作。有了这个确切的数字后,您就可以 100% 确定首先要增强什么。🥁

对于纯数学世界之外的那些人,让我们考虑以下想法。以下是“Actionable Agile Metrics for Predictability ”一书中引用“ How to Measure Anything ”一书的参考资料:

例如,Douglas Hubbard(他的著作“How to Measure Anything”列在参考书目中)就他的“法则”向他的客户提出建议:五法则——人口的中位数有 93.75% 的几率介于来自该总体的任意五个随机样本中的最小值和最大值。

五项行动似乎足以让我们开始深入思考系统改进。

请不要将此视为对前五个动作进行更改的禁忌。还要考虑其他方面:健康安全、团队凝聚力等。

从哪里开始增强?

如果我们采取基本动作,例如,通过按下电视上的按钮打开电视,我们可以将其视为一个整体。要减少移动次数和总时间,请给自己买一个答题器并将其放在沙发附近的一个地方。在这个例子中,第一个动作可能需要大约 20 秒,第二个……一秒。我的祝贺!您已经减少了之前所需时间的 95%,但仍然获得相同的价值。消除浪费真是太棒了!


并不是所有的行动都那么简单。已经提到的用户故事开发是复杂的。一次跳跃处理那里的改进是具有挑战性的。我们需要把事情分解成子动作,就像在建造房屋的例子中一样。我们可以从以下生命周期开始:

  1. 分析,
  2. 发展,
  3. 测试,
  4. 完毕。


从哪儿开始?


在精益制造中,创建过程或本文中命名的操作由三种子操作组成:

  • 增值活动;
  • 必要的非增值活动;
  • 浪费。


制定用户故事、设计解决方案并对其进行编码都是增值活动。在开发过程中使用 git 分支可能被认为是必要的非增值活动。它不会为此更改添加任何内容,但会组织整个过程。浪费会在一段时间内无缘无故地阻止价值积累。等待非工作数据库是一种浪费。


在精益制造中,浪费(或muda )由丰田生产系统的创建者 Taiichi Ohno 了解和定义。至少它们是为汽车制造商丰田公司定义的。其他行业有其变体。这是我们的,由 Mary 和 Tom Poppendiecks 在“精益软件开发”一书中创建:


  1. 部分完成的工作,
  2. 额外的过程,
  3. 额外的功能,
  4. 任务切换,
  5. 等待,
  6. 运动,
  7. 缺陷。

还是这些?来自同一作者的“ 实施精益软件开发”一书:

  1. 部分完成的工作,
  2. 额外的功能,
  3. 再学习,
  4. 不必要的交接,
  5. 任务切换,
  6. 延误,
  7. 缺陷。


至少软件工程师现在可以移动了!


我们行业的这些支柱怎么会在短短几年内发生如此大的变化?我看到了不可能为未来所有时代提供足够的废物清单的答案。甚至丰田,在某个时候,也提出了第八种浪费。

很高兴我们行业的名单发生了如此巨大的变化。这种变化打开了我们的思路,让我们重新考虑我们对不断浪费的想法。以下是关于软件开发中可能浪费的部分的另一种观点:


软件世界最大的误解之一就是代码的价值。但代码是一种责任,正如我们将在本书中反复强调的那样。我们编写的代码越多,我们为自己产生的复杂性和风险就越大。


这是 David Anderson 与 Mark McCann 和 Michael O'Reilly 合着的“价值飞轮效应”中的一句话。哇,多棒啊!


那么,我们如何开始呢?通过查看效率最低的子操作。我们寻求什么?不增加价值的子行动。

重新考虑用户故事开发工作流程

让我提醒您我们的工作流程:

  1. 分析,
  2. 发展,
  3. 测试,
  4. 完毕。

通常,这些都是由不同的人完成的部分,并且总是有一些时间等待交接。让我们记录一下:

  1. 分析活跃,
  2. 分析完成,
  3. 发展活跃,
  4. 开发完成,
  5. 测试,
  6. 完毕。

我没有设计这些步骤。我从ActionableAgile Analytics 产品演示中获取了它们。我们可以信任他们吗?我会说是的,因为我看过真实数据的不同示例,而这个看起来很接近。让我们调查以下阶段的统计数据。它展示了平均值。

ActionableAgile 演示数据的平均值

系统周期时间为9.37天。此语句意味着任务到达Analysis Active阶段,移动到所有下一个阶段,并离开Testing for Done ,平均而言,这条路径需要 9.37 天。名称中带有“Active”的阶段似乎为结果和测试带来了用处。以“完成”结尾的阶段是排队、等待,没有任何用处。如果我们使用 Flow Efficiency 图相应地标记它们,我们会发现,平均而言,花在单个用户故事上的时间中只有 40% 是有价值的。

ActionableAgile 演示数据的流程效率图


在此图中,我们还包括跟踪的阻塞时间和奇怪的任务,它们将所有时间都花在“完成”阶段。如果我们排除它们,这个演示示例的流效率将在 50% 左右。

解决已发现的浪费时间问题

由于我们对演示数据集的信息太少,因此不会有具体的建议,例如:“给 E 队更好的计算机”。然而,在你的情况下会有足够的想法来激发你自己的想法。我们流程中效率最低的部分是分析完成阶段。我们甚至不能称它为等待,因为它描述了等待。然而,它几乎占每项任务的 29%。这可能是什么原因?


活跃的开发阶段看起来并不慢,比活跃的分析部分需要更少的时间来完成。查看平均 WIP,我们会突出问题:分析部门可以同时处理更多的用户故事。


平衡这一点,例如,让更多的开发人员加入团队,可能是一个可能的解决方案。但是,不要在这里操之过急。原因可能完全不同。 Analysis Done阶段可以包含秘密工作。可能是开发人员对需求质量不满意,但无法系统地解决此问题,并在此阶段花时间进行改进。发现边界条件,提出异步请求的 UI 处理等。


在提出解决方案之前应用根本原因分析:使用五个为什么鱼骨或其他东西。

验证应用变更是否成功

假设我们解决了上一节中的问题。我们如何确定提议的更改是否有效?我们需要再次积累数据。你还记得上面的五法则吗?我们也可以在这里使用它。我们的系统现在已经调整好了。让我们再测量一下。

在我的工作中,我使用两个工具来衡量实验的结果:

  1. 累积流程图,
  2. 周期时间散点图上的趋势线。

ActionableAgile 演示数据的累积流程图

您看到Analysis Done的青色区域了吗?随着时间的流逝,它至少会变薄,最多会消失。

ActionableAgile 演示数据的 85% 趋势

看看这张已经很熟悉的图表上出现的绿色虚线。它显示了最近 N 天的 85% 周期时间趋势。我使用 30 而不是 N,因为它足够稳定以演示更改。如果发现的解决方案能够处理足够深的根本原因,预计这条线将下降 ≈30% 至 11 天。

如果没有明显的数据变化,是时候寻找其他解决方案了。

接下来的步骤

下一个明显的改进点是开发完成阶段。让我们想象一下,我们也应对过它。我们已经减少了最初完成用户故事所需时间的 50%。然而,故事的标题承诺将生产力提高四倍。在这种情况下,我们可以开始考虑Analysis Active阶段。然后尝试将 Testing 和Development Active并行化。

不过,我不确定这里是否有必要。想象一下使用每两天获得新功能的软件。市场可能还没有为此做好准备。市场成为我们系统的约束。这一发现并不意味着我们的改进总是那么有限。通常,我们有多个开发系统创造价值,而我们的功能需要超过 9 天的时间。以我的经验,持续六个月的鸟瞰项目只发现了30%的增值时间。 30% 内任务的更详细图片再次显示了准确的 30% 的增值时间。原来,整整180天,增值活动只有16天。可以看到提高 11 倍的潜力。

总结方法

  1. 发现你的系统,
  2. 发现它的约束,
  3. 消除它的浪费,直到它不再是一种约束,
  4. 重复。

有效问题

我觉得所描述的方法在进行二十世纪的贡献管理方面具有很高的潜力。当我告诉别人这个方法时,我通常会面临几个问题:


  1. 这不会破坏编程的乐趣吗?

  2. 软件开发是如此不可预测,又如此富有创造力。我们怎么能谈论提高它的效率呢?!


该提案不会破坏编程的乐趣。您可能已经注意到,我们致力于消除流程中没有发生任何事情的漏洞。能够接手刚刚创建的任务,就像两天后接手一样快乐。另一个乐趣来自于将您的代码视为处于变化中的系统,而您的团队也是如此。您拥有编程工具和方法的新领域。


为什么您以前需要在线暴徒编程工具?变得更快?但是那时候什么更快?为什么需要明确的软件设计阶段?啊哈!我们的开发团队背负着错误,这就是为什么用户故事等待开发人员修复错误的生命周期高达 30%。我们为什么不阻止他们呢?


扼杀编程乐趣的是经常需要割肉来完成任务。拥有更好的方法、工具和知识并不会扼杀快乐。

是的,软件开发创作确实是不可预测的,不是常规的。然而,它是无限不可预测的吗?一年是否足以完成积压工作中的任何任务?十年又怎样?它们变异的本质是否如此难以捉摸,以至于我们对此无能为力?周期时间散点图的存在向我们表明软件开发变化是有限度的。您可以指出,某些任务需要快速文本常量修复,而其他任务则需要数天的调查时间。我同意这一点,但我还要问你:“这些任务的存在是软件本质的必然结果,还是你使用的软件架构的结果?进程中的大泥球不是为什么会这么乱?”


对更顺畅的开发流程的需求最终难道不是解决您的技术、架构和流程债务的可靠理由吗?


是的,即使在对变更最友好的架构中,也会出现比我们希望的需要更多时间的棘手问题。我们已经在第 95 个百分位数线上方的周期时间散点图上放置了一个位置来处理它们。但他们是例外,我们不希望一切都成为例外。


作为管理者,我们不应该救火,而应该致力于我们的系统设计及其变化。

避免明显和错误的步骤

我不是第一个在我们的行业中寻求效率的人。一些寻求者认为他们已经熟悉这个话题。他们的做法是在雇主的电脑上安装跟踪软件,并惩罚那些做一些被视为不工作的人。这种方法表明完全没有意识到软件开发效率的来源。巨大的压力导致巨大成功的想法不仅是糟糕的。这是致命的。它限制了我们仅在一个维度上看待我们的系统:工作不够努力或不够努力。你的个人经历提供了足够多的精疲力尽的例子。历史告诉我们,一些国家掉进了这个陷阱,并伴随着许多人员伤亡。不,努力工作不是持续改进的途径。但它是什么?

发现起点

一个多世纪以前,弗雷德里克·泰勒 (Frederick Taylor) 开始了他的研究,即我们现在所知的科学管理。他看着他的同事并寻找更有效的方法让他们完成工作:

泰勒决心通过科学方法来发现人们完成每件给定的工作需要多长时间。 1882 年秋天,他开始将科学管理的最初特征付诸实施。

我不知道泰勒当时从事的业务结构。可能是他的生产步骤属于其他步骤,这也可能意味着泰勒陷入了局部次优化陷阱。这是关于增加我们想象中的房屋建筑公司可以处理的屋顶数量的问题。泰勒的发现影响并没有减弱,即使是这种情况。现在我们知道这个陷阱的危险并且可以采取更明智的行动。


你还记得我用持续六个月或 180 天的物品举例吗?如果我成功地消除了工程师工作的内部项目的时间浪费,我将节省 38 天,并有 142 天的时间来处理一个大项目。如果我对整个团队工作的外部执行相同的操作,我将节省 126 天,而相同的大项目有 54 天。如果你想赢得大奖,用加班和办公室床来折磨开发人员是没有意义的。从鸟瞰的角度看待价值交付过程,只有在您超出该级别的改进空间后才能更深入。