前段时间有一天在日常交流中,杨宇老师**[公众号:编程的道与术]** 突然问起我一个问题:

FrameWork与toolkit有什么区别

当然,这个并不是凭空产生的一个问题,这个问题来源于Vert.x官网对自己的一个介绍中的话语:

Vert.x在官网中申明自己是一个toolkit,而非一个framework。

因此,笔者近期也再次好好想了下这个问题,试图能找出它们的异同。

这次笔者一并把Library也加上,阐述下自己对它们的一些不太成熟的理解。

1. 中文释义

library

library在计算中行业的中文语境中,我们通常称之为类库,想必这个争议性不大。

framework

而对于framework,通常中文会称之为框架

toolkit

而toolkit则好像未见专业的中文翻译,也很少在哪本书或文章上说到它。

为此,我翻查了下剑桥词典对这个词的解释,希望能为其寻找一个合适的中文翻译

如果按照剑桥词典的解释,那称其为工具包可能比较合适,当然计算中行业英语不能照搬普通英语。关于此点,在分析它们之间的异同后,再进一步阐述笔者的想法。

2 异同分析

2.1 相同点

2.1.1 它们都是对特定语言或技术方向的扩展支持

相同点其实非常好理解,它们都是对语言的扩展支持

想必我们都明白,编程都是基于特定的语言之上,比如Java,Swift等,语言也非常多,不同技术方向的语言也不尽相同。不同范式的语言也各有代表,总之是五花八门。

但任何一个程序员都清楚,无论自己从事哪个技术方向,后台也好,前端或移动端也罢,使用的语言也不是哪种,都会不约而同的去做一件事:寻找与使用当前语言中的生态支持

我之所以使用生态这个词,是因为无论上library,framework或是toolkit,它们都是对特定语言或技术方向的一种扩展支持。都属于某个技术方向或语言的生态的一部分。

这就它们的相同点。

2.1.1 它们都是独立并可被添加的

无论是什么,它们都是独立的东西,可被依赖并添加进项目。不同技术方向使用的依赖或管理方式不尽相同而已。

    # 在Java中,我们使用依赖,这是gradle中的定义

dependencies {
    implementation(kotlin("stdlib"))
    //base
    api("io.vertx:vertx-core:${rootProject.extra["vertx_version"]}")
    api("io.vertx:vertx-lang-kotlin-coroutines:${rootProject.extra["vertx_version"]}")

    //api
    api(project(":myddd-vertx-ioc:myddd-vertx-ioc-api"))
    api(project(":myddd-vertx-i18n:myddd-vertx-i18n-api"))
    api(project(":myddd-vertx-base:myddd-vertx-base-api"))

    //api implement
    implementation(project(":myddd-vertx-ioc:myddd-vertx-ioc-guice"))
    implementation(project(":myddd-vertx-i18n:myddd-vertx-i18n-provider"))
    implementation(project(":myddd-vertx-base:myddd-vertx-base-provider"))


    //test
    testImplementation("io.vertx:vertx-junit5:${rootProject.extra["vertx_version"]}")
    testImplementation("io.vertx:vertx-web-client:${rootProject.extra["vertx_version"]}")

}
def pods
    # 一个简单的依赖注入实现
    pod 'Base_IOC' , ' ~> 0.0.2'
    # SWTableViewCell的修改版,兼容iOS12
    pod 'Module_SWTableViewCell' , '~> 0.0.2'
    # Cordova的修改版本,完全去除UIWebView
    pod 'Module_Cordova' , '~> 0.0.2'
    # 项目数据库框架
    pod 'Module_OPF' , '~> 0.0.2'
    # 项目抽取的网络框架
    pod 'Module_OPH' , '~> 0.0.2'

    #日志组件
    pod 'CocoaLumberjack'
    #....
end
  "dependencies": {
    "@types/sqlite3": "^3.1.6",
    "@types/winston": "^2.4.4",
    "antd": "^4.0.3",
    "async-lock": "^1.2.2",
    "concurrently": "^5.2.0",
    "electron-updater": "^4.2.5",
    "fs-extra": "^9.0.1",
    "image-size": "^0.8.3",
    "imagemin": "^7.0.1",
    "imagemin-pngquant": "^8.0.0",
    "jimp": "^0.16.1",
    "lodash": "^4.17.20",
    "zip-a-folder": "^0.0.12"
  }

2.2 不同点

理所当然,它们是有所不同的,不然不会分别使用一个名词来示意。

好吧,在阐述笔者对它们的不同点的理解前,笔者先讲述一段笔者设想的编程的生态史

2.2.1 编程的生态史

在现代化语言出现的早期阶段,比如Java类似的面向对象的现代编程语言出现了,这极大的解放与提升了编程的生产力。现代化的编程语言极大的减少了编程的准入门槛,程序员再也不用去学习或编写汇编等极难掌握的语言及语法。

于是越来越多的人进入了编程的行业,越来越多的软件或产品出现,在这个过程中,产生了大量的可重用代码。一部分有远见的程序员发现很多人编写的代码做的事都是非常类似及重复的。于是他们认为为什么不去复用这些重复的代码或功能呢

于是,这些优秀的程序员发明出了library,我们称之为类库。library的作用非常直接及单一,对某种重复性调用非常多的功能点,将其抽象整理出来,形成某种单独的可被使用的代码块

