系统运维本质上是人与计算机共同参与的一项系统性工程

sre - 图1
Mikey金字塔围绕着沟通设计,每一层都建立在前一层的基础之上,它被沟通所包围,因为每一层都需要沟通才能成功

  • 监控:确保洞察系统、跟踪系统的健康状态、可用性,以及系统内部发生的事情。(不仅仅是工具)
  • 事故响应:定义提醒的规则,做出响应。建立随叫随到的轮换机制与团队合作的最佳实践,以及建立必要的基础设施以尽可能的降低事故带来的压力
  • 事后回顾:一旦服务中断,如何确保问题不会再发生(事故的回顾会议、文档记录)
  • 测试与发布:专注于预防而不是事后处理。

    预防是指尝试限制发生的事故数量,并确保在发布新代码时基础架构和服务能够保持稳定。

  • 容量规划:预测未来和发现系统的极限,确保系统可以随着时间的推移得到完善和增强。

  • 开发:构建工具,开发新工具和服务。工具一部分将用于自动化一些手工任务,一部分用于改进Mikey金字塔的其余部分
  • 用户体验:确保用户获得良好的体验

评估方式:

  • 团队结构,负责内容
  • 查找团队为服务或项目编写的文档
  • 了解系统架构图及服务交互、服务部署

    绘制一个项目人员的简介示例表,明确该如何沟通

  • 然后依次提出问题:

    • 服务有监控机制吗
    • 团队有事故响应计划吗
    • 团队有事后回顾报告吗
    • 有人曾做过扩展计划吗
    • 能使用什么工具来改进服务
    • 当前的可靠性水平是否提供了令人满意的用户体验

      监控

      观察和检查一段时间内(某事物)的进展或质量持续进行系统审查
  • 确定质量标准,并确保系统持续逼近保持在质量标准极限范围内

  • 系统地关注工作

    为什么需要监控

    软件中通常需要两种不同类型的监控:

  • 指标:度量数字,侧重于性能数字,如磁盘的空间使用率、接受的数据包数量、CPU负载等

  • 日志:记录事故,通常也包含一些数字与数据,但往往结构松散

    RED

    我们需要有针对性的度量应用程序。对于web应用程序,最常见的指标是:

  • 错误数

  • 请求数
  • 请求持续时间

最常见的日志是错误堆栈跟踪

RED(Error Counts,Request Counts, Request Duration),错误,请求,延迟

为什么往往从这些指标开始

  1. 错误数

我们可以在每次发生错误时增加一个计数器,并将该错误写入带有时间戳的日志。

某些服务允许你按计数器增量存储元数据,并将日志绑定到计数器上,但通常只需要使用相同的时间戳写日志和计数器增量即可

计数器可以知道系统何时向用户发送了错误查看日志以评估该错误的性质,递增计数器,就可以计算请求错误率,以及快速查看错误的长期增长趋势。总请求数很有用,因为据此可以知道应用程序的使用频率

  1. 请求数

总请求数是对服务器正在执行的工作量的准确反映,它可以知道应用程序的使用频率。如果服务器是流服务器,那么团队通常会计算字节数数据包而不是请求数。(一个请求可能涉及多个服务器)

  1. 请求持续时间

度量服务器处理请求时间,是指从收到完整请求到发送完整响应的时间。请求持续时间有多方面的用途

  • 确定某种类型的请求是否比其他请求花费时间更长(URL命中率、请求方法,返回的状态码等)
  • 可以查看类似请求随时间而变化的情况

    度量什么

    监控理念决定了监控什么,以及何时监控:

  • 监控一切:如果团队在时候回顾发现需要一些新的数据,它应该被检测、监控和存储

  • 最小化延迟监控:度量新数据的决策被延迟到事后的回顾中

    基础

  • web服务器:RED

  • 某种数据管道、批处理服务或cron作业:作业调用次数、作业持续时间、作业成功次数
  • 后台服务: IDS (Instrusion Detection Systems, 入侵检测系统)

    扩展

    目标:验证服务是否按预期执行

开始时记录业务逻辑(数据库记录数量、连接到依赖项的指标、发生了多少种类型的操作等等),然后才可以根据指标扩容
扩容通常记录服务器使用的资源:硬盘存储、网络带宽、CPU和内存等指标

