项目规范,主要指项目结构规范和命名规范。
无论是大型、中型甚至小型项目,清晰的目录结构是开发过程的好的开始。项目目录结构规划属于架构设计的基础,清晰、条理、统一规范的目录结构,对于开发和维护项目非常重要。
而项目文件命名和业务统一命名,也要遵循同样的一致性规范,这才有利于项目的规范性、可维护性。良好的命名规范,可以减少阅读代码的成本,避免歧义或多义引起的理解偏差问题。
src
├─ main
│ ├─ java
│ │ └─ com
│ │ └─ ywt
│ │ ├─ gapi // grpc 定义文件生成类
│ │ └─ PROJECT
│ │ ├─ configs // 配置类(db, grpc, etc)
│ │ ├─ core // 封装核心类
│ │ │ ├─ annotations // 自定义注解
│ │ │ ├─ exceptions // 自定义异常
│ │ │ ├─ utils // 工具类
│ │ ├─ domain // POJO,领域模型类
│ │ │ ├─ entities // DO(jpa entity & repository)
│ │ │ ├─ models // DTO or BO,可以根据业务细分子目录
│ │ │ ├─ enums // 枚举类
│ │ ├─ impl // grpc 实现类
│ │ ├─ services // service
│ │ ├─ web // web 服务目录
│ │ │ ├─ configs // web 相关配置
│ │ │ ├─ controllers // controllers
│ │ │ └─ interceptors // 拦截器
│ │ └─ Main.java // 主文件
│ └─ resources // 配置文件
│ ├─ application.properties
│ └─ logback-spring.xml
└─ test // 测试
Project
├─ src
│ ├─ api // 接口服务
│ │ ├─ controller.js // 接口控制类
│ │ └─ index.js // 接口服务入口文件
│ ├─ defs // grpc 定义文件目录
│ ├─ util // 工具类
│ └─ service // rpc 服务
├─ conf.json // 配置文件
├─ index.js // 入口文件
├─ package.json
└─ test.js // 测试
TODO
TODO
app
┣ 📂assets
┃ ┣ 📂images // 应用内的图片资源
┃ ┃ ┗ 📜logo.png // 应用 logo
┃ ┗ 📂styles // 样式
┣ 📂components // 通用组件
┃ ┣ 📂GlobalFooter // 通用页脚
┃ ┣ 📂GlobalHeader // 通用页头
┃ ┣ 📂SiderMenu // 侧栏菜单
┃ ┣ 📂StandardTable // 表格封装
┣ 📂config // 配置
┃ ┗ 📜routes.js // 业务页面路由
┃ ┗ 📜const.js // 全局常量定义
┣ 📂containers // 业务页面
┃ ┣ 📜App.js
┃ ┗ 📜Root.js
┣ 📂layouts // 通用页面,如通用业务页面、登录页面
┣ 📂services // 接口类
┣ 📂store // store
┣ 📂utils // 工具类
┣ 📜app.global.scss
┣ 📜app.html
┣ 📜index.js
┣ 📜main.dev.js
┣ 📜menu.js // APP 顶部菜单
┣ 📜package.json
┣ 📜Routes.js // 通用页面路由
resources // 图标等资源
package.json
主要包括业务统一命名规范和代码命名规范。
在版本迭代过程中,通常会有一个或多个新增的业务,在开发过程中,就避免不了会针对新增的业务去修改数据库、代码、定义文件、配置文件等,在改动这些文件的时候,一般来说都是直接使用业务名称的英文来表示。但在开发过程中,由于工程师的英语水平参差不齐,再加上很多业务名称通常是专业性较强的术语或全称比较冗长的名词,最终可能导致负责不同模块的各个工程师使用的英文命名不完全一致,从而降低了项目的可维护性。
早期的开发过程,并没有针对业务统一命名做出规范,也导致出现了一些业务在数据库、代码、定义文件、配置文件等多个地方存在不同命名的问题。例如之前在开发医疗设备检查这个业务功能,在数据库设计中使用了 checklist 的命名,但在接口和服务层使用的是 MedEquip,这样的分歧对项目的可持续维护是灾难性的。
因此,在迭代过程中,数据库、数据表、文件夹(代码文件夹、资源文件夹等)、文件名(代码文件、配置文件等),同一种业务必须使用统一的英文名称。
在需求评审通过后,确定开发计划开始的时候,由技术负责人统一命名业务关键字,负责各个模块开发工作的工程师必须遵守这个命名去开发、修改项目文件。
通用命名规则:
尽量不要使用拼音;不能拼音和英文随意混用。对于一些通用的表示(如业务上 taihe 表示太和医院,nfyybyfy 表示白云分院)或者难以用英文描述的可以采用拼音。
命名过程中尽量不要出现特殊的字符。
尽量不要和项目使用的框架中已存在的类重名,也不能使用项目编程语言中的关键字或保留字命名。
妙用介词,如 for(可以用同音的4代替), to(可用同音的2代替), from, with,of 等。如类名采用 User4RedisDO.class,方法名 getUserInfoFromRedis(),convertJson2Map() 等。
项目名称全部采用小写方式, 以短横线 -
分隔。示例:taihe-rpc.
包名统一使用小写,统一使用 com.ywt
作为前缀。单词间如果需要分隔,用下划线 _
分隔。示例:com.ywt.gapi.covid19_questionnaire.
类文件全部使用大驼峰式命名。对于一些特殊特有名词缩写,除第一个字母其他都变成小写。示例:IdCardUtil.java, XmlParser.java.
Java 常用类文件命名约定:
根据工具类的功能使用英文命名,后缀加上 Util
。示例:IdCardUtil.java;
根据异常的描述使用英文命名,后缀加上 Exception
。示例:AppMessageExcpetion.java;
根据拦截器的功能使用英文命名,后缀加上 Interceptor
。示例:LoginInterceptor.java;
领域模型命名规范
DO: 和数据库表名保持一致,用大驼峰式命名。示例:SnsUserInfo.java;
DTO/BO: 根据业务名称使用英文命名,用大驼峰式命名。如果是接口类使用,使用 xxReq
表示请求参数对象,xxResp
表示响应参数对象,禁止使用 Map
类来传输。示例:QueryDishListReq.java, QueryDishListResp.java, NatOrderInfo.java;
JPA repository: 使用数据库表名,作为前缀,后缀加上 Repository
。示例:DepartmentRepository.java;
枚举类命名规范
根据枚举的功能使用英文命名,后缀加上 Enum
。示例:OrderStatusEnum.java;
根据 grpc 实现的功能使用英文命名,后缀加上 Impl
。示例:UserServiceImpl.java;
根据 service 的功能使用英文命名,后缀加上 Service
。示例:DoctorService.java;
根据 controller 的功能使用英文命名,后缀加上 Controller
。示例:PayController.java;
根据测试文件的功能使用英文命名,后缀加上 Test
。示例:CreateOrderTest.java;
方法命名采用小驼峰的形式。方法命名一般为动词或动词短语,与参数或参数名共同组成动宾短语,即动词 + 名词。一个好的函数名一般能通过名字直接获知该函数实现什么样的功能。示例:getUserName(), isNameValid().
变量 & 常量命名:
变量采用小驼峰命名。变量命名时,尽量简短且能清楚的表达变量的作用,命名体现具体的业务含义即可。不允许使用意义不明的拼音首字母缩写。示例:userName, updateCount.
常量命名一般采用全部大写,单词间用下划线分隔。如果是一组同类型的常量,将类型前置。示例: HOSPITAL_ID_TAIHE, HOSPITAL_ID_NFYYBYFY.
Redis key 命名全部采用小写字母,单词间用下划线分隔;如果是独立使用的键,最好使用项目名称 + :
作为前缀。示例:wapapi:wechat_access_token.
项目名全部采用小写方式, 以短横线 -
分隔。示例:central-control-service.
文件夹命名,当有复数结构时,要采用复数命名法,如有多个单词时,用短横线 -
分隔,示例: scripts, styles, images, data-models.
所有的 JavaScript 文件均以.js结尾。
文件名全部采用小写,当遇到多个单词组成时,以短横线 -
分隔,示例:check-commit.js.
js 和 css 压缩文件, 统一以-min 结尾, 示例:源码文件为 react.js, 压缩后为 react-min.js.
变量 & 常量命名
局部变量一定要声明,避免全局污染;
推荐使用let全面代替var,因为它创建了块级作用域变量(变量只在代码块内生效),尤其是 for 循环内;
建议只有在逻辑上是常量的情况才使用 const,它代表常量,定义的同时必须赋值;
常量命名采用单词所有字母大写,并用下划线分隔,示例:FORM_NAME
对象、函数、和实例采用小驼峰命名法
示例:
// 对象
let isObject = {};
// 函数
function isFun(){
...
};
// 实例
let myBbj = new Object();
示例
// 类
class Point {
...
};
// 构造函数
function User(options) {
this.name = options.name;
}
let myBbj = new User({
name: 'yup'
});
避免 magic number
magic number 主要指在代码中没有具体含义的数字、字符串。影响了代码可读性,读者看到的数字无法理解其含义,从而难以理解程序的意图。当程序中出现的 magic number 过多时,代码的可维护性将会急剧下降,代码变得难以修改,并容易引入错误。
要将 magic number 定义为常量,并增加注释。示例:
// 接口成功返回的标识
const SUCCESS_CODE = 1;
// 接口失败返回的标识
const FAIL_CODE = 0;
$.ajax({
url: baseUrl + 'v1/activity/getAct',
type: 'GET',
dataType: 'json',
success: function(result) {
// do something
}
});
参考前端规范CSS BEM 命名约定