Spring 为何总是受到青睐
Spring 为何总是受到青睐
Java 的方式是冗长与简单,这两者并不矛盾。Java 简单在于它屏蔽了许多底层概念,如从 C/C++带过来的指针,同时屏蔽了许多更高层次的概念,如函数式抽象;Java 冗长在于它缺少语法糖,一切都必须以类的形式封装,用对象传递一切,且缺乏对函数式编程更进一步的支持。这两者本就是一体两面的,它们共同构成了 Java。
作为 Java 生态中可能是被最广泛使用的框架,Spring 继承了 Java 的许多原则,其中最重要的就是规范与限制。Spring 近乎强制性地使用 Controller、Service、Repository 的三层结构组织代码,要编写任何一个接口,都必须把这套逻辑自底向上走一遍。有人会说,这并非强制性的,完全可以只写一个 Controller 然后拿 JDBC 操纵一切,的确如此,但 Spring 和它的约定与惯例绑定得那么紧密,以至于任何一个初学者从他第一次接触 Spring 时,就几乎必然接触到 Spring 的项目结构与逻辑。Spring 框架自身与它的各种“最佳实践”绑定得如此紧密,以至于许多人都没有意识到他们其实可以不用为每个 Service 添加一个 Interface。
我们很少看到有其他编程语言社区像 Java 一样如此注重“最佳实践”和“设计模式”。Java 社区的人总是想要为每个场景都找到唯一一种编写代码的方式,并且乐此不疲,然后消灭每一个代码中的 if 语句,编写一大堆类来解决一切。这种风气是如此的根深蒂固,以至于每当有新人学完了 Java 问下一步要学什么,Java 程序员们异口同声地回答“设计模式”。
我想说的是——Java 与 Spring 的这种对“最佳实践”的极端追求,反而大大提高了 Java 代码的下限。即使再烂的程序员,只要让他写 Spring,那总是能看到数据库访问层和服务层是解耦的,而很少会看到在前端中经常发生的,直接在视图层中把接口地址写死。即使确实有一些习惯糟糕的程序员经常搞不清楚 Controller 和 Service 的区别,一通乱糊,但终归是将数据本身和服务解耦了。而在 MVC 时代,后端程序员除 Controller 外还需要单独编写一个视图层,把数据显式地从 Controller 传到 View 中,这又进一步解耦了服务逻辑和视图。
得益于 Java 自身对面向对象结构(主要是类结构)的严格限制,如一个文件只能存在一个 public 接口,Spring 程序员不得不为每一个 Controller、每一个 Service、每一个 Repository 建立单独的文件,完美解决了其他后端语言中程序员为了图省事把代码糊到一起的问题。这使得你总是能够相信 Java 项目的文件树,你总是能够直接通过文件树看到每一个 Controller、Service 和 Repository,而不用担心任何一个文件莫名其妙地包含了多个类体。
当然,由于历史原因,Java 还有一些微不足道的问题。例如 NPE 问题,如果能在编译时报错显然好得多。例如未标上泛型参数的泛型本应该像 C++一样直接报错,但当时为了兼容 Java 1.4 放弃了这一点。例如所有类本应该默认为 final,但当时还没有认识到滥用继承的弊端,所以并没有这样设计。还有很多这样的不足。但是在这些不足中,除 NPE 的确是实实在在的大问题之外,其他都真的只是微不足道的小问题。
于是我们看到 Spring 项目几乎总是类似的,类似的代码组织形式,类似的处理模式,类似的响应机制。一切都是那么相像。给 Spring 项目作 Code Review 几乎总是能够看懂代码的,而为 JavaScript 项目,尤其是 React 项目 Code Review,则总是陷入两个极端——要么代码组织得极端漂亮,要么组织得极端恶心。
Spring 之所以成功,且至今仍为大多数公司的后端选择,显然是有原因的。其中的原因就是 Spring 最大程度地保证了极烂的程序员能写出大致可读的代码。放到前端那块,我就不敢如此信任了。