监控体系是需要逐步建立的,随者服务的增长,可以发现所查看的指标哪些是无用的。随者团队的发展,其他开发人员可以且应该添加他们锁关心的指标。

黑盒监控:假设监控工具对应用程序一无所知或知之甚少,通常是一个探测或一系列常规请求,以检测事情是否按预期方式工作 白盒监控:对代码的加测,它知道程序是如何工作的,因为它来自于程序内部

SLI、SLO和错误预算简介

SLI

服务水平指示器(Service Level Indicator),对于业务来说可能是最重要的指标

  • 网站:如请求得到正常响应的百分比
  • 其他服务:如性能指标(100ms内返回搜索结果的百分比等)

    SLI是这些目标背后的指标,用以评判服务水平

SLO

服务水平目标(Service Level Objective) 是一个围绕SLI构建的目标,它通常是一个百分比,并与一个时间范围挂钩。

SLA

服务水平协议(Service Level Agreement)是企业围绕SLO发布的协议,它要求在不满足SLO时向客户提供货币补偿。

错误预算

一旦对SLO有了大概的了解,并且对它进行了一些度量,就可以用它来做风险决策了。

并非每个服务都需要SLO和错误预算,但它们可以称为非常有用的工具,以确定何时可以安全地承担风险。
没有SLO的服务,有可能让客户定义什么是可接受的性能水平

即使发布了SLO,也不能保证用户能够恰如其分地预计服务地可用性

收集和保存监控数据

检测用于展示和追踪变化,人们总是希望能够保留所有地历史数据,但并不可能在没有大量资金或资源的情况下存储所有东西
在对应用程序进行监控后,需要将数据存储在某个位置。

轮询应用程序

轮询程序从服务中抓取数据,然后存储并显示数据

缺点:需要保留一些关于所有服务的记录,以备不时之需

典型的开源轮询程序:

  • Nagios:C语言开发,有很多fork,将数据存储在RRD(环状数据库,使用循环缓冲区来保持数据库的大小恒定)
  • Prometheus:golang语言开发,查询语言学习难度大,但非常强大,有自己的数据库,也可以将数据导出和备份到外部数据库,还有自己的警报管理器
  • Cacti: 基于PHP和MySQL,但往往需要白那些相当多的代码才能启动和运行,也使用RRD数据库来存储数据
  • Sensu:Ruby语言开发,将状态存储在Redis中,但可以与很多后端系统进行实时的指标数据集成

    推送应用程序

    推送应用程序与轮询应用程序相反,它被动的由服务向它传送指标数据。它通常会存在一个中间服务,负责把指标数据转换和聚合,然后传给中央监控程序。

    如果许多服务同时向它传送数据,可能会出现问题。

典型的开源推送程序:

  • StatsD:用JS编写
  • Telegraf:可以写入InfluxDB数据库并未TICK监控技术中的T(Telegraf,InfluxDB,Chronograf,Kapacitor)
  • ELK

    展示监控信息

    任意查询

    应该提供一个简单的界面或命令行界面,以允许任何人查询数据

    图表

    用作随时间变化的数据的可视化展示

  • x轴包含时间

  • 无论绘制什么,都必须有一个键
  • 所有的轴都必须标记
  • 所有的数字都必须有单位

可以定期输出图表副本,使得在一段时间时候,即使监控的数据已不存在,仍可以通过图表副本获取信息。

仪表盘

一组图表的集合,通常在某个时间段内同步。

聊天机器人

提供图表的聊天机器人不是监控基础架构的必须部分,但可以方便沟通

管理和维护监控数据

  1. 托管: 花钱让别人去做
  2. 自己管理: 需要管理好存储

    事故响应

    在软件中,事故一般是相似的,它们往往是系统性的变化(来自系统本身或系统正在接收的输入)或系统运行环境的变化而引起的故障。系统本身的变化通常是由于代码的部署或系统操作的规模变化造成的。

事故响应是对发生的事故做出反应:

  • 关注,注意到有些东西不对劲,是通过警报实现的。自动化系统的警报更受欢迎,它们是一致的,并且可以以相同的方式去定义。监控发现系统不正常并发出警报,请求人们去查看系统的某一部分
  • 交流,告诉别人哪些东西不对劲,在事件进行的不顺利或一切恢复正常时,都需要去进行告知,,让他们知道类似的情况不会再次发生。
  • 恢复,纠正不对劲的东西,尽快恢复正常,保证事故不会再发生。

    警报

    什么时间发起警报

  • 最严重的警报:服务未正常工作

  • 关键的警报:在30分钟内做出反应
  • 非紧急警报:24小时内做出反应
  • 非关键警报:把它放到工单系统中,让某人在接下来的几个星期修复它

