V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
zioc
V2EX  ›  程序员

前后端分离的边界在哪

  •  1
     
  •   zioc · 2017-05-14 04:53:07 +08:00 · 6314 次点击
    这是一个创建于 2756 天前的主题,其中的信息可能已经有所发展或是发生改变。
    有一句话说业务逻辑后端做,渲染逻辑前端做。

    具体怎么理解呢?

    例如表数据如下:
    id name pid
    0 广东 -1
    10 广州 0
    11 深圳 0
    21 天河 10
    22 南山 11


    前端需要的格式如下:


    A 方案后端递归处理数据最后输出如上,前端直接使用


    B 方案服务端直接按照表结构给数据,前端递归,格式如下:


    B 的好处是:
    1 后端输出简单,节省服务器资源
    2 源数据结构,不管页面怎么改,restful api 都不用改
    3 分离清晰,后端只提供数据



    是 A 还是 B 呢?
    26 条回复    2017-05-16 10:12:07 +08:00
    geelaw
        1
    geelaw  
       2017-05-14 05:00:58 +08:00
    A 方案怎么分页?每次重新返回整个链条?

    如果可以保证 pid < id,那么用 B 显然可以很简单地处理分页。

    另外如果数据出现不一致(譬如有环),如果用 A 会更容易导致后端崩溃,如果是 B 那么后端很难崩溃。毕竟,一个顾客心肌梗死和一个商店塌了相比,还是商店塌了更可怕一些。

    还有另外的考虑:如果分级的层数是固定的,那么你的 model 可以变化为固定深度的,那应该用 A。
    binux
        2
    binux  
       2017-05-14 06:19:13 +08:00
    我觉得你这个表首先设计就有问题,它天生带有一个需要递归查找所有的 children 的逻辑在里面。
    如果你每次都要全读出来,那你还搞这个 pid 干嘛,直接存成 A 不就好了。
    如果你要去遍历,难不成前端读完广东,还要再去读 where pid = 0 吗?

    所以根本原因是你这个表设计得有问题。
    think2011
        3
    think2011  
       2017-05-14 06:28:17 +08:00
    跟前同事都是这样约定的

    1. 前端负责展示,后端负责数据
    2. 后端要是处理数据太麻烦,丢给前端整理
    3. 前端要是运算数据太麻烦,丢给后端运算

    基本上就 1 + 2,楼主的这种情况,通常是 2 的方案
    ywgx
        4
    ywgx  
       2017-05-14 10:10:31 +08:00
    在安全性考虑的前提下,一般会尽量把计算量放到前端,分摊服务端压力
    当然如果设计上前段解决起来,异常复杂,导致简单问题复杂化,就放在后端吧
    这个灵活度比较大,还是具体项目具体实施吧~
    reus
        5
    reus  
       2017-05-14 10:30:31 +08:00   ❤️ 2
    当然是 A,用 B 的后端也太懒了吧,什么都丢给前端。就想着自己有好处,想过前端怎么骂你吗?
    前端要树,我就给树,前端要表,我就给表。分成两个 api。我不用 restful,一个 api 干什么的,我好好命名,不搞那套偷懒甩锅的把戏。
    节省服务器资源?构造一个树,纯粹的计算,没有 io,能用你多少资源?找借口偷懒而已。
    klesh
        6
    klesh  
       2017-05-14 10:50:53 +08:00   ❤️ 1
    A
    前端不应关心数据如何存储,既然这是一个树形结构就要返回一个对应的树形结构。后端应保持数据结构的统一表述和抽象隔离。现在是一个表结构,以后是一个文档结构呢?使用产后端分离最大的诉求之一是前端可能有无数个,从种类上分有 spa / mpa / iOS app / android app / 各种平台的 app。若在前端进行递归整理,工作量和维护量会增多。反之,你只要在后端维护一个树形结构,就可以节省很多前端的工作量以及可能出现的 bug。

    1. 节省服务器资源的问题不存在,后端必须做 cache,否则只要有某一些前端 /app 调用不合理后端就跨掉?
    2. 源数据结构不改页面就不用改?那要看你怎么定义源数据结构这个概念了。是从业务层面上去看这个问题,还是从数据库层面上去理解。
    3. 我觉得可以用『去餐厅吃饭』这件事来类比这个事情。对于一个树形结构,直接返回原始底层数组,就相当于餐厅把原材料给你上上来,然后叫你自己拿回家去煮。

    以上,你说的三条好处全部站不住脚,这不是后端偷懒的理由。即使你们要按哪端去处理比较方便,也得以『前端会有很多个 app 』这样的前提去考虑,以后端必须做 cache 为前提去考虑,以业务逻辑和关注点分隔的原则去考虑。

    再扩展一下话题,若将来你们要集成第三方平台,然后他们的 location id 与你们的 location id 不一致要怎么处理?若『后端只给数据』这个是可以接受的话,然后是要把第三方的 id 也返回给前端,让所有的前端去处理吗?


    @geelaw location selection 最多做一个联动选择界面,为什么要分页?分页之后只有一部分的数据,如何正确重建树形结构(如何说某一个 parent 没返回来过,但它的 children 返回了)?


    @binux 有意思,表应如何设计?
    coderfox
        7
    coderfox  
       2017-05-14 10:51:07 +08:00 via Android
    原始数据的结构是树,只是数据库设计上表现为表,所以应该用树。

    如果后端有压力可以尝试使用缓存。

    我理解的前后端分离是:后端提供的接口呈现数据的原始模式。
    reus
        8
    reus  
       2017-05-14 11:10:08 +08:00
    @binux 没问题,不需要递归,一般是把所有行读出来,构建树结构,然后返回客户端。这个树可以缓存起来。这样查询和更新都很方便。直接在数据库存树,更新不方便。
    geelaw
        9
    geelaw  
       2017-05-14 11:18:51 +08:00
    @binux 然而似乎没有什么好的策略用于存储层数任意的树。当然题主给的这个例子里面层数是有限的。

    @klesh 所以我说如果 pid < id 且按照 id 升序返回那就不会有问题啊。

    @klesh @coderfox 为什么有根树的森林就一定要是递归的样式?有根树的森林不可以是符合一个约束的父亲数组存储?
    ezreal
        10
    ezreal  
       2017-05-14 11:18:56 +08:00
    A
    klesh
        11
    klesh  
       2017-05-14 11:53:19 +08:00
    @geelaw
    "所以我说如果 pid < id 且按照 id 升序返回那就不会有问题啊"
    第一,即使你的假定可以做到,分页的意义在哪里?第二,你的假定根本不可能做得到,行政区的划分并不是一成不变的,一定会存在 pid > id 的情况:如新区成立, 老的村镇其 pid > id

    "为什么有根树的森林就一定要是递归的样式?有根树的森林不可以是符合一个约束的父亲数组存储?"
    这里说的不是存储的问题,而是前后端数据结构交换的问题。前端不应关心后端如何存储数据,后端不应关心前端如何展示数据,两者之间通过合理的数据结构进行交流。
    geelaw
        12
    geelaw  
       2017-05-14 12:04:49 +08:00
    @klesh

    前一个问题:可以通过一开始取较大的 gap 避免,没说 id 必须是连续产生的;还有一种方法是准备另一个排序的 column,然后修改那个 column 以便以后按照“好”的顺序返回结果。(吐槽:行政区划这点数据还犯不着纠结这个问题,而且行政区划已经是有限层的问题了,不需要用这种组织形式存储。)

    “前端不应关心后端如何存储数据,后端不应关心前端如何展示数据”

    这个和你说用 A 不是矛盾的么?按照这个想法,A 和 B 都没有天然的优势,因为 A 是按照前端想要展示的方式准备数据,B 是按照后端立刻就可以得到的格式准备数据。

    或者可能是我对“展示”的理解和你不同?在我看来数据以一个特定的逻辑形式存储出来(例如按照某种对象的形式)已经算是“展示”了,最后出现在屏幕上的方式不重要,因为从数据的逻辑存储形式到人可以通过不同的介质(常见的:屏幕、声音、编程)。或者说我认为前端和后端对接的部分是 model,而不是 view / view model,前端可以自己把 model 变成别的 model、view model。

    如果把“展示”理解为打印到屏幕上,那前端和后端之间的 gap 可太大了……
    int64ago
        13
    int64ago  
       2017-05-14 15:22:32 +08:00
    这种问题都是前后端彼此太狭隘造成的,如果一个人前后端都写,就会很自然的选出代价最小最优雅的方式,作为后端出生的前端,我更希望跟懂点前端的后端合作,大家很清晰如何分工

    对于狭隘的后端恨不得把整个数据库直接查出来丢出来,特别是用 Java 的,那些又长又臭的数据结构都是一坨一坨扔出来的(想保证一行 80 字符都难)

    对于狭隘的前端恨不得拿到数据直接展视(既然后端给了数组,为何还要给个 length ?),后端应该是尽可能给出简洁的**元数据**,因为很多时候暂时的时候顺便处理的一些数据计算是很自然的,放后端需要额外处理


    对于楼主的问题,我觉得应该放后端处理,倒不是考虑遍历的性能代价(其实这点计算双方代码量和执行效率都差不多)。因为这种结构有很强的依赖性,这种依赖性从前端看是完全由 pid 决定,而这个太不靠谱,如果数据结构重新组织,肯定是前后端都需要改了,而且 pid 的规则对于前端有点类似于魔法的感觉。再换一个大胆的构想,现在你用关系型数据库,于是很方便返回列表,后面假如换成了 mongo 呢,会发现直接返回递归形式更方便,而这些不应该是前端关心的
    binux
        14
    binux  
       2017-05-14 18:02:37 +08:00
    @reus #8 然而你这个例子里面,树结构是不会变的,不会有更新需求。即使变了,增加一个同名节点比修改指向更简单。
    maomaomao001
        15
    maomaomao001  
       2017-05-14 18:49:48 +08:00 via Android
    lodash.js
    sagaxu
        16
    sagaxu  
       2017-05-14 20:47:40 +08:00
    我来提一个概念,中端,有的公司把中端归为后端,也有公司把中端归为前端,最有代表性的中端语言就是 php。
    后端负责基础数据和基础业务逻辑的 API,中端组合后端 API 提供具体业务 API,并按前端的要求的格式返回。
    fohuhu
        17
    fohuhu  
       2017-05-14 21:08:10 +08:00
    有意思的帖子,公司目前也在谋划前后端分离
    learnshare
        18
    learnshare  
       2017-05-14 21:18:59 +08:00
    前端不应该做类似数据库查询这种的动作,这增加了前端的复杂度,数据结构最好能够由后端处理完成。
    当然,如果后端能够把数据库核心操作和 API 服务再分离一次,这种操作就有地方去了
    x464744246
        19
    x464744246  
       2017-05-15 09:11:00 +08:00   ❤️ 1
    这种省市级 其实建议取消 pid 直接类似
    id name
    11 广东
    1101 广州
    110101 天河
    类似 直接取位数匹配就好
    x464744246
        20
    x464744246  
       2017-05-15 09:11:36 +08:00
    @x464744246 然后 就直接 B 方案
    bengle
        21
    bengle  
       2017-05-15 15:10:08 +08:00
    前端更偏向交互,后端更偏向业务逻辑。理论上应该是这样,但是现实中只能各种撕逼。。。所以需要一层前后端对接的中间层,后端保持一种数据结构输出,中间层把后端数据转成前端需要的结构,这个中间层可以后端搞也可以前端搞,我厂是前端做的,诶~
    johnpang
        22
    johnpang  
       2017-05-15 15:54:39 +08:00
    [
    {"1":{"name":"广东","pid":0}},
    {"2":{"name":"广州","pid":1}},
    {"3":{"name":"天河","pid":2-1}},

    ]


    在已知层级数的情况下这样会不会好点呢。。。
    zioc
        23
    zioc  
    OP
       2017-05-15 18:39:52 +08:00
    @x464744246 实际业务类型并不是省市
    @bengle 感觉现在前端做更合理,或者叫客户端
    @learnshare 如果把前端换成 iOS/安卓客户端呢,应该客户端做吗
    @sagaxu 这个沟通成本更高了,如果中端的工程师水平一般或者对接口质量没有追求,那简直是一场灾难。我前公司就有中间件。
    @ywgx 比较同意,而且前端处理起来并不复杂
    learnshare
        24
    learnshare  
       2017-05-15 19:55:44 +08:00
    @zioc 移动端也不做
    类似的数据几乎是永远不变的,服务器生成一份缓存起来,以后就都是直接返回了,代价真的小
    zioc
        25
    zioc  
    OP
       2017-05-16 09:41:38 +08:00
    @learnshare 如果数据是变得呢
    learnshare
        26
    learnshare  
       2017-05-16 10:12:07 +08:00
    @zioc 变得也有理想的改变周期
    比如估计一天才改动一次,那缓存 1 小时,改动后更新缓存。类似的设计
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3598 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 34ms · UTC 10:33 · PVG 18:33 · LAX 02:33 · JFK 05:33
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.