大家好,我卡颂。

最近AIGC(AI Generated Content,利用AI生成内容)十分热,技术圈也受到了很大冲击。目前来看,利用LLM(Large Language Model,大语言模型)辅助开发还停留在十分晚期的阶段,次要利用是辅助编码,即用自然语言输出需要,模型输入代码。更近一步的摸索也仅仅是在此基础上的一层封装(比方copilot Xcursor)。

但即便在如此晚期阶段,也对开发者的心智产生极大震撼,AI让程序员就业这样的论调甚嚣尘上。

LLM的暴发对前端意味着什么?本文尝试预测一波2024年之后的前端开发模式,这个预测遵循如下准则:

  • 尊重技术主观倒退法则。以以后已有技术为根底预测,而不是将预测建设在某种扑朔迷离的高端技术,或者假想某些技术冲破重大瓶颈
  • 尊重兽性。程序员只是谋生的职业,新的开发模式即便再厉害,如果让程序员赚不到钱,那也是很难推广开的

欢送退出人类高质量前端交换群,带飞

范式迁徙的实质

为了预测将来,先看看咱们是如何走到当初的。

在前端开发畛域,咱们经验了从jQuery为代表的面向过程编程向前端框架为代表的状态驱动模式的迁徙。

当问到该选Vue还是React开发?,这样的问题会引起很大争议,但如果问到该选jQuery还是框架开发?,这样的问题就不会有太多争议。

为什么前端畛域广泛承受了这种范式的迁徙?在我看来,有两个起因:

1. 开发效率进步

这一点毋需多言,置信前端同学都有领会。

2. 门槛进步

面向过程编程是十分浅显易懂的开发模式。君不见,已经的前端靠一本尖锐的jQuery就能打天下。相比之下,状态驱动就有肯定学习门槛。

当一项有肯定门槛的技术(这里指前端框架)变为行业事实上的规范时,行业门槛就晋升了,这为从业者构筑了行业壁垒。

事实上,正是因为:

  1. web利用复杂度进步
  2. 前端框架的风行

才让后端工程师工作职责中的view层,分化出前端工程师这一职业。

对于前端畛域来说,只有同时均衡了提效进步门槛的技术,才会被市场(这里的消费者指前端工程师)承受。

举个反例,Angular全家桶的模式尽管进步了开发效率,然而同时,门槛进步太多了。

而且更糟的是,Angular中的很多概念都是从后端迁徙而来,作为一款前端框架,对后端更亲和且门槛高,这对自身就是从后端view层中分化出的前端工程师来说,是比拟排挤的。

再举个反例 —— Vue。有同学会说,Vue这么风行的前端框架,你说他是反例?

还是从提效进步门槛的角度看,Vue提效的同时,因为其模版语法、响应式更新等个性,他是升高了开发门槛的,这意味着应用Vue时:

  1. 同样是开发业务,老前端与新前端差距不大
  2. 必要时后端通过简略的学习,也能接手局部需要

重申一下,我并不是说Vue不好,相同,他是很优良的前端框架。这里只是从兽性的角度剖析,并且这个剖析很有可能是主观、带有偏见的。

再看个侧面例子 —— React HooksHooks对开发效率、组件复用性以及他对React将来倒退的影响这里不赘述了。次要聊聊进步门槛

  1. 一方面,什么时候封装自定义Hook,如何封装自定义Hook,如何躲避Hook的坑,老前端与新前端有比拟大的差别
  2. 更重要的是,后端改改JSX还行,要改基于Hooks的组件逻辑,是有肯定难度的

既提效,又进步门槛,我认为这才是Hooks在前端畛域炽热的起因。

同样的起因,从兽性的角度,我很看好Vue Composition API

所以,前端编程范式迁徙的实质是:把握提高效率进步门槛之间的均衡。

这个论断会成为前面预测将来开发模式的根据。

当范式无奈再迁徙时

以后端框架成为事实上的规范后很长一段时间,业界也在一直摸索新的开发范式。

有一种开发模式每过几年都会被搬出来炒一遍,他就是低代码。用咱们下面的论断来剖析下:在市场抉择的状况下,先抛开低代码是否能提高效率不谈,显然他的目标是升高门槛

从兽性的角度登程,他就很难在程序员群体中自发流传开。

那么,如果没有新的范式呈现,会产生什么事件?会内卷。

咱们会发现,这几年前端的倒退轨迹,就是在反复一件事:

  1. 围绕前端框架周边,一直摸索各细分畛域的最佳实际
  2. 当摸索出最佳实际后,就把他集成到框架中