本质上来说,像监控一样,警报是一个不断变化的东西,要警惕过于频繁的警报,因为无论是谁收到警报,效率都会降低。不断地评估是必须地,这样人们才能确保警报是有用地并对它做出正确反应。

怎样发出警报

通常包含以下方式:

  • 电话
  • 短信
  • 大声响应用程序
  • 群组聊天消息
  • 电子邮件
  • 警报器

    警报服务

    发送警报地方法有很多,需要找到合适自己公司地渠道。

    警报内容

    首先考虑开头的字符串,通常是电子邮件的主题聊天中的第一条消息警报头,它应该是简短的、描述性的:

  • 主题应当小于50个字符

  • 使用祈使句
  • 在主题后面提供额外的注解

    向谁发出警报

    可以为待命者创建时间表,如每周轮流一次三四分开

    沟通

    一旦有人接收警报,并且已经确认了警报,就需要开始通报消息。

    最好每30分钟向所有相关人员发送一条消息,尽量简明扼要。还需要在团队聊天中解释正在做什么,以便人们能够协调操作,并且为日后保留日志。这样做也可以避免重复工作,而且可以让那些正在提供帮助的人提出训练有素的问题和建议。也可以为没有上线的人通过阅读你的日志,了解事故的当前状态

可以设置两个频道:

  • 一个用于处理停机的人员的讨论
  • 一个可用于受事故影响的人员(客户通道),让团队中负责通信的人员保持消息传递的一致性,并且给客户一个单独的联系点,以便将信息发送回对事件做出响应的群组

    事故指挥系统

    沟通的一方面是确定负责人,在SRE领域中经常使用ICS,因为它关注随时古的扩大或长时间持续,对某个事故或一系列事故做出响应的特定组织的扩展和持续

    ICS,事故指挥系统

一般是谁先到场谁负责,直到角色被授权。目的是规范化应对事故的结构。

在哪里沟通

在何处进行沟通的关键是始终保持一致,并共享沟通发生的位置。除了内部沟通,也要有发布公共状态页面。

事后回顾

事后回顾是在发生生产事故后进行的回顾(回顾会、根因分析(root cause analysis RCA)、事故回顾等)

为什么写事后回顾报告

在响应一个事故时,需要集中精力尽快使系统恢复到健康状态。这种需要常常会阻止发现事故的根本原因,而撰写事后回顾报告正是找出根本原因的好时机。

  • 进程是如何死亡的
  • 系统的哪部分引起了不稳定
  • 事故发生后多久我们才注意到
  • 为什么其他系统也失败了
  1. 从最开始的事故入手进行彻底、细致地事后回顾

首先必须确保拥有所有的数据,并且确认问题已经被完全解决。
当事故发生时,人们往往会保持高度紧张的状态,靠直觉快速做出决定,很少有时间来思考和权衡决策。如果事后进行分析和研究,可以和更多的人交谈,没有了宕机造成的压力,就会有更多的时间来做出深思熟虑的决定。
可以通过创建一个文档来总结发现和分享事故。

  • 记录发生的事情
  • 解决问题的方法
  • 学到了什么
  1. 有关事件的文档

事件的文档在形式上往往更自由,但也能提供相同的好处。事件可能指:

  • 产品上线
  • 重要的新特性
  • 复杂的集成
  • 供应商的变化

记录重要的业务事件可以对日后有所指引,并在做出未来决策时有所参考,防止未来的团队以相同的方式实现新特性或再次尝试相同的产品策略,帮助团队通过过去的事件来规划将来类似的事件

  1. 对外发布的事后回顾报告

可用于评估依赖关系是否应该继续维持或终止(对于双方都是如此)。
服务打破了约定的SLA,发布事后回顾报告也是种责任。

