写点什么

从玩扑克到软件开发

  • 2008-05-19
  • 本文字数:4653 字

    阅读完需:约 15 分钟

我以前不是做软件开发的。在加入 ThoughtWorks 两年之前,我主要靠玩扑克为生。当然,如果你曾跟我打听过我前臂上的纹身,那你肯定已然听过我的故事了。要是还没有,等下次我们一起喝一杯时,我可以讲给你听。

我从未因为花这么长时间玩牌而感到过遗憾,从中我学到了一些放之四海而皆准的知识。开发软件的时间愈久,我就愈加确信这二者之间具有令人难以置信的相似性。

学习

我学习打扑克和学习软件开发的方式是一样的:尽可能多读书。我用两年的时间,读完了所能找到的每一本有关扑克的书。最后竟至 39 本之多。编程亦如是。此刻,我面前仍然摆着接下来要读的 5 本书;而在过去三年 ThoughtWorks 的工作中,我翻烂的书亦不在少数。

我认为,无论编程还是玩牌,阅读书籍、博客与杂志都是要想有所成就的必备条件;而若要以二者为谋生之业,仅靠读书却是远远不够的。也许你可以把书本上的一切知识都装入脑中,但知道在何时应用何种规则,这才是真正高手的标志。

诚然,开卷有益。但总要走过万里路,方能对应用特定技术的具体环境烂熟于心。书本不可能把所有情况都囊括一空,只有通过亲身体会得来的经验,才能让你在某些状况下为自己或是雇主做出快速而正确的决策,而这些决策可能价值几千乃至数百万美元。

经验之宝贵,世间无物可代。

艺术的巅峰

你可以设计出击败普通扑克玩家的计算机程序。遵守一些基本规则,自然就可获胜。但迄今为止,还没有任何程序可以击败最好的扑克玩家。因为扑克技能达到巅峰时,也就成了一门艺术。软件开发亦如是。要想成为一个还行的开发者,只要遵循一系列最佳实践即可。如果按照经典参考指南一类的书籍行事,开发出还不错的应用程序应该不成问题,而且效果会胜过其他最常见的做法。有了这么多失败的项目作为前车之鉴,我相信,还不错的应用就足以令大多数管理层甘心掏腰包了。

当然,有些经理有更高的标准。在银行、创业公司、医疗系统等领域,标准则更为严苛。“还不错”自是远远不够。那些经理会很乐意为最佳选择买单,他们期待的是远超常人的技能。但问题在于,专家级程序员的技能与普通程序员不同。普通程序员知道做事的方式;专家知道做事的目的。普通程序员会僵化跟随模式书籍中的指示,就如遵守参考指南一般;专家则明白对模式的创新可能会带来指数级的性能改善。

他们看到的绝非同一个世界,所以普通程序员很难跟专家对面交流。做艺术评论家易,做优秀的艺术评论家难。

决策技能

在扑克和编程中有一条绝对真理:几乎没人能像他自我感觉的那么良好。有自知之明是不错的开始,但人们依然很难知道自己与专家之间的差距。程序员接触专家的机会并不多,也就无法公正评判自己的技能。在牌桌上,每个人都是为了锦标而来,可大多数人都会过高评价自己的牌技,这总是让我惊讶不已。

程序员之间亦是如此,而且大多数人可以获得的信息更少得可怜。一个从不参加任何大会的技术领导人,只能跟自己的团队成员一比高下。当然,他可能已经很优秀了,否则也不会成为技术领导。但如果与整个行业中最出类拔萃的人相比,他又处于什么位置?如果觉得在自己的圈子里已经一览众山小了,那碰到不同意见时,他又会作何反应?有些人会视之为学习的契机并为此感到兴奋,但绝大多数都会对不同意见嗤之以鼻。

团队协作

