如果管理是唯一可走的路,那就完蛋了

译自:https://moz.com/rand/if-management-is-the-only-way-up-were-all-fd/

注:作者 Rand 是 Moz 的 CEO,文中反复出现两个词:IC (Individual Contributor) 和 PW (People Wrangler),分别翻译成了一线员工和经理人。


Geraldine 很喜欢她曾经在 Cranium 的工作 (西雅图的桌游初创公司,在 Hasbro 收购他们并裁员之前)。她为桌游撰写问题,并为包装盒和营销材料撰写文案。她很擅长这个。但是发生了一些奇怪的事情——他们想让她晋升。我记得她晚上回家后非常的苦恼。她不想让人们向她汇报。她不想在团队中拥有更大的责任。她只想写写东西。

这很奇怪。当我们审视一家公司的结构时,很容易发现团队需要很多高质量的一线员工 (IC) 以及少数高质量的经理人。然而我们的公司文化和这个世界的“模式”已经让我觉得除非你要带人,否则你的影响力、薪水、利益、职位和自我价值都不会增长。

这都什么乱七八糟的。

我过去写过关于多样化成长轨迹的重要性——一线员工和经理人——但是我们最近在 Moz 花了大量的时间碰撞想法,很快会实施一个新的职位/团队的结构,最终付诸实践,我对此充满期待。

现在我会为一个在其工作岗位上做的很优秀的一线员工表达对管理的兴趣而担心。我担心这种渴望的很重要的一部分不源自真正的管理责任感,而是因为他们想要在职业生涯和/或影响力上得到提高,并且认为这是唯一的办法。

我画了这张图来辅助说明两种角色之间的不同:

ics-vs-pws-small
(大图)

一线员工为他们自己及其工作负责。因为他们以一线员工的方式取得了长足的发展,所以他们的影响力变得更加广泛。一个在 Moz 的好的例子就是 Dr. Pete,他判断公司的战略指示并随之协力投入。他通过审查来协助大数据操作,通过战术指导和策略输入来辅助市场,发表如此高质量的博客指南,甚至从头开始设计整个项目并基于他们的创意执行。他的影响遍及整个公司,横跨多个团队,和他们一同成长。他通过自己的影响力定义了这个角色,这比其它方式都好。

另一方面,优秀的经理人有义务让他们的团队开心、团结自主,也要负责审查、指导等等。他们发展的越顺利,就越不需要“待在壕沟里”了。很多情况下,他们只会协助定义战略问题。剩下的定义范围、搜索相关答案、实现和执行统统都交给一线员工来做。一个在 Moz 的好的例子就是 Samantha Britney。她长期是一个一线员工,但现如今已经成为了经理人,帮助产品团队的几个一线员工,给予他们工作的自主性,通过工具、资源和协助把事做好,并提供作为一个经理人必要的辅导、一对一、回顾和 HR 工作。她的报告中从不会提及任何细枝末节,但总会驱动他们的项目向前。

基本上,如果你喜欢并且能够把这件事做好,那么你应该做一个一线员工。如果你喜欢 (且擅长) 把自主权交给其他人,帮助他们成长和成功,那么你应该做一个经理人。

这些一线员工和经理人之间有这样一些差别

  • 随着一线员工们的发展,他们希望和经理人的职责范围有更多的重叠。对经理人来说恰恰相反——随着他们的发展,他们实际干的活越来越少。
  • 资深的一线员工的角色更加灵活——他们能够在各种地方工作,并且由于工作得到认可,收到的会议和活动邀约就越来越多。资深的经理人相反——他们在办公室的时间更为关键,所以很少出差,也经常身居幕后 (很明显 CEO 在这方面是一个例外)。
  • 如果你有很多一线员工却只有很少的经理人,那么你会发现汇报和管理很有挑战。但是如果你有一堆经理人而没几个一线员工,你会面临“厨师太多伙计不够了”的问题 (并且这通常意味着你们的组织和文化已经一团糟了)。
  • 优秀的一线员工有时会发展成为经理人,并因此在新的角色上变得平庸或失败。这绝对是个悲剧。公司不仅失去了一个卓越的一线员工,而且连管理也被搞砸了,因为这会造成大量传染式的问题。如果一个一线员工表现平平,问题往往不至于这么严重。
  • 待遇是个技巧活儿。在我理想的世界里 (对了我们在 Moz 创建的工资范围是跨发展路线的),一线员工和经理人的级别是大致等价的。假设在某一条路线上有 7 个级别,那么 level 3 的一线员工可以做 level 3 的经理人的事情。最高级别的一线员工应该能够和 CXO 挣得一样多。