何时写事后回顾报告

  1. 几天内发生两次相同的事故
  2. 服务中断超过30分钟

    开展事故分析

    事故分析是复杂的,应该从事故现场触发,深入挖掘各个方面,谨防先入为主的观念,小心验证假设
    逆向工程系统:从一个系统开始,通过与它交互并查看它如何响应输入,从而确定其工作原理地方法。如果不了解一个系统,且不能得到帮助,首先要看看事情是如何与之相互作用的(浏览器调试,客户端,网络数据包等)
    阅读代码:代码审查、阅读别人编写的代码、阅读自己很久以前编写的代码,尝试构建函数图,在阅读时列出函数的调用链。
    查看日志和系统生成的指标: 在代码中进行搜索以查看是什么生成了特定的日志行或更改了特定的指标,可以非常快速地确定发生了什么

    如何写事故回顾报告

    摘要

    无论谁打开了这个文档,都应该对发生了什么何时发生的谁收到影响有一个大致的了解,往往是简短的,给读者一个关于事故的快照

    举例:2020年9月25日,有一个有问题的配置变更更新到了我们的边缘路由器。边缘路由器将请求分发给各种应用程序的后端。这导致网站20%的请求失败了30分钟。失败的请求都向客户返回了500响应

影响

不一定要包括这一部分,但对确定客户的响应是什么,或停机的话是否会对外部有影响是有帮助的。这一部分非常适合用来描述感到宕机的客户、关于宕机的新闻,关于影响SLA的讨论,或是图表;也可以包括恢复时间或按需响应速度的统计数据。产品团队会发现此部分有助于衡量他们应该关注的程度,也有助于管理层确定行动项目的优先级。

举例:此图表显示,在30分钟内,边缘路由器的所有请求中的20%会返回500错误。我们没有看到这些外部故障,但在此次中断期间,客户提交了15个相关的生产环境支持案例。我们决定不发布公开的事后回顾报告,但对这15个案例做出了回应

时间表

给出每一分钟都发生了什么,应该做简短的描述

  1. 说明事故是何时开始何时结束的
  2. 谁对事故做出反应并执行了行动

    举例: 2020年9月25日 14点42分:提交abc1234用于配置存储库,为即将上限的项目配置新的路由路径 14点53分:1%的边缘路由器完成部署,错误开始出现,但没有触发警报[服务中断开始] …

根本原因

事后回顾报告中最重要的部分。它描述了造成服务中断的原因。如果想要预防未来的中断,需要知道它们为什么发生,找出系统如何失败、为什么失败、如何防止这种情况。根本原因是分析得出的主要结果

举例:所做的配置更改出发了边缘路由代码中的未知错误。在路由代码中,假设在配置的路径中只允许使用ASCII字符。此假设围在验证代码中定义,因此当使用前缀/定义新路由时,路由解析器会引发异常。边缘路由器没有捕获此异常,而是开始逐步崩溃,因为它们在引导时读取配置,并且一旦使用非ASCII字符解析配置就会崩溃

行动项目

行动项是事故发生后要采取的行动清单,通常附有工单或跟踪项。
工单的好处就是它列明了问题解决所需的责任和优先顺序。
行动项确保一群人努力防止类似的中断事故再次发生,并让人们各司其职。

举例:

1234 — 添加不相同路由的测试

1235 — 调大第一只金丝雀的灵敏度,以确保在有问题时及时发出警报

1236 — 确保当前所有一线运维成员都具有回滚路由配置的能力

附录

添加与事故相关的所有事项的部分

  • 聊天日志
  • 相关服务日志
  • 屏幕截图
  • 图形
  • 外部URL

    停止事后职责

    安心地承担风险

举行事后回顾会议

最后确定行动项目,讨论根本原因地发现,并使讨论时钟处于安全的氛围下。

  • 简短的时间线和事故摘要
  • 讨论根本原因
  • 提问
  • 讨论行动项
  • 什么事情有效
  • 什么事情无效
  • 应该怎样开始
  • 应该停止做什么
  • 应该改进做什么

    分析以往的事后回顾报告

  • 故障恢复时间

  • 故障间隔时间
  • 触发的警报数量与生成的事后回顾报告数量
  • 轮值者触发的平均报警数量

    MTTR: 平均恢复时间 - 很高意味着团队不理解如何响应事故,或用于执行回滚和其他恢复操作的工具很差或很慢 MTBF: 平均故障间隔时间 - 很低以为着团队在测试上投入不够

测试和发布

测试

验证所测之事物是否在按预期工作。

测试内容

  1. 观察:例如发现服务中断、获得一个需求,或者只是在编写软件
  2. 提问:提问自己,当软件处理这种类型的输入,或者这个依赖方不存在,或者软件进入这种状态时,会发生什么
  3. 假设:提出假设。在代码中,这更多是询问想要发生什么
  4. 测试:行动并验证,代码是否以想要的方式做出了响应
  5. 拒绝或通过:如果测试失败,那么需要修改一些东西以满足期望

    测试代码

  • review
  • 单元、特性和集成测试

    • 单元测试:用于确保函数和方法正常工作【验证函数的执行,模仿外部服务】
    • 特性测试:也称为冒烟测试和验收测试,它们验证特性是否正常工作【测试业务逻辑、用户交互、通过多个函数的数据流】
    • 集成测试:用于确保特性和系统正确地协同工作【启动一个初始请求并进行监视一切正常进行】

      测试基础设施

  • 确保基础设施配置正确

  • 确保基础设施在任何时候都能够处理单点故障
  • 确保代码能够应付生产环境的运维级别

    定期验证

数据恢复测试

  1. 有常规的数据备份吗
  2. 对数据备份的过程有常规的测试吗
  3. 对备份的数据有验证吗

    发布

    发布或部署是获取代码,将其打包并分发给用户使用的步骤。

确保构建和分发是一致的和稳定的通常需要发布具有3个属性

  • 可重复:如果两次构建相同的代码,可以给出相同的构建物
  • 已测试
  • 幂等性:类似于可重复性,但更关注发布的部署和分发阶段,较少关注构建方面。如果要在服务器上每小时运行一次部署脚本,无论何时,将始终是服务器处于相同状态。它们的目标是能够在任何状态下获取系统并将其引向相同的最终状态

    何时发布

  • 如果在SLO内,则可以发布

    发布到生产环境

    蓝绿部署,要确保有某种方式可以展现版本之间的差异。这样,在试图跟踪问题时,就可以看到版本之间发生了什么变化。

    回滚

    回滚时恢复发布的做法。回滚越快,越容易,则发布时可能承担的风险就越大。在快速回滚的同时,要确保回滚经过测试。

    自动化

    自动发布和测试是常见的任务,通常包含

  • 构建

  • 测试
  • 分发

    容量规划

    容量规划是根据过去的经验教训作为度量的标准应对未来并做出规划的过程。

    定义一个规划

    当前的容量是多少

    有很多方法可以定义基础设施的容量,可以使用聚合指标,比如CPU使用率、磁盘存储可用率、每分钟请求数、每秒数据包或任何应用程序的指标。

    通常,你想要关注的指标是你使用最多的资源或对你来说最重要的资源,最重要的往往是来自SLO和SLI

选择容量指标的另一个重要之处在于找到与系统使用率相匹配的指标。人们经常使用聚合CPU使用率或聚合内存使用率,因为如果没有CPU资源或RAM资源,计算机常常不能正常工作。随者可用CPU百分比下降,而访问量增加,系统将更接近它的容量极限。命中指标的一种方法是隔离服务的单个实例,并缓慢增加它接收的访问量直到它停止响应。观察哪些指标随者流量的增加而增加,可以帮助了解什么与容量相关。这通常以生产环境的访问量来检测,或者至少应该以与生产环境访问量量级相仿的访问量来检测

可以让负载均衡器复制访问量,这样用户的正常操作由正常的应用程序池处理,但是测试服务器也获得每个请求的副本。

除一些服务对每台机器的资源有基本的需求之外(可以通过不向服务发送任何请求,检测它其实还是会占用资源来证实),系统的历来想或架构在性能方面也会有阻碍。可能应为数据库过载了,或者与之交互的一个服务存在并发问题,不饿能在1分钟内处理1个以上的请求,而发送的请求比这多得多。

何时达到容量极限

一旦有了当前容量的指标,下一步就是确定何时会达到极限。
可以通过图表进行预测,但是系统不是静态的,需要做好监控并于业务人员做好沟通

应该如何更改容量

假设有一个粗略的时间表来确定容量何时耗尽,应该提出一个防止这种情况的计划。
首先是如何扩展。应该找到一个可以复制现有服务器的工具(快照)或可以将空服务器变为以配置服务器的工具(供应)

有许多技术可以创建基础设施的快照,有些文件系统甚至将其作为内置特性,如使用dd之类的工具对硬盘驱动器进行快照,并将其应用到新机器上。大多数云服务器都允许对正在运行的硬盘驱动器进行快照

