丰田生产方式的启发

十二月 9th, 2014 评论关闭

众所周知,日本车在全世界都是很受欢迎的。究其开端,很多人会想到20世纪70年代的石油危机,认为是油价高涨,为尺寸小、油耗低的日本车打开了市场。这固然可以解释一部分原因,但另一方面,为何日本车能够持续受到欢迎,为何日本车能摆脱“价廉质差”的形象,既有优惠的价格又有优异的品质(缺陷率常年很低)。这一切,都与日本汽车厂商所采用的“精益生产”,尤其是丰田开创的“丰田生产方式”(Toyota Product System, TPS)有很大的关联。最近因为与供应链打交道很多,我花了些时间学习这种生产方式。有趣的是,我发现,它的价值不只限于汽车行业,甚至不只限于制造业,对其它许多行业(包括软件行业)。所以下面我讲讲丰田生产方式给我的启示。

 

“丰田生产方式”给我印象最深的要求是,员工必须同时对工作和工艺负责。自从福特发明了“流水线”之后,工人似乎成了机器的附庸,只是完成机器暂时无法完成的工作。生产的终极形态,就是把一切工作变成简单重复劳动,用机器执行。所以,工人的工作也应该简单机械,比如每天按照生产线的运作,以一定节奏拧紧某个螺丝,就是一种典型。而在丰田生产方式下,工人不但要完成简单机械的本职工作,还必须对工艺负责,也就是理解该工作的意义,思考并不断思考改进自己的工作过程——他们既有这个义务,也有这个权力。结果,整条生产线就好像具备了不断改进的活力,而不再由少数专职的“专家”负责优化(实际上专家也负不了那么多责任)。

软件开发/互联网虽然看起来是光鲜亮丽的高科技行业,但不少时候是达不到这种要求的。许多公司并不要求员工去思考和改进,许多员工也更愿意只做简单重复劳动,不愿意开动脑筋去思考和改进自己的工作。所以,无论是工作质量还是工作效率,其实都停留在相当低的水平上。而许多公司的解决办法,无非是找一些“技术牛人”来负责,这就好像汽车生产厂找“工艺专家”来优化生产一样,或许有效果,但不会太明显。与“对工作和工艺负责”的工人类似,有些程序员会积极开动脑筋编写或者学习一些工具软件来改进自己的工作,他们或许不能编写复杂的框架或精深的算法,但确实堪称优秀的程序员——就好比生产线上优秀的工人。可以说,如果公司的大部分员工都具有这样的意识和习惯,公司也支持和提倡这样的工作方式,那么其产品一定不会太差。

“丰田生产方式”中的还有一点要求,即员工一定不能只了解自己的工作  阅读全文...

分布式系统的事务处理

十一月 24th, 2014 评论关闭

当我们在生产线上用一台服务器来提供数据服务的时候,我会遇到如下的两个问题:

1)一台服务器的性能不足以提供足够的能力服务于所有的网络请求。

2)我们总是害怕我们的这台服务器停机,造成服务不可用或是数据丢失。

于是我们不得不对我们的服务器进行扩展,加入更多的机器来分担性能上的问题,以及来解决单点故障问题。 通常,我们会通过两种手段来扩展我们的数据服务:

1)数据分区:就是把数据分块放在不同的服务器上(如:uid % 16,一致性哈希等)。

2)数据镜像:让所有的服务器都有相同的数据,提供相当的服务。

对于第一种情况,我们无法解决数据丢失的问题,单台服务器出问题时,会有部分数据丢失。所以,数据服务的高可用性只能通过第二种方法来完成——数据的冗余存储(一般工业界认为比较安全的备份数应该是3份,如:Hadoop和Dynamo)。 但是,加入更多的机器,会让我们的数据服务变得很复杂,尤其是跨服务器的事务处理,也就是跨服务器的数据一致性。这个是一个很难的问题。 让我们用最经典的Use Case:“A帐号向B帐号汇钱”来说明一下,熟悉RDBMS事务的都知道从帐号A到帐号B需要6个操作:

  1. 从A帐号中把余额读出来。
  2. 对A帐号做减法操作。
  3. 把结果写回A帐号中。
  4. 从B帐号中把余额读出来。
  5. 对B帐号做加法操作。
  6. 把结果写回B帐号中。