我和他人分享这些观点时,大部分情况是直观的。我遇到过的最大问题和一个简单的概念有关——战略战术的所有权。有一天一个 Mozzer 同事和我在这方面的看法就不一致。他觉得在 Moz 的历史上,有些团队的经理人掌握着战略和战术的所有权。个人开发者没有定义他们做什么,怎么做,如何衡量,也没有定义执行过程,他们只是接受命令。

是的这样做也行得通并且这种情况确实发生过。但是我不同意我的同事,这样做相比于,把更大的所有权交给一线员工,让他们决定做什么、何时何地、如何做,让经理人指决定谁来做已经为什么要做,效果不可能一样。诚然,很多初级经理人和一线员工之间会具有更大的内容重叠,而很多高级个人开发者会决定谁来做和为什么要做 (如上所述)。但是我强烈的相信,从长期来看,我们应该走这条路。人们的快乐便在此之上。

当 Daniel Pink 问道“是什么让我们的工作快乐?”时,答案已经很明显 (并且被很多其他学者和不太正式调查者证实):

  1. 自治——主导我们自己生活的渴望。
  2. 精通——在关键的事情上越做越好的欲望。
  3. 目的——渴望做好比我们自己更重要的事情

如果个人开发者无法控制自己的工作内容并且能够掌握工作技能,他们中间优秀的人就会离开,去那些提供这种机会的公司。我们将只留下经理人,而且这会很快。

很奇怪,我是那种一线员工风格的 CEO (也许这并不都是奇怪)。我是一个高级别的一线员工,所以我和经理人有很大的职责重叠,但是我会服务所有的团队、工作和细节。我可能是最直接参与到产品和市场的人,我也经常让这些团队 Mozzer 们像对待资源和工具一样对待我。你让我写篇博客我就会去写,你让我答复一个客户我就会冲上去,你需要聊聊一个项目如何匹配更广泛的目标,以及如何改变你的做法,那就一起聊聊呗。我喜欢我汇报给这些 Moz 员工的感觉——而不是其它方式。我想这件事情永远也不会改变。

p.s. 我很喜欢 Phil Scarr 的这篇文章,它描述了自己从经理人转变为一线员工的经历以及为什么。Carin 从带领着我们的大数据团队,转变为一个产品团队的资深一线员工,我为之感到骄傲。

p.p.s. 如果我的思路不对 (或者对) 而你也有相关的经验,不妨也留言给我。我一定虚心学习——因为我一直在提醒自己,我是第一次当 CEO

如何撰写 Git 提交信息

译自:https://chris.beams.io/posts/git-commit/


介绍:为什么好的提交信息非常重要

如果你浏览任何 Git 仓库的日志,你可能会发现那些提交信息多少有些混乱。比如,看看这些我早年提交给 Spring 的精品

$ git log --oneline -5 --author cbeams --before "Fri Mar 26 2009"

e5f4b49 Re-adding ConfigurationPostProcessorTests after its brief removal in r814. @Ignore-ing the testCglibClassesAreLoadedJustInTimeForEnhancement() method as it turns out this was one of the culprits in the recent build breakage. The classloader hacking causes subtle downstream effects, breaking unrelated tests. The test method is still useful, but should only be run on a manual basis to ensure CGLIB is not prematurely classloaded, and should not be run as part of the automated build.
2db0f12 fixed two build-breaking issues: + reverted ClassMetadataReadingVisitor to revision 794 + eliminated ConfigurationPostProcessorTests until further investigation determines why it causes downstream tests to fail (such as the seemingly unrelated ClassPathXmlApplicationContextTests)
147709f Tweaks to package-info.java files
22b25e0 Consolidated Util and MutableAnnotationUtils classes into existing AsmUtils
7f96f57 polishing

,比较一下这个仓库最近的提交

$ git log --oneline -5 --author pwebb --before "Sat Aug 30 2014"

5ba3db6 Fix failing CompositePropertySourceTests
84564a0 Rework @PropertySource early parsing logic
e142fd1 Add tests for ImportSelector meta-data
887815f Update docbook dependency and generate epub
ac8326d Polish mockito usage

你更喜欢读哪个呢?

过去的信息从长度到形式都很多样;最近的信息比较简洁且一致。过去的信息是一般情况下会发生的;最近的信息绝不是偶然发生。

虽然很多仓库的日志看起来像是过去的,但也有例外。Linux 内核和 Git 自身就是伟大的例子。再比如 Spring Boot 或其它由 Tim Pope 管理的仓库。

这些仓库的贡献者知道,对于一个开发同事来说 (其实对未来的自己也是一样),一条用心撰写的 Git 提交信息是用来沟通这则改动最好的上下文。一个 diff 会告诉你什么改变了,但是只有提交信息能正确的告诉你为什么。Peter Hutterer 阐述得非常好:

