Don编码的方法论重构准则:手工编写代码,更能程序员

Don Roberts 提出的重构指南:

第一次做某事,就去做;第二次你做类似的事情,但无论如何你都可以做到;第三次做类似的事情,你应该重构。

编码也是如此,在多次编写类似的代码时,我们需要考虑是否有办法提高编码速度。作者多年致力于敏捷开发,总结了一套帮助程序员“快速、优质、高效”编码的编码方法。

手工编码

大多数刚学过Java的程序员都会怀着崇敬之情在开发工具上逐字打出如下代码:

public class Test {
public static void main(String[] args) {
System.out.println("Hello world!");
}
}

是的,这就是经典的“Hello world”,也是大多数人手写的第一个程序。

手写代码更能体现程序员的基本素质。有很多公司把计算机编程考试作为面试的重要手段之一。受访者需要根据题目要求选择熟悉的编程工具(如Eclipse),手动编写代码并调试运行。整个过程不能通过网络搜索答案,不能查看在线帮助文​​档,要求面试者手写代码,主要考查面试者手写代码的能力——语法、函数、逻辑、思维、算法和动手能力。

手写代码是一个优秀程序员必须具备的基本能力。手写代码就像用笔写文章。语法是选择单词和句子的方法,函数是组成文章的单词和句子,类库是基于经典的轶事,架构是写作风格,函数是写文章的目的,算法是组织。语言的逻辑……所以,只要掌握一门编程语言的语法,学习一堆基础类库的功能,参考一些需要的第三方类库,选择成熟稳定的架构,明确产品需要的功能,选择实现逻辑的算法……手写代码就像写文章一样简单。

复制粘贴代码

俗话说:“熟唐诗三百首,即使不会写诗,也能唱歌。” 编码也是如此。编码的第一步是模仿,也就是简单的“复制代码”——复制粘贴代码。复制粘贴代码是一门艺术,如果使用得当,工作量会更大。但是,没有经过测试的东西毕竟是不可信的。当我们看到自己需要的代码,在复制粘贴之前,我们都需要仔细研究,思考,详细识别……很多东西都是仁者见仁,智者见智,适合的适用于其他场景,但不一定适合您的场景。. 作为一名合格的程序员,千万不能盲目“用教条”。

1.为什么复制粘贴代码2.复制粘贴代码会产生问题

总之,复制粘贴代码和其他编码方式一样,没有对错之分。它只是一种方法,你可以很好地使用它,也可以滥用它。如果我们使用复制和粘贴,我们必须对结果负责。

用文本替换生成的代码1.生成的代码示例

已编写的用户查询相关代码:

/** 查询用户服务函数 */
public PageData queryUser(QueryUserParameterVO parameter) {
Long totalCount = userDAO.countByParameter(parameter);
List userList = ;
if (Objects.non(totalCount) && totalCount.compareTo(0L) > 0) {
userList = userDAO.queryByParameter(parameter);
}
return new PageData<>(totalCount, userList);
}

/** 查询用户控制器函数 */
@RequestMapping(path = "/queryUser", method = RequestMethod.POST)
public Result> queryUser(@Valid @RequestBody QueryUserParameterVO parameter) {
PageData pageData = userService.queryUser(parameter);
return Result.success(pageData);
}

如果我们要写公司查询相关代码,代码形式类似于用户查询,替换关系整理如下:

使用记事本、EditPlus等文本编辑器,选择区分大小写,进行正常的文本替换。最终结果如下:

/** 查询公司服务函数 */
public PageData queryCompany(QueryCompanyParameterVO parameter) {
Long totalCount = companyDAO.countByParameter(parameter);
List companyList = ;
if (Objects.non(totalCount) && totalCount.compareTo(0L) > 0) {
companyList = companyDAO.queryByParameter(parameter);
}
return new PageData<>(totalCount, companyList);
}

/** 查询公司控制器函数 */
@RequestMapping(path = "/queryCompany", method = RequestMethod.POST)
public Result> queryCompany(@Valid @RequestBody QueryCompanyParameterVO parameter) {
PageData pageData = companyService.queryCompany(parameter);
return Result.success(pageData);
}

使用文本替换生成代码,整个代码生成时间不会超过1分钟。

2.主要优点和缺点

主要优势:

主要缺点:

使用 Excel 公式生成代码

Excel 的公式功能非常强大,可以用来编写一些公式化的代码。

1.使用 Excel 公式生成模型类

将接口模型定义从 Wiki 复制到 Excel。样本数据内容如下:

编写Excel公式如下:

= "/** "&D6&IF(ISBLANK(F6), "", "("&F6&")")&" */ "&IF(E6 = "否", IF(C6 = "String", "@NotBlank", "@Not"), "")&" private "&C6&" "&B6&";"

利用公式生成代码如下:

