这为何对公共价值重要

如今,一位公民接触到的几乎每一项公共服务——登记出生、申领福利、缴纳税单、预约法庭日期——都在柜台或屏幕背后的某处运行着软件。这套软件很少是一次性的采购;它变成了国家永久性基础设施的一部分,常常比委托建造它的政府、建造它的供应商,以及它的工程师所受训使用的编程语言都存续得更久。一个公共机构不会像体验一栋建筑或一条道路那样体验软件——建筑或道路的状况是可见的;而软件会不可见地退化,这种衰败的账单会在多年之后作为一场紧急事件到来。

驱动本主题的张力是结构性的。软件天生是迭代性的——需求随着用户与一个可运作的系统互动而变得更清晰,而最佳的工程实践,是先构建一些小东西、从中学习,再加以调整。而相比之下,公共采购与问责周期(见主题3.7——公共采购与委托),是为资本工程与国防合同而建立的:一份固定的规格、一次单一的大额授标、里程碑付款,以及一份在交付开始之前数年就已签核的商业论证。当一个立法机关或一位审计人员期望的是一份固定价格、固定范围的合同,而一支工程团队却需要在第一次发布之后改变方向时,这种不匹配便表现为范围蔓延、预算超支,或一套在2019年被正确地明确规定、却在交付时早已过时的系统。

本主题这门工程实践存在的意义所要建立的这些平台——共享身份系统、支付轨道、跨部门重复使用的个案管理工具——是主题5.1的主题(见主题5.1——数字政府与数字化转型);本主题讲的是构建与购买软件的学问,它使任何这样的平台、或任何单一一项服务,变得可靠、可替换,并归依赖它的公共机构所拥有,而不是归恰好最先写出它的那家供应商所拥有。

核心概念

自建与外购的决策,是在为一个组织的具体需求委托编写定制软件、与采用一款已经为一个由相似买家构成的市场而建立的可配置商品软件之间做出的选择。对于一项并非真正独特的需求——薪资、电子邮件、标准的个案管理——外购通常更便宜、风险更低,而自建只有在需求差异大到没有任何可配置的产品能够适配、或这项能力本身就是这个组织需要拥有并使其演进的一项战略资产时才是站得住脚的。

技术债务是软件工程师沃德·坎宁安在1992年提出的一个比喻,指的是选择一种权宜的方式来现在就发布软件、而非一种本会花费更长时间、更彻底的方式所累积起来的成本。技术债务,与财务债务一样,并非本质上就是错的——坎宁安自己的观点是,快速发布可用的代码、之后再重构,可能是正确的决定——但从未被偿还的债务,会以更慢的交付、更多的缺陷,以及不断上升的风险的形式产生利息,而一个看不见自己债务的公共机构,无法决定是应该偿还它,还是任由它累积。

遗留系统是一种旧技术、应用程序或平台,尽管已经过时,却仍在被积极使用,常常是因为替换它代价高昂,或是因为这个组织里已经没有人完全理解它做了什么。遗留系统在政府中格外顽固:数十年前用诸如COBOL——通用商业导向语言,于1960年为行政计算而设计——这样的语言编写的核心税务、福利与社会保险系统,至今仍在为数百万公民处理交易,因为这些系统能用,而安全地淘汰它们所需要的制度知识,常常先于系统本身"退休"了。

软件现代化是把一套遗留系统转换、重写,或迁移到一种当前架构、语言或平台的统称。软件现代化涵盖一个谱系,从一次完整的重写,到诸如把同样的代码重新托管在现代基础设施上等更为保守的选项,而在二者之间的选择,既是一项风险管理决策,也是一项技术决策。

绞杀榕模式是一种渐进式的现代化方式,以一种缠绕在宿主树周围、逐渐取代它的藤蔓命名,在这种方式中,新功能与遗留系统并列构建,流量被逐块重新导向它,而非在一次换约中替换整个系统。绞杀榕模式之所以重要,是因为它让每一次增量都能被测试、被回滚,或被暂停,而不必让整项服务停摆——这与一次大爆炸式替换正相反,后者是在单一一个时刻关闭旧系统、开启新系统,一旦出了问题就没有回头路。

供应商锁定发生在一位客户变得如此依赖于单一一家供应商的专有技术、数据格式或合同条款,以至于转向另一家供应商会带来令人望而却步的成本或风险。供应商锁定在公共部门软件中是一种特有的危险,因为买方是一位重复购买的客户,却几乎没有实际能力放弃一套正在运行一项关键服务的系统,这削弱了它在此后每一次续约时的谈判地位。

自由与开源软件是在一种授予用户使用、研究、修改与再分发源代码自由的许可证之下发布的软件。自由与开源软件支撑着一项默认开源的政策,依据这项政策,一个公共机构默认公布自己委托编写的源代码,除非某项具体理由——安全敏感性、第三方权利——证成扣留它;其理由通常被总结为"公共资金,公共代码":用公共资金支付过一次的软件,不应该需要在一个不同的辖区、由一个正在解决同一个问题的不同公共机构再次付费。

数字公共物品是在一种开放许可证之下发布的开放软件、数据或内容,旨在帮助实现一项公共发展或治理目标、而非产生商业回报。数字公共物品把一个政府的开源发布,重新构建为一整套更广泛的、其他政府与公民社会组织能够直接借鉴的共享基础设施的一部分,而不仅仅是一种内部透明度姿态。

敏捷软件开发是构建软件的迭代方式的统称,偏好可运作的软件、频繁的交付,以及对变化的响应,而非遵循一份事先商定的固定计划。敏捷软件开发与瀑布模型形成对比,后者是一种顺序性方式,需求、设计、构建与测试各自完全完成之后,下一个阶段才开始;瀑布模型对公共机构的吸引力,一直在于它的里程碑能够整齐地对应到一份固定价格合同与一个年度预算周期,这正是为什么如此多的采购法至今仍然假设它,即便交付实际上是真正敏捷的。

最小可行产品是一项服务能够被发布给真实用户、以检验它是否可行、并了解接下来应该构建什么的最小版本。这个最小可行产品概念,被改编进公共部门数字服务的操作手册之中,给了一支迭代团队一种站得住脚的方式,能在完整范围完成很久之前,就向一位资助方或一位审计人员展示一些真实、可运作的东西——前提是问责流程接受一次真正最小化的发布,而非把它当作换了个名字的成品来对待。