为了数据的一致性,这6件事,要么都成功做完,要么都不成功,而且这个操作的过程中,对A、B帐号的其它访问必需锁死,所谓锁死就是要排除其它的读写操作,不然会有脏数据的问题,这就是事务。那么,我们在加入了更多的机器后,这个事情会变得复杂起来:

 

1)在数据分区的方案中:如果A帐号和B帐号的数据不在同一台服务器上怎么办?我们需要一个跨机器的事务处理。也就是说,如果A的扣钱成功了,但B的加钱不成功,我们还要把A的操作给回滚回去。这在跨机器的情况下,就变得比较复杂了。

2)在数据镜像的方案中:A帐号和B帐号间的汇款是可以在一台机器上完成的,但是别忘了我们有多台机器存在A帐号和B帐号的副本。如果对A帐号的汇钱有两个并发操作(要汇给B和C),这两个操作发生在不同的两台服务器上怎么办?也  阅读全文...

CTO这点事

十月 13th, 2014 评论关闭

 

转自:曹政 @zhihu http://zhuanlan.zhihu.com/iamcaoz/19856992

 

几乎整个互联网行业都缺CTO,特别是一些草根背景的创业者,这个问题更加显著。从我自己的感受,身边各种朋友委托我找CTO的需求,嗯,算下来超过两位数了,光最近一个月就有3个,而且这三家都是刚拿了A轮的。其他那些公司CTO大部分空缺了一两年,或者其他高管临时暂代过渡。实话说,我觉得每个公司都不错的,但通常也只能遗憾的说,真没有能推荐的。

其实,根据个人的观察,每个互联网团队都喊需要CTO,但是具体诉求却各不相同,如果说共性,就只有一点,那就是,公司老板对技术的期望值与目前技术团队的能力表现,有较大的差异,而这个差异,对于老板来说,就是一个想法,找个合格的CTO,一切就都解决了。其实,真不是这回事。

今天要说的第一点,就是期望值的控制;很多互联网公司都希望自己走技术驱动的路线,期望小而美,复制美国技术新贵的市场表现;这不能说是一个错误的期望,但是,现实能有多少符合这种需求的人才呢?这样的人才需要技术有前瞻性,对产业格局有判断,对管理有心得,情商还不能低(算了一下,四项里我至少三项不符合。)。整个行业内这样的人有几个?凭什么会跟你? 事实上我身边确实有这样的案例,一个以业务为主的公司,搞定了一个超棒的CTO,很快就转型成以技术为驱动的公司,公司价值极大提升,问题是,这种现象很难具有复制性。

下面我说一下一个最基本的让人纠结的问题,到底什么是CTO?其实,空谈这个名词的定义毫无意义,从我身边很多朋友公司的实例来看,他们对这个角色的定义和定位是差异非常大的。具体而言,不同创业团队,对CTO需求的真实想法,包括如下层面。

技术选型,这其实是创业公司最纠结的问题;他们往往一上来基于已有的程序员的个人习惯和爱好,选择了一个技术方案,然后到某一天一看,我靠,全是坑(当然,也可能与执行者的能力有关)。而更糟的是,这个技术方案相对冷门,市场上去招聘都很难做。还有就是技术方案成本过高,(不只是钱的问题,特别是时间成本!)结果严重影响到后续的发展速度。 我举个简单例子,最近我给多个创业者提建议,比如做app,很多以内容运营为核心的app,不要用原生态开发,目前一堆第三方的跨平台开发架构,如果选择合适,可以极大减少开发成本,以及降低技术招聘的难度。微信开店开社区,也有一堆第  阅读全文...

架构选择和团队影响

九月 23rd, 2014 评论关闭

转自:https://www.linkedin.com/today/post/article/20140920230659-284548454-%E6%9E%B6%E6%9E%84%E9%80%89%E6%8B%A9%E5%92%8C%E5%9B%A2%E9%98%9F%E5%BD%B1%E5%93%8D

架构选择

架构是协作基础。架构层面的基本决策深刻影响着团队学习/协作的方式和效率。

在这里,我想尝试探讨技术架构有关的一些选择对团队工作的影响。题目有点大,希望我能在小心控制范围的同时,又不失深度。

 