重建一段代码的上下文是非常费时费力的,这是无法完全避免的。所以我们应该努力尽可能的减少它。提交信息可以帮上这个忙,也正因为此,一个提交信息反应了一名开发者是不是个好的协作者。

如果你对于创建一个伟大的提交信息还没有想过太多,那说明你可能还没有在 git log 及相关的工具上花费太多的时间。这里有一个恶性循环:因为提交历史不成体系且不一致,我们就不会花更多的时间使用和关心它。因为它得不到使用和关注,所以它就一直不成体系且不一致。

但是用心写出来的日志是美丽且实用的。git blamerevertrebaselogshortlog 以及其它子命令就是生命的一部分。回顾其他人的提交和 pull requests 变成了值得去做的事情,并且可以快速独立完成。理解最近几个月或几年为什么发生了这些事情不止是可能的并且是高效的

一个项目的长期成功靠的是其可维护性,以及一个拥有比项目的日志更强大的工具的维护者。这里值得花时间学习一下如何正确的考虑它。一开始可能是个麻烦的东西很快会变成习惯,并且最终变成一切投入的自豪和产能的源泉。

在这篇文章中,我只会致力于保障一个健康的提交历史的最基本要素:如何撰写一份个人提交信息。这里还有其它重要的实践比如压缩提交 (commit squashing) 就不是我在这里想说的。可能会为此写一篇吧。

大多数编程语言都建立了良好的编码规约,以形成惯用的风格,比如命名、格式化等。当然在这些编码规约中有一些差异,但是大多数开发者赞同取其一并养成习惯好过每个人都选择自己的风格而发生混乱。

一个团队的提交日志方法应该是一致的。为了建立一个有用的修订历史,团队应该首先约定一个提交信息的规约,该规约至少定义以下三方面:

样式。标记句法、缠绕边距、语法大小写标点符号。把这些东西都找出来,去除猜测,把规则定的尽量简单可行。最终的产出将会是不同寻常的一致的日志,不只是乐于阅读,实际上也让阅读变成了一种习惯

内容。提交信息的正文 (body) (如有) 应该包含什么样的信息?不应该包含什么?

元数据。Issue 追踪 ID、pull request 号等信息如何放进来?

幸运的是,这里有一些已经被良好建立的规约,用来创建惯用的 Git 提交信息。事实上,有些规约中很多都是以某种 Git 命令的方式工作的。不需要你重新发明任何东西。只需遵循下面七大法则,你就可以像专家一样进行提交:

伟大的 Git 提交信息七大法则

注意:这些 法则 之前 在别的地方 提到过

  1. 用一个空行把主题和主题隔离开
  2. 把主题行限制在 50 个字符以内
  3. 主题行大写开头
  4. 主题行不必以句号结尾
  5. 在主题行中使用祈使句
  6. 正文在 72 个字符处折行
  7. 使用正文解释是什么为什么而不是怎么样

比如:

Summarize changes in around 50 characters or less

More detailed explanatory text, if necessary. Wrap it to about 72
characters or so. In some contexts, the first line is treated as the
subject of the commit and the rest of the text as the body. The
blank line separating the summary from the body is critical (unless
you omit the body entirely); various tools like `log`, `shortlog`
and `rebase` can get confused if you run the two together.

Explain the problem that this commit is solving. Focus on why you
are making this change as opposed to how (the code explains that).
Are there side effects or other unintuitive consequences of this
change? Here's the place to explain them.

Further paragraphs come after blank lines.

 - Bullet points are okay, too

 - Typically a hyphen or asterisk is used for the bullet, preceded
   by a single space, with blank lines in between, but conventions
   vary here

If you use an issue tracker, put references to them at the bottom,
like this:

Resolves: #123
See also: #456, #789

1. 用一个空行把主题和正文隔离开

git commit 的 manpage 手册中写到:

虽然不是必须的,但是你最好以一句少于 50 个字符的话简短概括你的改动,然后空一行,再深入描述。提交信息中空行之上的文本会被当作提交的标题,该标题在 Git 中到处都会用到。比如 Git-format-patch(1) 会把一个提交转换为一封电子邮件,它会把这个标题作为邮件的主题,其余的部分会作为邮件的正文。

首先,不是每一次提交都同时需要一个主题和一段正文。有的时候单独一行就可以了,尤其是当改动很简单没有更多必要的上下文的时候。比如:

Fix typo in introduction to user guide

无需说更多;如果读者好奇到底修复了什么 typo,她可以通过诸如 git showgit diffgit log -p 简单看看改动的内容就可以了。

如果你是在命令行中提交,则很容易使用 git commit-m 选项:

$ git commit -m"Fix typo in introduction to user guide"

