近期在学习IBM全栈应用开发微学士课程,故此记录学习笔记。

1. 云原生入门

云原生应用是一种构建和运行在云上的应用程序。云原生应用由协同工作的微服务组成,以充分利用云计算的优势。

云计算,简称“云”,是一种基于互联网的计算方式,通过这种方式,共享的软硬件资源和信息可以按需求提供给计算机各种终端和其他设备。

  • NIST将其定义为:一种实现对可配置计算资源的共享池进行便捷、按需网络访问的模式,这些资源可快速调配和释放,只需极少的管理工作或服务提供商的互动
  • 计算资源包括网络、服务器、存储、应用程序和服务

云模式由五个基本特征、四种部署模式和三种服务模式组成:

  • 五个基本特征:按需自助服务、广泛网络访问、资源池共享、快速弹性伸缩、可度量服务
  • 四种部署模式:私有云、社区云、公有云、混合云
  • 三种服务模式:基础设施即服务(IaaS)、平台即服务(PaaS)、软件即服务(SaaS)

1.1. 现代软件开发

  • 以服务形式交付
  • 集中托管并通过互联网访问
  • 网络应用程序、SaaS

1.2. 云原生堆栈

  1. 应用程序代码:持有云原生应用程序
  2. 应用程序运行时:中间件
  3. 应用程序和数据服务:数据库、消息队列、缓存
  4. 调度和协调:控制面板,比如Kubernetes
  5. 云基础设施:定义环境

1.3. 使用案例

云中的一切都应采用云原生方法构建,以充分利用云的优势。

应用代码需要使用以下工具:

  • 标准化的日志
  • 标准化的事件
  • 多个微服务和云原生应用程序可使用的标准目录
  • 微服务的标准化跟踪

1.4. CNCF

云原生计算基金会(CNCF)是一个非营利性组织,致力于促进云原生计算的采用和技术进步。CNCF的使命是通过开源、中立和可持续的项目来推动云原生计算的采用。

CNCF通过为参与公司的项目提供营销和支持来帮助他们。CNCF还通过培训和认证来支持开发人员。

1.5. 混合云

混合云是指在私有云和公有云之间创建连接的计算环境。 混合云允许应用程序和数据在私有云和公有云之间移动。

公共云由外部提供商管理,在一个硬件平台上有多个租户,可包括多个地点的服务器;私有云由企业管理,通常在企业的数据中心中,由企业拥有和使用。

内部部署的私有云属于单个组织,由其托管和管理自己的云空间。

1.6. 实践与方法

  • 测试驱动开发(TDD):在编写代码之前编写测试
  • 行为驱动开发(BDD):关注从外部看到的系统行为,而非系统内部的工作方式
  • 持续集成/持续交付(CI/CD):一种软件开发方式;你可以构建和部署软件,以便随时将其发布到生产中
  • 敏捷开发(Agile):一种迭代的项目管理方法,可帮助团队快速响应并向客户交付价值
  • Scrum:一种进行增量产品开发的管理框架
  • 微服务架构:一种单一应用程序由多个松散且可独立部署的小型服务组成的方法,每个服务通过API进行通信
  • 容器(Container):独立的、包罗万象的可执行软件单元

2. 开发运维和CI/CD

2.1. 开发运维(DevOps)

DevOps是一种软件开发方法,旨在通过自动化软件交付流程来加快软件交付速度。DevOps是开发(Dev)和运维(Ops)的组合。

Patrick Debois是DevOps的创始人。
他如此形容DevOps:“敏捷开发环境的延伸,旨在加强整个软件交付的过程。“

DevOps推动文化和技术变革,促进开发和运维团队之间的协作,简化流程,自动化任务,并持续交付高质量的软件。

DevOps提高了效率和客户价值,要求组织学习和文化转型。

其核心目标是自动化软件交付。

DevOps诞生前,开发和运维团队之间的沟通和协作很少。开发团队开发软件,然后将其交付给运维团队,运维团队负责部署和维护软件。这种模式导致了开发和运维团队之间的隔阂,从而导致了低效率、低质量的软件交付。

各自为政行不通,因此DevOps的目标是将开发和运维团队合并为一个团队,并遵循敏捷开发原则,以便更快地交付更高质量的软件。

2.1.1. DevOps的要求

  • 改变文化:重视开放、信任和透明度
  • 新的应用设计:无需为增加一项功能而重新部署整个系统
  • 利用自动化:加快并提高应用交付的一致性
  • 可编程平台:持续部署

