我是一名来自蚂蚁金服-保险事业群的前端工程师,在一线大厂的业务部门写代码,非常辛苦但也非常充实。业务代码不同于框架代码、个人项目或者开源项目,它的特点在于逻辑复杂、前后依赖多、可复用性差、迭代周期短,今天辛辛苦苦写的代码,上线运行一周可能就下线了。能熟练书写框架代码、构建底层基础设施的工程师不一定能写好业务代码。
有人说,业务代码无非就是按部就班,优不优雅?who care?。但实际业务规则复杂得多,不是依葫芦画瓢就能轻松解决的,写一段糟糕的代码,可能要用双倍的时间去发现和解决问题,麻烦了自己、也难受了和你并肩作战的战友。
有时候为了减少重复开发的成本,反复提炼和沉淀有复用价值的功能,就需要我们对业务代码进行合理抽象、甚至精雕细琢,要把业务代码写得优雅并非易事。我一直认为,程序设计和搬砖的最大区别在于设计二字,写代码也是一门艺术活。今天就借此机会,站在前端工程师的视角,给大家分享关于书写业务代码的最佳实践。
渐进式重构是不断地对既有代码进行抽象、分离和组合。做代码重构之前需要回答两个问题:
1、什么样的代码需要重构?
2、何时进行重构?
设计不是一蹴而就的,有时候写着写着才发现某些代码可以抽离出来单独使用,需要重构的代码需要满足几个条件:
1、代码后期可复用
2、代码无副作用
3、代码逻辑单一
过早重构可能会因需求变化太快白白浪费许多时间;过晚重构会因为代码逻辑复杂、相似代码积压过多导致变更风险太高,难以维护。渐进式重构如下图所示(红色部分为增加的代码):
首先我们在同一个源文件中新增功能,发现部分代码无副作用且可分离,因此在同一个文件中进行代码分割,形成许多功能单一的模块。如此往复后发现单文件的体积越来越大,此时就可以将功能相关联的模块抽出来放到单独的文件中统一管理,如 helpers、components、constants 等等。
高内聚低耦合一直是软件设计领域里亘古不变的话题,重构的目标是提高代码的内聚性,降低各功能间的耦合程度,降低后期维护成本,特别是写业务代码,这一点相当重要。
举个栗子,比如新需求希望在现有的产品页面上增加发红包功能,以吸引用户开通某个功能,按照正常逻辑,我需要:
1、在当前页面中引入相关依赖
2、初始化,查询红包相关信息
3、用户点击时,触发红包发送
白色部分表示上个版本的代码,红色部分表示完成这个需求需要变更的代码:
这样一来,这个发红包功能就和以前的代码严重耦合,如果这是个只需要上线一周的临时需求,下线代码的时候就是一个高风险的动作;如果上线运行期间还需要对产品页面进行迭代,越往后就越搞不清楚谁是谁了。合理的设计应该是下面这个样子的:
将和产品代码无关的功能性代码拆分出来,放到另一个文件中内部维护好整个生命周期状态,对外只暴露少量的接口或是方法,这样一来对产品页面的改造只需要:
1、引入红包组件
2、用户点击时,调用红包组件的发奖方法
这样的变更是极小的、明确的、可控的。换句话说,整个红包功能是高内聚的,与产品代码是低耦合的。这样实践也带来另一个好处:我得到了一个可复用的红包组件!
业务需求是多变的,写出来的代码也是如此,频繁地抽象很可能导致过度设计,一个抽象很可能随着迭代次数的增多变得十分复杂。在存在多个变量的分支业务场景,比如同时包含活动是否过期、是否已参加活动、是否完成一次任务这样的情况,会存在多个嵌套 if-else 结构,这时将代码冗余设计是个不错的选择。下面举一个例子来说明什么是合理冗余:
e.g. 有这样一个需求,一开始很简单,需要设计两个运营展位:
那么抽象一个组件:
const Item = ({ title, content }) => (
<div>
<h4>{title}</h4>
<p>{content}</p>
</div>
);
现在需求要求在第一个展位的标题上增加热文标记:
也很容易:
const Item = ({ title, content }, index) => (
<div>
<h4>{title}{index === 0 && <span>hot</span>}</h4>
<p>{content}</p>
</div>
);
需求又变了,要求:在第一个展位去掉内容,并且在下方加个按钮;第二个展位的标题右边增加一个超链接以及增加一个副标题:
这下有点恶心了:
const Item = ({ title, content }, index) => (
<div>
<h4>
{title}
{index === 0 && <span>hot</span>}
{index === 1 && <a href="xxx">去看看</a>}
</h4>
{index === 1 && <h5>副标题</h5>}
<p>
{index !== 0 && content}
{index === 0 && <button>领福利<button>}
</p>
</div>
);
可以看到,之前抽象的好好的,现在需求一变,代码就面目全非了,中间混杂着两个状态(第一个、第二个)的判断逻辑。实际情况很可能比这个更复杂,在多状态交织逻辑难以通过一套代码表达清楚时,进行合理冗余就是个不错的选择,将上面的例子用两个 if 重写如下:
// 第一个展位
if (index === 0) {
return (
<div>
<h4>标题一<span>hot</span></h4>
<p><button>领福利<button></p>
</div>
);
}
// 第二个展位
if (index === 1) {
return (
<div>
<h4>标题二<a href="xxx">去看看</a></h4>
<h5>副标题</h5>
<p>内容</p>
</div>
);
}
合理冗余其实也是一种重构,根据业务逻辑和代码规模,做相似抽象还是代码冗余,这其实也是渐进式重构的一种体现。无论采用何种方式,只要能把业务逻辑表达清楚,让代码始终保持良好的可读性和可维护性,就OK。
下面介绍一个过度抽象的例子。
在 JavaScript 代码中进行深度抽象有时并非好事,有 OOP(面向对象编程)背景的同学很容易先入为主设计:所有数据结构都想封装成一个类 (Class) 。实际上 Class 在 JavaScript 中是个不好的设计,它并非真正的类。几年前,我曾看到一位 Java 转前端的同学写出了类似这样的代码:
class DataItem {
constructor(id, name, value) {
this.id = id;
this.name = name;
this.value = value;
}
}
class DataCollection {
constructor() {
this.items = new Array();
}
insert(item) {
this.items.push(item);
}
}
const item1 = new DataItem(1, 'name1', 100);
const item2 = new DataItem(2, 'name2', 200);
const list = new DataCollection();
list.insert(item1);
list.insert(item2);
...
一股浓浓的 Java 味道扑面而来。上面的代码并没有发挥出 JavaScript 的语言优势,也增加了不少理解成本,如果用面向对象编程的思路去写前端代码,特别是业务代码,可真是一场噩梦。正确的写法如下:
const list = [{
id: 1,
name: 'name1',
value: 100
}, {
id: 2,
name: 'name2',
value: 200
}];
由于 JS 属于弱类型语言,弱类型语言就要发挥弱类型的优势,无需过多类型定义和 Class 抽象,用最原始的 object 和 function 足以胜任从简单到复杂的业务场景。这里特别想提及前端所熟知的 Redux 状态管理器,Redux 中,state 就是普通的 object,reducer 就是普通的 function,action 也是普通的 object,不加任何类型约束。因为简单,所以强大。
用弱类型语言编程意味着无需编译,无需编译的语言天生存在一个问题是在运行前缺少必要的类型检查,将问题暴露在运行时往往会导致非常严重的故障。这就要求开发者能在写代码的阶段严格保证代码质量,特别是写业务代码。
集成开发环境(IDE)对 JavaScript 代码的智能提示能力有限,很多时候不能通过 IDE 查找某个变量或者函数的所有引用,这时就要善用 Ctrl + F 进行全局查找来保证自己的单点变更不会影响到其他地方。如果使用 TypeScript,在类型检查、引用查找上的帮助会更好。
今天给大家分享了关于书写业务代码的一些实践经验:对代码进行渐进式重构是提升代码健壮性的有力武器;设计高内聚低耦合的代码可以让你在做需求的过程中沉淀出一套通用解决方案;合理冗余可以简化复杂的场景,让开发变得高效、测试变得容易;拒绝过度抽象,拥抱简单,灵活变化。保持 眼观六路 的好习惯能让代码质量提升一个台阶。
最后,希望大家能在实际开发过程中去体会和学习,不断思考和总结,将业务代码写优雅,是个很大的挑战。
我们是蚂蚁保险体验技术团队,来自蚂蚁金服保险事业群。我们是一个年轻的团队(没有历史技术栈包袱),目前平均年龄92年(去除一个最高分8x年-团队leader,去除一个最低分97年-实习小老弟)。我们支持了阿里集团几乎所有的保险业务。18年我们产出的相互宝轰动保险界,19年我们更有多个重量级项目筹备动员中。现伴随着事业群的高速发展,团队也在迅速扩张,欢迎各位前端高手加入我们~
我们希望你是:技术上基础扎实、某领域深入(Node/互动营销/数据可视化等);学习上善于沉淀、持续学习;性格上乐观开朗、活泼外向。
如有兴趣加入我们,欢迎发送简历至邮箱:yiyuan.lpy@antfin.com
Original url: Access
Created at: 2019-05-09 23:59:40
Category: default
Tags: none
未标明原创文章均为采集,版权归作者所有,转载无需和我联系,请注明原出处,南摩阿彌陀佛,知识,不只知道,要得到
java windows火焰图_mob64ca12ec8020的技术博客_51CTO博客 - 在windows下不可行,不知道作者是怎样搞的 监听SpringBoot 服务启动成功事件并打印信息_监听springboot启动完毕-CSDN博客 SpringBoot中就绪探针和存活探针_management.endpoint.health.probes.enabled-CSDN博客 u2u转换板 - 嘉立创EDA开源硬件平台 Spring Boot 项目的轻量级 HTTP 客户端 retrofit 框架,快来试试它!_Java精选-CSDN博客 手把手教你打造一套最牛的知识笔记管理系统! - 知乎 - 想法有重合-理论可参考 安宇雨 闲鱼 机械键盘 客制化 开贴记录 文本 linux 使用find命令查找包含某字符串的文件_beijihukk的博客-CSDN博客_find 查找字符串 ---- mac 也适用 安宇雨 打字音 记录集合 B站 bilibili 自行搭建 开坑 真正的客制化 安宇雨 黑苹果开坑 查找工具包maven pom 引用地 工具网站 Dantelis 介绍的玩轴入坑攻略 --- 关于轴的一些说法 --- 非官方 ---- 心得而已 --- 长期开坑更新 [本人问题][新开坑位]关于自动化测试的工具与平台应用 机械键盘 开团 网站记录 -- 能做一个收集的程序就好了 不过现在没时间 -- 信息大多是在群里发的 - 你要让垃圾佬 都去一个地方看难度也是很大的 精神支柱 [超级前台]sprinbboot maven superdesk-app 记录 [信息有用] [环境准备] [基本完成] [sebp/elk] 给已创建的Docker容器增加新的端口映射 - qq_30599553的博客 - CSDN博客 [正在研究] Elasticsearch, Logstash, Kibana (ELK) Docker image documentation elasticsearch centos 安装记录 及 启动手记 正式服务器 39 elasticsearch 问题合集 不断更新 6.1.1 | 6.5.1 两个版本 博客程序 - 测试 - bug记录 等等问题 laravel的启动过程解析 - lpfuture - 博客园 OAuth2 Server PHP 用 Laravel 搭建带 OAuth2 验证的 RESTful 服务 | Laravel China 社区 - 高品质的 Laravel 和 PHP 开发者社区 利用Laravel 搭建oauth2 API接口 附 Unauthenticated 解决办法 - 煮茶的博客 - SegmentFault 思否 使用 OAuth2-Server-php 搭建 OAuth2 Server - 午时的海 - 博客园 基于PHP构建OAuth 2.0 服务端 认证平台 - Endv - 博客园 Laravel 的 Artisan 命令行工具 Laravel 的文件系统和云存储功能集成 浅谈Chromium中的设计模式--终--Observer模式 浅谈Chromium中的设计模式--二--pre/post和Delegate模式 浅谈Chromium中的设计模式--一--Chromium中模块分层和进程模型 DeepMind 4 Hacking Yourself README.md update 20211011
Laravel China 简书 知乎 博客园 CSDN博客 开源中国 Go Further Ryan是菜鸟 | LNMP技术栈笔记 云栖社区-阿里云 Netflix技术博客 Techie Delight Linkedin技术博客 Dropbox技术博客 Facebook技术博客 淘宝中间件团队 美团技术博客 360技术博客 古巷博客 - 一个专注于分享的不正常博客 软件测试知识传播 - 测试窝 有赞技术团队 阮一峰 语雀 静觅丨崔庆才的个人博客 软件测试从业者综合能力提升 - isTester IBM Java 开发 使用开放 Java 生态系统开发现代应用程序 pengdai 一个强大的博主 HTML5资源教程 | 分享HTML5开发资源和开发教程 蘑菇博客 - 专注于技术分享的博客平台 个人博客-leapMie 流星007 CSDN博客 - 舍其小伙伴 稀土掘金 Go 技术论坛 | Golang / Go 语言中国知识社区
最新评论