老翟书摘:《50大管理难题解决方案》

初做管理,想快速成长,而不想只依赖磨时间来带动“管理”的能力成长。所以,找到此书。 我期望从这本书中弄清楚的是管理过程中,到底会遇到哪些难题,以及别人解决这些难题的思路是什么样的。很幸运,这本书没有辜负我。 以下是书摘: 管理者,是不可能花大量时间去查阅几百本书之后再下决定 商业界却比以往任何时候都要复杂和扑朔迷离,管理者需要在更短的时间内对不同的观点和建议做出判断。但是他们通常工作繁忙,日程紧张,不可能花大量时间去查阅几百本书之后再下决定,他们需要的是马上就能帮助解决问题的答案或思路。 管理者,每天都有各种问题等着做决策,不论是自己的还是别人提出的。而且,还会面对有不少问题是之前从来没有想过的,也需要做决策。 这里并不是在抱怨做管理需要不停地做决策,心累。而是要说明,1. 管理者需要有一些原则来指导决策;2. 管理者平时就需要多思考,必须提前对自己提问,而不是等到问题出现再去考虑;3. 管理者必须有能力对问题进行抽象、分类。 其实我们自己在写代码时,也会不停地做决策。这个类要怎样的命名,这段逻辑到底要不要抽出来等等。编程时的决策大多已经有前人总结出来,只要你多学习前人经验+自己勤思考,基本上也就能成为合格的程序员了。但是管理不一样。很多问题,是必须你即时做决策的,比如员工当面向你提出离职,没有时间留给你查资料后做决定。那么如何才能更即时地做出更正确的决策呢?这个没有答案的问题,我自己是这样看的:很多能力是可以通过练习的方式习得的,在你还没有成为管理者的时候,应该向你的管理者学习如何管理并对其管理方式进行抽象。当然,我不是说你不学编程了就一心只学编程。就像我自己学开车,我不是一开始就找个驾校,而是抓住很一次坐车的机会,向司机学习,同时看着司机开车,自己在大脑里预演自己应该如何开车。 管理难题的分类 书中是对管理难题这样分类: 员工层面的难题 团队层面的难题 来自外界的难题 冲突带来的难题 变革中难题 权力、政治和影响力带来的难题 涉及自己的难题 其实,这和你自己当前所在岗位有关。如果你只是一个小小的PM,通常你只会遇到员工和团队层面的难题,涉及自己的难题除外。但是这并不妨碍你,看到公司中有变革中难题时,向那些真正遇到这方面问题的人学习。我想这就是这个分类,对我们这些小PM最大的益处。我甚至从上几家公司学习如何劝一名员工不离职。 员工层面的难题 最常见的管理难题通常与团队中个人的需求相关,这些个人需求之所以会变成管理难题,原因在于管理者宁愿解决和工作任务相关的问题,也不愿处理一些有关自我认知或照顾他人感受的问题。 成功的管理者既能意识到这些问题,也有能力解决它们。不管是个人缺乏动力、缺乏信心或者是个人能力不足,这些都是团队或组织沉重的负担。 每位管理者还必须有能力与员工就棘手的问题进行交流,不管是员工出现了个人变动,或者他们需要得到企业的关注,还是他们做了不可接受或进行了破坏性的行为,你都必须能够开启那些具有挑战性的交流,或者当问题反映到你这里时,你要能够对其做出积极的回应。 员工层面可能会遇到的难题: 缺乏动力 缺乏信心 能力不足 虽优秀但“难伺候” 授权与放手 …. 相信每个管理者都遇到过千奇百怪的,比如员工的家人说做IT不好,然后这个员工最离职了。 遇到员工层面的难题,如何分析呢?我个人从书中总结出的: 出问题是团队新成员,还是老员工?出问题前是这个人是怎样的:有没职位上的变动,能力能否胜任当前工作,有没有新人加入,他和其他团队成员的关系怎么样等等;企业环境是怎样的:公司最近出了什么政策,公司的薪资水平是否有调整等 但是这些毕竟是你自己猜想。所以,处理员工层面的问题(其实也适用于处理每个层面的问题)最重要的事情就是:沟通,沟通,沟通! 团队层面的难题 如何有效管理团队并让团队发挥最大功效是管理者要应对的最大也是最常见的管理难题 很多人将发挥最大功效等同于压榨。我个人想法是大家对于发挥最大功效的理解不同。在体力工作年代,产出的物件越多,就是量越大功效越大。但是知识工作则不同,知识工作不是量越大,功效越大。因为你根本无法度量“知识”这个东西,多大量才算大功效呢?一个月生产了10个ERP软件就算功效大?真实场景是一个月只需要生产一个ERP,然后由销售卖出10个。 对于知识工作,是否是压榨?取决于自己是否在做重复工作。比如你工作3年了,每年做的工作都是一样的,那么,你就是自己压榨自己!你不学习,你就不能胜任新工作,毕竟学习是自己的事。 反过来,作为技术管理者,我们应该思考,什么才是技术团队的最大功效? 权力、政治和影响力带来的难题 在企业生活中,所有东西都带有政治色彩,这是因为总是有公开的或隐藏的组织意图与公开或隐藏的个人意图交叉在一起。这些意图通常并非一心为公,更多的是为了一己私利,队员们追求的是对自己、自己所属团队或部门有利的意图,而非无私地追求企业、企业的客户和顾客有利的意图。 刚毕业时感受不到这些“权力”、“政治”带来的难题,但是随着年龄增长,慢慢就发现真的就是那样:即使两个人公司也会存在政治。 带来的思考是“政治”这个东西在什么环境是好的,什么环境是坏的?如果无法消除这种“私心”,那么如何把企业的利益和员工的利益相结合呢?这本书没有回答。但是另一本书叫《联盟》的书,也许能给我们答案。 总结 整本书最关键的是带给我们一种解决问题的思维方式。书中没有直接说明这点。什么思维方式呢?当我们面对管理上的难题时,可以这样思考: 首先,想一想 确定行动思路 想什么呢? 想清楚问题到底是什么? 事实有哪些? 理清相关者背后的利益关系 听取当事人的想法 如何确定行动思路?这点,书中倒是没有很好的抽象,只是告诉你怎样做。也许这方面就真的依赖于经验了。 在“涉及自己的难题”这一章开头: 管理者面临的一些最大挑战实际上并不是和其他人相关或者与技巧和能力方面的要求相关。这些有形的挑战他们往往都能处理好。对很多管理者来说,最大的挑战是更加无形的,通常都与自我意识有关。有些挑战看起来似乎是直接针对你个人的,并不是以职业身份发起,而是以个人的名义发起的,对于这样高度私人化的难题,你该怎样做出最佳回应? 自我意识有助于你应对那些针对你个人本身的难题,因为它让你清楚地明白自己是谁以及在做什么。如果你了解自己,就知道什么是重要的,知道自己喜欢怎样工作以及怎样和别人打交道,知道自己作为个体的优势以及哪些方面还有待改善。 唯有自己真正强大了,难题也就不存在了。 思考题 公司有些福利政策,但这些政策依赖于个人自觉。如果出现了不自觉的情况,你如何管理?比如灵活的上下班机制,起初是考虑到大家如果真有事或住得远,可以晚到一会。但是慢慢会变成了每天必须晚到。如果你是管理者,你觉得这类问题是问题吗?为什么? 题外话 有时我会和别人讨论这些管理问题。但常常得到的回答却是:你不知道“不在其位,不谋其政”吗? 想必看这篇文章其中一部分读者也会这么想。我的个人观点是:机会都是交给那些随时准备着的人的,在做好你当前工作的同时,多思考一些,等机会来的时候,你就不会失去机会。 老翟书摘说明 书摘内容完全来自原书,如果原书的作者或出版商觉得我侵权了。请通过开源中国 @翟志军 联系我。 老翟书摘旨在通过一种书摘的方式让大家花最少的时间了解一本书,从而决定要不要继续读下去。书摘的每一本书都是本人亲自读过并理解的。

