基于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 ...
随机推荐
- java日期转化
package com.kang.util; import java.text.ParseException; import java.text.SimpleDateFormat; import ja ...
- Android设置View抖动动画
在应用中,有时候我们要吸引用户去点击某些按钮,比如应用市场的推荐按钮,为了能够吸引用户主动点击而且不过分的打扰用户,最好的方法就是给我们想吸引用户注意的view添加一些抖动动画,比如这张图 这里我主要 ...
- linux内核体系结构
linux内核第一记 1.linux体系结构 从上图可知,Linux分为:用户空间和内核空间.内核空间和用户空间是程序执行的两种不同的状态,通过系统调用和硬件中断能够完成从用户空间到内核空间的 ...
- phpcmsv9更换模板介绍
先分享下大概的步骤: 1.上传模版文件到服务器:2.在站点管理 里边[模板风格配置]选择新模板:3.设置不同模型对应模板:4.修改现有的栏目,匹配新模板:5.更新栏目缓存.系统缓存,更新HTML静态页 ...
- Java中private、protected和public作用域的异同
Java中private.protected和public作用域的异同 说明:(1)private的作用范围为当前类,protected的作用范围哦不能超过其他包: (2)区别不同的作用域的不同作用范 ...
- touch.js下载使用方式
touch.js下载地址 https://gitee.com/mirrors/touch-js Touch 在开发移动端的应用中会使用到很多的手势操作,例如一指拖动.两指旋转等等,为了方便开放者快速集 ...
- C#图解教程 第十七章 泛型
泛型 什么是泛型 一个栈的示例 C#中的泛型 继续栈示例 泛型类声明泛型类创建构造类型创建变量和实例 使用泛型的栈的示例比较泛型和非泛型栈 类型参数的约束 Where子句约束类型和次序 泛型方法 声明 ...
- C#图解教程 第十九章 LINQ
LINQ 什么是LINQLINQ提供程序 匿名类型 方法语法和查询语法查询变量查询表达式的结构 from子句join子句什么是联结查询主体中的from-let-where片段 from子句let子句w ...
- Python Cookbook(第3版)中文版:15.15 C字符串转换为Python字符串
15.15 C字符串转换为Python字符串¶ 问题¶ 怎样将C中的字符串转换为Python字节或一个字符串对象? 解决方案¶ C字符串使用一对 char * 和 int 来表示, 你需要决定字符串到 ...
- 【NOIP2016】蚯蚓(队列,单调性)
题目不再重复叙述 请参考: 洛谷 CJOJ 题解 先来说说非完美解法,也是我去年考场上的做法 考虑一下每一只蚯蚓增加的长度, 这个值并不需要每一次依次增加, 用一个变量维护即可,每次取出蚯蚓就加上这个 ...