最佳实践

  1. 默认为未经区分的需求外购,把自建保留给真正独特的东西。 薪资、电子邮件与一般性个案管理需求,很少与其他任何组织的需求有足够的差异,以证成定制软件;只有在需求、规模,或对这项能力数十年拥有权与演进权的需要,真正不同于市场所提供的东西时,才自建。
  2. 在决定要携带多少技术债务之前,先让它变得可见。 为每一套正在运行的系统维护一份已知的权宜之计、被推迟的修复,以及不受支持的依赖项的登记册,按固定周期加以审查,使再携带一年债务成为一项刻意的权衡,而非没有人去看它。
  3. 绝不要把一次单一、不可逆的换约,当作摆脱一套关键遗留系统的唯一路径来规划。 优先选择诸如绞杀榕模式这样的渐进式方式,让每一部分都能被测试、被逆转,并逐步推出;一次大爆炸式地替换一套数百万人依赖的系统,会把多年的风险集中到单一一个周末,而一旦出了问题就没有回头路。
  4. 把你的组织付费编写的源代码,当作它所拥有的一项资产,而非租用的一项服务来对待。 在签约的那一刻、而非一次纠纷已经开始之后,就协商好源代码托管或彻底的所有权,因为一家掌握着你关键服务代码唯一副本的供应商,就是被设计出来的供应商锁定。
  5. 默认公布源代码为开源,并要求一项具体理由才能扣留它。 一贯地应用一项默认开源政策,能把每一个部门定制构建的软件,变成一项跨政府的共享资产、而非一项一次性成本,并让外部专家能够发现一支内部团队自己会错过的安全漏洞。
  6. 编写让迭代式交付合法化、而不仅仅是在技术上可能的软件合同。 一份只依据签约时商定的固定规格才付款的合同,迫使一支团队在诚实的敏捷实践与合同合规之间做出选择;转而使用与已展示的可运作软件挂钩的分阶段资金关卡,而非最后的单一里程碑。
  7. 把现代化当作一项持续的项目来资助,而非一次性的资本项目。 一套仅仅现代化一次、随后又被放置二十年的遗留系统,会积累起它最初就有的同样的风险;要像一个道路管理机构为重新铺路编列预算那样,为持续的、渐进式的更新编列预算,而不是每一代人才进行一次的宏大替换。
  8. 即便在购买商业软件时,也选择开放标准与可移植的数据格式。 要求一家供应商的系统以开放的、有文档记录的格式存储与导出数据,即便软件本身是专有的,也能保持较低的转换成本,而这常常是一项比坚持要求每一套系统都是开源的更容易在短期内实现的、防范锁定的保障措施。
  9. 在承诺完整范围之前,先构建一款最小可行产品,并展示给真实用户看。 发布一个真正最小化的版本,再依据学到的东西加以迭代,能在错误的假设修复成本仍然低廉时捕捉到它们,而非在一套完整规模的系统已经依据它们构建完成之后。
  10. 保持足够的内部工程能力,使自己成为一位精明的买家,即便交付被外包出去。 一个已经掏空自己技术专业能力的公共机构,无法评估一位供应商的提案、无法发现一个陷入困境项目的早期预警信号,也无法谈出一条脱离锁定的路径,无论它的采购规则在纸面上怎么写。
  11. 在改造一套遗留系统的用户界面之前,先淘汰它的风险状况。 优先替换不受支持的语言、未打补丁的基础设施,以及没有文档记录的集成——那些造成宕机与安全漏洞的失败点——而非运营风险小得多的外观现代化。
  12. 用工程指标、而非仅仅预算与进度差异来衡量交付的健康状况。 部署频率、缺陷率,以及最陈旧的未处理技术债务项目的年龄,能比"目前是否在预算之内"——这常常是最后一个变动的指标——更多地告诉一个治理董事会,一项项目是否会成功。

与团队讨论的问题

我们是否真的知道自己逐套系统携带着多少技术债务? 大多数公共机构能够说出自己当年的资本预算,却无法有信心地说出,自己的软件资产中有多少运行在不受支持的组件、无文档记录的逻辑,或没有任何留任员工完全理解的代码之上。用这个问题要求房间里每一位系统负责人诚实地估计,他们的团队有多大信心,能够安全地更改自己最关键的系统、而不破坏任何没有人预料到的东西。讨论一下,要把这些估计变成一份真正的登记册——按固定周期审查、而非随一位关键工程师离职而流失的部落知识——需要什么。也想一想,目前是谁在决定携带多少债务是可以接受的,以及这项决定是刻意的、还是默认的。

如果我们最关键的遗留系统从今天开始就需要被替换,我们会规划一次大爆炸式换约,还是一次渐进式迁移——为什么? 一次性替换一套旧系统的本能冲动,常常是由预算周期与项目管理便利性所驱动的,而非技术上的必要性,而它把巨大的风险集中到了单一一个时刻。用这个问题具体地梳理一下,你最关键的遗留系统的一次绞杀榕式渐进式迁移,一块一块地看,实际上会是什么样子。讨论一下,是什么阻止了你今天选择那条路线——围绕单一一个上线日期构建的资金安排、一个想要一个干净利落的里程碑的治理流程,还是一项让这套系统的渐进式迁移真正不可能的技术约束。