2016-07-20 · 1 min · 69 words · 翟志军 Jack Zhai

性别字段存储时应该使用的字符串,还是数字?

在我和同事结对时,发现数据库中多个表中,分别都会有gender这个字段。比如A表,B表,C表。这三个表中,gender字段都是int类型。但是同一性别,在各个表中的值是不同的。比如A表中,1代表男,在B表中却代表了女,在C表中代表未知。 我突然意识到这背后存在更大的问题。从而引发我对“性别字段存储时应该使用的字符串,还是数字?”这个问题思考。也许已经有前辈思考过这个问题并写在某本书的某页,如果有,请告知。谢谢。 0代表女,1代表男 首先,你可能会问,对于这样的问题还用想吗?不是都使用数字吗?0代表女,1代表男。 其实,淘宝就是这么做的: html代码是这样的: 这时,我会问如果这个用户没有填写性别信息呢?那你可能将原来的实现改成0代表空,1代表男,2代表女。我提醒你,当你开发的是一个大型网站时,你要将原来的“0代表女”改成“0代表空”,不会那么容易。历史数据要处理。你还需要修改所有用到0,1的代码,即使你使用的是常量代替而不是魔法数字,也不会容易到哪里去。 有经验的程序员 是的,有经验的程序员写代码时,一开始就会想到这个问题,所以一开始就设计“0代表空,1代表男,2代表女”。从前端到后端都统一使用数字。比如: class User{ final static int GENDER_NULL = 0 final static int GENDER_MALE = 1 final static int GENDER_FEMALE = 2 int gender } class UserController{ void saveUser(int gender) } <div>gender: #if($user.gender == 1)男#elseif($user.gender == 2)女 blabla….</div> 当然前端这样写有些难看,那我们使用宏来代替,比如<div>#displayGender($user.gender)</div>。这里我想留一个疑问:如果想国际化呢?你的displayGender怎么实现的? 实习生来了 某天公司招来了一个实习生要实现一个活动申请表页面。领导觉得这个功能应该不难,所以就将这个任务分配给他。他为了表现自己,哐啷哐啷很快就写完了,还得到了领导的表扬。但实习生根本没有参照前面有经验的程序员的写法(有时不是他的问题,可能是没有人告诉他需要参照某个功能的写法来实现)。有意识一些的实习生还知道将gender的值写成常量,没有意识的,可能你只有去到前端页面看源码才能知道0, 1分别代表什么。 class ActivityApply{ final static int GENDER_MALE = 0 final static int GENDER_FEMALE = 1 int gender } 如果他没有参照前面有经验程序员的写法,我不确定他是否会重用那个前端宏。所以,讲到这里,你应该明白,有时你设计好的“重用”,并不一定会被重用。为什么呢?:P ...

2016-04-15 · 1 min · 187 words · 翟志军 Jack Zhai

每日站会、代码审查、结对编程 之开源中国实践

