如果您要总结软件开发的整个过程,您会说:"该项目迟到了,它被取消了"。
我们已经到了《困难的计算机》的结尾。 在讨论了各个软件组件的组成方式(从打印机驱动程序到密码哈希)后,我想总结一下构建软件产品的原理。
也许有些尴尬,但是即使经过了几年的行业发展,我仍然不明白为什么高科技公司如此着迷于速度。 这种迷恋被融入软件的语言中,其中工作周期称为冲刺,进度的度量称为速度。 但是,快速交付软件真的那么重要吗? 我不知道。 我不是自己开发软件,而是每天都对它进行故障排除,还是有时候,我希望工程师的工作速度稍慢一些。
我将有关构建软件方法论的问题带给了一个对该主题进行过激烈辩论的人。 David Heinemeier Hansson创建了Ruby on Rails,是Basecamp的联合创始人兼CTO,并且是商业书籍(例如Rework)的作者。 他还擅长与行业趋势抗衡,不管这些趋势是技术性的(例如微服务的日益普及)还是机构性的(例如风险资本成为发展高科技业务的默认方式)。 我们讨论了当今的软件构建方式,对进行构建的人员意味着什么以及如何构建软件。
享受《困难的计算机》的最后一章。
Wojtek Borowicz:软件方法学是其自己的行业。 有Scrum,Agile,教练,书籍以及所有这些。 但是您和您的Basecamp团队不遵循这些做法。 为什么?
DHH:首先,我们的软件开发方法受到敏捷宣言和敏捷价值观的极大启发。 它并没有像今天那样受到敏捷实践的启发。
许多敏捷软件方法论侧重于产品开发领域,而这些领域并不难。 它们与程序结构息息相关。 在大多数情况下,软件本质上是不可预测的,不可知的和不可变形的。 几乎就像气体一样。 它可以适应来自同一基本思想的各种不同的开口。 尝试估计功能需要花费多长时间的想法不起作用,因为您不知道自己要构建的内容,而且人类很难估计任何东西。 软件开发的历史是最近或被取消的项目之一。 如果您要总结软件开发的整个过程,您会说:"该项目迟到了,它被取消了"。 可以这么说,规划工作无效。
我们在Basecamp所做的选择是将Shape Up贴上标签,仅仅是因为那是我们发现需要努力的地方。 我们正试图接受核心约束条件,即不可能准确地指定应该先执行哪些软件。 您只能发现在限制条件下应该做什么。 但是,这也不像我们遵循完成后完成的想法。 那是产品管理思想的绝对放弃。 相反,我们所说的是:不要做估算,不要做预算。 Shape Up的核心是预算。 不是要花多长时间,而是值得。 因为某些事情可能需要一周或四个月的时间。 值多少钱?
在整个工作周期中,有些事情值得(通常是极限),对我们来说这是六个星期。 这就是我们所谓的大批量生产。 否则它的价值可能会比这少。 也许只有一个星期,也许是两个星期。 那是一小批。 这需要模糊的项目陈述"让我们添加特征A",将其置于约束之下,然后由代表来确定实施工作的对象。 这就是这里的关键见解。 如果您有一个大的问题定义和一个固定的边界,并且给有创造力的聪明人自由选择这些条件内的解决方案的能力,他们将做出色的工作,他们为此感到自豪。
敏捷清单
在2001年,由17名男性(当然是零女性)组成的小组发布了一份文件,为未来20年的软件开发设定了方向。 他们的《敏捷宣言》将敏捷软件开发的原则进行了整理。 这些想法是基本的(例如:"工作软件是进度的主要衡量标准"和"简单性至关重要"),但它们催生了敏捷教练,顾问和作家的整个领域。
因此,这些方法的问题在于它们过分注重估算,而软件本身是不可能做到的?
我走得更远,说估计是胡说八道。 它太不精确了,甚至在处理固定输入时也没有用。 而你不是。 在看到软件之前,没有人能够准确地描述该软件应该做什么。 我们可以抢先描述开始做某事之前应该做些什么的想法简直是铺天盖地。 敏捷的想法是,您需要运行软件来获取反馈,但是敏捷的现代实现并没有接受他们自己所教的课程。
但是技术在宗教上几乎痴迷于速度。 如果您想专注于速度却又不相信估计,那该如何工作?
我们正在谈论进度和速度。 那实际上是两件事。 您可以尝试做得越来越快,然后意识到自己实际上并没有前进。 我们对Shape Up的兴趣远不止于此。 最终将产生能够交付有意义的大量工作的项目,客户和实施者对此感到自豪和满意。 试图将反馈回路缩小到不可能的很小,这并没有改善。 这个想法是,不断的反馈是一件好事。 是的,出于某种原因! 我不想不断评估自己的工作。 例如,我们不进行冲刺。 按照Scrum和其他方法论的规定,每两周重新调整工作是一种完全压抑和反复无常的工作方式,只会使每个人精疲力尽,实际上什么也没提供。 大多数人都无法在两周内交付真正的大型功能。
真正的魔力在于将您的思维方式从预算转移到预算。 不要考虑花费多长时间。 考虑一下您愿意付出多长时间。 这颠倒了整个想法。 它使需求浮动。 模糊的项目定义实际上更现实。 高度具体的项目定义通常会很快误入歧途。 含糊不清的定义允许工作的人们发挥创造力和选择性。 而且,当您考虑到这两件事时,就可以授权本科代理商与这些人一起去做他们认为可以做的最好的工作,而不仅仅是遵循规范。
整个敏捷叛逆都是关于拒绝大型的前期设计。 但是我认为敏捷还没有得出足够的结论。 他认为:'我们不需要大型的前期设计。 我们只需要很少的前期设计'。 真的没有那么好。 许多软件方法学近距离地专注于实现的技术要求。 但是软件方面的艰苦工作正在弄清楚应该做什么,而不是如何使它工作。 10x程序员有一个神话。 但这不是在解决问题方面英勇的程序员。 10x程序员是解决问题的程序员。
重述问题确实应该在软件方法论的前列。
当团队受困于两周的周期,估算和制定规范时,代码和决策的质量会受到影响吗?
当然。 但不仅如此。 它导致了(我的意思是有点冒昧但不是那种冒犯)人类的痛苦。 在这种制度下工作的人只会被吃光和吐口水。 要每两周不断地重新评估您所做的所有事情,因为那是新的Sprint周期开始的时刻–进度非常快,无处可寻。
这就是为什么我们不做每日站立。 这种持续不断的搅动,在非常紧的皮带上绕圈旋转。 我认为这实际上是人性化。 敏捷再次说:'嘿,你知道吗? 您正在尝试进行为期两年的软件项目? 这是一个完全的概念。 太遥远了。 是的,绝对! 但是后来,敏捷方法学在最近被实践,过度纠正并且太短了。 他说,每天站立两个星期是这个神奇的周期。 不,人们需要一些懈怠。 一些自主权。 一些空间。
通过广泛的实验,我们发现大约六个星期为我们提供了足够的呼吸和思考空间。 只要设定了界限,即使每天看起来不一定像以前一样,您也会取得进步。 您可能会发现在消费社区反馈循环方面,团队的活动更加紧密。 他们疯狂地搅动,但最终并没有取得更大的进步。 有时候,跑得最快的团队是看上去很冷静的团队。 他们不是一直在某些方法论的跑步机上或在某个程序时钟上响! 叮! 叮! 每五秒钟。
您相信您的Shape Up方法可以在更大的组织中工作吗? 一个拥有500或5,000个而不是50个工程师的工程师?
首先,您不应该考虑能够从五个人扩展到五千人的软件方法论。 试图为一个单位计划5,000人的工作是一个愚蠢的事情,但实际上没有人这样做。 更为有趣的方法是:对于任何公司,适当的团队限制一般是多少? 假设有500个大型公司,则是100个团队,每组5个。 这就是您进行比较的方式。
但这并不是说六个星期对每个人都有效。 我认为它实际上可以在数量惊人的情况下工作,比两周的方法要频繁得多。 慷慨得多。 而且更现实的是,您可以运送整个东西。 但是,如果您不能在六周内交付完整的功能,则您的反馈循环仍然太短。 如果我无法完成所有事情,从创建,实施到发货,都在我的周期内完成,那么周期太短了。
如果您从事本机应用程序开发,并且声誉很高,那么也许六个星期的时间还不够。 也许您还需要更多。 或者可能不是。 这取决于您是否可以运输要运输的物品。 但是整个行业已经开始思考"哦,两周是一个很好的时间表"。 什么? 我们如何变得如此确定? 即使对于一家拥有5,000名员工的公司来说,六个星期也是一个比较现实的起点。
您还不太满意地谈到了软件开发中出现的其他趋势,例如微服务和无服务器或测试驱动开发。 您实际上是否对软件工程学中的任何趋势感兴趣?
这是一个棘手的问题。 找出我不喜欢的所有东西要容易得多。
显然,我有些偏见,因为我在推动这些事情。 我正在实施Ruby on Rails和Shape Up,并分享了一些我认为应该如何进行软件开发的知识。 这并不意味着没有其他方法可以做到。 Web开发有各种各样的技术堆栈和方法,这些使我微笑。 我很高兴看到我们在JavaScript开发方面取得的进步。 前端发生的升级在原子级别上非常出色。 我认为我们误入歧途的是分子水平。 人们采用的框架和方法都不是很好,但是我认为基础的技术改进是通过编译器,polyfilling和JavaScript在这些版本上的核心进展。
我们在网络上所做的许多事情都使用了25年的基础知识。 发生的核心创新更多地是在识别应该强调的重点,重要的方面和推动的方面。 例如,对于Web行业而言,前端开发应通过JSON(服务器端仅负责生成API,然后API返回JSON)的做法是绕道而走。 我们应该回到拥抱HTML的角度。 将HTML放在我们的工作中心,通过网络发送HTML,以便我们在第一次加载时就返回完整的Web文档,然后再通过HTML进行后续水化或更新。
我想回到微服务。 我之前与之交谈的一位工程师谈到了它们,这是对整体软件变得过于复杂以至于无法维护的一种回应。 微服务对您有什么帮助?
让我们从前提开始。 单片软件变得如此复杂……这是什么"成为"? 这只是发生在我们身上吗? 我们是完全无辜的旁观者吗? 复杂性只是笼罩着我们,我们无能为力吗? 那是胡扯的假设,我们需要反驳。 完全废话。 您不必让复杂性翻滚。 您选择。 一旦您选择了复杂性,那么自然的反应就是尝试将这种复杂性推到更多不同的盒子中,因为您无法一次全部处理好吧? 错误! 首先处理该死的事情。 为什么事情如此复杂? 他们必须这么复杂吗? 他们可以不那么复杂吗? 我认为答案是:是的,它们不必这么复杂。 是的,我们可以做些什么。 不,这并不意味着我们只需要提交即可。
我想在这里解决根本原因。 大规模的Web开发应该比以往更简单。 我们在压缩过去非常复杂且人们需要非常仔细考虑的众多领域的概念性开销方面迈出了巨大的一步。 人们仍然以某种方式最终导致整体应用不堪重负,这是他们自己创造的野兽。 与其尝试去思考我们该怎么做,不如说:"我们可以把复杂性放到哪里?"我们将讨论的重点放在为什么我们首先具有复杂性上吗?
开发人员谈论意外的和固有的复杂性。 实施过程是偶然的复杂性,固有的复杂性是我们工作所在领域的复杂性。 大多数Web应用程序固有的复杂性与以往一样。 我们退步的地方是引入大量的意外复杂性。 如果您无法控制单一应用程序的复杂性,那么到底是什么让您认为有能力在一系列服务中分配这种复杂性,这些服务现在必须进行交互并处理网络的不可靠性,重试,两阶段提交和 在处理方法调用,参数以及运行单个进程的基础知识时,所有这些其他复杂性根本就不存在。 在复杂性级别上,与分发应用程序相比,对应用程序造成的危害几乎没有。 您甚至可以解决最小的问题,一旦分发,问题的复杂性就会增加一个数量级。
其他行业,甚至政治家都将技术视为创新的来源。 同时,我听到开发人员越来越多地说整个领域从根本上被破坏了……
不不不。 这是由于误解,认为大多数软件开发都是工程学。 我不相信。 是的,当您通过工程师的眼光看待软件开发时,事情看起来很糟。 然后工程师会说:'好吧,您的规格确实很宽松。 您的公差是不确定的'。 所有这些东西,所有的工程评估,等等,等等。 这是对什么是软件开发的根本误解。 软件开发的工程意义与搭建桥梁的意义不同。 它们不仅是同一根学科的不同分支。
许多软件工程师的这种自我厌恶完全是徒劳的,而且永远都不会解决。 软件开发是一个年轻的行业,如果我们再给它30年的ISO认证或任何严格的要求,我们将得出一个浪漫的工程概念,即它们在航空航天,电梯或桥梁中的工程…… 不是。 这是一个根本不同的领域,需要根本不同的方法。
我们已经有了许多答案。 我们只是害怕拥抱他们。 例如,在传统工程估计中,很大一部分。 事情是根据估算和关键路径图进行的,因为这只是建造摩天大楼的方式。 倒入混凝土后,您无需重新配置定向塔的方式。 软件开发并非如此。 软件在许多方面都非常接近写作,游戏制作和电影的创作过程。 体验设计未知事物的过程,直到看到它,您才知道它是否好。
看电影制作。 我们拍摄电影已有一百年了。 我们还没有弄清楚创作过程吗? 没有! 我们还没有。 您可以聘请出色的导演,出色的演员,但仍可以制作一部完全烂影片。 与建筑物相比,如果您选择了一个伟大的建筑师,一个伟大的工程公司和一个伟大的总承包商,那么您将到达一栋可以运转的建筑物。 您可能会犯一些小错误,但是基本结构是合理的,除非有人犯了一个完全疏忽的错误。 在电影制作,音乐,软件中,事情总是失败的。 即使知道如何构建事物的技巧的好人聚在一起并从事某些工作,他们仍然会失败。
工程师对编程语言的强烈选择是他们的选择之一。 有没有好和坏的语言?
是的,对于一个人。 对于个人而言,编程语言可能是好是坏。 我认为从客观的角度来看,它们的优劣也可以,但这种讨论几乎没有意思。 对我来说有趣的讨论是个人真理之一。
例如,关于哪种语言能使编程语言变得更好的长期争论之一是您应该使用静态还是动态类型还是强类型还是弱类型的语言。 在Ruby中,您没有静态类型的语言,并且存在某些方法或方法不能很好解决的重构或错误。 另一方面,您有类似Java之类的东西,只是以最强类型语言的标准示例为例,它以不同的方式工作。 对于具有不同大脑的不同人,不同的语言或者不说话。 当您学习风格时,情况类似。 有些人在视觉上学习,有些人在听觉上学习,而这些样式对个人而言绝对是对还是错。 如果您是视觉学习者,那么尝试以听觉或触觉的方式学习对您来说是行不通的。 对我来说,Ruby是一种比我尝试过的任何其他语言都要优越的编程语言,因为它像手套一样适合我的大脑。
我们应该研究并接受来自不同大脑的个人真理,但我们不应该回避那些拥有不同大脑类型的人争论什么更好和什么不好。 意见冲突具有巨大的价值。 即使您有一个像我这样的人说Ruby是有史以来最伟大的语言,而另一个人说Java是有史以来最伟大的语言。 这些是我们应该接受的。 就像原子互相撞击一样。 然后我们得到光,我们得到能量,我们得到兴奋。 那很好! 工程师们非常讨厌冲突,以至于他们不能让两个人不同意而又不退缩并进行"权衡! 权衡取舍! 这取决于!'。 就像哭泣的叔叔一样,我认为这对学习,启发和任何事物都是完全相反的。
当我辩论软件开发以及我的选择和观点时,我会全心全意地确定适合自己的方式。 观众可以决定自己更喜欢谁。 他们可以自己尝试。 他们可以看到我提出的关于我与Ruby的恋情的论点是否引起他们的共鸣。 如果没有呢? 谁来哄!
类型检查
数据被分为类型,每种编程语言都有自己的规则来决定您可以对哪种类型进行处理。 类型检查意味着强制执行这些规则,以便程序知道,例如,您应将分配给变量的值30视为数字还是两个字符的字符串。 语言是根据类型检查的时间进行静态或动态输入,而根据其完成方式则是强类型还是弱类型。