我们的组织付费构建的软件的源代码,实际上归谁所有,我们能证明吗? 许多公共机构只有在与一家供应商的关系恶化之后,才会发现合同从未确保过它们关键服务所依赖的代码的明确所有权或托管。用这个问题拿出你三套最重要的定制系统的合同,具体核查每一份合同关于代码所有权、托管,以及把代码转交给另一家供应商的权利怎么说。讨论一下,如果这三套系统中任何一套的主要供应商明天倒闭、或拒绝继续这段关系,会发生什么。

我们在哪些地方出于习惯默认使用封闭、专有的软件,而一种默认开源的方式本可以同样好、甚至更好地服务于我们? 默认开源政策存在的意义,恰恰是因为大多数公共机构独立解决着相互重叠的问题,各自支付另一个公共机构早已构建、本可共享的软件的全部成本。用这个问题识别出一套目前正在构建或明确规定的系统,追问一个等价物是否已经作为开源软件存在于政府别处,或者你正在构建的这个东西,是否可以有用地被发布出去,供其他人重复使用。讨论一下究竟是什么具体障碍——安全顾虑、采购习惯、缺乏明确的政策——阻止了这种复用,而不要假设它在这里不适用。

我们的采购与问责流程,是否真的允许诚实的敏捷交付,还是仅仅把瀑布式里程碑重新贴上了冲刺的标签? 一支团队一边运行着名义上敏捷的仪式,一边仍然依据合同签约时商定的固定规格获得资金、被治理并接受汇报,这种情况很常见,这在敏捷的标签之下重现了每一种瀑布式失败模式。用这个问题追溯一项正在进行的数字项目,从它的商业论证到它当前的治理汇报,追问这套资金结构,是否能容忍这项项目依据一次真正的早期发布所学到的东西而改变方向。讨论一下,要让迭代式交付变得真实、而非表面文章,这项项目的资金与汇报方式需要做出什么改变(见主题3.7——公共采购与委托)。

我们是否拥有足够的内部工程能力,能够成为我们最依赖的那些系统的一位精明买家? 一个不仅外包了自己的交付能力、也外包了自己全部技术判断力的组织,无法判断一位供应商的提案是否合理、一个项目是否正在悄悄走向麻烦,或者这项工作的公平价格实际上是多少。用这个问题追问一下,你的组织中有多少人能够可信地评审一份针对你最重要系统的技术架构提案,以及这个数字在过去五年里如何变化。讨论一下,在这项能力已经流失的地方,要重建它需要什么,以及每多一年没有这项能力,你的组织在谈判地位与交付风险上都损失了什么。

实践中的公共价值案例

一个虚构的区域政府——仅用于说明,不描述任何真实辖区——通过一套三十多年前首次编写的系统处理失业福利申请,由数量不断减少、理解其原始编程语言的工程师维护。申请量早已远远超出了这套系统设计者所预期的水平,夜间处理批次日益无法在早晨的交易开始之前完成,而这个机构的技术领导层警告说,一次影响福利支付的计划外中断,如今只是时间问题,而非会不会发生的问题。

该机构最初的本能反应,是针对一个感觉紧迫的问题所做出的常规回应:委托一份单一的大型合同,用一套现代平台替换整个系统,提前完整地明确规定,依据一份固定的两年时间表交付,末尾有一个换约周末。该机构审计委员会委托进行的一次实施前审查,在合同签署之前提出了一个尖锐的问题:如果新系统在其第一周的全面、实时运营中出现了一项未被发现的缺陷,而旧系统早已被淘汰、无法回头,那么数十万申请人的福利支付会发生什么。

