从Simple Design入手让代码易修改

人们擅长处理好简单的事情,遇到复杂、繁杂的事情可以通过拆分成为易于处理的简单事情。

《技术人员如何拥抱变化?》那边文章中提到了“Simple Design”。那么如何让Simple Design来让代码易修改呢?

先回顾下Simple Design指什么。

1. 实现功能;
2. 揭示意图;
3. 消除重复;
4. 最少元素

如果你真的实践过,但是感觉没有什么效果,可能是遇到了下面两个问题:

  1. 每次按照上面的流程做感觉一点都不人性,我觉得我们如何使用的问题;
  2. 按照Simple Design的推荐做了,代码易修改上确实有一定的提升,但是似乎又止步不前进了。

下面我们来分析以上两个问题:

1. 每次按照上面的流程做感觉一点都不人性,我觉得我们如何使用的问题;

当我们将一个方法应用到实践中时,其实需要做到两点:

  1. 正确理解方法的本身的目的和内容;
  2. 刻意练习后,根据实际场景灵活应用。

下面根据对Simple Design的熟悉程度,列举了两个使用Simple Design的实践过程。

  1. 对Simple Design并不熟悉,刚接触Simple Design或者平时Coding时有时会记得有时根本就忘了。
  2. 对Simple Design已经非常熟悉。

针对上面两场场景,我们看看如何应用Simple Design:

1.1 对Simple Design并不熟悉,刚接触Simple Design或者平时Coding时有时会记得有时根本就忘了。

对Simple Design不熟悉,那么就解决不熟悉的问题。我们可以按照下图的优先级来进行练习和应用。

simple.png

首先实现业务功能,应为价值是我们做所有事情的核心,但并不能仅止于实现业务,因为后续是否易于修改取决于当前是否能够保持代码简单。

所以,在实现业务之后利用2分钟来review一遍自己的的代码。看是否代码揭示了意图,是否有重复代码存在。如果有,那么就进行修改让代码揭示意图、消除重复代码。

为了易于操作,我们建议先揭示意图,然后消除重复代码。

我们举个实际例子:

@GetMapping("/users")
public Map<String, Object> getUsers() {
    List<User> us = userService.getAllUsers();
    
    List<UserDTO> uds = usersMapper.toDtoList(us);
    
    Map<String, Object> r = new HashMap<>();
    r.put("status", "success");
    r.put("users", uds);
    return r;
}

很显然上面的代码已经实现了业务功能。

我们看看是否揭示了意图,揭示意图指的是业务意图。

