规划管道的生成依赖项

已完成

在本单元中,将了解如何打包代码以便于共享。 你将了解为什么要创建包、可以创建哪些类型的包、可以在哪里托管包以及托管包后可以如何访问它们。 还将了解包版本控制。

代码库总是变得越来越大,越来越复杂。 团队编写其应用使用的所有代码是不常见的。 相反,团队包含由其他开发人员编写的现有代码。 在应用中可能有许多此类包或依赖项。 积极管理这些依赖项以便能够正确维护这些依赖项,并确保它们满足安全要求,这一点非常重要。

让我们检查并了解团队的工作方式。 Andy 已召集团队讨论了其代码可能发生的变化,这将有助于另一个团队。

团队会议

Andy:嗨,大家好。 我在和 Space Game 的后端系统开发团队聊天。 他们可以在计划编写的后端应用中使用我们用于网站的模型。

Amita:模型意味着什么?

Andy:如你所知,Space Game 网站是 ASP.NET Core 应用程序。 它使用模型-视图-控制器 (MVC),这是一种将数据与数据在用户界面中的显示方式分离的模式。 我想我们可以创建一个包含模型类的包,以便任何应用都可以使用它们。

Amita:目标究竟又是什么?

Andy:我们的两个团队将共享同一个数据库。 游戏发送数据库中的高分;我们读取这些分数以显示在排行榜上。

Amita:这种说法很合理。 我们将如何创建此包?

Andy:这就是我想和你交谈的原因。 我们有几个选项,让我想一想。

Tim:我很乐意帮忙,但首先我有几个问题。 我是新手,我想了解其工作原理。

什么是包?

“包”包含其他开发人员可以在其自己的项目中使用的可重用代码,即使他们未曾编写该代码。

对于编译的语言,包通常包含编译后的二进制代码,例如 .NET 中的 .dll 文件或 Java 中的 .class 文件。 对于解释而不是编译的语言(例如 JavaScript 或 Python),包可能包含源代码。

无论哪种方式,包通常被压缩为 ZIP 或类似格式。 包系统通常会定义一个唯一的文件扩展名,例如 .nupkg 或 .jar,以使包的使用更加清晰。 压缩有助于减少下载时间,还可以生成单个文件,从而简化管理。

包通常还包含一个或多个文件,这些文件提供有关包的元数据或信息。 此元数据可能描述包的功能、指定其许可条款、作者的联系信息和包的版本。

为什么要生成包?

与复制代码相比,生成包更具优势。

创建包而非复制代码的一个原因是防止出现偏差。 如果出现重复代码,每个副本都可以快速分离以满足特定应用的要求。 将更改从一个副本迁移到另一个副本会变得困难。 换句话说,失去了以有利于所有人的方式改进代码的能力。

包还将相关功能分组到一个可重用组件中。 根据编程语言,包可以为应用提供对某些类型和功能的访问,同时限制对其实现细节的访问。

生成包的另一原因是提供一致的方法来生成和测试该包的功能。 如果出现重复代码,每个应用都可以不同的方式生成和测试该代码。 一组测试可能包括另一组从中获益的检查。

一个弊端是,使用包时需要测试和维护另一个代码库。 添加功能时也必须小心。 通常情况下,包应包含有益于多种应用的功能。 例如,Json.NET 就是受欢迎的 .NET NuGet 包,它允许使用 JSON 文件。 Json.NET 是开放源代码,因此社区可以提出改进并报告问题。

当多个应用可以从相同的代码中受益时,优势远远超过了弊端。 你只有一个代码库、一组测试和一个要管理的生成过程。

如何标识依赖项?

如果目标是将代码重新组织到单独的组件中,则需要标识应用的哪些部分可以删除、打包以便可重复使用、存储在一个中心位置并进行版本控制。 你甚至可能要将自己的代码替换为开放源代码或许可的第三方组件。

可以通过许多方式来标识代码库中的潜在依赖项。 其中包括扫描代码以了解重用模式,以及分析解决方案的体系结构。 下面是一些用于标识依赖项的方法:

  • 重复代码。

    如果某些代码段出现在多个位置,则表明可以重用此代码。 将这些重复的代码段集中在一起,并对它们进行相应的重新打包。

  • 高内聚和低耦合。

    另一种方法是查找彼此之间具有高内聚并且与代码的其他部分之间耦合度低的码位元素。 从本质上讲,高内聚意味着将彼此相关的代码库的各个部分保留在一个地方。 同时,低耦合度是指尽可能多地分隔代码库的无关部分。

  • 个体生命周期。

    查找具有类似生命周期并且可以单独部署和发布的代码部分。 如果此代码可由单独的团队维护,则表明可以将其打包为解决方案外部的组件。

  • 稳定的部分。

    代码库的某些部分可能是稳定的,并且不经常更改。 检查代码存储库以查找更改频率较低的代码。

  • 独立代码和组件。

    如果代码和组件是独立的并且与系统的其他部分无关,可以将它们隔离到不同的依赖项中。

可以使用各种工具来帮助扫描和检查代码库。 这些工具包括扫描重复代码并绘制解决方案依赖项关系图的工具和可以计算耦合度和内聚指标的工具。

