跳转到内容

研发规范总结

总结现实过程中感觉到生疏、可总结归纳的问题。

- 关于命名的规则?
- 程序的设计
- 关于错误的处理?应该实在内部,还是应该在内部?最好有统一的原则
- 关于日志的输出?内外部怎么配合?最好有统一的原则
- 关于编程的实现的思路与方法?针对那些代码应该进行封装、那些应该(针对的是最大为模块粒度)
- 不同语言的社区规范
- 结构化命名,基于前后缀规范(类型、用途、作用域、角色)
- 通用项目规范(词汇表、角色与类型前后缀、动名词)
  • 架构设计
- 单体架构
- 分布式架构SOA
- 微服务架构
- 事件驱动架构
  • 技术选型
# 顺序
- 选方案(Sass、开源、自研)
- 选组件(优劣势,主/备选)
- 选语言
- 选框架
# 原则
- 人工投入最少
- 法律法规
- 公司技术栈
- 社区活跃度
- 满足需求
- 优先轻量简单
  • 组织模式
# 分层模式
- 底层
- 业务层
- 表现层
# 边界层隔离
  • 设计模式

《大话设计模式》

  • 模块
- 配置模块
- 日志模块
- 工具模块
- 输入模块
- 输出模块
- 通知模块
- 中间件模块
- 错误定义模块
- 错误处理模块
- 生命周期模块
- 主模块
- 数据模型模块
- 依赖模块(用于依赖注入)
  • 实现
- 写备注,定义功能单元:定义实现的功能。
- 整理,提取公共单元:提取公共代码,降低重复率;规范参数(传参、返回参数);分配到合适的模块,尽量较少引用并符合逻辑依赖。
- 实现功能:处理异常、日志等
  • 方案
## 异常机制
- 控制流分离
- 错误传播
- 控制流中断
## 状态码机制
- 显示检查
- 信息简单
- 不中断控制流
  • 异常分类
# 基于类型
- 错误(底层运行时负责、不需要):通常是系统层级的、外部环境导致。
- 异常:可预见、可恢复的异常。
- 检测性异常:一般是强类型语言检测类异常。
- 运行时异常: **内层可以恢复,则恢复。不能回复则向上抛**
- 技术异常:程序发生错误
- 底层技术异常:(IO/网络/数据库等)。**如果当前层能处理(如重试),则处理;否则转换为自定义技术异常或运行时异常向上抛出**
- 编程异常:空指针。**通常直接向上抛出,由最外层兜底,记录完整日志,并返回 `HTTP 500`(Internal Server Error),对用户隐藏详细信息。**
- 业务异常:用户发生错误(通常是自定义异常)
# 基于分层
- 底层: 抛出最具体的、技术性错误。
- 中间层:局部恢复,异常转化
- 外层:全局拦截处理。统一的日志、状态码转化、格式化输出。
  • 关注问题
- 什么时候需要捕获(是否)?
- 在那个进行捕获处理?
- 怎么处理异常?
- 自定义异常怎么规划?
  • 原则
# 错误
不捕获,不处理,不规划
# 异常
- 异常处理应在“有意义”的层次进行。(恢复处理、资源清理、日志记录与监控、友好的反馈、异常转换/封装)
- 就近原则,尽可能早的抛出。
- 恢复处理、资源清理、日志记录与监控、友好的反馈、异常转换/封装、向上抛出、通知等
- 层级规划、捕获可粗可系粒度
- 不滥用异常、只有当前的异常不足以表达时在新增。
- 预期会有大量“非成功”结果的场景中,使用状态码机制。
# 最佳实践
底层抛出具体异常 -> 中间层捕获、转换/封装为业务异常或进行部分恢复 -> 上层(如Web控制器)捕获所有异常,统一处理(日志、用户反馈)
  • 风险
## 不进行错误处理
- 不安全,会打印完整的堆栈信息
- 难以调试与定位(难以确定确定崩溃的状态与上下文信息)
## 仅作全局处理
- 业务语义丢失/过度泛化
- 性能影响
  • 关注问题
- 日志记录,什么时候需要输出?
- 日志规范?
- 日志标准?
- 日志级别
  • 日志记录