然而,当一个提交值得一些解释和上下文的时候,你需要撰写正文。比如:

Derezz the master control program

MCP turned out to be evil and had become intent on world domination.
This commit throws Tron's disc into MCP (causing its deresolution)
and turns it back into a chess game.

带正文的提交信息并不便于通过 -m 选项来撰写。你最好找一个合适的文本编辑器撰写信息。如果你并没有在命令行中为 Git 设置过编辑器,那么请移步阅读 Pro Git 的这个章节

当你在任何情况下浏览日志的时候,都会觉得把主题从正文中分离出来是值得的。这里有一整段日志:

$ git log
commit 42e769bdf4894310333942ffc5a15151222a87be
Author: Kevin Flynn <kevin@flynnsarcade.com>
Date:   Fri Jan 01 00:00:00 1982 -0200

 Derezz the master control program

 MCP turned out to be evil and had become intent on world domination.
 This commit throws Tron's disc into MCP (causing its deresolution)
 and turns it back into a chess game.

现在运行 git log --oneline,这个命令只会打印主题行:

$ git log --oneline
42e769 Derezz the master control program

或者,git shortlog,这个命令会把提交按照用户分组,同样出于简洁的考虑只会打印主题行:

$ git shortlog
Kevin Flynn (1):
      Derezz the master control program

Alan Bradley (1):
      Introduce security program "Tron"

Ed Dillinger (3):
      Rename chess program to "MCP"
      Modify chess program
      Upgrade chess program

Walter Gibbs (1):
      Introduce protoype chess program

在 Git 里还有一些其它的情况下,会区分主题行和正文——但是如果没有它们中间的空行的话是不会正常工作的。

2. 把主题行限制在 50 个字符以内

50 个字符并不是一个严格的限制,只是个经验之谈。保持主题行的长度以确保它可读且促使作者考虑一下最简略的表达方式足矣。

提示:如果你做总结很艰难,你可能是一次性提交太多东西了。把原子提交从中剥离出来吧 (每个主题是一个独立的提交)。

GitHub 的 UI 都会提醒这些规约。如果你输入超过 50 个字符的限制,它会警告:

gh1

而且会主题行超过 75 个字符的部分会被截断,留下一个省略号:

gh2

所以奔着 50 个字符去写,但是 72 个字符是底线。

3. 主题行大写开头

如题。比如:

  • Accelerate to 88 miles per hour

而不是:

  • accelerate to 88 miles per hour

4. 主题行不必以句号结尾

主题行结尾的标点符号用法不是必要的。而且,当你打算控制在 50 个字符以内时,连空格都是很宝贵的。比如:

  • Open the pod bay doors

而不是:

  • Open the pod bay doors.

5. 在主题行中使用祈使句

祈使句就是指“说起来或写起来像是在发号施令”。举几个例子:

  • Clean your room
  • Close the door
  • Take out the trash

其实这七大法则的每一条读起来都是祈使句的 (“正文在 72 个字符处折行”等)。

祈使句听起来有一点粗鲁;这也是我们为什么不常用它的原因。但是这非常适合写在 Git 提交的主题行中。其中一个的原因就是 Git 本身就是根据你的意志命令式的创建一个提交的

例如,使用 git merge 的默认信息读起来是这样的:

Merge branch 'myfeature'

而用 git revert 的时候是:

Revert "Add the thing with the stuff"

This reverts commit cc87791524aedd593cff5a74532befe7ab69ce9d.

再或者在一个 GitHub pull request 上点击“Merge”按钮时:

Merge pull request #123 from someuser/somebranch

所以当你以祈使句撰写你的提交信息时,你遵循了 Git 自己内建的规约。比如:

  • Refactor subsystem X for readability
  • Update getting started documentation
  • Remove deprecated methods
  • Release version 1.0.0

这样撰写一开始会觉得有点怪怪的。我们更多的在说话的时候使用陈述句来陈述事实。这是为什么提交信息经常读起来像:

  • Fixed bug with Y
  • Changing behavior of X

有的时候提交信息写起来像是对于其内容的描述:

  • More fixes for broken stuff
  • Sweet new API methods

为了避免混淆,这里有一个简单原则,可以用在每一个地方。

一个 Git 提交的主题行的准确的格式应该始终完全遵循下面的句式:

  • If applied, this commit will 这里是你的主题行

比如:

  • If applied, this commit will refactor subsystem X for readability
  • If applied, this commit will update getting started documentation
  • If applied, this commit will remove deprecated methods
  • If applied, this commit will release version 1.0.0
  • If applied, this commit will merge pull request #123 from user/branch

