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

服务端复杂项目超长代码该如何组织呢?

  •  
  •   vertigo ·
    lidamaoHub · 2020-08-04 10:28:34 +08:00 · 4767 次点击
    这是一个创建于 1571 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如题,最近我在整理之前写的项目,发现有一个接口的代码越发出现失控的趋势(一个请求已经一百多行了),想请教一下大家是怎么处理这种问题的

    项目是一个社区程序,用户回复一个主题后首先要

    1. 对内容进行审核(看是否有黄暴或者攻击词汇)
    2. 筛选关键 tag
    3. 如果附带图片,图片内容审核
    4. 如果是匿名回帖还要生成随机昵称
    5. 如果是匿名私信还要处理私信内容
    6. 处理回复者和发帖人的积分变动
    7. 如果主贴超过一定回复数同步到其他社交平台等等
    8. 数据库处理入库

    要做的内容非常的多,但是能抽象成单独函数的貌似只有审核和生成昵称,其他大部分都无法复用

    但是我总觉得一个请求接口就这么老长,是不是我写项目的方式不对?

    请各位大神指教

    项目使用 Flask+Mongo

    60 条回复    2020-08-06 10:13:50 +08:00
    seki
        1
    seki  
       2020-08-04 10:30:54 +08:00
    你的逻辑就是这样,那就这么写咯

    如果想不到怎么优化就先别优化,过早优化的效果不一定会那么好
    hunter2015
        2
    hunter2015  
       2020-08-04 10:38:36 +08:00
    拉面条就对了,优化,啥是优化
    2kCS5c0b0ITXE5k2
        3
    2kCS5c0b0ITXE5k2  
       2020-08-04 10:43:53 +08:00 via iPhone
    才 100 多行嘛 还好啦
    lower
        4
    lower  
       2020-08-04 10:44:00 +08:00
    才一百多行……就敢叫超长代码?😀
    vertigo
        5
    vertigo  
    OP
       2020-08-04 10:47:34 +08:00
    @lower 啊?不然呢...我一般超过 40 行就有点受不了了
    IceBay
        6
    IceBay  
       2020-08-04 10:50:32 +08:00 via iPhone
    无法复用为什么就不能拆呢?
    kop1989
        7
    kop1989  
       2020-08-04 10:57:44 +08:00
    没想好就先别动。千万别把代码设计和所谓“行数”做强关联。
    你把他们都抽象出来看似接口只有几行了,其实是掩耳盗铃。
    buffzty
        8
    buffzty  
       2020-08-04 10:59:04 +08:00   ❤️ 1
    四十行就受不了只能说明你没写过大项目. 你去看看 mysql oracle 源码
    四十行? 你说的是一个小函数里面的括号吗
    gz911122
        9
    gz911122  
       2020-08-04 11:07:59 +08:00
    不要过分拆分看着更累.
    逻辑清晰按步骤走就行了
    wysnylc
        10
    wysnylc  
       2020-08-04 11:18:09 +08:00
    经验太少,过几年你就知道怎么写屎了
    angryfish
        11
    angryfish  
       2020-08-04 11:18:18 +08:00
    感觉逻辑挺清晰的啊
    ppphp
        12
    ppphp  
       2020-08-04 11:22:38 +08:00
    没文档不清楚上下文就是这样的,吃过的奥利给多了,就香起来了
    vertigo
        13
    vertigo  
    OP
       2020-08-04 11:26:59 +08:00
    @kop1989 是的,我也是这样理解的,不能为了设计而设计.所以才有这种疑惑
    lijsh
        14
    lijsh  
       2020-08-04 11:31:14 +08:00
    积分变动和同步社交内容这个可以搞成事件或者消息吧
    Vegetable
        15
    Vegetable  
       2020-08-04 11:33:51 +08:00
    100 行的超长代码可还行?
    每一个步骤可以分开,哪怕不能复用也可以抽象一下,不是过度设计,只是为了让逻辑更有层次方便理解。不会各种语句堆在一起,看着眼花。
    xuanbg
        16
    xuanbg  
       2020-08-04 11:43:45 +08:00
    每个功能抽象一个方法,接口负责调用这些方法。有些方法还可以异步处理,进一步减少接口响应时间。
    WebKit
        17
    WebKit  
       2020-08-04 11:47:32 +08:00 via Android
    40 行??我移动端传参数就 10 几行
    VictorJing94
        18
    VictorJing94  
       2020-08-04 11:49:10 +08:00
    .............骚年,见过几万行的函数嘛
    hoyixi
        19
    hoyixi  
       2020-08-04 12:01:05 +08:00
    你这里好几个步骤都是子功能 or 单独模块,别的地方都会用到,你这里不过调用一下罢了
    Jackeriss
        20
    Jackeriss  
       2020-08-04 12:42:24 +08:00 via iPhone
    不是能复用才抽函数呀,函数可以让代码逻辑更清晰
    EscYezi
        21
    EscYezi  
       2020-08-04 13:18:31 +08:00 via iPhone
    按功能拆分函数,就算无法复用以后维护也更容易
    libook
        22
    libook  
       2020-08-04 13:35:07 +08:00
    出现问题或确定会出现问题的时候再考虑优化,把精力放在当下最重要的事情,如果实在没有事情可做,就对自己的系统做压力测试、可用性测试、边界测试,提前发现些问题,再根据问题的影响排优先级,从高优先级的问题开始解决优化。

    如果代码可读性上有问题,就适当调整代码结构、增加注释,少用些奇淫技巧,少偷懒。
    skypyb
        23
    skypyb  
       2020-08-04 13:36:10 +08:00 via Android
    你说的这些审核啊、积分变动啊、内容同步啊。 后续需求拓展起来应该是可以有一大堆代码的。
    需要保证先后关系的如 审核- 匿名去敏 - 入库,可以解耦成责任链, 后续往上加东西对其他的代码改动就不会那么大。 其他的像是内容同步和积分变动这种,考虑观察者模式, 发个事件 /消息之类的
    vertigo
        24
    vertigo  
    OP
       2020-08-04 13:43:29 +08:00
    @lijsh
    @xuanbg
    @hoyixi
    @Jackeriss
    @EscYezi

    我想表达的意思是,比如一个函数是

    ```python
    def foo():
    print('a')
    print('b')
    print('c')
    ```
    改成
    ```
    class methods:
    def a(self):
    print('a')
    def b(self):
    print('b')

    def foo():
    bar = methods()
    bar.a()
    bar.b()
    print('c')
    ```
    反而会凭空多出复杂度出来,又少了可读性.比较困扰
    但是看了上面其他大佬的回答,那么看来基本就是这个样子啦,那就保持原样这样吧
    vertigo
        25
    vertigo  
    OP
       2020-08-04 13:44:33 +08:00
    @skypyb 如上条回复,我觉得可能只是把代码换了一个位置,真改起来来回找文件感觉更麻烦
    vertigo
        26
    vertigo  
    OP
       2020-08-04 13:46:46 +08:00
    @skypyb 观察者模式这种方式很不错,我没有想到,谢谢大佬
    Hanggi
        27
    Hanggi  
       2020-08-04 13:52:10 +08:00
    复杂的代码一定要装进黑盒,避免污染到其他功能,对外接口要简单清晰,里面爱怎么整怎么整。
    Veneris
        28
    Veneris  
       2020-08-04 14:20:05 +08:00
    审核,匿名抽象出工具类,大概率会复用
    积分变动,同步到其他平台等使用消息队列异步处理
    btw,其实这个代码行数不多
    ZehaiZhang
        29
    ZehaiZhang  
       2020-08-04 14:23:18 +08:00
    那你是没见我同事七千行的代码
    msaionyc
        30
    msaionyc  
       2020-08-04 14:57:13 +08:00
    其实代码长不是问题,你这个抽方法,抽模块都很容易解决,最难解决的是慢接口,你这审查图片和审查文本,查表,落表,筛选这么多流程,后期数量大了,用户体验会非常差
    有几个地方可以优化:
    1.匿名的随机昵称是否需要使用到时再生成,可不可以预生成
    2.增加积分功能抽模块,消息?
    3.同步到其他社交平台也可以抽成模块,异步去做,或者定时任务去做
    4.图片处理一定要在这个逻辑里同步做吗?是否可以异步做,然后再处理掉
    vertigo
        31
    vertigo  
    OP
       2020-08-04 15:37:28 +08:00
    @msaionyc
    1. 随机昵称这个必须同步做,因为用户回复完立刻就显示出来了
    2. 同步平台的确可以异步或者定时任务完成,这个我事先没想到,nice.
    3. 积分想了想的确可以抽象
    4. 图片和内容审查就比较纠结,因为前有 soul 那档子烂事...如果做成异步或定时的,就怕有恶意用户发帖截图删举报一条龙(虽然法律上可以很直接追责,但是一旦发生产品基本也 GG 了)这是我完全独立运营和开发的项目,我觉得这种风险还是要权衡下
    bugmakerxs
        32
    bugmakerxs  
       2020-08-04 15:55:45 +08:00
    看到这个数了数公司那个大接口的代码。。。2000 多行一个方法,不敢动不敢动
    Rwing
        33
    Rwing  
       2020-08-04 15:57:47 +08:00
    设计模式
    RadishWind
        34
    RadishWind  
       2020-08-04 15:59:53 +08:00
    抽象成 workflow,然后复用 workflow 中的 step
    vertigo
        35
    vertigo  
    OP
       2020-08-04 16:04:14 +08:00
    @bugmakerxs 我整个项目一共 900 多行代码(包含注释和空行).....你说的那个接口肯定 java 写的吧
    Youen
        36
    Youen  
       2020-08-04 16:07:52 +08:00
    不一定非要短.

    https://news.ycombinator.com/item?id=18772873

    // ==================================================================
    // PLEASE DO NOT ATTEMPT TO SIMPLIFY THIS CODE.
    // KEEP THE SPACE SHUTTLE FLYING.
    // ==================================================================
    h123123h
        37
    h123123h  
       2020-08-04 16:16:34 +08:00
    我见过一个项目很多代码都是几千行的,第二天果断跑路了
    coderxy
        38
    coderxy  
       2020-08-04 16:18:33 +08:00
    我最夸张的一个方法里 3000 行代码。 你这不算什么
    wellsc
        39
    wellsc  
       2020-08-04 16:20:49 +08:00 via iPhone
    两三千行的函数见过嘛
    xuxuzhaozhao
        40
    xuxuzhaozhao  
       2020-08-04 16:35:40 +08:00
    100 多行也叫超长代码,玩呢?我现在正在改一个 800 多行的函数。
    msaionyc
        41
    msaionyc  
       2020-08-04 17:03:34 +08:00
    @vertigo 第一点预生成的意思是提前生成好,到时候直接取,但想了想这个操作也是不太需要的,生成昵称这个操作基本 0 耗时
    raaaaaar
        42
    raaaaaar  
       2020-08-04 17:37:30 +08:00 via Android
    一个函数只做函数名所表示的功能。只要能做到这一点,函数长度不要过于要求。
    zhuweiyou
        43
    zhuweiyou  
       2020-08-04 17:39:07 +08:00
    100 毛毛雨,几千行的都写过。
    bccoder
        44
    bccoder  
       2020-08-04 18:04:17 +08:00 via Android
    我提交的参数有 100 多个,加上校验逻辑什么的,好几百行
    csl1995
        45
    csl1995  
       2020-08-04 18:05:15 +08:00
    一个函数上千行。。。
    luxinfl
        46
    luxinfl  
       2020-08-04 18:54:52 +08:00
    jdk 和 spring 里面也有很多超长的源码,这都不是事
    amundsen
        47
    amundsen  
       2020-08-04 19:04:08 +08:00
    都是一把梭,又不是不能用~
    rockyou12
        48
    rockyou12  
       2020-08-04 19:06:23 +08:00
    从你描述的业务来看,其实 100 行不算多啊……就码 if else if else 都要码很多行,逻辑清晰就别乱优化行数了
    zgzb
        49
    zgzb  
       2020-08-04 19:08:50 +08:00
    现在硬盘容量足够大,只要功能多,界面美观,写成屎也没关系
    EminemW
        50
    EminemW  
       2020-08-04 19:22:24 +08:00 via iPhone
    我司有个几千行的接口,一个函数几百行,我改了几次,最后怕改出啥问题,就回退了
    leafdream
        51
    leafdream  
       2020-08-04 19:23:00 +08:00
    一个文件 8000 行的路过
    nthhdy
        52
    nthhdy  
       2020-08-04 19:35:54 +08:00
    只要不影响阅读和思考,单个函数长一些是没问题的。
    抽函数的另一个考量是,是不是有一些部分是独立的概念,从而能当作新的 building block,简单的说就是看它能不能被重用。行数不是“硬指标”。
    不用太教条了。
    Jooooooooo
        53
    Jooooooooo  
       2020-08-04 19:57:18 +08:00
    八个模块八个方法

    主方法就八行?

    挺清晰的
    zjddp
        54
    zjddp  
       2020-08-05 09:54:17 +08:00
    说个歪的,换个带鱼屏,竖过来用就不超长了手动狗头
    NCZkevin
        55
    NCZkevin  
       2020-08-05 10:15:27 +08:00
    写的一个处罚接口 快 1000 行,感觉随时可能出问题
    vertigo
        56
    vertigo  
    OP
       2020-08-05 10:22:12 +08:00
    @zjddp 有,脖子疼
    taowen
        57
    taowen  
       2020-08-05 10:25:22 +08:00
    ```
    对内容进行审核(看是否有黄暴或者攻击词汇)
    筛选关键 tag
    如果附带图片,图片内容审核
    如果是匿名回帖还要生成随机昵称
    如果是匿名私信还要处理私信内容
    处理回复者和发帖人的积分变动
    如果主贴超过一定回复数同步到其他社交平台等等
    数据库处理入库
    ```

    这个例子举得挺好的。把所有的这些逻辑都实现在帖子回复这个接口里的问题是什么?如果没有问题,改进也就没有收益。楼主提出了抽函数貌似也无法复用,那还需要抽函数吗? 这里有两个关键词

    * 抽函数
    * 复用

    为什么手段一定是抽函数,为什么目标是复用? 这种一竿子写到底的写法的问题是什么? 如果问题不清楚,直接拿抽函数这个解决方案去套,就可能缘木求鱼了。

    所以希望楼主或者其他回复的人,能够举一些具体场景的具体例子,这样的写法会带来的非常具体的问题。只有针对这些问题才有讨论价值。一段静态的代码文本,没有对错好坏之分。只有带入了具体的场景里,有针对性的问题,才有讨论意义。
    vertigo
        58
    vertigo  
    OP
       2020-08-05 10:38:59 +08:00   ❤️ 1
    @taowen 我认为一竿子写到底方法的问题是"边界感",细想一下,我们看代码的第一眼并不是精细到文字,而是一个个矢量块(常见例子是 3d 游戏渐进式加载,先是一个大立方体块,接着更多细节,最后才是具体贴图)

    作为不常修改的稳定模块(不常改就记不住),突然想加东西时第一眼就是一长条色块,接下来需要自己通读一下代码才可以知道哪里改

    例:添加一个自动添加水印功能,我需要找到图片审核后,生成昵称前,然后插入逻辑,但是如上说,纯文字代码需要彻底读完或者读到大班才能知道在哪里动手,效率有点尴尬.(并且随着代码变大,每次这个通读过程会越来越多)

    而极端的抽离逻辑后,我们视觉上是一个个短色块,此时我们只要读取 function name 就能大致知道这个模块是不是该改动(类似数据库加 index 了),这是我觉得抽象逻辑的好处

    实际上我也认同楼上其他大佬说的,能不乱改还是不乱改,只是想知道有没有两者结合的方法
    Ryzebo
        59
    Ryzebo  
       2020-08-05 15:41:59 +08:00
    其实,作为老实人,
    你是面向薪资编程,还是面向项目编程,还是面向自己编程,还是面向加班编程?
    vertigo
        60
    vertigo  
    OP
       2020-08-06 10:13:50 +08:00
    @Ryzebo 这个是我个人项目呀,面向彩虹屁编程
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3595 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 43ms · UTC 04:18 · PVG 12:18 · LAX 20:18 · JFK 23:18
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.