隶属于用户个人的页面或者功能必须进行权限控制校验。
说明:防止没有做水平校验就可随意访问、修改、删除别人的数据,比如查看那他人的私信内容、修改他人的订单。
中国大陆个人手机号码显示未 173****1314,隐藏中间 4 位,防止隐私泄露。
用户输入的 SQL 参数,严格使用参数绑定或者 METADATA 字段值限定,防止 SQL 注入,禁止字符串拼接 SQL 访问数据库。
如果忽略,可能会导致:
说明:Java代码用正则来验证客户端的输入,有些正则写法验证普通用户输入没有问题,但是如果攻击人员使用的特殊构造的字符串来验证,有可能导致死循环的结构。
禁止向 HTML 页面输出未经安全过滤或未正确转义的用户数据。
CSRF(Cross-site request forgery)跨站 请求伪造是一类常见的编程漏洞。对于存在 CSRF 漏洞的应用/网站,攻击者可以事先构造号 URL,只要受害用户一访问,后台便在用户不知情的情况下对数据库中用户参数进行相应修改。
在用使用平台资源,譬如短信、邮件、电话、支付,必须实现正确的防重防的机制,如:
说明:如注册时发送验证码到手机,如果没有限制次数和频率,那么可以利用此功能能骚扰到其他用户,并造成短信平台资源浪费。
说明:发帖、评论、发送即时消息等用户生成内容的场景必须实现防刷、文本内容违禁词过滤等风控策略。
表达是与否概念的字段,必须使用 is_xxx
的方式命名。
数据类型是 unsigned tinyint
:
说明:任何字段如果为非负数,必须是 unsigned。
# 正例,删除
is_deleted 1表示删除、0表示未删除
数据库字段名的修改代价很大,因为无法进行预发布,所以字段名称需要慎重考虑。
MySQL 在 Windows 中不区分大小写,但在 Linux 下默认是区分大小写。因此,数据库名、表名、字段名,都不允许出现任何大小字母,避免节外生枝。
# 正例
aliyun_admin、rdc_config、level3_name
# 反例
AliyunAdmin、rdcConfig、level_3_name
说明:表名应该仅仅表示里面的实体内容,不应该表示实体数量,对应于 DO 类名也是单数形式,符合表达习惯。
禁用保留字,如 desc、range、match、delayed等,请参考 MySQL 官方保留字。
主键索引名为: pk_字段名
唯一索引名为:uk_字段名
普通索引名为:idx_字段名
说明:
pk_
即 primary keyuk_
即 unique keyidx_
即 index 的简称说明:在存储的时候,float 和 double 都存在精度损失问题,很可能在比较值的时候,得到不正确的结构。如果存储的数据范围超过 decimal 的范围,建议将数据拆成整数和小数分开存储。
如果存储的字符串长度几乎相等,使用 char 定长字符串类型。
varchar 是可变长字符串,不预选分配粗出空间,长度不超过 5000。
如果长度超过5000,定义字段类型为 text,独立出来一张表,用主键来对应,避免影响其他字段索引效率。
说明:其中 id 必为主键,类型为 bigint unsigned、单表时自增,步长为1。
create_time、update_time 的类型均为 datetime 类型。
表命名最好遵循: 业务名称_表的作用
# 正例
alipay_task
force_project
teade_config
库名与应用名称尽量一致
如果修改字段含义,或对字段表示的状态追加时,需要及时更新字段注释。
字段允许适当冗余,已提高查询性能,但必须考虑数据一致。冗余字段应遵循:
# 正例
商品类目名称使用频率高。字段长度短,名称基本不变,可在相关联的表中冗余存储类目名称,避免关联查询。
单表行数超过 500 万行,或者单表容量超过 2GB,才推荐进行分库分表。
说明:如果预计 3 年后的数据量根本达不到这个级别,请不要在创建表时就分库分表。
合适的字符存储长度,不但节约数据库表空间、节约索引存储,更重要的是提升检索速度。
正例:如下表,其中无符号值可以避免误存负数,且扩大了表示范围。
对象 | 年龄区间 | 类型 | 字节 | 表示范围 |
---|---|---|---|---|
人 | 250岁之内 | tinyint unsigned | 1 | 无符号值:0~255 |
龟 | 数百岁 | smallint unsigned | 2 | 无符号值:0~65535 |
恐龙化石 | 数千万年 | int unsigned | 4 | 无符号值:0~约42.9亿 |
太阳 | 约 50 亿年 | bigint unsigned | 8 | 无符号值:0~约10的19次方 |
业务上具有唯一特性的字段,即使是多个字段的组合,也必须建成唯一索引。
**说明:**不要以为唯一索引影响了 insert 的速度,这个速度损耗可以忽略,但提高查找速度是明显的;另外,即使在应用层做了非常完善的校验控制,只要没有唯一索引,根据墨菲定律,必然有脏数据产生。
超过三个表禁止 join。需要 join 的字段,数据类型必须绝对一致;
多表关联查询时,保证被关联的字段需要有索引。
**说明:**即使双表 join 也需要注意表索引、SQL 性能。
在 varchar 字段上建立索引时,必须指定索引长度,没必要对全字段建立索引,根据实际文本长度,决定索引长度即可。
说明:索引的长度与区分度是一对矛盾体,一般对字符串类型的数据,长度为 20 的索引,区分度会高达 90% 以上,可以使用 count(distinct left(列名, 索引长度))/count(*)
的区分度来确定。
页面搜索,严禁使用走模糊或者全模糊,如果需要请走搜索引擎来解决。
说明:索引文件具有 B-Tee 的最左前缀匹配的特性,如果左边的值未确定,那么无法使用此索引。
如果有 order by 的场景,请注意利用索引的有序性。order by 最火的字段是组合索引的一部分,并且放在索引组合顺序的最后,避免出现 file_sort 的情况,影响查询性能。
# 正例
where a=? and b=? order by c;
# 反例
索引如果存在范围查询,那么索引的有序性无法利用,如:
where a>10 order by b;
其中,索引 a_b 无法排序。
利用覆盖索引来进行查询操作,避免回表。
说明:我们看一本,只需要就看目录即可知道章节标题,无需翻到指定页面查看查看标题。
# 正例
能够建立索引的种类分为:主键索引、唯一索引、普通索引三种,而覆盖索引指示一种查询的一种效果,用explain的结果,extra列就会出现:using index
说明:MySQL 并不是跳过 offset 行,而是去 offset + N 行,然后返回放弃前 offsert行,返回 N 行,那当 offset 特别大的时候,效率就非常低下,要么控制返回的总页数,要么对超过特定阈值的页数进行 SQL 改写。
# 正例
# 先快速定位需要获取的 id 段,然后在关联
select a.* from 表1 a,
(select id from 表1 where 条件 limit 100000, 20) b
where a.id=b.id;
SQL 性能优化的目标:至少要达到 range 级别,要求是 ref 级别,如果可以是 consts 最好。
说明:
# 反例
explain 表中的结构,type=index,索引物理文件全扫描,速度非常慢,这个index界别比较range,还低,与全表扫描是大巫见小巫。
# 正例
# 如果 a 列几乎接近于唯一值,那么只需要单键 idx_a 素索引即可。
where a=? and b=?
说明:存在非等号和等号混合是,在建立索引时,请吧等号条件列前置
where c>? and d=?
其中,c的区分度更高,也必须把 d 放在索引的最前列,即索引 idx_d_c。
防止因字段类型不同造成的隐式转换,导致索引失效。
图中默认上层依赖于下层,箭头关系可表示直接依赖,如:开放接口层可以依赖于Web层,也可以直接依赖于 Service 层,依此类推:
开放接口层:
可以直接封装 Service 方法暴露成RPC接口;
通过Web封装成 http 接口;
进行网关安全控制、流量控制等
终端显示层
各个端的模板渲染并执行显示的层。当前主要是 velocity渲染、js渲染、jsp渲染、移动端展示、小程序等。
Web 层:
主要是对访问控制进行转发,各类基本参数校验,或者不服用的业务简单处理等。
Service 层:
相对具体的业务逻辑服务层。
Manage 层:通用业务处理层,它具有以下特征:
DAO 层:
数据访问层,与底层 MySQL、Oracle、Hbase 等进行数据交互。
外部接口或第三方平台:
包括其他部门 RPC 开放接口,基础平台,其他公司的 HTTP 接口。
Exception e
的方式,返回给上层 Manager/Service。(1)GroupID 格式:
com.{公司/BU}.业务线.[子业务线]
,最多四级。# 正例
com.couragesteak.blog
com.couragesteak.dubbo.register
(2)ArtifactID 格式:
# 正例
dubbo-client
fastjson-api
jstorm-tool
couragesteak-api
(3)Version:
格式:主版本号.此版本号.修订号
(1)主版本号:产品方向改变,或者大规模 API 不兼容,或者架构不兼容升级。
(2)此版本号:保持相对兼容性,增加主要功能特性,影响范围极小的 API 不兼容修改。
(3)修订号:保持完全兼容,修复 BUG、新增次要功能特性等。
说明:
主要版本起始版本号必须为:1.0.0,而不是 0.0.1,正式发布的类库必须先去中央仓库进行查证,使版本号有连续性,正式版本号不允许覆盖升级。如当前版本:1.3.3,那么下一个合理的版本号:1.3.4 或 1.4.0 或 2.0.0
# 正例
1.0.0 # 最低版本号
1.0.1
必须声明所有依赖的版本号,避免自动下载最新依赖导致的不兼容。
# 正例
SQLAlchemy==1.4.43
aiomysql==0.1.1
(1)精简可控原则。
移除一切不需要的 API 和依赖,只包含 Service API、必要的领域模型对象、Utils类、常量、枚举等、如果依赖其他二方库,尽量是 provided 引入,让二方库使用者去依赖具体版本号;
无 log 具体实现,值依赖日志框架。
(2)稳定可追溯原则。
每个版本的变化应该被记录,二方库由谁维护,源码在哪里,都需要能方便查到。除非用户主动升级版本,否则公共二方库的行为不应该发生变化。
说明:操作系统默认 240 秒后,才会关闭处于 time_wait 状态的连接,在高并发访问下,服务端会因为 time_wait 的连接数过多,可能无法建立新的连接,所以需要再服务器上调小此等待值。
# 正例
# 在 linux 服务器上通过变更 /etc/sysctl.conf 文件去修改该缺省值
net.ipv4.tcp_fin_timeout = 30
调大服务器所支持的最大文件句柄数(File Descriptor,简写为 fd)。
说明:主流操作系统的设计是将 TCP/UDP 连接采用与连接文件一样的方式去管理,即一个连接对应于一个 fd。主流的 linux 服务器默认所支持最大 fd 数量为1024,到那个并发连接数很大时很容易因为 fd 不足而出现 “open too many files” 错误,导致新的连接无法建立。建议将 linux 服务器所支持的最大句柄数调到最高数倍(与服务器的内存数量无关)。
服务器内部重定向使用 forward;外部重定向地址使用 URL 拼装工具类来生成,否则会带来 URL 维护不一致的问题和潜在的安全风险。
存储方案和底层数据结构的设计需要获得评审一致通过,并沉淀为文档。
说明:有缺陷的底层数据结构容易导致系统风险上升,可扩展性下降,重构成本也会因历史数据迁移和系统平滑过渡而突然增加。所以,存储方案和数据结构需要认真地进行设计和评审,生产环境提交执行后,需要进行 二次检查。
# 正例
评审内容包括存储介质、
表结构设计能否满足技术方案、
存储性能和存储空间能否满足业务发展、
表活字段之间的辩证关系、字段名称、字段类型、索引等;
数据结构变更(如在原有表中新增字段),也需要进行评审通过后上线。
如果某个业务对象的状态超过3个,使用状态图来表达并且明确状态变化的各个触发条件。
说明:状态图的核心是对象状态,首先明确对象有多少种状态,然后明确两两状态之间是否存在直接转换关系,在明确触发状态的条件是什么。
# 正例
淘宝订单状态有:已下单、待付款、已付款、待发货、已发货、已收货等。
比如:已下单与已收货这两种状态之间是不可能有直接转换关系的。
当功能链路涉及对象超过3个时,使用时序图来表达并且明确各调用环节的输入与输出。
说明:时序图反应了一系列对象的交互与协作关系,清晰立体地反应系统的调用纵深链路。
需求分析与系统设计在考虑主干功能的同时,需要充分评估异常流程与业务边界。
# 反例
用户在淘宝付款过程中,银行扣款成功,发送给用户扣款成功短信,但是支付宝入款时由于断网演练产生异常,淘宝订单页面依然显示未付款,导致用户投诉。
说明:单一原则最易理解,确是最难实现的一条规则,随着系统演进,很多时候,忘记了类设计的初衷。
说明:不得已使用继承的话,必须符合里氏代换原则,此原则说父类能够出现的地方,子类一定能够出现。
比如:“把钱叫出来”,前的子类包括人民币、美元、欧元等都可以出现。
说明:低层次模块依赖于高层次模块的抽象,方便系统间的解耦。
说明:在极端情况下,交付上线生产环境的代码都是不可修改的,同一业务域内的需要变化,通过模块或类的扩展来实现
系统设计阶段,共性业务或公共行为抽取出来公共模块、公共配置、公共类、公共方法等,避免出现重复代码或重复配置的情况。
说明:随着代码的重复次数不断增加,维护成本指数级上升。
**说明:**敏捷开发是快速交付迭代可用的系统,沈略多余的设计方案,摒弃传统的审批流程,但核心关键点上的必要设计和文档沉淀是需要的。
# 反例
某团队为了业务的快速发展,敏捷成了产品经理催进度的接口,系统中均是勉强能运行,但像面条一样的代码,可维护性和可扩展性极差,一年之后,不得不进行大规模重构,得不偿失。
系统设计主要目的是明确需求、理顺逻辑、后期维护,次要目的用于指导编码。
**说明:**避免为了设计而设计,系统设计文档有助于后期的系统维护和重构,所以设计结果需要分类归档保存。
设计的本质是识别和表达系统难点,找到系统的变化点,并隔离变化点。
说明:在众多设计模式中,目的均为隔离系统变化点。
python
https://zh-google-styleguide.readthedocs.io/en/latest/google-python-styleguide/python_language_rules/
java
https://github.com/chjw8016/alibaba-java-style-guide