Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
EthanLin-TWer opened this issue May 19, 2017 · 0 comments
Assignees

Comments

@EthanLin-TWer
Copy link
Owner

EthanLin-TWer commented May 19, 2017

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

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

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

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

库和框架的问题:

@EthanLin-TWer EthanLin-TWer added this to the Iteration 5: Supreme❗ milestone May 19, 2017
@EthanLin-TWer EthanLin-TWer self-assigned this May 19, 2017
@EthanLin-TWer EthanLin-TWer removed this from the Iteration 5: Supreme❗ milestone Aug 10, 2017
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant