Go Engineering - Foundation - Error - Package
功能需求
支持错误堆栈
支持不同的打印格式,例如 %+v、%v、%s 等
支持 Wrap/Unwrap 功能:在已有 error 的基础上,追加一些新的信息
errors.Wrap(err, "open file failed")
调用 Wrap 时,会生成一个错误堆栈节点
支持 Is 方法:判断某个 error 是否为指定的 error
Go 1.13 之前,并没有 wrapping error
if err == os.ErrNotExist {}
有 wrapping error 后,直接用 == 判断会有问题,因为可能是 wrapping error
func Is(err, target error) bool
err 和 target 是同一个
当 err 是 wrapping error 时,target 包含在这个嵌套 error 链中
支持 As 函数
Go 1.13 之前,并没有 wrapping error,可以使用 type assertion 或者 type switch
if perr, ok := err.(* ...
Go Engineering - Foundation - Error - Code
设计方式
场景:用户账号没有找到
200
HTTP Code 通常代表的是 HTTP Transport 层的状态信息;但对性能有一定的影响,因为需要解析 HTTP Body
12345678{ "error": { "message": "Syntax error \"Field picture specified more than once. This is only possible before version 2.1\" at character 23: id,name,picture,picture", "type": "OAuthException", "code": 2500, "fbtrace_id": "xxxxxxxxxxx" }}
4xx + 简单信息
可以让客户端快速感知请求失败,但提供的信息过于简单,不能准确地定位问题
12 ...
Go Engineering - Foundation - API Doc
Swagger
Swagger 是一套围绕 OpenAPI 规范构建的开源工具,可以设计、构建、编写和使用 REST API
Swagger 工具
Swagger Editor
基于浏览器的编辑器,可以在其中编写 OpenAPI 规范,并实时预览 API 文档
Swagger UI
将 OpenAPI 规范呈现为交互式的 API 文档,并可以在浏览器中尝试 API 调用
Swagger Codegen
根据 OpenAPI 规范,生成服务器存根和客户端代码库
Swagger vs OpenAPI
OpenAPI 是一个 API 规范,前身也叫 Swagger 规范
通过定义一种用来描述 API 格式或者 API 定义的语言,来规范 RESTful 服务开发过程
目前最新的 OpenAPI 规范是 OpenAPI 3.0 (即 Swagger 2.0)
OpenAPI 规范定义了一个 API 必须包含的基本信息
描述、路径和操作、输入输出参数、验证方法等
OpenAPI 是一个 API 规范,而 Swagger 是实现规范的工具
go-swagger特性
基于代码注释自动生成 S ...
Go Engineering - Foundation - Linting
golangci-lint 优点
速度快
基于 gometalinter 开发,平均速度比 gometalinter 快 5 倍
并行检查代码 + 复用 go build 缓存 + 缓存分析结果
可配置
支持 YAML 格式的配置文件
IDE 集成
VS Code + Goland
Linter 聚合器
集成了很多 Linter,无需单独安装,并且支持自定义 Linter
最小误报数
调整了所集成的 Linter 的默认设置,大幅减少误报
良好的输出
检查出问题的源码文件、行号和错误行内容
不符合检查规则的原因
报错的 Linter
更迭速度快
不断有新的 Linter 被集成进来
使用者:Google、Facebook、Istio、Red Hat OpenShift 等
golangci-lint 命令
cache123456789$ golangci-lint cache statusDir: /Users/zhongmingmao/Library/Caches/golangci-lintSize: 1.9MiB$ golangci-lint cache clean$ ...
Go Engineering - Foundation - RD
功能需求
为 iamctl 新增 helloworld 命令,该命令向终端打印 hello world
开发阶段代码开发
选择 Git Flow:适用于大型非开源项目
创建分支
基于 develop 分支,新建一个功能分支 feature/helloworld
1$ git checkout -b feature/helloworld develop
branch 名要符合 Git Flow 的分支命名规范,会通过 pre-commit 的 githook 来确保分支名符合规范
123$ md5 ./githooks/pre-commit ./.git/hooks/pre-commitMD5 (./githooks/pre-commit) = 3324d20a738461f3b6347f9ce7dae6b6MD5 (./.git/hooks/pre-commit) = 3324d20a738461f3b6347f9ce7dae6b6
./.git/hooks/pre-commit123456789101112131415161718#!/usr/bin/env bashLC_ALL= ...
Go Engineering - Foundation - Makefile
使用
先编写 Makefile 文件,指定整个项目的编译规则,然后通过 Linux make 命令来解析该 Makefile 文件,实现自动化
默认情况下,make 命令会在当前目录下,按照 GNUmakefile、makefile、Makefile(推荐)的顺序查找
make -f golang.mk 或者 make --file golang.mk
规则
规则一般由目标、依赖和命令组成,用来指定源文件编译的先后顺序
Makefile 规则可以自动判断是否需要重新编译某个目标,从而确保目标仅在需要时编译
规则语法
主要包括:target、prerequisites 和 command
1234target ...: prerequisites ... command ... ...
target
可以是一个 object file,也可以是一个执行文件,还可以是一个标签
可以使用通配符,当有多个目标时,使用空格分隔
prerequisites:代表生成该 target 所需要的依赖项,当有多个依赖项时,使用空格分隔
command:代表该 target 要执行 ...
Go Engineering - Foundation - API - RPC
RPC
Client 通过本地调用,调用 Client Stub
Client Stub 将参数打包(Marshalling)成一个消息,然后发送这个消息
Client 所在的 OS 将消息发送给 Server
Server 接收到消息后,将消息传递给 Server Stub(或者 Server Skeleton)
Server Stub 将消息解包(Unmarshalling)后得到消息
Server Stub 调用服务端的子程序,处理完成后,将最终结果按照相反的步骤返回给 Client
gRPC概述
gRPC:google Remote Procedure Call
gRPC 是由 Google 开发的高性能、开源、跨语言的通用 RPC 框架,基于 HTTP 2.0,默认使用 Protocol Buffers 序列化
gRPC 的特点
支持多语言
基于 IDL(Interface Definition Language)文件定义服务
通过 proto3 生成指定语言的数据结构、服务端接口和客户端 Stub
通信协议基于标准的 HTTP/2,支持特性:双向流、消息头压缩、单 TCP ...
Go Engineering - Foundation - API - RESTful
概述
REST:Representational state transfer
REST 只是一种软件架构风格,是一组架构约束条件和原则,而不是技术框架
REST 有一系列规范,满足这些规范的 API 均可称为 RESTful API
REST 规范把所有内容都视为资源,对资源的操作对应 HTTP 协议提供的 GET、POST、PUT 和 DELETE 方法
由于 REST 与 HTTP 协议相辅相成,因此 HTTP 协议已经成为 RESTful API 的事实标准
特点
以资源为中心,一切都可以抽象成资源,所有行为都是对资源的 CRUD
资源对应着面向对象范式里面的对象
资源使用 URI 标识,每个资源实例都有一个唯一的 URI 标识
资源是有状态的,使用 JSON/XML 等在 HTTP Body 里表征资源的状态
客户端通过 HTTP Method 对资源进行操作,实现 REST
无状态:每个 RESTful API 请求都包含了所有足够完成本次操作的信息,服务器无需保持 Session
无状态对于服务端的弹性扩容是很重要的
设计原则
RESTful API 的核心是规范
...
Go Engineering - Specification - Design Pattern
GoF
创建型模式
提供一种在创建对象的同时隐藏创建逻辑的方式,而不是直接使用 new 运算符直接实例化对象
单例模式
分为饿汉方式(包被加载时创建)和懒汉方式(第一次使用时创建)
饿汉方式1234567891011package hungertype singleton struct {}// 实例是在包被导入时被初始化的var ins *singleton = &singleton{}func GetIns() *singleton { return ins}
懒汉方式
非并发安全,需要加锁
1234567891011121314151617181920package singletonimport "sync"type singleton struct {}var ins *singletonvar lock sync.Mutexfunc GetIns() *singleton { if ins == nil { lock.Lock() ...
Go Engineering - Specification - Design Method
Go 项目
Go 项目是一个偏工程化的概念,包含 Go 应用
Go 应用
代码结构按层拆分
最大的问题:相同功能可能在不同层被使用,而这些功能又分散在不同的层中,容易造成循环引用
12345678910├── controllers│ ├── billing│ ├── order│ └── user├── models│ ├── billing.go│ ├── order.go│ └── user.go└── views └── layouts
按功能拆分
Go 项目最常用的拆分方法
不同模块,功能单一,可以实现高内聚低耦合的设计哲学
所有功能只实现一遍,引用逻辑清晰,大大减少循环引用的概率
12345pkg├── billing├── order│ └── order.go└── user
代码规范编码规范
Uber Go 语言编码规范
静态代码检查工具:golangci-lint
最佳实践
Effective Go
Go Code Review Comments
Style guideline for Go packages
代码质量编写可测试 ...