业务代码解构利器--SWAK

简介

业务的不断发展、商品类型的不断增多、不断添加的业务需求使得闲鱼的代码出现“bad smell”——平台代码和业务代码耦合严重难以分离;业务和业务之间代码交织缺少拆解。这也是行业中的通病。为解决此类问题,闲鱼自研了一套技术框架——SWAK。本文带大家一起看看SWAK是怎么解构闲鱼代码的。

SWAK是Swiss Army Knife的简称,众所周知,瑞士军刀是一款小巧灵活、适用于多种场景的工具。在闲鱼服务端,SWAK框架也是这样一种小巧灵活、适用于多种场景的技术框架, 它所要使用的场景都具有同一个特点——多实现间的规则化执行。本文将以一个例子开篇,来详细介绍其中的概念。

多实现和规则化执行

熟悉闲鱼的朋友们应该知道,在闲鱼App里面,商品有丰富的表现形式,不妨叫做类型A、类型B和类型C,各种类型也可以有各自的子类型。每种类型的业务逻辑存在一定的共性,但是也存在部分差异——如在分享页面中,subtitle字段的展示逻辑就不尽相同:

这种单一的实现通常会被写成如下的代码:

if(A类型) {if(A1类型) {doSomething1();}else if(A2类型) {doSomething2();}
} else if(B类型) {doSomething3();
} else if(C类型) {if(C1类型) {doSomething4();}else if(C2类型) {doSomething5();}
}

类似的代码大家应该都写过不少。逻辑简单的时候写成这样无可厚非,但当逻辑开始变复杂的时候这种写法会具有较多的坏处:

  • 难以抽出公共的逻辑,代码块愈发臃肿。
  • 有较多相同点少量异同点的新类型的实现很难复用原先的代码。
  • 各个类型的代码实际上融合在一块,更改代码可能会影响到其他类型,提高上线风险和测试回归成本。
  • 对于新接手的开发人员来说,理解成本高,上手难度大,无形中降低开发效率。

按照面向对象的思想,获取title的方式对于所有类型都是一致的,应该沉淀成平台逻辑,而获取subtitle就可以抽象成一个接口方法,而类型A、类型B和类型C的宝贝都具有各自的实现而已。对于 获取subtitle这个接口方法来说,它有着多种实现。

那么什么是规则化执行呢?在上面的例子中,我们按照了商品的类型(type)进行了逻辑的分离,但通常情况下并非能分隔地如此彻底。举一个例子,运营团队的划分可能也按照商品类型(type)做划分,也有可能按照类目(category,如手机、3C数码、服饰、图书等)体系来做划分,甚至还有可能按照地域进行划分。那么一个商品可能既会受到商品类型体系的约束,又会受到类目体系的约束,还会受到地域的约束。如果几种约束不一致的话,就会产生冲突。比如subtitle字段,从类型A的视角上来看应该显示价格,在图书类目的视角下或许应该透出出版社——毕竟爱读书的人大多更关注质量而出版社是衡量质量的一个重要标准。是展示价格,还是出版社?或者都展示?如果都展示的话先展示价格还是先展示出版社?如果一行不够放下所有内容又怎么办?无论是上述的哪一种展示方式,背后都是“规则”(在设计模式里,称之为“策略”),代码也无非是按照“规则”进行编写而已。

以上的例子是多实现规则化执行的一个经典场景。类似地,如ABTest、双写等逻辑也是多实现规则化执行的应用场景。

基本思想

在上面的例子中,按照商品的类型或者按照商品的类目进行区分会产生冲突。其实无所谓类型或者类目,对于商品这个对象来说,无非是给其贴上了不同的标签而已——如一个类型A的图书类目宝贝被贴上“类型A”和“图书”两个标签。“类型A”的获取subtitle接口方法对应着一种实现,而“图书”的获取subtitle接口方法又对应着另一个实现。当一个对象被贴多个标签的时候,多个标签对应的实现就会产生冲突。

冲突的解决依赖于“规则”。“规则”最重要的两个部分是——优先级(Priority)和归约(Reduce)策略;执行的先后顺序由优先级决定,而显示第一个实现的结果、显示第二个实现的结果还是两个实现结果的拼接等都是归约策略。“规则”还可以包含如“并行执行方式”和“异常处理方式”等其他组成部分。