2.1.2. 这些不是DevOps!

  • DevOps不单单是简单地将开发和运营结合起来
  • DevOps不是一种工具或技术
  • DevOps不是一个独立的团队
  • DevOps不是一刀切的解决方案
  • DevOps不只是自动化

2.1.3. 工具

  • 版本控制

    • 管理和跟踪更改
    • 实现团队协作
    • 维护记录
    • Git实现了无缝代码管理
    • GitLab和GitHub是两个流行的Git托管服务
  • CI/CD

    • 自动构建、测试和部署流程
    • 整合变更并自动发布
    • CI工具:构建和测试
      • Concourse CI
      • Circle CI
      • Travis CI
    • CD工具:自动化应用发布
      • Spinnaker
      • Go CD
      • Argo CD
    • CI/CD工具
      • Jenkins
      • Tekton
      • GitLab CI/CD
      • GitHub Actions
  • 配置管理

    • 自动配置软件和基础设施,确保一致性并简化环境管理
    • Ansible
    • Chef
    • Puppet
    • SaltStack
  • 容器化和容器协调

    • 可在容器中打包和部署应用程序,从而实现轻松扩展和高效资源管理
    • Docker
    • Kubernetes
  • 监控和日志记录

    • 监视应用程序性能、健康状况并分析日志
    • Prometheus
    • Grafana
    • ELK Stack
    • Mesmo
    • New Relic
  • 合作和交流

    • 促进团队成员之间有效的团队合作、知识共享和协调
    • Slack
    • Microsoft Teams
    • Atlassian Jira
    • Trello
    • Asana

2.2. CI/CD

持续集成(CI)确保变更通过必要的测试;将测试变更集成到主分支中。

持续交付(CD)确保快速安全的部署;将变更交付到类似生产的环境中。

CI/CD不是一个过程,而是两个不同的过程:CI不断将代码整合回main/master/trunk分支,CD将整合后的代码部署到生产环境。

  • CI包括计划、编码、构建和测试阶段
  • CD包括发布、部署和运行阶段

持续部署(Continuous Deployment)是生产自动化,专门用于实际持续推送到生产环境的情况。
它与持续交付不同,后者是将代码部署到类似生产的环境中,比如开发服务器,但不会自动部署到生产环境。

2.2.1. CI的优势

  • 更快的代码更改反应时间
    1. 更改代码
    2. 测试代码
    3. 构建变更
    4. 快速向客户交付解决方案
  • 降低代码集成风险
    • 集成小的内容
    • 无需在代码库中集成大量代码
    • 只需集成10-50行代码
  • 更高的代码质量
    • PR(Pull Request):开发人员将代码更改推送到代码库中的分支,然后请求其他开发人员审查和合并代码更改
    • 当有人提出PR时,就可以对代码进行审查
  • 版本控制中的代码工作

2.3. TDD

测试驱动开发(TDD)是一种软件开发方法,它要求在编写代码之前编写测试。

  1. 编写失败的测试用例
  2. 编写足够的代码使测试通过
  3. 重构代码
  4. 重复

TDD意味着测试用例驱动代码的设计和开发,使开发人员能够更快地编写代码。

2.4. BDD

行为驱动开发(BDD)是一种软件开发方法,它关注从外部看到的系统行为,而非系统内部的工作方式。

在软件测试中执行BDD的适当级别是集中测试、系统测试和验收测试。

3. Agile

敏捷开发是一种迭代的项目管理方法,可帮助团队快速响应并向客户交付价值。

Agile强调了:

  • 适应性规划
  • 渐进式发展
  • 早期交付
  • 持续改进

敏捷开发宣言:

  • 个人和互动高于流程和工具
  • 可以工作的软件高于详尽的文档
  • 客户合作高于合同谈判
  • 响应变化高于遵循计划

符合敏捷开发宣言的迭代式软件开发方法强调灵活性、互动性和高透明度,使用小型、同地办公、跨职能、自组织的团队。

主要启示:按需建设,而非按计划建设。

3.1. Scrum

Agile和Scrum不是同一个东西!

两者的区别为:

  • Agile是一种工作哲学(非规范性的)
  • Scrum是一种工作方法(增加流程)

Scrum是一种渐进式产品开发的管理框架。

  • 规定了小型、跨职能、自我组织的团队
  • 提供角色、会议、规则和工件的结构
  • 使用固定长度的迭代,称为Sprint
  • 目标是在每次迭代中构建一个可交付的产品增量

3.1.1. Sprint

Sprint是设计、代码、测试和部署周期中的一次迭代。

每个Sprint都应有一个目标,且通常持续两周。

3.1.2. Scrum流程

  1. 产品积压(Product Backlog):产品所有者(Product Owner)创建产品积压,其中包含想在产品中实现且未在Sprint中实施的所有功能
    • 按重要性和业务价值排序,最上方的功能最详细
  2. 积压工作细化(Backlog Refinement):团队和产品所有者一起讨论产品积压中的功能,以便团队了解功能的细节
  3. Sprint计划:定义在Sprint阶段可以交付的工作以及如何完成这些工作
    • 产品所有者、Scrum主管(Scrum Master)和开发团队参与
    • 目标在于定义每个Sprint的明确业务目标
  4. Sprint积压(Sprint Backlog):要比产品积压小得多,仅包含团队在下个Sprint中(未来两周内)要完成的功能
  5. 每日Scrum:每个人都应回答三个问题
    • 昨天做了什么?
    • 今天要做什么?
    • 遇到了什么问题?
  6. 有价值的产品

3.1.3. 团队

适当的组织是成功的关键,这往往意味着现有团队可能需要重组。

团队应当是松散耦合、又紧密配合的。这代表着每个团队都有着自己的任务,同时还要与业务保持一致。

Scrum强调自主权,这同时是一种鼓励团队成员自我管理的方法,也是速度和质量的保证。

决策在团队中就地做出,同时还让团队成员为自己构建的产品承担完全的责任。

自主权最大限度地减少了交接和等待,让团队成员能够快速做出决策并采取行动。

3.2. Agile不是……

Agile不仅仅只是迭代。在每次迭代的最后,团队都必须在部署应用程序后从客户那里收到反馈。

Agile不是瀑布式软件开发生命周期的新版本。每次Sprint阶段都不应当是采取传统的开发方法,并且不能只有开发人员参与,它涉及一个跨职能的团队。

3.3. 鸡汤

不要在最不了解的时候决定一切,应当根据所了解的情况制定计划。 随着了解的增多而调整计划,你的估计会更加准确。

如何失败:不对员工进行培训就安排他们担任新职务。

3.3.1. 职务之间的区别

产品经理(Product Manager):管理预算的业务人员,主要负责业务运营方面。

产品所有者(Product Owner):项目中有远见的人,带领团队进行一系列旨在实现Sprint目标的实验。

项目经理(Project Manager):让每个人都按照固定计划行事的任务负责人。

Scrum主管(Scrum Master):让团队专注于当前Sprint的教练,帮助团队解决问题、消除障碍并保持团队的高效率。

开发团队(Development Team):仅由开发人员组成的团队。

Scrum团队(Scrum Team):跨职能团队,包括开发人员、测试人员、安全人员、业务分析师、运营人员等。

3.4. 用户故事

用户故事(User Story)是一种简短的、简单的描述,代表团队在一次迭代中可以交付的一小部分业务价值。

用户故事往往包含了以下几个部分:

  • 为谁而设?
  • 他们需要什么?
  • 为什么他们需要?
  • 他们从中获得的商业价值是什么?

用户故事的内容应是需求和业务价值的简要说明,包含了所有的假设和细节,即“完成”的定义。

用户故事记录了一个角色为实现目标而提出的功能要求,即:作为一个【角色】我需要【功能】以便【目标】。

3.4.1. 验收标准

记录“完成”的定义至关重要,要让利益相关者、客户和开发人员都能轻松描述“完成”的定义。

也就是:给定【条件】,当【事件】发生时,我希望【结果】。

3.4.2. INVEST原则

  • 独立性(Independent):用户故事应该是独立的,这样就可以按照任何顺序进行开发
  • 可协商性(Negotiable):用户故事应该是可协商的,这样就可以在开发过程中进行更改
  • 有价值(Valuable):用户故事应该是有价值的,这样就可以在每次迭代中交付价值
  • 可估算(Estimable):用户故事应该是可估算的,这样就可以在每次迭代中估算工作量
  • 小型(Small):用户故事应该是小型的,这样就可以在每次迭代中交付
  • 可测试(Testable):用户故事应该是可测试的,这样就可以在每次迭代中测试

3.4.3. Epic

Epic是一种大型用户故事,它可以进一步分解为较小的用户故事。

当一个用户故事的范围过大时,就会被称为Epic。当优先级较低、定义较少时,积压项目往往会以Epic的形式存在。

3.4.4. 故事点

故事点(Story Points)是一种估算工作量、估算特定用户故事实施难度的指标。它是总体工作量的抽象度量,而非时间单位。