该机构改变了方向。它保留了遗留系统作为记录系统,并开始使用一种绞杀榕方式,在它旁边构建新的申请受理与资格评估功能:每一个新模块首先只被发布给一小部分新申请,依据旧系统的并行输出加以核实,只有在结果匹配之后才加以扩展。十八个月之内,大多数新申请都通过了现代组件运行,而原始系统处理着不断缩减的剩余案件量,并保留着如果任何一个具体案例看起来有问题,就能把它路由回旧路径的能力。该机构还在为这项工作发出的每一份新合同中要求,源代码归该机构所有,并在安全审查完成后作为开源发布,使面临同样老旧大型机问题的其他区域政府,能够改编这些组件,而不必从零开始重复同样的构建。

遗留系统最后剩余功能的完全替换,花了将近四年——在纸面上,比最初两年的大爆炸式计划所承诺的更长。但没有任何一位申请人在过渡期间经历过一次计划外的中断,每一次增量的规模都足够小,一旦发现缺陷就能在几个小时内回滚,而两个相邻的区域政府,在该机构发布的资格评估代码发布的第一年之内,就开始为自己的系统改编它。

四种部门视角

地方政府

地方政府通常运行着大量较小、互不相连的系统,而非少数几个国家规模的平台,这意味着技术债务是在许多分别采购、分别维护的应用程序中积累起来的,而非集中在一个可见的旗舰系统之中。地方政府通常拥有所有政府层级中最薄弱的内部工程能力,这使得购买可配置商品软件、而非定制构建的理由格外充分,也使得共享的区域或国家平台——主题5.1的主题(见主题5.1——数字政府与数字化转型)——成为一条避免每个地方政府各自重复构建同一项能力的格外有价值的路径。

国家政府

国家政府通常是最古老、后果最严重的遗留系统所在之处——核心税务、社会保险与福利行政——因为这些常常是政府最早的大规模计算化努力之一,如今任何一次现代化失败都承担着最高的利害关系。国家政府通常拥有运行一项真正渐进式现代化项目、并在自己的合同中谈成真正代码所有权的专业商业与工程能力,它通常也是最适合设定一项默认开源政策的政府层级,因为它拥有足够的规模,能真正让跨政府的复用发生。

社会部门与非营利组织

非营利组织与慈善机构很少自己构建大型定制平台,但它们常常是由一个政府资助方委托或强制要求使用的软件的接受端——一个汇报门户、一份拨款或合同要求它们使用的个案管理系统——对其设计、技术债务或供应商几乎没有影响力。一个依赖一套政府强制要求系统的社会部门组织,继承了这套系统的失败模式,却没有继承任何修复它们的杠杆,这是基于成果的资金关系需要考虑强制性技术的运营负担、而非仅仅是成果指标本身的又一个原因(见主题3.7——公共采购与委托)。

多边与国际

多边机构与发展机构越来越多地把为一个国家公共行政构建的软件,推广为一项其他国家可以改编的可重复使用数字公共物品,而不是让每一个政府各自从头以全部成本委托一套等价系统给一家私营供应商。这里特有的风险是,一项为一个国家的法律与行政情境构建的数字公共物品,可能在其他地方以太少的改编就被采纳,输入了一些实际上并不能迁移的假设——关于身份、资格,或流程。共享、开放基础设施的承诺是真实的,但只有当真正的本地改编能力与代码相伴而行时才成立。

常见失败模式

在上线时失败的大爆炸式换约。 一套关键遗留系统,在多年的开发之后、没有任何实时生产环境暴露的情况下,通过一次单一、不可逆的换约被替换,而一个只在真实规模下、或在一个没有人测试过的边缘情形中才会出现的缺陷,在全面运营的第一天就浮现出来,而由于旧系统早已被淘汰,没有回头路可走。这项代价以漏付的款项、被拒绝的服务,或恰恰影响这套系统存在意义所要服务的公民的中断来衡量,而且是在最糟糕的时刻——每个人都在依赖这个替代方案能够正常工作的那个时刻。

