4.2 需求变动与开发模型 Requirement change and development models

发布于 2022-04-28 13:13:42 字数 11413 浏览 1112 评论 0

http://todomvc.com/

把这个视频再看一下,感受下这个演进:https://classroom.udacity.com/nanodegrees/nd001-cn-advanced/parts/7cfc9f99-e827-4ed3-8e13-126f6b0f3998/modules/59e5bbe2-0738-4654-ba6b-fd0feaa632de/lessons/3417188540/concepts/33916789400923

前端开发模式 发展简史

  1. HTML+CSS+JS+jQuery spaghetti: 面条式代码。一个需求,到处改动。根据页面变动的地方,找到其 id/selector,修改所有与其相关的 handler、样式、逻辑。这种组织,所有组件都依赖于 dom 元素的一个 id,也决定了 DOM API 的操作方式
  2. MV*(P or C):然后这时就开始分离关注点了。分离是怎么分离呢,就是人为划分出一个数据 model、展示 view 的概念,然后把其他所有的都划归为 controller 或 presentor。这是初步的 SOC,结果就是,数据和视图之间不能直接接触,事件发生后,由 controller 从 model 中拿数据,处理后结果反映到 model 中去,并通知 view 使用新的 model 更新页面,也即是 model 和 view 分别作为数据和展示的 single source of truth,所有控制(比如获取并处理 model、通知 view 等)类的工作全部揉到控制器中做。这其实只是上个阶段代码的重新组织,但也不是毫无进步。数据的这层解耦,使得一大部分数据的获取不再需要去 dom 中取;但本质上,只是把 jQuery way of working 中的5步划分了责任:getData 给 model 做,callAPI 给 controller 做,并负责通知 view 做 recalculateStylerenderDOMrenderCSSOM 的操作。并未改变 VC 仍然需要通过全局的 html-selector 获取 HTML 元素进行所有后续操作的本质
  3. 声明式、双向绑定:我认为所有近现代的前端框架都是抓住了 需要全局 html-selector 这个痛点入手的,而解决方案就是声明式的双向绑定;实现上则比如有 observable(Knockout.js / Angular.js)、props(React)、框架自实现的 html-anchor 标签(data-bind(Knockout.js)、v-if(Vue.js)、JSX(React)、ng-app(Angular 1.x))、变化检测(脏检查、VirtualDOM)等。这个使你的 handler 真正地能专注于业务处理、数据改变即可,数据你也不需获取,就在你自己控制下,反过来是框架来监测你的数据;数据改变后,你也不需要手动通知视图了,框架会帮你通知到特定的 HTML 元素上并做更新;更新视图时,你也不需要通过 jQuery 提供 html-selector 了,框架会用你所使用的 html-anchor 来追踪到你真正需要更新的 html view 上。可以说,这个阶段 通过声明式解决了全局的 html-selector 问题通过双向绑定解决了对视图的手动通知,让开发者可以真正专注在业务开发上。简直伟大的设计,演变到这里,基本就是近代前端框架的能力所在了,代表作有 Knockout / Backbone / Angular 1 等。但是不是到这里就没有继续发展了呢?当然不是,否则「现代」框架提法哪里来
  4. Modularization: 模块化。模块化说起来是 JS 本身的缺乏,ES6 的 import/export 应该是完美解决方案,可惜目前还没有原生实现,不过能通过 babel 使用也很满足了。除此之外,很多框架提供了自己框架特定的解决方案,比如 labjsangular 自带的 module 机制等。严格来说,模块化是整个 JS 领域发展的潮流,是 JS 代码的组织方式,不特定于框架,因此它应该算是一波独立的浪潮,与前端应用的框架没有紧耦合的联系
  5. Component: React 为代表作,Angular 1.5 component 跟上,后来成为许多现代前端框架组织前端代码的默认方式。它比第3步讲的分层

jQuery 操作模式