在我来到开源中国之后,尝试将每日站会、代码审查、结对编程这三种编程实践带入团队。而这个过程,我个人觉得是一项非常宝贵的体验。我觉得可以拿出来和大家分享。 先介绍下目前我们团队的结构:3名Java开发,1名前端,2名实习。 以下我不会详细介绍它们分别是什么,也无意讨论它们有什么好处坏处,本文侧重分享在实践它们的过程可能遇到的问题,以及我们是如何处理的。 每日站会 每日站会 (Stand-up ):是每天进行的会议旨在在组队成员之间进行状态更新。‘半实时’的状态允许参与者了解到潜在的挑战以及用于处理一个困难或者耗时的问题的协调精力。它在一些敏捷软件开发过程中有着特定的价值,譬如Scrum,但是同样可以在任何开发方法论中被使用。术语 “站” 衍生于通过保持与会人员站立的状态(长时间站立会导致不适)从而帮助控制会议的时间的实践。 我们每天会早上花十几分钟(具体时长看团队大小),大家一起站(是站)在卡墙前过卡。卡墙其实就是Team中的任务看板。就这样,我们从“已验收”列到“待办中”列,从上往下,一张卡一张卡的过。这里的卡是指定义了一个小功能需求的卡片。 站会不过是向领导汇报 我在实践每日站会的时候,发现不少人把每日站会当成一种“向领导汇报”的过程。比如他们会习惯地汇报:我昨天做了1,2,3 blabla。一大串,仿佛说得少就是做的少。所以这个过程,我不断地指正,你们不是在向领导汇报,我们只需要对这件事情负责,说到你的卡时,你就说你的卡的当前状态就好了。慢慢地团队里就养成了对事不对人的文化。为什么呢?每日站会就是提醒我们每日的工作就是对这些“事”负责。 随着时间迁移,我们的团队就慢慢习惯了这种站会。也会在站会上开一些开玩笑了。不要认为这是浪费时间,这是团队文化中很重要的一部分。 站会时间把控问题 站会还可能会遇到的问题是站会时间的把控。所以,我们每日站会会有一个主持人。如果大家说偏题了,主持人就必须指正,让相关人在站会后自己讨论。如果大家讨论的这个问题是个大问题,那么,也是在站完会后再讨论。另外,主持人还要是轮换的,这样就可以将团队所有成员带入项目。 站会上的新人问题 每日站会常常遇到的问题是过卡时,这个人说得太细了,把功能的具体实现细节都说出来了。这时,我们不应该立即打断他。出现这样的情况,说明他一定是新人。我们应该选择在站会后单独找他重申一次每日站会的目的和内容。当然,一开始实践每日站会时,团队里除了你每个人都不懂时,你就有必要马上指正了。 代码审查 代码审查(Code review)是指对计算机源代码系统化地审查,常用软件同行评审的方式进行,其目的是在找出及修正在软件开发初期未发现的错误,提升软件质量及开发者的技术。代码审查常以不同的形式进行,例如结对编程、非正式的看过整个代码,或是正式的软件检查。 我今天没有什么好说的 一开始,我实践时,遇到的最大问题是:团队成员喜欢说,我今天没有什么好说的。这句话听起来冷漠,其实背后的原因是大家不完全理解代码审查是什么,而不是因为他们真的没什么好说的。 这时,我会说:只要你今天做了的事情,你都可以说。然后,他们常常不知从何说起,接着,一上来就给我们讲代码细节。 遇到这种情况,我们需要再强调一遍代码审查需要说什么:上下文、你是如何解决问题的、解决过程遇到什么问题……有时被审查的人可能说的不够明白,我就会帮助补充。 这个过程,你可能会发现有些人在表达能力上的不足,导致听的人一头雾水。我的做法是理解他说的,然后尝试帮助他更好表达出来。这样,提升他的表达能力的同时,让他在团队里也更有归属感。 说得太多了 有时,有些成员可能会说的非常非常细。多人这样了,就会导致代码审查的时间过长。发生这种情况,将表达能力的问题排除外,大概就是这个人没考虑哪些应该是自己应该重点说出来的。这时leader就要站出来指正了。 没写代码怎么审查? 其实,我们实践的代码审查并不是十分严格。因为有时,我们一天下来没有写代码,而是做调研工作。遇到这种情况,被审查人也需要主动分享他今天的习得。有时,他说出来某个问题,也许其他成员也遇到过同样的问题,并解决了。这样就为团队节约时间。 结对编程 结对编程(Pair programming)是一种敏捷软件开发的方法,两个程序员在一个计算机上共同工作。一个人输入代码,而另一个人审查他输入的每一行代码。输入代码的人称作驾驶员,审查代码的人称作观察员(或导航员)。两个程序员经常互换角色。 如何将结对编程带入团队? 我们的做法由一个懂得结对的人分别和团队里每一个人进行结对。结对前,详细说明结对可能遇到的情况,比如双方有争执,一直都是一个人写的情况,双方都遇到不懂的情况……然后,结对时穿插结对编程的知识。 团队成员中的两个都没有结对编程的经验,怎么办? 实际情况是我们遇到更麻烦的事情。 因为我在前端不擅长,所以我决定让两名前端结对。问题来了,这两个人都不会结对,在沟通方面也不是非常擅长。让他们结对后,我发现他们一起结对的时间非常少,一天下来基本就是各做各的。这时,我发现不对劲。我就分别找他们谈。为什么要分别呢?是希望他们大胆说自己的感受。 在和他们谈了之后,发现根本原因是他们没有完全理解结对编程的目的。这时,找到他们俩再重申一遍结对编程是为了什么,以及如何结对。 新人对结对编程常常有的疑惑? 他在写代码,我看着有什么用? 软件开发是一项集体脑力活,知识的流动在这项活动中非常关键。结对编程是促进知识流动的行为。 看别人写代码的人,我们称为“观察者”。写代码的人,我们称为“驾驶员”。观察者的职责是对写代码的人的代码进行审查。其实除了这点,我更看重的是这个分享思维方式的过程,会加速双方的成长。这个过程还能营造一种相互学习的文化。 我觉得我一个人一下子就写完了 说这句话的人的能力不会差。其实有这样的想法很正常。这时,我们就鼓励他多分享。当我深究下去时,他说写那些东西根本不需要动脑。还很得意的样子。不知道你们有没有发现其中的问题:他在做体力活。更大的问题是:他还不知道自己在做体力活。这时,我会说:当你在做体力活时,和机器没有区别,说明你在退步,这时,你应该跳出来,挑战自己,比如coach别人,或找到一种避免这种体力活的方法。 如果你有什么疑惑,可在本文评论留言。 小结 每日站会,代码审查,结对编程实践的先后顺序的? 本质上是没有先后顺序的。但是如果你是一位新来的leader,你就需要考虑你加入的团队的情况了。我们是先施行每日站会,代码审查。最近一个月才开始实施结对编程。为什么呢?因为对这些编程实践,如果强硬推行,可能会受到排斥。你需要时间让团队成员消化。 给人留下“什么都管”的印象 由于我带来了这些新的实践,看到团队成员实践过程的一些问题就会指出,所以经常给人“什么都管”的印象。 当leader什么都管时,leader要问自己为什么什么要管,而团队成员也要反问自己为什么什么都要被管。排除leader的性格问题外,大多数时,是因为团队还处于比较初级的阶段。你问问自己,团队里有多少人可以自己做leader的就知道了。leader应该跟大家说清楚这点。这样大家就理解你了。但是这个“初级”的阶段要多长时间?就要看你什么时候培养出另一个leader了。 你会发现我在本文没有谈什么M捷或者精Y,是因为我想就事论事,不想谈理论,只想解决实际问题。 问题来了,你发现团队中没有人会结对,你作为leader不懂得如何结对编程时,怎么将结对编程带入团队中呢? 这时就需要请外援了。好听一些,请咨询顾问。如果你觉得看了我的文章,觉得我还行,也可以找我。我在开源中国众包发布了一个专家服务: 将每日站会、代码审查、结对编程带入团队

2016-04-01 · 1 min · 56 words · 翟志军 Jack Zhai

老翟书摘:从《大野耐一的现场管理》看软件工程管理

前年,接触到了《丰田生产方式》,就对大野耐一这个人十分感兴趣,就专门找他的书来看。 同时,我一直都有一种“感觉”:我们软件工程的管理方式都是从传统工业借鉴的。比如被吹上天的“精益”概念及“看板”概念。然而,这些概念里,少有人说明这样地借鉴的理由及借鉴了哪些,放弃了哪些。想回答这个问题就必须分别弄清楚传统工业和软件工程的本质。 我尝试在这本书了解一些关于传统工业的管理概念。以下是书摘: ####“精益”的概念的产生 1990年,美国麻省理工学院的詹姆斯 沃麦克等多位教授,在《改变世界的机器》一书中,首次以“精益生产”(learn production)为核心介绍丰田生产方式,自此,欧美的一些企业才开始把丰田生产方式作为全球化以及提高生产率的标准和尺度。 领导说服力:坦诚即代表强劲的说服力 要想说服别人或是得到理解,若没有什么根据或道理是行不通的。 不要总是认为自己的言行没有错误,意识到错之后就应该爽快地说出来。如果有了这种胸怀,指挥现场以及下属不就变得轻而易举了吗? 犯了错误之后,应该不吝于向他人甚至的下属道歉,怀着这样坦诚的态度,怎么会没有说服力呢? 为了形成强劲的说服力,重要条件之一就是管理者自身应该怀着谦虚的胸襟。 现实生活中,人们似乎随着知识越来越丰富,产生错觉的可能性反而越大。 传统工业也会遇到我们软件工程一样的问题:面对同样一份工作,存在不同的意见。传统工业时里的体现可能是组装配件有两种方式,哪个效率更高;软件工程里的体现是实现某个功能,怎么实现更快(不要忘了,我们还要考虑可维护性,可读性)。当存在不同的意见时,双方容易在无用的争论上浪费时间,大野耐一是这么处理的: 在产生两种意见的情况下,各给双方一个工作日的时间,让他们按照自己的意见试着做一做,最后比较结果,直到让大家彻底理解、赞同为止。 其实,这样处理的最大好处是将**“实践出真理”**的文化慢慢带入企业。 ####要提高生产效率,“意识革命”是首要问题 从上层管理者到中层管理者甚至工作在生产一线的作业员们,由于大家都是普通人,所以都有可能被禁锢在错觉之中,认为现行的做法是最科学的;或者说即使不认为是最好的,也觉得别无选择,这就是被常识化了。 我们软件行业更是如此,特别是一毕业就只在一家公司待很久的人。很容易被“常识化”,认为软件开发就只有一种方式:手工将jar包下载回来,导入到IDE中,然后写代码;部署软件也就是ssh上服务器,然后stop,start。 大野耐一说: 若是不改变从管理顶层到一线作业员以及工会的意识、观念和想法,那么怎么可能探索出做好工作的新方法呢?组织上的改革或许相对容易,但是“意识革命”应该会更加困难一些吧。 再比如很多人认为写单元测试会导致进度被拖慢。其实,关于单元测试是否加快进度,需要更多的数据支撑。所以,需要软件项目管理工具为我们提供更全面的统计工具,来收集这些数据。这也说明了软件行业和传统工业的一个很大的不同。传统工业中很多工作是重复的(产品通常是批量生产),可以快速实验,快速看效果。而软件行业中,根本没有批量生产某一软件的说法。 ####无效率的动作不是工作 身为生产现场的管理者和主管,必须具有分辨“动”和“働”的慧眼,也就是说,必须能够分辨清楚哪些动作是无效率的,哪些动作与工作是无关的。 这里,对于这个“无效率”的定义会有争议。我是这样认为的,如果不能帮助我写出可读、可维护、用户可用的软件的动作都是无效率的。比如手动去管理软件依赖、手动部署、需求沟通需要等上一个星期、新加入团队的成员需要花两天的时间搭建开发环境、重复手工测试、单元测试写在main方法里、写代码过程分心看微博,动弹…… 作为leader,发现这些无效率动作,然后找到改善办法是一项重中重的工作。 ####改善应该按顺序进行 所谓作业改善,就是能够让现有的设备更好地发挥作用。在改善过程中,首先需要考虑的不是购买设备,而是最佳的工作方法。 我认为首先需要进行的是作业改善,之后才依次为设备改善、工序改善,也就是改善应该有先后顺序。 软件行业中,顺序应该是软件开发流程改善,之后依次是实现技术改善、软件开发工具改善。原因是软件开发流程的成本收益率比实现技术改善、软件开发工具改善更高。这只是我的片面之词。希望有数据的同学能帮我证实。 ####产品质量问题 如果某个零件比较容易在前几道工序的时候出现问题,是不是应该考虑将检验工作提前呢?提前发现并剔除不良品,总比让它们一直往下走要好得好多。 品质融于生产过程中,因此,如果能在必要的地方做好检验工作,那么就不必等到工程的最后才发现不良品,或者说到工序的最后阶段只需要重点检验某些部分即可。 产品质量融于软件开发过程中,将风险高的软件模块提前开发。QA在功能开发前就参与需求的讨论,并提出验收条件AC。 ####降低成本 如果有人问我,为什么要拼命减少库存、降低成本,我会告诉他,是为了让资金周转更加轻松。 然而,只要提到降低成本,大家就会觉得这是财务人员的责任,其实不然,财务人员根本无法促使成本降低,这只能通过集体的努力实现。 因此,所谓的降低成本,唯有依靠生产现场来进行,现场的降低成本的意识要做到比鬼还要精才行啊。 减少浪费也可以降低成本。关键是我们如何看待浪费。在《丰田生产方式》中定义的浪费: 1.过量生产的无效劳动:软件行业中指在不合适的时候开发多余的功能 2.窝工的时间浪费 3.搬运的无效劳动:需求沟通不完整,导致重复沟通 4.加工本身的无效劳动和浪费 5.库存的浪费 6.动作上的无效劳动:花费过多的时候搭建开发环境 7.制造次品的无效劳动和浪费:品质没有融于生产过程中 从这里就可以看出光靠架构师是不能彻底杜绝浪费,更不可能靠财务了。 ####小结 这本书给我最大的启发是:高高在上不接地气的技术管理是无法管理好团队的。高高在上意味着他无法或很难及时、准确得知开发现场的情况的。如果你连“施工现场”的情况都不了解,谈何改善? 同时,我也发现软件行业的代码审查、每日站会就很好的体现了大野耐一的现场管理思想。通过这两个实践,我们的leader才有更多机会靠近“现场”。这才是代码审查、每日站会背后更深层的原因。 半年后再次重读这本小书,又知新。 老翟书摘说明 书摘内容完全来自原书,如果原书的作者或出版商觉得我侵权了。请联系我。 老翟书摘旨在通过一种书摘的方式让大家花最少的时间了解一本书,从而决定要不要继续读下去。书摘的每一本书都是本人亲自读过并理解的。

