政采云前端团队

政采云前端团队 查看完整档案

杭州编辑  |  填写毕业院校政采云有限公司  |  前端团队 编辑 www.zoo.team/ 编辑
编辑

Z 是政采云拼音首字母,oo 是无穷的符号,结合 Zoo 有生物圈的含义。寄望我们的前端 ZooTeam 团队,不论是人才梯队,还是技术体系,都能各面兼备,成长为一个生态,卓越且持续卓越。

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

个人动态

政采云前端团队 发布了文章 · 9月25日

ZooTeam 前端周刊|第 101 期

ZooTeam 前端周刊|第 101 期

浏览更多往期小报,请访问: https://weekly.zoo.team

一位架构师的感悟:过度忙碌使你落后

我踩过的坑,希望大家不用再踩。

全面拥抱云原生应用研发的拐点已经到来_SegmentFault 行业快讯

简介:随着云原生 Serverless 的概念在国内悄然升起,许多技术人似乎从中看到了希望,许多 IT 架构师已经把它作为目标技术架构之一。Serverless 的跨代优势对有技术敏感的架构师来说是技术发展的红利,一般都在持续关注它的发展。但是在这两年间,随着整个研发生态接触到 Serverless 的内容也越来越多,尝试也越来越多。...

东半球最酷的学习项目

东半球最酷的学习项目 | 1、我写的三十万字算法图解 2、千本开源电子书 3、100 张思维导图 4、100 篇大厂面经 5、30 个学习专题,右上角点个 star,加入我们万人学习群!English Supported!

我来聊聊前端应用表现层抽象

表现层设计和选型

32个手撕JS,彻底摆脱初级前端(面试高频)

作为前端开发,JS是重中之重,最近结束了面试的高峰期,基本上offer也定下来了就等开奖,趁着这个时间总结下32个手撕JS问题,这些都是高频面试题,完全理解之后定能彻底摆脱初级前端。

注意!下个月开始 GitHub 新建存储库的默认分支就不叫“master”了!

用 main 代替 master ,是为什么呢?

Moment.js 进入维护状态:周下载量超 1200 万的 JS 库已经完成了它的使命

近日,Moment.js 库的维护者表示,Moment.js 将进入维护模式,后续将不会再对其进行更新。同时建议开发人员考虑替代方案。

不四:产品工程师的修炼之路

我是不四,毕业后一直在阿里和蚂蚁工作,不四是我在阿里的花名,社区中一般以另一个花名 “死马” 出现。每一个人的成长轨迹都不一样,一路上遇到的机遇也各不相同,这次分享也仅站在一个普通工程师的角度来分享我的成长经历和贯穿其中的一些个人习惯。

让我们来写个 webpack 插件

对 webpack plugin 的简要介绍。

Node.js 如何处理 ES6 模块 - 阮一峰的网络日志

Node.js 如何处理 ES6 模块 - 阮一峰的网络日志

Vue3.0全球发布会干货总结

观看Vue3全球发布会的总结笔记,翻译水平有限大家海涵。 最后有学习资料汇总。

查看原文

赞 0 收藏 0 评论 0

政采云前端团队 发布了文章 · 9月21日

浅谈 React 中的 XSS 攻击

70 篇原创好文~
本文首发于政采云前端团队博客:浅谈 React 中的 XSS 攻击

前言

前端一般会面临 XSS 这样的安全风险,但随着 React 等现代前端框架的流行,使我们在平时开发时不用太关注安全问题。以 React 为例,React 从设计层面上就具备了很好的防御 XSS 的能力。本文将以源码角度,看看 React 做了哪些事情来实现这种安全性的。

XSS 攻击是什么

Cross-Site Scripting(跨站脚本攻击)简称 XSS,是一种代码注入攻击。XSS 攻击通常指的是利用网页的漏洞,攻击者通过巧妙的方法注入 XSS 代码到网页,因为浏览器无法分辨哪些脚本是可信的,导致 XSS 脚本被执行。XSS 脚本通常能够窃取用户数据并发送到攻击者的网站,或者冒充用户,调用目标网站接口并执行攻击者指定的操作。

XSS 攻击类型

反射型 XSS

  • XSS 脚本来自当前 HTTP 请求
  • 当服务器在 HTTP 请求中接收数据并将该数据拼接在 HTML 中返回时,例子:
   // 某网站具有搜索功能,该功能通过 URL 参数接收用户提供的搜索词:
   https://xxx.com/search?query=123
   // 服务器在对此 URL 的响应中回显提供的搜索词:
   <p>您搜索的是: 123</p>
   // 如果服务器不对数据进行转义等处理,则攻击者可以构造如下链接进行攻击:
   https://xxx.com/search?query=<img data-original="empty.png" onerror ="alert('xss')">
   // 该 URL 将导致以下响应,并运行 alert('xss'):
   <p>您搜索的是: <img data-original="empty.png" onerror ="alert('xss')"></p>
   // 如果有用户请求攻击者的 URL ,则攻击者提供的脚本将在用户的浏览器中执行。

存储型 XSS

  • XSS 脚本来自服务器数据库中
  • 攻击者将恶意代码提交到目标网站的数据库中,普通用户访问网站时服务器将恶意代码返回,浏览器默认执行,例子:
   // 某个评论页,能查看用户评论。
   // 攻击者将恶意代码当做评论提交,服务器没对数据进行转义等处理
   // 评论输入:
   <textarea>
      <img data-original="empty.png" onerror ="alert('xss')">
   </textarea>
   // 则攻击者提供的脚本将在所有访问该评论页的用户浏览器执行

DOM 型 XSS

该漏洞存在于客户端代码,与服务器无关

  • 类似反射型,区别在于 DOM 型 XSS 并不会和后台进行交互,前端直接将 URL 中的数据不做处理并动态插入到 HTML 中,是纯粹的前端安全问题,要做防御也只能在客户端上进行防御。

React 如何防止 XSS 攻击

无论使用哪种攻击方式,其本质就是将恶意代码注入到应用中,浏览器去默认执行。React 官方中提到了 React DOM 在渲染所有输入内容之前,默认会进行转义。它可以确保在你的应用中,永远不会注入那些并非自己明确编写的内容。所有的内容在渲染之前都被转换成了字符串,因此恶意代码无法成功注入,从而有效地防止了 XSS 攻击。我们具体看下:

自动转义

React 在渲染 HTML 内容和渲染 DOM 属性时都会将 "'&<> 这几个字符进行转义,转义部分源码如下:

for (index = match.index; index < str.length; index++) {
    switch (str.charCodeAt(index)) {
      case 34: // "
        escape = '&quot;';
        break;
      case 38: // &
        escape = '&amp;';
        break;
      case 39: // '
        escape = '&#x27;';
        break;
      case 60: // <
        escape = '&lt;';
        break;
      case 62: // >
        escape = '&gt;';
        break;
      default:
        continue;
    }
  }

这段代码是 React 在渲染到浏览器前进行的转义,可以看到对浏览器有特殊含义的字符都被转义了,恶意代码在渲染到 HTML 前都被转成了字符串,如下:

// 一段恶意代码
<img data-original="empty.png" onerror ="alert('xss')"> 
// 转义后输出到 html 中
&lt;img data-original=&quot;empty.png&quot; onerror =&quot;alert(&#x27;xss&#x27;)&quot;&gt; 

这样就有效的防止了 XSS 攻击。

JSX 语法

JSX 实际上是一种语法糖,Babel 会把 JSX 编译成 React.createElement() 的函数调用,最终返回一个 ReactElement,以下为这几个步骤对应的代码:

// JSX
const element = (
  <h1 className="greeting">
      Hello, world!
  </h1>
);
// 通过 babel 编译后的代码
const element = React.createElement(
  'h1',
  {className: 'greeting'},
  'Hello, world!'
);
// React.createElement() 方法返回的 ReactElement
const element = {
  $$typeof: Symbol('react.element'),
  type: 'h1',
  key: null,
  props: {
    children: 'Hello, world!',
        className: 'greeting'   
  }
  ...
}

我们可以看到,最终渲染的内容是在 Children 属性中,那了解了 JSX 的原理后,我们来试试能否通过构造特殊的 Children 进行 XSS 注入,来看下面一段代码:

const storedData = `{
    "ref":null,
    "type":"body",
    "props":{
        "dangerouslySetInnerHTML":{
            "__html":"<img data-original=\"empty.png\" onerror =\"alert('xss')\"/>"
        }
    }
}`;
// 转成 JSON
const parsedData = JSON.parse(storedData);
// 将数据渲染到页面
render () {
    return <span> {parsedData} </span>; 
}

这段代码中, 运行后会报以下错误,提示不是有效的 ReactChild。

Uncaught (in promise) Error: Objects are not valid as a React child (found: object with keys {ref, type, props}). If you meant to render a collection of children, use an array instead.

那究竟是哪里出问题了?我们看一下 ReactElement 的源码:

const symbolFor = Symbol.for;
REACT_ELEMENT_TYPE = symbolFor('react.element');
const ReactElement = function(type, key, ref, self, source, owner, props) {
  const element = {
    // 这个 tag 唯一标识了此为 ReactElement
    $$typeof: REACT_ELEMENT_TYPE,
    // 元素的内置属性
    type: type,
    key: key,
    ref: ref,
    props: props,
    // 记录创建此元素的组件
    _owner: owner,
  };
  ...
  return element;
}

注意到其中有个属性是 $$typeof`,它是用来标记此对象是一个 `ReactElement`,React 在进行渲染前会通过此属性进行校验,校验不通过将会抛出上面的错误。React 利用这个属性来防止通过构造特殊的 Children 来进行的 XSS 攻击,原因是 `$$typeof 是个 Symbol 类型,进行 JSON 转换后会 Symbol 值会丢失,无法在前后端进行传输。如果用户提交了特殊的 Children,也无法进行渲染,利用此特性,可以防止存储型的 XSS 攻击。

在 React 中可引起漏洞的一些写法

使用 dangerouslySetInnerHTML

dangerouslySetInnerHTML 是 React 为浏览器 DOM 提供 innerHTML 的替换方案。通常来讲,使用代码直接设置 HTML 存在风险,因为很容易使用户暴露在 XSS 攻击下,因为当使用 dangerouslySetInnerHTML 时,React 将不会对输入进行任何处理并直接渲染到 HTML 中,如果攻击者在 dangerouslySetInnerHTML 传入了恶意代码,那么浏览器将会运行恶意代码。看下源码:

function getNonChildrenInnerMarkup(props) {
  const innerHTML = props.dangerouslySetInnerHTML; // 有dangerouslySetInnerHTML属性,会不经转义就渲染__html的内容
  if (innerHTML != null) {
    if (innerHTML.__html != null) {
      return innerHTML.__html;
    }
  } else {
    const content = props.children;
    if (typeof content === 'string' || typeof content === 'number') {
      return escapeTextForBrowser(content);
    }
  }
  return null;
}

所以平时开发时最好避免使用 dangerouslySetInnerHTML,如果不得不使用的话,前端或服务端必须对输入进行相关验证,例如对特殊输入进行过滤、转义等处理。前端这边处理的话,推荐使用白名单过滤,通过白名单控制允许的 HTML 标签及各标签的属性。

通过用户提供的对象来创建 React 组件

举个例子:

// 用户的输入
const userProvidePropsString = `{"dangerouslySetInnerHTML":{"__html":"<img onerror='alert(\"xss\");' data-original='empty.png' />"}}"`;
// 经过 JSON 转换
const userProvideProps = JSON.parse(userProvidePropsString);
// userProvideProps = {
//   dangerouslySetInnerHTML: {
//     "__html": `<img onerror='alert("xss");' data-original='empty.png' />`
//      }
// };
render() {
     // 出于某种原因解析用户提供的 JSON 并将对象作为 props 传递
    return <div {...userProvideProps} /> 
}

这段代码将用户提供的数据进行 JSON 转换后直接当做 div 的属性,当用户构造了类似例子中的特殊字符串时,页面就会被注入恶意代码,所以要注意平时在开发中不要直接使用用户的输入作为属性。

使用用户输入的值来渲染 a 标签的 href 属性,或类似 img 标签的 src 属性等

const userWebsite = "javascript:alert('xss');";
<a href={userWebsite}></a>

如果没有对该 URL 进行过滤以防止通过 javascript:data: 来执行 JavaScript,则攻击者可以构造 XSS 攻击,此处会有潜在的安全问题。
用户提供的 URL 需要在前端或者服务端在入库之前进行验证并过滤。

服务端如何防止 XSS 攻击

服务端作为最后一道防线,也需要做一些措施以防止 XSS 攻击,一般涉及以下几方面:

  • 在接收到用户输入时,需要对输入进行尽可能严格的过滤,过滤或移除特殊的 HTML 标签、JS 事件的关键字等。
  • 在输出时对数据进行转义,根据输出语境 (html/javascript/css/url),进行对应的转义
  • 对关键 Cookie 设置 http-only 属性,JS 脚本就不能访问到 http-only 的 Cookie 了
  • 利用 CSP 来抵御或者削弱 XSS 攻击,一个 CSP 兼容的浏览器将会仅执行从白名单域获取到的脚本文件,忽略所有的其他脚本 (包括内联脚本和 HTML 的事件处理属性)

总结

出现 XSS 漏洞本质上是输入输出验证不充分,React 在设计上已经很安全了,但是一些反模式的写法还是会引起安全漏洞。Vue 也是类似,Vue 做的安全措施主要也是转义,HTML 的内容和动态绑定的属性都会进行转义。无论使用 React 或 Vue 等前端框架,都不能百分百的防止 XSS 攻击,所以服务端必须对前端参数做一些验证,包括但不限于特殊字符转义、标签、属性白名单过滤等。一旦出现安全问题一般都是挺严重的,不管是敏感数据被窃取或者用户资金被盗,损失往往无法挽回。我们平时开发中需要保持安全意识,保持代码的可靠性和安全性。

小游戏

看完文章可以尝试下 XSS 的小游戏,自己动手实践模拟 XSS 攻击,可以对 XSS 有更进一步的认识。

招贤纳士

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com

查看原文

赞 3 收藏 3 评论 0

政采云前端团队 发布了文章 · 9月18日

ZooTeam 前端周刊|第 100 期

ZooTeam 前端周刊|第 100 期

浏览更多往期小报,请访问: https://weekly.zoo.team

HOC真的就那么高级吗?你可知道还能这么玩

自己也调研了很多关于HOC的资料,其中确实也有很多写的比较好的文章。但如果你想问本篇文章的优势在哪里?唔...我可以斗胆的说,会更加详细,案例也会更加齐全。所以这篇文章我会从HOC是什么、怎么用它、用它需要注意什么等方面详细的去讲解,尽量让大家都能理解。

面试官问:大量的 TIME_WAIT 状态 TCP 连接,对业务有什么影响?怎么处理?

什么现象?什么影响?

智能UI:面向未来的UI开发技术

随着机器学习和人工智能渗入到各行各业,随着你画我猜、智能推荐、以图搜图、尬舞……渗入生活的方方面面,前端作为编程领域的一支,也必将迎来更多变化和挑战。

JavaScript错误处理完全指南

本文将介绍如何处理同步和异步JavaScript代码中的错误和异常。建议收藏!

JavaScript著名面试题: 0.1 + 0.2 !== 0.3,即将成为过去

From 阿里巴巴前端标准化组

他写出了 Vue,却做不对这十道 Vue 笔试题

请原谅我起了这么个浓浓营销号味道的标题。但这可丝毫没有夸大宣传,而是前端娱乐圈今日份的瓜—— 有十道关于 Vue 的选择题,在群里引出了一众社区知名人士竞折腰,最后钓出了 @尤雨溪 本人亲自挑战……

领域驱动设计在前端中的应用

在开始本篇文章前,我给读者们分享一个很考验人性的有趣现象,在公司洗手间的洗漱台旁边,放置了一个垃圾桶,每次我洗完手,用纸巾擦干手后,将其扔进垃圾桶,但是偶尔扔不...

vue的双向绑定原理及实现

vue的双向绑定原理及实现

CSS: filter: blur(); 实现高斯模糊效果,不可不知的细节优化

原文链接前言在项目中,要实现如下的效果:页面顶部的设计稿,前面一个卡片式的轮播,后边的背景(是椭圆的一部分)取前面的图片,进行一个高斯模糊的处理。开始前面的轮播部分,使用了第三方的轮播插件,非常好用,推荐给大家(地址)。轮播,不作为今天的主要内容,暂时简单描述下,有机会再详细讲解。有兴趣的同学可以自己试一试,根据插件提供的功能,进行一些样式调整即可。现在开始分析后面背景...

逐行分析鸿蒙系统的 JavaScript 框架

我在前文中曾经介绍过鸿蒙的 Javascript 框架,这几天终于把 JS 仓库编译通过了,期间踩了不少坑,也给鸿蒙贡献了几个 PR。今天我们就来逐行分析鸿蒙系统中的 JS 框架。

文中的所有代码都基于鸿蒙的当前最新版(版本为 677ed06,提交日期为 2020-09-10)。

⏰ Moment.js 宣布停止开发,现在该用什么?

Moment.js 宣布停止开发,进入维护状态。

这是一个大而全的时间日期库,极大方便了我们在 JavaScript 中计算时间和日期,每周下载量超过 1200 万,已成功用于数百万个项目中。

前端职业规划 - 现在很多前端团队都改名叫体验技术团队了, 那什么是体验技术?

一种职能或者工种的诞生都伴随着这类职能在整个价值创造的链条中定位的变化, 从软件工程师到按语言划分再到按职能划分, 每一个职能背后都有有一个核心内容驱动这项职能的发展, 职能发展的好就会有更长的生命周期和更宽广的衍生选择.

查看原文

赞 0 收藏 0 评论 0

政采云前端团队 发布了文章 · 9月14日

我的前端职业进阶之路

69 篇原创好文~
本文首发于政采云前端团队博客:我的前端职业进阶之路

自我介绍

大家好。我叫陈梦兰,花名沫沫,来自政采云团队,担任前端技术专家一职,实线带领 10 人负责项目采购业务线,虚线负责前端物料体系建设和前端 AI 智能化方向。今天给大家分享的主题是:我的前端职业进阶之路。

分享大纲

img

本次分享的内容主要分为两个部分:

第一部分,关于个人成长,整体概览下我的个人职业发展过程,以及在这个过程中,我在每个阶段所遇到的问题、瓶颈和破局的方法。

第二部分,主要是通过整个成长过程后,沉淀的一些经验总结和对未来的展望。

个人成长过程

img

第一阶段:一线执行

2014-2017 年,当时这个阶段的目标是:夯实技术基础扩展技术广度尽可能多的接触复杂的业务场景和技术方案

在编码上,要关注编码规范代码质量,尽可能每个需求都自己做下 Code Review,或者让师兄一起 Code Review,总结最佳实践。平时可以抽空看一些开源项目的源码,会有很多的收获。

另外,提及到扩展技术广度,我个人觉得比较好的一种方式是:从实际的场景或者问题出发,去寻找解决方案,过程中去学习和实践新的技术,这样成长速度会更快。

如果我们只是一门心思学了很多东西,而短时间内得不到实际场景的应用,一方面容易感觉到迷茫和困顿,另一方面,很多时候只有在实际场景中应用后才会发现一些问题和新的关联知识点。

第二阶段:业务接口人/师姐

2018 年开始带 2 个同学,负责一条业务线,独当一面。

当时除了自己作为那条业务线的核心开发以外,还需要协助新人/师弟成长,帮助他们提升技术能力和职业化能力。

作为业务接口人,需要把控技术方案的合理性和扩展性,了解业务的短期和长期规划考量需求的投入产出比尽可能的帮助业务实现利益最大化等等

回顾那个时候,其实也是综合能力快速提升的阶段。潜移默化中,跨团队的沟通协调能力风险把控能力业务理解力都有很大的提升

第三阶段:组长 Acting

2019 年开始带 7 - 8 个人,负责多条业务线。当时大家都是之前来自不同的业务团队,相互之间的熟悉度和信任度会差一些。

所以,刚开始我是刻意安排两两结对的方式来对接不同业务,让大家彼此之间快速熟悉起来。我一直认为,没有什么比一起 “打过仗” 来得更容易建立信任关系。

随着整个小组的凝聚力逐渐加强,而后,为了更好的支撑多条业务线,就要考虑小组的梯度建设,业务接口人的培养和我自己的 Backup 培养。

以上这些都是对小组内部的团队建设,除此之前,还需要具备某个领域的技术专项化能力,虚线能带动其他人共建和落地一些技术建设的事情

我个人在这个阶段负责的是前端物料体系的建设。当然,在这个阶段需要面对更多的人和事,更多跨团队的沟通和推动,对自身软实力的培养也会很有帮助。

当前阶段:Team Leader

从工作内容上来说,很多跟去年是类似的,今年负责的也是对我而言崭新的业务和团队。

目前对我而言,也需要进一步强化体系化能力对内对外的影响力跨部门的推动和建设梯队建设人才培养绩效管理(确定绩效目标,过程跟进,结果评估)等等。

经验总结

第一阶段:一线执行

img

在一线执行阶段,当时遇到的问题是,在外企这样一个比较安逸的环境工作了 3 年后,明显感觉到自己的成长已经进入了滞缓期,同时在工作节奏偏慢的氛围下,感觉这样下去自己会走下坡路。

所以,当时的选择是跳槽来到了政采云。但在半年多之后,已经逐步熟悉了业务和技术栈,能独立负责后,发现自己本质上还是在做 “纯业务执行” 的事情,跟之前没什么太大的区别。

这边讲的 “纯业务执行” 指的是,能够很好的把业务需求做完并按时交付,但并不会思考如何从业务和技术的角度出发,做得更好。

破局:认知的突围

img

这个阶段的破局,很大程度是思想和认知方面的转变。

我意识到,换平台并不能解决根本问题,而本质上是我把自己当做了一个单纯的执行角色,觉得做完了产品需求就够了。

但业务支撑并不只是如期交付业务需求就可以了,而是要自驱的去发现业务中的一些痛点问题寻找解决方案并推进落地然后再不断迭代优化形成一个完整的闭环。其实就是从做完到做好,给业务带来改变。

有时候我会想,对公司而言,我的个人价值点在哪里,如果只是做业务纯执行,那么其实所有人都是一样,因为做完业务是最最基本的,本职工作而已。

所以,个人价值的体现在于能发现别人发现不了的问题点解决别人解决不了的事情

案例:知识问答小机器人

这边给大家分享一个具体的 Case。当时有个知识问答小机器人的业务需要交接到我这边。

交接过程中,和业务方、产品提前沟通了后续一个季度的业务规划,期望在全平台所有业务的所有页面全部植入这个小机器人,总计 100+ 个前端应用。

但基于当时植入的技术方案,这个植入成本非常高,每个业务线需要挨个手动接入,并且后续小机器人的迭代,各业务线也需要发版。

显然当时的技术方案对后续业务的扩展是有影响的,所以,决定推动重构,最终实现了个业务线的 0 成本植入,后续迭代各业务线也无感知。

这个 Case 其实很小,但可能大家在日常工作中都会遇到类似的问题。

我们可以总结 2 点经验:

  • 第一,主动提前了解业务后续规划,不要只看当下产品导入的需求,会对技术方案的选择很有帮助
  • 第二,需要有一定的洞察力,能发现一些痛点问题,寻找解决方案,并推进落地,帮助业务快速推广

复盘

img

针对一线执行阶段,我做了下复盘和总结,主要分为 4 个方面:在这个阶段的基本要求、更高的标准、素质瓶颈以及能力结构的瓶颈。

基本要求:

包括业务理解和支撑能力;独立承担和独立执行;扎实的技术功底和编码质量;风险反馈意识。其中风险反馈意识是比较容易忽略的,这也是一个比较重要的基本要求。

  • 为什么风险反馈意识这么重要

    我们很难做到所有需求在具体执行过程中,确保完全没有风险。导致风险的原因有很多:

    • 比如前期技术方案评估有疏漏;
    • 在研发过程中需求有变更;
    • 需求拆解不够细,导致估时不够准确等等。
  • 假设真的出现了风险,那及时反馈就很重要了,如果是在最后一刻搞不定了才反馈的话,那团队也无法横向协助解决问题,可能最终会导致项目延期
  • 千万不要觉得反馈风险是不是显得自身能力不够,在我看来,及时反馈风险是职业化的体现。事后可以复盘,后续如何规避类似风险的发生,但当下最有效的就是及时反馈问题
  • 这个阶段往往已经一个人负责某个业务模块或者业务线了,所以,业务理解力、独立承担和独立执行也很重要,这点能体现出我们的技术功底和解决问题的能力
更高标准:

包括对编码质量的精益求精;自驱主动的发现痛点问题,具备强执行力,针对问题能输出好的解决方案并推动落地。

  • 一部分人可能对问题的感知力比较弱,本质上也没有精益求精的习惯。
  • 还有一部分人缺乏的不是对问题的感知力,而是发现问题后的视而不见,可能会吐槽下,但不会主动去寻找解决方案,并推动落地解决。
  • 但其实我们的目标是问题能够最终得以落地解决,所以就需要具备强执行力
素质瓶颈,体力

在这个阶段大多数事情都是通过体力来解决,下个阶段就是用脑力来解决问题。

能力结构瓶颈

包括业务理解能力、技术方案能力、沟通能力、反馈意识、推动落地的强执行力。

第二阶段:业务/团队核心

img

在作为业务接口人/师姐的阶段,开始带几个新人,负责一条大的业务线。当时遇到的问题用一个字概括就是 “”,但这种情况下的忙其实是有问题的。

由于当时自己在这条业务线待的时间比较长,对整体业务更熟悉,所以其他协作方遇到问题会习惯于找到我。

刚开始很多事情还是习惯于自己来解决,每天加班到很晚,而对于新人而言,反而得不到更快速的成长,小组整体的业务支撑能力也偏低。

破局:思考和复盘

img

越忙的时候,越要抽出时间来思考和复盘

当变成业务接口人之后,不仅要考虑自己个人的能力提升,更要学会靠一群人的力量解决问题,更要考虑其他人的成长小组整体的业务支撑能力

要给新人足够的授权和信任,制定新人培养计划,在过程中进行辅导,每周阶段性沟通,协助新人快速成长。

同时,每周组织小组内部 Code Review业务分享技术分享等等,这些都是提升小组成员业务理解力、技术能力以及整体产出能力的很好方式。

案例:物料体系0到1的建设

img

这个阶段,除了实线负责业务线以外,还虚线主导整个前端物料体系的建设

这边给大家解释下什么是 “虚线” 的技术建设。在我们公司并不是由独立的前端架构组来做技术建设,而是来自不同业务线的同学组成 “虚线” 小组的形式。

本身所有的技术建设其实都是为业务服务的,业务线的同学会更深入了解业务上的问题,以及如何落地。

接下去,我大概回顾下,如何从 0 到 1 规划和建设整个物料体系的。

img

当时我们面临了什么问题呢?

  • 第一,由于历史原因,各业务线的视觉规范不统一
  • 第二,当时公司内部只有一个 React 选型的 UI 组件库,对整个物料体系而言还只是很薄的一层

我们知道物料体系建设很明确的目标就是对内进行研发提效。首先,我们思考一个问题,如何实现研发提效?对物料体系而言,很直观的 2 个方向就是通过物料复用工具化来提效。

那物料应该包含哪些内容呢?因为前端交付的是完整的页面,我们可以把一个页面拆解为模板业务组件UI 组件底层视觉规范,具体详细见上图。

而工具化其实就是为了让研发同学在使用物料的过程中更加便捷,进一步提效。当然,还有任何技术建设中,必不可少的一个模块,就是量化数据统计

数据可以很好的反映出整个物料体系在业务线的使用情况,也是为后续物料体系不断优化迭代提供数据支撑

其实,我的第一版规划里面并没有全部涵盖上面所有的内容,大概只有 70% 左右。我想说的是,有时候很多事情一下子想不全没关系这是一个逐渐完善的过程。先 0 到 1 建设最最核心的能力,然后再不断丰富完善,进行 1 到 10 的优化迭代。

img

另外,这边也给大家分享下,如何做好整体规划?明确且细致的规划能够让大家更有目标感方向感,也能更好的把控推进节奏

一种思维方式是,先确定大方向需要做什么,然后细化各种 Action,最后思考这些 Action 达成了哪些目标。

但其实更好的是以下这种方式:

  1. 从业务/技术场景出发,分析背景/现状
  2. 根据现状,分析和罗列出痛点和问题
  3. 为了解决这些痛点和问题,我们需要指定的整体目标是什么
  4. 将整体目标进行细化拆解成阶段性小目标
  5. 针对每个阶段性小目标,思考要达成阶段性小目标,有哪些可突破的方向
  6. 有了具体方向后,针对性的拆解成对应的 Action
  7. 制定里程碑计划
  8. 落地和推广

复盘

img

针对业务接口人/师姐阶段,同样做了复盘和总结,主要分为 4 个方面:在这个阶段的基本要求、更高的标准、素质瓶颈以及能力结构的瓶颈。

  1. 基本要求,包括深入理解业务、独当一面、培养新人/师弟、把控风险、把控技术方案、沟通协调能力。
  2. 更高标准,包括考虑投入产出比(ROI)、帮业务赢、带动和影响他人。

    • 为什么投入产出比的考量很重要?

      • 在业务高速发展的公司,业务需求的增加速度是非常快的,通常需求体量是超过研发资源负荷量的。
      • 在研发资源有限的情况下,我们需要考虑投入产出比,和产品一起实现业务价值交付的最大化
  3. 素质瓶颈脑力
  4. 能力结构瓶颈,包括主导能力、流程感知、ROI 考量、跨部门的项目 PM 能力。

第三阶段:Leader

img

第三阶段 Leader 阶段,因为今年正好刚轮岗到了一个新的团队,所以我着重讲下今年遇到的一些问题以及解决方法。

来到这个崭新的团队,第一件事就是盘人盘事,过程中我发现了以下几个问题:

  • 业务流程链路长,复杂度高,研发同学对整体业务熟悉度不够
  • 部分项目的技术选型老旧(jQuery),历史 “债务” 较多
  • 合作伙伴同学占比较高,代码质量参差不齐
  • 需求迭代流程不合理,一线同学疲惫感较重

破局:团队环境升级

img

面对上述这些问题,目前我的解决方法如下:

  • 分享沉淀:加强内部业务分享,建立业务知识库
  • 技术选型升级:降低复杂度和维护成本,研发提效
  • 流程规范:标准化、合理化
  • 梯队建设:培养自己的 Backup。每条业务线都配备业务接口人+合作伙伴。每个新人指定对应师兄,一对一帮带
  • 团队凝聚力&氛围:互帮互助、乐于分享、群策群力

复盘

img

作为 Leader,我也还在不断地学习和成长中。回顾在这个阶段的经历,我也简单做了下复盘和总结,同样分为 4 个方面:在这个阶段的基本要求、更高的标准、素质瓶颈以及能力结构的瓶颈。

  1. 基本要求,包括梯队建设、绩效管理、沟通协调、推动优化&改变。
  2. 更高标准,包括破圈建设、跨部门项目的 PM 能力、探索新的技术领域。

    • 破圈建设就是跨出前端职能部门,以更开阔的视野去看,各个职能部门之间更好的协作和共建,帮助业务拿到更好的结果。
  3. 素质瓶颈心力
  4. 能力结构瓶颈,包括前瞻性、目标感、主导力、整合力、推动并拿结果的能力、影响力、领导力。

职能·能力矩阵

img

上述图表达的是作为一个优秀的职业化的前端,所该具备的能力项矩阵。

纵向分成 4 块,业务支撑力技术创新力组织发展力内外影响力。很多能力项之前都有详细讲过,这边就不再赘述了。

其实每个人的成长过程都是在不断的丰富和提升自己的能力项:

  • 业务非常忙的时候,过程中可以重点提升自己业务支撑力
  • 业务相对稳定的时候,可以做一些技术建设,更好的为业务赋能。

Tips

  • 任何职业阶段,过硬的技术功底都是立身之本
  • 关注行业动态、了解新技术趋势
  • 横向/纵向对比,三人行必有我师
  • 复盘,勤总结
  • 保持利他共赢的思维

未来:智能化

img

提到未来,我所想到的一个词就是 “智能化”。过去的几年我们用 Low Code 搭建的方式完成了一次大幅度的提效,但搭建最终还是要依赖于组件的迭代。

相信接下去就是智能化的时代,简单的 HTML + CSS 都可以通过智能化的方式直接从 UI 视觉稿生成可用代码。

目前我们已经开始了 “前端智能化(UI to Code)” 方面的探索,对这方面有兴趣的同学,欢迎加入我们。

好书推荐

img

我个人非常推荐《金字塔》这边书籍,它能够帮助我们强化思考架构能力和逻辑沟通能力,帮助我们更高效的思考、表达和解决问题。

招贤纳士

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com

查看原文

赞 9 收藏 5 评论 1

政采云前端团队 发布了文章 · 9月11日

ZooTeam 前端周刊|第 99 期

ZooTeam 前端周刊|第 99 期

浏览更多往期小报,请访问: https://weekly.zoo.team

「一劳永逸」一张脑图带你掌握Git命令

最近在网易工作之余,遇到Git上面一些问题,趁这次的机会,补一补Git基础知识。

在 React 中实现 keep alive

什么是 keep alive在 Vue 中,我们可以使用 keep-alive 包裹一个动态组件,从而缓存不活跃的实例,而不是直接销毁他们……

浅谈 TypeScript 类型系统

时下,TypeScript 可谓当红炸子鸡,众多知名开源项目纷纷采用,大型项目几乎成为必备。其中缘由,除了微软这一开源项目新势力的强大背书以外,最为核心的即是 TypeScript 的类型系统。JavaScript 太需要一套合适的…

React Hooks 入门教程

React Hooks 入门教程

完全理解React Fiber

react fiber 原理

蚂蚁金服如何把前端性能监控做到极致

蚂蚁金服如何把前端性能监控做到极致

技术专题第四期 | 我们的微前端是如何炼成的

微前端相关的尝试,我很早就有尝试,当时还没有这么百花齐放跟铺天盖地的资料可以参考. 全靠当初的一些概念与实践将这套方案落了地.相信很多实践微前端的同学也看过这系列文章. 看掘金有相关的征文,今天就发掘金了.

【前端体系】从一道面试题谈谈对EventLoop的理解

对于Event Loop(事件轮询)所涉及的知识概念太多了,如果上来就讲一大堆概念性的东西太枯燥且从一开始就是按照我的思路来走的,所以我打算换一种方式来写这篇文章,你先按照你之前对于Event Loop(事件轮询)的理解来解这道题,我在后面写出我从Event Loop的理解思考这题的方式。

Dooring可视化之从零实现动态表单设计器

从零实现一款动态表单设计器

网页布局都有哪种?一般都用什么布局?

在Web布局中,现代CSS特性就可以更好的帮助我们快速实现,例如等高布局,水平垂直居中,经典的圣杯布局、宽高比例、页脚保持在底部等。在本文中,我将会介绍一些不同的CSS属性来实现这些效果,希望大家会感兴趣。

查看原文

赞 1 收藏 1 评论 0

政采云前端团队 发布了文章 · 9月7日

从实习到入职:与你分享我在政采云的工作和成长

68 篇原创好文~ 本文首发于政采云前端团队博客:从实习到入职:与你分享我在政采云的工作和成长

前言

大家好,我是 2020 年秋招入职政采云公司的前端开发者,作为疫情年的本科毕业生,想与大家、尤其是 2021 届毕业的弟弟妹妹和哥哥姐姐们分享一些技术以外的事情,比如,我作为一个菜鸡小萌新,是怎样接触到政采云这样一个公司,在政采云工作给我带来了怎样新奇的体验,跟随着优秀的同事们我学到了什么,这也是对我自己的一个总结吧。

以人为镜,可观来路,知远方。我年轻愚笨,文字拙劣,愿能不辜负你阅读的几分钟。

相逢于秋招

我是 2019 年的秋天的时候接触到政采云公司的。

当时,秋招大场,各家宣讲开得如火如荼,“政采云”这个名不见经传的公司名被淹没在了浩荡浪潮里,它曾经确实没引起我的注意,即使提前搜索了相关资料,看到了某招聘 APP上贴出的本公司图片,也几乎没有产生多少“我想去这家公司”的想法,而且,尤其是了解到政采云是关于面向“政府采购”的 to G 的业务时,让我实在是有点心慌:它与一众竞争得如火如荼、团队气氛年轻热烈的 to B 业务公司相比,这样的业务内容会不会让工作氛围变得有些单调、重复性高?同事关系比较复杂,技术氛围不强?

后来旁听宣讲会的时候,就打消了我的一部分疑虑,一开始,公司播放了一个特别炫酷、热情又有创意的宣传视频,先在我心里怒刷了第一波好感,猜想这里的工作也会比较有趣。接着,一下午的宣讲会上,公司的 3、4 位 Leader 们陆续出席,各自从自己擅长的角度详细地讲述了公司的业务和发展方向,又让我觉得他们有认真地对待校招生,从行为上尊重和认可我们,当做一起共事的人、当做平等的朋友,而不是把我们当做不谙世事的新人,需要被单方面捶打教导。

后来,经历了两波面试以后,当我忐忑地等待三面的面试官 @堂主 进行下一场灵魂拷问,却没想到他自顾自地跟我展示了很久自己团队开发的谷歌插件、桌面应用、搭建系统、埋点系统,几乎忘了我才是来面试的人,短短几分钟下来,让我觉得这个神秘高手(其实进去后才发现是前端部门的老大)很坦率有趣,很务实,也对自己团队的技术力量非常有自信,如果我在这里工作,想必也能跟着大家一起努力,得到更快的进步和成长。

没想到,一晃一年过去,去年秋天那个凭着直觉懵懵懂懂跟着来到政采云的傻学生,如今已经在这一家公司度过了冬、春、夏,从秋招走向了实习,又从实习走向了入职。

从学校走向工作

入职培训 + 企业文化

以前在学校里是没有入职培训这样的东西的,我从心底里总觉得类似的活动都是一些场面话和套话,也很难想象到这些官方活动能给人带来什么实质性的提升,但是参加了公司针对新人的“百乐门”和针对校招生的“青云计划”以后,又真实地感觉到,关于提到的企业文化,诸如“客户第一”、“诚信”、“持续改善”、“自驱”等,自己的对很多事的看法心态都因此发生了巨大的变化。

以前在学校里,我是很难深入理解“合作”的,觉得“合作”充其量是和同学朋友好好相处,学生干部负起责任,参加合作性比赛的时候各司其职、互相理解,真正的学习生活还是要靠每个人读书练习,有些“各顾各的”的意味吧,而且,一遇到组织班级活动的时候,就难免会出现不配合、意志不集中的情况,而这种问题,在工作上肯定是需要避免的。

我们的工作生活中常常会牵扯到不同的角色,作为一个开发来说,前面有业务方、有产品去调研,对于不同岗位来说,每个人都是一块各有所长的七巧板,每一次版本的迭代、项目的落地,都需要各个环节稳中求好,更进一步。每个人都会有自己的看法,倾听、理解、表达、确认、同步,其中每一步都变得尤为重要,而这些,是我当初处于未毕业、或者刚毕业的人,是不能一步登天地领会的,也需要一次次培训的过程中耳濡目染地理解,通过一个个小游戏亲身体会——“我们应当如何达到合作共赢的终点”。

承担业务的基础:工作排期

以前我在学校里的时候,是不太注重排期和目标的,脑子里总会有一种“计划赶不上变化”的想法。虽然也能知道自己最近想学什么,还不至于浑浑噩噩枉度光阴,但是也确实很难和别人同步分享,做到完全可控,这在团队合作的工作中,是非常不合适的。

在工作中,我们的每一天任务和进度都应该有计划,这样才能保证无差错地按期交付,有延期风险才能及时解决。对新人开发者来说,也只有做到心中有数,才不会一直是一个“被安排工作的人”,既可以避免加班过重,也能避免无事可做,让我们慢慢具备起独立肩负起责任、承担业务的能力。

关于我学习到的在开发之前需要协作排期的步骤,画了如下的简单示意图。

开发成本和实际效果

我以前在实习和在学校里做作品的时候,思维比较简单,很少会注意和评估开发成本,如果安排了什么困难的任务,总觉得延长开发时间就可以解决了,但是来到公司以后发现事情不是这样的。

每一日的工作时间都是一项支出,而开发的实际效果是这份支出带来的意义,当支出配得上意义的时候,我们才可以肯定支出是值得的,否则很可能就是一种“浪费”。假如存在开发成本和实际效果不对等情况,我们需要提前和产品人员说明,可以协调出一个可实现的临时方案,再慢慢迭代,或者争取宽限的时间,就像买东西一样,尽可能地做到物有所值,而不是盲目开发。

而至于他的效果好不好,我们可以通过公司的埋点系统查看它的点击量、浏览量等,判断它的使用率,也可以去问相关的业务方、产品方、运营方来收集有效的信息。

互相沟通,两相权衡,目的在于更好地完善这个作品,而不是一味地争吵、给自己加压,又或者埋怨同事,这些都不是我们所期望的。

同心同德做事,快快乐乐生活

之前未出学校大门的时候,深知自己总是被称为“象牙塔”里的孩子,对社会、工作的“毒打”总是会抱有一些不确定的担忧,比如会不会有同事不配合工作,推卸责任,会不会有复杂的办公室斗争、上下级关系之类的,但是来到公司以后,就会发现,这种担心是多余的。

公司的人员结构非常扁平化,不论是几级部门的 Leader 都不会有架子,不论是技术还是业务,有什么问题都可以当面提出,大家也很乐于讨论和分享自己的观点。我们工作的时候尽心尽力,开会的时候尽情发散头脑风暴,而余下的时间在周围的饭店、KFC 一起吃吃喝喝、玩玩闹闹,关系甚至比同一个班级的同学还和乐融洽。

就活动而言,百乐门是我最早参加的活动了,对新入职的同学开放三天的培训 + 实践活动,其中也包括户外拓展,将每一批新人组成 6 到 8 人的小组,一边游湘湖/西湖,一边打卡景点、完成任务,有点像电视上的综艺活动,也是为了让我们彼此留下一个印象,一段回忆、当然,最后也给我的手机里储存了许多好看的照片。( ˘͈ ᵕ ˘͈ )

公司鼓励我们跨部门了解业务,增进感情,每年都有外出旅游的 outing 经费,钉钉的云社区里会发出组团帖子,贴上令人垂涎的美食和超级动人的美景,鼓励怠惰在家的小宅们一起游遍中国的大江南北。在工作之余,还能再钉钉窗口里接受到跨部门的小哥哥小姐姐一起出游的邀请,还是很快乐的呀!

每个月都有生日趴,原来没有疫情的时候,给当月过生日的同学开 party,有可爱的小姐姐组织我们玩游戏、切蛋糕、分水果,不过最近几个月因为疫情不能聚集,所以我们跳过了玩游戏,直接收礼物和吃吃吃。✧ʕ̢̣̣̣̣̩̩̩̩·͡˔·ོɁ̡̣̣̣̣̩̩̩̩✧

除此以外,公司还有周年庆、俱乐部、图书角、年会和其他活动,不过我比较宅,对于爬山、游泳、羽毛球之类俱乐部就了解不多了,相比更外向爱玩的同学会乐在其中。

每逢圣诞节,还会每人发一个毛茸茸的吉祥物小蜜蜂——“采宝”,来公司多年的哥哥姐姐度过了一个又一个圣诞节,办公桌上已经拥有了许多个毛绒小蜜蜂,而去年圣诞节我刚刚拿到了我的第一个“采宝”,希望未来可以拥有第二只,第三只吧。

工程师文化

领走一位导师

我记得之前秋招的时候,有很多公司都会说:会有导师制,会好好培养新人。相信每个刚毕业的同学都有这样的期待,但是就我本人的经历,在前东家实习的时候,这种“培养”每次都提、但每次都不能落到实处,时间长了,对市面上各家公司宣讲会上所说的“导师制”也就不太相信了。

想想也是——大家各忙各的,每个人都有自己的任务要完成,都有代码要写,谁会管你呢?

但是出乎意料的是,在政采云公司工作的过程中发现,无论是主管, HR,还是导师本人,都是很在意“导师”这一角色的。除了小组的同事们都很友好、每个人都可以当技术上传道受业的“导师”以外,安排的导师也会经常凑来“关怀”自己的学生。

有人常常耳提面命,勤加督促总要好过自己孤军奋战,而前辈们随口提到的开发、工作、合作经验,也都是我们这些新人宝贵的财富啊。

校招生培训的“青云计划”里,曾经放过一个电影片段,我觉得能对这段“师生”关系有一个有趣、更形象化的表述:

“你想学习功夫吗?”

“当然。”

“那么我就是你的师父。”

——《功夫熊猫》

撸一些代码,服务自己

除了工作产出以外,我们团队有很多给自己用的产出,比如用于投稿前端小报的系统、增进学习的谷歌插件、自己开发的博客、桌面应用、校招闯关游戏,和一些自动发稿的脚本等。这些虽然比不上服务于业务的、更大更优秀的代码作品,诸如能够显著提效的自动化表单系统、能够反馈实际效果的埋点系统和性能测试系统等,但也是我们这些的一些实践。

我最近跟随公司里的小姐姐一起,参加了校招闯关关卡的设计和开发,看着大家兴致勃勃地撸代码、“玩”技术,也让我产生了许多兴趣,想更深入地参加到“用代码建设生活”的过程中,努力发现身边可以提效、可以用机器代替人力的方面。

而在这个过程也让我们更加认识到,人不是生产代码的机器,代码才应该是服务于人的工具,包括我们公司的产品,以及市面上一些耳熟能详的互联网产品,诸如滴滴、美团、淘宝等,其实也是服务于人的工具。

当我认识到这个因果关系以后,才觉得,工作其实没有那么枯燥——并不是工作在驱赶我们,而是我们在追逐技术和生活。

分享、沉淀、输出

比起作为一个学生、在学校里孤军奋战地学习编程,公司更能为我们营造一种共同开发的氛围。大家各自遇到的难题、拥有的感悟都可以拿出来交流,也许是某顿午饭后,也许是某次周会上,七嘴八舌,更能碰撞出思维的火花,这也让开发生活不那么枯燥了吧。

除了分享以外,每次分享后还需要梳理清问题的产生、原因、解决等,详细整理记录下来,这就是“沉淀”,如果没有“沉淀”,分享就只是“空口白话”、“纸上谈兵”,很快就忘记了,沉淀的过程需要我们查阅更多的资料,更加结构化地表述问题,罗列方案,对比优劣,你能够把问题挖掘到更深的层次,而不是仅仅停留在“解决了”这个表面上。

“输出”则是我们在掘金、博客、思否上发表的技术文章,“输出”是“沉淀”的终点,是更大范围的“分享”,以此形成一个良性循环。

其实立志要产出技术文章的人想来不少,但是也贵在坚持,有大环境的督促,希望我们每个人也能在“分享”、“沉淀”、“输出”的道路上,愈行愈远。

CodeReview

CodeReview,直译过来的意思是代码评审,也就是我们每次 commit 代码前,有人专门地查看你的写法是都得当,是否可以优化,并给出建议的过程,这是我加入团队后才慢慢接触到的一项活动。

之前在学校里,自己写的代码都是自己看,这样很难知道编码的局限性、考虑不周的地方在哪里。加入政采云团队后,才意识到这样“野生”撸代码非常不利于新人的成长和进步。

团队提倡 CodeReview 的好习惯,即便我们自以为非常小的功能,非常普通的 CSS ,都值得检查,比如我们要怎样封装代码、怎样组织数据流向、甚至包括怎样命名对象和函数、怎样组织代码文件、怎样理解业务,都大有可以互相学习的地方。

学无止境,“从完成到更好”的路该如何走,永远是值得我们去讨论和思考的问题。而每一次的 CodeReview,都是一段不起眼、却又坚实无比的阶梯。

理解需求与交互:假如我是一个用户

什么是用户呢?

相信很多刚毕业的学生都是很难讲清楚的——或许可以对此夸夸其谈,却也总是纸上谈兵,当离开学校,加入公司团队以后,才知道一个专业的团队会对用户理解到什么程度。

我们用户的身份是什么?要怎样定位其年龄范围、性别比例、电脑系统比率、使用 IE 比例?用户在不同区域内各有什么使用习惯,买家、卖家、经销人、审核人等不同角色之间的关系是什么?他们在其他平台的使用习惯,现在的期望,真正的诉求又是什么?这些答案都需要我们自己思考。小到字体的字号、颜色,大到业务的战略发展,都与用户、与我们息息相关。

刚毕业时,我理解的前端就是接收产品、视觉方面的需求,像一个流水线上的工人一样,配合后端,加工产品,再放到流水线上传递给测试,最终到达标准,产出产品,但是来到公司以后,才发现团队对我们的期望不是这样的,团队期望我们能从自己开始,设身处地地理解用户,优化需求和交互。

我亲眼看着我们的开发为页面重点、信息展示量等交互问题争论不休,也看到产品开会时拉来业务方,用实例阐述这个功能的意义来说服我们,我想,这是对彼此不同岗位同事的尊重、也是对整个项目、我们产品的尊重,是公司几百人之间的凝聚力。身在其中,我也渐渐地融入到了这样的工作习惯、工作方式中来。

以每个人的倾力思考促成产品更好地实现,再用产品带来的收益回馈每一个员工,其实是这样一个良性循环。

成为更好的自己

提出问题前先给出自己的答案

团队 Leader 开会的时候,总会说到这样一句话——“我们提倡不懂就问,却不希望你只是被动地接受别人的答案,你的答案可以不对,但是不能不思考,要带着自己的答案问问题”。

乍一这听些话,总觉得很像学校里老师的教导,而实际上,却从没有一个老师对我提出过这样的要求。后来,我渐渐理解了这句话的意义,并乐于按照这种方式去做,这次也想通过分享文章把我们团队的智慧分享给大家。就我个人而言,我的表达渐渐变成“出现了这样的问题,我可不可以这样解决”、“这个地方我不太懂,是不是因为这样的原因”。

在每一次分享答案,被别人纠错的过程中,我们才能知道我们的答案距离最好的解决差了那些,我们的考虑方向有什么偏差,在未来,我们才可以不“复制”别人的解决方案,而是在此基础上创造出更妥善的解决方案。

最难得的是可靠

“可靠”这一点也是我在学校里、作为一个学生很少注意到的,诸如按时完成期末作品、转达老师的通知,这些都太简单了,还算不得可靠,而且,相信很多人的学生时期,都是通过临时抱佛脚、加班加点地做完的吧,这样就更难以达到工作中的“可靠”的要求了。

在工作中,我们需要预先对时间进行正确评估,对每天的任务和进度都能准确把控,尤其是多个项目交叉推进的时候,更容易手忙脚乱,这时候更容易忽略一部分事情,造成一定的风险。好记性不如烂笔头,对每个项目进度进行记录,对每一天的安排记录,及时跟进,按时汇报,将大家的信息同步,为成功和失败负责,这样才会接近“可靠”的要求。

世界并不是非黑即白的

“世界并不是非黑即白的”——这是我们团队对入职新人的要求,老大也在开会时多次提到。我最初还有点疑惑,为什么招聘的时候会有这个要求,想来也许是为了减少工作中的冲突和争执,更好地进行管理吧,但是后来又慢慢了解到,“非黑即白”其实也是一种思考的惰性,让我们不去想中间灰色的部分,长此以往,会限制我们看待世界的角度。

我很感谢团队有这个指导思想,可以时时在心里提醒我们去开拓更多、更广的视角,这样在今后的技术学习和个人成长中,都能够为我们提供无限的可能。

一起为政采事业添砖加瓦

每天坐地铁、乘公交的时候,我们总觉得自己是一个碌碌终日的平凡人,吃饭、睡觉、上班,日复一日,淹没在人海中再没有一丁点影子,但是我们是不是也可以有自己想做的事?任务是死的,但任务的意义是活的,能清晰地意识我们在做什么,为世界带来了什么,不也是一种幸福吗?

如今,互联网技术如擎天大厦拔地而起,以更先进、更透明、更便捷的互联网技术服务于国家、服务于政府也必将是大势所趋。作为编程的开发者,我们写的一行行代码,便是构建这个互联网时代、构建这个国家的一砖一石,我们在试错、在尝试、在开拓,就像数千年前的革新者一样,一往无前。

我想,也许我们每个人都平凡卑微,都不曾拥有“障百川而东之,回狂澜于既倒”之力,但是,能以我们所学之能,为建设和创新政府采购事业添砖加瓦,为这个时代开辟一种新的可能性,想来也是一个不错的选择吧!

总结

在这个世界上有许许多多的公司,也有千千万万的开发者。在辛苦与收获并存的光阴里,我们从不孤独,而前路依然宽广明亮。

以上是我个人在政采云的体验与工作经验的分享, 2021 年校招在即,期待这里有更好的你与你在这里更好的未来。

招贤纳士

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com

查看原文

赞 2 收藏 1 评论 0

政采云前端团队 发布了文章 · 9月4日

ZooTeam 前端周刊|第 98 期

ZooTeam 前端周刊|第 98 期

浏览更多往期小报,请访问: https://weekly.zoo.team

一个可能让你的页面渲染速度提升数倍的CSS属性

浏览器在接收到服务端返回的 HTML 之后,需要把这段数据渲染成用户看到的页面,在开始渲染第一个元素之前可能

【网页特效】11 个文本输入和 6 个按钮操作 特效库

11 个文本输入和 6 个按钮操作 特效库

前端也要懂物理 —— 惯性滚动篇

我们在平时编程开发时,除了需要关注技术实现、算法、代码效率等因素之外,更要把所学到的学科知识(如物理学、理论数学等等)灵活应用,毕竟理论和实践相辅相成、密不可分,这无论是对于我们的方案选型、还是技术实践理解都有非常大的帮助。今天就让我们一起来回顾中学物理知识,并灵活运用到惯性滚动的动效实现当中。

「一劳永逸」48张小图带你领略flex布局之美

掘金是一个帮助开发者成长的社区,是给开发者用的 Hacker News,给设计师用的 Designer News,和给产品经理用的 Medium。掘金的技术文章由稀土上聚集的技术大牛和极客共同编辑为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。用户每天都可以在这里找到技术世界的头条内容。与此同时,掘金内还有沸点、掘金翻译计划、线下活动、专栏文章等内容。即使你是 GitHub、StackOverflow、开源中国的用户,我们相信你也可以在这里有所收获。

TypeScript 4.1 新特性:字符串模板类型,Vuex 终于有救了?

TypeScript 4.1 快要发布了,老爷子 Anders Hejlsberg加入了一项重大更新:「字符串模板类型」,Vuex 终于有救了?一起来了解一下。

前端效率提升,Baidu开源低代码前端框架——amis

用来负责文件上传,文件上传成功后会返回文件地址,这个文件地址会作为这个表单项的值,整个表单提交的时候,其实提交的是文件地址,文件上传已经在这个控件中完成了。

我的前端成长之路:中医药大学毕业的业务女前端修炼之路

前端工程师的修炼没有捷径,踏踏实实的通过一个个项目的实践来升级打怪实现进阶;本文仅分享自己11年的前端生涯,探讨一直在业务中的技术人的成长之路,也复盘再认识下自己,每个节点我遇到的问题和我的选择。

自适应布局方案

掘金是一个帮助开发者成长的社区,是给开发者用的 Hacker News,给设计师用的 Designer News,和给产品经理用的 Medium。掘金的技术文章由稀土上聚集的技术大牛和极客共同编辑为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。用户每天都可以在这里找到技术世界的头条内容。与此同时,掘金内还有沸点、掘金翻译计划、线下活动、专栏文章等内容。即使你是 GitHub、StackOverflow、开源中国的用户,我们相信你也可以在这里有所收获。

烤透 React Hook

掘金是一个帮助开发者成长的社区,是给开发者用的 Hacker News,给设计师用的 Designer News,和给产品经理用的 Medium。掘金的技术文章由稀土上聚集的技术大牛和极客共同编辑为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。用户每天都可以在这里找到技术世界的头条内容。与此同时,掘金内还有沸点、掘金翻译计划、线下活动、专栏文章等内容。即使你是 GitHub、StackOverflow、开源中国的用户,我们相信你也可以在这里有所收获。

饿了么4年 + 阿里2年:研发路上的一些总结与思考

作者 | 石佳宁“最重要的是选择,最困难的是坚持。”我是在 2014 年入职饿了么,从前端和 PHP 一直做

如何设计一个JavaScript插件系统,编程思维比死磕API更重要

插件是库和框架的常见功能,并且有一个很好的理由:它们允许开发人员以安全,可扩展的方式添加功能。这使核心项目更具价值,并建立了一个社区——所有这些都不会增加额外的维护负担。太好了!

查看原文

赞 3 收藏 1 评论 0

政采云前端团队 发布了文章 · 8月30日

编写高质量可维护的代码:数据建模

67 篇原创好文~
本文首发于政采云前端团队博客:[编写高质量可维护的代码:数据建模
](https://zoo.team/article/data...

什么是数据建模

数据建模是一种用于定义和分析数据的要求和其需要的相应支持的信息系统的过程。

随着前端页面的交互变得更加细腻复杂,原本存放于服务端的状态放置在了前端,类似 flux、redux、mobx、dva、rematch、vuex 的状态管理库也成了每个项目的标配。

因为分层理念的普及,前端工程师们需要把更多精力放在数据管理上,数据建模也成了基本功。

而建模的产物是数据模型,数据模型是定义数据如何输入和输出的一种模型,其主要作用是为信息系统提供数据的定义和格式。

数据模型包括数据结构、数据操作、数据完整性约束条件这三要素。

简单理解就是数据模型提供了一个“模具”,数据按照预先的设计和约束进行放置。

三要素

数据完整性约束条件

好的数据结构必须要有约束,例如描述同一个状态的字段有时候是字符串,有时候是数字,这样的话就容易造成预期之外的情况。添加约束可以最大限度保障这份数据是干净整齐的;

// status 是字符串的时候不通过
if (status === 1) {
  ...
}
// 按照一定约束
model.define(
  'user',
  {
    name: { 
      field: 'name',
      type: STRING(64),
      allowNull: false, 
      comment: '姓名',
    },
    sex: {
      field: 'sex',
      type: INTEGER(1),
      allowNull: false,
      comment: '性别',
    }
  }
);

数据结构

描述模型本身的性质之外,还需通过某些字段表达模型(表)和模型之间的关联;

数据操作

在数据结构上对数据或者数据之间的关联关系的操作。

领域驱动设计

在围绕着数据模型进行应用开发的时候,我们会思考如何进行建模呢?

实际上,软件开发行业中已经积累了一些方法论,例如领域驱动设计(DDD)就被广泛采用。

在进行软件开发前,通常需要先进行业务知识梳理,而后到达软件设计的层面,最后才是开发。而在业务知识梳理的过程中,我们必然会形成某个领域知识。根据领域知识来一步步驱动软件设计,就是领域驱动设计的基本概念。简单来说领域驱动设计就是关注精简的业务模型及实现的匹配

分层架构

按照领域驱动设计的分层架构可以将应用进行分层

  • UI 层:负责向用户展现信息以及解释用户命令。
  • 应用层:用来协调应用的活动。它不包含业务逻辑;它不保留业务对象的状态;但它保有应用任务的进度状态。
  • 领域层:业务软件的核心所在。在这里保留业务对象的状态,对业务对象和它们状态的持久化被委托给了基础设施层。
  • 基础设施层:为其他层的支撑库存在。它提供了层间的通信,实现对业务对象的持久化,包含对用户界面层的支撑库等作用。

按照这个分层,越往左边代码变动越频繁。随着业务复杂,应用层和领域层的边界变得模糊,领域之间也容易交错在一起。

良好的设计应该避免层与层之间产生过多依赖,如果代码没有被清晰地隔离到某层中,它会迅即变得混乱和难以维护。

通过分层架构和高内聚低耦合的设计思想,最终实现系统与需求有较好的一致性,在业务迭代中快速响应需求变更。

实体

实体在领域模型中是必需的对象,并且它们应该在建模过程开始时就被考虑。例如要实现一个“猫”的概念,我们可能会去创造一个 Cat 的类,这个 Cat 可能包含名称、性别、品种等属性,但是这些属性都不足以区分这只猫,所以我们需要创建一个唯一不重复的 ID 来区分他们,也就区分实体的标识符。

创建 ID 的方式有很多种,它可以是主键、可以来自外部、也可以由系统自己产生,但它必须符合模型中的身份差别。

值对象

用来描述领域的特殊方面,且没有标识符的一个对象,叫做值对象。例如画布上的一个点 Customer 会跟姓名、省份、城市、区、街道相关。最好是将地址分离出来,保留对地址的引用,因为它们都是同一个址属性。

服务

你可以简单地将行为理解成一种服务。例如你去商店购买商品,你的朋友也可以去购买商品。如果将购买这个能力作为一个属性放在 Person 这个实体里显然有点不对劲,因为“去购买”这个功能并不属于你和你的朋友(实体或者值对象),同时去购买也可能涉及到商品对象。

保证服务的单一性和隔离非常重要,注意区分领域服务和应用服务。决定一个服务所应归属的层是非常困难的事情,我们在设计阶段建立模型时,需要确保领域层从其他层中隔离开来。

模块

模块是一种被用来作为组织相关概念和任务以便降低复杂性的方法,通常情况下由功能或者逻辑上属于一体的元素构成,以保证高内聚,同时通过接口的形式暴露给第三方以降低模块之间的耦合。

聚合

聚合是针对数据变化可以考虑成一个单元的一组相关对象。聚合基于(有且仅有)一个实体(根),聚合通过这个根被外部访问,它可以引用任意聚合或者被其他聚合引用。以下是一个简单的聚合例子:客户作为聚合的根,其他信息都是客户内部的,如果需要地址则将地址的拷贝传递出去( Javascript 中特别需要注意)。

工厂

工厂用来封装对象创建所必需的知识,它们对创建聚合特别有用。工厂方法是一个对象的方法,包含并隐藏了创建其他对象的必要知识。

资源库

资源库作为一个全局可访问对象的存储点而存在。它是一个独立的层,介于领域层与数据映射层(数据访问层)之间。它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口,提供给领域层进行领域对象的访问。

前端的数据建模

数据建模和后端的工作关联较为紧密,前端的数据模型更多是依赖后端传递的数据传输对象(DTO)进行二次构建。无论二次构建是发生在服务端聚合阶段还是用户端AJAX请求完成阶段,前端都需要参与一定的数据清洗,并应用到前端的数据模型之上。

领域划分

现在你可以开始尝试划分你应用内的业务领域。以一个商城为例子,它可能会包括用户、商品、货架、订单、结算、账户等内容。

每一个业务领域都可以至少拆分成一个领域,按照业务领域来组织代码,例如在交易领域中按照以下目录结构划分:

src
  modules 
    ...
    trading             # 交易领域
      components/         # 组件
      models/             # models
      pages/              # 页面
      redux/              # redux
      services/           # 交易模块相关api
      styles/             # 交易模块样式
      index.ts
  ...

概念模型

数据建模的前提是对业务的充分理解,充分理解业务相当于在更高的视角去看待业务之间的关系,有利于更好地完成模型建设。

尝试回想一下你所维护的业务(应用)场景,你是否清晰业务场景和业务对象之间的关系以及具体交互?

使用思维导图梳理出概念模型,这个阶段可以不用严格遵守三要素,目标清晰表达现实世界就行。

定义模型

定义模型可以依据概念模型,补充细节和关联关系,例如简单定义一个营销商品:

以上展示了商场货架上划分的一块活动区域,规则是满XX减XX,再将参与该活动的商品在区域内进行上架。

降低复杂度

在大部分情况下,特别是展示逻辑这块,前端不应该是重逻辑的。

以商品为例,不同商品的营销类型背后隐藏着复杂的价格体系,尽管是同一种营销类型,商品在不同的状态展示的价格也不一定相同。你可以想象这背后的字段,以及计算规则。

假如后端把这些字段、各种price和规则一股脑抛给你,先不谈前后端对称问题,光挑字段都能让你目瞪狗呆。

遇到类似情况更好的办法是:尽量避免在前端(用户端)去处理复杂的业务判断,在聚合层或者让后端同学给你处理好这些展示逻辑。

特别是在 C 端场景下,数据直出显得更加重要,同时前端同学也有更多时间去做性能优化(早点下班不香么?)。

另外一个好处是假如出现展示问题,你只要确定读取的字段正确,剩下的仅需一个人排查就够了;

// Bad
const switchPrice = product => {
  switch(product.status) {
    case 0:
        return product.priceA;
    case 1:
        return product.priceB;
    case 2:
        return product.priceB;
    default:
        return  product.priceBase;
  }
}
<Price value={switchPrice(product)}/>
     
// Good
<Price value={product.price}/>

逻辑分层

设计上需要区分应用逻辑(业务逻辑)和展示逻辑。应用层注重对领域层的调度,是业务逻辑的实现,展示层专注渲染和交互动作。

在一个大型项目中,同一个 Model 可能被多处引用,你很难确定谁最终会对同一份数据进行怎样的操作。

同时 Model 中仅保留数据源的抽象结构,而不修改数据源的内容。

// 在视图层只做展示逻辑处理
// 组件A
...
<>
    <span>日期:{format(res.date, 'YYYY-MM-DD')}</span>
</>

// 组件B
...
<>
    <span>日期:{format(res.date, 'YYYY-MM')}</span>
</>

统一字段

在设计模型的时候,尽可能与后端保持统一字段。比如某些表单场景在回显和提交的时候要多一层转换,后期维护会带来多一层心智负担。在前后端分离的开发模式下,不一定能保证后端会先给出字段,我的习惯是标记字段,等联调的时候全局替换一下就行了。

简化字段、明确语义、改变不合理的前后端交互是做好数据建模的基础,否则你将花费大量时间去理解这些字段背后的含义和计算规则。

小结

没有一个十全十美的数据模型可以适用任何需求场景,模型的落地需要综合考虑业务实际场景和技术选型。在构建模型的过程中,锻炼系统性思考能力、从更高的视角看待业务,才能创造出一个生命周期更长的模型。

招贤纳士

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com

查看原文

赞 5 收藏 5 评论 0

政采云前端团队 发布了文章 · 8月28日

ZooTeam 前端周刊|第 97 期

ZooTeam 前端周刊|第 97 期

浏览更多往期小报,请访问: https://weekly.zoo.team

Scott:总结 10 年前端经验,谈谈前端人如何更快地成长

前端新人该如何选择技术栈?前端新人怎样能更快地成长?拥有 10 年工程师经验的 Scott 给你带来了一些建议。

我团队的一年前端实现Promise所有方法

最通俗直白方式,告诉你实现Promise所有方法。

前端进阶必经之路(一):1.2w字深入理解JavaScript26个核心概念

掘金是一个帮助开发者成长的社区,是给开发者用的 Hacker News,给设计师用的 Designer News,和给产品经理用的 Medium。掘金的技术文章由稀土上聚集的技术大牛和极客共同编辑为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。用户每天都可以在这里找到技术世界的头条内容。与此同时,掘金内还有沸点、掘金翻译计划、线下活动、专栏文章等内容。即使你是 GitHub、StackOverflow、开源中国的用户,我们相信你也可以在这里有所收获。

CSS Triggers

CSS Triggers

学习Vue应用测试,让你的项目更加健壮和稳定 - 掘金

掘金是一个帮助开发者成长的社区,是给开发者用的 Hacker News,给设计师用的 Designer News,和给产品经理用的 Medium。掘金的技术文章由稀土上聚集的技术大牛和极客共同编辑为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。用户每天都可以在这里找到技术世界的头条内容。与此同时,掘金内还有沸点、掘金翻译计划、线下活动、专栏文章等内容。即使你是 GitHub、StackOverflow、开源中国的用户,我们相信你也可以在这里有所收获。

[[译]18个有用的JavaScript片段 - 掘金](https://juejin.im/post/686257...

掘金是一个帮助开发者成长的社区,是给开发者用的 Hacker News,给设计师用的 Designer News,和给产品经理用的 Medium。掘金的技术文章由稀土上聚集的技术大牛和极客共同编辑为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。用户每天都可以在这里找到技术世界的头条内容。与此同时,掘金内还有沸点、掘金翻译计划、线下活动、专栏文章等内容。即使你是 GitHub、StackOverflow、开源中国的用户,我们相信你也可以在这里有所收获。

「1.4万字」玩转前端 Video 播放器 | 多图预警 - 掘金

掘金是一个帮助开发者成长的社区,是给开发者用的 Hacker News,给设计师用的 Designer News,和给产品经理用的 Medium。掘金的技术文章由稀土上聚集的技术大牛和极客共同编辑为你筛选出最优质的干货,其中包括:Android、iOS、前端、后端等方面的内容。用户每天都可以在这里找到技术世界的头条内容。与此同时,掘金内还有沸点、掘金翻译计划、线下活动、专栏文章等内容。即使你是 GitHub、StackOverflow、开源中国的用户,我们相信你也可以在这里有所收获。

三分钟打造七夕专属的插件化脚手架

背景七夕节将至,你是否还因没有找到合适的表白机会而苦恼,还是说在纠结于为伴侣挑选合适的情人节礼物。那么今天你来对地方了。相信在读完这篇文章后,你就可以自己动手打造出一个专属于他/她/它的七夕专属插件化脚手架,通过本篇文章,不仅可以轻松拉近你与你爱人的距离,还能顺便学会插件化脚手架的相关知识。 温馨提醒本篇文章需要一定的命令行知识,若在阅读本篇文章时有任何的疑惑,可以通过自行搜索相关内容或者阅读一下。

前端图片处理 - 高斯模糊

前端图片处理 - 高斯模糊

如何画好一张架构图?

如何画好一张架构图?

查看原文

赞 2 收藏 0 评论 0

政采云前端团队 发布了文章 · 8月24日

npm 依赖管理中被忽略的那些细节

66 篇原创好文~
本文首发于政采云前端团队博客:[npm 依赖管理中被忽略的那些细节
](https://www.zoo.team/article/...

前言

提起 npm,大家第一个想到的应该就是 npm install 了,但是 npm install 之后生成的 node_modules 大家有观察过吗?package-lock.json 文件的作用大家知道吗?除了 dependencies 和 devDependencies,其他的依赖有什么作用呢?接下来,本文将针对 npm 中的你可能忽略的细节和大家分享一些经验 。

npm 安装机制

A 和 B 同时依赖 C,C 这个包会被安装在哪里呢?C 的版本相同和版本不同时安装会有什么差异呢?package.json 中包的前后顺序对于安装时有什么影响吗?这些问题平时大家可能没有注意过,今天我们就来一起研究一下吧。

A 和 B 同时依赖 C,这个包会被安装在哪里呢?

假如有 A 和 B 两个包,两个包都依赖 C 这个包,npm 2 会依次递归安装 A 和 B 两个包及其子依赖包到 node_modules 中。执行完毕后,我们会看到 ./node_modules 这层目录只含有这两个子目录:

node_modules/ 
├─┬ A 
│ ├── C 
├─┬ B 
│ └── C 

如果使用 npm 3 来进行安装的话,./node_modules 下的目录将会包含三个子目录:

node_modules/ 
├─┬ A 
├─┬ B 
├─┬ C 

为什么会出现这样的区别呢?这就要从 npm 的工作方式说起了:

npm 2 和 npm 3 模块安装机制的差异

虽然目前最新的 npm 版本是 npm 6,但 npm 2 到 npm 3 的版本变更中实现了目录打平,与其他版本相比差别较大。因此,让我们具体看下这两个版本的差异​。

npm 2 在安装依赖包时,采用简单的递归安装方法。执行 npm install 后,npm 根据 dependencies 和 devDependencies 属性中指定的包来确定第一层依赖,npm 2 会根据第一层依赖的子依赖,递归安装各个包到子依赖的 node_modules 中,直到子依赖不再依赖其他模块。执行完毕后,我们会看到 ./node_modules 这层目录中包含有我们 package.json 文件中所有的依赖包,而这些依赖包的子依赖包都安装在了自己的 node_modules 中 ,形成类似于下面的依赖树:

图片

这样的目录有较为明显的好处:

​ 1)层级结构非常明显,可以清楚的在第一层的 node_modules 中看到我们安装的所有包的子目录;

​ 2)在已知自己所需包的名字以及版本号时,可以复制粘贴相应的文件到 node_modules 中,然后手动更改 package.json 中的配置;

​ 3)如果想要删除某个包,只需要简单的删除 package.json 文件中相应的某一行,然后删除 node_modules 中该包的目录;

但是这样的层级结构也有较为明显的缺陷,当我的 A,B,C 三个包中有相同的依赖 D 时,执行 npm install 后,D 会被重复下载三次,而随着我们的项目越来越复杂,node_modules 中的依赖树也会越来越复杂,像 D 这样的包也会越来越多,造成了大量的冗余;在 windows 系统中,甚至会因为目录的层级太深导致文件的路径过长,触发文件路径不能超过 280 个字符的错误;

​ 为了解决以上问题,npm 3 的 node_modules 目录改成了更为扁平状的层级结构,尽量把依赖以及依赖的依赖平铺在 node_modules 文件夹下共享使用。

npm 3 对于同一依赖的不同版本会怎么处理呢?

npm 3 会遍历所有的节点,逐个将模块放在 node_modules 的第一层,当发现有重复模块时,则丢弃, 如果遇到某些依赖版本不兼容的问题,则继续采用 npm 2 的处理方式,前面的放在 node_modules 目录中,后面的放在依赖树中。举个例子: A,B,依赖 D(v 0.0.1),C 依赖 D(v 0.0.2):

图片

但是 npm 3 会带来一个新的问题:由于在执行 npm install 的时候,按照 package.json 里依赖的顺序依次解析,上图如果 C 的顺序在 A,B 的前边,node_modules 树则会改变,会出现下边的情况:

图片

由此可见,npm 3 并未完全解决冗余的问题,甚至还会带来新的问题。

为什么会出现 package-lock.json 呢?

为什么会有 package-lock.json 文件呢?这个我们就要先从 package.json 文件说起了。

package.json 的不足之处

npm install 执行后,会生成一个 node_modules 树,在理想情况下, 希望对于同一个 package.json 总是生成完全相同 node_modules 树。在某些情况下,确实如此。但在多数情况下,npm 无法做到这一点。有以下两个原因:

1)某些依赖项自上次安装以来,可能已发布了新版本 。比如:A 包在团队中第一个人安装的时候是 1.0.5 版本,package.json 中的配置项为 A: '^1.0.5' ;团队中第二个人把代码拉下来的时候,A 包的版本已经升级成了 1.0.8,根据 package.json 中的 semver-range version 规范,此时第二个人 npm install 后 A 的版本为 1.0.8; 可能会造成因为依赖版本不同而导致的 bug;

