研发规范总结
总结现实过程中感觉到生疏、可总结归纳的问题。
- 关于命名的规则?- 程序的设计- 关于错误的处理?应该实在内部,还是应该在内部?最好有统一的原则- 关于日志的输出?内外部怎么配合?最好有统一的原则- 关于编程的实现的思路与方法?针对那些代码应该进行封装、那些应该(针对的是最大为模块粒度)2.1. 命名
Section titled “2.1. 命名”- 文件整理方式
- 命名方法
- 不同语言的社区规范- 结构化命名,基于前后缀规范(类型、用途、作用域、角色)- 通用项目规范(词汇表、角色与类型前后缀、动名词)2.2. 设计
Section titled “2.2. 设计”- 架构设计
- 单体架构- 分布式架构SOA- 微服务架构- 事件驱动架构- 技术选型
# 顺序- 选方案(Sass、开源、自研)- 选组件(优劣势,主/备选)- 选语言- 选框架
# 原则- 人工投入最少- 法律法规- 公司技术栈- 社区活跃度- 满足需求- 优先轻量简单- 组织模式
# 分层模式- 底层- 业务层- 表现层
# 边界层隔离- 设计模式
《大话设计模式》
2.3. 实现
Section titled “2.3. 实现”- 模块
- 配置模块- 日志模块- 工具模块- 输入模块- 输出模块- 通知模块- 中间件模块- 错误定义模块- 错误处理模块- 生命周期模块- 主模块- 数据模型模块- 依赖模块(用于依赖注入)- 实现
- 写备注,定义功能单元:定义实现的功能。- 整理,提取公共单元:提取公共代码,降低重复率;规范参数(传参、返回参数);分配到合适的模块,尽量较少引用并符合逻辑依赖。- 实现功能:处理异常、日志等2.4. 错误处理
Section titled “2.4. 错误处理”- 方案
## 异常机制- 控制流分离- 错误传播- 控制流中断
## 状态码机制- 显示检查- 信息简单- 不中断控制流- 异常分类
# 基于类型- 错误(底层运行时负责、不需要):通常是系统层级的、外部环境导致。- 异常:可预见、可恢复的异常。 - 检测性异常:一般是强类型语言检测类异常。 - 运行时异常: **内层可以恢复,则恢复。不能回复则向上抛** - 技术异常:程序发生错误 - 底层技术异常:(IO/网络/数据库等)。**如果当前层能处理(如重试),则处理;否则转换为自定义技术异常或运行时异常向上抛出** - 编程异常:空指针。**通常直接向上抛出,由最外层兜底,记录完整日志,并返回 `HTTP 500`(Internal Server Error),对用户隐藏详细信息。** - 业务异常:用户发生错误(通常是自定义异常)
# 基于分层- 底层: 抛出最具体的、技术性错误。- 中间层:局部恢复,异常转化- 外层:全局拦截处理。统一的日志、状态码转化、格式化输出。- 关注问题
- 什么时候需要捕获(是否)?- 在那个进行捕获处理?- 怎么处理异常?- 自定义异常怎么规划?- 原则
# 错误不捕获,不处理,不规划
# 异常- 异常处理应在“有意义”的层次进行。(恢复处理、资源清理、日志记录与监控、友好的反馈、异常转换/封装)- 就近原则,尽可能早的抛出。- 恢复处理、资源清理、日志记录与监控、友好的反馈、异常转换/封装、向上抛出、通知等- 层级规划、捕获可粗可系粒度- 不滥用异常、只有当前的异常不足以表达时在新增。- 预期会有大量“非成功”结果的场景中,使用状态码机制。
# 最佳实践底层抛出具体异常 -> 中间层捕获、转换/封装为业务异常或进行部分恢复 -> 上层(如Web控制器)捕获所有异常,统一处理(日志、用户反馈)- 风险
## 不进行错误处理- 不安全,会打印完整的堆栈信息- 难以调试与定位(难以确定确定崩溃的状态与上下文信息)
## 仅作全局处理- 业务语义丢失/过度泛化- 性能影响2.5. 日志
Section titled “2.5. 日志”- 关注问题
- 日志记录,什么时候需要输出?- 日志规范?- 日志标准?- 日志级别- 日志记录
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 级别开启。不适合作为业务监控的主要依据。