/** 用户标识 */ @Not private Long id;
/** 用户名称 */ @NotBlank private String name;
/** 用户性别(0:未知;1:男;2:女) */ @Not private Integer sex;
/** 用户描述 */ private String description;

创建一个模型类并组织代码如下:

/** 用户DO类 */
public class UserDO {
/** 用户标识 */
@Not
private Long id;
/** 用户名称 */
@NotBlank
private String name;
/** 用户性别(0:未知;1:男;2:女) */
@Not
private Integer sex;
/** 用户描述 */
private String description;
......
}

2.使用Excel公式生成枚举类

将 WIKI 中的枚举定义复制到 Excel 中,示例数据内容如下:

编写Excel公式如下:

="/** "&D2&"("&B2&") */"&C2&"("&B2&", """&D2&"""),"

使用公式生成代码如下:

/** 空(0) */NONE(0, "空"),
/** 男(1) */MAN(1, "男"),
/** 女(2) */WOMAN(2, "女"),

创建枚举类,整理代码如下:

/** 用户性别枚举 */
public enum UserSex {
/** 枚举定义 */
/** 空(0) */
NONE(0, "空"),
/** 男(1) */
MAN(1, "男"),
/** 女(2) */
WOMAN(2, "女");
......
}

3.使用Excel公式生成数据库语句

Excel中组织的公司列表如下,需要组织成SQL语句直接插入数据库:

编写Excel公式如下:

= "('"&B2&"', '"&C2&"', '"&D2&"', '"&E2&"'),"

使用公式生成SQL如下:

('高德', '首开大厦', '(010)11111111', 'gaode@xxx.com'),
('阿里云', '绿地中心', '(010)22222222', 'aliyun@xxx.com'),
('菜鸟', '阿里中心', '(010)33333333', 'cainiao@xxx.com'),

添加 into 语句头并组织 SQL 如下:

insert into t_company(name, address, phone, email) values
('高德', '首开大厦', '(010)11111111', 'gaode@xxx.com'),
('阿里云', '绿地中心', '(010)22222222', 'aliyun@xxx.com'),
('菜鸟', '阿里中心', '(010)33333333', 'cainiao@xxx.com');

4.主要优点和缺点

主要优势:

主要缺点:

使用工具生成代码

图片[1]-Don编码的方法论重构准则:手工编写代码,更能程序员-老王博客

使用工具生成代码,顾名思义,就是借用现有的工具来生成代码。很多开发工具都提供了一些生成代码的工具,比如:生成构造函数、重载基类/接口函数、生成Getter/Setter函数、生成toString函数……可以避免大量的手工打字。还有一些代码生成插件,也可以生成满足某些应用场景的代码。

这里我们以mybatis-generator插件生成代码为例介绍如何使用该工具生成代码。

1.安装并运行插件

具体方法这里不再赘述,大家可以自行搜索文档了解。

2.生成代码示例2.1.生成模型类代码

文件 User.java 内容:

......
public class User {
private Long id;
private String user;
private String password;
private Integer age;
......
}

2.2.生成映射接口代码

文件 UserMapper.java 内容:

......
public interface UserMapper {
User selectByPrimaryKey(Long id);
......
}

2.3.生成映射XML代码

文件 UserMapper.xml 内容:

......
apper namespace="com.test.dao.UserMapper" >







id, user, password, age


......
apper>

3.主要优点和缺点

主要优势:

主要缺点:

用代码生成代码

从代码生成代码就是自己编写代码并以自己的格式生成代码。下面以生成基于MyBatis的数据库访问代码为例。

1.查询表单信息

首先,我们需要从数据库中获取生成代码所需的表和列相关信息。

1.1.查询表信息

查询表信息语句:

select t.table_name as '表名称'
, t.table_comment as '表备注'
from information_schema.tables t
where t.table_schema = ?
and t.table_type = 'BASE TABLE'
and t.table_name = ?;

其中,第一个问号指定数据库名,第二个问号指定表名。

查询表信息结果:

1.2.查询列信息

查询列信息语句:

select c.column_name as '列名称'
, c.column_comment as '列备注'
, c.data_type as '数据类型'
, c.character_maximum_length as '字符长度'
, c.numeric_precision as '数字精度'
, c.numeric_scale as '数字范围'
, c.column_default as ''
, c.is_able as '是否可空'
, c.column_key as '列键名'
from information_schema.columns c
where c.table_schema = ?
and c.table_name = ?
order by c.ordinal_position;

其中百度富文本编辑器赋值,第一个问号指定数据库名,第二个问号指定表名。

查询列信息结果:

2.编写生成的代码2.1.编写生成的模型类代码

/** 生成模型类文件函数 */
private void generateModelClassFile(File dir, Table table, List columnList) throws Exception {
try (PrintWriter writer = new PrintWriter(new File(dir, className + "DO.java"))) {
String className = getClassName(table.getTableName);
String classComments = getClassComment(table.getTableComment);
writer.println("package " + groupName + "." + systemName + ".database;");
......
writer.println("/** " + classComments + "DO类 */");
writer.println("@Getter");
writer.println("@Setter");
writer.println("@ToString");
writer.println("public class " + className + "DO {");
for (Column column : columnList) {
String fieldType = getFieldType(column);
String fieldName = getFieldName(column.getColumnName);
String fieldComment = getFieldComment(column);
writer.println("\t/** " + fieldComment + " */");
writer.println("\tprivate " + fieldType + " " + fieldName + ";");
}
writer.println("}");
}
}

2.2.编写生成DAO接口代码

/** 生成DAO接口文件函数 */
private void generateDaoInterfaceFile(File dir, Table table, List columnList, List pkColumnList) throws Exception {
try (PrintWriter writer = new PrintWriter(new File(dir, className + "DAO.java"))) {
String className = getClassName(table.getTableName);
String classComments = getClassComment(table.getTableComment);
writer.println("package " + groupName + "." + systemName + ".database;");
......
writer.println("/** " + classComments + "DAO接口 */");
writer.println("public interface " + className + "DAO {");
writer.println("\t/** 获取" + classComments + "函数 */");
writer.print("\tpublic " + className + "DO get(");
boolean isFirst = true;
for (Column pkColumn : pkColumnList) {
if (!isFirst) {
writer.print(", ");
} else {
isFirst = false;
}
String fieldType = getFieldType(pkColumn);
String fieldName = getFieldName(pkColumn.getColumnName);
writer.print("@Param(\"" + fieldName + "\") " + fieldType + " " + fieldName);
}
writer.println(");");
......
writer.println("}");
}
}

2.3.编写并生成DAO映射代码

/** 生成DAO映射文件函数 */
private void generateDaoMapperFile(File dir, Table table, List columnList, List pkColumnList) throws Exception {
try (PrintWriter writer = new PrintWriter(new File(dir, className + "DAO.xml"))) {
String className = getClassName(table.getTableName);
String classComments = getClassComment(table.getTableComment);
writer.println("");
......
writer.println("");
writer.println("apper namespace=\"" + groupName + "." + systemName + ".database." + className + "DAO\">");
writer.println("\t");
writer.println("\t");
if (CollectionUtils.isNotEmpty(columnList)) {
boolean isFirst = true;
String columnName = getColumnName(pkColumn.getColumnName);
for (Column column : columnList) {
if (isFirst) {
isFirst = false;
writer.println("\t\t" + columnName);
} else {
writer.println("\t\t, " + columnName);
}
}
}
writer.println("\t
");
writer.println("\t");
writer.println("\t");
writer.println("
apper>");
}
}

3.生成相关代码3.1.生成模型类代码

/** 组织公司DO类 */
@Getter
@Setter
@ToString
public class OrgCompanyDO {
/** 公司标识 */
private Long id;
/** 公司名称 */
private String name;
/** 联系地址 */
private String address;
/** 公司描述 */
private String description;
}

3.2.生成的DAO接口代码

/** 组织公司DAO接口 */
public interface OrgCompanyDAO {
/** 获取组织公司函数 */
public OrgCompanyDO get(@Param("id") Long id);
}

3.3.生成的DAO映射代码


apper namespace="xxx.database.OrgCompanyDAO">


id
, name
, address
, description



apper>

3.主要优点和缺点

主要优势:

主要缺点:

绝招:无招胜

编码的终极方法,是直接对电脑说需求,然后电脑自动生成代码吗?当未来技术发展到一定程度时,这种情况可能会成为现实。然而,目前这是不现实的。在现实中,如果你想做到“大嘴巴,代码就来”,除非你是老板、产品经理或技术经理。

编码的终极方法是“无招胜有招”,“无招”并不是说你不注意“招”,而是不拘泥于某个“招”百度富文本编辑器赋值,找到触手可及的合适“动作”是恰当的。本文所列举的各种编码方式不高不低,只看合适不合适。因此,灵活运用各种编码方式是编码的终极方法。

代码规范化

在上面的各种编码方法中,很多都需要手写示例代码。如果你的代码不遵循代码规范,就很难找到代码之间的共同点,抽象出可以作为标准的示例代码;如果标准示例代码不符合代码规范,必然会导致生成的代码。代码规范,所以这些违规行为被放大了十倍、一百倍甚至一千倍。因此,代码规范化是编码的重中之重。

作者简介:陈昌义,本名昌义,高德地图技术专家。2018年加入阿里巴巴,一直从事地图数据采集工作。

5G进入元年,物联网发展越来越火!

你有没有人知道的天赋;不要让您的物联网项目默默无闻!

继首届AI优秀案例评选活动后,2019年案例评选活动再次升级。CSDN将评选出TOP 30优秀物联网案例,赶快扫码参与评选吧!重磅福利等着你!

© 版权声明
THE END
喜欢就支持一下吧
点赞0
分享
评论 抢沙发

请登录后发表评论