rails, django, phoenix,你们错了

写这个题目估计会招人骂。

这三个著名的 MVC(或者 MTV) framework,分别对应 Ruby,Python,Elixir 三种语言。说他们是这几门语言的顶梁柱毫不为过。很多人都是慕着 framework 的名而来,进而学了语言。典型的就是曾经大红大紫(现在也算是一线明星)的 rails:很多 rails 工程师最初只知 rails,写了 rails 后发现语言的短板才反过来学的 Ruby。Phoenix 和 Elixir 大抵也是如此。

在 django / phoenix 上能看得出 rails 的很多影子。rails 在 flickr / delicious 时代是工程师追捧的明星框架。其后有了很多其他语言的跟风者或者学习者,django 不算是第一个, phoenix 也不是最后一个。通过这些框架,工程师可以快速地创建一个 web 项目的脚手架,和数据库(一般是 RDBMS)绑定,生成 model,controller 和 view,不消数日,一个可以运行部署的「网站」就攒出来了。

开发者的效率高么?很高。代码的效率高么?rails / django 虽让人诟病,但 phoenix 很高,在 benchmark 中狂胜各大 framework。

架构优秀么?似乎也很优秀 —— 如果让你我从头写一套 web framework,决计赶不上它们的水平。

那它们错在哪里?

它们错在给 web app 开发者带来「人人都能写 web app」的希望的同时,又把诸多程序员的思维禁锢在那一方小小的 MVC 中。

假设我们要做一个 MOOC 软件。用户可以浏览课程,可以注册课程,收藏课程,在上课的过程中可以为课程评分,记笔记,并和别人互动,等等。

我们看通常情况下一个 rails 程序员如何开始构建其后端:

  • 设计数据库结构:User / Content / Bookmark / Review / ...
  • rails new mooc
  • rails generate model
  • 把数据库设计映射到 rails model 中
  • rails generate controller
  • 撰写各个页面的 controller 和 view
  • (如果有时间)撰写 test

顺着 framework 的思路,我们不知不觉地做了一些假设:

  • 所有的状态都是存储在一个或者若干个 database 中的
  • 如果某个 database 没有 framework 的 adapter,那么我们就无法使用
  • 数据是强耦合的,比如 User 和 Content 间有一张 enroll 的表作为用户注册哪个课程的凭证
  • 一个 controller 可以跨越多个 model 获取数据,并提供给某个 view 把数据展现出来

有了这些假设,我们能够很快地搭建出应用程序,却付出了高耦合度的代价。

有同学疑惑了,MVC 设计模式的初衷不就是解耦么?为什么反倒耦合度变高了呢?经典的 MVC 分层设计是一种纵向的解耦,数据有序流动,各层只管自己的工作,「上帝的归上帝,凯撒的归凯撒」,不必关心其他层次如何实现。然而它并不能避免横向的耦合,比如 model 和 model 的耦合,controller 和多个 model 的耦合。而 web framework 却有意无意地在倡导这种耦合。更令人发指的是,它还将这种耦合做进了数据层面,使得日后无论是从代码层面解耦,还是数据层面解耦,都困难重重。

在 rails 出现以前,我们知道写代码还有一个 business logic layer —— 业务层。在 rails 出现之后,在大家的实践当中,业务层被莫名并入 model 层,有些功能还去了 controller,就此消失。然而,业务层被这样揉进了一个 web framework 中,是不是哪里不太对劲?

rails 们代表的 web 层并不是业务的全部。如果哪天我们要向第三方提供 API 呢?如果 web 的逻辑被大刀阔斧地改变怎么办?如果突然哪天公司被收购,用户账号整合到对方系统里,自己并不保留一个所谓的用户表怎么办?

回到我们的 MOOC 软件的例子里。课程的管理,排期,注册等等,都是业务层的事情。一个用户注册一门课程,在业务层,应该表述成为:{:enroll, uid, cid} -> true/false,而非 controller 和 model 里那些繁杂的逻辑。而展示一个用户订阅的所有课程,应该表述为:{:show, uid} -> [a list of courses]。

所有这些,和 model 无关。User model 甚至不该看见 Content model,也看不见作为连接表的 enroll 表。

这是横向的解耦。大家都是一个个黑盒的服务,user service 负责用户的个人信息的维护和展示,auth service 负责验证身份,content service 负责管理课程内容,content enroll service 处理 enroll 相关的事宜,等等。如下图:

我们甚至还可以将这些服务按照属性分成不同的部分,有些是核心服务,有些是社交服务,有些是交流服务。这些服务都有各自明确的接口,比如 auth 服务提供:

  • 用户名密码验证:{user, pass} -> {:ok, access_token, refresh_token} or :error
  • token 验证:access_token -> {:ok, token_info} or :error
  • token 刷新:refresh_token -> {:ok, access_token} or :error
  • 修改密码:{refresh_token, old_pass, new_pass} -> {:ok, new_refresh_token}