在创建副本时,要注意一些问题:

  1. 状态和并发:还有分布式事务的问题
  2. 服务是否受其他服务的限制
  3. 为事件扩容
  4. 不可预测的增长
  5. 预先计划与自动扩容
  6. 公布:预算、预算用来做什么、预算能花多久

    执行规划

    如果规划都是周全的,并且已经得到了预算,就可以展开它了。
    在执行规划时,要确保对变更进行了监控。基础设施的变更就像代码的变更:提交代码时出错的所有东西在部署基础设施时都会出错。
    除了一般的基础设施和系统状态之外,还应该确保假设得到了验证,验证是否按照规划预期的速率增长

    构建工具

    编写代码,构建工具可以把自己和其他人从重复的工作中解放出来。

    寻找项目

    初入团队,第一个项目可能会被别人指定。通常,一个团队雇佣某个人,是因为他有团队当前缺乏的技能。当完成被指定的任务时,可能会寻找想修复或改进的项目。
    项目灵感:
  • 修复一些让人烦恼的事情
  • 防止意外的发生
  • 清理工作
  • 自动化手动完成任务
  • 改进依赖关系以使其更具弹性

一个新的项目通常是令人感兴趣的,但是可能知识一种直觉。除了观察和直觉之外,阅读当前软件工程和其他领域中正在发生的事情也很有用,这样就可以了解其他人看到了什么问题,以及是如何处理这些问题的。阅读大公司的新开源项目,观看来自会议的演讲,以及仅仅阅读技术博客的帖子都是有用的方法。
和同事讨论问题也很有用。
关键是倾听和观察。
另一个找到项目灵感的好方法是寻找那些最近没有人看的软件,探索它们的缺陷和可能的改进点将提高逆向工程技能。
最后一个方法:使用自动化尽可能地解放自己。

定义项目

一旦有了任务或问题,就需要弄清楚如何去开展工作。首先把问题写在笔记本上,然后记下不知道的知道的尝试解决问题的办法。
评估别人的解决方案可以了解这个问题在不同的环境中是如何呈现的。弄清楚一个开源软件是否能够解决问题,也是非常有用的。
一旦做好了研究,就需要弄清楚项目的规模了。先考虑一下能在几个小时或几天内做的小事吗?如果是,可以采用RDD(Readme Driven Development,自述文件驱动开发)。如果不是,可能要编写一个设计文档,因为项目越大,需要做的计划就越多,以确保项目在进行过程中不会有什么意外。(如果有进行协作,那么一个设计文档也会方便交流)

RDD

在每个项目的根目录中都有一个README.md文件,用于描述项目。这时编写软件的第一件事,它描述项目的基本要求,以及项目如何工作。这样做的目的是如果有人偶然发现了这个项目,他们应该能够深入理解我试图解决的问题、解决问题的方法、以及正在考虑的其他一些事情。

设计文档

在编写文档时,可以列一个提纲:

  • 摘要
  • 背景
  • 概述
  • 详细设计
    • 测试
    • 迁移
    • 安全
    • 依赖
    • 隐私
    • 结算
    • 日志
    • 监控
  • 潜在备选方案
  • 事先计划
  • 生产影响

    项目计划

    可以通过敏捷开发来实现版本更新和版本迭代。列好待办事项清单。如果完成了项目的一部分,并且意识到由于将来要完成的事情必须改变已完成的部分,那么就应该改进旧代码。随者学习如何更好的分解项目,计划能力也会增长。

    回顾会与站会

    回顾会是一种持续回顾过去一周、一个月、靓照或其他的迭代计划的方法。大家定期开会,分享做的好的与做的不足的地方,以及如何改进。

    工作分配

    软件开发存在危险,有些项目其实一个人就可以完成开发,此时需要让一个人专门负责对这种单人开发的项目进行代码review。

    构建项目

  • 使用版本控制

  • 始终进行代码评审
  • 所有项目都应该有一个指定的所有者
  • 人是最终问题

    OKR

    objectives and key results 把希望实现的事情罗列并形成列表作为目标,然后创建可度量的检查点作为关键成果。

    文档和维护项目

    尽早为文档标准化可以促进其他人来共同维护文档。有一种方法是将文档更改与代码评审联系起来,这样评审人员不仅可以看到代码更改,还可以看到传达给用户的修改信息