1、对开源的使用和态度

要不要使用开源软件?以何种方式/态度对待开源和社区?

如今的软件/互联网企业,相信已经很难找出不使用开源软件/库的了,但对待开源的态度,差别还是很大。

 

有些人可能一直用着开源软件,但从不关心它的源码,更别提参与开发、做出贡献;而有的人则会仔细的研究代码,对设计水平和代码质量作出自己的判断,能够更好的调整/适应自身项目的需要,并且以 bug 报告、提交补丁、提出建议、讨论需求的形式回馈社区。

在一个封闭的、和开源社区鲜有接触的企业里,重复发明的轮子很常见;而在一个开放的、拥抱开源的企业里,则会把更多精力放在广阔世界里的发现、评估、创造、改进上,尽量不在重复发明轮子上浪费时间。

 

开源对团队的影响,就是积极参与/拥抱开源的团队,

  • 投入更有效,不会大量浪费在重复发明轮子上;
  • 视野更开阔,对技术/软件的认识更精湛;
  • 团队的沟通/协作更开放、更高效(注:和对代码相当了解的人讨论问题,比起对代码所知了了的人,当然更高效;而开源所体现出来的开放和坦诚,也更容易赢得信任和尊重)。

 

对于团队拥抱开源后的提醒,主要在于两点:

  • 对发散的精力/兴趣的重新聚焦,聚焦于产品、目标、质量和进度等
  • 开源世界里选择众多,深刻了解才能作出明智选择

 

2、代码组织和存取

是所有代码集中存放在一个大源码仓库,严格控制签入签出;还是不同模块/项目代的码存放不同的源码仓库,各自管理签入签出?

 

这个问题看起来不起眼,但其实影响巨大,请让我细细分  阅读全文...

转:来自HeroKu的HTTP API 设计指南(中文版)

八月 31st, 2014 评论关闭
简介

本指南中文翻译者为 @Easy ,他是国内首家互联网人才拍卖网站 JobDeer.com 的创始人。转载请保留本信息。

本指南描述了一系列 HTTP+JSON API 的设计实践, 来自并展开于 Heroku Platform API 的工作。本指南指导着Heroku内部API的开发,我们希望也能对Heroku以外的API设计者有所帮助。

目录

基础

  • 总是使用TLS
  • 在Accepts头中带上版本号
  • 通过Etags支持缓存
  • 用Request-Ids追踪请求
  • 用Ranges来分页

请求

  • 返回适当的状态码
  • 总是返回完整的资源
  • 在请求body中接收JSON序列
  • 使用一致的路径格式
  • 小写所有路径和属性
  • 支持非ID的参数作为快捷方式
  • 少用路径嵌套

响应

  • 总是提供资源(UU)ID
  • 提供标准的时间戳
  • 使用ISO8601格式的UTC时间
  • 嵌入外键数据
  • 总是生成结构化的错误信息
  • 显示频率限制的状态
  • 在所有的响应中压缩JSON数据

文档及其他

  • 提供机器可读的JSON格式
  • 提供人类可读的文档
  • 提供可执行的示例
  • 描述稳定性
基础 总是使用TLS

总是使用TLS(就是https)来访问API,没有必要指出什么时候需要用,什么时候不需要用,只管任何时候都用它就好。

对所有非TLS的请求返回403 Forbidden,不要用重定向,这会允许一些不良的客户端行为,而又没有任何好处。依赖重定向的客户端会使流量翻倍,而让TLS毫无意义 —— 敏感数据已经在第一次请求时发送出来了。

在Accepts头中带上版本号

从一开始就为API分配版本。使用Accepts头来发送版本信息,可以使用自定义的内容类型,如:

Accept: application/vnd.heroku+json; version=3

不要提供默认版本,而由客户端显式指定它使用哪一个特定的版本。

通过Etags支持缓存

在所有的请求中带上 ETag 头 , 用于识别特定版本的返回资源。用户可以在随后的请求中通过提供If-None-Match头的值来检查内容是否过期。

用Request-Ids追踪请求

在每个API相应中提供Request-Id头,带上一个唯一的UUID值。如果服务器和客户端都记录了这些值,在跟踪和调试请求时会派上大用场。

用Ranges来分页

对所有可能产生大量数据的  阅读全文...

