mcpField
T
The Standard Practices

The Standard Practices

github.com/hassanhabib开发2072 次安装13 周前更新
代码仓库

关于 The Standard Practices

The Standard Practices 是用于团队协作与项目管理的技能,面向贡献者和维护者,涵盖分支、提交、评审、配置及工程度量,并规定分支命名与单项操作等规则。

主要功能

  1. 01代码贡献与项目结构规范
  2. 02分支策略及命名约定
  3. 03提交与 Pull Request 规则
  4. 04FAIL/PASS 测试纪律
  5. 05配置、环境变量与密钥处理
  6. 06工程度量与贡献成长

适用场景

  1. 01规划仓库协作流程
  2. 02为工作选择分支并命名
  3. 03准备提交和 Pull Request
  4. 04配置环境并保护敏感信息

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/hassanhabib/the-standard-skills --skill the-standard-practices

安装后在 Claude Code 中输入/the-standard-practices确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

manifest.json
contracts/
contracts.json
examples/bad/
example_bad_branches.md
example_bad_commits.md
examples/good/
example_commit_messages.md
example_branch_names.md
rules/
rules.json
rules.md
templates/
branch_naming_guide.md
pull_request_template.md
validations/
anti-patterns.md
checklist.md

详细介绍

标准实践规范

这项技能是什么

这项技能是 The Standard 的团队流程、贡献和项目纪律层。 它规定了如何组织、命名、提交、审查、配置、衡量工作,以及如何随着时间推移不断发展。

明确的涵盖范围

这项技能明确涵盖:

  • 代码贡献
  • Fork/克隆/分支
  • 分支命名规范
  • 分类系统
  • 项目/解决方案结构
  • 提交策略
  • FAIL/PASS 规范
  • Pull Request 规范
  • 配置处理
  • 环境变量和密钥
  • GitHub Actions 配置指南
  • 衡量指标
  • 贡献积分
  • 平均实现时间
  • 排名
  • 随项目实现规范提供的扩展实现规范实践部分

适用时机

规划工作、命名分支、组织代码仓库、编写提交信息、创建 Pull Request 或配置环境时,都应使用这项技能。

强制执行规则

  1. 贡献必须有条理。
  2. 分支必须有明确的命名意图。
  3. 提交必须准确说明实际完成的工作单元。
  4. TDD 工作必须遵循 FAIL/PASS 规范。
  5. Pull Request 必须使用 Standard 分类命名。
  6. 敏感配置不得以明文形式提交到代码库。
  7. 衡量指标是工程成长和公平性的一部分,而非虚荣指标。

标准实践

4. 实践

为代码贡献、分支、提交策略和项目结构制定明确的实践规范,对任何软件开发项目都至关重要。 这些实践为代码库管理提供清晰且一致的方法,确保贡献以受控且有条理的方式进行。 这有助于避免混乱和冲突,并确保代码库保持稳定且易于维护。 此外,明确规定代码贡献和项目结构的实践规范,有助于改善开发团队内部的协作和沟通,让跟踪和审查变更以及发现并解决问题更加轻松。 总的来说,为代码贡献、分支、提交策略以及项目结构制定明确的实践规范,是任何成功软件开发项目的关键组成部分。

实践规范要求考虑以下主要方面:

  1. 代码贡献
    1. Fork/克隆和分支
    2. 项目结构
    3. 提交
    4. Pull Request

The Standard 团队必须清楚地理解并定义上述每个方面。

4.1 代码贡献

为任何开源或协作软件开发项目制定贡献指南都至关重要。 它明确规定了贡献者应如何提交和审查变更,以及相关要求,从而确保所有贡献都以一致且有条理的方式完成。 此外,贡献指南可以提供有关编码、测试和文档编写最佳实践的指导,有助于提高代码库的整体质量。 它也可以作为面向新贡献者的教学工具,为他们提供有效参与项目所需的信息和说明。 (此外,制定完善的 GitHub 贡献指南有助于吸引新的贡献者,并维护健康的开源社区。)

4.1.1 分叉与分支策略

代码分支策略对于维护稳定且易于维护的代码库至关重要。 它允许多位开发者同时处理不同的功能或错误修复,互不干扰。 每位开发者都可以创建自己的分支进行开发,待分支经过审查并获批后,再将其合并到主分支。 这有助于避免冲突,并确保代码库保持稳定且一致。 此外,分支策略支持版本控制,还能创建和跟踪代码库的不同版本。 这有助于在必要时回退更改,也便于为不同环境维护软件的多个版本。 总的来说,分支策略是任何软件开发项目的关键组成部分,对于确保代码库保持稳定且易于维护至关重要。

软件开发中有多种分支策略可供选择,包括:

  1. Gitflow:一种流行的分支策略,遵循严格的分支模型:开发工作在功能分支中进行,然后合并到主开发分支中。这种策略适合贡献者众多的大型项目。

  2. 主干开发:这种策略是在主分支(即主干)上工作,并直接向其提交更改。这种策略适合规模较小、贡献者较少的项目。

  3. 功能分支:这种策略是为每项功能或错误修复创建单独的分支,完成后再将其合并到主分支。这种策略适合有多位贡献者的大型项目。

  4. 分叉:这种策略是复制代码仓库,并在副本上单独开展工作。这适合多位贡献者共同开发同一代码库的开源项目。分叉工作流的主要优势在于,无需所有人都向同一个中央代码仓库推送更改,就能集成贡献。开发者将更改推送到各自的服务器端代码仓库,只有项目维护者才能向官方代码仓库推送更改。这样,维护者无需授予开发者对官方代码库的写入权限,也能接受来自任何开发者的提交。

  5. 发布分支:这种策略是为每个版本创建单独的分支,准备发布时再将其合并到主分支。这种策略适合有固定发布计划的项目。

  6. 持续集成:这种策略是在代码更改完成后立即合并,并运行自动化测试,以确保代码库保持稳定。这种策略适合更改频率较高的项目。

归根结底,选择的分支策略应符合项目的需求和限制,并且所有贡献者都能轻松理解和遵循。

4.1.1.1 开源开发

由于 The Standard 推崇开源工作,让我们快速了解一下 Forking 工作流。

工作原理

Forking 工作流从存储在服务器上的官方公共仓库开始。当新开发者想要开始参与项目时,不会直接克隆官方仓库。

相反,他们会 Fork 官方仓库并创建一份副本。这份新副本将作为他们个人的公共仓库。
创建好服务器端副本后,开发者会执行 git clone,将其副本克隆到本地计算机。
和其他工作流一样,这就是他们的私有开发环境。

准备好发布本地提交时,他们会将提交推送到自己的公共仓库(而不是官方仓库)。
然后,他们会向主仓库提交拉取请求,以便项目维护者知道有更新可供集成。
随后可以审查拉取请求;如果贡献的代码存在问题,它也可以作为方便的讨论串。

以下是此工作流的分步示例:

  1. 开发者 Fork 一个“官方”的服务器端仓库,从而创建自己的服务器端副本。
  2. 将新的服务器端副本克隆到本地系统。
  3. 创建一个新的本地功能分支。
  4. 开发者在新分支上进行更改。
  5. 为这些更改创建新的提交。
  6. 将该分支推送到开发者自己的服务器端副本。
  7. 开发者从新分支向“官方”仓库发起拉取请求。
  8. 审查拉取请求,并验证构建成功且测试通过。此时,维护者可以要求修改,也可以批准合并;批准后,更改便会合并到原始服务器端仓库中。
4.1.1.2 分支命名约定

分支名称可以采用以下命名约定:users/[username]/[category]-[entity]-[action]

变量可以替换为:

  • [username] => 你的 GitHub 用户名
  • [category] => 你正在处理的类别
  • [entity] => 你的服务 / broker 使用的实体
  • [action] => 操作——必须与所处理层的语言一致
各层的分支操作语言

[action] 部分使用该层的词汇,而不是通用描述:

层正确的操作错误的操作
BROKERSinsert、select-all、select-by-id、update、deleteadd、retrieve、modify、remove
FOUNDATIONSadd、retrieve-all、retrieve-by-id、modify、removeinsert、select、update、delete
PROCESSINGSensure、upsert、try-add、try-remove基础设施操作动词
INFRA、DATA、CONFIGcreate、setup、update、remove(没有严格的语言限制)

示例:

# Correct — infrastructure verb for a BROKERS branch
users/hassanhabib/BROKERS-student-insert
users/hassanhabib/BROKERS-student-select-all
users/hassanhabib/BROKERS-student-select-by-id
users/hassanhabib/BROKERS-student-update
users/hassanhabib/BROKERS-student-delete