2016-02-15 · 1 min · 54 words · 翟志军 Jack Zhai

Puppet,Chef,Ansible的共性

本文试图找到类似Puppet、Chef、Ansible这样自动化配置管理工具的共性,以不至于迷失在杂乱的尘世中。总会有各种人为各种目的造概念,来让世界更复杂。 本文同样适用于没有运维经验的人。因为我就是一个没有运维经验的人。欢迎斧正。 与这仨之间的历史 本人接触自动化运维的时间比较晚,也就一年前才知道Puppet及自动化运维(只限于知道),而Chef、Ansible就更晚了。然而在学习它们之前,我对运维要做哪些事情并没有概念。这就对我学习Puppet,Chef和Ansible造成的障碍。因为不知道这三个工具在运维领域的位置,解决运维过程中的哪些问题。我对这三个工具的最初印象就是有了它们,不用我手工的SSH上服务器,然后一条条命令去执行安装软件,不用SCP war包上服务器等,对服务器的操作都可以自动化了。 这个最初印象也就是我跟它们的历史。为什么要说这些呢?就是因为这个最初印象,让我觉得它们是有共性。所谓共性就是存在一些共通的概念或原理之类的东西,掌握这些“东西”,我就可以站在一个更高的高度去思考。Puppet, Chef, Ansible都是工具,对于工具来说,共性指的是它们共同要解决的问题。 但是当我翻了不少文章后依然没有结果。所以,我决定自己去找它们的共性,并记录下来。 自制一个自动化运维工具 但是要从多个相似的东西中找到共性,似乎需要同时很熟悉它们。但是我没有那么多时间。所以,我选择了另一种方法:在大脑中预想自己去实现一套自动化运维工具。但问题是,我都不知道“自动化运维工具要实现哪些功能。 那我就先把目标降低一些,把问题简化一下:将我最初的“印象”实现自动化了。我能想到的就是写一个bash脚本: ssh .... apt-get install -y java apt-get -y nginx scp .. 好,现在将问题难度加大:对多台服务器进行同样的操作。我能到想就是将所有的服务器的IP放在一个数组里,然后用for循环执行。问题来了,如果我对服务器已经执行了一次命令时可能会失败,我再想执行第二次怎么办呢?这时,我们可以在bash脚本里加上if语句,如果安装了java就不安装第二次了。 显然现实中还会有很多问题,如: 反向配置问题,这时,我们应该另写一个bash脚本来解决这个反向的问题?如果采用这种方案,我们bash脚本数量上升到一定程度,如何管理这些脚本及它们之间的关系,这个方案带来的新的复杂性将会成为我们的新问题; 服务器上操作系统的兼容性问题:不同的操作系统,我们的bash命令会不同; 软件的版本升级或降级问题等等。 面对这些问题,我们是可以每次都用bash解决,但是这样始终不是个办法。因为,bash对于建立一个自动化运维工具过于底层。说到这句话,你应该很容易就想到设计一种DSL。到这个点,我觉得我们的方向已经明朗。Puppet, Chef和Ansible都分别采用不同的DSL。而这种DSL是需要编译成服务器可执行的东西的。什么东西是可执行的?目前,我们假设这个东西是bash脚本。 但是这个DSL是放在哪里编译呢?放在受控机器端,还是主控机器上?所以,我认为所有的自动化运维工具都会遇到这个问题。什么是受控机器与主控机器?你就理解成一台机器只发命令,另一台机器只执行命令。 我们刚刚谈的是设计DSL。但是,要设计一个完整的自动化运维工具,我们最先应该考虑是主控机器如何与受控机器通信。这个问题让我很长时间感到很无力,因为无从下手。后来醒悟,原来你不能单独考虑这个问题,通信方式还与你设计的DSL及编译DSL的方式有关。同时,受控机器的执行结果这个问题,也影响着我们设计DSL。 上面我们似乎忘记了一个事实:自动化运维工具应对的往往不是一台机器,而是很多台机器。当面对多台机器时,就会产生一个新的问题:如何组织它们?因为不同的机器的职责不同,所对应的配置也就不同。 我想我们已经知道自动化运维工具都要解决的问题了: 如何与受控机器通信 如何组织成百上千台机器 DSL的设计与编译 如何得到执行结果 我不确定我们的思路与Puppet,Chef和Ansible的作者一样。也不一定完全正确。但是至少,我们大概知道自动化运维工具要解决哪些问题了。而它们是不是自动化运维工具的共性?我不确定。 但是没有关系,我们假设它们就是所有配置管理工具都要解决的问题,它们的共性,接下来我们来看看它们分别是怎么解决这些问题的。 这仨的背景 在进入学习之前,我们先看看它们的背景,然后详细了解它们是如何解决问题的。 Puppet 如何与受控机器通信 Puppet的主控机器(Server)称为Puppet master,受控机器(client)称为Puppet agent。它们使用HTTPS进行通信。在安装puppet之前,需要分别在主控机器和受控上设置的hostname。 因为是C/S架构的,意味着你需要在主控机器上安装Puppet master,(安装的过程或翻阅其它教程的时候,请注意教程所使用的Puppet的版本,Puppet版本之间是有差异的)我们以Ubuntu为例: sudo apt-get install -y puppetmaster 在受控机器上安装Puppet agent: sudo apt-get install -y puppet 安装完成后,受控机器需要设置在/etc/puppet/puppet.conf文件的[main]节点下加入server=<master’s hostname>,同时运行sudo puppet agent —test向主控机器申请认证。主控机器执行sudo puppet cert sign <agent’s hostname>认证。 ...

