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

(深度分析)开源框架/库的伟大与罪恶

  •  
  •   ScottHU · 271 天前 · 3280 次点击
    这是一个创建于 271 天前的主题,其中的信息可能已经有所发展或是发生改变。

    前段我发了一篇《是时候该换掉你的 axios 了》的文章引起了热议,各位小伙伴也给出了自己的看法,本来只是随便一发的对比 axios 和 alova 优劣势的文章,但是却遭到了一些同学的质疑。

    思想碰撞是我们进步的阶梯,我没有要贬低这些质疑的意思,相反,我要感谢他们(质疑者)推着我思考和前进,在这边我想对这些声音做出自己回应。

    因为我从这些质疑声中看到了,很多人的代码思维都还停留在使用层面,而缺少更深度的理解和思考,这篇文章我想聊聊我对开源框架和库更深入的观点,从更深入的角度聊聊我为什么看好 alova !!!

    看完我保证你一定会有所收获的,没有的话你尽管喷。 还不知道 alova 的可以预先了解下:

    alova 的 Github 地址

    alova 官网

    如果你不知道 axios 的话,直通车在这

    本文主要讨论编程背后的东西,而不是某个技术点的解决方案,欢迎大家参与共同讨论!

    省流目录

    1. react 和 vue 的伟大
    2. (解答各位的质疑) alova 的优势在究竟哪里
    3. (升华)开源框架罪恶史

    react 和 vue 的伟大

    深有体会的是,开源框架和库已经实实在在地给我们带来了太多便利,在深入讨论 alova 前,我们先从来 react 和 vue 等大家最熟悉的 UI 框架说起。

    这些 UI 框架究竟给我们带来了什么,过去的王者 jquery 可谓雄霸天下,jquery 所解决的问题是提供一种更简单兼容性更好的 dom 操作 api ,让大家不需要关注兼容性问题,但对于新手来说,照样会把全部代码写在一个 js 文件中然后把代码乱放,来欣赏一段意大利泡面一样的 jquery 代码:

    // ❌整个页面的 js 处理都集中在这里了
    (function(win) {
        // 处理页头按钮点击事件
        $('#header .button').click(function() {
            // ...
        });
    
        // 处理页脚某个 tag 的鼠标移入事件
        $('#footer .tag').mouseenter(function() {
            // ...
        });
    
        // 处理主界面轮播图的事件
        $('#swiper .btn-left').mouseenter(function() {
            // ...
        });
        $('#swiper .btn-right').mouseenter(function() {
            // ...
        });
    })(window);
    

    项目以 html 、js 、css 为大模块进去分开,结构大概是这样的

    WechatIMG684.jpeg

    一团扭来扭去还弯弯曲曲的代码,可维护性直降负分,谁愿意接盘谁倒霉,随着项目逐渐复杂,每改动一处都像是一锤子锤在接盘侠的胸口上 —— 痛苦无比,只要团队里有新手,不管技术 leader 怎么制定模块拆分的规范都无法避免这种事的发生,最终接盘侠们也抛了盘……

    为什么呢?

    因为 leader 的规范只是写在文档上的意见型规范,你可以不遵守也能让项目跑起来。而 react 和 vue 等 MVVM UI 框架(以下简称 UI 框架)的优势就立即凸显出来了,这让它们很快把过去的王者 jquery 击败了,这些 UI 框架的最伟大之处就在于,它们提供了一种可维护性更高的代码组织模式 —— 组件化,并强制大家都使用这种方式来开发应用。组件化中,html 、js 、css 以组件为最小单元聚合,组件之间相互解耦,大概是这样的

    WechatIMG683.jpeg

    它们形成了一种制约型规范,不遵守项目就无法跑起来,这种方式让天底下的前端开发者达成了统一的模块化共识,就像你家的电源插槽那样统一。

    我觉得以上就是框架和库的区别!!!

    这种制约型规范才能让组件库百花齐放,各种组件库开始诞生进一步为大家减少开发量。

    这就是制约型规范的威力,可能你突然就懂了为什么要用 husky 了。

    而使用数据驱动视图的 MVVM 模式,虽然相比于 jq 也是降维打击的存在,但我觉得它的重要性并没有组件化伟大。

    (重要)制定规范的目的除了规范变量名和注释外,更重要的是在代码组织层面实现高聚合、低耦合, 不陌生吧,而且我觉得 vue 的 SCF 、指令相比 react 的 jsx 又进一步做到了强制型规范。

    (解答各位的质疑) alova 的优势在究竟哪里

    如果你理解了上面的规范问题,我们再接着聊相比于react-queryswrvueuse 的 useFetch以及ahook 的 useRequest等,alova 有什么特别之处?我很认同作者在《是时候该换掉你的 axios 了》中的评论:

    1.png

    在得知我还要再发一篇深度解析文后,在周一晚上,作者找到了我,聊了 3 个小时,他表达了不希望 alova 被我带偏了,那次聊过后也体会到了作者的思想,大概如下:

    js 库可以分为规范型 js 库和功能型 js 库

    规范型 js 库

    像 react 和 vue 等 UI 框架除了提供 api 外,还提供了组件化(制约型规范),很显然是规范型的库,即框架。

    功能型 js 库

    如 axios 、moment 、lodash 、jquery 等都是属于功能型 js 库,它们更多的价值是提供便于调用的 api ,而 react-query 和 swr 等确实是使用 use hook 管理请求以及使用请求缓存的先驱者,但好像除了这些再没有规范层面的影子,因此更倾向于把它们归类到功能型 js 库中,贴上示例。

    react-query 官方示例简析

    function Example() {
      // 在每次 useQuery 中调用 fetch 或 axios 发送请求,耦合度较高
      // 需手动维护 queryKey
      const { isLoading, error, data } = useQuery({
        queryKey: ['repoData'],
        queryFn: () =>
          fetch('https://api.github.com/repos/tannerlinsley/react-query').then(
            (res) => res.json(),
          ),
      })
    
      if (isLoading) return 'Loading...'
      if (error) return 'An error has occurred: ' + error.message
      return (
        <div>
          <h1>{data.name}</h1>
          <p>{data.description}</p>
          <strong>👀 {data.subscribers_count}</strong>{' '}
          <strong>✨ {data.stargazers_count}</strong>{' '}
          <strong>🍴 {data.forks_count}</strong>
        </div>
      )
    }
    

    swr 官方示例简析

    // 耦合的方式请求
    const fetcher = url => fetch(url).then(r => r.json())
    function App () {
      const { data, error } = useSWR('/api/data', fetcher)
      // ...
    }
    
    // 解耦的方式
    import useSWR, { SWRConfig } from 'swr'
    function Dashboard () {
      const { data: events } = useSWR('/api/events')
      const { data: projects } = useSWR('/api/projects')
      const { data: user } = useSWR('/api/user', { refreshInterval: 0 }) // override
      // ...
    }
     
    function App () {
      return (
        <SWRConfig
          value={{
            refreshInterval: 3000,
            fetcher: (resource, init) => fetch(resource, init).then(res => res.json())
          }}
        >
          <Dashboard />
        </SWRConfig>
      )
    }
    

    我觉得 vercel 团队是有思考到这点的,只是把解耦的方式作为了一个可选项。

    alova 的不同之处

    虽然 alova 相比于 axios 、react query 、swr 等前辈大咖,alova 只能算是新秀中的新秀,其他库已经发展了 5 到 10 年了,作者好像也比较低调。但在我看来 alova 在解决思想上和前辈们相比会更加深入,也更加彻底。

    alova 的作者提出了一个叫 RSM 规范(请求场景模型) 的模型,并让 alova 遵循这个模型来设计,官方示例代码如下:

    import { createAlova } from 'alova';
    import GlobalFetch from 'alova/GlobalFetch';
    import VueHook from 'alova/vue';
    
    const alovaInstance = createAlova({
        // 假设我们需要与这个域名的服务器交互
        baseURL: 'https://api.alovajs.org',
    
        // VueHook 可以帮我们用 vue 的 ref 函数创建请求相关的,可以被 Alova 管理的状态
        statesHook: VueHook,
    
        // 请求适配器,我们推荐并提供了 fetch 请求适配器
        requestAdapter: GlobalFetch(),
        
        // 全局请求前钩子
        beforeRequest(method) {  
            // ... 
        },
        
        // 全局响应钩子
        responsed: {
            onSuccess(response, method) {
                // ...
            },
            onError(err) {
                // ...
            }
        }
    });
    
    // 创建一个 Get 实例,描述一次 Get 请求的信息
    const todoListGetter = alovaInstance.Get('/todo/list', {
        // 请求头
        headers: {
            'Content-Type': 'application/json;charset=UTF-8'
        },
        // params 参数将会以?的形式拼接在 url 后面
        params: {
            userId: 1
        },
        
        // 单独为这个请求设置缓存时间
        localCache: 50000,
        // 单独为这个请求开启请求共享
        shareRequest: true,
        // 数据转换
        transformData(result) {
            // ...
        },
        // ...
    });
    

    从以上示例中,可以看出 alova 的以下两个优势:

    1. alova 以请求适配器、存储适配器、UI 框架适配器的方式,将请求工具和请求方式进行了强制解耦,实现了低耦合,提高了代码的可移植性,而不是可选项。
    2. alova 中的 Method 概念,用于实现 RSM 的请求行为,它也强制将请求相关的信息、请求行为相关的信息高度聚合在了 Method 中,实现了高聚合。

    作者原话告诉我:alova 提供了高聚合低耦合的代码组织方式,可以更大程度地管理请求相关的代码,随着项目越来越复杂,它的优势也就会慢慢显现出来,而且在编码方面也更加统一了。同时保持了高度了灵活性,供用户提供了足够的自定义空间。

    因此,我会把 alova 放在介于规范型库和功能型库的中间位置

    最后,据官网介绍,alova 的目标是通过按业务场景来实现兼开发体验和用户体验为一体,而 alova 的高度灵活性就可以支持自定义策略,你可以封装了公司内部用,比如你的公司很喜欢用某种处理来优化性能,或者写成 alova 插件一样的自己的策略库,那 alova 刚好都可以提供支持。

    说到这边,好像 alova 的 use hook 形式显得好像没那么重要了,这个就要问作者了🙄。不懂有没有解答大家的疑问。

    (升华)开源框架罪恶史

    react 和 vue 都更关注 UI 层面,它们简化了 UI 层面的问题,但据我的理解,目前从 js 逻辑的层面却还是没有统一制约规范,或相关的 js 逻辑框架来解决这个问题,新手和高手写出的代码可维护性上还是有一定差距的。UI 框架让事情简单化的同时,也养肥了一堆躺在 UI 框架的成绩上好吃懒做的人,这些人往往会有以下两个问题:

    1. 不再思考规范问题、模块之间的界限和协作,甚至都意识不到这些东西的存在,然后不分职责、把代码到处乱写,请想象有一只狗到处乱拉……,然后堆积成的叫什么山😎。
    2. 他们只享受上层成果,不再关注底层的东西,哪怕稍微底层一点的,因为确实用不着了,就像我们不再关注垃圾回收的问题( C 语言里是需要手动回收的),更离谱的是,有些人连getElementByIdappendChildinsertBefore是干什么的,更别问他们 nodetype 有几种类型,fragment 是什么,注释是不是一种 node 等等。

    可想而知,尖端人才变少是有理由的,知道为什么高级前端难招了吧!!!当然也不乏一小部分喜欢钻研的同学,喜欢知其然知其所以然。

    这好像是时代发展、科技进步带来的无法避免的副作用,它们为我们提供了强大且便利的工具外,也在慢慢摧残着这么一大群人,和平年代不需要那么多英雄。这让我又想到了《反脆弱》里的观点 —— 现代化是这个世界的脆弱推手。

    插个题外话,毕竟 react 和 vue 接管的是 UI 层面的组件化规范,但在 js 逻辑层面的规范都还停留在文档上,还没有形成制约型规范,在这个层面新手朋友一样可以把它们写成意大利面,有兴趣的同学也可以开始思考一下了,有没有可能从 js 逻辑层面提出制约型规范,然后形成一个新的 js 框架,就像 UI 框架组件化规范一样,如果有人做到了,可否回来留言告诉我下😌😌😌

    结尾

    这篇文章并没有去解决一个具体问题,能看到这里的同学,看来都是学习和交流的同学。

    那问题来了,你们理解的代码规范是怎样的呢?

    24 条回复    2023-08-01 01:40:46 +08:00
    agagega
        1
    agagega  
       271 天前 via iPhone
    关键字:抽象泄露。在抽象能够完美工作,不需要面对性能问题或无法实现的需求时,框架带来的技能需求下降不是好事吗?
    haolongsun
        2
    haolongsun  
       271 天前
    过早优化是万恶之源,遇到了再去解决,没遇到之前就不去想,不然劳心费神,没办法专注当前事情。
    janus77
        3
    janus77  
       271 天前
    看了半天,没发现前端的形容词
    haha512
        4
    haha512  
       271 天前   ❤️ 1
    回字的第 108 种写法
    Garwih
        5
    Garwih  
       271 天前   ❤️ 7
    一人分饰两角,有种精神分裂的美
    dw2693734d
        6
    dw2693734d  
       271 天前 via iPhone
    phoenix 的 LiveView 也不错
    hsfzxjy
        7
    hsfzxjy  
       271 天前   ❤️ 2
    > 可想而知,尖端人才变少是有理由的,知道为什么高级前端难招了吧

    框架的诞生降低了领域的门槛,使更多的人涌入这个领域。尖端人才的绝对数量没有减少,而是被稀释了。

    > UI 框架让事情简单化的同时,也养肥了一堆躺在 UI 框架的成绩上好吃懒做的人

    我同意你描述的这个现象,但最好不要责怪他们/框架。这其实是多数领域的普遍规律:技术的进步降低了一个领域的门槛,导致更多的人以此谋生,这从社会层面来看是好的事情。只要在领域高层的地方一直有人思考领域的前进方向,这个领域就是会良性发展的。

    ---

    > 因为我从这些质疑声中看到了,很多人的代码思维都还停留在使用层面,而缺少更深度的理解和思考

    另外,你的两篇帖子的标题都有过分扩大化的嫌疑——上一篇帖子的大多数负面评价多来源于此。我认为你将“大量质疑的出现”完全归因于“很多人缺少更深度的理解和思考”是不合适的,因为标题有很强的情绪引导效果。理性的交流还需要我们使用较为平常的表达方式。
    charlie21
        8
    charlie21  
       271 天前 via Android
    在你的例子里提到的 vue SFC (Single-File Component ,本质上是 vue 编译器新晋支持的语法糖) 刚出时候也是受到抵制的。但后来经受住了时间的检验
    iOCZ
        9
    iOCZ  
       271 天前   ❤️ 1
    如果人人都要精通的话,能从事这个行业的人就会变少,生产效率就会比较底下。社会化分工也存在于互联网这个行业。让不同水平的人去关注不同层面的东西这个是合理的。但总得有人去维护底层,需要掌握所有的基础知识。
    snoy
        10
    snoy  
       271 天前
    什么开源框架目前都不如节流框架给力😄,搞一个节流框架团队人员减半😄,
    chenyduan
        11
    chenyduan  
       271 天前
    首先开源无罪,把自己的知识成果无私奉献出来是值得称赞的;

    但是我感觉你所说的优势(低耦合),作为一个网络请求工具,是没有使用场景的;
    回忆一下我自己使用 ajax 或者 axios 的场景,通常就是只配置一次公共属性,在业务中我只需要关心请求路径、请求方法(get,post,put...)和请求参数.;
    如果我担心在文件中引入了第三方库的文件,完全可以用一个 wrapper 来处理. 至于路径、方法,参数这三者本来就是业务的一部分.要改这三者,只能是业务变了.
    lanlanye
        12
    lanlanye  
       271 天前 via iPhone
    这个升华部分的批判毫无道理……就好像在批判 Java 这样有 GC 的语言让程序员的平均水平降低了一样……
    事实上确实降低了,但它同时降低的还有这个行业的门槛,最终的结果是提高了整个行业的生产效率,而效率才是市场真正追求的东西。
    至于顶尖人才变少,这个不知道有没有具体数据支撑?也许这些人的绝对数量并没有什么变化,给你这种感觉是因为他们占行业总人数的比例减少了。
    danhahaha
        13
    danhahaha  
       271 天前   ❤️ 6
    啥时候能把这个捧一个打一个的丑毛病改改?
    jiangzm
        14
    jiangzm  
       271 天前   ❤️ 1
    罪恶都来了 哈哈哈哈😂,前端的东西很多但都很简单,写框架的和写业务的区别真不大只是侧重方向不一样,没必要拉高踩低的。
    还有造这种轮子除了拿来练练手其他意义不大。 还有看了项目代码总结就是不太规范、质量不高,过度设计。
    http client 仅关心网络层就够了,不需要关心业务场景,比如缓存、分页、组件、应用层框架等。
    代码并不是多就是好,有很多前端优秀的库都是如此,简单易用是首要原则。
    molvqingtai
        15
    molvqingtai  
       271 天前 via Android   ❤️ 1
    分析得很好,请以后不要分析了
    adoal
        16
    adoal  
       271 天前   ❤️ 1
    前端戏精姿势多
    geligaoli
        17
    geligaoli  
       271 天前
    凡是一旦扯上伟大与罪恶的,秒变精神小伙
    KENNHI
        18
    KENNHI  
       271 天前 via Android
    前端弄出来这么一大堆概念库和框架,最后因为用户的设备带不动他们的“先进理念”,打开网页动不动狂吃内存风扇狂转之后又得借助 SSR 通过服务器渲染,给我整不明白了,那我为什么不用 Thymeleaf 甚至 jsp 加点类似 jQuery 的库呢。你们又不是在浏览器里实现个 office365 ,自己问问自己写的那些东西用 jQuery 是不是一样能实现?把 Model 和 Router 都还给后端吧,脚本程序在浏览器验证下表单,必要的时候用个 Ajax 差不多了,整个 web 都被你们搞得卡得要死。
    Cloudust
        19
    Cloudust  
       271 天前
    分析的很好,不过从使用来看跟 axios 貌似没什么太大区别?没看出优势到底在哪
    zdw189803631
        20
    zdw189803631  
       271 天前
    难道不是因为你起的标题的缘故... 这种标题见得多,谁看到都想喷一句😂
    AlexHsu
        21
    AlexHsu  
       271 天前
    害 说白了前端需要一个巫妖王 天天维护屎的前端知道 spring 为啥又丑又大又笨 天天有新框架要干他就是干不掉了吧 因为没有这个巫妖王 行业规范化都是暂时的
    所以问题来了 前端为什么没有巫妖王 框架这么割裂
    sankooc
        22
    sankooc  
       271 天前
    你们真觉得 react 在大部分应用场景上都有优势么? 为啥我觉得接盘 react 更痛苦
    Daming
        23
    Daming  
       270 天前
    标题很有攻击性,让人看了就有进来喷的冲动。
    learningman
        24
    learningman  
       270 天前 via Android
    一桶水不满,半桶水晃荡。
    啥时候进了 ecma 委员会再来高屋建瓴吧
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   2959 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 30ms · UTC 08:05 · PVG 16:05 · LAX 01:05 · JFK 04:05
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.