# Correct — business verb for a FOUNDATIONS branch
users/hassanhabib/FOUNDATIONS-student-add
users/hassanhabib/FOUNDATIONS-student-retrieve-all
users/hassanhabib/FOUNDATIONS-student-modify

# Wrong — business verb in a BROKERS branch
users/hassanhabib/BROKERS-student-add        ← should be 'insert'
users/hassanhabib/BROKERS-student-retrieve   ← should be 'select-by-id' or 'select-all'
每个分支只处理一个操作

每个分支代表一个操作。当提示词对范围的描述不明确时 (例如,“为 Student 构建一个 storage broker”),Agent 必须先询问要实现哪些操作, 然后才能创建分支或编写代码。不得假设要搭建所有 CRUD 操作。

Ambiguous prompt:  "Build a storage broker for Student"
Required response: "Which operation should this branch implement?
                   insert / select-all / select-by-id / update / delete"
4.1.1.3 类别列表
Category描述
INFRA初始项目设置,创建构建项目/构建脚本。
MAJOR INFRA重大更新,移除或添加简单配置或文件。
MEDIUM INFRA中等更新,移除或添加简单配置或文件。
MINOR INFRA轻微更新,移除或添加简单配置或文件。
PROVISIONS创建配置项目/脚本。
RELEASES发布软件所需的基础设施工作。
DATA创建数据模型(使用 EF 时还包括迁移)
MAJOR DATA更改现有数据模型,添加/修改 5 个或更多属性。
MEDIUM DATA更改现有数据模型,添加/修改 3-4 个属性。
MINOR DATA更改现有数据模型,添加/修改 1-2 个属性。
MIGRATION将数据从一个系统移动或转换到另一个系统、更新现有数据,或生成报告。
MAJOR MIGRATION涉及大量数据或复杂操作的重大数据迁移或转换任务。
MEDIUM MIGRATION涉及中等数据量或工作量的中等复杂度数据迁移或更新。
MINOR MIGRATION复杂度低或数据量小的轻微数据迁移或简单数据更新。
BROKERS创建封装外部库、资源、服务或 API 的代理时使用
MAJOR BROKERS对现有代理进行重大更改(功能有显著变化)。
MEDIUM BROKERS对现有代理进行中等更改(多项重要修改)。
MINOR BROKERS对现有代理进行轻微更改(简单修改)。
FOUNDATIONS创建基础服务时使用
MAJOR FOUNDATIONS更改现有基础服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM FOUNDATIONS更改现有基础服务,并编写或更新 3-4 个测试。
MINOR FOUNDATIONS更改现有基础服务,并编写或更新 1-2 个测试。
PROCESSINGS创建处理服务时使用
MAJOR PROCESSINGS更改现有处理服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM PROCESSINGS更改现有处理服务,并编写或更新 3-4 个测试。
MINOR PROCESSINGS更改现有处理服务,并编写或更新 1-2 个测试。
ORCHESTRATIONS创建编排服务时使用
MAJOR ORCHESTRATIONS更改现有编排服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM ORCHESTRATIONS更改现有编排服务,并编写或更新 3-4 个测试。
MINOR ORCHESTRATIONS更改现有编排服务,并编写或更新 1-2 个测试。
COORDINATIONS创建协调服务时使用
MAJOR COORDINATIONS更改现有协调服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM COORDINATIONS更改现有协调服务,并编写或更新 3-4 个测试。
MINOR COORDINATIONS更改现有协调服务,并编写或更新 1-2 个测试。
MANAGEMENTS创建管理服务时使用
MAJOR MANAGEMENTS更改现有管理服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM MANAGEMENTS更改现有管理服务,并编写或更新 3-4 个测试。
MINOR MANAGEMENTS更改现有管理服务,并编写或更新 1-2 个测试。
AGGREGATIONS创建聚合服务时使用
MAJOR AGGREGATIONS更改现有聚合服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM AGGREGATIONS更改现有聚合服务,并编写或更新 3-4 个测试。
MINOR AGGREGATIONS更改现有聚合服务,并编写或更新 1-2 个测试。
CONTROLLERS创建控制器时使用
MAJOR CONTROLLERS更改现有控制器,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM CONTROLLERS更改现有控制器,并编写或更新 3-4 个测试。
MINOR CONTROLLERS更改现有控制器,并编写或更新 1-2 个测试。
CLIENTS在其他人可使用的库中创建客户端时使用
MAJOR CLIENTS更改现有客户端,并编写或更新 5 个及以上测试。
MEDIUM CLIENTS更改现有客户端,并编写或更新 3-4 个测试。
MINOR CLIENTS更改现有客户端,并编写或更新 1-2 个测试。
PROVIDERS在其他人可使用的 SPAL provider 库中创建提供程序时使用
EXPOSERS创建其他类型的公开入口时使用,例如 Program.cs
MAJOR EXPOSERS
MEDIUM EXPOSERS
MINOR EXPOSERS
VIEWS创建视图服务时使用
MAJOR VIEWS更改现有视图,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM VIEWS更改现有视图,并编写或更新 3-4 个测试。
MINOR VIEWS更改现有视图,并编写或更新 1-2 个测试。
BASES创建前端基础组件时使用
MAJOR BASES
MEDIUM BASES
MINOR BASES
COMPONENTS创建组件时使用
MAJOR COMPONENTS更改现有组件,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM COMPONENTS更改现有组件,并编写或更新 3-4 个测试。
MINOR COMPONENTS更改现有组件,并编写或更新 1-2 个测试。
PAGES创建 Blazor 页面时使用
MAJOR PAGES
MEDIUM PAGES
MINOR PAGES
ACCEPTANCE编写验收测试时使用
MAJOR ACCEPTANCE
MEDIUM ACCEPTANCE
MINOR ACCEPTANCE
INTEGRATION编写集成测试时使用
MAJOR INTEGRATION
MEDIUM INTEGRATION
MINOR INTEGRATION
CODE RUB修复样式、代码格式或拼写问题的小改动(不用于修复 bug)
MAJOR CODE RUB影响多个文件的重大代码清理。
MEDIUM CODE RUB影响多个文件的中等程度代码清理。
MINOR CODE RUB影响少数文件的轻微代码清理。
MINOR FIX轻微 bug 修复/更改,不会显著改变程序的整体功能。
MEDIUM FIX对程序或系统的功能或性能产生中等影响的修复。
MAJOR FIX重大 bug 修复是指对软件程序或系统进行的重要修复或更正,用于解决关键或重大问题。
DOCUMENTATION常规文档
CONFIG任何配置更改,例如为不同环境设置 appsettings.json。
REVIEW根据项目标准和标准合规性审查已提交的工作。
STANDARD更新或引入 Standard 中的新内容时使用
DESIGN创建包含架构设计细节的文档(高层设计/低层设计)
MAJOR DESIGN设计 15 个及以上服务方法。
MEDIUM DESIGN设计 10-14 个服务方法。
MINOR DESIGN设计少于 10 个服务方法。
BUSINESS创建概述业务流程/标准操作规程的文档。
IMPORT从其他系统复制代码和测试,且不做更改或仅做少量更改(例如命名空间)。应包含导入的组件,格式:IMPORT: [COMPONENT]: [Description]
STATUS更新设计文档中的 STATUS 信息时使用。
PLANNING每项功能应进行一次规划,并涉及跨服务协作。个人工作和为自己进行的规划不算作规划。规划需要多位工程师参与,由一位负责人分配并分发团队任务。
MAJOR PLANNING规划 10 项及以上任务。
MEDIUM PLANNING规划 5 项及以上任务。
MINOR PLANNING规划少于 5 项任务。
MENTORSHIP60 分钟及以上的辅导会议。
MAJOR MENTORSHIP60 分钟及以上的辅导会议。
MEDIUM MENTORSHIP45 分钟的辅导会议。
MINOR MENTORSHIP30 分钟的辅导会议。
DISCUSSION以 DISCUSSION 为标题,围绕技术问题进行讨论会议时使用。
MAJOR DISCUSSION60 分钟及以上的讨论。
MEDIUM DISCUSSION45 分钟的讨论。
MINOR DISCUSSION30 分钟的讨论。
4.1.2 项目

Visual Studio 使用分层项目结构,让开发者能够以合乎逻辑且易于浏览的方式组织代码和资源。 最顶层是解决方案,它是一个或多个项目的容器。 项目则是构成应用程序的所有文件和资源的容器。

4.1.2.1 解决方案中的项目

典型的解决方案结构如下所示……

  |-- Taarafo.Core                              (API)
  |-- Taarafo.Core.Infrastructure               (Console App)
  |-- Taarafo.Core.Tests.Acceptance             (xUnit Test Project)
  |-- Taarafo.Core.Tests.Unit                   (xUnit Test Project)
