基于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 ...
随机推荐
- HashMap并发导致死循环 CurrentHashMap
为何出现死循环简要说明 HashMap闭环的详细原因 cocurrentHashMap的底层机制 为何出现死循环简要说明 HashMap是非线程安全的,在并发场景中如果不保持足够的同步,就有可能在执行 ...
- java 学习第二天小练习
1.从控制台输入学员王浩3门课程成绩,编写程序实现 ChengJi (1)数学课和英语课的分数之差 (2)3门课的平均分 代码如下: p.p1 { margin: 0.0px 0.0px 0.0px ...
- 3.3.4 PCI设备进行DMA写时发生Cache命中
如果PCI设备访问的地址在某个CPU的Cache行中命中时,可能会出现三种情况. 第一种情况是命中的Cache行其状态为E,即Cache行中的数据与存储器中的数据一致:而第二种情况是命中的Cache行 ...
- Caused by:org.hibernate.DuplicateMappingException:Duplicate class/entity/ mapping
1.错误描述 java.lang.ExceptionInInitializerError Caused by:org.hibernate.InvalidMappingException:Could n ...
- Java中的三目运算符
1.问题背景 以下代码运行的结果是: A.hai B.1987 C.1988 D.以上答案都不对 /** * 三目运算符 * A.hai * B.1987 * C.198 ...
- IOS开发之XCode学习008:UIViewController基础
此文学习来源为:http://study.163.com/course/introduction/1002858003.htm 红色框选部分用A代替,AppDelegate类在程序框架启动时,如果在i ...
- ASP.NET WebAPI String 传值问题
如果我们再WebAPI中定义了只有一个string参数的WebAPI函数,如下所示: [HttpPost] public string TrackBill(string str) { return s ...
- Codeforces Round #467 (div.2)
Codeforces Round #467 (div.2) 我才不会打这种比赛呢 (其实本来打算打的) 谁叫它推迟到了\(00:05\) 我爱睡觉 题解 A. Olympiad 翻译 给你若干人的成绩 ...
- 【Luogu3768】简单的数学题(莫比乌斯反演,杜教筛)
[Luogu3768]简单的数学题(莫比乌斯反演,杜教筛) 题面 洛谷 \[求\sum_{i=1}^n\sum_{j=1}^nijgcd(i,j)\] $ n<=10^9$ 题解 很明显的把\( ...
- [HNOI2010]BUS 公交线路
题面 Bzoj Sol 状压很显然 重点在于转移:题目就相当与每\(p\)长度的车站必须有且仅有\(k\)个被经过 那么转移时状压的二进制一定要有\(k\)个一 且两个相邻转移的状态之间必须满足:设为 ...