作为一个在IT界摸爬滚打将近4年的全栈开发猿,从在象牙塔里刚接触编程时的不知其所云,到毕业后为求职弃硬从软,再到现在变秃变强,一路坎坷(脱发),现在终于有时间总结以下自己的开发经验与大家分享交流.如果有理解不到位之处还请各位在评论区留言.
以下排名不分先后
0. 设计需求(UI)
- 组件化的设计
- 响应式
- Accessibility (抱歉不知中文哪个合适)
解决方案
- mobile first design (优先小设备显示的设计)
- 保持和UX设计师良好的沟通,设计尽量组件化,多提一些能够减少开发周期的设计反馈
- 明确前端适配的浏览器以及版本
- 明确前端适配的显示屏大小
- 根据以上来确定测试方案
- Accessibility是一个很难界定的东西,有A,AA,AAA标准,但是基本上要确保的原则包括但不限于:用户只用键盘也能顺利使用你的App,以及在一些屏幕阅读工具例如NV access能够正确的读取内容
1. 安全需求
- 用户验证与鉴权(Authentication & Authorization)
- 防范中间人攻击(Man in the middle atack)
- 防范代码注入,例如JSON注入,SQL注入等(JSON injection & SQL injection)
解决方案
- 常见的安全框架:Spring security 或者Apache shiro
- 通过Auth server与reverse proxy来统一解决验证与鉴权.Auth server 处理用户登录以及生成安全令牌而reverse proxy 负责令牌验证和过期处理
- 使用单向https来提供外部服务,以及双向https用来内部服务间建立安全连接
- 使用第三方插件来确保JSON 和 SQL中的恶意注入代码失效(大部分框架都有提供SQL安全防护)
2. 日志,监控以及追踪需求
- 同步日志与异步日志的选择
- 不同日志框架的选择logback vs log4j2
- 日志格式Json vs 传统格式
- 日志处理
解决方案
- Log4j2 搭配异步日志来达到最小次I/O写入,最大性能输出.并且搭配shutdown hook来确保程序停止运行时,缓存的日志写入磁盘
- Elastic search (索引)+logstash (处理)+ kibana(展示)+beats (收集)
- 如果接收到的请求没有UUID,使用filter等生成并添加,然后使用MDC来将这个UUID包括在每一条日志记录中.如果需要调用下游api, 将此UUID添加到请求头当中
- 通过分析日志来监控应用,以便及时发现,处理异常(ELK)
- 统一的日志格式:Json易于ELK来处理,但是笔者更喜欢传统格式,代价便是在logstash需要多花些功夫
- 服务追踪:zipkin对代码的侵入性很低,能够提供直观的api调用链以及在在每个环节的时间消耗.
3. 存储需求
- 不同的数据类型:结构性数据与非结构性数据,小数据与大数据
- 数据缓存
- 有限制的数据(例如最多可储存数量)
- 读写数据带来的性能瓶颈
- 数据审计(谁创建,谁更改,什么时候创建,什么时候更改)
- 不同数据库的选择
- 数据加密
- 不同的数据更新频率
- 一直在增长的数据
解决方案
笔者对于数据库的研究并不多,这里只做了解内的阐述
- 使用数据库索引
- 使用缓存Redis 或者hazelcast
- 读写分离
- 利用spring自带的auditaware功能来audit所有数据
- 数据加密(TBD)
- 对于不经常更新的数据,可放入property文件中
- 如果数据的数量一直会增长,那么一开始最好设计分页
- 如果一个Query可能带来m个其他的Query(例如一个Order中有多个产品), 考虑用空间换时间,将m个子类创建一个只读版本并存储在父类中
4. 通信需求
- 不同通信协议的需求:http, smtp, ftp, websocket, soap, message broker
- 不同的格式:Json vs. Xml
- 统一处理输入与输出
- 调用或者提供不同特性的Api:只能调用一次,可重复调用(幂等与非幂等),有间隔的调用,定时调用
- re-try失败请求
解决方案
- 使用interceptor来统一处理请求和响应
- 尽量简单的通信接口,将逻辑放在service中
- Utility 来重新发送请求
5. 测试需求
- 单元测试
- 集成测试(Mock所依赖的下游服务)
- 系统集成测试
- 性能测试
- 并发测试
解决方案
- SonarQube,Jacoco等第三方来提供直观的反馈
- 不单纯追求测试覆盖率,根据项目压力与经验灵活调整
- 每一个发现的Bug都写一个测试
- 在CI/CD中执行单元测试以及集成测试(集成测试慢但是有时候是必要的)
- 单独建立一个项目来周期性的执行系统集成测试,测试结果以及失败测试存储到数据库,每一个测试都有UUID来识别
- Jmeter是一个非常好用和上手的性能测试工具,记得使用non-GUI模式
- 在测试中加入一定的并发测试,确保得到正确的返回值
6. 验证需求
- 表单验证
- 外部输入信息的验证以及内部逻辑的验证
解决方案
- Hibernate validation annotation, 笔者本人并不喜欢用,因为太松散了,而且验证的东西多了的话可读性差.个人喜欢专门写一个验证层,根据不同的业务情况来验证.
7. 代码规范需求
- 高内聚低耦合的代码设计
- 统一的代码风格以及标准
- code review
解决方案
- 使用lint 工具来检查语法
- 采用团队内共识的代码标准
- 周期性的code review
8. 共享需求
- 代码共享
解决方案
- 采用内部repository来共享代码,例如nexus
- 用script 来机械的复制代码
9. 错误需求
- 应用抛出异常(checked vs. unchecked)
- 调用下游服务失败
- 异常中事务性的处理
- 错误boundary
- fail fast vs fail tolerant
解决方案
- 抛出checked 如果你希望这个异常调用者处理,抛出unchecked如果这个异常不需要被立刻处理
- 创建一个错误消息的规范格式,并且每个错误都有root cause,UUID,异常代码
- 如果有反向代理,生产环境中可以在反向代理中过滤掉错误细节.如果没有反向代理,可以在error class添加jsonIgnore来过滤掉特定域或者单纯的只返回异常代码
- 500来表示服务器错误,400表示客户端错误
- 单实例中使用Transactional来正确的回滚
- 微服务中的事务回滚(TBD)
- 根据业务来灵活的选择fail fast or fail tolerant
10. Mock 需求,随机数据需求
解决方案
- 建立一个nodejs项目来生成随机的数据(json),并且可以转化成Sql语句格式.
- mock server (目前还没有深入了解)来mock api 调用
11. 文档需求
- set up文档
- api 文档
解决方案
通过阅读readme,简单几步即可将应用启动
- readme 中包含环境信息 os, jvm version, nodejs version
- swagger doc, spring-fox来自动生成swagger doc
12. CI/CD需求
- 全自动
- 可配置
- 版本控制,回滚等
- 快速的构建
解决方案
- 传统的Jenkins
- 新型的云CI/CD服务(docker hub)