共享库鼓励代码重用,提升团队之间的一致性,并最终提高产品速度和质量。但应用程序开发人员仍然需要选择合适的库来使用,弄清楚如何正确配置这些库,并将所有内容连接在一起。通过预安装和预配置库,应用程序框架提供了简化的开发者体验和更高的一致性,尽管这以牺牲一定的灵活性为代价。
通过拥有整个应用程序生命周期,框架超越了单纯的库集合。有保证的框架行为可以扩展开发——例如,避免对每个应用程序进行深入的安全或隐私代码审查。框架提供的跨团队和跨语言一致性也是更高层次自动化和智能系统的必要基础。
本文首先概述框架的中心方面,然后深入探讨框架的好处、其带来的权衡,以及我们建议实施的最重要功能。最后,本文介绍了框架在 Google 的实际应用:开发微服务平台如何帮助 Google 打破其单体代码库,以及框架如何促成这一变革。
框架在许多方面类似于共享库,并具有类似的好处。对于 Google 而言,两个技术原则有助于区分框架和库:控制反转和可扩展性。虽然看似不起眼,但本文讨论的框架的许多好处主要源于这些原则。
在从头开始构建的应用程序中,工程师决定程序的流程——这是正常的控制流程。在基于框架的应用程序中,框架控制流程,并将调用用户代码——这是反转的控制流程。反转的控制流程有时被称为好莱坞原则:“不要打电话给我们;我们会打电话给你。” 框架控制流程是明确定义的,并且在所有应用程序中都是标准的。理想情况下,应用程序仅实现特定于应用程序的逻辑,而框架可以处理构建类似微服务的其他所有细节。
可扩展性是框架与库的第二个关键区别,并且与控制反转密切相关。由于框架的控制流程由框架拥有,因此更改框架行为的唯一机制是通过其公开的扩展点。例如,服务器框架可能具有一个扩展点,允许应用程序在每次请求后运行一些代码。此行为还意味着框架的不可扩展部分是固定的,并且无法被应用程序更改。
框架除了共享库提供的功能之外,还具有多重优势,并且以不同的方式对不同的利益相关者有利。
最终决定是否使用可用框架的开发者是框架最明显的受益者。开发者的主要优势包括提高生产力、简化性和符合最佳实践。开发者可以通过利用内置框架功能来编写更少的代码,并且他们编写的代码可以更简单,因为框架处理了样板代码。框架通过提供合理的默认值并消除毫无意义且耗时的决策,为最佳实践提供了一条明确的道路。
除了提高开发者生产力外,框架还可以通过释放原本用于构建冗余基础设施的团队资源来使产品团队受益。然后,产品团队可以将精力集中在使其产品与众不同的方面。
当框架将产品团队与底层基础设施的变化隔离开来时,产品团队也会受益。虽然并非在所有情况下都可能,但框架提供的额外抽象意味着某些基础设施迁移可以被视为完全由框架维护者处理的实现细节。
Google 的产品发布通常需要多个团队的批准。例如,发布协调工程师负责审查发布的生产安全性和有效性,而信息安全工程师将检查应用程序的设计是否存在常见的安全漏洞。当执行审查的团队熟悉框架并可以依赖其行为保证时,框架可以简化发布审查流程。发布后,标准化还将使系统更易于管理。
在公司层面,通用框架可以通过减少开发者在新应用程序上快速上手所需的时间来提高开发者流动性。如果公司拥有足够大的开发者社区,那么投资高质量的文档和培训计划是值得的;反过来,这有助于吸引来自社区本身的文档和代码贡献。框架的广泛使用也意味着对框架改进的相对较小的投资可能会产生巨大的影响。
随着时间的推移,框架架构的集中化可以允许大规模应对不断变化的环境。例如,如果您依赖于一致的微服务/RPC(远程过程调用)框架,并且相对于 CPU 而言带宽变得更加昂贵,那么框架默认值可以根据该成本权衡集中调整压缩参数。
虽然框架具有刚刚描述的多重优势,但它们也带来一定的权衡。
框架通常必须就支持哪些类型的技术做出选择。虽然支持每一种可以想象到的技术是不切实际的,但当框架是有主见的时——也就是说,当它们鼓励使用某些技术或设计模式而不是其他技术时,显然是有好处的。
有主见的框架可以极大地简化开发者处理空白状态新系统的工作。当开发者有很多方法可以完成相同的任务时,他们很容易陷入对整体系统影响微乎其微的决策细节中。对于这些开发者来说,接受有主见的框架的首选技术可以让他们专注于构建系统的业务。即使答案并不完美,拥有通用且一致的首选项也有利于整个公司。
当然,您可能需要处理大量的应用程序和团队,并且某些产品需求或团队偏好可能不太适合现有的框架。框架维护者处于决定什么是最佳实践,以及非常规用例是否“有效”的位置,这可能会让所有相关人员感到不舒服。
另一个重要的考虑因素是,即使某些东西在今天显然是最佳实践,技术也在快速发展,并且存在框架跟不上创新的风险。尝试替代应用程序设计可能会更加昂贵,因为开发者需要学习框架实现细节,或者依赖框架维护者的帮助。
许多框架优势(例如通用控制面(稍后解释))只有在大量应用程序使用相同的框架时才能实现。这样的框架必须足够通用,以支持绝大多数用例,这在实践中意味着拥有丰富的请求生命周期和任何应用程序所需的所有可扩展性挂钩。这些要求必然会在应用程序和底层库之间添加一些间接层,这可能会增加认知和 CPU 开销。对于应用程序开发者来说,软件堆栈中的更多层可能会使调试变得复杂。
框架的另一个潜在缺点是它们是工程师必须学习的又一件事。新入职的 Google 员工经常会被他们需要学习的大量技术淹没,仅仅是为了让一个“hello world”示例正常工作。功能齐全的框架可能会使情况变得更糟,而不是更好。
Google 通过尝试使每个框架的核心尽可能简单和高性能,并将其他功能保留为可选模块,在某种程度上缓解了这些问题。Google 还尝试提供框架感知工具,这些工具可以利用框架的固有结构来简化调试。然而,最终,框架是有成本的,您必须承认这一点,并且您需要确保任何给定的框架都提供足够的好处来证明这种成本是合理的。不同的编程语言框架也可能具有不同的权衡组合,从而为开发者创造另一个决策点和成本/收益情景。
正如已经讨论过的,控制反转和可扩展性是框架的基本方面。除了这些基本参数之外,框架还应考虑其他几个特性。
重申一下,控制反转意味着框架拥有并标准化应用程序的整体生命周期,但这种结构实际上带来了什么好处?避免级联故障的场景提供了一个示例。
级联故障是系统中断的众所周知的原因,包括 Google 的许多中断。当分布式系统的某一部分发生故障时,可能会发生级联故障,这会增加其他部分发生故障的可能性。有关级联故障的原因以及如何避免它们的更多信息,请参阅站点可靠性工程(O'Reilly Media,2016 年)中关于解决级联故障的章节。
Google 的服务器框架具有许多针对级联故障的内置保护措施。最重要的两个原则是
• 保持服务。如果服务器可以成功响应请求,则应该这样做。如果它可以成功服务某些类型的请求,但不能服务其他类型的请求,则应继续运行并响应它可以服务的请求。
• 快速启动。服务器应尽可能快速启动。更快的启动意味着从崩溃中更快地恢复。服务器应避免串行等待涉及与外部系统的 RPC 的初始化完成。
Google 生产环境为每个服务器提供可配置的时间量,使其变为“健康”(开始响应请求)。如果时间到期,系统会假定发生了无法恢复的错误并终止服务器进程。
在没有框架的情况下,自然会发生一种常见的反模式:库创建自己的 RPC 连接,然后等待该连接准备就绪。随着服务器代码库随着时间的推移而增长,您最终可能会在传递依赖项中包含数十个这样的库。结果是服务器初始化代码,如果展开,它实际上看起来像图 1。
在正常情况下,此代码可以正常工作,这尤其成问题,因为没有迹象表明存在潜伏的问题。当相关的后端服务之一变慢或完全关闭时,问题就会显现出来——现在主服务器的启动被延迟了。如果启动被充分延迟,它将在有机会开始处理请求之前被杀死,这可能会导致级联故障。
一种可能的改进是首先创建 RPC 存根,如图 2 所示,然后并行等待所有存根。在这种情况下,您只需要等待存根初始化时间的最大值,而不是总和。
虽然仍然不完美,但即使是这种有限的重构也表明,您需要在创建 RPC 存根的库之间进行某种协调——它们必须将等待存根的责任移交给库外部的某些东西。在 Google 的案例中,该责任由服务器框架拥有,该框架还具有以下特性
•并行等待所有存根准备就绪,通过定期轮询就绪状态(< 1 秒)。一旦可配置的超时时间过去,即使并非所有后端都已准备就绪,服务器也可以继续初始化。
• 发出人类和机器可读的日志,用于调试以及与标准监控和警报系统集成。
• 通过通用机制插入任意资源,而不仅仅是 RPC 存根。从技术上讲,只需要一个返回布尔值(表示“我准备好了吗?”)的函数和一个名称用于日志记录目的。这些挂钩通常由处理资源的通用库(例如,文件 API)使用;应用程序开发者通常只需使用库即可自动获得该行为。
• 提供一种集中方式将某些后端配置为“关键”,这会改变它们的启动和运行时行为。
对于任何单个库来说,这些特性(理所当然地)都将被认为是过度的,但如果您可以在一个中心位置执行这些特性,所有使用后端的库都可以从中受益,那么实现这些特性是有意义的。正如共享库是在应用程序之间共享代码的一种方式一样,在这种情况下,框架是库本身共享功能的一种方式。
SRE(站点可靠性工程师)更乐于支持基于框架的服务器,因为具有这些特性,他们经常鼓励他们的开发者同行选择基于框架的解决方案。框架提供了一个基线级别的生产规律性,如果只是将一堆断开连接的库粘合在一起,则很难(如果不是不可能)实现。
虽然细节因应用程序类型而异,但许多框架除了整体应用程序生命周期之外,还支持其他生命周期。对于 Google 服务器框架,最重要的工作单元是请求。遵循类似的控制反转模型,请求生命周期的目标是将请求的不同方面的职责划分为单独的可扩展代码片段。这允许应用程序开发者专注于编写使其应用程序独一无二的实际业务逻辑。
以下是一个真实世界框架及其组成部分的示例,如图 3 所示
• 处理器——拦截传入和传出的有效负载。主要用于日志记录,但具有短路请求的一些功能(例如,跨整个应用程序强制执行不变性)。
• 操作——应用程序业务逻辑,它接受请求并返回响应对象,可能带有副作用。
• 异常处理程序——将未捕获的异常转换为响应对象。
• 响应处理程序——将响应对象序列化到客户端。
虽然应用程序可以利用框架扩展点,但绝大多数应用程序代码都采用操作的形式,这些操作体现了特定于应用程序的业务逻辑。
这种关注点分离在 Web 安全领域非常有用。Google 开发了许多 Web 应用程序,因此强烈希望防范各种 Web 安全漏洞,例如 XSS(跨站脚本)。XSS 漏洞通常是由应用程序代码返回包含未充分清理或转义的数据的字符串响应引起的。修复这些错误的传统方法是简单地添加缺失的转义数据,并希望测试和代码审查能够防止将来出现类似的问题(剧透:它们不会)。
从根本上讲,这种方法行不通,因为应用程序正在编码的基础 API 本身就容易出现像 XSS 这样的错误,因为它们接受字符串或类似的不结构化/非类型化数据。例如,Java Servlet API 为应用程序提供了一个原始的 Writer,您可以向其中传递任意字符。这种方法给开发者带来了太多的负担,让他们去做正确的事情;相反,Google 的安全团队专注于设计本质上安全的 API,例如
• 具有上下文感知转义的 HTML 模板系统。
• 抗 SQL 注入的数据库 API。
• “安全 HTML”包装器类型,它们带有合同,规定它们的值在各种上下文中可以安全使用。
Google 服务器框架的请求生命周期补充了这些 API 的使用,因为应用程序代码永远不会处理原始字符串或字节。相反,代码返回高级响应对象,其类型如 SafeHtmlResponse
,只能以保证格式良好的方式构造。将这些响应对象转换为网络上的字节是响应处理程序的责任,响应处理程序通常是框架的内置部分。Google 有时需要自定义响应处理程序,但所有用法都必须经过安全团队的审查——这是在构建级别强制执行的要求。
最终影响是,Google 已将使用这些框架的应用程序中的 XSS 漏洞数量减少到几乎为零。您可以想象,Google 的安全团队强烈鼓励使用框架,并为改进所有框架用户的安全故事做出了许多框架贡献。基于标准框架的服务器可以有效地跳过许多定制服务器启动所需的安全或隐私审查,因为框架被信任可以保证某些行为。
当然,结构化和可扩展的请求生命周期的好处远不止将业务逻辑与响应序列化分离。最基本的好处是,它使每个组件都保持小巧且易于推理,这有助于长期的代码健康。Google 内的其他基础设施团队可以轻松扩展框架功能,而无需直接与框架团队合作。最后,应用程序可以引入自己的横切功能,而无需触及每个操作。在某些情况下,这些功能是特定于域的,但其他功能最终会变得普遍适用,并最终“上游”到框架本身。
我们将控制面称为二进制文件作为黑盒查看时的所有非应用程序特定输入和输出。这些包括操作控制、监控、日志记录和配置。
服务器之间的统一性使故障排除变得更加容易。无论他们正在对哪个服务器进行故障排除,开发者和 SRE 都知道哪些信息可用以及在哪里查找。如果需要调整服务器的某些方面,每个人都知道哪些旋钮可用以及如何更改它们。
除了使人类更容易操作服务器之外,跨服务器拥有通用控制面也使共享自动化变得可行。例如,如果所有服务器都以标准方式导出错误,则更改发布管道以执行自动 Canary 测试变得可能:您可以首先将新二进制文件发布到少量服务器,并在执行更广泛的发布之前查找错误峰值。您可以从站点可靠性工程(O'Reilly,2016 年)中关于不断发展的 SRE 参与模型的章节中了解更多关于通用控制面的好处。
框架为强制执行跨应用程序控制面的一定程度的统一性提供了绝佳的机会。虽然通常只有少数人关心控制面的确切组成,但对于公司而言,拥有一个单一一致的答案具有巨大的价值。一致性意味着您可以轻松地跨多个二进制文件共享和扩展自动化。通过简化与周围生态系统的集成,您可以多次获得拥有标准的收益,而与标准本身的优点无关。
实施通用控制面的一个挑战是,框架维护者通常是第一个发现跨编程语言库的不一致之处的人。例如,所有语言都存在命令行参数的概念,其值为持续时间(时间长度)。从积极的一面来看,语法在语言之间在某种程度上是兼容的,至少对于最基本的示例(例如“1h30m”)而言是如此。然而,一旦我们深入研究细节,就会出现不同的情况,如图 4 所示。
如今,库所有者更加意识到跨语言一致性的价值,以及需要将这种一致性纳入考虑范围。在框架方面,Google 还使用测试工具来针对每种编程语言编写的服务器运行相同的测试套件,以确保未来的一致性。
无论好坏,Google 都没有中央软件工程权威机构。虽然大多数开发者都在针对单个代码存储库工作,但工程实践在团队之间仍然差异很大。任何给定项目的技术选择通常由项目的技术负责人决定,几乎没有自上而下的指令。可以理解的是,人们倾向于选择他们以前有经验的技术。因此,为了使一项新技术获得广泛采用,它必须具有明显的价值或较低的入门门槛;通常,它必须两者兼具。
对于 Google 的服务器框架,核心生命周期管理和请求分派是唯一严格要求的特性。所有其他功能都捆绑到可选的、独立的“模块”中,这些模块使用框架公开的各种生命周期挂钩来实现其功能,如前所述。应用程序开发者可以选择将哪些模块添加到他们的服务器中,并且在许多情况下,即使是主要功能也可以通过一行代码添加
install(new LoadSheddingModule());
可用的标准模块的实际列表多达数百个,包括身份验证、实验和日志记录等功能。
将框架功能增量添加到服务器的能力是 Google 框架采用的一个重要因素。它允许“hello world”示例和原型服务器变得小巧且易于理解,同时仍然可以轻松扩展到更全面的服务器(在适当的时候)。
模块的独立性还允许在您有特殊要求时轻松地用特定于应用程序的模块替换标准框架模块。由于标准框架模块使用与特定于应用程序的模块相同的可扩展性 API,因此将有用的功能上游到框架中通常只是移动代码的琐碎问题。这允许框架成为不断增长的最佳实践集合,一旦这些实践在现实世界中证明了它们的价值。
这里展示的高度封装意味着框架维护者可以彻底更改模块的实现,而无需触及任何应用程序代码。当后端系统被弃用或需要 API 更改时(这种情况非常普遍),这尤其有用。Google 框架使许多应用程序开发者免于执行复杂或昂贵的迁移,对于许多团队来说,这是当今框架最引人注目的好处之一。
框架维护者的一个角色是确保模块彼此正确协作。维护者还可以选择默认模块列表,或提供关于在不同情况下应使用哪些模块的建议和约束。一个挑战是在粒度方面取得适当的平衡:虽然开发者倾向于使用细粒度模块以获得灵活性,但框架维护者更难确保所有组合都能很好地协同工作。
框架的广泛使用提供的标准化为更高级别的工具和自动化创造了机会。这使 Google 能够创建一个微服务平台并打破单体服务器。
共享库和框架的存在极大地简化了在 Google 内部编写生产质量代码的实际操作。然而,编写代码只是在 Google 部署应用程序的一部分。其他关键要素包括集成测试;针对安全和隐私等方面进行发布审查;获取生产资源;执行发布;收集和保存日志;实验;以及调试和解决中断。
从历史上看,处理所有这些项目都是一项昂贵的过程,所有服务器所有者都必须完成,无论服务器的大小如何。因此,与其部署新服务器,不如添加新服务的小团队会寻找现有服务器,他们可以在其中添加他们的代码。这样,团队就可以专注于编写他们的业务逻辑,并“免费”获得其他一切。当然,一旦足够多的团队采取了这种方法,就很明显,搭便车使用现有服务器功能实际上并非免费。这种激励结构在 Google 多次导致了公地悲剧:得到良好支持的服务器继续增长,直到它们变得庞大且难以维护的单体。
单体具有许多负面后果。在开发者生产力方面,您必须处理缓慢的构建、缓慢的服务器启动,以及当您尝试提交更改时,您的预提交测试很有可能会中断。例如,一个重要的与 Google 搜索相关的 C++ 二进制文件变得如此之大,以至于即使考虑到当时的技术限制(12 GB 内存)也无法链接。
在发布方面,很难按计划将它们推送到单体。随着单体的增长,贡献开发者的数量也在增加,这自然会导致更多的阻塞错误。延迟发布可能会使实现下一次发布更加困难,这可能会造成恶性循环。
在生产中,单体在表面上不相关的服务之间造成了危险的共同命运,以及更大的由意外交互引起的错误机会。独立于彼此扩展服务是不可能的,这使得资源配置更加困难。
虽然最终很明显 Google 的单体情况是不可持续的,但没有好的替代方案。仅仅强制人们停止向单体添加内容会产生同样糟糕的后果。相反,Google 需要消除生产化和运行新服务器的辛劳。这将允许根据纯粹的生产原因,而不是开发者便利性,来决定哪些服务应该构成一个服务器,如图 5 所示。
从开发者应该只关注其特定于应用程序的服务的业务逻辑,以及其他一切都应尽可能自动化的目标倒推,一些要求最终变得清晰
• 开发者应该声明和实现服务 API,而不是编写 main
方法;编排二进制文件实际运行方式是微服务平台的角色。
• 自动化所需的所有元数据,包括生产配置,都应以声明性格式与服务代码一起存在。
• 服务之间的资源和依赖关系应该是显式和声明性的。理想情况下,您应该能够仅通过查看服务领域的元数据来可视化整个生产拓扑。
• 服务应彼此隔离,以便可以将任意服务共同组装到服务器中。在其他要求中,这意味着避免全局状态和副作用。
当这些要求得到满足时,几乎所有以前的手动流程都可以自动化。例如,测试基础设施可以在运行集成测试时使用元数据来连接服务依赖关系图的一部分。
Google 开发了一个使用这些原则的微服务平台,最初目的是打破一个特定的、大型的、由于 интенсив 的功能开发而快速增长的单体服务器。一旦平台被证明是有益的,它就被 Google 内的其他团队有机地采用,并最终被分拆成一个单独的官方支持项目。
如今,该平台已成为新的服务器开发的 фактический 标准,部分原因是它吸引了小型团队和大型组织。由于高度自动化,小型团队现在可以在几天内轻松启动 Google 质量的生产服务,而在以前,遵循最佳实践的启动可能需要数月时间。对于大型组织而言,跨团队的一致性降低了支持成本,并且共享平台意味着通常不需要为组织特定的基础设施团队配备人员。
迁移到微服务的另一个好处是鼓励开发者更多地思考服务之间工作的适当划分,这导致了更合理的系统架构。使用 gRPC 和协议缓冲区等技术作为不同系统之间的边界,迫使您以一种在您仅在同一进程中使用函数调用时不必考虑的方式来考虑 API。RPC 系统也是语言无关的,因此每个微服务所有者都可以独立决定使用哪种语言。
一个仍然存在的挑战,也是未来工作的沃土,是提供更高级别的工具来管理不断增长的微服务数量。例如,在以前的时代编写的监控控制台可能假设只有相对较少的独特二进制文件,这将需要一个新的用户界面来适应人们完全采用微服务时出现的更多数量的二进制文件。
框架是使 Google 的微服务平台工作的关键组成部分,原因有以下几点
• 框架生命周期中固有的控制反转自然而然地适用于应用程序开发者只需将其服务实现移交给平台的模型。
• 许多平台功能(包括发布管理、监控和日志记录)都需要通用控制服务(跨服务器和语言)。
• 模块化意味着平台和应用程序代码都可以提供独立的模块,这些模块组合在一起时,可以以合理的方式协同工作以形成完整的服务器。
图 6 显示了 Google 微服务平台的完整开发堆栈。
如前所述,框架可以提供比库更高程度的封装,这简化了应用程序编写,并提供了与底层库变动的隔离。以类似的方式,微服务平台超越了代码,封装了其他工件,例如生产配置。这允许相应地更高程度的简化和与变动的隔离。例如,平台维护者可以(如果必要)自动应用紧急代码修复或配置更改,以统一的方式重建所有受影响的二进制文件并将它们推送到生产环境——这在以前是不可能的。
然而,使用微服务平台确实带来了一些挑战。其中最大的挑战之一是,强制执行使微服务平台正常运行所需的所有不变量可能很繁琐,甚至可能影响应用程序的编码方式。举一个例子,Google 的 Java 服务器共享某些线程池。结合所有服务必须彼此隔离的要求,这意味着不允许使用阻塞的每个请求一个线程的模型——阻塞服务很容易用完所有线程并使另一个服务饥饿。因此,服务器被强制只能是异步的,但并非所有团队都对这种解决方案感到满意。
另一个挑战是,在微服务之间添加更多跳跃可能会增加整体请求的延迟。在某些情况下,这种延迟可以通过作为微服务重写一部分发生的架构改进来缓解。对于其微服务平台,Google 还确保恰好位于同一服务器中的服务之间的请求使用优化的进程内传输。
虽然框架可能是一个强大的工具,但它们也有一些缺点,并且可能不适合所有组织。框架维护者需要提供标准化和明确定义的行为,同时又不会过于规范。然而,当框架达到适当的平衡时,它们可以带来巨大的开发者生产力提升。框架的广泛使用所提供的一致性对于其他团队(例如 SRE 和安全团队)来说是一种福音,这些团队对应用程序的质量有既得利益。此外,框架的结构为构建更高级别的抽象(例如微服务平台)奠定了基础,这为系统架构和自动化解锁了新的机会。在 Google,此类框架和平台已获得广泛的自然采用,并产生了重大的积极影响。
Brad Hawkes 是 Google 核心基础设施部门的高级软件工程师。他致力于 Java 虚拟机上的服务器框架,该框架在 Google 的数千台服务器中使用。他的 LinkedIn 个人资料是 www.linkedin.com/in/bhawkes。
Chris Nokleberg 是 Google 服务器框架的首席软件工程师和技术主管。大约 10 年前,他开始在 Google Docs 担任技术主管时开发和推广框架。他目前的重点是帮助大型团队采用 Google 的微服务平台,并将开发者最佳实践标准化到整个公司。
版权 © 2020 归所有者/作者所有。出版权已授权给 。
最初发表于 Queue vol. 18, no. 6—
在 数字图书馆 中评论本文
Catherine Hayes, David Malone - 质疑评估非加密哈希函数的标准
虽然密码学哈希函数和非密码学哈希函数无处不在,但在它们的设计方式上似乎存在差距。密码学哈希函数存在许多标准,这些标准是出于各种安全需求而提出的,但在非密码学方面,存在一定的传统认知,尽管哈希函数历史悠久,但这些认知尚未得到充分探索。虽然针对真实世界数据集以实现均匀分布很有意义,但当面对具有特定模式的数据集时,这可能是一个挑战。
Nicole Forsgren, Eirini Kalliamvakou, Abi Noda, Michaela Greiler, Brian Houck, Margaret-Anne Storey - DevEx 实践
DevEx(开发者体验)在许多软件组织中越来越受到关注,因为领导者们在财政紧缩和人工智能等变革性技术的背景下,寻求优化软件交付。技术领导者们凭直觉普遍认为,良好的开发者体验能够提高软件交付效率和开发者幸福感。然而,在许多组织中,旨在改善 DevEx 的拟议倡议和投资难以获得支持,因为业务利益相关者质疑改进的价值主张。
João Varajão, António Trigo, Miguel Almeida - 低代码开发生产力
本文旨在通过呈现使用基于代码、低代码和极限低代码技术进行的实验室实验结果,来提供关于生产力差异的新见解。低代码技术已明确显示出更高的生产力水平,为低代码在短期/中期内主导软件开发主流提供了有力的论据。本文报告了程序和协议、结果、局限性以及未来研究的机会。
Ivar Jacobson, Alistair Cockburn - 用例至关重要
虽然软件行业是一个快节奏且令人兴奋的世界,在这个世界中,为了服务于商业和社会,新的工具、技术和方法不断被开发出来,但它也很健忘。在它急于快速前进的过程中,它容易受到时尚潮流的影响,并且可能会忘记或忽略一些针对它面临的永恒问题的成熟解决方案。用例,最早在 1986 年被引入并在后来普及,就是这些成熟解决方案之一。