注意非祈使句在这里别扭的地方:

  • If applied, this commit will fixed bug with Y
  • If applied, this commit will changing behavior of X
  • If applied, this commit will more fixes for broken stuff
  • If applied, this commit will sweet new API methods

注意:使用祈使句只在主题行中至关重要。当你撰写正文的时候就可以放下这些限制了。

6. 正文在 72 个字符处折行

Git 不会自动给文本折行。当你为一个提交撰写消息正文的时候,你必须意识到它正确的边距,并且手动折行。

这里推荐在 72 个字符处折行,这样 Git 有足够的空间,即便缩进文本也可以保证所有东西在 80 个字符以内。

一个好的文本编辑器是可以帮上忙的。比如在 Vim 中配置在 Git 提交的 72 个字符处折行非常容易。然而传统的 IDE 在给提交信息文本折行方面提供的智能支持很糟糕 (尽管 IntelliJ IDEA 在最近的版本中终于在这方面做得好一些了)。

7. 使用正文解释是什么和为什么而不是怎么样

这个来自比特币核心的提交是一个非常好的解释改动是什么和为什么的例子:

commit eb0b56b19017ab5c16c745e6da39c53126924ed6
Author: Pieter Wuille <pieter.wuille@gmail.com>
Date:   Fri Aug 1 22:57:55 2014 +0200

   Simplify serialize.h's exception handling

   Remove the 'state' and 'exceptmask' from serialize.h's stream
   implementations, as well as related methods.

   As exceptmask always included 'failbit', and setstate was always
   called with bits = failbit, all it did was immediately raise an
   exception. Get rid of those variables, and replace the setstate
   with direct exception throwing (which also removes some dead
   code).

   As a result, good() is never reached after a failure (there are
   only 2 calls, one of which is in tests), and can just be replaced
   by !eof().

   fail(), clear(n) and exceptions() are just never called. Delete
   them.

看一眼完整的 diff,想一下作者此时此刻通过提供这样的上下文为同事以及未来的提交者节省了多少时间。如果他不这样做,这些信息可能永远找不回来了。

在很多情况下,你可以忽略这个改动发生时的各种细节。从这个角度看,代码自己会说话 (如果代码很复杂以至于需要长篇大论的解释,那也是代码注释该做的事情)。请首先专注于弄清你产生这个改动的理由——改动前的工作方式,改动后的工作方式 (以及这样做哪里不对),以及为什么你决定以这样的方式解决问题。

你将来某一天维护它的时候也许会感激今天的你!

提示

学者爱上命令行。远离 IDE。

[和 Git 子命令同样多的原因][For-as-many-reasons-at-there-are-Git-subcommands],拥抱命令行是明智的。Git 是超级强大的;IDE 也一样,但是套路不同。我每天都使用 IDE (IntelliJ IDEA) 也用过很多其它的 (Eclipse),但是我从未见到 IDE 对 Git 的集成能够配得上命令行的易用和强大 (一旦你意识到这一点)。

某些 Git 相关的 IDE 功能是非常宝贵的,比如当你删除一个文件时调用 git rm、当你重命名一个文件时完成相应的 git 命令。但是当你尝试提交、合并、rebase、或通过 IDE 做复杂的历史分析时,事情就分崩离析了。

当你想发挥出 Git 全部的能量的时候,命令行始终是不二之选。

记住不论你是用的是 Bash 还是 Z shell,都有 tab 补全脚本减轻忘记子命令和开关的痛苦。

阅读 Pro Git

Pro Git 这本书已经可以免费在线阅读,这本书非常棒。用好它吧

C 程序的原则

按照 Doug Gwyn 的话说:“Unix 不会阻止你做愚蠢的事情,因为那会同样阻止你做聪明的事情”。C 是一个非常强大的工具,但使用它的时候需要非常小心和自律。学习这些纪律是绝对值得的,因为 C 是所有程序语言中最优秀的。一个自律的 C 程序员将会……

喜欢可维护性。不要在不必要的地方自作聪明。取而代之的是,找出最简单最易懂的满足需求的方案。诸如性能之类考量是放在第二位的。你应该为你的代码做一个性能预算,并自在的支配它。

随着你对这门语言越来越了解,掌握了越来越多能够从中获益的特性,你也应该学会什么时候不能使用它们。相比用到了很多新奇的方式去解决问题,易于新手理解是更重要的。最好是让一个新手理解你的代码并从中有所收获。像你大概去年就在维护它一样去撰写代码。

避免使用魔法。不要使用宏 (macros)——尽管用它定义常量是没问题的。不要使用 typedef 来隐藏指针或回避撰写“结构”。避免撰写复杂的抽象。保持你的构建系统简单透明。不要因为一个愚蠢的 hacky 的废物解决问题的方式酷炫就使用它。你的代码在行为之下应该是明显的,甚至不需要上下文。