auth service 存储的数据只是用户/密码相关的信息,这信息只有 auth 服务自己知道,连 user service 都没有访问的权限。

起初,这种解耦会带来很多工作量,但随着系统的发展,你会发现,这样设计会为系统的扩展和可重用带来很多的好处。添加新的服务并不会影响已有的服务,我们甚至可以撰写一个已有服务的全新升级替代版,把部分流量导入新的服务,测试良好后把旧服务直接删掉。

这样做的另一个好处是重归以业务为中心的正道。说句不太好听的话,rails 等 framework 很容易引导人们走向一个 web 前端为中心的歧路。这里所说的「前端」,是指后端的前端。我们应该根据需求,先把业务模型构建出来,各个服务构建妥当后,再使用 rails 等打造前端。我们可能需要一个面向用户的前端,可能还要面向管理员的前端,每个独立的服务可能也需要它们各自的管理前端,我们还要有统计分析的前端,用户行为分析的前端等等。这些所有的前端基本都没有所谓的 model,因为数据的存储在各个服务中解决了。

如此这般,我们打破了上述的假设,数据变得弱耦合,每个服务有各自独立的数据,它们只是在需要的时候被组装起来。

至于这样一个个服务嘛,你管它叫 micro service 也好,叫 application 也好,只要它们足够独立,能够随需而动就好。

原文发布于微信公众号 - 程序人生(programmer_life)

原文发表时间:2016-11-21

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏Golang语言社区

大数据架构下对于业务监控的几点思考

许俊是极光的第一位严格意义上的大数据工程师,目前是大数据平台的负责人,见证了极光大数据平台从0到1,迅速发展到现在规模的历程。他给开发者带来的是大数据架构下对于...

2944
来自专栏程序员的SOD蜜

“领域驱动开发”实例之旅(1)--不一样的开发模式      一、分析业务需求。    二、设计领域对象模型    三、测试领域对象模型    四、设计业务处理类    五、设计Entity和Vi

    听说DDD-“领域驱动开发”已经很久了,园子里面已经有不少大牛写过博文介绍,但我一直没有尝试过,直到今年公司的一个项目出现数据库移植,原来的业务逻辑都写...

2437
来自专栏微信公众号:Java团长

Java程序员修炼之路

大多数人选择Java可能只是因为听说Java前景好、Java比较好找工作、Java语言在TIOBE排行榜上一直位于前三等等之类的原因,但是Java具体好在哪里,...

1172
来自专栏Java技术栈

阿里巴巴Java开发手册(终极版)

别人都说我们是码农,但我们知道,自己是个艺术家。也许我们不过多在意自己的外表和穿着,但我们不羁的外表下,骨子里追求着代码的美、质量的美。而代码规约其实就是一个对...

4708
来自专栏互联网高可用架构

Java领域从传统行业向互联网转型你必须知道的那些事儿

1413
来自专栏架构师小秘圈

1亿级PV网站架构演变

作者:叶军 来自:http://www.yejun.cn/?p=1154 一个网站就像一个人,存在一个从小到大的过程。养一个网站和养一个人一样,不同时期需要不...

5287
来自专栏服务端技术杂谈

想将系统服务化?看看服务化鼻祖亚马逊踩过了哪些坑

SOA 面向服务架构 服务化 公司项目最近的主要工作是准备服务化,作为服务化的鼻祖亚马逊的架构服务化过程经历了哪些困难,踩了哪些坑?通过这篇文章你可以略知一二...

3837
来自专栏Golang语言社区

大数据架构下对于业务监控的几点思考

许俊是极光的第一位严格意义上的大数据工程师,目前是大数据平台的负责人,见证了极光大数据平台从0到1,迅速发展到现在规模的历程。他给开发者带来的是大数据架构下对于...

5046
来自专栏WeTest质量开放平台团队的专栏

数风流人物之《游龙英雄》--说说如何脱颖而出

在2014年的腾讯游戏嘉年华盛会上,由银汉游戏开发,腾讯游戏独家代理的横板格斗手游大作《游龙英雄》重磅首发,并在之后一发不可收拾,一跃成为一代动作类手游的巅峰之...

1113
来自专栏ThoughtWorks

如约而至|2018年5月期技术雷达正式发布!

ThoughtWorks每年都会出品两期技术雷达,这是一份关于技术趋势的报告,由 ThoughtWorks 技术战略委员会(TAB)经由多番正式讨论给出,它以独...

1081

扫码关注云+社区

领取腾讯云代金券