4.1.2.1 项目结构

典型的项目文件夹结构如下所示……

Taarafo.Core
  |-- Brokers
        |-- DateTimes
        |-- Loggings
        |-- Storages
  |-- Models
        |-- Foundations
            |-- Posts
               |-- Exceptions
            |-- Comments
               |-- Exceptions
  |-- Migrations
  |-- Services
        |-- Foundations
            |-- Students
        |-- Processings
            |-- Students
        |-- Orchestrations
            |-- Students
  |-- Controllers

上述文件夹结构也可以沿用到测试项目中,以组织模型, 并按 Services\[Service Type]\[ServiceName] 对各项测试进行分组。

4.1.3 提交

本标准遵循 TDD(测试驱动开发)软件开发方法,强调先编写测试,再编写实际代码。 流程是先编写测试用例,运行测试并观察其失败,然后编写代码使测试通过。 这是一个迭代过程,有助于开发者专注于代码的需求、设计和实现。 使用 TDD 时,开发者会使用 xUnit 或 NUnit 等测试框架编写测试用例,并使用该框架运行测试和进行断言。 目标是实现较高的测试覆盖率,确保代码经过充分测试,并在开发过程中尽早发现任何错误或问题。 这种方法有助于确保代码易于维护、易于理解,并符合项目要求。

遵循 TDD 流程编写测试用例时,我们可以使用测试名称及其结果来提交工作。 编写测试并观察其失败后,可以将这部分工作提交为 [Test Name] -> FAIL,例如 ShouldAddPostAsync -> FAIL; 随后,将使测试通过的工作提交为 [Test Name] -> PASS,例如 ShouldAddPostAsync -> PASS。

如果你处理的是不需要测试的代码,即 DATA、BROKERS、CONTROLLERS,则采用与 Pull Request 相同的命名约定, 即使用类别和已完成工作的描述,格式为 [CATEGORY]: [Description Of Work Completed]。类别始终使用大写,描述使用 Pascal Case。 例如:DATA: Add Student Model、BROKERS: Insert Student 或 CONTROLLERS: POST Student(类别完整列表请参见上方的类别表)。

4.1.4 Pull Request

开发者完成工作后,可以向主仓库创建 Pull Request,让项目维护者知道有一项更新已准备好集成。 Pull Request(PR)的名称可采用以下格式:[CATEGORY]: [Description Of Work Completed]。类别始终使用大写,描述使用 Pascal Case。 例如:FOUNDATIONS: Add Student

PR 的评论部分也可以填写其他信息,描述已完成的工作,并提供对审批者有帮助或相关的内容。 例如,附上 CONTROLLER 操作按预期运行的截图,展示各种响应结果,如 201 - Created、400 - Bad Request 或 424 - Failed Dependency 等。

你还可以将 Pull Request 关联到某个 issue,以表明修复正在进行中,并在合并 Pull Request 或分支时自动关闭该 issue。只需在评论部分的任意位置添加一个 KEYWORD #ISSUE-NUMBER。 例如:Closes #10;如果 PR 涉及多项内容,则可以写成 Closes #10, closes #123。

如果你只想关联 issue,而不希望在合并时关闭它,可以省略关键词,只添加 #ISSUE-NUMBER,例如 #10。

4.1.5 配置

配置设置是决定软件应用行为的值。 它们可以包括数据库连接字符串和 API 密钥,也可以包括功能标志和日志记录级别。 使用配置设置,开发人员无需修改代码即可自定义应用的行为, 从而更轻松地部署和管理不同的环境。

在 .NET 应用中,一种常见的配置设置存储方式是使用 appsettings.json 文件。 该文件采用 JSON 格式,包含一组代表配置设置的键值对。 开发人员可以轻松修改这些设置,以改变应用的行为。

然而,并非所有配置设置都适合安全地存储在 appsettings.json 文件中。 敏感数据,例如 API 密钥、数据库密码,或任何可能导致未经授权访问应用或其资源的数据,都应保密。 将敏感数据存储在配置文件中,尤其是以纯文本格式存储,可能会危及应用的安全。

开发人员遵循安全编码实践至关重要,切勿将密码或其他敏感数据存储在配置提供程序代码或纯文本配置文件中。 此类敏感数据应存储在安全的位置,例如 Azure Key Vault,或部署环境中设置的环境变量中。此外, 也不建议将密码存储在本地设置文件中,因为这很容易导致密码被意外提交到代码仓库: 开发人员可能忘记将该文件排除在版本控制之外,也可能有人修改文件后无意中将其纳入提交, 从而危及应用的安全。

保护敏感数据的一种方法是使用用户机密。用户机密是 .NET 的一项功能,为开发人员在开发期间存储和检索敏感数据提供了 便捷方式。这些数据存储在开发人员的本地计算机上,不适用于生产环境。 用户机密有助于避免将敏感数据纳入源代码管理,并在开发期间轻松访问这些数据,但需要注意,它与 GitHub 工作流操作不兼容。 开发人员应考虑采用更安全的机密存储方式, 例如使用环境变量,或将机密存储在 GitHub Action Secrets 或 Azure Key Vault 等安全位置。 由于用户机密与 GitHub 构建流水线不直接兼容,因此我们不再进一步探讨此选项。

保护敏感数据的另一种方法是使用环境变量。 环境变量是在操作系统中设置的变量,应用可以在运行时访问它们。

同时使用 appsettings.json 和环境变量, 开发人员可以将敏感数据与其他配置设置分开, 从而更轻松地进行管理和保护。此外, 这种方法使开发人员能够在构建流水线中安全地存储配置设置, 确保敏感数据在整个开发生命周期中得到保护。

4.1.5.1 appsettings.json

如果 appsettings.json 和 appsettings.{Environment}.json 文件位于应用程序的根目录中,.NET 应用将在应用程序启动时自动加载这些文件,并将其注册到 IConfiguration 接口中。 这意味着,开发者可以通过 IConfiguration 对象访问 appsettings.json 文件中定义的键值对,从而在整个应用程序中轻松访问和使用配置设置。

值得注意的是,除了 appsettings.json 文件之外,.NET 还提供了其他配置提供程序,允许开发者从各种来源加载配置设置, 例如环境变量或命令行参数。 (开发者也可以根据需要创建自定义配置提供程序,从其他来源加载配置设置。)

配置源的读取顺序由其配置提供程序的指定顺序决定。 请在代码中对配置提供程序排序,以匹配应用程序所需的底层配置源优先级。

典型的配置提供程序顺序如下:

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. 用户机密
  4. 使用 Environment Variables 配置提供程序读取的环境变量。
  5. 使用 Command-line 配置提供程序读取的命令行参数。

下面来看一些代码示例,了解这一切是如何运作的。

4.1.5.1 应用程序设置

appsettings.json

