082020.7

和leader阿义的对话中,他指出,现在前端面试或许已经不适用原来的前端能力模型了,传统要求性能、对基础知识的全面掌握,可能已经不适用现在的招聘需求,前端分工明显,企业招聘更多希望是招到合适的立马可以上手的人,但一个人精力有限,不可能所有知识和能力都掌握。所以,细化的能力模型越来越突出,比如我们团队而言,在性能这个点上的要求并没有那么高,但是在对业务的把控、代码的稳定性上要求很高,因为我们对接的是toB的产品,不同产品对代码、系统的要求重点不同,所以不能一概而论的对应聘者进行要求。

09:41:54 已有1条回复
  1. 吾辈更倾向于招优秀(喜欢学习和自我驱动)的人,而不是合适但不愿变化的人(入职即巅峰)╮( •́ω•̀ )╭
    #940 rxliuli 2020-07-09 07:39 回复
292020.6

Creating custom JavaScript syntax with Babel

212020.6

Does DDD Belong on the Frontend? - Domain-Driven Design w/ TypeScript

172020.6

NPM 依赖包版本范围控制

基本概念就不多说了,主要是想在项目中,使用“范围”控制的优势,写了一个依赖版本号之后,未来依赖包升级可以不需要手动升级该版本号,可自动安装最新兼容版本。

常规兼容

常规情况下,需要掌握 ^, ~, x, - 这几个版本控制符即可。例如 ^1.0.0 相当于 1.x,~1.1.0 相当于 1.1.x。

实验阶段的包

版本号以 0 开头的包都是实验阶段的。例如 0.0.1, 0.1.0 这种包都是处于实验阶段,还为发布正式版本,因此,在正式环境使用时要小心。基于这种情况,我建议直接写死版本号,而不要采用 ^ 或 ~,因为你怎么知道新加的实验功能是否符合你的预期。

当然,纯理论探讨,实验阶段的包也可以 ^ 或 ~,但是相对而言,全部降一位。例如 ^0.1.0 可以兼容 0.1.1 版本,但不兼容 0.2.0 版本。如果 ~0.0.1,相当于没写 ~。

Prerelease

和实验阶段包又不同,它处于预发布阶段。比如在发布 3.0.0 之前,可能需要公测一段时间,各种修 bug。但理论上,prerelease 相当于正式版的实验阶段。

对于 prerelease 版本而言,前面的常规方案和实验阶段常规方案,都不包含 prerelease 版本,也就是说 ^3.0.0 并不包含 3.1.0-alpha.1。但是反过来,3.1.0-alpha.1 属于 3.1.0 的一部分,用一个比喻来类比:A-, A, A+ 都属于 A 等。但是 ~A, ^A 都只包含 A, A+ 而不包含 A-,类比数学上的概念,就是复数中虚数部分。

那么怎么控制 prerelease 的范围呢?

^3.0.0-alpha 将包含 3.0.0-alpha.0, 3.0.0-beta.0, 3.0.0-rc, 3.0.0, 3.1.0...,但不包含 3.1.0-alpha.x。也就是说,^ 或 ~ 可以包含所指示的版本的 prerelease 版本,以及兼容该版本的高版本(不含高版本的 prerelease 版本)。

升级 prerelease 可以使用 npm version prerelease 进行升级。

两个 prerelease 版本号谁的版本更高呢?prerelease 末尾版本号部分纯粹以字母顺序进行排序,因此 rc > beta > alpha,而且,由于纯粹按字母排序,所以没有 alpha.x 这种使用 x 的表示方法。因此,如果要控制为只包含 prerelease 的版本,没有直接的办法,只能使用 >=3.0.0-alpha <3.0.0-beta 这种表示方法。

12:07:28 已有0条回复
112020.6

纯CSS实现Table固定表头和首列

Table固定表头和首列这种需求应该比较常见。以往的做法,需要写一大堆脚本,而现在,可以使用position:sticky轻松实现这个效果。

.table-container {
width: 100%;
height: 100%;
overflow: auto;
}

/* 首列固定 */
.table-container thead tr > th:first-child,
.table-container tbody tr > td:first-child {
position: sticky;
left: 0;
z-index: 1;
}

/* 表头固定 */
.table-container thead tr > th {
position: sticky;
top: 0;
z-index: 2;
}

/* 表头首列强制最顶层 */
.table-container thead tr > th:first-child {
z-index: 3;
}