这就是笔者理解的libraray

libraray的一个最重要的特点是:

它是被依赖及被调用的事物,为解决某一种特定的并具有普遍性的问题

也就是,library是被调用的,它只解决某一种特定并具有普遍性的问题。比如加密解密类库

这里要特别强调被调用,后面讲到framework就可以明白了。

library的出现极大的减少了重复代码,开发人员终于可以复用一些轮子,减少了重复代码,提升了编程的效率。

但是,随时软件的飞速发展,业务的不断扩充,开发人员发现代码越来越难以维护与扩展,新的问题的产生必然会引发新的解决方案。还是我们群体中的优秀者们,他们在实践的过程中发现一些特定的方式可以让代码更易于维护,这就是方法论及模式

比如他们发现在Web开发中,使用MVC模型的编码模式比旧有的其它方式要好多很。

于是,一些模型就流行起来了,但光有模式或方法论还不行,如果没有好的工具或代码的支撑,还是难以推广与约束。在这种需求下,一些流行的framework就应用而生了,比如MVC模式中的Spring MVC或早期的Struts MVC

与单纯的library不同,framework不仅仅是抽取重复代码,更重要的功能是:它制定了一些行为规范,要求你遵守并按照它的规范来编写代码。而且它有一整套内建的机制,来支撑运行这个规范或模式。

所以,framework具备以下几个与library明显不同的特点:

  • 它是对某种特定模式或方法论支撑
  • 它有约束或规范,要求你按照它的方式来编写代码
  • 它并不单纯被调用,更重要的是,它会调用你写的代码来最终实现某种特定的模式的运行

对此,很明显的就是上述笔者所说的Spring MVC,使用Spring MVC,你就得按照它的规范与约束来编写Controller的代码,而且最终这些Controller是怎么运行起来的,编码的人都可能并不清楚,因为是Spring MVC它调用你写的Controller的代码来运行的。

好吧,到这里为止,你应该能明白library与framework的区别了吧?

但是,事情并未结束,仍在发展

有了framework之后,优秀的方法论或模式得以运行,是不是编程就没有后顾之忧了呢?

不是,开发人员慢慢发现,framework是不错,但就算是framework,也只针对一个特定的方向,无法面面俱到。一个项目,会需要很多不同的framework结合起来搭配着用,才能形成一个好的整体解决方案。

比如前些年比较流行的SSH,它就是把Struts,Spring以及Hibernate几个框架或类库整合起来形成一个整体的解决方案。

再比如最近流行的微服务,那服务的注册与查找用什么?于是出现了不同的方案,都可以。

这种把不同framework搭配起来的做法也延续了蛮久,但又有一部分程序员觉得:为什么要这样,为什么我不提供一个整体的解决方案呢

于是,现在后端最流行的框架Spring Boot出现了。

用过Spring Boot的开发人员很清楚,Spring Boot包含的东西五花八门,从数据到REST,再到缓存等,全部有自己的解决方案,虽然很多它也是在别人的类库或框架之上封装的。

这就形成了一个整体的解决方案,与程序员东拼西凑各种框架与类库不一样,这种做法的优秀在于它的质量及可靠性,就相当于Spring对开发人员说:别乱找了,就全用我们的,我们保证它没问题

于是,笔者认为toolkit出现了。而Spring Boot就是toolkit的一种表现形式。Vert.x也能算的上。

笔者认为toolkit具备以下几个特点:

  • 它一定是一个集合,这个集合中可能包含各种framework或library,每个framework或library解决某一类问题
  • 它并不着眼于某一个问题,而是着眼于一整套解决方案,也就是你用它,就是用一个工具套件,大部分技术上的需求它都能解决,不用去找其它工具了。
  • 它致力于 1+1 >2 的效果,不单纯的拼凑各种类库或框架,而是会让它们的结合更紧密,编码更简单等

这种toolkit,在各个技术方向都会有,比如笔者前面说的后端的Spring Boot,移动端类似Android中Google主推的jetpack,而前端的Vue也明显属于这类型的

2.2 结论

以下结论为笔者一家之言,仅供参考

library是单纯的可复用的代码或功能块,它是被调用的

framework是制定了一套约束或规范,依赖它,你不仅仅是调用它的API,更重要的是按照它的规范或约束编写代码,它会运行自己的一套机制,结合并调用你写的代码来实现某种特定的模式或方法论

它是主动而非被动

toolkit是一种工具集,它包含各种library以及framework,它致力于提供一个整体解决方案,并努力让这些搭配产生 1 + 1 > 2的效果

3 然后呢?

可能会有人认为区分这些玩意没什么用,还不如流行什么就用什么或什么性能好就用什么

这当然不是正确的想法,知道了library,framework以及toolkit的异同后,对我们有什么帮助?

当然会有作用,知道它们的区别后,对于我们的架构设计会产生非常不一样的考虑方式,我们在做架构时,对于library,framework或toolkit的选择与考量的思考点并不一致。

这一点,笔者后续再谈


更多优质文章,请访问笔者的个人网站 https://lingenliu.cc 或关公众号:【御剑轩】 - 致力于实践与传播优雅的编码之道

05-18 10:00