public Map<String, Object> getUsers() {

通过第1行和第2行,通过方法名我们知道应该返回的user列表。但是返沪指却是Map类型,造成了疑问1:为什么返回Map呢?

再继续往下读,因为方法实现很短,我们能够快速知道方法内做了什么事。

先看下倒数第2行到倒数第5行,

@GetMapping("/users")
public Map<String, Object> getUsers() {
    ...
    
    Map<String, Object> r = new HashMap<>();
    r.put("status", "success");
    r.put("users", uds);
    return r;
}

通过Map中的Key原来是期望返回status和users两个信息。第二个问题是Map类型的变量名用了r表示,这是一个显而易见的问题,后面会同意说变量命名问题。

返回status估计是想告诉调用方处理正常,这里开发者如果对HTTP状态码熟悉,完全可以使用HTTP状态码的200来表示请求处理正常,所以这里可以直接返回List<User>,而不用使用和方法名格格不入的一个Map类型。修改后的代码如下;

@GetMapping("/users")
public List<Users> getUsers() {
    ...
    
    return usd;
}

细心的同学或许早就发现,第3行、第5行的变量名的问题,以及刚才的Map类型的变量使用的是r表示。

    ...
    List<User> us = userService.getAllUsers();
    List<UserDTO> uds = usersMapper.toDtoList(us);
    Map<String, Object> r = new HashMap<>();
    ...

获取有人觉得这样写省时间,毕竟开发时间有限。但是却暴露了一个对开发工具不熟悉的问题。如果真的是为了省时间,可以直接使用自动生成变量的快捷键,自动生成的命名不单单命名规范而且用时最短。这里我们将变量名重新命名后,代码如下:

@GetMapping("/users")
public Map<String, Object> getUsers() {
    List<User> users = userService.getAllUsers();
    List<UserDTO> userDTOs = usersMapper.toDtoList(users);
    return userDTOs;
}

结束了吗?还没有。

我们发现中间的这些变量users、userDTOs,虽然定义了,但是均使用了一次,所以我们针对这个问题可以Inline。Inline后的代码如下:

@GetMapping("/users")
public Map<String, Object> getUsers() {
    return usersMapper.toDtoList(userService.getAllUsers());
}

Inline后发现仅剩下一行,为了让代码更加具有可读性。我们增加一些刻意的换行。

@GetMapping("/users")
public Map<String, Object> getUsers() {
    return usersMapper.toDtoList(
                userService.getAllUsers()
    );
}

到现在,再看看这段代码是不是非常易读了,这也就是在上一遍文章《为什么要关注代码的可读性?》讲述的,可读性提升了降低了代码的修改成本。

【误区:】

关于消除重复上,很多开发着只能识别出工具类,提前或者有意识的创建工具类。但是重复不仅仅是指生成公共工具类这样。同时还包括业务上的重复、业务代码中的重复、技术上的重复。上面的例子中就是status其实就是自定义和HTTP 状态码上的重复。如果有业务需要我们当然建议添加status,但是如果只是告诉接口调用方状态,那么建议直接使用HTTP状态码即可。

1.2 对Simple Design已经非常熟悉。

当对Simple Design非常熟悉之后,其实并不是按照之前的说的顺序去做的。如下图:

在编码时就会不自觉的考虑到揭示意图、消除重复、最少元素,很有可能Simple Design中的结构动作一气呵成。当完成后提交代后提交代码前的Review是,同样按照Simple Design中的建议内容去查看刚才的代码是否还有改进的空间。

2. 按照Simple Design的推荐做了,代码易修改上确实有一定的提升,但是似乎又止步不前进了。

在现有能力下,使用Simple Design可能能为代码带来一些改善。但随着软件越来越复杂,你或许会发现依然有很多不易修改的代码出现。出了我们之前《技术人员如何拥抱变化?》说的:使用设计原则发现问题,使用设计模式解决问题。还有两方面来提升代码的易修改性。

  1. 识别代码的Bad Smell
  2. 熟悉重构手法。

下面是坏味道和重构手法速查表:

坏味道(英) 坏味道(中) 重构手法
Alternative Classes with Different Interfaces 异曲同工的类 改变函数声明,搬移函数,提炼超类
Comments 注释 提炼函数,改变函数声明,引入断言
Data Class 纯数据类 封装记录,移除设值函数,搬移函数,提炼函数,拆分阶段
Data Clumps 数据泥团 提炼类,引入参数对象,保持对象完整
Divergent Change 发散式变化 提炼函数,搬移函数,提炼函数,提炼类
Duplicated Code 重复代码 提炼函数,移动语句,函数上移
Feature Envy 依恋情结 搬移函数,提炼函数
Global Data 全局数据 封装变量
Insider Trading 内幕交易 搬移函数,搬移字段,隐藏委托关系,以委托取代子类,以委托取代超类
Large Class 过大的类 提炼类,提炼超类,以子类取代类型码
Lazy element 冗赘的元素 内联函数,内联类,折叠集成体系
Long Function 过长函数 提炼函数,以查询取代历史变量,引入参数对象,保持对象完整,以命令取代函数,分解条件表达式,以多态取代条件表但是,拆分循环
Long Parameters List 过长参数列 以查询取代参数,保持对象完整,引入参数对象,移除标记参数,函数组合成类
Loops 循环语句 以管道取代循环
Message Chains 过长的消息链 隐藏委托关系,提炼函数,搬移函数
Middle Man 中间人 移除中间人,内联函数,以委托取代超类,以委托取代子类
Mutable Data 可变数据 封装变量,拆分变量,移除语句,提炼函数,将查询函数和修改函数分离,移除设值函数,以查询取代派生变量,函数组合成类,函数组合成变换,将引用对象改为值对象。
Mysterious Name 神秘命名 改变函数声明,变量改名,字段改名。
Primitive Obsession 基本类型偏执 以对象取代基本类型,以子类取代类型码,以多态取代条件表达式,提炼类,引入参数对象。
Refused Bequest 被拒绝的遗赠 函数下移,字段下移,以委托取代子类,以委托取代超类。
Repeated Switches 重复的Switch 以多态取代条件表达式
Shotgun Surgery 霰弹式修改 提炼函数,搬移字段,函数组合成类,函数组合成变换,拆分阶段,内联函数,内联类
Speculative Generality 夸夸其谈通用性 折叠集成体系,内联函数,内联类,改变函数声明,移除死代码
Temporary Field 临时字段 提炼类,搬移函数,引入特例。

3,最为重要的

读了上面的内容,最重要的还是了解后理解并实践。可以使用下面的格式列出清单后,去实践上文的内容:

在 xxx 时间内
针对 xxx 内容
计划做 xxx
并通过 xxx 来验收
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,590评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,808评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,151评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,779评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,773评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,656评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,022评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,678评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,038评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,756评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,411评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,005评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,973评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,053评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,495评论 2 343