2)针对 1)中的问题,可能有的小伙伴会想,把 A 的版本号固定为 A: '1.0.5' 不就可以了吗?但是这样的做法其实并没有解决问题, 比如 A 的某个依赖在第一个人下载的时候是 2.1.3 版本,但是第二个人下载的时候已经升级到了 2.2.5 版本,此时生成的 node_modules 树依旧不完全相同 ,固定版本只是固定来自身的版本,依赖的版本无法固定。

针对 package.json 不足的解决方法

为了解决上述问题以及 npm 3 的问题,在 npm 5.0 版本后,npm install 后都会自动生成一个 package-lock.json 文件 ,当包中有 package-lock.json 文件时,npm install 执行时,如果 package.json 和 package-lock.json 中的版本兼容,会根据 package-lock.json 中的版本下载;如果不兼容,将会根据 package.json 的版本,更新 package-lock.json 中的版本,已保证 package-lock.json 中的版本兼容 package.json。

package-lock.json 文件的结构

package-lock.json 文件中的 name、version 与 package.json 中的 name、version 一样,描述了当前包的名字和版本,dependencies 是一个对象,该对象和 node_modules 中的包结构一一对应,对象的 key 为包的名称,值为包的一些描述信息, 根据 package-lock-json官方文档,主要的结构如下:

  • version :包版本,即这个包当前安装在 node_modules 中的版本
  • resolved :包具体的安装来源
  • integrity :包 hash 值,验证已安装的软件包是否被改动过、是否已失效
  • requires :对应子依赖的依赖,与子依赖的 package.jsondependencies 的依赖项相同
  • dependencies :结构和外层的 dependencies 结构相同,存储安装在子依赖 node_modules 中的依赖包