HTML结构上,必须将 <table> 放在 <div class="table-container"> 子节点,且内部不要有其他 position 设置。

14:48:16 已有0条回复
102020.6

NPM 版本范围控制

092020.6

angularjs有什么点可以碾压vue, react之流

这里所指的angularjs是只angular早期的1.x版本。虽然vue, react在热度上已经碾压angularjs几条街,但是在面对web开发(以DOM为中心的开发)中,某些场景下面,angularjs可能比任何框架或库都做得好。这里,主要举例两个点。

Modal弹窗的隐现

现在是单向数据流和immutable的天下,其目的是为了数据流所蕴含的业务流清晰,但代价是代码编写变得复杂。举一个例子,用react写一个弹出框modal,按照单向数据流的范式,必须将modal的隐现通过一个prop来控制,而这个prop必须由外部组件传入,为了控制这个prop,就必须再配合一个回调函数来触发prop的改变。这是对modal组件而言,而对于外层调用modal组件而言,必须自建一个state传给对应的prop,同时,必须自建一个方法作为回调函数传给modal。这里面编程出错的几率远远大于保证业务流正确的几率,也就是成本的提升。因为,你必须在回调函数中,正确处理state的变化值。

而双向数据绑定则完全不需要,传入prop之后,不需要再在回调函数中修改state,双向绑定逻辑会自动修改state。(当然,这基于不同的数据思想,一个是immutable,一个是mutable,各自不同。)虽然基于的范式不同,但是一个modal的显示和隐藏在双向数据绑定范式下,更有利。

表格固定列

Web表格(grid table)是前端交互领域及其复杂的一个场景。其中的一个需求是,固定表格的前n列,剩下的可以左右滑动来查看。在基于 virtual dom 的 vue, react 编程中,自己手写是及其麻烦的,你需要手动在模板中拆分块,在脚本中拆分数据。总之,由于virtual dom的编程范式如此,本身就是要隔绝dom的操作。但是实际上,在前端领域,grid table的操作往往是virtual dom最早提出来的,基于数据变化,只修改小部分dom的需求。但是,实际上最终,virtual dom类编程,在这个点上,反而是最辣鸡的。辣鸡之点不在于性能,而在于编程的复杂。

而使用angularjs则太过便利。首先,angularjs也是基于数据响应更新界面的。其次,angularjs是基于DOM操作进行渲染的。所以,在angularjs中,如果要实现表格固定列的需求,只需要写一个directive,使用 template() 函数来动态返回模板,返回的模板是字符串,于是可以各种骚操作修改字符串来控制html结构,这比vue、react的结构编程快上10倍不止。接下来是对DOM的重新调整,当按照模板结构和样式完成渲染之后,你可能还需要调整列宽度、位置、滚动条是否显示、左右两边每行的点击联动、左右都可滚动(pointer-events: none;)等等操作,在不修改任何数据的情况下,瞬间通过DOM操作完成。而如果这些东西依赖virtual dom去做,可以说极其麻烦,代码量上翻10倍很正常。

除了上述这两个例子外,我在开发中还会碰到其他的一些场景,发现有的时候恨angular是垃圾,有的时候又觉得它diao。总之,在不同的场景下,不同的编程范式所带来的收益是不同的,但是问题点在于,我们无法真正的完全在同一套代码中享受不同范式的好处。这也是前端框架的一个不足之处吧。

13:26:17 已有0条回复
282020.5

react-tyshemo-form 发布

昨晚想到了很晚,睡不着,然后就实现了它,今天就把它发布了。react-tyshemo-form基于tyshemo的model实现响应式,基于react-tyshemo实现react和model的绑定,最终体现为一个Field组件。

<Field model={model} name="field" component={FieldComponent} />

整个包的核心就在这个Field组件上面,它基于我早前在robust中提出的表单范式理论,对于表单视图而言,实际上只需要 value, required, disabled, readonly, hidden, errors 这几个信息,以及一个 onChange 回调函数。所以,这这个 Field 组件的实现上,完全遵照这个理论去做,对于用于展示字段 UI 的组件,只需要接收这些 prop 就够了。当然,为了必要的扩展,Field 也支持一个 extend 属性,用来确保可以传入其他 prop。

以上面这段示例代码为例,<Field /> 只是一个驱动器,主要作用是确保 model 上的 field 字段值发生变化时,可以重新渲染该字段。仅此而言,所以使用也超级简单。