如上,可以得出SWAK的基本思想:

  • 分析对象所具有的标签。
  • 分离出不可变的逻辑和可变的逻辑。可变的逻辑抽象成接口。
  • 可变的逻辑根据标签的不同有多种实现。每种实现是独立的,即每种实现是互相隔离的。
  • 当对象同时具有多个标签时,使用优先级和归约策略来解决冲突问题。

值得一提的是,SWAK的基本思想借鉴自阿里巴巴中台的TMF架构,关于TMF的细节可以参考《尽在双11--阿里巴巴技术演进与超越》一书的《基于TMF框架的交易平台架构》章节。

相应地,使用SWAK框架将带来如下的好处:

  • 代码逻辑清晰,可变和不可变一目了然。
  • 代码复用度变高。
  • 可变逻辑按照标签进行隔离,单个标签的实现不会影响到其他标签的实现,降低开发和测试成本。无论是按照“类型”分还是按照类目分,对应的开发和测试同学只需要关注对应的逻辑即可。
  • 新接手的开发人员能够快速理解,轻松上手。

实现原理

相较于运行期才进行根据标签去扫描并加载实现类的方式,SWAK框架更倾向于在静态期就能分析出具有某几个标签的对象在不同的实现方法下会有着怎样的执行逻辑。一方面通过缓存可以明显降低响应时间,另一方面也便于在开发期间发现和排查问题。整体的实现原理可以分成两个部分:注册和 执行。基本流程如下:

在注册过程中,SWAK框架将会扫描文件(多实现接口、归约策略、冲突优先级采用了Java注解或者XML文件进行了配置,下面的代码示例中介绍多实现接口和其实现类是如何配置的),扫描出的结果都注册到了本地缓存中,而在执行过程中SWAK框架会从本地缓存中直接查找其所需的冲突优先级配置和归约策略等,这样有助于减少响应时间。另外,使用统一的本地缓存有助于进行“可视化的展现”——开发人员可以直观地看到并分析出程序的执行流程;产品经理也可以直观地看到哪些功能点可以方便扩展,哪些地方的优先级需要更新等等,甚至有助于需求的估时和排期。使用统一的本地缓存也为“可视化的配置”提供了可能性,结合阿里内部的Diamond或者Switch框架(轻量级的开关和动态配置项管理框架),可以无需更新代码,仅需推送配置就可以更新冲突优先级,为开发和测试提供了极大的便利。

/*** 此处用一个简单的demo演示下基本的配置,实际的业务要远比demo复杂*/
@SwakInterface(desc="获取subtitle") // 使用注解声明这是一个多实现接口
public interface SubtitleFetcher {@SwakMethodString fetchSubtitle();
}@SwakTag(tags = {"tagA"}) // 使用SwakTag绑定tagA的实现
@Component
public class TagASubtitleFetcher implements SubtitleFetcher {@Overridepublic String fetchSubtitle() {return "我是TagA";}
}@Component
@SwakTag(tags = {"tagB"}) // 使用SwakTag绑定tagB的实现
public class TagBSubtitleFetcher implements SubtitleFetcher {@Overridepublic String fetchSubtitle() {return "我是TagB";}
}

闲鱼服务端应用基本都基于Spring框架。为了便于在服务端应用上使用SWAK框架,在设计之初,我们就要求SWAK需要100%地兼容Spring框架。最终的实现版本做到了这一点,无论是业务的bean还是SWAK框架自身引入的bean,都完全由Spring容器托管。框架还使用了cglib代理了上图里执行过程中的一系列流程,完全由框架执行,对开发同学是完全透明、无感知的,使用起来如普通的单实现的接口一般,如下代码块所示。

@Autowired 
private SubtitleFetcher subtitleFetcher;//省略大段代码.......String subtitle = subtitleFetcher.fetchSubtile();//省略大段代码.......

在闲鱼的应用情况

目前,SWAK框架在闲鱼已经在商品发布和编辑的部分流程上得以应用,我们正在积极将SWAK框架扩展到到更多的流程上。下图是基于SWAK框架的商品域核心功能的改造计划。经过基于SWAK的升级改造,闲鱼商品域核心功能按照业务隔离,各业务开发同学仅需关系其对应业务的开发即可,其通用逻辑和业务隔离由基于SWAK框架的一层和二层充分保证。代码质量和开发效率将获得显著提升。

 

总结

闲鱼自研的SWAK这一多实现规则化执行框架,可以很好地解决平台代码和业务代码耦合严重难以分离、业务和业务之间代码交织缺少拆解的问题。并且SWAK 100%兼容Spring,使用方便,快速上手。名副其实地,SWAK框架就像瑞士军刀一样可以适用于多种场景,小巧方便。当然,SWAK仍在不断进化,特性和功能仍在不断丰富。类似地,在闲鱼还有很多有意思的、创造性的尝试。


原文链接
本文为云栖社区原创内容,未经允许不得转载。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/520954.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

MySQL8.0 · 优化器新特性 · Cost Model, 直方图及优化器开销优化

MySQL当前已经发布到MySQL8.0版本,在新的版本中,可以看到MySQL之前被人诟病的优化器部分做了很多的改动,由于笔者之前的工作环境是5.6,最近切换到最新的8.0版本,本文涵盖了一些本人感兴趣的和优化器相关的部分&#xf…

(Docker实战) 第4篇:Centos7 拉取和部署Redis

文章目录搭建redis搭建redis docker run --name redis -di --publish 6379:6379 redis:4.0远程验证测试: 想学习更多微服务、分布式、中间件、数据库、项目快速构建等系列技术 请访问http://gblfy.com 让我们一起进步!!!

python autohotkey_PyAutoGUI-python版的autoit/AHK

简单介绍各个图形界面自动操作的python库,类似按键精灵\autoit\ahk(autohotkey)等等这些自动化工具。这类python库不是只是用来实现自动游戏之类的程序,业界也用这些库来做GUI 自动化测试。第一推荐的库: PyAutoGUI 跨平台PyAutoGUI 在windows下无依赖&a…

阿里巴巴上线静态开源站点搭建工具 Docsite

近日,阿里巴巴在Github上线了静态开源站点搭建工具Docsite,这是一款集官网、文档、博客和社区为一体的静态开源站点的解决方案,具有简单易上手、上手不撒手的特质,同时支持react和静态渲染、PC端和移动端、支持中英文国际化、SEO、…

重磅 | 边缘计算核心技术辨析

戳蓝字“CSDN云计算”关注我们哦!作者 | 中国电信广研院责编 | 阿秃边缘计算(Edge Computing)是云计算向边缘的延伸,本文对边缘计算、雾计算、MEC、Cloudlet、分布式云等边缘计算领域相关概念和技术的定义、架构、场景等进行了比…

php请求接口两次,php curl post请求执行一次curl_exce 请求的接口确执行两次

1、php curl post请求接口,打印日志执行了一次curl_exce,但是请求的接口却重复执行两次.2、代码:$ch curl_init();if(false $ch){writeRedisLog(create_curl, $activity_id, $mobile, $user_id, , 0, curl failed to initialize);}curl_set…

(Docker实战) 第5篇:Centos7 拉取和部署搭建 NEXUS私服

文章目录搭建nexus私服1. 安装nexus3(admin/admin123)2 .配置nexus32.1 新建一个maven2(proxy)仓库2.2. 新建一个maven2(hosted)仓库2.3. 配置public仓库搭建nexus私服 1. 安装nexus3(admin/admin123) #创建文件夹,安装过程如果…

Nacos发布 v0.2 版本,无缝支持 Spring Cloud 微服务生态及高可用集群模式

近日,阿里巴巴新开源项目Nacos 发布了 v0.2 版本,该版本开始支持完整的Spring生态技术栈,这包括 Spring Framework、Spring Boot和Spring Cloud。 为了让更多的Spring用户可以在生产上基于 Nacos 做微服务平台的服务发现、配置管理、服务管控…

python中的def语句输出1000以内的回文_各种方法测试回文的性能[Python]