C 最大的优势之一就是透明和简单。这应该被信奉,而不是被颠覆。但是 C 的优良传统是给你足够的空间施展自己,所以你可以为了一些魔术般的目的使用它。但最好还是不要这样,做个麻瓜挺好的。

辨识并回避危险的模式。不要使用固定尺寸的 buffers (有人指出这种说法并不是完全正确。我之前打草稿的时候提到了这些,但还是删掉了)——始终计算你需要分配的空间。阅读你使用的函数的 man 手册并掌握他的成功有出错模式。立刻把不安全的用户输入转换为干净的 C 结构。如果你之后会把这些数据展现给用户,那么尽可能把 C 结构保持到最后。要学会在使用例如 strcat 的敏感函数时多加留意。

撰写 C 有的时候像握着一把枪。枪是很重要的工具,但是和枪有关的事故都是非常糟糕的。你对待枪要非常小心:不要用枪指着任何你喜爱的东西,要有好的用枪纪律,把它当作始终上膛一样谨慎。而就像枪善于拿来打孔一样,C 也善于用来撰写内核。

用心组织代码。永远不要把代码写到 header 里。永远不要使用 inline 关键字。把独立的东西分开写成不同的文件。大量使用静态方法组织你的逻辑。用一套编码规范让一切都有足够的空间且易于阅读。当目的显而易见的情况下使用单字符变量名,反之则使用描述性的变量名。

我喜欢把我的代码组织成目录,每个目录实现一组函数,每个函数有属于自己的文件。这些文件通常会包含很多静态函数,但是它们全部用于组织这个文件所要实现的行为。写一个 header 允许这个模块被外部访问。并使用 Linux 内核编码规范,该死

只使用标准的特性。不要把平台假设为 Linux。不要把编译器假设为 gcc。不要把 libc 假设为 glibc。不要把架构假设为 x86 的。不要把核心工具假设为 GNU。不要定义 _GNU_SOURCE

如果你一定要使用平台相关的特性,为这样的特性描述一个接口,然后撰写各自平台相关的支持代码。在任何情况下都不要使用 gcc 扩展或 glibc 扩展。GNU 是枯萎的,不要让它传染到你的代码。

使用严谨的工作流。也要有严谨的版本控制方法。撰写提交记录的时候要用心——在第一行简短解释变动,然后在扩展提交记录中加上改变它的理由。在 feature 分支上工作要明确定义目标,不要包含和这个目标不相关的改动。不要害怕在 rebase 时编辑你的分支的历史,它会让你的改动展示得更清晰。

当你稍后不得不回退你的代码时,你将会感激你之前详尽撰写的提交记录。其他人和你的代码互动时也同样会心存感激。当你看到一些愚蠢的代码时,也可以知道这个白痴当时是怎么想的,尤其是当这个白痴是你自己的时候。

严格测试和回顾。找出你的改动可能会经过的代码路径。测试每条路径的行为是正确的。给它不正确的输入。给它“永远不可能发生”的输入。对有错误倾向的模式格外小心。寻找可以简化代码的地方并让过程变得更清晰。

接下来,把你的改动交给另外一个人进行回顾。这个人应该运用相同的程序并签署你的改动。而且回顾严格,标准始终如一。回顾的时候应该想着,如果由于这些代码出了问题,自己会感到耻辱

从错误中学习。首先,修复 bug。然后,修复实际的 bug:你的流程允许里这个错误的发生。拉回顾你代码的人讨论——这是你们共同的过错。严格的检查撰写、回顾和部署这些代码的流程,找出根源所在。

解决方案可以简单,比如把 strcat 加入到你的触发“认真回顾”条件反射的函数列表。它可以通过电脑进行静态分析,帮你检测到这个问题。可能这些代码需要重构,这样找出问题变得简单容易。疏于避免未来的错误才是真的大错


重要的是记住规则就是用来打破的。可能有些情况下,不被鼓励的行为是有用的,被鼓励的行为是应该被忽视的。你应该力争把这些情况当作例外而不是常态,并当它们发生时仔细的证明它们。

C 是狗屎。我爱它,并希望更多的人可以学到我做事的方式。祝好运!

Vue 2.0 来了!

终于发布了!

原文:https://medium.com/the-vue-point/vue-2-0-is-here-ef1f26acf4b8#.6r9xjmu6x

今天我非常兴奋的官宣 Vue.js 2.0 的发布:Ghost in the Shell。历经 8 个 alpha 版本、8 个 beta 版本和 8 个 rc 版本 (矮油好巧!),Vue.js 2.0 已经为生产环境准备好了!我们的官方教程 vuejs.org/guide 也已经全面更新。