举个例子,React Router作为React技术栈中路由这一细分畛域的一个开源库,通过长期迭代,逐步成为支流路由计划之一。

React Router团队基于React Router开发出Remix这一React框架。

这么做,在没有新的范式呈现前,也能基于以后范式(前端框架),达到上述2个目标:

  • 提高效率:框架集成了最佳实际,开发效率更高
  • 进步门槛:除了学习React,还得学习新的下层框架

相似的,各种CSS解决方案(比方tailwind css)也是同样的情理:

  • 提高效率:进步CSS编写效率
  • 进步门槛:新的概念、语法须要学习

那么,将来围绕提高效率进步门槛的均衡,前端开发模式会如何倒退呢?

从思考范式到思考流程

首先,我认为,在无限的将来,不会呈现新的更先进的范式能让前端畛域广泛认可并大规模迁徙(就像从jQuery到前端框架的迁徙)。

那么,为了提高效率,除了扭转范式范式内 内卷两个抉择外,还有个抉择 —— 让整个开发流程提效。

从需要文档到最终代码,存在4级形象:

  1. PM用自然语言编写的需要文档
  2. 需要评审时,PM给开发形容需要后,开发脑海里造成的业务逻辑
  3. 开发依据业务逻辑划分各个模块或组件
  4. 开发实现各个模块或组件的具体代码

以后咱们应用LLM辅助编程时(比方以chatGPT为例),次要是用自然语言输出模块或组件业务逻辑,再让模型输入具体代码。也就是借助模型主动实现从3到4级形象的转变。

比如说下图咱们让chatGPT实现一个计时器:

这个计时器可能是咱们需要中的某个模块,在此chatGPT帮咱们实现了从形象3(实现一个计时器组件)到形象4(计时器组件的代码)。

如果仅仅到这一步,只能说这是个更高效的辅助工具,并不能达到整个开发流程提效的水平。为了达到这种水平,咱们须要让LLM帮咱们实现从形象1到4的整个过程。

LLM如何实现4级形象转换

接下来咱们来看,基于以后已有的模型,如何实现形象1到形象4的主动转换。

首先,来看形象1(PM用自然语言编写的需要文档)。chatGPT以后曾经把握根底的理解能力,所以他是可能了解需要文档的含意的。

下图是我从网上找的某需要文档中的登录性能流程图:

以以后支流的GPT-3.5举例,尽管GPT-3.5不能了解图片(不能了解需要文档中的流程图),但咱们能够将流程图用文字描述进去(最新的GPT-4曾经领有了解图片含意的能力)。

上述登录性能流程图能够用文字概括为:

  1. 关上App后有3个选项,别离是“账号密码登录”、“快捷登录”、“第三方登录”
  2. 抉择“第三方登录”,进入第三方,批准受权后登录胜利
  3. 抉择“快捷登录”,输出手机号和验证码并抉择身份,点击登录后登录胜利
  4. 抉择“账号密码登录”,输出手机号,如果已注册,输出明码,点击登录后登录胜利
  5. 抉择“账号密码登录”,输出手机号,如果未注册,进入注册页,输出手机号,如果手机号已注册,回到“账号密码登录”
  6. 抉择“账号密码登录”,输出手机号,如果未注册,进入注册页,输出手机号,如果手机号未注册,填写手机号、验证码、明码、姓名、抉择身份,点击注册,结束

形象1到形象2

如何实现从形象1到形象2(业务逻辑)的转变呢?换句话说,如何用一种介于自然语言与理论代码之间的标准形容业务逻辑?

这种标准应该领有齐备的数据结构(相似JSONXML),因为这样会带来很多益处:

  • 相比于自然语言,用标准的数据结构示意的业务逻辑可能传播更精确的用意
  • 业务需要的一直增多,仅仅对应数据结构体积的增大,即便再简单的业务,只须要分批将业务逻辑代表的数据结构投喂给模型,模型就能齐全了解咱们的业务
  • 数据结构能够保留在变量中,通过变量名就能指代业务逻辑,无需再用自然语言大段的向模型形容业务逻辑

咱们能够利用SCXML(State Chart XML)格局。SCXML是由W3C定义的一种示意状态机XML格局,他可能示意状态之间的变动。

前端利用的实质其实就包含两局部:

  • 状态的变动
  • 状态到视图的映射

其中状态到视图的映射框架曾经帮咱们做了。所以,只有能示意状态的变动,其实就能示意业务逻辑。

当初,咱们让chatGPT将流程图翻译为SCXML格局:

失去如下构造(你不必细看,理解个大略就行):

<scxml version="1.0" xmlns="http://www.w3.org/2005/07/scxml">  <state id="mainMenu">    <transition event="THIRD_PARTY_LOGIN" target="thirdPartyLogin" />    <transition event="QUICK_LOGIN" target="quickLogin" />    <transition event="ACCOUNT_LOGIN" target="accountLogin" />  </state>  <state id="thirdPartyLogin">    <onentry>      <send event="AGREE_AUTHORIZATION" />      <send event="LOGIN_SUCCESS" />    </onentry>  </state>  <state id="quickLogin">    <onentry>      <send event="INPUT_PHONE_NUMBER" />      <send event="INPUT_VERIFICATION_CODE" />      <send event="SELECT_IDENTITY" />      <send event="LOGIN_SUCCESS" />    </onentry>  </state>  <state id="accountLogin">    <state id="inputPhoneNumber">      <transition event="PHONE_NUMBER_SUBMITTED" target="checkRegistered" />    </state>    <state id="checkRegistered">      <onentry>        <send event="CHECK_REGISTERED" />      </onentry>      <transition event="REGISTERED" target="inputPassword" />      <transition event="UNREGISTERED" target="register" />    </state>    <state id="inputPassword">      <onentry>        <send event="INPUT_PASSWORD" />        <send event="LOGIN_SUCCESS" />      </onentry>    </state>    <state id="register">      <state id="inputPhoneNumber">        <transition event="PHONE_NUMBER_SUBMITTED" target="checkRegistered" />      </state>      <state id="checkRegistered">        <onentry>          <send event="CHECK_REGISTERED" />        </onentry>        <transition event="REGISTERED" target="inputPassword" />        <transition event="UNREGISTERED" target="inputUserInfo" />      </state>      <state id="inputUserInfo">        <onentry>          <send event="INPUT_PHONE_NUMBER" />          <send event="INPUT_VERIFICATION_CODE" />          <send event="INPUT_PASSWORD" />          <send event="INPUT_NAME" />          <send event="SELECT_IDENTITY" />          <send event="REGISTER_SUCCESS" />        </onentry>      </state>    </state>  </state></scxml>

至此,咱们实现了形象1到形象2的转变。

形象2到形象3

SCXML格局没法间接在JS代码中应用。为了用代码实现逻辑,咱们须要应用遵循SCXML标准的库。xstateJS中比拟风行的状态机开源库。

所以接下来咱们让chatGPT将上述SCXML格局转换为xstate语法:

失去后果(同样,具体代码你不必在意,理解我想表白的转换意思就行):

import { Machine, sendParent } from 'xstate';const loginMachine = Machine({  id: 'login',  initial: 'mainMenu',  states: {    mainMenu: {      on: {        THIRD_PARTY_LOGIN: 'thirdPartyLogin',        QUICK_LOGIN: 'quickLogin',        ACCOUNT_LOGIN: 'accountLogin'      }    },    thirdPartyLogin: {      onEntry: [        sendParent('AGREE_AUTHORIZATION'),        sendParent('LOGIN_SUCCESS')      ]    },    quickLogin: {      onEntry: [        sendParent('INPUT_PHONE_NUMBER'),        sendParent('INPUT_VERIFICATION_CODE'),        sendParent('SELECT_IDENTITY'),        sendParent('LOGIN_SUCCESS')      ]    },    accountLogin: {      initial: 'inputPhoneNumber',      states: {        inputPhoneNumber: {          on: {            PHONE_NUMBER_SUBMITTED: 'checkRegistered'          }        },        checkRegistered: {          onEntry: sendParent('CHECK_REGISTERED'),          on: {            REGISTERED: 'inputPassword',            UNREGISTERED: 'register.inputPhoneNumber'          }        },        inputPassword: {          onEntry: [            sendParent('INPUT_PASSWORD'),            sendParent('LOGIN_SUCCESS')          ]        },        register: {          initial: 'inputPhoneNumber',          states: {            inputPhoneNumber: {              on: {                PHONE_NUMBER_SUBMITTED: 'checkRegistered'              }            },            checkRegistered: {              onEntry: sendParent('CHECK_REGISTERED'),              on: {                REGISTERED: 'inputPassword',                UNREGISTERED: 'inputUserInfo'              }            },            inputPassword: {              onEntry: [                sendParent('INPUT_PASSWORD'),                sendParent('REGISTER_SUCCESS')              ]            },            inputUserInfo: {              onEntry: [                sendParent('INPUT_PHONE_NUMBER'),                sendParent('INPUT_VERIFICATION_CODE'),                sendParent('INPUT_PASSWORD'),                sendParent('INPUT_NAME'),                sendParent('SELECT_IDENTITY'),                sendParent('REGISTER_SUCCESS')              ]            }          }        }      }    }  }});export default loginMachine;