百度员工离职总结:如何做个好员工

七月 21st, 2014 评论关闭

2014 年 7 月 4 日,我从百度离职了。

这是第一次,我不是因为和老板闹翻而离职;

这是第一次,我带着晋升的喜悦而离职;

这是第一次,我带着满满的收获而离职。

我曾经认为,我永远不会成为一个好员工,因为我太独、太挑剔、不喜欢听话的好孩子、而且讨厌一切想要改变我的人。但是三年过去,我改变了不少,我必须承认,所谓“进步”的过程,就是被认可的过程,也是被“驯化”的过程。

所谓“驯化”,就是了解规则、遵守规则、利用规则的过程。我并非被某些人“驯化”,而是被社会与职场的规律驯化。我曾经鄙视这个过程,但今天看来,作为一个资质平庸的人,如果你想在这个社会里做成点儿什么,“被驯化”是不可避免的。

我也曾自诩“卓尔不群”,又受了老罗“彪悍的人生不需要解释”的“蛊惑”。但在现实中,这个路子不一定行得通。你不得不向很多人解释、用他们(而不是自己)喜欢的方式解释,因为只有得到他们的认可和支持,你才能继续工作下去。如果你是一个资质平庸的人,你不得不这样做,美剧《犯罪心理》中有一句话:“凡按自己的方式追求理想者,无不树敌。”

树敌多了,你就死了。

现在,我不敢说自己是个“好员工”,我只是觉得我是个比曾经的自己更好的员工。在离职的时候,我打算把自己这几年的职场心得总结一下,算是给自己的一个礼物。

我是一个资质平庸的人,以下这些心得只适用于愚钝且资质平庸的我,对于才华横溢的天才们并不适用。

一、你有“同理心”吗?

什么叫“同理心”?

说复杂点儿,同理心就是站在当事人的角度和位置上,客观地理解当事人的内心感受,且把这种理解传达给当事人的一种沟通交流方式。

说简单点儿,同理心就是“己所不欲,勿施于人”。将心比心,也就是设身处地去感受、去体谅他人。

说白了,同理心就是“情商”。

具体点说:

同理心就是,领导交办一项工作,你要读懂他的目的、看清他的用意。我经常遇到这样的情况:给团队成员安排工作时,一再询问“我说明白了吗”“有没有问题”,再三确认后,提交上来的东西仍然答非所问。所以我在接受任务时,总会向领导确认:你想要的是什么?你的目的是什么?了解这个以后,就可以站在他的角度,有效的帮他解决问题。

同理心就是,在激励员工时,点准他们的“兴奋点”,不揭“伤疤”。每个人都  阅读全文...

转:为SSD编程:总结每个程序员都应该了解的固态硬盘知识

六月 4th, 2014 评论关闭

在这部分,我以独立的简单段落的形式总结了其它部分的内容。每个段落概括了其他部分一节或几节的内容,这样可以让读者在每个主题下能够得到更多细节。

基础 1. 存储单元类型

固态硬盘(SSD)是基于闪存的数据存储设备。每个比特都存储在存储单元中,而存储单元分为三类:每个单元1比特(单层单元,SLC),每个单元2比特(多层单元,MLC),每个单元3比特(三层单元,TLC)。

>> 详见第1.1节

2. 寿命限制

每个单元都有P/E(写/擦)循环的最大限制,在此之后存储单元被认为是损坏的。这表示NAND闪存已经损耗殆尽,并有一个寿命限制。

>> 详见第1.1节

3. 基准测试很难

测试者是人,因此并不是所有的基准测试都毫无破绽。在读生产商或者第三方的基准测试结果的时候请小心,并在相信这些数据之前使用多个来源的数据。在有可能的时候,使用你的系统特定的工作负载在你打算使用的SSD型号上,运行自己的内部基准测试。最后,着眼于与你的系统最相关的性能指标。

>> 详见第2.2节和第2.3节

 

页和块 4. NAND闪存页和块

闪存单元组织成为阵列,称为块,而块组织成为面。块中能够进行读写操作的最小单元是页。页不能独立擦除,只能整块擦除。NAND闪存页大的大小并不一致,大多数硬盘的页大小是2KB、4KB、8 KB 或16 KB。大多数SSD每个块有128或256个页。这即表示一个块的大小可能在256 KB 到4 MB之间。例如Samsung SSD 840 EVO的块大小是2048 KB,每块包括256页每页8KB。