需要注意的是,并不是所有的子依赖都有 dependencies 属性,只有子依赖的依赖和当前已安装在根目录的 node_modules 中的依赖冲突之后,才会有这个属性。

package-lock.json 文件的作用

  • 在团队开发中,确保每个团队成员安装的依赖版本是一致的,确定一棵唯一的 node_modules 树;
  • node_modules 目录本身是不会被提交到代码库的,但是 package-lock.json 可以提交到代码库,如果开发人员想要回溯到某一天的目录状态,只需要把 package.json 和 package-lock.json 这两个文件回退到那一天即可 。
  • 由于 package-lock.json 和 node_modules 中的依赖嵌套完全一致,可以更加清楚的了解树的结构及其变化。
  • 在安装时,npm 会比较 node_modules 已有的包,和 package-lock.json 进行比较,如果重复的话,就跳过安装 ,从而优化了安装的过程。

依赖的区别与使用场景

npm 目前支持以下几类依赖包管理包括

  • dependencies
  • devDependencies
  • optionalDependencies 可选择的依赖包
  • peerDependencies 同等依赖
  • bundledDependencies 捆绑依赖包

下面我们来看一下这几种依赖的区别以及各自的应用场景:

dependencies

dependencies 是无论在开发环境还是在生产环境都必须使用的依赖,是我们最常用的依赖包管理对象,例如 React,Loadsh,Axios 等,通过 npm install XXX 下载的包都会默认安装在 dependencies 对象中,也可以使用 npm install XXX --save 下载 dependencies 中的包;