2.0 的工作自今年 4 月启动以来,核心团队为 API 设计、bugfix、文档、类型声明做出了很重要的贡献,社区中的同学们也反馈了很多有价值的 API 建议——在此为每一位参与者致以大大的感谢!

2.0 有哪些新东西

性能

基于第三方 benchmark,数值越低越好

基于第三方 benchmark,数值越低越好

2.0 用一个 fork 自 snabbdom 的轻量 Virtual DOM 实现对渲染层进行了重写。在其上层,Vue 的模板编译器能够在编译时做一些智能的优化处理,例如分析并提炼出静态子树以避免界面重绘时不必要的比对。新的渲染层较之 v1 带来了巨大的性能提升,也让 Vue 2.0 成为了最快速的框架之一。除此之外,它把你在优化方面需要做的努力降到了最低,因为 Vue 的响应系统能够在巨大而且复杂的组件树中精准的判断其中需要被重绘的那部分。

还有个值得一提的地方,就是 2.0 的 runtime-only 包大小 min+gzip 过后只有 16kb,即便把 vue-routervuex 都包含进去也只有 26kb,和 v1 核心的包大小相当!

渲染函数

尽管渲染层全面更新,Vue 2.0 兼容了绝大部分的 1.0 模板语法,仅废弃掉了其中的一小部分。这些模板在背后被编译成了 Virtual DOM 渲染函数,但是如果用户需要更复杂的 JavaScript,也可以选择在其中直接撰写渲染函数。同时我们为喜欢 JSX 的同学提供了支持选项

渲染函数使得这种基于组件的开发模式变得异常强大,并打开了各种可能性——比如现在新的 transition 系统就是完全基于组件的,内部由渲染函数实现。

服务端渲染

Vue 2.0 支持服务端渲染 (SSR),并且是流式的,可以做组件级的缓存,这使得极速渲染成为可能。同时,vue-routervuex 2.0 也都支持了可以通用路由和客户端状态“hydration”的服务端渲染。你可以通过 vue-hackernews-2.0 的 demo app 了解到它们是如何协同工作的。

辅助库

官方支持的库和工具——vue-routervuexvue-loadervueify——都已经升级并支持 2.0 了。vue-cli 现在已经默认生成 2.0 的脚手架了。

特别之处在于,vue-routervuex 在它们的 2.0 版本中都已经有了很多改进:

vue-router

  • 支持多命名的 <router-view>
  • 通过 <router-link> 组件改进了导航功能
  • 简化了导航的 hooks API
  • 可定制的滚动行为控制
  • 更多复杂示例

vuex

  • 简化了组件内的用法
  • 通过改进 modules API 提供更好的代码组织方式
  • 可聚合的异步 actions

它们各自的 2.0 文档里有更多的细节:

社区项目

中国最大的在线订餐平台饿了么的团队已经基于 Vue 2.0 构建了一套完整的桌面 UI 组件库。不过还没有英文文档,但是他们正在为此而努力!

很多其他社区的项目也都在为 2.0 做兼容——请移步到 awesome-vue 搜索关键字“2.0”。

从 1.0 迁移

如果你是一个 Vue 的新同学,现在就可以“无脑”使用 Vue 2.0 了。最大的问题其实是目前 1.0 的用户如何迁移到新的版本。

为了帮助大家完成迁移,团队已经在配合 CLI 迁移辅助工具制作非常详实的迁移教程。这个工具不一定捕获每一处被废弃的东西,但相信能帮你开个好头。

One More Thing……

中国最大的电商公司阿里巴巴的工程师们已经发起了一个叫做 Weex 的项目,通过 Vue-inspired 语法在移动端渲染 native UI 组件。但是很快,“Vue-inspired” 将会成为 “Vue-powered”——我们已经启动了官方合作,让 Vue 2.0 真正成为 Weex 的 JavaScript 运行时框架。这让用户能够撰写横跨 Web、iOS 和 Android 的通用 Vue 组件!我们的合作才刚刚开始,这将会是 2.0 发布后未来我们专注的重点,请大家拭目以待!

Vue 从一个不起眼的 side project 开始如今已经有了长足的发展。今天它已经是社区资助的被实际广泛认可的,并且根据 stats.js.org 统计在所有 JavaScript 库中增势最强劲的一个。我们相信 2.0 会走得更远。这是 Vue 自启动以来最大的一次更新,我们期待大家用 Vue 创造出更多好产品!

【整理】Vue 2.0 自 beta 1 到 beta 4 以来的主要更新

主要内容来自 https://github.com/vuejs/vue/releases

之前 Vue 2.0 发布技术预览版 到现在差不多三个月了,之前写过一篇简单的 code review,如今三个月过去了,Vue 2.0 在这个基础之上又带来了不少更新,这里汇总 beta 以来 (最新的版本是 beta 4) 的主要更新,大家随意学习感受一下

