关于后端开发分层的疑问 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
请不要在回答技术问题时复制粘贴 AI 生成的内容
chaleaochexist
V2EX    程序员

关于后端开发分层的疑问

  •  2
     
  •   chaleaochexist 2024-05-02 22:52:52 +08:00 2772 次点击
    这是一个创建于 527 天前的主题,其中的信息可能已经有所发展或是发生改变。

    之前也发过好多贴, 看过好多贴, 还是没有彻底搞懂。

    简单来说 controller service dao 三层。

    controller 和 service 之间的分层相对比较清晰, 业务逻辑和显示逻辑的拆分, 譬如 MQ/http/RPC 和业务分离。

    service 和 dao 的区分我有点搞不懂。主要是因为分不清什么是存储逻辑(非业务逻辑)什么是业务逻辑。 尤其是加入了 manager 层之后。

    因为是 python 后端, 所以很自然的将业务逻辑加到 Model 上。 (我理解这里的 Model 是指业务 Model ) UserModel.is_super() 带业务的查询。
    或者
    UserModel.objects.all() 原生将 permissons,groups ,Commany,等等一起都带过来了。
    或者
    UserModel.*** 做一些跨表的操作。

    我的问题:

    1. 什么是业务逻辑, 什么是非业务逻辑。
      我的理解是,客户看不到的逻辑都算非业务逻辑, 譬如
      1.1 表结构,表关联关系等。
      UserManager.delete()DepartmentManager.delete() 这俩可以同时包含删除关联关系表( UserDeptModel )的能力。不是二取一。 同理 save 也是。 如果没有 manager 层, 那么我的理解 Dao 是可以做连/跨表操作的,只要这个跨表操作和业务无关,没必要在 service 调用两次 dao 。
    class UserManager: def delete(): UserDao.delete() UserDeptDao.delete() class DepartmentManager: def delete(): DepartmentDao.delete() UserDeptDao.delete() 

    1.2 密码加盐。
    用户最多只需要知道你的密码是不明文保存就可以了。 加盐动作可以放在 DAO/Manager 层处理。

    class UserDao: def make_password(passwd): return salt(passwd) def save(): passwd = self.make_password(passwd) self.passwd = passwd super.save() 

    1.3 DAO 层的方法命名和设定
    是否可以类似get_super_user 这种带有非业务逻辑(假设这个 super 与业务逻辑无关),但是具有明显语义的方法名?还是只能get_user_by_type("super")
    1.4 http 请求也可以封装层 dao. 譬如后端有一些依赖(另一个 team 提供支持), 我可以将这些依赖封装成 dao, 而不是 service.
    2. 在 django/flask 中, 很容易实现 django filter 的功能。 https://www.django-rest-framework.org/api-guide/filtering/
    https://django-filter.readthedocs.io/en/stable/
    甚至于在 ModelViewSet 中直接集成了 filter, https://github.com/encode/django-rest-framework/blob/master/rest_framework/mixins.py#L33 如果用 python 做三层架构且想实现类似 django filter 功能的话, 那么 DAO 中一定需要传入 request 参数。且层层穿透。在没有 spring 这种自动注入框架的帮助下,如何处理类似的问题? java 中是如何实现类似 django filter 类似功能的?
    3. 什么是数据实体? 是否 controller service dao 是一一对应的,如果不是, 能否举几个例子。 主要是 DAO 和 service.

    三层架构和 DDD 的优缺点建议不再本贴讨论。担心歪楼。 谢谢大家啦!

    12 条回复    2024-05-03 22:16:54 +08:00
    huijiewei
        1
    huijiewei  
       2024-05-02 23:02:04 +08:00
    你这么分就很明显了

    controller -> service -> data provider(db:dao, third api)
    XCFOX
        2
    XCFOX  
       2024-05-03 03:40:50 +08:00
    我平常写 node.js 比较多,在 node.js 的世界里几乎见不到 DAO 层。就算是 Spring 味最重的 Nest.js 里也见不到 DAO 层。因为 node.js 的 ORM 很强大很好用,所有 DAO 层的事情 ORM 都干好了,直接在 Service 层里调用 ORM 方法就完事儿了。
    我个人理解 DAO 在 Java 、Go 的不使用高自动化 ORM 、需要大量手写 SQL 的项目中会起比较大作用。
    对于 Python 来说,如果有好用的 ORM 的话,没必要硬写 DAO ,直接用 ORM 短平快地完成需求岂不美哉。
    BeautifulSoap
        3
    BeautifulSoap  
       2024-05-03 05:57:05 +08:00 via Android
    对于不复杂的业务,倒不用分层,一个 Controller+最多一个 Service 就够了,数据交互全直接写 Service 都没问题

    但对于复杂点的业务,分层我觉得不如按照 DDD 的分层来做比较好(自己搜 DDD layered architecture )。我觉得 DDD 分层思想最好的一点就是所有都围绕着 Domain 层中的 entity 这点。基本上搞清楚了 entity 扮演了怎样的角色那么各层里奇奇怪怪的概念就都清楚了
    a5X77vajGRyLA2aF
        4
    a5X77vajGRyLA2aF  
       2024-05-03 07:04:33 +08:00 via Android
    问题有点多。个人理解(不一定正确)
    1. 业务逻辑就是需求实现逻辑,参考业务流程图。非业务逻辑,没听过,感觉是非功能需求,如要求响应时间,吞吐量,可靠性等

    1.1 manager 层主要是
    1. 把多个 service 循环依赖才能实现的方法下沉到 manager 对象中,避免循依赖
    2. 管理可复用资源,如 cacheManager ,transationManager 。。。

    1.2 推荐在 service 层加密,dao 层主要做发送 sql 到数据库操作

    1.3 支持方法重载就不推荐加 by_xx ,参数多就封装为一个查询对象

    1.4 不写 python ,没懂

    2. 没有 spring ,JAVA servlet 实现 filter 功能也很简单,继承 Filter ,配置类到 web.xml 就可以了

    3. 数据实体?指 entity ?理解是一个数据库表对应的一个类。controller:service 是一对多,service:dao 是一对多。如 userservice 中注入 userdao, accountdao,
    ixixi
        5
    ixixi  
       2024-05-03 10:11:45 +08:00
    你还漏了一个逻辑层 logic
    chaleaochexist
        6
    chaleaochexist  
    OP
       2024-05-03 10:37:44 +08:00
    @yusheng88
    感谢回复哈。
    这里的 filter 是类似 orm 层面的功能, 和 java 中的 filter 不是一个东西,java 中的 filter 是 django 中的 middleware 。
    >>> 1.3 支持方法重载就不推荐加 by_xx ,参数多就封装为一个查询对象
    但是如果这样做的话, 那么 orm 就完全代替 dao 了。不知道 dao 还有什么其他作用?
    参考本站
    t/779785#reply32
    中的 case2
    a5X77vajGRyLA2aF
        7
    a5X77vajGRyLA2aF  
       2024-05-03 11:12:44 +08:00 via Android
    dao 层的作用:
    1. 方便后续做多数据源管理,读写分离等拓展操作
    2. 后续切换 orm ,修改比较方便
    3. 工程化,谁接手都知道查询数据库要通过 dao 对象
    bsg1992
        8
    bsg1992  
       2024-05-03 13:22:40 +08:00
    后端分层 是前人在项目开发遇到项目规范和代码组织总结出来的一种最佳实践
    不必要非得 100%遵守 适合自己团队的方案才是最好的。
    ORM 作为 DAO 层 也是可以的,不过还是没法避免在 service 中去写 sql 的场景。
    Terryx
        9
    Terryx  
       2024-05-03 14:56:57 +08:00 via iPhone
    我觉得可以这么理解,有一天你老板要你三天拉个分支把数据库切换到 PostgreSQL ,业务不变。
    sujin190
        10
    sujin190  
       2024-05-03 15:09:39 +08:00 via Android   1
    数据层和业务层不难区分吧,数据层主要封装的是对数据结构逻辑的读写,这个包含着完整数据逻辑,大多数情况下一个数据逻辑只有一个读写操作,但有时候也会有多个,也许层对应的自然是现实需求和产品表达的具体实现了

    举个简单例子,判断是都是超级用户这显然是一个数据逻辑,在用户登陆成功后需要判断是否是超级用户提示不可用这显然是业务逻辑

    数据层不应该对应使用场景,而业务层必定应该对应具体使用场景,就这样啊
    chaleaochexist
        11
    chaleaochexist  
    OP
       2024-05-03 20:26:14 +08:00
    @sujin190 也就是说, 你认为:

    `is_super()` 是数据逻辑

    ```python
    if not is_super():
    return 404
    ```
    是业务逻辑。

    是这样吗?
    sujin190
        12
    sujin190  
       2024-05-03 22:16:54 +08:00 via Android   2
    @chaleaochexist 可以这么认为,数据层是对数据准确、严谨并且完整无歧义的读写封装,理论上不应该和具体的需求场景上有关联,虽然吧数据结构完全是按产品和业务需求来设计的,但在软件分层架构中按产品和业务需求设计完数据结构后,我们却首先应该抛弃产品和业务的具体需求和场景,完全按照数据结构自身来设计标准数据读写封装层,而且吧现实情况下太多时候一个具体的产品和业务需求可能只有一个数据读写,如果没按标准分层架构设计,后续一部分变更需求逻辑后,很大可能就越来越混乱一塌糊涂了
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     889 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 24ms UTC 19:44 PVG 03:44 LAX 12:44 JFK 15:44
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86