乍看上去,扑克是一种彼此对抗的游戏。但事实很少如是。即使在赌注最小的牌桌上,通常也至少会有几个人常打交道。他们不会达成条件一致对付牌桌上的其他人——他们也不必如此。大家都明白一条道理:你不是要去跟牌玩得好的人对着干,赢他们的钱,而是要从水平低的人身上赚钱。专业牌手甚至会像一个团队一样协同工作。有些人彼此利益相关,故而一人得利则众人均有收益。他们不仅互相了解,而且认识很多人。如果出现一局精彩牌局,楼层经理会跟他们打招呼;侍者会为他们的对手调制酒精度高的饮品;和手(即发牌者)会故意“犯错”以影响某人心情(很少有人在心情不好的时候能够打好牌)。每个人都在协同工作,确保大家都能挣到钱。

颇为有趣的是,程序员的情况也与之相似。很多人都坐在格子里,完全依赖自己解决问题。他们往往工作在代码个人独有制模式之下。我曾亲眼目睹,在这种程序员交付的应用中,集成问题一直都是大家的心病。而更为不幸的是,集成之痛还只是最小的问题。假设 IT 部门把业务需求锁定为 500 页的需求文档。如果公司决定改变业务方向,随之而来的系统变更需求将令人痛不欲生。数以百万计的金钱付诸东流,因为程序员开发的特性已不再具备业务价值,而 IT 部门还没有找到更好的方式来应对业务变化。

当然,情况并非总是如此。专家懂得协作。他们会跟其他专家协作,但也不排斥与经理、客户、业务部门、分析师、质保人员,以及所有可以为成功贡献力量的人协作。他们胸怀大局:只有协作,才能让每个人有所收获。

度量

雄心勃勃的牌手常常讨论他们赢了多少手牌,又输了多少手。他们讨论最多的还是本该赢但却输掉的那几手牌。有时人们会犯错误输钱,但他们一般都不会记得这几手是怎么输掉的。相反的是,如果有些牌局只是因为手气不好而输掉,他们就会记得那一局中的每一处细节,他们还会在故事中透露对手必然获胜的几率,来证明自己根本没有胜出的机会。真正的牌手知道他们输掉过多少手牌,以及失败的大概几率。他们懂得度量。而且专业牌手会专注于重要的度量标准。你赢了多少手,输了多少手,这无关紧要;重要的是你赢了多少钱,输了多少钱。而且,为你的狗屎运(译者注:bad beat,即开局时输家比赢家牌好,赢的几率更大,但关键时刻赢家却来了更好的牌。碰到狗屎运——take a bad beat——用来形容输家,来了狗屎运——lay a bad beat——用来形容赢家)苦恼实际上等于替你对手的牌运犯愁。既然你的收入来自于对手的错误,那你就是在抱怨为什么对手把钱给了你。

有度量标准是好事,不过专业人士懂得哪些标准重要,哪些只会分散注意力,哪些介于二者之间。

软件开发也有很多度量标准,而且有很多标准身上的光环已经远远超出了它们所应有的范围。例如,知道代码行数几乎不能带来任何价值。复杂应用需要相当多的代码,但这个“相当”到底是多少?它得依赖于语言、工具及其他因素。

修复的 bug 数量也是个很有趣的话题,只是略逊于前一个。为什么人们会在乎修复了多少个 bug?Bug 数量也许有其价值,但是修复的 bug 数目并不能为我们带来多少有用信息。

特性完成率是我自己最喜欢把玩的一个标准。除非我们使用特性来评估工作量,否则知道完成了多少特性又有何用?而且,如果已经对工作量做出了评估,那为什么不把剩余工作与已完成工作相比较,从而得到工作进度呢?我很难从特性完成率中看到价值所在。

代码覆盖率让我想起了记录狗屎运。这项度量是有意义的,但很多人都没抓住重点。代码覆盖率低意味着可能有问题存在,但是代码覆盖率高只能表示你有一个很大的代码覆盖率数值。高代码覆盖率与高质量之间没有必然联系。

注意人,而不是逻辑