沉默的技术债务累积。 截止日期的压力,反复战胜了修复已知权宜之计所需要的时间这一论点,而每一次推迟单独看都是站得住脚的,直到累积起来的债务让即便是一个小小的改变也变得代价不成比例、风险不成比例。这项代价在多年之后浮现,变成一套没有人能够安全修改的系统、一支已经悄悄不再尝试任何东西、只处理最紧急补丁的员工队伍,以及一个最终比持续的、较小规模的更新原本会需要的规模大得多、代价高得多的现代化项目。

把供应商锁定误认为稳定。 一个公共机构反复续签同一家供应商的合同,因为转换看起来太具破坏性、以至于不敢尝试,却从未检验过真正的转换成本会是多少,也从未协商过能让这些成本保持可控的代码所有权与开放数据格式。这项代价是一种在价格与条款上被永久削弱的谈判地位,只有当这家供应商的服务质量下滑、或它的定价上涨,而这个公共机构发现自己没有任何可信的替代方案时才会被发现。

表面上的敏捷。 一支交付团队采用了敏捷仪式——站会、冲刺、待办事项清单——而底层的合同、资金与治理结构仍然假设着一份固定规格与一个单一的通过/不通过里程碑,于是这支团队汇报着冲刺速度,而实际上却在依据一份底层的瀑布式计划交付。这项代价是,敏捷真正的收益——早期用户反馈改变方向、风险被及早暴露——没有一项真正实现,而现代实践的外观,却让监督机构更难看清并质疑底层的僵化。

没有维护计划的开源政策。 一个公共机构为满足一项默认开源政策而发布了源代码,却把这次发布当作一次性的合规步骤,没有为审查外部贡献、修补漏洞,或维护文档配置任何资源。这项代价是,一个已发布的代码仓库看起来是开放的,实际上却是一个无人维护的死胡同,这对更广泛的默认开源项目的信任所造成的损害,比一开始就从不发布还要大。

成熟度模型

子维度 启动 发展 标准化 管理 协同
技术债务是可见的、被管理的 债务未被记录,只被个别工程师非正式地知晓 部分系统存在一份不完整的清单,未按固定周期审查 一份债务登记册涵盖所有关键系统,按有据可查的周期接受审查 债务削减获得资助,并对照可衡量的目标被追踪 债务数据在这个组织的整个资产范围内共享,为现代化投资的优先排序提供依据
遗留系统现代化避免大爆炸式风险 替换被假设为意味着一次完整的重写与换约 渐进式方式偶尔被使用,没有一致的方法 绞杀榕式的渐进迁移是关键系统有据可查的默认方式 迁移进度与回滚准备情况被主动衡量并汇报 现代化方法与工具在同行公共机构之间共享并改进
自建与外购决策是刻意做出的 自建或外购由习惯或供应商关系决定,未经评估 在重大软件决策之前,不一致地进行一些评估 一套有据可查的决策框架被应用于每一项重大的自建/外购选择 自建/外购结果随时间对照其最初的理由被追踪 自建/外购的能力与经验教训与面临同样选择的其他公共机构共享
源代码与数据默认开放 封闭、专有的交付是不容置疑的默认选项 开源化偶尔发生,由个别团队推动 一项默认开源政策被记录在案,并一贯地应用 已发布的代码得到积极维护,并为外部贡献配置了资源 已发布的代码在整个政府及其他辖区之间被复用,复用作为一项收益被追踪
交付方式与问责结构相匹配 无论交付实际如何发生,合同与治理都假设瀑布模式 使用了敏捷仪式,但资金与治理仍以一份固定规格设置关卡 合同与资金关卡围绕已展示的可运作软件而构建 交付健康状况用工程指标、而不仅仅是预算与进度差异来衡量 采购与问责规则依据证据被主动调整,以适应迭代式交付