{
  "MySettings": {
    "ApiUrl": "https://api.somesite.com/",    
    "ApiKey": "1ae4e397-ec3c-4ed7-8280-a17d0e2cbe78",
    "OrganisationId": "1bac6df0-cd68-4ce5-9c29-b2beb58201cd"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

有了上面的 appsettings.json 文件,我们就可以像这样加载变量:

    string apiUrl = configuration["MySettings:ApiUrl"];
    string apiKey = configuration["MySettings:ApiKey"];
    string organisationId = configuration["MySettings:OrganisationId"];
4.1.5.2 环境变量

我们可以通过以下方式为 Web 应用添加环境变量:

var builder = WebApplication.CreateBuilder(args);
...
builder.Configuration.AddEnvironmentVariables();
...
var app = builder.Build();

如果想在控制台应用或单元测试中试用,可以这样做:

var configurationBuilder = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
    .AddEnvironmentVariables("MYAPP_ACCEPTANCE_");

this.configuration = configurationBuilder.Build();

注意,我们定义了环境变量必须以其开头的前缀。
配置生成器会自动从环境变量名称中移除此​​前缀。
这是一个非常实用的功能,因为现在你可以为多个应用和/或环境存储同名环境变量。

到目前为止,如果获取配置项,我们仍会得到相同的值,因为我们尚未为任何环境变量设置值。

在 C# .NET 中,使用环境变量非常简单。
Environment 类提供了多种读取和设置环境变量的方法。
例如,要读取环境变量,可以使用 Environment.GetEnvironmentVariable 方法,并传入要获取的变量名称。
要设置环境变量,可以使用 Environment.SetEnvironmentVariable 方法,并提供变量名称和值。
你也可以通过命令行运行 SETX 命令来设置环境变量。

为了演示,我们会将 appsettings.json 中 MySettings:ApiUrl 的值保留下来。

接下来,我们将通过这行代码设置 MySettings:ApiKey 的值

Environment.SetEnvironmentVariable("MYSETTINGS:APIKEY", "3d4a1c55-fcd7-4b34-8536-99c8ae6ae33c");

对于 MySettings:OrganisationId,我们将通过具有管理员权限的控制台窗口使用命令行参数

setx MYSETTINGS:APIKEY "b2440ae9-cad2-4d70-b138-4a807abe1bb7"

注意 Visual Studio 启动时会预加载环境变量,并将其缓存,直到应用程序关闭。
与通过代码设置的环境变量不同,通过命令行设置的环境变量不会立即生效,这是因为存在预加载行为。
你需要关闭并重新打开 Visual Studio。

重新加载 Visual Studio 后,我们可以通过以下方式再次获取配置值:

    string apiUrl = configuration["MySettings:ApiUrl"];
    string apiKey = configuration["MySettings:ApiKey"];
    string organisationId = configuration["MySettings:OrganisationId"];

你会发现 ApiUrl 与之前相同,但 MySettings:ApiKey 和 MySettings:OrganisationId 的值现在已更改,且分别等于我们通过代码和命令行上的 SETX 为环境变量指定的值。

你也可以通过将值设为 null,以代码方式移除环境变量。 Environment.SetEnvironmentVariable("MYSETTINGS:APIKEY", null);

或者,也可以通过命令行执行

setx MYSETTINGS:APIKEY /delete

如果更喜欢使用 GUI,也可以前往 SYSTEM PROPERTES > ENVIRONMENT VARIABLES,在那里添加/移除环境变量。

4.1.5.3 GitHub Actions 工作流

要设置供 GitHub 使用的环境变量,我们需要设置仓库机密,并在工作流文件开头添加一个部分。

  1. 前往要使用这些设置的 GitHub 仓库,点击顶部导航栏中的“Settings”。

  2. 在左侧边栏中,点击“Secrets”,然后点击“New repository secret”按钮。

  3. 创建三个新机密,分别命名为“MYAPP_ACCEPTANCE_MYSETTINGS__APIKEY”和“MYAPP_ACCEPTANCE_MYSETTINGS__ORGANISATIONID”, 并为其分别设置给定配置中的“ApiUrl”、“ApiKey”和“OrganisationId”对应的值。

    注意

    • 我们为环境变量添加了前缀 MYAPP_ACCEPTANCE_,以匹配前面 .AddEnvironmentVariables("MYAPP_ACCEPTANCE_"); 的配置。
    • 另一个区别是,GitHub Secrets 不允许使用冒号(:)表示层级,因此必须改用双下划线(__)。
  4. 要将这些机密公开为 GitHub Action 工作流中的环境变量,请在工作流文件开头添加以下代码片段:

env:
  API_URL: ${{ secrets.MySettings__ApiUrl }}
  API_KEY: ${{ secrets.MySettings__ApiKey }}
  ORG_ID: ${{ secrets.MySettings__OrganisationId }

dotnet.yml 文件的完整示例如下:

name: MyApplication Build
on:
  push:
    branches:
    - main
  pull_request:
    branches:
    - main
jobs:
  build:
    runs-on: windows-latest
    env:
      ApiKey: ${{ secrets.MYAPP_ACCEPTANCE_MYSETTINGS__APIKEY }}
      OrgId: ${{ secrets.MYAPP_ACCEPTANCE_MYSETTINGS__ORGANISATIONID }}
    steps:
    - name: Pulling Code
      uses: actions/checkout@v2
    - name: Installing .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 7.0.201
        include-prerelease: false
    - name: Restoring Packages
      run: dotnet restore
    - name: Building Solution
      run: dotnet build --no-restore
    - name: Running Tests
      run: dotnet test --no-build --verbosity normal

4.2 衡量标准

本标准倡导公平对待所有人的理想。本标准认可,创新理念、卓越贡献和出色表现并非特定头衔者的专属。为了真正公平地衡量每个人的贡献,本标准为不同级别和类别的贡献设定了价值和积分。累积这些贡献后,贡献者的等级会逐步提升。

4.2.0 贡献积分

以下列出了所有类型的贡献及其对应价值:

Title Starts WithReturn Value
INFRA10
MAJOR INFRA10
MEDIUM INFRA3
MINOR INFRA1
DATA5
MAJOR DATA5
MEDIUM DATA3
MINOR DATA1
MIGRATION20
MAJOR MIGRATION20
MEDIUM MIGRATION10
MINOR MIGRATION5
BROKER5
MAJOR BROKER5
MEDIUM BROKER3
MINOR BROKER1
FOUNDATION10
MAJOR FOUNDATION10
MEDIUM FOUNDATION5
MINOR FOUNDATION1
PROCESSING15
MAJOR PROCESSING15
MEDIUM PROCESSING10
MINOR PROCESSING5
ORCHESTRATION20
MAJOR ORCHESTRATION20
MEDIUM ORCHESTRATION15
MINOR ORCHESTRATION10
COORDINATION20
MAJOR COORDINATION20
MEDIUM COORDINATION15
MINOR COORDINATION5
MANAGEMENT20
MAJOR MANAGEMENT20
MEDIUM MANAGEMENT15
MINOR MANAGEMENT5
AGGREGATION10
MAJOR AGGREGATION10
MEDIUM AGGREGATION5
MINOR AGGREGATION1
CONTROLLER5
MAJOR CONTROLLER5
MEDIUM CONTROLLER3
MINOR CONTROLLER1
ACCEPTANCE10
MAJOR ACCEPTANCE10
MEDIUM ACCEPTANCE5
MINOR ACCEPTANCE3
INTEGRATION15
MAJOR INTEGRATION15
MEDIUM INTEGRATION10
MINOR INTEGRATION10
VIEW10
MAJOR VIEW10
MEDIUM VIEW5
MINOR VIEW1
BASE5
MAJOR BASE5
MEDIUM BASE3
MINOR BASE1
COMPONENT15
MAJOR COMPONENT15
MEDIUM COMPONENT10
MINOR COMPONENT5
PAGE5
MAJOR PAGE5
MEDIUM PAGE3
MINOR PAGE1
CLIENT5
MAJOR CLIENT5
MEDIUM CLIENT3
MINOR CLIENT1
EXPOSER5
MAJOR EXPOSER5
MEDIUM EXPOSER3
MINOR EXPOSER1
DESIGN20
MAJOR DESIGN20
MEDIUM DESIGN10
MINOR DESIGN5
MAJOR FIX20
MEDIUM FIX10
MINOR FIX5
PLANNING15
MAJOR PLANNING15
MINOR PLANNING10
MINIOR PLANNING5
MENTORSHIP20
MAJOR MENTORSHIP20
MINOR MENTORSHIP15
MINIOR MENTORSHIP10
DISCUSSION15
MAJOR DISCUSSION15
MINOR DISCUSSION10
MINIOR DISCUSSION5
MAJOR CODE RUB10
MEDIUM CODE RUB5
MINOR CODE RUB1
CODE RUB1
PROVISION10
IMPORT5
RELEASE10
CONFIG5
REVIEW1
DOCUMENTATION1
STANDARD100
BUSINES50
STATUS1
UNKNOWN0

这些类别已在上一节中定义。

4.2.1 平均实现时间

下表列出了在 The Standard 架构中实现不同层或组件所需的平均估算时间。
这些时间基于实践经验,可作为规划和工作量估算的一般参考。

层/组件平均时间
Brokers,Base约 1 小时
Foundations,Components约 3 小时
Processing,Orchestration,Coordination,Orchestration Components约 5 小时
Management,Uber Manager约 3 小时
Controllers,Pages,Clients约 1 小时

这些估算表示单个服务或组件的典型实现时长,假设复杂度一般且没有外部依赖。

4.2.2 级别

以下级别根据对 The Standard 社区和符合 The Standard 规范的项目的终身累计贡献确定:

职位分数
软件工程师 I10,000
软件工程师 II25,000
高级软件工程师50,000
首席工程师100,000
合伙人/总监300,000
副总裁500,000
杰出贡献者1,000,000
The Standard 的旗手1M + 委派

Implementation-profile 实践补充

12. 实践

为代码贡献、分支、提交策略和项目结构制定实践规范,对任何软件开发项目都至关重要。
这些规范为管理代码库提供了清晰、一致的方法,确保贡献以受控、有序的方式进行。
这有助于避免混乱和冲突,并确保代码库保持稳定且易于维护。
此外,完善的代码贡献和项目结构规范有助于改善开发团队内部的协作与沟通,让变更更容易跟踪和审查,也更便于识别和解决问题。
总而言之,为代码贡献、分支和提交策略以及项目结构制定明确的实践规范,是任何成功软件开发项目的重要组成部分。

制定实践规范时需考虑以下主要方面:

  1. 代码贡献
    1. Fork、克隆与分支
    2. 项目结构
    3. 提交
    4. Pull Request

The Standard 团队需要清楚地理解并定义上述每一点的方方面面。

12.1 代码贡献

为任何开源或协作式软件开发项目制定贡献指南都至关重要。
它为贡献者如何提交和审查变更确立了明确的规则和预期,有助于确保所有贡献都以一致、有序的方式完成。
此外,贡献指南还可以提供有关编码、测试和文档最佳实践的指导,有助于提升代码库的整体质量。
它也能作为面向新贡献者的学习工具,为他们提供有效参与项目所需的信息和说明。
(此外,完善的 GitHub 贡献指南有助于吸引新的贡献者,并维护健康的开源社区。)

12.1.1 分叉和分支策略

代码分支策略对于维护稳定且易于维护的代码库至关重要。 它允许多名开发者同时处理不同的功能或错误修复,而不会相互干扰。 每位开发者都可以创建自己的分支进行开发,经过审查和批准后,再将其合并到主分支。 这有助于避免冲突,并确保代码库保持稳定且一致。 此外,分支策略支持版本控制,还可以创建和跟踪代码库的不同版本。 这在必要时回滚更改,以及为不同环境维护软件的多个版本时会很有用。 总而言之,分支策略是任何软件开发项目的关键环节,对于确保代码库保持稳定且易于维护至关重要。

软件开发中可以采用多种不同的分支策略,包括:

  1. Gitflow:一种流行的分支策略,遵循严格的分支模型:开发在功能分支中进行,并合并到主开发分支。这种策略适用于贡献者众多的大型项目。

  2. 主干开发:这种策略是在主分支(即主干)上工作,并直接向其提交更改。这种策略适用于贡献者较少的小型项目。

  3. 功能分支:这种策略是为每项功能或错误修复创建一个单独的分支,并在完成后将其合并到主分支。这种策略适用于有多名贡献者的大型项目。

  4. 分叉:这种策略是创建代码库的副本,并在其中独立开发。这适用于多名贡献者共同开发同一代码库的开源项目。分叉工作流的主要优势是,无需所有人都向单一中央代码库推送,就可以集成贡献。开发者将更改推送到自己的服务端代码库,只有项目维护者才能向官方代码库推送。这样,维护者无需向开发者授予官方代码库的写入权限,也能接收他们提交的内容。

  5. 发布分支:这种策略是为每个发布版本创建一个单独的分支,并在准备好发布时将其合并到主分支。这种策略适用于定期发布的项目。

  6. 持续集成:这种策略是在代码更改完成后立即合并,并运行自动化测试,以确保代码库保持稳定。这种策略适用于更改频率较高的项目。

最终,重要的是选择一种符合项目需求和限制、且所有贡献者都能轻松理解并遵循的分支策略。

12.1.1.1 开源开发

由于 The Standard 推崇开源工作,我们来快速了解一下 Forking 策略。

工作原理

Forking 工作流始于存储在服务器上的官方公开仓库。新开发者想要开始参与项目时,不会直接克隆官方仓库。

相反,他们会 Fork 官方仓库并创建一个副本。这个新副本就是他们个人的公开仓库。
创建服务器端副本后,开发者会执行 git clone,将其副本克隆到本地计算机上。 这与其他工作流一样,构成了他们的私有开发环境。

准备好发布本地提交时,他们会将提交推送到自己的公开仓库(而非官方仓库)。 随后,他们会向主仓库提交拉取请求,让项目维护者知道有更新可以集成。 之后可以审查拉取请求;如果贡献的代码存在问题,它也可以作为便捷的讨论串。

以下是此工作流的分步示例:

  1. 开发者 Fork 一个“官方”服务器端仓库,从而创建自己的服务器端副本。
  2. 将新的服务器端副本克隆到本地系统。
  3. 创建一个新的本地功能分支。
  4. 开发者在新分支上进行更改。
  5. 为这些更改创建新的提交。
  6. 将该分支推送到开发者自己的服务器端副本。
  7. 开发者从新分支向“官方”仓库发起拉取请求。
  8. 审查拉取请求,并验证构建是否成功以及测试是否通过。此时,维护者可以要求进行更改,也可以批准合并;获批后,这些更改便会合并到原始服务器端仓库中。
12.1.1.2 分支名称约定

分支名称可以采用以下命名约定:users/[username]/[category]-[entity]-[action]

变量可以替换为:

  • [username] => 你的 github 用户名
  • [category] => 你正在处理的类别
  • [entity] => 你的服务 / broker 使用的实体
  • [action] => 操作
12.1.1.3 类别列表
Category描述
INFRA初始项目设置,创建构建项目/构建脚本。
MAJOR INFRA重大更新,移除或添加简单配置或文件。
MEDIUM INFRA中等更新,移除或添加简单配置或文件。
MINOR INFRA轻微更新,移除或添加简单配置或文件。
PROVISIONS创建配置项目/脚本。
RELEASES发布软件所需的基础设施工作。
DATA创建数据模型(使用 EF 时还包括迁移)
MAJOR DATA更改现有数据模型,添加/修改 5 个或更多属性。
MEDIUM DATA更改现有数据模型,添加/修改 3-4 个属性。
MINOR DATA更改现有数据模型,添加/修改 1-2 个属性。
MIGRATION将数据从一个系统移动或转换到另一个系统、更新现有数据,或生成报告。
MAJOR MIGRATION涉及大量数据或复杂操作的重大数据迁移或转换任务。
MEDIUM MIGRATION涉及中等数据量或工作量的中等复杂度数据迁移或更新。
MINOR MIGRATION复杂度低或数据量小的轻微数据迁移或简单数据更新。
BROKERS创建封装外部库、资源、服务或 API 的代理时使用
MAJOR BROKERS对现有代理进行重大更改(功能有显著变化)。
MEDIUM BROKERS对现有代理进行中等更改(多项重要修改)。
MINOR BROKERS对现有代理进行轻微更改(简单修改)。
FOUNDATIONS创建基础服务时使用
MAJOR FOUNDATIONS更改现有基础服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM FOUNDATIONS更改现有基础服务,并编写或更新 3-4 个测试。
MINOR FOUNDATIONS更改现有基础服务,并编写或更新 1-2 个测试。
PROCESSINGS创建处理服务时使用
MAJOR PROCESSINGS更改现有处理服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM PROCESSINGS更改现有处理服务,并编写或更新 3-4 个测试。
MINOR PROCESSINGS更改现有处理服务,并编写或更新 1-2 个测试。
ORCHESTRATIONS创建编排服务时使用
MAJOR ORCHESTRATIONS更改现有编排服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM ORCHESTRATIONS更改现有编排服务,并编写或更新 3-4 个测试。
MINOR ORCHESTRATIONS更改现有编排服务,并编写或更新 1-2 个测试。
COORDINATIONS创建协调服务时使用
MAJOR COORDINATIONS更改现有协调服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM COORDINATIONS更改现有协调服务,并编写或更新 3-4 个测试。
MINOR COORDINATIONS更改现有协调服务,并编写或更新 1-2 个测试。
MANAGEMENTS创建管理服务时使用
MAJOR MANAGEMENTS更改现有管理服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM MANAGEMENTS更改现有管理服务,并编写或更新 3-4 个测试。
MINOR MANAGEMENTS更改现有管理服务,并编写或更新 1-2 个测试。
AGGREGATIONS创建聚合服务时使用
MAJOR AGGREGATIONS更改现有聚合服务,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM AGGREGATIONS更改现有聚合服务,并编写或更新 3-4 个测试。
MINOR AGGREGATIONS更改现有聚合服务,并编写或更新 1-2 个测试。
CONTROLLERS创建控制器时使用
MAJOR CONTROLLERS更改现有控制器,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM CONTROLLERS更改现有控制器,并编写或更新 3-4 个测试。
MINOR CONTROLLERS更改现有控制器,并编写或更新 1-2 个测试。
CLIENTS在其他人可使用的库中创建客户端时使用
MAJOR CLIENTS更改现有客户端,并编写或更新 5 个及以上测试。
MEDIUM CLIENTS更改现有客户端,并编写或更新 3-4 个测试。
MINOR CLIENTS更改现有客户端,并编写或更新 1-2 个测试。
PROVIDERS在其他人可使用的 SPAL provider 库中创建提供程序时使用
EXPOSERS创建其他类型的公开入口时使用,例如 Program.cs
MAJOR EXPOSERS
MEDIUM EXPOSERS
MINOR EXPOSERS
VIEWS创建视图服务时使用
MAJOR VIEWS更改现有视图,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM VIEWS更改现有视图,并编写或更新 3-4 个测试。
MINOR VIEWS更改现有视图,并编写或更新 1-2 个测试。
BASES创建前端基础组件时使用
MAJOR BASES
MEDIUM BASES
MINOR BASES
COMPONENTS创建组件时使用
MAJOR COMPONENTS更改现有组件,并编写或更新全部测试,或 5 个及以上测试。
MEDIUM COMPONENTS更改现有组件,并编写或更新 3-4 个测试。
MINOR COMPONENTS更改现有组件,并编写或更新 1-2 个测试。
PAGES创建 Blazor 页面时使用
MAJOR PAGES
MEDIUM PAGES
MINOR PAGES
ACCEPTANCE编写验收测试时使用
MAJOR ACCEPTANCE
MEDIUM ACCEPTANCE
MINOR ACCEPTANCE
INTEGRATION编写集成测试时使用
MAJOR INTEGRATION
MEDIUM INTEGRATION
MINOR INTEGRATION
CODE RUB修复样式、代码格式或拼写问题的小改动(不用于修复 bug)
MAJOR CODE RUB影响多个文件的重大代码清理。
MEDIUM CODE RUB影响多个文件的中等程度代码清理。
MINOR CODE RUB影响少数文件的轻微代码清理。
MINOR FIX轻微 bug 修复/更改,不会显著改变程序的整体功能。
MEDIUM FIX对程序或系统的功能或性能产生中等影响的修复。
MAJOR FIX重大 bug 修复是指对软件程序或系统进行的重要修复或更正,用于解决关键或重大问题。
DOCUMENTATION常规文档
CONFIG任何配置更改,例如为不同环境设置 appsettings.json。
REVIEW根据项目标准和标准合规性审查已提交的工作。
STANDARD更新或引入 Standard 中的新内容时使用
DESIGN创建包含架构设计细节的文档(高层设计/低层设计)
MAJOR DESIGN设计 15 个及以上服务方法。
MEDIUM DESIGN设计 10-14 个服务方法。
MINOR DESIGN设计少于 10 个服务方法。
BUSINESS创建概述业务流程/标准操作规程的文档。
IMPORT从其他系统复制代码和测试,且不做更改或仅做少量更改(例如命名空间)。应包含导入的组件,格式:IMPORT: [COMPONENT]: [Description]
STATUS更新设计文档中的 STATUS 信息时使用。
PLANNING每项功能应进行一次规划,并涉及跨服务协作。个人工作和为自己进行的规划不算作规划。规划需要多位工程师参与,由一位负责人分配并分发团队任务。
MAJOR PLANNING规划 10 项及以上任务。
MEDIUM PLANNING规划 5 项及以上任务。
MINOR PLANNING规划少于 5 项任务。
MENTORSHIP60 分钟及以上的辅导会议。
MAJOR MENTORSHIP60 分钟及以上的辅导会议。
MEDIUM MENTORSHIP45 分钟的辅导会议。
MINOR MENTORSHIP30 分钟的辅导会议。
DISCUSSION以 DISCUSSION 为标题,围绕技术问题进行讨论会议时使用。
MAJOR DISCUSSION60 分钟及以上的讨论。
MEDIUM DISCUSSION45 分钟的讨论。
MINOR DISCUSSION30 分钟的讨论。
12.1.2 项目

Visual Studio 采用分层项目结构,让开发者能够以合乎逻辑且易于浏览的方式组织代码和资源。 顶层是解决方案,它是一个或多个项目的容器。 项目是构成应用程序的所有文件和资源的容器。

12.1.2.1 解决方案中的项目

典型的解决方案结构如下所示……

  |-- Taarafo.Core                     (API)
  |-- Taarafo.Core.Infrastructure      (Console App)
  |-- Taarafo.Core.Tests.Acceptance    (xUnit Test Project)
  |-- Taarafo.Core.Tests.Unit          (xUnit Test Project)

12.1.2.1 项目结构

典型的项目文件夹结构如下所示……

Taarafo.Core
  |-- Brokers
        |-- DateTimes
        |-- Loggings
        |-- Storages
  |-- Models
        |-- Foundations
            |-- Posts
               |-- Exceptions
            |-- Comments
               |-- Exceptions
  |-- Migrations
  |-- Services
        |-- Foundations
            |-- Students
        |-- Processings
            |-- Students
        |-- Orchestrations
            |-- Students
  |-- Controllers

上述文件夹结构也可以应用于测试项目,以便组织模型, 并按照 Services\[Service Type]\[ServiceName] 对各种测试进行分组。

12.1.3 提交

Standard 遵循 TDD(测试驱动开发)软件开发方法,强调先编写测试,再编写实际代码。 这一过程包括编写测试用例、运行测试并观察其失败,然后编写代码使测试通过。 这是一个迭代过程,可帮助开发者专注于代码的需求、设计和实现。 使用 TDD 时,开发者会借助 xUnit 或 NUnit 等测试框架编写测试用例,并使用该框架运行测试并断言测试结果。 目标是实现较高的测试覆盖率,确保代码经过充分测试,并尽早发现开发过程中的错误或问题。 这种方法有助于确保代码易于维护、易于理解,并满足项目需求。

遵循 TDD 流程编写测试用例时,我们可以使用测试名称及其结果来提交工作。 编写测试并观察其失败的工作可提交为 [Test Name] -> FAIL,例如 ShouldAddPostAsync -> FAIL, 随后,使测试通过的工作可提交为 [Test Name] -> PASS,例如 ShouldAddPostAsync -> PASS。

12.1.3.1 FAIL/PASS 提交规范

每个 TDD 周期恰好产生 两个 提交:

  1. FAIL 提交 — 包含新测试(以及编译所需的任何新异常模型文件),但不包含任何能使测试通过的实现代码。
  2. PASS 提交 — 仅包含使之前失败的测试通过的实现代码(例如 catch 块、辅助方法、验证逻辑)。

关键规则: 创建 FAIL 提交前,必须通过测试运行器执行测试,并确认测试确实失败。无法运行、无法编译或通过的测试,都不是有效的 FAIL。类似地,创建 PASS 提交前,必须执行所有测试,并确认它们全部通过,而不只是新测试。

TDD 周期如下:

1. Write the test                    → build → run test → verify FAIL → commit "[TestName] -> FAIL"
2. Write the minimum implementation  → build → run ALL tests → verify PASS → commit "[TestName] -> PASS"
3. Repeat for the next test
12.1.3.2 各类提交包含的内容
提交类型包含不包含
FAIL新测试方法、测试编译所需的新异常模型类、新 using 指令服务中的实现(catch 块、验证逻辑、辅助方法)
PASS服务中的实现代码(catch 块、辅助方法、验证逻辑)新测试(这些应放在下一个 FAIL 提交中)
12.1.3.3 Foundation Service 的 TDD 提交顺序

以下是实现 Add{Entity}Async 方法时 FAIL/PASS 提交对的确切顺序:

 1. ShouldAdd{Entity}Async                                                              -> FAIL
 2. ShouldAdd{Entity}Async                                                              -> PASS
 3. ShouldThrowValidationExceptionOnAddIf{Entity}IsNullAndLogItAsync                    -> FAIL
 4. ShouldThrowValidationExceptionOnAddIf{Entity}IsNullAndLogItAsync                    -> PASS
 5. ShouldThrowValidationExceptionOnAddIf{Entity}IsInvalidAndLogItAsync                 -> FAIL
 6. ShouldThrowValidationExceptionOnAddIf{Entity}IsInvalidAndLogItAsync                 -> PASS
 7. ShouldThrowDependencyValidationExceptionOnAddIfBadRequestErrorOccursAndLogItAsync    -> FAIL
 8. ShouldThrowDependencyValidationExceptionOnAddIfBadRequestErrorOccursAndLogItAsync    -> PASS
 9. ShouldThrowDependencyValidationExceptionOnAddIfConflictErrorOccursAndLogItAsync      -> FAIL
10. ShouldThrowDependencyValidationExceptionOnAddIfConflictErrorOccursAndLogItAsync      -> PASS
11. ShouldThrowCriticalDependencyExceptionOnAddIfUnauthorizedErrorOccursAndLogItAsync    -> FAIL
12. ShouldThrowCriticalDependencyExceptionOnAddIfUnauthorizedErrorOccursAndLogItAsync    -> PASS
13. ShouldThrowCriticalDependencyExceptionOnAddIfForbiddenErrorOccursAndLogItAsync       -> FAIL
14. ShouldThrowCriticalDependencyExceptionOnAddIfForbiddenErrorOccursAndLogItAsync       -> PASS
15. ShouldThrowCriticalDependencyExceptionOnAddIfNotFoundErrorOccursAndLogItAsync        -> FAIL
16. ShouldThrowCriticalDependencyExceptionOnAddIfNotFoundErrorOccursAndLogItAsync        -> PASS
17. ShouldThrowCriticalDependencyExceptionOnAddIfUrlNotFoundErrorOccursAndLogItAsync     -> FAIL
18. ShouldThrowCriticalDependencyExceptionOnAddIfUrlNotFoundErrorOccursAndLogItAsync     -> PASS
19. ShouldThrowDependencyExceptionOnAddIfInternalServerErrorOccursAndLogItAsync          -> FAIL
20. ShouldThrowDependencyExceptionOnAddIfInternalServerErrorOccursAndLogItAsync          -> PASS
21. ShouldThrowDependencyExceptionOnAddIfServiceUnavailableErrorOccursAndLogItAsync      -> FAIL
22. ShouldThrowDependencyExceptionOnAddIfServiceUnavailableErrorOccursAndLogItAsync      -> PASS
23. ShouldThrowCriticalDependencyExceptionOnAddIfHttpRequestErrorOccursAndLogItAsync     -> FAIL
24. ShouldThrowCriticalDependencyExceptionOnAddIfHttpRequestErrorOccursAndLogItAsync     -> PASS
25. ShouldThrowServiceExceptionOnAddIfServiceErrorOccursAndLogItAsync                    -> FAIL
26. ShouldThrowServiceExceptionOnAddIfServiceErrorOccursAndLogItAsync                    -> PASS

所有测试通过后,最后提交配置,将服务注册到 Program.cs:

27. CONFIGURATIONS: Register I{Entity}Service in Program.cs

对于基于存储的服务,第 7–24 个提交将替换为相应的 SQL/EF 异常测试 (DuplicateKeyException、DbUpdateException、SqlException 等),并遵循相同的 FAIL/PASS 模式。

12.1.3.4 非测试提交

如果你处理的是不需要测试的代码,即 DATA、BROKERS、CONTROLLERS,那么我们会采用与拉取请求相同的命名约定,使用类别和对已完成工作的描述,语法为 [CATEGORY]: [Description Of Work Completed],其中类别始终使用大写字母,描述使用 Pascal Case 例如:DATA: Add Student Model 或 BROKERS: Insert Student 或 CONTROLLERS: POST Student(完整类别列表请参见上方的类别表)

12.1.4 拉取请求

开发者完成工作后,可以向主代码库创建拉取请求,通知项目维护者有更新可供集成。 拉取请求(PR)的名称可以使用以下语法:[CATEGORY]: [Description Of Work Completed],其中类别始终使用大写字母,描述使用 Pascal Case 例如:FOUNDATIONS: Add Student

PR 的评论区也可以填写有关已完成工作的其他信息,供审批者参考。 例如:展示 CONTROLLER 操作按预期运行情况的屏幕截图,并显示各种响应结果,例如 201 - Created、400 - Bad Request 或 424 - Failed Dependency 等。

你还可以将拉取请求关联到某个问题,以表明修复正在进行中,并在拉取请求或分支合并时自动关闭该问题;只需在评论区任意位置添加一个 KEYWORD #ISSUE-NUMBER。 例如:Closes #10;如果 PR 涉及多个事项,则可以写 Closes #10, closes #123

如果你只想关联问题,而不希望在合并时关闭它,可以省略关键词,只添加 #ISSUE-NUMBER,例如:#10

12.1.5 配置

配置设置是用于决定软件应用行为的值。 它们可以包含各种内容,例如数据库连接字符串和 API 密钥、功能开关和日志级别。 开发者可以通过使用配置设置,在不修改代码的情况下自定义应用的行为, 从而更轻松地部署和管理不同的环境。

在 .NET 应用中,常见的配置设置存储方式是使用 appsettings.json 文件。 这是一个 JSON 格式的文件,其中包含一组表示配置设置的键值对。 开发者可以轻松修改这些设置,以改变应用的行为。

然而,并非所有配置设置都适合安全地存储在 appsettings.json 文件中。 敏感数据(例如 API 密钥、数据库密码,或任何可能授予未经授权者访问应用或其资源权限的数据)都应该保密。 将敏感数据存储在配置文件中,尤其是以纯文本格式存储,可能会危及应用的安全。

开发者遵循安全编码实践至关重要,绝不要将密码或其他敏感数据存储在配置提供程序代码或纯文本配置文件中。 此类敏感数据应存储在 Azure Key Vault 等安全位置,或部署环境中设置的环境变量中。 同样不建议将密码存储在本地设置文件中,因为这很容易导致密码被意外提交到代码仓库:开发者可能忘记将文件排除在版本控制之外,也可能有人修改了文件后不慎将其纳入提交,从而危及应用的安全。

保护敏感数据的一种方法是使用用户机密。用户机密是 .NET 中的一项功能,为开发者在开发期间存储和检索敏感数据提供了便利。 这些数据存储在开发者本地计算机上,不用于生产环境。 用户机密有助于避免将敏感数据纳入源代码管理,并在开发期间轻松访问这些数据,但需要注意,它与 GitHub 工作流操作不兼容。 因此,开发者应考虑使用更安全的机密存储方式,例如环境变量,或将机密存储在 GitHub Action Secrets 或 Azure Key Vault 等安全位置。 由于用户机密与 GitHub 构建流水线不直接兼容,我们不会进一步探讨这一选项。

保护敏感数据的另一种方法是使用环境变量。 环境变量是在操作系统中设置的变量,应用可以在运行时访问它们。

同时使用 appsettings.json 和环境变量, 开发者可以将敏感数据与其他配置设置分开, 从而更轻松地管理并保护这些数据。此外, 这种方法使开发者能够在构建流水线中安全地存储配置设置, 确保敏感数据在整个开发生命周期中受到保护。

12.1.5.1 appsettings.json

如果文件位于应用程序的根目录中,.NET 应用程序会在启动期间自动加载 appsettings.json 和 appsettings.{Environment}.json,并将其注册到 IConfiguration 接口中。 这意味着,开发者可以通过 IConfiguration 对象访问 appsettings.json 文件中定义的键值对,从而轻松地在整个应用程序中访问和使用配置设置。

值得注意的是,除了 appsettings.json 文件之外,.NET 还提供了其他配置提供程序,允许开发者从各种来源加载配置设置, 例如环境变量或命令行参数。 (如果需要,开发者也可以创建自己的自定义配置提供程序,从其他来源加载配置设置。)

配置源按照其配置提供程序的指定顺序读取。 请在代码中排列配置提供程序的顺序,以满足应用程序对底层配置源的优先级要求。

典型的配置提供程序顺序如下:

  1. appsettings.json
  2. appsettings.{Environment}.json
  3. 用户机密
  4. 使用 Environment Variables 配置提供程序读取的环境变量。
  5. 使用 Command-line 配置提供程序读取的命令行参数。

下面来看一些代码示例,了解这一切的工作方式。

12.1.5.1 应用程序设置

appsettings.json

{
  "MySettings": {
    "ApiUrl": "https://api.somesite.com/",    
    "ApiKey": "1ae4e397-ec3c-4ed7-8280-a17d0e2cbe78",
    "OrganisationId": "1bac6df0-cd68-4ce5-9c29-b2beb58201cd"
  },
  "Logging": {
    "LogLevel": {
      "Default": "Information",
      "Microsoft": "Warning",
      "Microsoft.Hosting.Lifetime": "Information"
    }
  },
  "AllowedHosts": "*"
}

使用上述 appsettings.json 文件,我们可以这样加载变量:

    string apiUrl = configuration["MySettings:ApiUrl"];
    string apiKey = configuration["MySettings:ApiKey"];
    string organisationId = configuration["MySettings:OrganisationId"];

12.1.5.2 环境变量

我们可以通过以下方式向 Web 应用程序添加环境变量:

var builder = WebApplication.CreateBuilder(args);
...
builder.Configuration.AddEnvironmentVariables();
...
var app = builder.Build();

如果想在控制台应用程序或单元测试中尝试,可以这样做:

var configurationBuilder = new ConfigurationBuilder()
    .AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
    .AddEnvironmentVariables("MYAPP_ACCEPTANCE_");

this.configuration = configurationBuilder.Build();

注意,我们定义了一个前缀,环境变量必须以该前缀开头。
配置生成器会自动从环境变量名称中移除这个前缀。
这是一个非常实用的功能,这样一来,你就可以为多个应用程序和/或环境存储同名的环境变量。

到目前为止,如果我们获取配置项,仍会得到相同的值,因为我们尚未设置任何环境变量的值。

在 C# .NET 中,使用环境变量非常简单。 Environment 类提供了多种读取和设置环境变量的方法。 例如,要读取环境变量,可以使用 Environment.GetEnvironmentVariable 方法,并传入要获取的变量名称。 要设置环境变量,可以使用 Environment.SetEnvironmentVariable 方法,并提供变量名称和值。 你也可以通过命令行运行 SETX 命令来设置环境变量。

为了演示,我们将保留 appsettings.json 中 MySettings:ApiUrl 的值。

接下来,我们将通过这行代码设置 MySettings:ApiKey 的值:

Environment.SetEnvironmentVariable("MYSETTINGS:APIKEY", "3d4a1c55-fcd7-4b34-8536-99c8ae6ae33c");

对于 MySettings:OrganisationId,我们将通过具有管理员权限的控制台窗口使用命令行参数:

setx MYSETTINGS:APIKEY "b2440ae9-cad2-4d70-b138-4a807abe1bb7"

注意 Visual Studio 启动时会预加载环境变量,并将其缓存,直到应用程序关闭。
与通过代码设置的环境变量不同,通过命令行设置的环境变量不会立即可用,这是由于预加载行为导致的。
你需要关闭并重新打开 Visual Studio。

重新加载 Visual Studio 后,我们可以通过以下方式再次从配置中获取值:

    string apiUrl = configuration["MySettings:ApiUrl"];
    string apiKey = configuration["MySettings:ApiKey"];
    string organisationId = configuration["MySettings:OrganisationId"];

你会发现 ApiUrl 与之前相同,但 MySettings:ApiKey 和 MySettings:OrganisationId 的值现已改变,并且与我们通过代码和命令行中的 SETX 指定的环境变量值一致。

你也可以在代码中将环境变量的值设为 null 来移除它。 Environment.SetEnvironmentVariable("MYSETTINGS:APIKEY", null);

或者,也可以通过命令行执行:

setx MYSETTINGS:APIKEY /delete

如果你更喜欢使用 GUI,也可以前往 SYSTEM PROPERTES > ENVIRONMENT VARIABLES,在那里添加或移除环境变量。

12.1.5.3 GitHub Actions 工作流

要设置在 GitHub 中使用的环境变量,我们需要设置仓库机密,并在工作流文件开头添加一个部分。

  1. 前往要使用这些设置的 GitHub 仓库,然后点击顶部导航栏中的“Settings”。

  2. 在左侧边栏中,点击“Secrets”,然后点击“New repository secret”按钮。

  3. 创建三个新的机密,名称分别为“MYAPP_ACCEPTANCE_MYSETTINGS__APIKEY”和“MYAPP_ACCEPTANCE_MYSETTINGS__ORGANISATIONID”, 并分别使用给定设置中“ApiUrl”、“ApiKey”和“OrganisationId”对应的值。

    注意

    • 我们为环境变量添加了前缀 MYAPP_ACCEPTANCE_,以匹配之前的配置 .AddEnvironmentVariables("MYAPP_ACCEPTANCE_");。
    • 另一个区别是,GitHub Secrets 不允许使用冒号 (:) 表示层级,因此必须使用双下划线 (__)。
  4. 要将这些机密作为环境变量提供给 GitHub Action 工作流,请在工作流文件开头添加以下代码片段:

env:
  API_URL: ${{ secrets.MySettings__ApiUrl }}
  API_KEY: ${{ secrets.MySettings__ApiKey }}
  ORG_ID: ${{ secrets.MySettings__OrganisationId }

完整的 dotnet.yml 文件示例如下:

name: MyApplication Build
on:
  push:
    branches:
    - main
  pull_request:
    branches:
    - main
jobs:
  build:
    runs-on: windows-latest
    env:
      ApiKey: ${{ secrets.MYAPP_ACCEPTANCE_MYSETTINGS__APIKEY }}
      OrgId: ${{ secrets.MYAPP_ACCEPTANCE_MYSETTINGS__ORGANISATIONID }}
    steps:
    - name: Pulling Code
      uses: actions/checkout@v2
    - name: Installing .NET
      uses: actions/setup-dotnet@v1
      with:
        dotnet-version: 7.0.201
        include-prerelease: false
    - name: Restoring Packages
      run: dotnet restore
    - name: Building Solution
      run: dotnet build --no-restore
    - name: Running Tests
      run: dotnet test --no-build --verbosity normal

12.2 衡量标准

该标准倡导公平对待所有人的理想。该标准认可,创新理念、卓越贡献和出色表现并非某些特定头衔人士的专属。为了真正公平地衡量每个人的贡献,该标准为不同级别和类别的贡献设定了价值和分值。贡献分值的累积会让贡献者从一个级别晋升到下一个级别。

12.2.0 贡献分值

以下列出了所有类型的贡献及其对应的价值:

Title Starts WithReturn Value
INFRA10
MAJOR INFRA10
MEDIUM INFRA3
MINOR INFRA1
DATA5
MAJOR DATA5
MEDIUM DATA3
MINOR DATA1
MIGRATION20
MAJOR MIGRATION20
MEDIUM MIGRATION10
MINOR MIGRATION5
BROKER5
MAJOR BROKER5
MEDIUM BROKER3
MINOR BROKER1
FOUNDATION10
MAJOR FOUNDATION10
MEDIUM FOUNDATION5
MINOR FOUNDATION1
PROCESSING15
MAJOR PROCESSING15
MEDIUM PROCESSING10
MINOR PROCESSING5
ORCHESTRATION20
MAJOR ORCHESTRATION20
MEDIUM ORCHESTRATION15
MINOR ORCHESTRATION10
COORDINATION20
MAJOR COORDINATION20
MEDIUM COORDINATION15
MINOR COORDINATION5
MANAGEMENT20
MAJOR MANAGEMENT20
MEDIUM MANAGEMENT15
MINOR MANAGEMENT5
AGGREGATION10
MAJOR AGGREGATION10
MEDIUM AGGREGATION5
MINOR AGGREGATION1
CONTROLLER5
MAJOR CONTROLLER5
MEDIUM CONTROLLER3
MINOR CONTROLLER1
ACCEPTANCE10
MAJOR ACCEPTANCE10
MEDIUM ACCEPTANCE5
MINOR ACCEPTANCE3
INTEGRATION15
MAJOR INTEGRATION15
MEDIUM INTEGRATION10
MINOR INTEGRATION10
VIEW10
MAJOR VIEW10
MEDIUM VIEW5
MINOR VIEW1
BASE5
MAJOR BASE5
MEDIUM BASE3
MINOR BASE1
COMPONENT15
MAJOR COMPONENT15
MEDIUM COMPONENT10
MINOR COMPONENT5
PAGE5
MAJOR PAGE5
MEDIUM PAGE3
MINOR PAGE1
CLIENT5
MAJOR CLIENT5
MEDIUM CLIENT3
MINOR CLIENT1
EXPOSER5
MAJOR EXPOSER5
MEDIUM EXPOSER3
MINOR EXPOSER1
DESIGN20
MAJOR DESIGN20
MEDIUM DESIGN10
MINOR DESIGN5
MAJOR FIX20
MEDIUM FIX10
MINOR FIX5
PLANNING15
MAJOR PLANNING15
MINOR PLANNING10
MINIOR PLANNING5
MENTORSHIP20
MAJOR MENTORSHIP20
MINOR MENTORSHIP15
MINIOR MENTORSHIP10
DISCUSSION15
MAJOR DISCUSSION15
MINOR DISCUSSION10
MINIOR DISCUSSION5
MAJOR CODE RUB10
MEDIUM CODE RUB5
MINOR CODE RUB1
CODE RUB1
PROVISION10
IMPORT5
RELEASE10
CONFIG5
REVIEW1
DOCUMENTATION1
STANDARD100
BUSINES50
STATUS1
UNKNOWN0

上述各类别已在上一节中定义。

12.2.1 平均实现时间

下表列出了实现 The Standard 架构中不同层或组件所需的平均预估时间。
这些时间基于实际经验,可作为规划和工作量估算的一般参考。

层 / 组件平均时间
Brokers,Base~1 小时
Foundations,Components~3 小时
Processing,Orchestration,Coordination,Orchestration Components~5 小时
Management,Uber Manager~3 小时
Controllers,Pages,Clients~1 小时

这些估算表示单个服务或组件的典型实现时长,假设复杂度为标准水平且没有外部依赖。

12.2.2 等级

以下等级依据对 The Standard 社区及符合 The Standard 规范的项目的终身累计贡献和投入确定:

职位积分
SWE I10,000
SWE II25,000
SR. SWE50,000
PRINCIPAL100,000
PARTNER/DIRECTOR300,000
VP500,000
DISTINGUISHED1,000,000
THE STANDARD BEARER1M + DELEGATION

评论

支持 Markdown