图片

devDependencies

devDependencies 是指可以在开发环境使用的依赖,例如 eslint,debug 等,通过 npm install packageName --save-dev 下载的包都会在 devDependencies 对象中;

图片

dependencies 和 devDependencies 最大的区别是在打包运行时,执行 npm install 时默认会把所有依赖全部安装,但是如果使用 npm install --production 时就只会安装 dependencies 中的依赖,如果是 node 服务项目,就可以采用这样的方式用于服务运行时安装和打包,减少包大小。

optionalDependencies

optionalDependencies 指的是可以选择的依赖,当你希望某些依赖即使下载失败或者没有找到时,项目依然可以正常运行或者 npm 继续运行的时,就可以把这些依赖放在 optionalDependencies 对象中,但是 optionalDependencies 会覆盖 dependencies 中的同名依赖包,所以不要把一个包同时写进两个对象中。

optionalDependencies 就像是我们的代码的一种保护机制一样,如果包存在的话就走存在的逻辑,不存在的就走不存在的逻辑。

try { 
  var axios = require('axios') 
  var fooVersion = require('axios/package.json').version 
} catch (er) { 
  foo = null 
} 
// .. then later in your program .. 
if (foo) { 
  foo.doFooThings() 
} 

peerDependencies

peerDependencies 用于指定你当前的插件兼容的宿主必须要安装的包的版本,这个是什么意思呢?举个例子🌰:我们常用的 react 组件库 ant-design@3.x 的 package.json 中的配置如下:

"peerDependencies": { 
  "react": ">=16.9.0", 
  "react-dom": ">=16.9.0" 
 }, 

假设我们创建了一个名为 project 的项目,在此项目中我们要使用 ant-design@3.x 这个插件,此时我们的项目就必须先安装 React >= 16.9.0React-dom >= 16.9.0 的版本。

在 npm 2 中,当我们下载 ant-design@3.x 时,peerDependencies 中指定的依赖会随着 ant-design@3.x 一起被强制安装,所以我们不需要在宿主项目的 package.json 文件中指定 peerDependencies 中的依赖,但是在 npm 3 中,不会再强制安装 peerDependencies 中所指定的包,而是通过警告的方式来提示我们,此时就需要手动在 package.json 文件中手动添加依赖;

bundledDependencies

这个依赖项也可以记为 bundleDependencies,与其他几种依赖项不同,他不是一个键值对的对象,而是一个数组,数组里是包名的字符串,例如:

{ 
  "name": "project", 
  "version": "1.0.0", 
  "bundleDependencies": [ 
    "axios",  
    "lodash" 
  ] 
} 

当使用 npm pack 的方式来打包时,上述的例子会生成一个 project-1.0.0.tgz 的文件,在使用了 bundledDependencies 后,打包时会把 Axios 和 Lodash 这两个依赖一起放入包中,之后有人使用 npm install project-1.0.0.tgz 下载包时,Axios 和 Lodash 这两个依赖也会被安装。需要注意的是安装之后 Axios 和 Lodash 这两个包的信息在 dependencies 中,并且不包括版本信息。

