Closed EthanLin-TWer closed 6 years ago
写的太好了。
最近看《娱乐至死》,看奕含的绝笔,慢慢有一个价值观产生:形式本身与内容同等重要。它的一个推论是,要做正确的事情。此处应该 @macdao
大家可能以为,思想(真理、道理)是一个实在存在的东西,只是用什么方式来表达它的问题,但它是存在的。那些想法存在于你的脑里,不管你是用写博客、和人交谈、录制视频、发社交媒体,它都是不变的一个思想,传播途径只是一个媒介,思想与媒介无关。《娱乐至死》告诉大家,错了。用什么方式表达不仅重要,而且影响你要表达的内容本身。
书里花大篇幅对比电视时代与印刷术时代,不同媒介本身对传播内容带来的不同。印刷术时代我们以书本为主要的交流途径,书本的表达方式是注重逻辑、事实、精心准备。而电视时代,我们首先看讲者的颜值高不高,播音者的声音是否吸引人,电视节目不容许思考,一个节目如果嘉宾现场花上5分钟准备论据以反驳对手,一定没人看这样的节目。我们的时间如此重要,以至于每时每刻都在刷信息,刷朋友圈,刷微博,一个手指滑上去就是好几个人一天的生活,我们忙到没时间花5分钟,停下来,等一个人将他的想法组织成思路。图像时代不需要阐述,不需要逻辑,只需要图。色彩鲜艳的图、让人若有所思的图、恍然大悟的图。人们没有时间进行深入阅读,就产生种种方便法门,比如抓人眼球的标题、目录清晰一眼5秒就能看清的文章、重点都帮你加粗标出的中心思想。种种这些,都是一个信息媒介所选择、所隐喻。你怎么还能说内容本身是独立于媒介存在的呢?
用奕含的话来讲,一个体系精巧,写出许多好的作品,思想真的不能说是不 美 的,本来应该是思无邪的艺术家,本人却虐打妻子,强暴女性。你要说艺术跟人品分开谈论,还是这样的艺术本身就是赝品,是一种巧言令色?
上面,使用 markdown 加粗、使用空格隔开突出的「美」字,也是一种表达方式,也是一种隐喻。而我慢慢觉得,这种表达方式也是我所舒服的。
所以回到 TDD 这个问题上,美静那天说,反正我们在分支上开发的代码最后都要合成一个提交,你自己在分支上进行小步提交是否觉得累?为什么不节省一下,大步一点,再大步一点?反正最后都只会变成一个提交,只要那个提交信息是详细的就行了。我回答,首先我觉得「分支开发」「合并提交」就不是正确的事情,只是因为项目现状使然;其次「节省」本身不是毫无成本,这种表达方式本身的隐喻是,小步提交是多余的,部分敏捷实践是多余可裁剪的,它鼓励你大步一点更大步一点地提交。这个隐喻本身是危险的,是错误的,是开发者自己技能不够熟练、实践不够持续集成所致,而不是实践本身的问题。所以,如果你真的感觉敏捷实践(以及其他任何东西)是有益(亲身确认是真的有益)的、正确的,就应该坚持。所以说要做正确的事情,对似乎无害的俭省实践说不。
在历经一个只有一周时间的小程序项目之后,我也想趁此机会做一个总结:
是的,这个小项目完全没有测试,当然也就完全没有 TDD。
本想说「痛并快乐着」,但我依然觉得痛苦居多。
作为一个经验依然“弱鸡”的人来说,在没有完成项目之前,甚至不知道哪些是痛苦,哪些是可以改进的,哪些又是凭借运气得以顺利惊险度过,哪些又是靠着神队友快速fix快速调整。
只有回过头来回顾、思考,才得以发现哪些地方是自身原因、哪些是准备/积累不够充分、哪些是当下context不得已的最佳实践方式。是啊,在那样的情况下,最佳实践竟然成了一种不得已,不得已的方式竟然是最佳实践。也许吧,能解决问题的实践,才是最佳实践。
举个🌰,如果某天地震了,你说“不,我要换上最好的跑步装备,打开百度(先搭 VPN 再 Google)地图查下最佳逃跑路线”,再用最优雅、最快捷的方式跑出来。
“是的,有可能你确实最后跑得比别人快;但也有比较凄惨、夸张的情况就是,没有了跑步的机会。”
“其实最后生死,不还是靠天靠地靠运气,有可能你跑得快,刚好前面电线杆掉下来砸到你;有可能你跑得慢,房子却因为旁边的大楼挡住而没有倒下。”
其实还是分两个角度看:
1.
还有一个角度就是,软件开发毕竟是团队协作,必然有人快有人慢,关键在于「尽力而为」;只有为自己努力才会尽力而为,也只有尽力而为才不会奖励惩罚,利弊自规。
然后就是「周期性」,我依然觉得最有用的敏捷实践其实是「回顾」,且每个迭代所带出来的节奏性。而精益创业的核心逻辑是缩短 “Build-Measure-Learn” 的周期,不再以时间(2 weeks)维度为划分,更关注价值(yes or no)的节奏性。
从以往的 C/S 架构到 B/S 架构也好,从现在的 App 到小程序也好,商品/服务的内容或许并没有发生变化,但是触达用户提供价值的路径是真的缩短了,从而能够更快验证价值的可 valuable,价值的节奏性或许就在于「快速试验、快速失败」。
回到 TDD,上面总结下来可以对应到 4 个角度:
当然咯,以上其实都是很个人或者说是很产品的,而没有太多触及到「团队」,不追求技术卓越的人,不在乎 1.
;不考虑产品价值的人,必然也就不在乎 4.
;
这么说来,我觉得 Scrum 其实很适合三靠谱这样稳定求增长,只需要交付团队完成任务的情况,因为借助于manage(IPM 和 KPI)辅以(走流程化的 Retro)就足以让团队变得稳步前进,算是做到了 2.
和 3.
。而厉害的团队或者其实不需要那么注重 manage,只需要关键时刻 lead (预测未来方向、及时调整方向)即可。
上述 management 潜在的危机当然就是缺乏创新,三靠谱从 Scrum 切换成 SAFE 或者有这方面的考虑。(虽然我也不知道SAFE是什么,但是我觉得 EDGE 还是很有用的。)
其实有点儿类似于从 KPI 切换成 OKRs,之前一直不太理解 OKRs,但是听完一个音频明白了 OKRs 的应用场景也就有所顿悟,原来其核心也在于 Lead 的人有所不同,普通人还是 KPI 机制来得实在有用。改天我再来反思反思。
当然,讨论 TDD 这个事情简单的前提一定还是「个人的」。它和团队的 TDD 是两个不同向度的事情,团队推广略去不谈,但个人的 TDD 完全是可以自由随时练习打磨的技能。
「价值」这个大出发点我觉得你说得很好。我理解「价值」的普适意义比较强,并且不同的阶段可能呈现出不同的价值。比如你举的地震的例子(我懂国内产品交付的节奏),这个时候「先活下来」的价值显然已经盖过「活得好好的」这个事情。所以说,「价值」这个东西应该是指导一切的思想,而不是哪些具体了又再具体的实践;应该是视不同的阶段采用多种不同的工具(比如问人,比如砍需求,比如其他非技术的手段)来达到当前的价值点,而不是不管进度交付人员等制约我都说要把这些实践做到💯。
有了价值这个盖子再来看 TDD(及其他敏捷实践)以及效率工具的意义,我觉得是:
说到团队上的东西。最近有个感想,就是觉得「流程」这套东西体现出来的假设,就是保护弱者。对于一个(大的)组织来说,如果大多数人无法真正灵活运用敏捷实践来达到快速验证价值的目的,那么将这些灵活的实践具体化成为可衡量的实践和指标,无疑对组织来说是高效的,尽管牺牲了一些灵活性。当组织对创新、快速验证的需求并不强烈时,这样的模型也就越有效。换句话说,当你越不敏捷时,你就能在公司活得越好。它是个相互塑造的关系…
噢,突然想到「策略性 TDD」 这个东西。就是我现在还蛮享受的一个状态,开始觉得自己可以裁剪一些东西,比如 T 不了的代码,还是可以紧紧抓住快速验证反馈、小步验证这个点找其他的办法手动验证(反馈速度),比如重点 TDD 逻辑比较复杂的代码(业务价值高),比如 tasking 其实可以在想好大面的基础上做补充和细化…其实说白了就是 效率 = 价值 / 时间
,可以调的变量有很多,对高价值的代码做策略性的投入,其实觉得更有效率,工作更舒服。
一周的代码库用不用长期维护还另说呢…能撸出来就很赞了。
这些东西本来没有意义的。不过既然都记录了,就不带情绪地记录在这好了。上个项目带给我的成长是,用平和的心态面对阻力,同时加强个人能力修炼。不要在意微不足道的声音,进程的方向是对的。学习 TDD,一定就要看创始人的书、演讲,接下来的学习方向大概是:
我看到的现象是:
if-else
- 质量不好 - bug 增多 - 修 bug 变紧急 - 质量不好无法收敛 bug - 只能往上继续堆代码 - 越来越紧急if-else
- 质量不好 - bug 增多 - 修 bug 变紧急 - 质量不好无法收敛 bug - 只能往上继续堆代码 - 越来越紧急说白了都是人的问题和能力问题。
再来看看邮件组里,更有技术性一些的讨论:
还有一些非常有价值的长篇大论,分别讲了「后面再加测试的不可能性」(Later equals never)、「设计能力」、「一般编程方式与 TDD」一些方面。非常有价值。我觉得搬运的东西比我自己写的价值大多了,厉害的人好多。以下是不负责翻译版:
我觉得任何项目中,抱持着「我们以后再回去做某事」的想法,对项目来说一般都是风险,甚至危害。
我认为,这里面发生的了认知上的错觉。当我们在大脑里把工作推迟时,同时也把它所需的成本从方程中完全移除了。与其做一些当下肯定需要成本的事情,我们这样麻醉自己:这个事情放到后面做,应该就会简单一些,甚至到时就不需要任何开销了。
我们同时默认假设,到了以后,现状与外在环境会改变,因此面临的限制和压力相比当下也会减少。我们通常不知道这个以后是多久的以后。我们能知道的是,以后,我们就能专注在这些工作上,因此现在先推迟吧。
现实是,现状不会改变,外在环境也不会改变。当下有压力,到时也会有压力。你希望有一段时间,所有的交付压力都降低了,大家都能休息一下重构重构代码。这样的以后是不会发生的。并且,复杂度和成本会增加,而非降低。因为到了「以后」,上下文完全消失了,你必须重新回忆搜集,这是成本增加的来源之一。其次,推迟了的工作,会影响所有下游系统的实现,这同样增加了复杂度。想「撤销」这些已有的实现,同样增加了总的成本。
也即是说,推迟了的工作不太可能再被拾起;即便可能,那时再做的成本只是徒然增加了,而非你所想象的那样会减少。完成它更难了。
怎么样让别人意识到这个错误的认识假设呢?我发现,在后面的某个时间节点,带领大家做一些计划练习会有帮助。让大家试着自己去估算,推迟工作并在以后去完成的成本会有多少。引导大家去思考「重新搜集上下文」、「撤销已有实现」等工作的成本。估算完成以后,让团队自己估算,要重新捡起这些工作需要多少成本,需要什么环境才能办到。
我的经验是,做完这个练习的团队都会意识到,以后再做远比现在做的成本高得多,也因此,以后再做这个承诺实现的可能性比他们预想的要小得多。 - P.G.Moss
我从来无法理解,不写测试怎么可能快于写测试。比方说,我在写一个网页,为了验证我写的代码是否工作,难道我要启动整个 web 服务器、登录然后点很多下鼠标才能到我需要测试的页面去?
话虽如此,在我的经验中,要做好 TDD 是需要对软件设计有个基本认知的。我看到有些人写的测试简直疯狂,有给构造函数写测试的,有用反射来获取方法参数,以检验是否传入了正确的 lambda 函数的,诸如此类。
恕我冒昧地推荐一些资料: [GOOS 一书]() 以及(给我们所做的大部分的数据库操作)对 hexagonal 架构 的基本了解(最近 Alistair 本人有个专题视频),它们可能可以让你了解,为何远在90年代前人们就觉得,某种形式的 TDD 是必要的。是否测试先行,我觉得无所谓,我有时也会先写一些实现,再添加测试来覆盖。前提是,写测试前我就已经知道测试会长啥样了。背后真正重要的是,你需要小步前进。每当你写了一些产品代码,你总需要一个测试(或其他什么)来验证代码是否写对了。
PS. 邮件组里各位在讨论什么我其实没有全部读完,我看到的是,有人写了一些不好的代码,TDD 未能阻止他继续写不好的代码(或说促使他写得稍微好一些)。于是这老哥就说,TDD 根本没用,因为他觉得写(这样的坏)代码,不用测试根本快多了。 - J.Soeters
我表示十分理解,为什么人们不觉得 TDD 是一项可以让他们作为个人,工作更加高效的技术。
在我接触到真正把敏捷的这些工程实践(TDD、持续集成、结对编程,等等)做得很好的团队之前,我在其他的公司做了10年的软件开发。我是读了有关 XP(极限编程)的书,但实际工作中,我从未见过真正这样工作,或者知道怎样实践 极限编程 的人。
读 XP 的实践然后自己去摸索实践,是个非常痛苦的过程。通常实际的情况是,你当前工作的代码库有着混乱纠结的依赖,想写书本上介绍的那种简单纯净的测试,根本不可能。很多情况下,你自己连如何写简单的测试都不知道。不知道怎么用 mock,不知道怎么重构…确实,自己去探索,感觉反而更乱了,还不如马上把活干完。
倒腾到最后,就像对绝大多数的团队来说一样,你对这些实践也只是有所耳闻。你知道有这么个东西。它理论上听起来很棒。不过你觉得,在实际工作中,没几个人是这么做的。大多数人还是用他们所习惯的那种方式编程,并且日子如常,并没什么问题。 - K.Morris