使用timeit模块进行速度测试,使用profile模块进行性能统计,使用dis模块进行字节码反汇编.下面的脚本演示了如何使用模块.从输出中注意到的一件事是函数调用的数量会影响整体性能(当然,字节码指令的数量也是如此).希望,(以及更多实验)应该为您提供有关如何提高功能效率的足够线索…

是时候展现真正的技术了!4道程序员智力题你能对几道| IT巨能唠

程序员对很多人来说那就是个神秘组织,高薪、加班多都是他们的代名词。但是,大家好像还忘了一点,那就是他们也绝对聪明!黑客、代码天才、编程老手……层出不穷,晦涩的计算机难题也是分分钟搞定,想想就令人神…

阿里关涛谈大规模计算—从数字化阿里到数字化城市的进化

在刚刚结束的2018杭州云栖大会上,阿里巴巴通用计算平台负责人,阿里巴巴计算平台资深技术专家关涛从计算力,联合计算,智能化,企业级服务能力四个方面详细介绍阿里巴巴统一的超大规模数据计算平台MaxCompute的探索与实践…

java double add,Java中的DoubleStream.Builder add()方法

add()Java中DoubleStream.Builder类的方法将元素添加到正在构建的流中。该方法返回此构建器。语法如下default DoubleStream.Builder add(double ele)此处,ele是要添加到此流中的元素。要在Java中使用DoubleStream.Builder类,请导入以下包import java.ut…

解决Linux操作系统下AES解密失败的问题

现象描述: windows上加解密正常,linux上加密正常,解密时发生如下异常: javax.crypto.BadPaddingException: Given final block not properly padded at com.sun.crypto.provider.SunJCE_f.b(DashoA13*…) at com.sun.crypto.prov…

深入Spring Boot:利用Arthas排查NoSuchMethodError

前言 有时spring boot应用会遇到java.lang.NoSuchMethodError的问题,下面以具体的demo来说明怎样利用arthas来排查。 Demo: https://github.com/hengyunabc/spring-boot-inside/tree/master/demo-NoSuchMethodError 在应用的main函数里catch住异常,保…

15年大厂经历!大佬总结:0基础如何学习Python?

在学习之前,你一定要知道你的学习目标是什么。现在市面上有太多人鼓吹“Python太火了”、“Python第一”。但是,注意,“火”、“第一”一定不能成为你学习的理由,千万别火急火燎的随大流。正确做法是,看看市面上的真正…

STL体系结构概述

文章目录 STL是什么?STL的六大组件STL的实现版本额外补充一、容器范围区间二、容器结构与分类序列式容器关联容器有序关联容器不定序关联容器 参考 本文将是STL系列的第一篇文章,主要参考《STL源码剖析》,辅以网络博文,不定时更新…

我所理解的工程师文化

对于什么是工程师文化,很多人都能说出很多关键词,比如:匠心,创新,专业,担当,开放…… 然而如果要用一句话来描述什么是工程师文化,如何判断一家公司是不是一家工程师文化的公司&…

matlab中的libsvm怎么录入数据啊,LibSVM在MATLAB中使用时的几个问题

在科研中需要用到支持向量机(Support Vector Machines, SVM)来进行分类,而目前比较成熟的用于实现SVM的软件包则首推LibSVM。LibSVM目前的版本已经能直接在MATLAB中使用了,虽然MATLAB已经提供了诸如svmtrain等SVM相关的函数,可是相比LibSVM的…

JAVA实现AES 解密报错Input length must be multiple of 16 when decrypting with padded cipher

加密代码 /*** 加密* * param content 需要加密的内容* param password 加密密码* return*/public static byte[] encrypt(String content, String password) {try { KeyGenerator kgen KeyGenerator.getInstance("AES");kgen.init(128, new SecureRando…

python 判断时间是否大于6点_python中判断时间间隔的问题

展开全部代码有点烂,不过还算能解决问题注释比较详细了# -*- coding: utf-8 -*-import datetime__author__ lpe234__date__ 2015-04-26f file(1.txt)file_content f.readlines()all_lines len(file_content)def get_(content):"""递归调用:para…