一点关于"fat model, skinny controller"的思考
导言
想来从事服务器端开发也有将近一年的时间,服务端开发不能忽略的一个架构就是MVC架构,但一开始作为小白的我对这些高大上的概念也是很迷惑,由于很长一段时间应对的业务也是十分简单,业务代码也是流水一样的代码,所以对架构方面的东西接触也不是很多。
而随着过去几个月应对的业务越来复杂,越来越觉得脚本一样的模式写起来非常吃力。
思考
此前用flask和nodejs写过一些接口,这些代码一直是这样的:
# flask
from flask import Flask
app = Flask(__name__)
@app.route('/api/path')
def get_path():
# do something
return jsonify({'code':'0'})
// NodeJS express框架
var express = require('express');
var app = new express();
function dosomething(){
// do something
}
app.route('/api/path').get(dosomething);
以NodeJS express框架搭建的项目为例,项目目录结构只有两层:
app/
|-- users/
|-- user.model.js
|-- user.controller.js
|-- user.routes.js
|-- products/
|-- product.model.js
|-- product.controller.js
|-- product.routes.js
其中*.model.js就是对应的是一个数据库的表,*.routes.js文件定义路由,*.controller.js定义了所有的业务逻辑。这种结构一开始工作良好,但随着需求增加,接口代码不断增加,上述每个*.controller.js的代码量急速增加,部分甚至达到一万多行,而且里面基本就是一个接口对应一个函数,每个函数里面就是各种通过对数据库的增删改查操作。
如果只是代码量增多那可以接受,问题是业务需求经常改动,经常牵一发而动全身,此外还要考虑版本的兼容性。有些接口功能、逻辑基本上一样,只有细微的差别,但就是这一点点差别不得不另外再写一个类似的函数,造成代码大量冗余。
几经寻找找到一个思路,就是"fat model,skinny controller",它的观点是将部分的业务逻辑放到数据模型中定义,作为数据模型类的方法。这对我来说是一种新的尝试,因为使用这种代码编排方法意味着很多类似的代码可以放到model中,从而分担controller的负担。而NodeJS项目中使用的mongoose本身就提供了许多现成的方法。
然而使用了一段时间之后我发现,一个业务操作往往涉及了多个模块的数据库操作,*.model.js因此引入了大量其他模块中的模型,这样的结果反而更加复杂,严重的时候甚至出现了循环引用的问题:一个功能逻辑上本应该属于模型A,然而由于这个功能需要引用模型B,而B模型在其它功能上又引用了模型A。结果就是很多模型相互缠绕在一起。
偶然看到一篇文章,里面指出,"fat model,skinny controller"的分工不是一个好主意,虽然它相比于"fat controller"有优势,但并好不了多少。因为随着功能的增加,开发者不得不将所有的代码放到少数的几个类中,最终造成所谓的"god object",也就是上帝对象,一个用数千行代码来定义的类实例。
最近在读《企业应用架构模式》这本书,书中总结的一些架构模式启发了我不少。
其中有一部分专门讲数据源架构模式,讲的是业务逻辑应当与数据源适当地隔开。复杂的业务逻辑往往需要隔离数据源层。这一定程度体现了"一个类只做一件事并把它做好"的原则,也就是关注点分离。"fat model,skinny-controller"的模式的问题在于,一个模型既扮演了数据读写的功能又承担了作为业务逻辑主体的角色。这不符合书中提出的分层原则。
前面的文章也指出,我们应当突破框架的局限,突破mvc这种设计模式的限制,使用更多的类取更好地组织你的代码。
重读这篇文章收获颇多,一方面是对fat model的反思,另一方面是对《企业应用架构模式》理解的深入。下一步的方向是将事务脚本的代码转变成为领域模型的形式,削弱业务逻辑对模型层的依赖,增加数据映射器的使用。
一点关于"fat model, skinny controller"的思考的更多相关文章
- MVC(Model View Controller)框架
MVC框架 同义词 MVC一般指MVC框架 MVC全名是Model View Controller,是模型(model)-视图(view)-控制器(controller)的缩写,一种软件设计典范,用一 ...
- MVC模式(Model View Controller)下实现数据库的连接,对数据的删,查操作
MVC模式(Model View Controller): Model:DAO模型 View:JSP 在页面上填写java代码实现显示 Controller:Servlet 重定向和请求的转发: 若 ...
- 深入浅出Java MVC(Model View Controller) ---- (JSP + servlet + javabean实例)
在DRP中终于接触到了MVC,感触是确实这样的架构系统灵活性不少,现在感触最深的就是使用tomcat作为服务器发布比IIS好多了,起码发布很简单,使用起来方便. 首先来简单的学习一下MVC的基础知识, ...
- Model View Controller (MVC) Overview
By Rakesh Chavda on Jul 01, 2015 What is MVC?Model View Controller is a type of user interface archi ...
- Model View Controller(MVC) in PHP
The model view controller pattern is the most used pattern for today’s world web applications. It ha ...
- What is the difference between Reactjs and Rxjs?--React is the V (View) in MVC (Model/View/Controller).
This is really different, React is view library; and Rxjs is reactive programming library for javasc ...
- Go语言根据数据表自动生成model以及controller代码
手写model的用法请参考: https://www.jianshu.com/p/f5784b8c00d0 这里仅说明自动生成model文件的过程 bee generate appcode -tabl ...
- AngularJS开发指南11:AngularJS的model,controller,view详解
model model这个词在AngularJS中,既可以表示一个(比如,一个叫做phones的model,它的值是一个包含多个phone的数组)对象,也可以表示应用中的整个数据模型,这取决于我们所讨 ...
- 设计模式 --- 模型-视图-控制器(Model View Controller)
模型-视图-控制器(Model-View-Controller,MVC)是Xerox PARC在20世纪80年代为编程语言Smalltalk-80发明的一种软件设计模式,至今已广泛应用于用户交互应用程 ...
随机推荐
- 九度OJ--Q1167
import java.util.Scanner;import java.util.TreeSet; /* * 题目描述: * 输入一个数组的值,求出各个值从小到大排序后的次序. * 输入: * 输入 ...
- 条件随机场CRF
条件随机场(CRF)是给定一组输入随机变量X的条件下另一组输出随机变量Y的条件概率分布模型,其特点是假设输出随机变量构成马尔科夫随机场.实际上是定义在时序数据上的对数线性模型.条件随机场属于判别模型. ...
- 移动端webapp如何隐藏浏览器的导航栏
webapp如何隐藏浏览器的导航栏 在webapp开发中,手机浏览器的导航栏会让我们的页面看起来很怪异,这个时候我们就需要将导航栏给隐藏起来,隐藏的方法十分简单,只需要在head头中加入以下几行代码就 ...
- input设置为readonly后js设置intput的值后台仍然可以接收到
今天发现一个奇怪现象,一个input属性readonly的值被设置为readonly,然后有前台js给input设置了新值. 虽然前台看不到效果,但是提交到后台后,仍然可以接收到新值,感觉很奇怪. 我 ...
- [剑指Offer] 40.数组中只出现一次的数
题目描述 一个整型数组里除了两个数字之外,其他的数字都出现了两次.请写程序找出这两个只出现一次的数字. [思路]此题考察的是异或运算的特点:即两个相同的数异或结果为0. 此题用了两次异或运算特点: ( ...
- JVM内存区域配置
堆内存:新域+旧域 设置堆内存初始化大小 java -Xms128m 设置堆内存初始化大小128MB 设置堆内存最大大小 java -Xmx256m 设置堆内存最大256MB 通常将堆内存的初始化大小 ...
- CF762E Radio Stations
题目戳这里. 我还以为是KDtree呢,但是KDtree应该也可以做吧. 这是一道数据结构好题.考虑到由于\(K \le 10\),所以我们用两个大vector--\(Left,Right\),\(L ...
- BZOJ_DAY6???
昨天没睡好啊啊啊,真是要命,睡不着,今天状态爆炸...34题击破. 下一步目标:网络流24题,树链剖分. (洛谷比赛了好开心,希望这次能比以前强吧,嗯)
- COGS1752. [BOI2007]摩基亚Mokia CDQ
CDQ的板子题 #include<cstdio> #include<cstring> #include<iostream> #include<algorith ...
- c#中数据库字符串的连接几种方式
ADO.net 中数据库连接方式(微软提供) 微软提供了以下四种数据库连接方式:System.Data.OleDb.OleDbConnectionSystem.Data.SqlClient.SqlCo ...