复杂软件系统的变化似乎需要永远,对吗? 尽管我们意识到系统的复杂性,但即使是工程师也经常认为更改超出了应有的范围!
对于客户而言,情况更加令人费解。 随机复杂性使问题变得更加复杂,由于系统支持不佳,随着时间的流逝,它变得越来越复杂。 有一种感觉,我们正在试图从一千个孔的船上sc水。
因此,客户迟早会发送一封信:“为什么要花这么长时间?” 别忘了,作为软件工程师,我们拥有通向世界的窗口,这是他们经常缺少的。 他们非常信任我们,但是有时看似微不足道的变化确实需要很多时间。 因此,出现了问题。
不要被这个问题冒犯; 借此机会表达同理心,使人更清楚地了解系统的复杂性。 同时,您可以建议改善情况的方法。 当某人不高兴时,这是提供解决方案的最佳时机!
下面发表了一封信,多年来,我们以一种或另一种形式反复寄出了这封信。 我们希望它能帮助您回答这些问题。
一封信
尊敬的客户,
我看到了您对“作业到期前通知”卡片的评论,我很高兴在下次会议上讨论该卡片。 在这里,作为参考,我将总结我的想法,没有必要回答。
解释一下您的笔记:
将完成任务的截止日期更改为一天,以便通过邮件通知应占用一行。 怎么需要4到8个小时? 我想念什么?一方面,我同意你的看法。 只需将请求部分从
tasks due <= today
tasks due <= tomorrow
tasks due <= today
更改为
tasks due <= tomorrow
。
另一方面,将其简化为这样一个简化的想法,我们无意间忽略了固有的复杂性,并做出了许多工程决策。 其中一些我们应该讨论。
第1部分。为什么这个小的变化比看起来的多?
这是一个简单的小更改,只需一行代码。 花一整天,甚至半天,似乎都过分了。
当然,如果不至少在本地或在测试服务器上运行,就不能仅仅发布生产变更。 您应该确保代码正确执行,并且如果请求发生更改,则需要比较输出并确保它看起来或多或少正确。
在这里,比较输出可能是最小的,只是抽查一下:确保结果有意义,等等。这是对内部员工的通知。 如果按日期计算的数学方法不正确(略有错误),我们将很快从团队中得知。 例如,如果这是给您客户的电子邮件,则需要进行更深入的研究。 但是,对于这种简单的测试和检查而言,20到40分钟就足够了,具体取决于是否出现异常或意外情况。 挖掘数据会浪费时间。 不进行审查就发布变更完全是非专业的疏忽。
因此,我们增加了正常物流的时间,例如提交代码,合并变更,部署等:从工作开始到生产发布,至少要有一个小时的专业工程师经验。
当然,这假设您确切知道要更改的代码行。 任务工作流基本上位于旧系统中,但是逻辑的某些部分位于新系统中。 从旧系统中移出逻辑是好的,但是这意味着任务的功能当前分为两个系统。
由于我们已经合作了很长时间,因此我们的团队知道哪个进程发送的电子邮件带有过期的任务,并且可以指向启动该进程的新系统中的一行代码。 因此,我们不必浪费时间弄清楚这一点。
但是,如果我们查看旧系统中的任务代码,则至少有四种不同的方法来确定任务是否到期。 此外,查看电子邮件的模式和行为,似乎至少还有两个地方可以实现此任务的自定义逻辑。
然后,通知逻辑比您想象的要复杂。 它可以区分一般任务和个人任务,开放任务和私人任务,重复任务,在发生逾期任务时管理器的附加通知功能等。但是我们可以很快发现,实际上,逾期任务的6个以上定义中只有2个用于通知。 为了实现目标,只需更改一件事。
这样的审查可能很容易又花费了半个小时左右的时间,如果您最近进入了代码库的这一部分,则可能会更少。 另外,潜在的复杂性意味着我们可以超出我们对手动测试的估计。 但是,我们只需要增加30分钟的时间就可以了。
因此,我们花了1.5个小时来确信更改将按预期进行。
当然,我们尚未检查是否有其他任何进程使用可变查询。 我们不希望通过将“截止日期”的概念更改为完成任务的最后一天之前的一天来意外破坏其他功能。 我们应该从这个角度考虑代码库。 在这种情况下,似乎没有主要的依赖关系-可能是因为大部分用户界面仍在旧系统上。 因此,无需担心更改或测试其他过程。 在最佳情况下,这是另外15-30分钟。
哦,由于任务用户界面的主要部分仍在旧系统中,因此,我们确实需要对该系统中的任务功能进行快速概述,并确保反馈正确。 例如,如果用户界面突出显示了截止日期已到的任务,我们可以更改此逻辑以匹配通知。 或者至少回头问客户他想怎么做。 最近,我没有查看旧系统中任务的功能,也不记得它是否对截止日期/延迟有所了解。 此评论又增加了15-30分钟。 如果旧系统还具有“任务”等的多个定义,则可能更多。
因此,我们花了2到2.5个小时的时间来完成任务,并确信一切都会好起来,而不会给用户带来意外的副作用或混乱。
第2部分。如何减少这个时间?
不幸的是,这些努力的唯一结果只是完成任务。 这不是最佳选择,这非常令人失望。 开发人员在工作过程中获得的知识是个人的和短暂的。 如果另一个开发人员(或六个月后的我们自己)再次需要对代码的这一部分进行更改,则必须重复该过程。
有两种主要策略可以纠正这种情况:
- 积极清理代码库,以减少重复和复杂性。
- 编写自动化测试。
注意:我们已经讨论过文档,但是在这种情况下,这不是最佳解决方案。 文档对于高级想法很有用,例如解释业务逻辑或经常重复的过程(例如新合作伙伴列表)。 但是,当涉及到代码时,文档会很快变得过于庞大,并且随着代码的更改而变得过时。
您注意到我们的2–2.5个小时中没有包含这些策略。
例如,维护一个干净的代码库意味着我们要提出的问题不仅仅是简单地完成任务:
- 为什么有这么多不同的方法来识别截止日期已到/过期的任务?
- 他们都需要他们并为此工作吗?
- 这些方法可以简化为一种或两种概念/方法吗?
- 如果将概念分为新旧系统,是否可以合并?
依此类推。
这些问题的答案可能很快:例如,如果我们遇到明显的死代码。 或者它们可能要花费几个小时:例如,如果在许多复杂的流程中使用了任务。 一旦获得这些答案,重构将需要更多时间来减少重复/混乱,并仅获得“最后期限”概念的描述-或在代码中重命名这些概念以清楚地理解它们之间的区别以及原因。
但是最后,这部分代码库将变得更加简单,并且将更易于阅读和修改。
我们通常使用的另一种策略是自动测试。 从某种意义上说,自动化测试类似于不能过时且易于检测的文档。 我们编写了一个测试代码来启动请求并以编程方式验证输出,而不是手动运行代码并查看输出。 任何开发人员都可以运行此测试代码,以了解系统应该如何工作并确保它仍能以这种方式工作。
如果您的系统具有良好的测试覆盖范围,那么这些更改将花费更少的时间。 您可以更改逻辑,然后运行完整的测试套件,并确保
- 更改工作正常;
- 更改没有破坏任何内容(与第一段相比,这是更有价值的信息)。
当我们在Simple Thread从头开始构建系统时,总是会在截止日期的评估中包括编写自动化测试的时间。 这会减慢最初的开发速度,但会大大提高工作和维护效率。 仅当系统扩展时,您才真正了解测试的重要性,但是此时很难将测试返回给系统。 测试的存在也极大地简化了新员工的工作,并且更改系统行为的速度更快,更安全。
第3部分。我们来自哪里? 我们要去哪里
今天,我们很少在您的评估中指出清除代码或编写测试的时间。 这部分是因为从头开始编写测试是很小的开销,而将测试添加到代码库的后备日期是很多工作,例如恢复人们所居住房屋的基础。
这也部分是由于您开始与您合作,我们会立即切换到复苏模式。 在同步第三方数据方面,我们几乎每天都有问题,在生成报告方面,每周都有问题,支持少量数据更改的持续请求,不足的监控和系统日志记录等。代码库在技术负担的重压之下淹没了,我们正竭尽全力地使系统保持运行状态浮动,同时用胶带粘住孔。
随着时间的流逝,系统变得更加稳定和可靠,我们会为频繁的支持请求的自助服务自动化/提供UI。 我们仍然有很多技术债务,但是我们退出了紧急模式。 但是我认为我们永远不会完全摆脱这种复苏心态,而变得更加积极,成熟的“计划和执行”心态。
我们尝试随时清除代码,并且始终进行全面测试。 但是,谨慎而勤奋并不是主动重构或创建良好的自动化测试所必需的基础结构。
如果我们不开始支付一些技术债务,我们将永远无法大幅度改善这种状况。 高素质,称职的开发人员将花费数月的时间进行导航和进行重要的更改。
换句话说,此任务需要4-8个小时,大约是供应量的2-4倍,但它将大大减少将来为此类更改所做的工作。 如果这部分代码更干净,并且具有良好的自动测试覆盖范围,那么经验丰富的资深开发人员将在一个小时或更短的时间内完成。 关键是新开发者将花费更多时间。
对于此类更改,我们需要您的同意。 这是一种有意识的尝试,从根本上改善系统的性能,而不仅仅是用户如何看待它。 我知道,仅因为没有明显的好处就很难同意这样的投资,但是我们很高兴与您坐在一起,并准备一些明确的数据,这些数据将从工程的角度显示这些投资将长期取得回报。
谢谢啦
铝