有哪种类型的包?

每种编程语言或框架都提供了其自己生成包的方法。 常用包的系统提供有关该过程工作原理的文档。

你可能已经熟悉了这些常用包的系统:

  • NuGet:包 .NET 库
  • NPM:打包 JavaScript 库
  • Maven:包 Java 库
  • Docker:在称为容器的隔离单元中打包软件

包托管在哪里?

可以在自己的网络上托管包,也可以使用托管服务。 托管服务通常称为“包存储库”或“包注册表”。 其中许多服务为开放源代码项目提供免费托管。

以下是我们刚介绍的包类型的一些常用托管服务:

  • NuGet 库

    NuGet 包用于 .NET 代码项目。 这些项目包括 .NET 程序集和相关文件、工具,有时还包括元数据。 NuGet 定义包的创建、存储和使用方式。 NuGet 包实质上是压缩文件夹结构,其中的文件采用 ZIP 格式,扩展名为 .nupkg。

  • NPM

    用于 JavaScript 的 NPM 包。 NPM 包是包含 JavaScript 文件以及描述包的元数据的 package.json 文件的文件或文件夹。 对于 node.js,包通常包含一个或多个可在使用包后加载的模块。

  • Maven 中央存储库

    Maven 用于基于 Java 的项目。 每个包都有一个项目对象模型文件,用于描述项目的元数据,是用于定义包和使用它的基本单位。

  • Docker 中心

    Docker 包称为映像,包含完整的自包含部署。 最常见的是 Docker 映像表示可以自行托管和执行而无需依赖其他映像的软件组件。 Docker 映像是分层的,可能依赖于其他映像。

“包源”指的是包存储库服务器。 此服务器可以位于 Internet 上,也可以位于网络上的防火墙后面。 例如,可以使用 Azure Artifacts 和 MyGet 等托管产品托管自己的 NuGet 源。 还可以在文件共享上托管包。

在防火墙后面托管包时,可以将源包含在自己的包中。 如果系统无法连接到 Internet,还可以缓存在网络上信任的包。

哪些元素可以构成良好的依赖项管理策略?

合理的依赖项管理策略取决于以下三个元素:

  • 标准化。

    标准化声明和解析依赖项的方式将有助于自动发布过程保持可重复且可预测。

  • 打包格式和源。

    每个依赖项都应使用适用的格式进行打包,并存储在一个中心位置。

  • 版本控制

    需要跟踪依赖项随时间发生的更改,就像你在自己的代码中所做的那样。 这意味着依赖项应进行版本控制。

谁可以访问包?

许多包源都提供对包的无限制访问。 例如,可以从 nuget.org 下载 Json.NET,而无需登录或进行身份验证。

其他包源需要身份验证。 可以通过多种方式对源的访问权限进行身份验证。 例如,某些类型的源需要用户名和密码。 其他源需要访问令牌,这通常是一长串字符,用于标识你的身份以及你有权访问的资源。 可以设置访问令牌在给定时间段后过期。

如何对包进行版本控制?

版本控制方案取决于使用的打包系统。

例如,NuGet 包使用语义化版本控制

语义化版本控制是一种常用的版本控制方案。 格式如下:

Major.Minor.Patch[-Suffix]

以下是每个参数的含义:

  • 新的主版本引入了重大更改。 应用通常需要更新如何使用包来处理新的主版本。
  • 新的次要版本引入了新功能,但与早期版本是向后兼容的。
  • 新的修补程序引入了向后兼容的错误修复,但没有引入新功能。
  • “-Suffix”部分是可选的,用于将包标识为预发布版本。 例如,1.0.0-beta1 可能会将包标识为 1.0.0 版本的第一个 beta 预发布生成版本。

引用包时,请按版本号进行引用。

以下是通过使用 PowerShell 和特定版本号安装包的示例:

Install-Package Newtonsoft.Json -Version 13.0.1

包更改后会发生什么?

从应用引用包时,通常使用 pin 或指定要使用的包的版本。

有许多框架可用于指定要安装的包版本的允许范围。 有些还可指定通配符,我们称之为“浮动版本”。

例如,在 NuGet 中,版本“1.0”表示第一个版本等于或大于 1.0。 “[1.0]”指定仅安装 1.0 版,而不是更新版本。

以下是几个其他示例:

此表示法: 选择:
(1.0,) 第一个版本大于 1。
[1.0,2.0] 第一个版本大于或等于 1.0 且小于或等于 2.0
(1.0,2.0) 第一个版本大于 1.0 且小于 2.0
[1.0,2.0) 第一个版本大于或等于 1.0 且小于 2.0

当每个维护者发布新的包版本时,你可以评估更改的内容并根据它测试应用。 准备就绪后,可以在配置中更新包的版本号,并将更改提交给生成管道。

以下示例演示了如何在 C# 应用程序的项目 (.csproj) 文件中包含 Newtonsoft.Json 包。 此示例指定该包的版本 13.0.1:

<ItemGroup>
  <PackageReference Include="Newtonsoft.Json" Version="13.0.1" />
</ItemGroup>

知识检查

1.

什么是包?

2.

假设已生成了一个要公开共享的包。 最简单的方法是什么?