检查清单

  • 盘点每一套关键系统的技术债务,并按固定周期审查这份登记册。
  • 在承诺任何重大新软件之前,应用一套有据可查的自建与外购框架。
  • 对于任何遗留系统替换,默认采用渐进式迁移方法,并要求为大爆炸式换约提供明确的理由。
  • 在签约之前,确认每一份软件合同中的源代码所有权或托管条款。
  • 依据一项默认开源政策公布源代码,并配有一套有据可查的例外流程。
  • 为在这项政策之下发布的每一个代码仓库配置持续维护的资源,而不仅仅是它最初的发布。
  • 即便底层软件是专有的,也要求开放的、有文档记录的数据格式。
  • 围绕已展示的可运作软件、而非单一一个固定规格的里程碑来构建资金关卡。
  • 在承诺完整范围之前,先与真实用户构建并测试一款最小可行产品。
  • 把部署频率、缺陷率与未处理的技术债务,当作常设的治理指标来追踪。
  • 依据成为一位精明买家所需要的东西,评估内部工程能力,并弥合已识别出的缺口。
  • 在外观现代化之前,优先处理不受支持的基础设施与无文档记录的集成。

关键资料来源

  • 英国《GOV.UK服务标准》,政府数字服务局——一项国家数字服务标准,要求为公共服务提供迭代式、以用户为中心的交付与开放标准。
  • 美国行政管理和预算局,《联邦源代码政策》(M-16-21)——要求各机构为定制开发的政府软件考虑复用与开源发布的联邦政策。
  • 欧洲自由软件基金会,《公共资金,公共代码》运动——为面向欧洲受众开发的、把公共资助软件的源代码在自由与开源许可证之下发布的理由。
  • 沃德·坎宁安,《WyCash投资组合管理系统》(1992年OOPSLA经验报告)——技术债务这一比喻的原始表述。
  • 数字公共物品联盟——一项多方利益相关者倡议,维护着为服务公共发展目标而设计的开放软件、数据与内容的标准与登记册。

参考文献

  1. Technical debt — Wikipedia — https://en.wikipedia.org/wiki/Technical_debt
  2. Ward Cunningham — Wikipedia — https://en.wikipedia.org/wiki/Ward_Cunningham
  3. Legacy system — Wikipedia — https://en.wikipedia.org/wiki/Legacy_system
  4. COBOL — Wikipedia — https://en.wikipedia.org/wiki/COBOL
  5. Software modernization — Wikipedia — https://en.wikipedia.org/wiki/Software_modernization
  6. Strangler fig pattern — Wikipedia — https://en.wikipedia.org/wiki/Strangler_fig_pattern
  7. Vendor lock-in — Wikipedia — https://en.wikipedia.org/wiki/Vendor_lock-in
  8. Free and open-source software — Wikipedia — https://en.wikipedia.org/wiki/Free_and_open-source_software
  9. Digital public good — Wikipedia — https://en.wikipedia.org/wiki/Digital_public_good
  10. Agile software development — Wikipedia — https://en.wikipedia.org/wiki/Agile_software_development
  11. Waterfall model — Wikipedia — https://en.wikipedia.org/wiki/Waterfall_model
  12. Minimum viable product — Wikipedia — https://en.wikipedia.org/wiki/Minimum_viable_product
  13. Service Standard — GOV.UK, Government Digital Service — https://www.gov.uk/service-manual/service-standard
  14. Requirements for Achieving Efficiency, Transparency, and Innovation Through Reusable and Open Source Software (M-16-21) — Digital.gov, Office of Management and Budget — https://digital.gov/resources/requirements-for-achieving-efficiency-transparency-and-innovation-through-reusable-and-open-source-software/
  15. Public Money, Public Code — Free Software Foundation Europe — https://publiccode.eu/
  16. 'The WyCash Portfolio Management System' (OOPSLA 1992 experience report) — Ward Cunningham — http://c2.com/doc/oopsla92.html
  17. Digital Public Goods Alliance — https://digitalpublicgoods.net/