基于TODO的开发方法
之前买了一本书,叫《架构探险—从零开始写Java Web框架 》(不推荐购买~),一本标题党书籍!但是我很推崇作者写代码的方式,就是基于TODO的方式进行开发!
个人认为以基于TODO的方式进行开发,至少有如下几点优势:
- 有助于理解需求
- 有助于梳理业务流程
- 有助于任务拆解和代码封装
- TODO即注释
- 更易于进入心流体验
同时还能避免如下两种情况:
下面我以Blog的创建流程为例,来演示基于TODO的开发方式,并说明为何基于TODO的开发方式有如上优势!
后端的开发框架请见Web开发框架推导!
流程演示
后端开发流程
基于上面的开发框架,整体流程就是Controller->Service->Mapper->Database!
就Blog创建流程来说,我们会有BlogController->BlogService->BlogMapper->Database的流程!
那我们的开发流程如下:
Step1:
@RestController
public class BlogController{
//todo 创建blog流程
//todo 接收参数
//todo 验证字段
//todo 构建Model
//todo 委托BlogService
//todo 返回blog主键
//todo 处理可能异常
}
@Service
public class BlogService{
//todo 创建blog
//todo 设置创建信息
//todo 委托blogMapper执行
//todo 返回主键
}
Step2:
@RestController
public class BlogController{
//创建blog流程
@PostMapping("/blog")
public Long create(BlogDto blog){
//todo 接收参数
//todo 验证字段
//todo 构建Model
//todo 委托BlogService
//todo 返回blog主键
//todo 处理可能异常
return null;
}
}
Step3:
@RestController
public class BlogController{
//创建blog流程
//接收参数
@PostMapping("/blog")
public Long create(@RequestBody @Validated BlogDto blog, BindingResult result){
//验证字段
if (bindResult.hasErrors()) {
throw new BindingException(bindResult.getFieldError().getDefaultMessage());
}
//todo 构建Model
//todo 委托BlogService
//todo 返回blog主键
//todo 处理可能异常
return null;
}
}
Step4:
@RestController
public class BlogController{
//创建blog流程
//接收参数
@PostMapping("/blog")
public ResponseEntity create(@RequestBody @Validated BlogDto blogDto, BindingResult result){
//验证字段
if (bindResult.hasErrors()) {
throw new BindingException(bindResult.getFieldError().getDefaultMessage());
}
//构建Model
Blog blog = BeanUtils.copyProperties(blogDto,Blog.class);
//todo 委托BlogService
//todo 返回blog主键
//todo 处理可能异常
return ResponseEntity.ok("");
}
}
Step5:
@RestController
public class BlogController{
@Autowired
private BlogService blogService;
//创建blog流程
//接收参数
@PostMapping("/blog")
public ResponseEntity create(@RequestBody @Validated BlogDto blogDto, BindingResult result){
//验证字段
if (bindResult.hasErrors()) {
throw new BindingException(bindResult.getFieldError().getDefaultMessage());
}
//构建Model
Blog blog = BeanUtils.copyProperties(blogDto,Blog.class);
//委托BlogService
Long recId = blogService.create(blog);
//todo 返回blog主键
//todo 处理可能异常
return ResponseEntity.ok("");
}
}
@Service
public class BlogService{
//创建blog
public Long create(Blog blog){
//todo 设置创建信息
//todo 委托blogMapper执行
//todo 返回主键
return null;
}
}
Step6:
@RestController
public class BlogController{
@Autowired
private BlogService blogService;
//创建blog流程
//接收参数
@PostMapping("/blog")
public ResponseEntity create(@RequestBody @Validated BlogDto blogDto, BindingResult result){
//验证字段
if (bindResult.hasErrors()) {
throw new BindingException(bindResult.getFieldError().getDefaultMessage());
}
//构建Model
Blog blog = BeanUtils.copyProperties(blogDto,Blog.class);
//委托BlogService
Long recId = blogService.create(blog);
//返回blog主键
return ResponseEntity.ok(recId);
//todo 处理可能异常
}
}
Step7:
@RestController
public class BlogController{
@Autowired
private BlogService blogService;
//创建blog流程
//接收参数
@PostMapping("/blog")
public ResponseEntity create(@RequestBody @Validated BlogDto blogDto, BindingResult result){
try{
//验证字段
if (bindResult.hasErrors()) {
throw new BindingException(bindResult.getFieldError().getDefaultMessage());
}
//构建Model
Blog blog = BeanUtils.copyProperties(blogDto,Blog.class);
//委托BlogService
Long recId = blogService.create(blog);
//返回blog主键
return ResponseEntity.ok(recId);
}catch (BusinessException e) {
//处理可能异常
logger.error("Create Blog Error!", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Create Blog Error!" + e.getMessage());
} catch (Exception e) {
logger.error("Create Blog Error!", e);
return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Create Blog Error!" + e.getMessage());
}
}
}
Step8:
@Service
public class BlogService{
//创建blog
public Long create(Blog blog){
//设置创建信息
Long userId = UserContext.getUser().getUserId();
blog.setCreateId(userId);
blog.setUpdateId(userId);
blog.setCreateTime(new Date());
blog.setUpdateTime(new Date());
//todo 委托blogMapper执行
//todo 返回主键
return null;
}
}
Step9:
@Service
public class BlogService{
@Autowired
private BlogMapper blogMapper;
//创建blog
public Long create(Blog blog){
//设置创建信息
Long userId = UserContext.getUser().getUserId();
blog.setCreateId(userId);
blog.setUpdateId(userId);
blog.setCreateTime(new Date());
blog.setUpdateTime(new Date());
//委托blogMapper执行
blogMapper.insert(blog);
//todo 返回主键
return null;
}
}
Step10:
@Service
public class BlogService{
@Autowired
private BlogMapper blogMapper;
//创建blog
public Long create(Blog blog){
//设置创建信息
Long userId = UserContext.getUser().getUserId();
blog.setCreateId(userId);
blog.setUpdateId(userId);
blog.setCreateTime(new Date());
blog.setUpdateTime(new Date());
//委托blogMapper执行
blogMapper.insert(blog)
//返回主键
return blog.getRecId();
}
}
前端开发流程
前端的开发除了需要处理代码逻辑,还需要处理页面流程!依然可以以TODO的方式来处理,借助于a标签和按钮,可以把页面流给串起来!
接着上面的Blog的CRUD逻辑,这里仅列出示例,不再演示流程,开发流程和上面的流程一致!
list.html:
<!-- todo 新增Blog-->
<a href="new.html">新增</a>
<!--TODO 搜索-->
<!--TODO 列表显示,操作-->
<table>
<tr>
<td>
<a href="view.html">查看</a>
<a href="edit.html">编辑</a>
<a href="delete.html">删除</a>
</td>
</tr>
</table>
<!--TODO 翻页-->
new.html:
<!--todo 表单字段-->
<!--todo 验证规则-->
<!--todo 保存逻辑-->
<a href="list.html">保存按钮</a>
<!--todo 取消逻辑-->
<a href="list.html">取消按钮</a>
view.html:
<!--todo 展示字段-->
<!--todo 返回逻辑,按场景返回?-->
<a href="list.html">返回按钮</a>
edit.html:
<!--todo 表单字段-->
<!--todo 字段赋值-->
<!--todo 验证规则-->
<!--todo 保存逻辑-->
<a href="list.html">保存按钮</a>
<!--todo 取消逻辑-->
<a href="list.html">取消按钮</a>
优势
首先问一个问题,对于你接收到的信息,你是以什么样的标准来评判你理解了或学会了?就是__用你自己的话再说一遍__!
基于TODO的开发方法就是以此为基础:
- 首先基于需求,以TODO文字的形式将业务流程写下来。写下来以后,可以和需求去确认,修正偏差,既__有助于理解需求__也__有助于梳理业务流程__
- 同时,可以看出,每个TODO的工作量都比较小,实际上也起到了__任务拆解和代码封装__的作用。既然任务拆解了,编写的代码也就相应的被拆解为一个个的功能代码了。当然对于逻辑较复杂的代码,还是需要使用重构手段,来进一步的对代码进行封装
- 代码编写完后,不需要将TODO完全删除,只需要把TODO字样去除,__TODO就变成了注释__了!
- 由于每个TODO的实现时间都较短(主要看拆解得如何),你开发的每个小功能,实际上都是在解决一个TODO,就像游戏里的打怪一样,能得到__准即时反馈__,心理得到满足!这是__进入心流体验__的一个必要条件!
关于心流体验:
- 心流英文叫"flow",我第一次见到这个词是在《人件》这本书上!这是两年前写的读书笔记《我的管理实践---《人件》读后感》!
- 心流的解释有很多,有兴趣的可以去搜索一下
- 相信很多人都经历过,比如你做某件事时很专注(写代码、玩游戏等等),当做完后,你以为没多长时间,但是回过神来一看,好几个小时已经过去了!
写在最后
本文只是演示了一种个人比较推崇的写代码的方式,并解释了为什么推崇这种方式!当然,仅供参考!毕竟__适合自己的才是最好的__!
公众号:ivaneye
基于TODO的开发方法的更多相关文章
- 基于微软XAML技术的前端开发方法
使用XAML技术的平台目前包括WPF,Silverlight,Windows8等平台,未来的Windows10统一Windows App也使用XAML技术. 前端开发指通过可视化集成开发环境进行用户界 ...
- 公共建筑能耗监测平台的GPRS通讯服务器的开发方法分享
公共建筑能耗监测平台的GPRS通讯服务器的开发方法分享 在这个文章里面我将用一个实际的案例来分享如何来构建一个能够接受3000+个连接的GPRS通讯服务器软件,这个软件被我认为是一个艺术品,实现周期为 ...
- 基于vue模块化开发后台系统——准备工作
文章目录如下:项目效果预览地址项目开源代码基于vue模块化开发后台系统--准备工作基于vue模块化开发后台系统--构建项目基于vue模块化开发后台系统--权限控制 前言 本文章是以学习为主,练习一下v ...
- 基于Laravel+Swoole开发智能家居后端
基于Laravel+Swoole开发智能家居后端 在上一篇<Laravel如何优雅的使用Swoole>中我已经大概谈到了Laravel结合Swoole的用法. 今天,我参与的智能家居项目基 ...
- Atitit.研发管理--提升效率--软件开发方法DSM总结o99
Atitit.研发管理--提升效率--软件开发方法DSM总结o99 1. 什么是DSM? 1 2. DSM使用的语言DSL 2 3. 模型的优点 2 4. DSM 跟与MDA区别 2 5. MDA的实 ...
- 项目的敏捷开发方法(转自MBAlib)
项目的敏捷开发方法 敏捷方法很多,包括 Scrum.极限编程.功能驱动开发以及统一过程(RUP)等多种法,这些方法本质实际上是一样的,敏捷开发小组主要的工作方式可以归纳为:作为一个整体工作: 按短迭代 ...
- 【翻译】十大要避免的Ext JS开发方法
原文地址:http://www.sencha.com/blog/top-10-ext-js-development-practices-to-avoid/ 作者:Sean Lanktree Sean ...
- 与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室
原文:与众不同 windows phone (31) - Communication(通信)之基于 Socket UDP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
- 与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室
原文:与众不同 windows phone (30) - Communication(通信)之基于 Socket TCP 开发一个多人聊天室 [索引页][源码下载] 与众不同 windows phon ...
随机推荐
- iOS 开发之内存泄漏问题
关于内存泄漏问题,一般情况下就是控制器或者视图没有正常的释放引起的,我们通常可以通过dealloc方法来检查一个控制器或者视图是否释放. 对于一个控制器或者视图没有释放,其实也就是还有强引用引用着这个 ...
- 区块链 PoW 与 PoS 的纷争
最近在研究区块链,可能会有一些非前端文章,感兴趣的可以关注关注哟. 有关注区块链的,肯定会经常看到这两个名词 -- PoW 与 PoS.但是很多人对他们的含义的理解存在很多偏差.那么他们的含义与区别是 ...
- java I/O框架 (二)文件操作(File)
1.介绍 java io中最常操作的就是我们电脑中的文件,将这些文件以流的形式本地读写,或者上传到网络上.java中的File类就是对这些存储于磁盘上文件的虚拟映射,这也体现了java面向对象的思想, ...
- 使用阿里云主机离线部署CDH步骤详解
一.Linux文件系统准备 1. 拍摄快照 登录阿里云控制台,拍摄快照,注意有几个关键点尽量拍摄快照,系统初始状态.CM环境准备完成.CM安装完成.CDH安装完成. 2. 挂载设备 三个主机都执行. ...
- Android4种网络连接方式HttpClient、HttpURLConnection、OKHttp和Volley优缺点和性能对比
比较的指标: 1.cpu 2.流量 3.电量 4.内存占用 5.联网时间 功能点: 1.重试机制 2.提供的扩展功能 3.易用性 4.是否https 5.是否支持reflect api,OkHttp有 ...
- Windows下的Memcache安装:
Windows下的Memcache安装:1. 下载memcache的windows稳定版,解压放某个盘下面,比如在c:\memcached2. 在终端(也即cmd命令界面)下输入 'c:\memcac ...
- String getProperty(String key, String def)
String getProperty(String key, String def) 获取用指定键描述的系统属性. * 若key 系统环境或properties等配置文件的键,如os.name等,返回 ...
- Caused by: java.sql.SQLException: Field 'id' doesn't have a default value
1.错误描述 org.hibernate.exception.GenericJDBCException: error executing work at org.hibernate.exception ...
- 利用PowerDesigner15在win7系统下对MySQL 进行反向工程(二)
利用PowerDesigner15在win7系统下对MySQL 进行反向工程 1.打开PowerDesigner,建立新模型,选择Physical Data Model中的Physical Da.. ...
- LightOJ1245 Harmonic Number (II)
题意 \(求\Sigma \lfloor \frac{n}{i} \rfloor\) Input starts with an integer T (≤ 1000), denoting the num ...