14:04:52 已有0条回复
272020.5

领域模型 Domain Model

今天学到的新知识点,领域模型 Domain Model。简单总结一下,什么是领域模型?领域模型有哪些好处?如何在开发中运用领域模型?

什么是领域模型?

有两个领域对领域模型做出解释。

  • 管理领域:领域模型是对整个行业的工作模式的抽象总结。
  • 软件领域:领域模型是对对象普遍性的最高抽象。

虽然出发点不同,但是实际上表达意思的核心思想是一致的。要理解领域模型,首先看下“领域”的概念。横向比较,domain对应的是range,domain是定义域,range是值域。纵向对比,领域是比专业/职业/业务更高水平的概念,例如我们经常说“机器人领域”“水产品领域”“航空航天领域”。“领域模型”概念的核心思想,就是寻找某一宽泛范围内的行为模式的共性,抽象为可适用于这一范围内所有行为的普遍性原则、规律或方法。

在编程领域怎么去理解?从大的层面讲,电商类应用与OA办公应用是两个领域的应用,它们适用不同的业务领域模型。从小的角度讲,用户鉴权和订单跟踪这两个业务完全不同,适用不同的编程领域模型。这里你可以发现两个点:1)虽然鉴权和订单领域模型不同,但是这两个业务之间可能存在联系,比如是否得到订单信息基于鉴权的结果;2)虽然电商应用和OA应用业务场景不同,但是它们可能都需要鉴权。

所以,从编程角度看,领域模型实际上既要解决对象抽象的问题,也要解决对象间的关系问题,还要解决在什么事件下触发对象关系的转变问题。

领域模型有哪些好处?

这里的好处是指相对于业务模型来说。我们开发过程中,经常基于业务场景去进行设计。而一个应用系统的开发,必须应对业务需求的变化。特别是办公软件这种系统,一个企业使用办公软件,必然遵循企业管理的流程,而流程变更是常有的事,基于业务场景去设计和架构软件,并持续迭代,最终带来的后果就是在多次迭代之后,不得不进行重构。而如果该次重构仍然基于业务模型去重构的话,必然还会经历再一次的重构。因为一个业务模型是无法适应所有业务场景的。所以,一旦现实中的业务需求迭代了,给原有的技术架构造成必须重构的影响时,开发者没有任何回旋余地。

而如果基于领域模型设计软件,那么可能接受的代价更小。在分析业务本身时,不只为了实现业务去设计架构,而是从行业的普遍性出发去设计架构,同时结合自己的业务特征,再在设计好的架构上包上一层。哪一天自身的业务发生变化,往往只需要在上面包的那一层上做调整。在软件整体上,分不同的层“视图层-业务层-数据层”,在每一层中又具体的去划分,比如业务层“领域模型-业务模型-流转模型”。而且在设计之初,每一个领域(鉴权、订单等)都采用行业标准,再在行业标准基础上包一层实现定制。那么这一就可以以最小的成本,把知识沉淀在自己的真实业务代码中。

如何运用领域模型?

以下是我在这篇文章中看到的建议。

  • 理解后端领域模型
  • 建立前端领域模型
  • 分离领域层
  • 主导接口约定
  • 开发中注意业务含义
  • 实时同步

简单讲,就是要建立抽象类,这些类去定义领域对象的属性、方法,而且这些类要有一定的内在联系,可扩展。在视图层可以被很好的使用,并不需要在视图层去撰写业务逻辑。

一些相关话题的文章:

  • https://juejin.im/post/5d3926176fb9a07ef161c719
  • https://zhuanlan.zhihu.com/p/37904835
  • https://juejin.im/post/5b1c71ad6fb9a01e5918398d
  • https://zhuanlan.zhihu.com/p/109114670
  • https://www.jianshu.com/p/fe45506ea358
  • https://zhuanlan.zhihu.com/p/59886663
  • https://www.cnblogs.com/luminji/p/3703082.html

另外,刚才在阅读的时候,发现“视图模型”“业务模型”“领域模型”这些概念。现在前端编程实际上大部分是杂糅“视图模型”和“业务模型”,也就是MVVM中的VM那一套东西,真正的MVC还非常少见。

22:08:17 已有0条回复
202020.5

现代 Web 开发的现状与未来(JSDC 2019 演讲全文)