1. - **启动/停止**:记录应用程序、服务或重要组件的启动和关闭。级别通常是 INFO。
- **初始化/销毁**:记录关键资源(如数据库连接池、消息队列消费者)的初始化成功或失败。级别可以是 INFO 或 ERROR。
2. **关键业务流程节点**:
- **流程开始/结束**:记录一个重要业务流程的开始 and 结束,例如“订单创建流程开始”、“用户注册成功”。级别通常是 INFO。
- **关键步骤**:记录业务流程中的重要中间步骤,尤其是在流程复杂或可能出现分支时。例如,“支付请求已发送”、“库存已扣减”。级别通常是 INFO 或 DEBUG。
3. **参数接收与结果返回**:
- **接口入参/出参**:在公共API或服务边界记录接收到的重要请求参数和返回结果。这对于调试接口调用和理解数据流非常有帮助。**注意脱敏敏感信息。** 级别可以是 INFO 或 DEBUG。
- **异常情况**:在捕获到异常时,**必须**输出日志,包含异常信息和堆栈。级别是 ERROR 或 WARN。
4. **条件分支**:
- **重要决策点**:当程序根据特定条件做出重要决策或进入不同分支时,可以记录日志,说明进入了哪个分支。级别可以是 INFO 或 DEBUG。
5. **外部系统交互**:
- **请求/响应**:与外部服务(数据库、API、消息队列)交互时,记录请求发送 and 接收到的响应。这对于排查集成问题至关重要。级别可以是 INFO 或 DEBUG。
- **超时/错误**:记录与外部系统交互时发生的超时或连接错误。级别是 ERROR 或 WARN。
6. **性能监控**:
- **耗时操作**:记录关键方法或代码块的执行时间。这有助于识别性能瓶颈。级别通常是 DEBUG 或 INFO。
  • 日志规范
- timestamp:精确到毫秒或微秒。
- level:日志级别。
- thread_name 或 thread_id:线程标识。
- logger_name 或 class_method:生成日志的类或方法。
- message:具体的日志内容。
- exception 或 stack_trace:异常堆栈信息。
- hostname 或 service_name:服务或主机标识。
- request_id 或 trace_id:用于追踪请求的唯一ID。
- user_id 或 session_id:用户或会话标识 (注意隐私)。
- duration_ms:操作耗时 (性能日志)。
  • 日志标准
1. **一致性 (Consistency)**:
- 在整个项目或团队中,日志级别的使用、格式和内容约定应保持一致。
- 使用统一的日志工具和配置。
2. **可追踪性 (Traceability)**:
- 通过 request_id (或 trace_id) 将一次请求在不同服务或模块中的日志关联起来。
- 在分布式系统中,这尤其重要,通常需要链路追踪工具 (如 OpenTelemetry, Zipkin, Jaeger) 来实现。
3. **可读性 (Readability)**:
- 即使是结构化日志,其内容也应易于人类阅读和理解。
- 消息内容清晰,避免使用只有开发者才懂的缩写或行话。
4. **可搜索性 (Searchability)**:
- 选择合适的字段进行索引,以便在日志系统中快速查询。
- 结构化日志天然具有更好的可搜索性。
5. **可监控性 (Monitorability)**:
- 关键错误和警告日志应该能够触发告警,及时通知运维人员。
- 利用日志中的指标进行性能监控和趋势分析。
  • 日志级别
# 外层(Service/API/Controller 层)输出(info+特殊表示)
- 目的:提供高层次的业务流程概览、请求生命周期追踪、用户行为记录。
接收到外部请求的入口点(如 Controller 方法的开始)。
请求的重要参数(脱敏)。
请求处理结果或返回码。
业务流程的关键节点。
在服务边界捕获到的异常。
request_id 或 trace_id 的生成和透传。
- 优点:
清晰地展示业务流程的执行情况。
便于追踪单个请求的完整生命周期。
适合作为审计日志或业务日志的主要来源。
- 缺点:
如果只在外层输出,缺乏底层细节,难以定位具体的技术问题。
# 内层(Service/Manager/Repository 层)输出(info)
- 目的:提供业务逻辑处理的详细过程、数据操作细节、特定模块的内部状态。
业务逻辑中的重要判断条件和分支。
数据转换或计算的关键步骤。
调用其他服务或持久层时的参数 and 结果。
特定业务逻辑的耗时。
捕获和处理的业务异常。
- 优点:
提供比外层更详细的业务逻辑执行细节。
有助于定位业务流程中具体哪个环节出了问题。
- 缺点:
过度输出可能导致日志量过大。
# 底层(DAO/Repository/Utility/Infrastructure 层)输出(DEBUG)
目的:提供基础设施、数据访问、第三方库交互、通用工具的详细技术细节。
数据库操作(SQL语句、参数、执行结果、行数)。
缓存操作(读/写/失效)。
消息队列发送/接收消息的详细信息。
第三方API调用的原始请求 and 响应。
底层异常(如数据库连接失败、IO 错误)。
- 优点:
提供最细粒度的技术细节,对于排查底层技术问题(如 SQL 语句错误、网络通信失败)至关重要。
- 缺点:
日志量可能非常巨大,需要合理配置日志级别,通常在 DEBUG 级别开启。
不适合作为业务监控的主要依据。