alpha 和 beta 版本的侧重点会有所不同

首先 Vue 2.0 对 alpha、beta 有自己的理解和设定:alpha 版本旨在完善 API、考虑所需的特性;而来到 beta 版则会对未来的正式发布进行充分的“消化”,比如提前进行一些必要的 breaking change,增强框架的稳定性、完善文档和周边工具 (如 vue-router 2.0 等)

最后的几个 alpha 版本主要更新

Vue 本身的语法基础这里就不多赘述了,网上有很多资料可以查阅,我们已经假定你比较熟悉 Vue 并对 2.0 的理念和技术预览版的状态有一定的了解。

alpha 5

  1. ref 的写法由 <comp v-ref:foo> 变成了 <comp ref="foo">,更加简单,同时动态数据的写法是 <comp :ref="x">
  2. 支持 functional components,这个特性蛮酷的,可以把一个组件的生成过程完全变成一个高度自定义的函数执行过程,比如:

    Vue.component('name', { functional: true, props: ['x'], render: (h, props, children) { return h(props.tag, null, children) } })

你可以在 render() 函数里写各种特殊的逻辑,这样标签的含义和能力都得到了非常大的扩展,在后续的几次更新中,你马上会感受到一些 functional components 的威力

另外剧透一下,h 方法里的第二个参数如果是 null 就可以省略,这个改动出现在了 beta 1

alpha 6

可以设置特殊的 keyCode,比如 Vue.config.keyCodes.a = 65,然后你就可以写 <input @keyup.a="aPressed">

alpha7

  1. 一个组件的生命周期名由 init 改成了 beforeCreated (大家可以在 Vuex 的源码里看到对应的改变哦)
  2. Vue.transition 的 hook 支持第二个参数,把 vm 传递进去

如:

Vue.transition('name', {
    onEnter (el, vm) {
        ...
    }
})

Beta 1 ~ Beta 4

beta 1

  1. 自定义 directive 里 update 的触发时机发生了变化,由于 functional component 等概念的引入,一个 directive 的变更的颗粒度也不完全是 directive 本身引起的,所以这里做了一个更具有通用性的调整;同时 hook 名 postupdate 也相应的更名为 componentUpdated——如果你想让 update 保持原有的触发时机,可以加入一句 binding.value !== binding.oldValue 即可。
  2. Vue.traisition 的 hook 名做了简化
    • onEnter -> enter
    • onLeave -> leave
  3. server-side rendering
    • server.getCacheKey 更名为 serverCacheKey,避免多一层结构嵌套
    • createRenderer/createBundleRenderer 方法不会强制应用 lru-cache,而是开发者手动选择

beta 2

<transition> 标签来了!

其实这个玩意儿我之前在 polymer 等其他框架里也见到过,不过看到 Vue 的语法设计,还是觉得巧妙而简洁:

<transition>
    <div v-if="...">...</div>
</traisition>

<transition-group tag="ul">
    <li v-for="...">...</li>
</traisition-group>

更牛掰的在这里,还记得 functional components 吧,你今天可以这样抽象一个动画效果的标签:

Vue.component('fade', {
    functional: true,
    render (h, children) {
        return h('transition', {
            props: {...},
            on: {
                beforeEnter,
                afterEnter
            }
        }, children)
    }
})

然后

<fade>...</fade>

就可以实现高度自定义的动画效果了,这个我个人觉得是非常赞的设计和实现!

beta 3

  1. 支持在自定义组件中使用原生事件。因为在 Vue 2.0 的设计中,自定义组件上是不能绑定原生事件的,自定义组件上的事件绑定被默认理解为组件的自定义事件,而不是原生事件。针对这个问题我很早就提了 issue 当时小右提出了一个新的语法设计,就是 <comp @click.native="..."></comp>,beta 3 的时候终于看到它被实现了,嘿嘿,有点小激动
  2. 支持两种语法 <div :xxx.prop="x"><div v-bind:prop="{ xxx: x }"> 来对 DOM 的 property 进行绑定,最近我自己也在思考一些在 virtual-DOM 上支持 properties 而不只是 attributes 的想法,这个设计让我也多了一些新的思路。

beta 4

2 天前发布的,其实这个版本以 bugfix 为主

总结

以上是近期 Vue 2.0 的一些更新,让我自己比较兴奋的主要是 functional component 以及基于这个设计的 <transition><transition-group> 标签和自定义 transition 标签的能力拓展,还有就是久违的 <comp @click.native="..."></comp>

最后希望大家可以多多试用,有更大兴趣的可以多多学习 Vue 的源码!