>> 详见第3.2节

5. 读是页对齐的

一次读取少于一页是不可能的。当然可以通过操作系统只请求一个直接,但SSD中会取回整个页,强制读取比所需多的多的数据。

>> 详见第3.2节

6. 写是页对齐的

写入到SSD的时候,写入将补齐到页大小。所以即便写入操作只影响一字节,都会重写整个页。写入比所需更多的数据被称为写入放大。写入一个页也被称为“(编置to program)”一个页。

>> 详见第3.2节

7.页不能覆写

NAND闪存页只能在其为“空”的状态下进行写入。当数据改变,页的内容被复制到内部寄存器中,数据更新,然后新版本的数据将存储字啊一个”空“页中,这个操作被称为”读-改-写“。数据并非原地更新,因为”空”页并非原先存储数据的页。一旦数据被保存到硬盘上,原来的页将被标记为“废弃”,并一直保持这样  阅读全文...

转:真正统治世界的十大算法

五月 10th, 2014 评论关闭

不久前的某一天,我在浏览Reddit发现了一篇有趣的文章《统治世界的十大算法》,作者George Dvorsky在那篇文章中试图解释算法之于当今世界的重要性,以及哪些算法对人类文明最为重要。

此时此刻,如果你已经学过算法的话,那么在你阅读那篇文章时,你脑海中所浮现的第一件事也许是“作者是否明白算法是什么?”或是“Facebook的新闻提要是一种算法?”,因为如果Facebook的新闻提要也算是一种算法的话,那么最终你可以把几乎所有的东西都归类为算法。因此,在本文中我会试着去解释什么是算法,以及哪十个(也许更多)算法是真正统治世界的。

什么是算法?

直白地说,算法就是任何明确定义的计算过程,它接收一些值或集合作为输入,并产生一些值或集合作为输出。这样,算法就是将输入转换为输出的一系列计算过程。来源:Thomas H. Cormen, Chales E. Leiserson (2009), 《算法导论第三版》。**

简而言之,我们可以说算法就是用来解决一个特定任务的一系列步骤(是的,不止计算机在使用算法,人类也同样如此)。目前,一个有效的算法应该含有三个重要特性:

1. 它必须是有限的:如果你设计的算法永无休止地尝试解决问题,那么它是无用的。
2. 它必须具备明确定义的指令:算法的每一步都必须准确定义,在任何场景下指令都应当没有歧义。
3. 它必须是有效的:一个算法被设计用以解决某个问题,那么它就应当能解决这个问题,并且仅仅使用纸和笔就能证明该算法是收敛的。

还有一个要点需要指出,算法不仅仅在计算机科学中使用,同时也存在于数学领域中。事实上,首个被记载的数学算法要追溯到公元前1600年,古巴比伦人开发了已知最早的算法,用作因式分解和计算平方根。这里,我们回答了前面所提到的那篇文章中的第一个问题,它认为算法是计算机范畴的实体,但如果你知晓算法这个词的真正内涵的话,真正统治世界的十大算法也能在数学书籍中找到(加法、减法、乘积等等)。

不过在这篇文章中,让我们将算法的定义限定在计算机算法上,所以剩下的问题是:哪十个算法统治了世界?在此我整理了一个小型列表,排名不分先后。

1. 归并排序,快速排序和堆排序

阅读全文...

转:不要成为工具的奴隶

四月 23rd, 2014 评论关闭

开发人员很容易迷恋上工具,因为工具通常比较实用,而且具备明确定义的行为,比起学习最佳实践或方法,学习工具更为简单。然而,工具仅仅为解决问题提供协助,他们并不能自行解决问题。

一位理解问题实质的开发人员能够使用工具提高生产率和质量,而拙劣的程序员从来不投入时间或精力去理解如何更好的编程和如何避免缺陷,他们会花时间学习如何使用工具,但这种学习方式脱离了对工具目标以及如何高效使用的正确理解。

在某种程度上说,这其中有一部分是工具供应商的错,他们嗅到了为一些普遍问题提供支持是一条财路,比如说:

*缺陷追踪器,帮助你进行缺陷追踪管理
*版本控制系统,管理源代码更改
*敏捷开发支持工具(Version One, JIRA)
*调试器,帮助你寻找缺陷

市面上有很多工具,但在这里我仅仅浏览一下下面的列表,同时指出在哪些地方开发人员和组织正在经受挑战。记住,以下所有的统计数据都来源于40多年间的超过15000个项目。

缺陷跟踪器

 

一些公司还没有用过缺陷跟踪软件,不管你信不信,我反正是信了,我遇到过这样几个奇葩公司,你一定觉得难以置信吧。没有缺陷跟踪软件的结果是相当杯具的,我们有证据证实。

不充分的缺陷跟踪方法:生产率 -15%,质量 -21%
就此我们达成了高度共识,那就是我们需要进行缺陷跟踪,并且我们都清楚,离开了这类工具,管理大量缺陷是不可能的。

自动化缺陷跟踪工具:生产率 +18%,质量 26%*

 

先说一个问题,开发人员总是爱争执哪个缺陷跟踪系统最好,这里的根本问题在于,几乎每个缺陷跟踪系统设置不好都会导致糟糕的结果。实际上,如果每个缺陷跟踪系统都能进行合理配置的话,结果都会大有裨益。这里最常见的误区是:
*在缺陷生命周期状态中引入了不相关属性,即创建诸如”延期“, ”无法解决“或 ”已设计的功能“这样的状态。
*无法指出问题是否已被修复。
*无法理解谁负责解决缺陷。

工具的供应商非常乐意继续提供这些缺陷跟踪器的新版本,然而要高效地使用缺陷跟踪器,更多的是取决于如何使用好这个工具,而非选择哪一种工具。

很多公司都在设法解决的一个最基本的问题是:如何定义缺陷?缺陷通常是指代码没有遵照规范工作,但是假设我们没有规范或规范很烂,那又会如何?你可以看一  阅读全文...

转:HAR(HTTP Archive)规范

三月 14th, 2014 评论关闭
HAR(HTTP Archive)规范

HAR(HTTP Archive),是一个用来储存HTTP请求/响应信息的通用文件格式,基于JSON。这个格式的出现可以使HTTP监测工具以一种通用的格式导出所收集的数据,这些数据可以被其他支持HAR的HTTP分析工具(包括Firebug,httpwatch,Fiddler等)所使用,来分析网站的性能瓶颈。目前HAR规范最新版本为HAR 1.2。HAR文件必须是UTF-8编码,有无BOM无所谓。

HAR数据结构:

一个HAR文件就是一个JSON对象,如下:

{ "log": { "version" : "1.2", "creator" : {}, "browser" : {}, "pages": [], "entries": [], "comment": "" } }
  • version [string] – 版本,默认为1.1。
  • creator [object] – 创建HAR文件的程序名称和版本信息。
  • browser [object, 可选] – 浏览器的名称和版本信息。
  • pages [array, 可选] – 页面列表,如果应用不支持按照page分组,可以省去此字段。
  • entries [array] – 所有HTTP请求的列表。
  • comment [string, 可选](new in 1.2) – 注释。

注:每个页面对应一个 对象,每个HTTP请求对应一个对象。如果HTTP的监测分析工具不能把请求按照page分组,那么为空。

<creator> & <browser>

这两个对象的结构是一样的

"creator": { "name": "Firebug", "version": "1.6", "comment": "", } "browser": { "name": "Firefox", "version": "3.6", "comment": "" }
  • name [string] – HAR生成工具或者浏览器的名称。
  • version [string] – HAR生成工具或者浏览器的版本。
  • comment [string, 可选](new in 1.2) – 注释。
<pages>

这个对象保存了页面列表,格式如下:

"pages": [ { "startedDateTime": "2009-04-16T12:07:25.123+01:00", "id": "page_0", "title": "Test Page", "pageTimings": {...}, "comment": "" } ]
  • startedDateTime [string] – 页面开始加载的时间(格式ISO 8601 – YYYY-MM-DDThh:mm:ss.sTZD, 例如2009-07-24T19:20:30.45+01:00)。
  • id [string] – page的唯一标示,entry会用到这个id来和page关联在一起  阅读全文...

无觅相关文章插件,快速提升流量