2016-01-02 · 3 min · 614 words · 翟志军 Jack Zhai

Spark本地开发环境搭建

本文使用Scala2.10.6,sbt。请自行提前装好。 设置SSH,本地免密码登录 因为Spark master需要ssh到Spark worker中执行命令,所以,需要免密码登录。 cat ~/.ssh/id_rsa.pub > ~/.ssh/authorized_keys 执行ssh localhost确认一下,如果不需要密码登录就说明OK了。 Tips: Mac下可能ssh不到本地,请检查你sharing设置: 下载Spark http://spark.apache.org/downloads.html 我选择的是spark-1.6.0-bin-cdh4.tgz 。看到cdh4(Hadoop的一个分发版本),别以为它是要你装Hadoop。其实不然,要看你自己的开发需求。因为我不需要,所以,我只装Spark。 配置你的Spark slave 我很好奇,worker和slave这个名称有什么不同?还是因为历史原因,导致本质上一个东西但是两种叫法? 在你的Spark HOME路径下 cp ./conf/slaves.template ./conf/slaves slaves文件中有一行localhost代表在本地启动一个Spark worker。 启动Spark伪分布式 <SPARK_HOME>/sbin/start-all.sh 执行JPS验证Spark启动成功 ➜ jps 83141 Worker 83178 Jps 83020 Master 打开你的Spark界面 http://localhost:8080 下载Spark项目骨架 为方便我自己开发,我自己创建了一个Spark应用开发的项目骨架。 下载项目骨架: http://git.oschina.net/zacker330/spark-skeleton 项目路径中执行:sbt package 编译打包你的spark应用程序。 将你的spark应用程序提交给spark master执行 <SPARK_HOME>/bin/spark-submit \ --class "SimpleApp" \ --master spark://Jacks-MBP.workgroup:7077 \ target/scala-2.10/spark-skeleton_2.10-1.0.jar 这个“spark://Jacks-MBP.workgroup:7077”是你在 http://localhost:8080 中看到的URL的值 可以看到打印出: hello world

2016-01-01 · 1 min · 64 words · 翟志军 Jack Zhai

老翟书摘:《MBA教不了的创富课》

我一直希望能了解那些富人一步步富起来的过程,更重要的是了解他们是如何思考的。但是很多传记写的就像李开复的《世界因你而不同》那样,除了鸡汤还是鸡汤。我不是说鸡汤没有价值,而是我更想看到真实世界到底是怎么样的。 而这本《创富课》很是落地,解答了不少我一直以来的疑惑。 下面从我的疑惑出发来对这本书进行书摘。 从工作到现在,我很多时候都会担任“反调”的角色。也就是领导说出什么决定。我思考后经常会提出另一个与之相反的论调。先不谈我的论调是否正确。不少人对于这个“反调”要么觉得你就一个小兵,执行就好;要么觉得很烦。我就疑惑,有不一样的声音不好吗?但是说不上背后的机理。来看看老雕怎么说的: 一方面,要做到团队统一理念。另一方面,又要鼓励团队中的反对声音。这一点儿不矛盾,换句话说,就是在“战略”上,大家要彼此达到共识(那是团队建设的核心),而在“战术”上,则必须反复认证,也就是怂恿争吵、鞭策博弈。 大家早就知道一个人再高明,也无法面面俱到。却少有人知道,其实一群人更容易陷入“集体无意识”。尤其你是最高决策人时,你发表的意见,大多数下属无条件接受。(别忘了大部分中国人都喜欢察言观色,随时保留意见)。所以这时候,如果一个声音喊道:“老板,我认为你说的不对!我倒认为,从反方面来看……” 你千万别把脸憋成番茄,或者拍着桌子打断他,而应该像偷猎者见到大熊猫般欣喜若狂。 说回来,我也很理解“领导”比常人更要“面子”。说到这里,我常常听人说要注意说话方式。这是另一个高深的话题,即使我总提醒自己:见人说人话,见鬼说鬼话。但是知易行难啊。 很久以前就听说“办公室政治”,苦于阅历尚浅,始终理解不过来。老雕年青时也和我一样有相同的疑惑: 没过多少日子,我所在部门的小领导,一个笨蛋,就找我谈话了,他苦口婆心劝我,教导我,“表哥,你这么拼,有问题的啊,你这么干,把很多同事反衬得不用功不努力似的,这会遭众怒的,明白吗?” 噢,原来这就是“办公室政治”了吧?虽然老雕我当年年纪小,但也体会到他所说话语的含义了。 关于如何做生意,老雕是这样的: 第一步,分析你的企业所在的产业链。 第二步,分析你的企业的“价值链” 第三步,从价值链里找到核心竞争力。 看任何企业问题,都首先站在产业链看价值链,然后站在价值链看核心竞争力,站在核心竞争力的高度上,看品牌、营销、成本控制……一系列的“药材”。 咋一看很虚,但是他虚得是有道理的。因为他告诉我们的是一种思考方式。说实在的,我不知道有多少企业是采用这种思考方式。但是,我尝试了,感觉还真有用。老雕文章还有不少例子,有兴趣的同学可以看看。 做生意,一定会有竞争对手。针对“我的竞争对手是谁”这个问题。老雕给了我一个没想到的答案: 可口可乐的竞争对手,是所有抢“喉咙份额”的家伙们。比如,茶、酒、矿泉水、果汁…… 原来,我们在分析竞争对手时,视野不能那么狭隘,认为可口可乐的竞争对手就只是百事可乐。 小结: 不要认为我把这些东西摘抄下来,就代表我完全赞同,就算我现在赞同部分观点,也不代表我将来赞同。 总的来说,还是能从这本书得到不少启示。 老翟书摘说明 书摘内容完全来自原书,如果原书的作者或出版商觉得我侵权了。请联系我。 老翟书摘旨在通过一种书摘的方式让大家花最少的时间了解一本书,从而决定要不要继续读下去。书摘的每一本书都是本人亲自读过并理解的。

2015-12-30 · 1 min · 26 words · 翟志军 Jack Zhai

老翟书摘:《丰田生产方式》