如果看过有玩牌镜头出现的电影,你大概听过这样一句话:你不是在与扑克玩,而是与人玩。此言极是。牌手无疑都是心理学家。有时你确实需要某些牌,但拿一手好牌只是赚钱的一部分而已。一旦有了好牌,你就需要知道怎样利用好它们。你是应该加注,还是先让牌然后加注,还是彻底让牌,还是跟进?这些做法依赖于很多因素,但关键还是要了解牌桌上的对手。当你得到一手好牌,首要目标就是尽可能多地从对手那里赢钱,而达到这种目的的唯一方式则是想办法让对手给你更多的钱。了解逻辑可以帮助你赢得几手牌,了解人则可以帮助你赢钱。

在交付软件时,人处于同样重要的地位。如果软件只是让一切工作起来,那只要把它变成自动化的工作,事情就容易得多了。但软件却远非功能组合这么简单。在一场高尔夫球比赛中,人们会卖出软件包;在全家到迪斯尼免费旅游时,人们会签下软件服务合同;为了避免法律纠纷,人们会履行合同去构建已经毫无用处的软件;为了超越竞争对手,人们会使用软件来加快业务响应速度。

人们使用软件、开发软件、维护软件,或是在某种程度上依赖软件。软件开发与这个世界有着千丝万缕的联系,要把洋洋洒洒的变量组合成简单方程,生产出高质量的软件,又与登天何异?但是,软件开发高手需要考虑每个人引入的所有已知与未知的变量,做出他们力所能及的推测。知道应该做什么会让你受益,而知道必须做什么所带来的价值却是难以衡量。了解逻辑可以帮助你交付应用,了解人则可以帮助你交付价值。

在残缺的信息下工作

有关这点,刚开始打牌的人处理的非常好:打好每一手牌,老老实实押注,从不虚张声势。这便是了,新手就应该只做该做的事情,除非你的钱多得没地方花了。难点在于如何从初学者的水平提升。大量信息霎那间纷至沓来,你需要注意牌桌上每个人的每一处细节:他们怎样交流,你从前跟他们每个人打过什么交道,他们所钟爱的玩牌方式,谁在赢,谁在输,凡此种种不一而足。而且,你也不可能知道对手手里的牌是什么,下一张牌又是什么。你所拥有的信息已超出所能处理的极限,而且这远非全部。

编程亦如是。领域专家无所不知,但把一切都向你倾囊相授却毫无意义。何况,你也不一定需要所有的领域知识。你需要熟悉团队,但同事总有些事情是你永远无法知晓,或者不能完全理解的。不过,编程高手能够把必要的领域知识融会贯通,掌握团队的动态,并始终提供技术上的真知灼见。他们知道他们永远无法成为百晓生,他们知道什么事情值得思考,哪些应该置之不理。纵使面前汹涌澎湃的信息仍是残缺不全,他们也总能做出正确的决定。

即时反馈

普通牌手在反馈信息少的游戏中表现最好。因为牌手是根据信息而赢钱的。在 5 张牌梭哈中只有一轮押注的机会。各位玩家只有一次机会来分析你给出的信息,而你也只有一次机会犯错。专家级牌手更喜欢多轮的游戏。游戏中的回合数越多,他们就有越多机会从低水平的对手身上捞到好处。他们喜欢即时反馈,并根据反馈做出调整。在有多个回合的游戏中,每一个回合都可以得到反馈,专业玩家就会根据当前局势调整打法。

编程高手同样喜欢即时反馈。从业务人员即时反馈回来的信息,可以避免你在构建业务应用时走上弯路。从另一个程序员即时反馈回来的信息,可以在软件产品化之前发现 bug。持续集成服务器可以提供即时的集成反馈,从而避免集成之痛。喜欢敏捷的人能马上说出迭代是一个有着显著成效的实践,因为它可以让程序员和业务人员得到即时反馈。不过,作为一个编程高手,纵使他不喜欢敏捷,他也能够意识到即时反馈的价值;即使在非敏捷的环境中,他也会争取得到更多的反馈,从而避免浪费时间精力。即时反馈可以让你了解前行的方向正确与否,每一个专家都会珍视这些信息。

上下文为王

无论扑克还是编程,没有绝对正确或是绝对错误的选择。如果你有一对 K,那么在翻牌之前你该不跟么?也许吧。这要看你是在打比赛还是赌钱、有上限还是没上限、你坐在哪个位置上、你是否已经不跟过一次还是已经封顶了等等。我在扑克中学到了一点,那就是在给出答案之前,一定要综合考虑所有的因素。