bindEvents(#selector, handler)
function handler(event) {
  const { currentState, params } = getNecessaryData(#selector)
  const { result, nextState } = callAPI(currentState, params)
  const style = recalculateStyle(nextState, previousState)
  
  renderDOM(#selector, result)
  renderCSSOM(#selector, style)
}

可以看到这个模式的短板在哪里?

  1. handlers都是全局绑定!原生的 JS+jQuery 是没有模块的。再说,JS 应该无法提供对 HTML 的模块化;只能通过模块化方案来解决;
  2. 在 handler 内部通过 HTML Selector 来进行元素定位,以进行 数据获取数据写回样式改变 等工作。这会带来几个问题:
    • 无法测试,因为 selector 是内部使用,无法传入,无法 mock,是函数黑箱行为。只能真实运行应用,真实使用 jQuery 进行测试,失去了单元测试快速的优势。不快,难测,最终都只可能导向两个结局:为了测一个简单功能堆叠大量测试数据,以至测试无法维护没人敢碰没人想写;没有测试
    • 无法查找引用点。任何 selector 的引用都是全局的,没有模块、没有组件的概念
    • 副作用难以预料。只要有一个 selector,应用的任何部分都可以向页面元素发出更改;你的页面挂了,可能是来自其他很远地方页面或脚本执行造成的结果
  3. 关注点无法分离。handler 需要自己处理数据搜集、API 调用、更新页面、更新样式等操作。实际上,真正业务发生的地方,只有 API 部分,更新页面和样式只不过是显示问题。在核心业务的 API 部分,它无法做到类似 redux reducer 这样纯净的 API:nextState = reducer(prevState, action)

现代前端框架 解决方案

现代的前端框架,先古如 Backbone / Knockout.js 者,后来者如 Angular / React / Vue.js 者,解决上面的哪些问题?使用了何理念和技术实现解决的?

写完前面的前端发展简史,我们应该就能发现,近现代框架进入前的 jQuery 时代有两个问题:无法分离的关注点,以及全局的 html-selector。前者主要是体现在,一个 event handler 需要处理多如 获取数据、业务逻辑、API 调用、更新视图、更新样式 等事务;后者主要是体现在一个 selector 是绑定到全局作用域下的,代码会污染全局环境。近现代框架提供的解决方案,主要即是解决了这两个问题。

无法分离的关注点一问,

在 MV* 和组件化的关系上,徐飞蜀黍讲,框架在做分层(就是我理解的 MVC、MVVM 等分层)的过程中其实推动了代码的组件化。

再提几个问题:解决后,现代的前端领域状态如何?又出来了哪些新的问题域?这些问题的可能解决方案又是什么?

复杂性管理

image
image
image
image

有 JS+ES6 是不够的,你需要组织文件,以反映需求变动的结构。我觉得「设计」的难点在于二:一是敏锐发现需求变动实际变的是哪个点,把它 SRP 出来;二是衡量设计好坏。

复杂性是不会凭空消失的,它只是从其中一处转移到另一处。对于设计评判,即看对于特定场景,该设计是否减少了复杂度。也即,复杂度是否正确地被转移到了框架内部,这取决于场景下的痛点是否客观存在,框架定位是否准确。

image

image

image

image

库和框架的区别?争论不休,有三点不错:

  • 都是在解决开发过程的「重复」问题。框架解决「代码组织、架构」方面的重复,库解决其他的重复
  • 库多为开发者主动调用,框架留下调用点,你写完由框架调用。这点区别基本是由上点确立的
  • 另一点忘了

组件化、模块化的关系是什么?提前设计的好处?提前设计的度?如何设计?

库和框架的问题:

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

JSmiles

生命进入颠沛而奔忙的本质状态,并将以不断告别和相遇的陈旧方式继续下去。

0 文章
0 评论
84960 人气
更多

推荐作者

linfzu01

文章 0 评论 0

可遇━不可求

文章 0 评论 0

枕梦

文章 0 评论 0

qq_3LFa8Q

文章 0 评论 0

JP

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文