我们需要承认人类非常不善于估算时间,因此要使用相对估算。许多工具采取了Fibonacci数列,因为它们是一种指数级增长的数列。用更抽象的概念来比喻的话,就是衣服的尺码。

例如,在第一个Sprint中,团队估算一个用户故事的故事点为M尺码,这可能会花费两天时间,也可能会花费一周时间。在第二个Sprint中,团队对故事点的估算有了更精准的认知,因此在估算另一个用户故事时,会根据花费在第一个用户故事上的时间,以及第二个用户故事的复杂程度,来估算第二个用户故事的故事点。

切记,绝对不要将故事点与时间混淆。

4. NoSQL

NoSQL这个概念在一次关于分布式数据库的开源活动中被提出。全称是Not Only SQL,意思是“不仅仅是SQL”。

NoSQL是一种非关系型数据库,它不使用SQL作为查询语言,而是使用其他语言。没有了标准的行和列,NoSQL数据库可以存储各种类型的数据,且在存储和查询数据的方式上更加灵活。

NoSQL设计用于大型数据集的高性能和灵活性,它们通常用于Web应用程序和大数据应用程序。

4.1. MongoDB

MongoDB是一种开源的文档和NoSQL数据库,它使用类似于JSON对象和Python字典的文档来存储数据。

1
2
3
4
5
6
{
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]",
"studentId": 20217484
}

集合(Collection)是一组文档,类似于关系数据库中的表。比方说,你可以创建一个名为students的集合,其中包含所有学生的文档。

数据库(Database)是一组集合,类似于关系数据库中的数据库。比方说,你可以创建一个名为school的数据库,其中包含所有学生的集合。

4.1.1. MongoDB的优势

  • 在读取和写入数据时建立数据模型,而非传统的先创建模式、再创建表格
  • 让用户能够引入任何结构化或非结构化数据
  • 通过保存多份数据副本,提高数据的可用性

MongoDB适合用于大型和非结构化、复杂、灵活、高度可扩展的应用程序。

在传统的关系数据库中,你需要先设计,再写代码。例如:

1
2
3
4
5
6
7
8
9
10
11
CREATE TABLE Students (
FirstName varchar(255),
LastName varchar(255),
Email varchar(255),
StudentId int);

INSERT INTO Students
VALUES ("John",
"Doe",
"[email protected]",
20217484);

而在MongoDB中,你可以直接写代码,无需设计复杂的表格定义。例如:

1
2
3
4
5
6
db.persons.insertOne({
"firstName": "John",
"lastName": "Doe",
"email": "[email protected]",
"studentId": 20217484
})

4.1.2. 案例

假设你正经营一家快递公司,因此需要存储送货地址。随着2020年送货流程的巨大变化,你需要存储更多的数据,比如该客户是否选用了无接触送货。

使用MongoDB可以轻松存储这些数据;如果使用的是关系数据库,你可能需要重新设计表格,以便存储新的数据。

4.1.3. 查询和分析

MongoDB提供了一种查询语言,称为MongoDB查询语言(MQL)。MQL拥有多种操作符,可用于查询和分析数据。

如果查询还要更复杂,你可以使用MongoDB聚合管道(Aggregation Pipeline)。

以下是一些实践练习:

  1. 启动MongoDB Shell

    1
    mongo
  2. 连接到MongoDB服务器

    1
    mongosh -u root -p xxx --authenticationDatabase admin local
  3. 列出所有数据库

    1
    show dbs
  4. 创建一个名为school的数据库

    1
    use school
  5. 创建一个名为students的集合

    1
    db.createCollection("students")
  6. 列出所有集合

    1
    show collections
  7. students集合中插入一条文档

    1
    2
    3
    4
    db.students.insertOne({
    "firstName": "John",
    "lastName": "Doe"
    })
  8. 数插入了多少条文档

    1
    db.students.count()
  9. 列出所有文档

    1
    db.students.find()
  10. 更新一条文档

    1
    2
    3
    4
    db.students.updateOne(
    {"firstName": "John"},
    {$set: {"lastName": "Smith"}}
    )
  11. 删除一条文档

    1
    db.students.deleteOne({"firstName": "John"})
  12. 从服务器断开连接

    1
    exit

4.1.4. Mongo Shell

Mongo Shell是MongoDB的命令行接口,它允许你与MongoDB服务器进行交互。

Mongo Shell也是一种JavaScript解释器,它允许你在MongoDB服务器上运行JavaScript代码。

连接到集群:

1
mongosh "mongodb://USER:PASSWORD@url/test"