这本书的作者是大野耐一,原丰田汽车工业公司副社长。里面写了大多是一些生产过程中的原则和看法。但是,这些原则和看问题的角度是通用的,即使我们是软件行业。同时,在看完这本书之后,你会对市面上的那些”精益”理论,会有不一样的看法,也不至于盲从。 序 我们的初衷是找出一条适合于日本经济环境的独特的方式,但又不想让别家公司,特别是不想让先进国家轻易地了解它,甚至不让他们留下一个完整的概念,而一直推行和强调“看板方式”或“包括人的因素的自働化”。因此,人们难以理解它,也是很自然的。 第一章:丰田生产方式的诞生 我认为只要杜绝浪费,生产效率就有可能提高10倍。这种想法,正是现在丰田生产方式的出发点。 “彻底杜绝浪费”是丰田生产方式的基本思想,而贯穿其中的两大支柱就是: (1)准时化 (2)自働化 所谓“准时化”,就是在通过流水作业装配一辆汽车的过程中,所需要的零件在需要的时刻,以需要的数量,不多不少地送到生产线的旁边。 究竟怎样才能做到“准时化”? 我们进行了各种试验,最后总结出以下做法:以生产工序的最后一道总装配线为起点,开始给装配线提出生产计划;而装配线上用的零部件的运送方法,也从过去由前一道工序向后一道工序运送的方式,改为由后一道工序在需要的时刻到前一道工序去领取,而前一道工序只按后一道工序的数量生产。 “看板”方式则是顺利推行丰田方式的手段。 丰田生产方式的另一个支柱是“自働化”,但不是单纯的机械“自动化”,而是包括人的因素的“自働化”。 丰田公司的“包括人的因素的自动机器”就是指“带自动停止装置的机器”。 因为当机器正常运转的时候用不到人,人只是在机器发生异常情况、停止运转的时候去处理就可以了。 “自働化”的作用主是,杜绝生产现场中过量制造的无效劳动,防止生产不合格品。 第二章:丰田生产方式的精髓 “为什么会出现生产过量的浪费呢?”针对这个问题,会得出因为“没有控制过量生产机能”的答案,据此展开便生产“目视化管理”的设想,进而导出“看板”的构思。 彻底杜绝浪费,最重要的是充分掌握下述两点: 第一,提高效率只有同降低成本结合起来才有意义。为此,必须朝着以最少量的人员、只生产所需要数量的产品这一方向努力。 第二,关于效率,必须从每一个操作人员以及他们组织起来的生产线,进而以生产线为中心从整个工厂着眼,每个环节都要提高,才能收到效果。 以运用丰田生产方式为前提,需要彻底找出无效劳动和浪费现象: 1. 过量生产的无效劳动 2. 窝工的时间浪费 3. 搬运的无效劳动 4. 加工本身的无效劳动和浪费 5. 库存的浪费 6. 动作上的无效劳动 7. 制造次品的无效劳动和浪费 我是彻底的现场主义者。这是因为我从年轻时起就是在生产现场的不断磨炼中长大的。当了负责经营的管理者以后,就更不开企业的主要数据来源的生产现场了。 我们曾反复提及“准时化”和“自働化”是丰田生产方式的两大支柱,把这一体系的运作工具称为“看板”。现在,让我谈谈它的由来。 实际上,“看板方式”是从美国的自选超市得来的启示。 前面我们已经谈到,这是从自选超市中得到启发的。自选超市使用“看板”后会出现什么情况呢? 在计价器将顾客购买的许多商品计价以后,要把记载着销售出去的商品的各类和数量的卡片(相当于“看板”)送到采购部。这样采购部便可以迅速地补充商品。这种卡片,拿丰田生产方式来说,就相当于“取货看板”。自选超市陈列的商品,就相当于生产现场的工序贮备。 丰田生产方式通过“看板”便可以完全杜绝“过量生产”的现象,不需要超出需求量的库存。不需要仓库,也不需要仓库管理人员,而且,也不需要散发许多单据、传票之类的东西了。 “看板”是“准时化”的一种手段。也就是它是以实现“准时化”为目的的。“看板”是生产线的反射神经,生产现场的作业人员可以根据“看板”开始作业,并判断所需加班时间的长短。 “看板”也能使用管理者、监督者的职责明确化。 “看板”的使用规则第一条是“后一道工序要到前一道工序去领取产品”。 “看板”的第二条使用规则是“前一道工序只生产后一道工序所需要数量的零部件”。 实际上,如果不遵守这些规则而只引进“看板”,既发挥不了“看板”本来的作用,也不能降低成本。这种孤立使用“看板”的做法是有百害而无一利的。 企业越大越需要要具备很好的反射神经。对于计划的微小改动,要做到无需大脑发令也能采取相应的行动。就是说,如果生产管理部不发指令或者不发计划变更通知便不能改变作业,不能采取行动的话,企业就不能避免受创伤、遇大害,并且还会贻误大好时机。只有企业具备无意识适应变化的微调机能,才可以说真正装上了反射神经。我确信:通过“目视化管理”和“准时化”、“自働化”丰田生产方式这两大支柱,将会更好地锻炼这种反射神经。 第四章:丰田生产方式与福特生产方式 丰田生产方式同福特生产方式一样,基本形式是流水作业。索伦森在放置零部件的仓库上颇费一番苦心,而丰田生产方式却不需要仓库。 把同一品种和同一型号的零部件凑在一起,即把批量加大,不换冲模,尽量多次连续冲压进行大批量生产的作法,现在仍是生产现场的常识。福特生产方式大批量体系的关键就在这一点上。美国汽车企业一直证明,有计划地进行大批量生产对降低成本最有成效。 丰田生产方式与此相反,而是“尽量缩小批量,迅速变换模具”。 福特生产方式要加大批量来提高产量,所以,在各处都要有工序间的库存贮备。丰田生产方式则不同,其考虑方法是把这些库存可能导致的生产过剩的无效劳动和浪费,以及管理这些库存的人员、土地建筑的负担完全清除。 福特生产方式和丰田生产方式任何一方都有自身的优点,而且两者都在日日求新与改革,无法下结论说哪一个更优秀,但是我个人深信在低增长的时代,以丰田生产方式较为适合。 老翟评书 市面上有一本有名的书叫《看板方法》的书。说实话,这本书,我没看完。是我看不下去(你可以想象背后的原因),所以我不好评论。为什么要提《看板方法》这本书呢?因为我见过不少把《看板方法》里面的“看板”与丰田生产方式中的“看板”看作是一样东西,包括我自己。所以,我建议大家先看这本大野耐一的《丰田生产方式》,再看《看板方法》。大野耐一说了,他的看板是从美国自选超市得到的启示,是为了实现丰田生产方式的支柱之一:准时化。所以,我也希望大家能从《看板方法》里找出它说的“看板”的根源。 不知道有没有注意到作者在序中说的:但又不想让别家公司,特别是不想让先进国家轻易地了解它,甚至不让他们留下一个完整的概念。这点时刻提醒着我自己,有时我们看不懂别人的理论,并不是我们读者的问题。而是有可能作者有意,或者他自己根本不懂,所以无法表达清楚。 老翟书摘说明 书摘内容完全来自原书,如果原书的作者或出版商觉得我侵权了。请通过开源中国 @翟志军 联系我。 老翟书摘旨在通过一种书摘的方式让大家花最少的时间了解一本书,从而决定要不要继续读下去。书摘的每一本书都是本人亲自读过并理解的。