"bundleDependencies": [ 
    "axios", 
    "lodash" 
  ], 
  "dependencies": { 
    "axios": "*", 
    "lodash": "*" 
  }, 

如果我们使用常规的 npm publish 来发布的话,这个属性是不会生效的,所以日常情况中使用的较少。

总结

本文介绍的是 npm 2,npm 3,package-lock.json 以及几种依赖的区别和使用场景,希望能够让大家对 npm 的了解更加多一点,有什么不清楚的地方或者不足之处欢迎大家在评论区留言。

参考文献

package.json官方文档

package-lock-json官方文档

npm文档总结

npm-pack

招贤纳士

政采云前端团队(ZooTeam),一个年轻富有激情和创造力的前端团队,隶属于政采云产品研发部,Base 在风景如画的杭州。团队现有 50 余个前端小伙伴,平均年龄 27 岁,近 3 成是全栈工程师,妥妥的青年风暴团。成员构成既有来自于阿里、网易的“老”兵,也有浙大、中科大、杭电等校的应届新人。团队在日常的业务对接之外,还在物料体系、工程平台、搭建平台、性能体验、云端应用、数据分析及可视化等方向进行技术探索和实战,推动并落地了一系列的内部技术产品,持续探索前端技术体系的新边界。

如果你想改变一直被事折腾,希望开始能折腾事;如果你想改变一直被告诫需要多些想法,却无从破局;如果你想改变你有能力去做成那个结果,却不需要你;如果你想改变你想做成的事需要一个团队去支撑,但没你带人的位置;如果你想改变既定的节奏,将会是“5 年工作时间 3 年工作经验”;如果你想改变本来悟性不错,但总是有那一层窗户纸的模糊… 如果你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的自己。如果你希望参与到随着业务腾飞的过程,亲手推动一个有着深入的业务理解、完善的技术体系、技术创造价值、影响力外溢的前端团队的成长历程,我觉得我们该聊聊。任何时间,等着你写点什么,发给 ZooTeam@cai-inc.com

查看原文

赞 8 收藏 6 评论 0

认证与成就

  • 获得 719 次点赞
  • 获得 2 枚徽章 获得 0 枚金徽章, 获得 0 枚银徽章, 获得 2 枚铜徽章

擅长技能
编辑

(゚∀゚ )
暂时没有

开源项目 & 著作
编辑

(゚∀゚ )
暂时没有

注册于 2019-08-16
个人主页被 3.8k 人浏览