我对今年组件的看法
这一年,对于我来说真是压力空前,之前公司接需求的时候大部分情况是看排期,如果排期紧张再协调安排处理。
BUT! 来这边以后概况大致如下:
这边有个需求来处理下,什么?有其他任务?那不是很正常;
优先级?并行!都很重要,并行很正常,我这里也有好几个事并行呢,DeadLine是xxx号;
做的差不多了您看看?整理好一份文档描述清楚,以便沉淀;
你上次做的那个需求有地址吗,有相关介绍吗,有实现步骤,组件放在哪里了?这样聊不清楚,你写一份文档;
Hi all,这里有个地方我觉得这样处理非常零散,这不好...那不好...,我觉得可以这样!——好这件事,你负责跟进就按照你的想法处理。
这里我重新做了一个库,可以把这些收集统一处理。
哇,不错啊,那可以把我们框架的加载都使用这个处理,你抽空处理下?
可是,这样影响面会不会....
重构完了,已经发到预发半个月了,有一些业务需求已经对这部分改动有依赖了,需要准备一波上线了? 这样直接发不行,风险太高了,你去梳理一份上线计划书,对现在线上的几个域的支持页面都做一份回归测试;
这里有一项新的技术?你抽时间研究一下,写一份文档,准备一次分享会;
最近招聘怎么没动静了?这样,大家以后晚上21-21.30大家一起集体捞简历。
KPI沟通。你近半年做的事情挺多,做的效果也不错,同事对你的评价也挺高。但是都是比较零散的点,没有一个面输出,期待你后面有更杰出的表现;
怎么才能有一个面的输出,给点指导意见?这样吧,你先把你近半年所有做过的事情详细的写一份文档给我看看,我给你点意见;
华丽丽的分割线
好了,本来是想随便唠两句引言一下,没想到一下子写了这么多。呼~ 突然有种排出一身毒素的感觉,爽!哈哈哈
我想了很久,这一年的工作我有什么地方做的不够好,或者说什么地方我做的没有像别人做的那么好。
嗯,从这点来讲,至少我现在还是在思考如何进步,不像之前觉得自己已经做的非常不错,无人能及了。
趁着休息日,还有点空闲时间,咱们来聊点技术吧!
背景
19年6月左右,我发布过一篇文章《Bit初体验》 。在梳理这篇文章的过程中,我可以说深度体验了一把 bit 所提出的概念和做法,就像一颗种子种在我的脑海中,一开始我觉得这东西没什么。
我还记得我第一次与我的同事分享 bit 后,他说:
emm,虽然你讲了这么多,但是我觉得好像没有那么...有体感?
感觉没什么卵用?
啊,emm,既然你说了,就像你说的。我觉得我们现在如果引入bit 会不会对我们的日常工作带来很多额外的工作量。
这种反应很正常,我是在18年初,就在Vue的官网见到过 bit ,当时我点进去大致浏览过一下。我当时的感受就是,没什么卵用,无非就是 ” 前端垂直领域的 git “。对国内的支持情况还不咋地,连一篇像样的中文文档都找不到。
在我们的团队中一下子直接切换到 bit 的工作流,这确实不现实,在公司有那么多的基础建设都不知道bit这么个玩意。
但是,bit 的做法和概念,却是非常非常有价值和可以借鉴的!
所以,我想做一件事情,一步一步的把 bit 的玩法用我们熟悉的方式引入进来甚至有所延伸扩展,让大家认同其中的好处和价值。
认识组件
随着近些年”微前端“概念的不断酝酿,越来越多的团队开始着手将自己的业务处理为不同组件,然后通过一定的为前端做法,编排到一个业务页面中去。
那么对于组件的维护就会变得越来越重要。所以,先来看看现在大多数团队是怎么维护组件的吧!
- 大库型,Antd、Element标准的大库型
- 一次型,完全业务组件,用完一次再也不维护
- 高复用型,一看就应该单独封装以后给其他人用,比如:视频播放器
- 二次封装型,一些库拿原生js写的,拿来包装一下当做组件直接引入
- 项目融合型,与业务项目在一起,混合store,不分你我
我暂时能想到的就这几种类型的组件,如果你的团队也在维护自己的一套组件库,那么应该很容易理解我上面所说的。
我相信,既然这么做了,肯定有这么做的理由和好处,没有人会闲着没事找麻烦做不是,那么这些做法都有什么好处和痛点呢?我从几个方面入手分别分析一下。
方便、快捷
组件嘛,当然是最快能跑起来,最方便能看到效果最好咯。就这点来讲,还有什么比直接在业务项目里撸组件更快的方式吗!?
现在用个展示的面板,立马去components目录撸一个。
数据?不是有store吗?引入进来不就拿到数据了!
所见即所得,现在改完马上看到页面上的效果!无法反驳..
这么看确实开发这个组件是好快了,但是从整个业务需求实现来看,这么做真的是最快的吗?如果这样的做法是最快捷的,那为什么那么多团队在强调沉淀、封装、抽象呢?
其实很多组件当时看起来,这辈子就只可能用一次,不用封装。可是往往交互稿过来的时候就会发现,这个样式好像我在哪里见过。然后去各种业务项目里一顿翻,哇终于找到了,复制过来发现各种爆红,定睛一看,store???
所以,聪明的团队早已洞察这一切,让我们把组件都维护到同一个地方,然后大家写好文档,用的时候从库里面取就可以了,有Bug的话统一修复就是,棒????!
可维护性
于是乎,大家便如火如荼的开始的组件抽象,组件整改的浩大工程。
一开始,一般会有一个团队中较为靠谱、能力突出的小伙子(嗯?怎么是我?)去把Webpack、Babel、TypeScript、Sass\Less、目录结构、单元测试结构、代码规范、Review规范、发布规范这些梳理好,然后写一个标准的组件出来,最后再强调一下大家一定要按照规范认真维护组件,书写文档,编写单元测试。
从维护性上来讲,大家把组件都写在一个库里面,然后再用到的项目中直接引入,业务上的问题逐渐被分为组件问题还是项目问题,甚至有些需求可以用这个交互在组件库中有相似的,用那个组件就可以了,来反驳产品和设计????。
就在大家用的不亦乐乎的时候,有一天发现,呀,我们的组件库怎么打包出来有10m啊????!
然后找一个靠谱、能力突出的小伙子(没错又是我)就去查了下,这个库是谁引入的?这个组件不是已经有一个了吗?lodash不是这么用的呀!这个组件是干什么的,怎么没文档?
面对上百个业务组件,只能感叹一声业务迭代的可真快啊。
所以,大库维护固然有大库维护的好处和适用场景,大家能够有这样的抽象思维已经是技术上的突破了,现在只是遇到了另外一个问题,解它!
组件大小、加载性能
接触webpack的一些周边工具,比如analyzer
很容易可找出具体是什么包”霸占“了这么多的流量。
发现原来组件包中还有一些个组件,看上去不应该放在大库中进行维护,比如那种一次性组件,二次封装型组件。
因为这种组件可能会引入一个很大的第三方依赖,比如视频播放器、Banner Swiper 等。
对于这样的组件,最好的处理方式应该是创建一个独立的仓库,封装完善后,写好README,发布至内网NPM,供业务项目使用。
But you know ,这样做成本太高,如果有时间的话,我肯定.....balabala...(一般来说,如果你对程序员说一个更好的方案时,除非这个方案他有参与设计,否则大部分回复都是这样????)
当然组件大小这方面也可以通过很多其他方式解决,比如:异步加载,NPM引入,按需加载等等啦...那么,让我们谈谈下面另外一个很重要、又很容易被忽略的部分吧。
组件说明及可索引性
老板,我们今年沉淀了组件200+,其中有几个组件写的特别好,同时支撑了20+项目。
哇,这么棒!来给我看看你们写的组件长什么样?啊,这,这样来看看我们做的这个页面,这个页面里面用了这几个组件,balabala ...
设计:听说你们已经沉淀了200+组件,能给我们看看有哪些组件吗?我们在下次设计的时候可以参考这些组件进行输出,减少沟通成本。
前端:@所有人 这个组件我们库里面有吗?有,CascadeSelect。哦,怎么用的?有文档吗?.......看下源码吧。well..????
组件的说明及可索引性,其实仅次于组件的可用性,甚至更高。
试想下如果今天你写了个巨牛的组件,复用性、接口设计和交互设计都非常棒,但是你有什么渠道能让大家一下子就知道吗,难道你要专门为此拉大家开个会?来今天占用大家1个小时的宝贵时间,介绍下我今天写的巨牛组件。????
反过来想,如果我在写组件的时候,反正我这个组件也没啥亮点,别人应该也不会用到,就不用补充文档了吧,应该也没人会知道。哦豁,丸蛋????
索引组件,来给大家分享一张图:
如果有一天你团队的组件库也能像这样,一板一眼有图有真相,那该是多么幸福和享受的一件事情!
我也知道这样好啊!谁不知道!如果我有时间,我肯定会....balabala...
所以你的意思是让我们每写一个组件不但要补充文档,还要补充用法说明,还要截图!?
对,还要单独建库,还要考虑配置Webpack、Babel、TypeScript、Sass\Less、目录结构、单元测试结构、代码规范、Review规范、发布规范这些????
哈!F*CK !!AWAY!!????
最*实践
说这么多呢,主要是想带读者们一起思考,也是我写作的风格(喜欢讲故事),大部分内容其实是 前端er 都会遇到的问题。
接下就进入正题,说了一大堆问题,总得有点办法来解决吧!
先看看bit是怎么做的吧,bit首先自身有一定的编译能力,内置了webpack及一些插件式loader来解决React、Vue等编译问题。
对于我们团队来说,都是使用React,所以咱们就先从一个编译React的脚手架开始。
如果把每一个组件都作为单独的NPM项目发布,首先要考虑的是,前端一系列的编译环境。如果我有N个前端组件项目,每个前端组件库的webpack、babel这些都需要重复配置,那真是要头大的事情,我只是想写一个组件而已,为什么要考虑这些。所以我们的脚手架首先要具备一些基础的编译命令。
啊对了,脚手架还没有名字,那就暂时叫它:comp 吧 ????
-
comp new 处理按照模板新建一个标准组件
-
初始化一个标准组件项目结构,所有接入所有 comp 命令
-
初始化 Git 仓库
-
初始化 CI/CD 云构建配置
-
-
comp start 处理日常开发,附加单个组件展示及调试能力
-
comp watch 处理 babel 及 scss 监听编译,用于 npm link 场景
-
comp babel 处理编译 npm 包
-
comp dev 处理监听编译 umd 包,用于代理调试
-
comp build 处理最后编译过程
-
webpack 编译 UMD 包
-
Babel 包
-
CI\CD过程中自动截图组件
-
CI\CD过程中自动生成 README
-
其他Hook
-
-
comp test 处理 jest 单元测试
那么等组件初始化以后,目录结构就长这样:
export default function(Component: typeof IComponent, mountNode) {
/** DOCS_START 请将Demo生成方法都写在以下区块内,用于生成README及Riddle **/
ReactDOM.render(
<Component
navigation={true}
pagination={true}
autoplay={true}
dataSource={[
{
href: 'http://xxxxxxxx',
image: 'https://xxxxxxx.cdn.com/tfs/TB1jHkBmNv1gK0jSZFFXXb0sXXa-1440-343.png',
},
{
image: 'https://xxxxxxx.cdn.com/tfs/TB1Y_XacrY1gK0jSZTEXXXDQVXa-1416-813.png',
},
]}
/>,
mountNode,
);
/** DOCS_END **/
}
项目结构中没有任何webpack\babel配置,当然如果有特殊配置需求,可以建立 comp.config.js
进行配置(此处借鉴很多已有的cli处理方式)。
这样处理的好处是,在项目初始化后,用户能见到的目录结构非常清晰明了,项目中不有很多允许配置的地方,所有组件的编译环境基本可以保证统一。
这都是些非常基础的功能,当然又是不可缺少的部分,这些基础命令我就不详细介绍了,重点在后面。
通过这几个问题来介绍功能:
你平时开发组件的流程是什么样子?
平时,一般就是根据设计稿,切分到组件后。
然后去创建组件,最后通过项目引入,一边看着一边开发啊。
你开发组件的时候对于你提供的Props是如何验证的?
最简单的给一个mock看看效果呗。
或者写一个单元测试?
那写Mock的过程算不算是在写Usage呢?
这个,应该也算吧,但是这些都是散落在各个项目里面,有些mock验证完就删掉了。
谁会闲的没事在开发的时候把这些补充到README里面去啊。
为什么他们不写文档?
这还用说?因为懒呗?
那你为啥不写?emm,那是因为....写文档这事儿吧,写了不一定有人看,还费时间呀!业务需求那么多!我要是有时间的话,我肯定....balabala...
OK,那我们来看下一个问题
一个好的组件文档需要那几部分?
开发组件背景,注意事项啥的,这个没啥太大的必要,有的组件需要的话就补充下,没有的话就不用补充。
主要需要的一些介绍有 :用法,Props入参,最好能有个截图!
还有安装、开发、编译的命令介绍得有吧。
锦上添花的话最好还能有几个badge,介绍下源码是TypeScript,下载量多少。
但是,要补充这些文档是在太麻烦了,要一个一个整理,Props这些信息,用的人可以在组件里面找到啊,我都有些注释和类型定义的呀!
完成一轮心灵拷问之后,就会发现在整个组件的开发过程中,开发者本人之所以对这个组件这么清楚,是因为开发者其实已经为自己写过一份README了。
- 用法:组件开发过程中需要看到效果,写过一些mock数据,已经知道什么样的props传进去会产生什么样的效果
- Props入参:组件有哪些Props,所代表的含义是什么,每个Props入参类型是什么,已经在TypeScript的Interface及注释中有体现
- 截图:有mock数据还不知道长什么样?已经看过N多边了
有了这三个最重要的介绍后,相信大部分开发者也都能知道这个组件是怎么个情况了。
所以,如果我们能把上面这些数据都收集到,是不是就可以利用脚本 自动生成README文档 了呢?
用法 / Usage
要收集用法其实很简单,如果让组件有独立开发的能力,不就可以保留这些Usage的Mock数据了吗
有些人可能没理解我说的”组件独立开发的能力“是什么意思,我解释一下下:我们平时开发一个组件,一般都是把这个组件放置于某个页面中,一遍调试页面一遍调试组件。独立开发组件的意思是,直接启动一个页面,可以看到组件的样子,这个页面展示的就是围绕组件的所有信息。
所以在脚手架中,只要在 docs.ts
中书写需要调试组件相关的mock数据,页面就可以展示出组件的样子,同时这些mock数据可以保留作为 README
文档数据。
另外,如果保证这份demo的接口输出统一规范,还可以支持直接生成在 CodePen,Riddle 这些在线编辑的代码内容。
试想下,你的README中如果出现一段 : 点击立即体验 ,跳转过去后可以在线编辑实时看到效果,那对于任何看到你组件的同学来说都是一种享受 ????
组件参数 / Props
要收集这部分数据就比较复杂了,我们需要深入分析 TypeScript AST 语法树,提取出其中组件 props 的类型以及对于Interface的注释内容。
经过一番github,终于找到可以实现一个可以处理这件事情的小众库 react-docgen-typescript
在开发过程中,因为对一些注释及类型输出与我预期的不太一样,所以我fork后做了一些修改,已经可以完成对一个完整组件的 Props 做分析后输出一份 typefile.json 。
同样的,通过基于该能力,可以扩展为webpack插件react-docgen-typescript-loader,为组件的静态属性中添加__docInfo
属性,来声明其属性内容,于是组件开发过程变可以实现以下效果:
截图 / Preview
有了组件,有了demo,还愁没有截图吗?
直接在构建过程中用 puppeteer ,读取运行docs.ts
渲染出组件,进行截图,然后随着云构建CD过程发到CDN,就完事了!
最后,README中加入一些特殊标记,在云构建过程中进行README替换生成就可以啦!并不会影响README本身要叮嘱的内容。
最后,Duang !一份完整,漂亮,详细的文档就生成好了,整个过程我们并没有特意写过什么README方面的内容,一切都是非常轻松标准的进行输出。
结语
在上面的一整套复杂的过程中,看上去最后好像我只得到了一个自动生成README的功能。但实际上呢,其实README只是一个顺带的产物。
整个过程中,我已经拿到了这个组件的所有我想要拿到的数据,它的Props,Usage,Preview,版本信息,包名,甚至构建过程会同步发布该组件的UMD CDN包及NPM包。
接下来,就可以围绕这些数据和工具,建立和扩展很多功能和平台。
举几个栗子:
- 建立一个bit 一样的,组件平台,把团队内的组件收集起来,统一在平台展示及索引
- 根据拿到Props类型信息做可视化的搭建平台,把Props的传参直接交给用户设置,根据不同数据类型提供不同的Form Setter
- 看似组件都分布在不同的库中,却可以通过组件cli做统一的构建处理
- 非常轻松接入 微前端 框架,因为所有组件的发布构建都是标准的构建协议
- 通过统计组件发布次数,下载次数,关联bug数评估代码质量
目前在我们团队,已经使用该工具产出 30+ 的可用组件,并且发布组件已经成功接入到我们已有的可视化编辑器中。
看一眼结合可视化设置面板后的效果吧:
我发现只要实现过程中,没有给开发者带来太多的工作量,又能带来实时可以看到的效果,开发者会很乐意为那些Props做一番解释和修饰????。
我们团队目前产出的组件看起来一片通透,整齐明了。
另外,因为脚手架出世时间还短,需要完善的地方还很多,还没有符合公司规定的开源标准,就不拿出来献丑啦????,不过我觉得整体思路更有参考价值!
我是一个热爱生活的前端工程师,个人博客! Yooh!????
写到这里,按照正常流程,我应该放点 招聘信息?
阿里国际化中台 招聘啦!前端、Java要求 P6 及以上!有兴趣的同学可以发简历到
yee.wang@alibaba-inc.com
期待您的加入~????????
推荐阅读
-
对 Lisp 的看法
-
我对 24 点算法的看法
-
一种结构设计模式,允许在对象中动态添加新行为。它通过创建一个封装器来实现这一目的,即把对象放入一个装饰器类中,然后把这个装饰器类放入另一个装饰器类中,以此类推,形成一个封装器链。这样,我们就可以在不改变原始对象的情况下动态添加新行为或修改原始行为。 在 Java 中,实现装饰器设计模式的步骤如下: 定义一个接口或抽象类作为被装饰对象的基类。 公共接口 Component { void operation; } } 在本例中,我们定义了一个名为 Component 的接口,该接口包含一个名为 operation 的抽象方法,该方法定义了被装饰对象的基本行为。 定义一个实现基类方法的具体装饰对象。 公共类 ConcreteComponent 实现 Component { public class ConcreteComponent implements Component { @Override public void operation { System.out.println("ConcreteComponent is doing something...") ; } } 定义一个抽象装饰器类,该类继承于基类,并将装饰对象作为一个属性。 公共抽象类装饰器实现组件 { protected Component 组件 public Decorator(Component component) { this.component = component; } } @Override public void operation { component.operation; } } } 在这个示例中,我们定义了一个名为 Decorator 的抽象类,它继承了 Component 接口,并将被装饰对象作为一个属性。在操作方法中,我们调用了被装饰对象上的同名方法。 定义一个具体的装饰器类,继承自抽象装饰器类并实现增强逻辑。 公共类 ConcreteDecoratorA extends Decorator { public ConcreteDecoratorA(Component 组件) { super(component); } } public void operation { super.operation System.out.println("ConcreteDecoratorA 正在添加新行为......") ; } } 在本例中,我们定义了一个名为 ConcreteDecoratorA 的具体装饰器类,它继承自装饰器抽象类,并实现了操作方法的增强逻辑。在操作方法中,我们首先调用被装饰对象上的同名方法,然后添加新行为。 使用装饰器增强被装饰对象。 公共类 Main { public static void main(String args) { Component 组件 = new ConcreteComponent; component = new ConcreteDecoratorA(component); 组件操作 } } 在这个示例中,我们首先创建了一个被装饰对象 ConcreteComponent,然后通过 ConcreteDecoratorA 类创建了一个装饰器,并将被装饰对象作为参数传递。最后,调用装饰器的操作方法,实现对被装饰对象的增强。 使用场景 在 Java 中,装饰器模式被广泛使用,尤其是在 I/O 中。Java 中的 I/O 库使用装饰器模式实现了不同数据流之间的转换和增强。 让我们打开文件 a.txt,从中读取数据。InputStream 是一个抽象类,FileInputStream 是专门用于读取文件流的子类。BufferedInputStream 是一个支持缓存的数据读取类,可以提高数据读取的效率,具体代码如下: @Test public void testIO throws Exception { InputStream inputStream = new FileInputStream("C:/bbb/a.txt"); // 实现包装 inputStream = new BufferedInputStream(inputStream); byte bytes = new byte[1024]; int len; while((len = inputStream.read(bytes)) != -1){ System.out.println(new String(bytes, 0, len)); } } } } 其中 BufferedInputStream 对读取数据进行了增强。 这样看来,装饰器设计模式和代理模式似乎有点相似,接下来让我们讨论一下它们之间的区别。 第三,与代理模式的区别: 代理模式的目的是控制对对象的访问,它在对象外部提供一个代理对象来控制对原对象的访问。代理对象和原始对象通常实现相同的接口或继承相同的类,以确保两者可以相互替换。 装饰器模式的目的是动态增强对象的功能,而这是通过对象内部的包装器来实现的。在装饰器模式中,装饰器类和被装饰对象通常实现相同的接口或继承自相同的类,以确保两者可以相互替代。装饰器模式也被称为封装器模式。 在代理模式中,代理类附加了与原类无关的功能。
-
我对直线经理、项目经理和技术经理的理解
-
从技术专家到技术管理者,我对管理的思考
-
麻省理工学院教授戴维-哈特(David Hardt)对工业 4.0 的看法
-
技术管理转型(I)--对技术管理的看法
-
像首席技术官一样思考:如何高效管理 30 人的研发团队?-管理越多越轻松。好的研发团队,应该是上拨下用,即下级对上级的向上管理;而不是反过来,总是向下管理,甚至是 CTO 做经理的事,经理做工程师的事,工程师最终会被当成实习生。如果是这样,就会越管越累,不仅团队无法成长,而且团队整天很忙还效率低下,问题一大堆。 有这样一个小故事:一位高级经理下班后帮忙倒垃圾,结果被老板训斥了一顿。这就好比首席技术官做了实习生自己该做的事。事情本身没有对错之分,只是从不同的角度有不同的理解。 古人云:"用人不疑,疑人不用"。在面对自己的研发团队时,应该相信他们能做好,授权一线开发人员充分发挥专业特长,不要限制他们的工作。但在相信他们的同时,也要进行二次确认,始终秉持 "我相信,但我要确认 "的原则和严谨的精神。因为每个人都会犯错和疏忽,通过发挥团队的智慧,团队犯错的机会就会大大减少。比如回归测试、代码审查、开发演示、变更审批等等。 如前所述,每个人都难免会犯错。但作为管理者,你所设计和商定的流程不能出错。管理者的每一个决定和沟通都应该经过深思熟虑。就像红绿灯的交通设计,某辆车不小心闯红灯可能会扣分,但红绿灯的设计一定要正确、人性化、统一。再比如,开发人员可能会因为疏忽大意写出 bug,但研发流程的设计和上线流程的发布不能有任何差错。因此,流程体系的设计,一方面要结合当前团队规模、业务特点和需要重点解决的问题来设计,另一方面也要在人员防错、效率提升、发挥团队集体智慧等维度进行综合考量。应该站在更高更抽象的角度去思考,不断思考一个倍受欢迎的园区应该如何设计,思考一个灵动、经典、永恒的建筑应该遵循怎样的模式,思考一个成功、优秀、卓越的研发团队应该需要怎样的流程和制度。 最后,反馈很重要。向上汇报很重要,向下反馈也很重要。能够保持顺畅的双向反馈和闭环管理,对研发团队的协作和沟通有着非常明显的积极作用。在向上汇报方面,要培养团队在正式汇报、会议汇报、私下沟通、书面总结、非正式场合等方面的沟通能力,提醒下属报喜也要报忧。凡事先记录,再跟进,最后反馈。反馈很重要,主动汇报更难得。 另一方面,同时也不要忽视向下反馈。好的爱,是双向的。团队也是如此,没有严格的上下级之分,只是分工和角色不同而已。作为管理者,不必总保持一种 "神秘感",让人 "捉摸不透 "才是牛。当团队做得好或有人做得好时,要记得在公开或私下场合给予肯定和赞许。业务有增长、业绩有提升时,别忘了给团队一些鼓励,或者安排一次下午茶或聚餐。在例会或正式会议上,也可以同步向大家传达一些重要信息和高层指示。"欲速则不达,欲远则同行"。 当向上汇报、向下反馈的沟通闭环形成后,同时结合前面研发过程的管理闭环,双管齐下,就能形成良性循环。如此反复,持之以恒,优秀卓越的研发团队,必将呈现。 能力、产出和效率 接下来,继续重复关于能力、产出和效率的话题。 站在不同的角色,以及一个企业经营、生存和发展所需要的基础上,我把研发生产力分为三个层次,分别是:一线员工关心的研发能力、管理层关心的软件产出和操作人员关心的企业生产效率。简单概括就是:既要把工作做好,又要能出成果,还要能帮企业赚钱。
-
对我来说,事务的 ACID 属性总是很愚蠢--事务的起源
-
我对构建人工智能的智能审查的浅薄理解