2015-12-29 · 1 min · 62 words · 翟志军 Jack Zhai

耦合的本质

耦合(coupling)的定义 耦合是对coupling的中文翻译。而coupling是couple的变形,指a connection (like a clamp or vise) between two things so they move together。我相信这就是coupling最朴实的定义。请允许我将其翻译成中文:存在一种连接在两事物之间,以至于这两事物相互影响。 在本文中,耦合可以是一个名词——耦合度的同义词,也可以作为形容词——耦合性的同义词。 软件行业中,耦合从何而来? 至于中文书籍什么时候将coupling翻译成耦合,已经不那么重要了。因为耦合不是从“翻译”而来的。从coupling的定义出发,我们看出不论在哪个层次,不存在绝对不耦合的软件。 软件与业务是需要耦合的,如果不耦合,软件就失去了意义。库存系统是需要和电子商务前端(销售)系统耦合的,否则前端就无法确定是否能供货给用户。如果我们的应用需要使用commons-lang库的StringUtils类,那么我们的应用就要commons-lang耦合的,否则我们没法使用StringUtils中的方法。在函数式编程中,我们的确可以将所有的逻辑(不论技术逻辑还是业务逻辑)封装在没有副作用的一个个函数中,但是我相信这些函数之间还是需要在某个时间点进行耦合。 进而我认为:耦合是“天生”的。 那是不是说我们就可以随意耦合了?显然不是,上述的耦合的例子只是表明耦合的存在性,并没有说明耦合的程度在软件开发过程所起的作用。 所以,和复杂性[1]一样,从根本上来说,我们可以掌握这种耦合,但不能消除这种耦合。 不同级别的耦合 软件是由不同级别的概念层组成,不同级别的概念层具有不同的职责,不同级别的概念层中存在不同的耦合:有方法级别、类级别、包级别、协议级别、语言级别、数据流级别、数据库级别、业务级别…… 方法级别:这不用多说了。 类级别:如果你了解“组合优于继承”原则,你就应该理解什么叫类级别的耦合。这里并不是说继承不好,而面对不同的问题,你需要权衡是“组合”还是“继承”与问题模型更匹配。 语言级别:我们的业务必须使用某各种语言来表达,无论是DSL还是通用编程语言Java、C#。 数据流级别:数据流是指一种我们处理问题的方式:输入数据,然后数据在一条充满处理环节的链上流动,直到完全最后一个处理环节输出处理结果。这很像我们的面向切面编程。 如果P_A要求输入的数据中的日期格式是: YYYY-MM。某天一个新手不小心把在P1中把日期格式改了,那么P_A就会出错。而现实中,我就遇到过一个数据处理流中有将近20多个处理环节,目前几乎没人敢动那块逻辑。另一个例子就是项目使用了Spring的切面编程,由于“切”得太多,到后来调试起来,我不得不遍历所有的切面的逻辑,以确定数据流到哪个环节出的错。 数据库级别:如果你的应用使用到了数据库Oracle特有的特性,那么你的应用就是和Oracle数据库耦合的。想像一下阿里去O的过程。也可以看下这篇文章:http://tech.it168.com/a2015/0417/1720/000001720950.shtml。ORM框架的好处在这方面尤为突出。 通信协议级别:如果通信的双方只依靠协议通信,而不关心实现这个协议的是Ruby程序还是Java程序。这也正是基于HTTP的 RESTFul风格的架构的关键所在。而业界提的微服务思路,其实就是期望各个应用之间只在协议级别耦合,从而与语言、操作系统解耦。通信协议级别上,我们也需要考虑解耦,比如,你的应用能否轻松从HTTP协议迁移到HTTPS。 操作系统级别:文件的路径的写法在各个系统下的不同,所以Java才会有: File.separator 这个常量,在Windows环境下返回\,而在*nix环境下返回/。如果不用此常量来拼文件路径,那么,那部分就是与操作系统耦合的。像: for Windows: C:\windows\system32\cmd.exe for Linux: /var/log/ansible.log 有些人觉得这不如挂齿,看看这条新闻:坚持用 XP 的代价:美国海军付给微软上千万。 PS:使用Ruby的某些gem时就要小心,因为某些gem用到了操作系统的库。 如Nokogiri (鋸) 业务级别:业务级别上的耦合度越高,软件的风险系数越高。假如A公司的领导在职时采用代码行数来KPI程序员,代码行数越多,KPI越好。如果在为这家公司设计HR系统时,你就必须考虑如果A公司换领导了或者原领导反省了,换采用360度评估进行KPI。你的系统能否以相当小的代价实现?又比如政府的某些老系统将一代身份证的身份证号作为自然人在数据库中的ID。可是某天,二代身份证出了,身份证号变成了18位了。那么如果自然人要求更新系统中的身份证号,你怎么办? 比较好玩的是,有时我们的程序有时会和系统用户耦合。 apache-commons-io 下的设置文件的可读/可写权限时,如果使用的是root用户执行此程序会有问题,因为root可对所有的文件可读。 File tmpFile = File.createTempFile(getClass().getSimpleName(), “localities.xml”); tmpFile.deleteOnExit(); tmpFile.setReadable(false); Assert.assertFalse(tmpFile.canRead()); // It would be failed 这个assert将会失败,因为不论该文件是否可读,以root用户执行此程序时,tmpFile始终是可读的。 ...

2015-12-29 · 1 min · 95 words · 翟志军 Jack Zhai