在编程中沉浸的时间愈久,同样的体会在我心里就愈加深刻。Java 在有些时候是不错的选择,但它并非万能。所有的编程语言均如此。工具亦然。Hibernate 很不错,但它不适用的地方还有 IBatis,当 IBatis 也不适用的地方还会出现或自己创造新的解决方案。几乎没有一款解决方案能够绝对有效,它只有在恰当的形势下才会发挥应有的作用。在错误的环境中,它也许会成为毒药。

所以,面对一门新的语言或者工具,无论是你是打算弃若敝履,或是爱不释手推而广之,不妨先想想它的适用环境,尽量做到对症下药,量体裁衣。

查看英文原文 Software Development Lessons Learned from Poker

2008-05-19 00:571814
用户头像

发布了 197 篇内容, 共 54.4 次阅读, 收获喜欢 20 次。

关注

评论

发布
暂无评论
发现更多内容

音视频:播放器与H.265播放探索

程序员架构进阶

视频流 播放器 H.265 10月月更

架构营模块一作业

GTiger

架构实战营

Java 面试八股文之数据库篇(三)

Dobbykim

数字货币合约交易系统开发内容(源码)

数字货币合约交易APP系统开发介绍(案例)

永续合约软件系统开发源码搭建

Vue进阶(幺肆叁):如何用绝对定位(position:absolute)完美定位布局及其注意事项

No Silver Bullet

Vue 绝对定位 10月月更

永续合约APP系统开发简介(搭建)

ARouter 在多 module 项目中实战

逆锋起笔

android arouter 路由框架 阿里arouter

模块一的命题作业

月影之臣

架构实战营

对自己深度学习方向的论文有idea,可是工程实践能力跟不上,实验搞不定怎么办?

Giant

自然语言处理 机器学习 深度学习 算法 论文

pygame 二次 hello world 项目感知

梦想橡皮擦

10月月更

数字货币期权交易软件系统开发内容(源码搭建)

👊 【Spring技术特性】采用protostuff和kryo高性能序列化框架实现RestTemplate的序列化组件

洛神灬殇

spring 序列化协议 序列化机制 10月月更

百度商业托管页系统高可用建设方法和实践

百度Geek说

架构 高可用

第一周作业

沐风

代码质量管理:SonarQube + Jenkins Pipeline配置

看山

DevOps 10月月更

期货合约系统APP开发简介(搭建)

Prometheus 查询操作符(四) 示例合集

耳东@Erdong

Prometheus 10月月更

Go 中如何写注释

baiyutang

golang 10月月更

理解 std::declval 和 decltype

hedzr

算法 元编程 C++11 c++17 纯虚函数

【Flutter 专题】23 图解自定义 Dialog 对话框

阿策小和尚

Flutter 小菜 0 基础学习 Flutter Android 小菜鸟 10月月更

持续测试、持续集成、持续交付、持续部署和DevOps

FunTester

持续集成 持续交付 持续测试 FunTester 持续构建

Shopee ClickHouse 冷热数据分离存储架构与实践

Shopee技术团队

数据库 后端 Clickhouse 存储 S3

区块链的监管架构基本成型

CECBC

docker 系列:实践工具

yuexin_tech

技术分析| WebRTC开源服务器商业化过程中遇到的问题及挑战

anyRTC开发者

开源 音视频 WebRTC 服务器 实时通信

ZooKeeper分布式配置——看这篇就够了

牧小农

zookeeper 分布式配置

【LeetCode】加一Java题解

Albert

算法 LeetCode 10月月更

官方线索|#1024小鹏汽车科技日#如约而至!关于未来出行,你有什么想象?

搬砖人

1024我在现场

从零到熟悉,带你掌握Python len() 函数的使用

华为云开发者联盟

Python 数据结构 函数 内置函数 len()

从玩扑克到软件开发_研发效能_Jay Fields_InfoQ精选文章