这段代码咱们能够间接粘贴到xstate的可视化编辑器中查看:

图中初始状态能够转移到3个状态(这些状态都是chatGPT生成的),其中:

  • QUICK_LOGIN —— 快捷登录
  • ACCOUNT_LOGIN —— 账号密码登录
  • THIRD_PARTY_LOGIN —— 第三方登录

每个状态接下来的变动逻辑都清晰可见。比方,当进入ACCOUNT_LOGIN状态后,后续会依据是否登录(UNREGISTEREDREGISTERED)进入不同逻辑:

也就是说,chatGPT了解了需要文档想表白的业务逻辑后,将业务逻辑转换成代码示意。

读者可将上述xstate代码复制到可视化编辑器中看到成果

形象3到形象4

接下来,咱们只须要让chatGPT根据上述xstate状态机生成组件代码即可。

这时有同学会问:chatGPT对话有token限度,没法生成太多代码怎么办?

实际上,这可能并不是好事。在我已经供职的一家公司,前端团队有条不成文的规矩 —— 如果一个组件超过200行,那你就应该拆分他。

同样的,如果chatGPT生成的组件超过了token限度,那么应该让他拆分新的组件。

拆分组件的前提是 —— chatGPT须要懂业务逻辑。显然,他曾经懂了xstate数据结构所代表的业务逻辑。

更妙的是,咱们能够让chatGPTSCXML格局转换而来的xstate数据结构保留在一个变量中,在后续对话中,咱们用一个变量名就能指代他背地所示意的业务逻辑(这里保留在变量m中)。

当咱们要生成业务组件代码时,让chatGPT从模块中导出m实现组件逻辑:

对于理论场景下比较复杂的需要,通过从形象1到形象3的转换,咱们会失去代表业务逻辑的不同变量,比方:

  • signin变量代表登录逻辑
  • login变量代表注册逻辑
  • PopupAD变量代表弹窗广告逻辑

如果弹窗广告的逻辑和是否登录相干,那么要实现弹窗广告组件代码只须要通知chatGPT

依据signinPopupAD实现弹窗广告的react组件,其中signin变量由xxx模块导出,PopupAD变量由yyy导出。

如果你司应用其余框架,只需将其中react换成其余框架名即可。当大家还在争执哪个框架更优良时,LLM曾经轻轻帮开发者实现了框架自在

新开发模式的劣势

让咱们从提高效率进步门槛的角度剖析这种新开发模式的劣势。

提高效率

首先,这种新模式能显著进步开发效率。实质来说,他将前端工程师从实现需求的角色转变为review代码的角色。

极其的讲,当需要评审会完结的那一刻,第一版前端代码就生成了。

其次,他能解放局部测试同学的生产力(抢局部测试同学的活儿)。对于保护过屎山代码的同学,必定遇到过这样的场景:明明只是改变一个小需要,测试问你改变影响的范畴,你本人都不分明会有多大影响,为了稳当起见只能让测试笼罩更大的回归测试范畴。

在应用基于状态机的开发模式后,任何改变会造成的影响在状态图中都清晰可见。同时,因为代码逻辑的实现基于状态机,能够据此主动生成端到端的测试用例,模型也能依据状态机形容的逻辑本人补足其余单测。

进步门槛

接下来,咱们从进步门槛的角度剖析。

首先,可能对模型生成的代码进行查漏补缺自身就要求开发者有肯定前端开发程度。

其次,这种开发模式引入了新的形象层 —— 状态机,这无疑会减少上手门槛。

但这都不是最重要的,最重要的是 —— 这套模式强制前端开发须要更懂业务。

以前,拿到产品的需要文档后,你能够在做的过程中遇到不懂的再问产品。应用新的开发模式后,你必须很懂业务,做到在需要评审时就能指出需要文档中不合理的中央

因为当需要评审完结后,你会将这份需要文档投喂给模型间接生成业务代码(两头会经验生成SCXML生成xstate数据结构保留xstate变量、应用变量生成组件代码)。

当大家技术水平旗鼓相当时,懂业务才是前端的外围竞争力。

综上,这套开发模式在极大提高效率的同时进步了门槛,我认为在将来很有可能成为支流前端开发模式。