自动化重构 - jscodeshift

自动化重构(jscodeshift) 在这篇文章里我想要通过一些小例子来介绍使用jscodeshift来进行自动化重构的技术。具体来说,我想要介绍在一个组件库的开发和维护过程中,如何使用jscodeshift来自动修改公开的API接口,从而尽可能小的产生对组件用户的影响。 如果你们团队开发的组件被其消费者(组织内部或者外部)使用了,而这些代码又不在你的控制之内,那么这里讨论的技术和模式可能对你很有帮助。而如果你的日常工作更多的是使用组件库来开发应用程序,我希望这里的知识和技巧仍然对你有所启发,毕竟在软件系统中,我们往往都既是某些库的消费者,又同时是另外一些库的生产者。 从一个简单场景出发 设想这样一个场景,你发布了一个酷炫的组件库(fancylib),其中有一个按钮(Button)组件。这个Button的一个属性是当点击后处于加载中(loading)状态时现实一个表示加载中的小图标。 (图片来源:https://xd.adobe.com/ideas/process/ui-design/designing-interactive-buttons-states/) 在代码实现中,这个加载中状态被定义为了名为isInLoadingStatus公开prop。用户可以通过设置其值来控制Button的状态: import Button from '@fancylib/button'; const app = () => ( <Button isInLoadingStatus>Click me</Button> ) 一个实习生在某一天code review的时候提出了一个问题:在组件库中的其他地方,所有的boolean状态都是用一个单词来表示的,比如checked, disabled等。如果按照这个惯例,这里应该把isInLoadingStatus简化为loading。好主意! import Button from '@fancylib/button'; const app = () => ( <Button loading>Click me</Button> ) 假如所有用到Button的地方都在你的控制之内,字符串替换大约是一个快速且80%有效的方案。不过稍微分析一下,你就会发现简单的Shift+F6会遇到很多问题。 复杂情况 比如用户对其做了二次包装以适配更符合自己用户的使用习惯,这使得简单的全局字符串替换变成了不可能:: import Button as FancyButton from '@fancylib/button'; const MyEvenFancierButton = (props: FancyButtonProps) => ( const theme = { backgroundColor: "orangered", color: "white" }; <FancyButton {...props} theme={theme}>Click me</FancyButton> ); 除了这些问题之外,由于这是一个非常受欢迎的组件库,Button在很多(包括内部和外部的)产品中都有使用,你没有办法访问所有的用户代码,更没有办法让所有人都用手工的查找替换来做更新,你需要另寻出路。 你需要一个工具 – 一个可以读懂代码意图的工具 – 来帮助你做修改,而且整个过程最好可以自动化,比如通过执行一个脚本来完成。...

December 11, 2020 · 2 min · 邱俊涛 | Juntao Qiu

从创意到产品:ToBuy的故事

一个故事:从想法到产品 毫无疑问,新冠疫情在很多方面都深刻的影响了我们的生活。不论是出门必须戴口罩,在户外保持社交距离,还是外出回来要使用6步洗手法洗手,又或者由于远程办公而形成的物理隔离带来的心理上的负面影响等等,这些都深远的影响了我们的日常。 我今天要分享的一个故事正是与此相关:我是如何在维州宣布进入灾难状态的一个多月后,不得不全天几乎24小时呆在家里的情况下,从零开始进行一个iOS App开发并最终上线的故事。而这一切自然要从原始的需求分析开始说起。 原始需求分析 这个需求其实由来已久。在平时购物的时候,为了避免花费太多时间在超市,很多人都会随身携带一个购物清单,像下面这张图上列出来的那样: 大家平时买东西也可能有类似这样的纸质的购物清单吧。这种购物清单便于携带,随用随扔,非常方便。不过有几个小的缺点:一是买完这次之后,下次再去买的时候很可能卡片不知道丢到哪里去了;二是如果不配合笔一起使用的话,很可能要检查多次清单才能确定某样商品是否已经买过。此外,纸片上的信息毕竟有限,有时候你想要描述类似这样的需求:在永辉超市买甘竹牌豆豉鲮鱼,不要错买成鹰金钱,就会发现纸和笔可能不够用了。 我希望有一个手机App可以帮我管理这些清单。因为手机基本上是我出门必然会带的设备,手机本身可以作为纸笔Todo的替代品,而且有图片作为参考可以快速定位并找到我需要的商品。 另外一个典型的购物场景是:我每次购物往往会去多个超市,有的超市新鲜果蔬比较好,但是价格偏贵;而另一家则百货齐全,有时候水果不太新鲜;另外有一些商品比如豆腐乳,胡椒粉之类只能去亚洲超市才能买到。这时候我希望这个App可以提供分组,我可以在某家超市买完所有想要的商品之后,再换一家买剩余的。 灾难状态的封城在某些方面促进了这个想法的实现:首先被关在家里不能外出的我平白多了很多时间,用这段时间来学习一项新的技能显然是可行的;其次每次购物必须速战速决,尽量避免在人多的地方待太长时间而增加感染新冠的可能性;最后每个家庭每天只能有一个人出去购物,需要将清单尽可能细化然后实施(软件可以在某种程度上简化这个过程)。 当然,苹果自带的Notes或者Reminder都有类似的Todo管理,但是并不专门面向买菜。我设想的这个应用专门用来管理购物清单。在实施方面,我不打算从Hello world这样一步步从Swift的基本与反学起,而是先确定要做的App的主要功能,然后带着问题一边学习一边实践,最终把它演进成一个公开发布的工具。 实施 现在我终于到了我有一个价值千万的idea,就差一个程序员的阶段了。而巧的是,我就是个程序员。唯一的问题是,我的Swift和移动App开发经验约等于零(虽然多年前在项目间隔中参加过张帅的Android和黄磊的iOS workshop,但是时间隔得太久已经基本上还回去了)。此外,一个产品还有很多杂项,比如界面设计,图标,legal相关,App发布流程等等,这些对我来说完全都是未知数。 在实践中学习 通常来说,我比较喜欢通过循序渐进的方式来学习,从简单的例子开始,逐渐学习各个主题(如何设计界面,如何连接数据库,如何使用网络等等),这种方式的好处是基础会比较扎实,而且很多细节都可以得到充分练习。不过缺点是战线太长,往往需要耗时数月而没有实际产出。也因此如果过程中被一些其他事情耽搁,就很难再连续起来。 另一种方法是结果导向,然后用结果反过来驱动需要学习的内容。比如你想要开发一个本地的图片编辑App,那么肯定需要学习访问摄像头,访问本地文件系统等,而无需考虑网络和数据库。这种方式的优点是可以提供实时反馈,并且时刻有明确目标。 同样的,这种方法也有一些缺点: 会花费很多时间在Google和Stackoverflow上 很多资料都严重过时了,很多object-c的资料,以及很多swift老版本的资料 大部分人分享的内容,都比Hello world级别稍微复杂一点点,但是基本上不可能直接应用到你的应用中 因此在这个项目里,我尝试将两者结合起来。比如在第一个milestone里,我通过结果导向的方式,仅仅浮光掠影的学习必要的知识点,比如列表视图,iOS里的MVC,navigation之类。主要课程就是参考youtube上众多的入门教程:通过一个简单的例子,手把手的写一个Todo之类。这个过程可以熟悉编辑器,快捷键的使用,Swift的简单用法,界面设计器的使用等等。 这个阶段之后就可以开始“野蛮”编码了,开始的时候并没有特别的章法,就是照着例子写就好了。如果进行的顺利的话,很快就会有一个简单的原型出来,但是过程中会遇到海量的问题。小到如何添加图标,配置颜色,大到两个view之间如何通信,如何同步数据。不过作为一个有工程经验的程序员,大部分问题都可以通过Google+Stackoverflow解决。实在自己找不到答案的,还有很多热心的同事可以请教。 如果说我有一丁点成绩的话,无非是把别人用来思考变量名的时间花在了尝试Google关键字上了而已。 – 鲁迅 过了这一个阶段之后 - 有了一个可以工作的原型 - 就可以好好的打磨它了。于是我开始系统的学习udemy上的课程,比如如何使用使用protocol模式,如何使用MVVM,使用segue的正确方式等等。这时候可以适当的做一些重构和修一些简单的bug。 下图是从第一个原型到当前最新版本的用户界面的演进示意。从一开始的原生的TableView到定制的单元格,再到对数据按照超市信息分组并展现,每一次都比之前略复杂一些,而且每次的修改基本上都是基于客户的反馈来改进的。 此处的一个建议是:如果时间充裕,还是建议从基础学起,循序渐进,这样的方式可以确保基础比较牢固。而如果时间有限,又害怕被别的事情分心,那就可以边做边看,用到了再学,等建立起正向反馈之后再回过头来查漏补缺。 项目管理 在实施过程中我发现:一个可视化的,有迹可循的故事板非常有用。当然比这个故事板更加重要的是你需要制定一些规则并确保执行。比如,所有的卡片都应该从Backlog开始(即所有的需求都要经过仔细分析),开始前需要和stakeholder确认优先级,在开发过程中需要及时收集反馈,有明确的DoD(definition of done)等等。简而言之,尽量将其当成一个正式的项目来运作。 另外我还发现,之前在客户那里见到的诸多反敏捷的实践,我自己也往往会再犯一次。比如不及时更新卡的状态,临时插入Doing任务或者不限制在制品数量,不及时从stakeholder那里收集反馈,验收条件不明确等等。不过后来就好很多了,我尽量让其变得正式一些,而这个过程也确实可以帮助我更加聚焦在高优先级,更具价值的(而不是更fancy)的功能上。 这个大约是最简单,投入成本最小,又可以产生很好效果的实践之一了。特别是如果被一些临时任务中断之后(比如过了一个周末,或者项目上很忙晚上要学一些其他资料),一个故事板可以快速的帮你建立上下文并快速进入状态。 上线 经过了大约两周之后,我注册了Apple developer账号,并提交了第一个原型。第一个原型包含了三个列表(一个商品catalogue,一个待买列表,一个推迟列表)结果被无情reject了,原因是……功能太简单。仔细分析之后,我发现功能虽然不算单调,但是界面太过于原始,很多界面元素也需要调整。于是有花费了一周的时间来调整设计,比如字体的选择,字号,色彩对比等,以及实现了共享列表功能(可以将你的购物清单通过Airdrop或者微信等发给别人)。第二次提交之后,3个小时后就审核通过了。 V1的开发大约耗时3周时间,每天晚上学习并编码2-3个小时左右,周末会稍微多一些。随后V2也差不多2-3周,除了功能开发之外,还有些周边的定义,比如screenshots海报的设计和实现(详见下一小节)。不过我最近发现To Buy在iOS 14上有个bug(原因是iOS自身对NSFetchedResultsControllerDelegate的更新上有个同步的bug,如果你正好知道解决方法的话,请不吝赐教,非常感谢),所以如果你使用的以后发现什么异常的话,请反馈给我。此外,所有代码都在Github上,如果有感兴趣的同学也可以一起来完善(野生iOS程序员写的代码,请轻拍)。 To Buy应用 这个应用叫To Buy: grocery shopping list,目前已经在App Store上线了。这是我的第一个从界面设计,到编码实现,到架构及运维(虽然目前主要用户只是我和我老婆),以及图标和海报的设计,文案的编写等完全端到端的产品。虽然没什么用户,不过作为第一个App,我自己还是挺满意的。 特性列表 再经过了几个版本(当前版本V2.5.0)的迭代之后,现在的To Buy的主要功能就是:维护一个购物清单。用户可以: 通过拍照/相册里的照片,文字等来添加一个要买的商品 商品会按照超市分类,这样我就可以在A超市买所有果蔬,在B超市买日用等 可以把历史上买过的商品存到字典里,方便下次购买 可以将购物清单分享给另一个人(比如通过Airdrop) 可以把Apple自带的Photos/照片中的照片直接添加到To Buy中 所有数据会同步到iCloud,即跨设备可以完全同步 在迭代中,我发现了一个很有意思的现象:不论我当初如何笃定某个特性的设计,它的最终形态都会和开始的时候想法相去甚远。比如最早的想法是个内置一个大而全的商品字典,然后用户从这个字典里选择商品。但是最终发现这样的操作效率很低,特别是在手机上操作的时候。...

October 19, 2020 · 1 min · 邱俊涛 | Juntao Qiu

我的第一本英文技术书

2021年6月更新 不知不觉已经过去快一年了,我来更新下这篇的后续。 首先我想分享给大家的是:这本书的纸质版已经由APress出版社正式出版了! 从原来的博客发布至今的近一年中,这本书经历了很多次的编辑和重构。事实上,在这本书有了初稿之后,我就曾请求同事Martin Fowler帮我review并提供一些早期的反馈,不过他当时还在忙于《重构》第二版的审校工作,所以只是放入了他的backlog里,直到去年7月才review完成。Martin的批注非常仔细,从目录结构,到遣词造句,再到实例与主题的关联度,以及参考文献等等方面,差不多有近10页。我根据这些批注重新组织了书的结构,并删减了差不多1/4的内容,使得结构和内容更聚焦。此外,Hannah又在此基础上进行了英文的编辑和润色,以及对一些代码实例的建议。 去年圣诞前后,APress的编辑找到我,表示他们有讲此书出版为纸质书并在他们平台上发售的意向。在经历了数个月的编辑,审校,勘误之后,这本书终于出版为纸质版本。在上周末我收到了出版社寄来的几本样书。看到自己的名字印刷在封面上是一种奇妙的感觉,开心当然是有的,不过随之而来的又是一些隐约的担忧:担心书中技术终会过时,担心有不好的comments等等。不过该来的终觉会来,这大约也是出版的一部分吧。 另外,感谢那些鼓励我的、默默提供勘误的、报告bug的人们,没有你们的帮助,这本书不会最终成为可能。 我的第一本英文技术书 太长不读 我写了一本关于React+TDD的英文书,你可以从这里免费获得(更新:和APress出版社的合同中明确要求需要从其他渠道将其下线)。在我写这篇文章的时候,读者大约是1000+。虽然读者不算多,但是通过一些渠道收集到的反馈还算不错,已经超出我自己预期很多了。如果你读完觉得还不错,而且愿意帮我宣传一下我会非常感激,如果你想要做一些修订甚至翻译的话那就更棒了(有一个俄罗斯小伙在帮我翻译俄文版,不过他貌似拖稿十分严重)。 缘起 实话实说,写这本书纯属意外之举,最开始的时候对于内容和形式是完全没有计划的,更不用说用另外一门语言作为载体了。应该是在2017年年末的时候,我在华为的无线部门做一个网管产品的Web化,人员能力提升显然是Web化的核心了 – 毕竟功能需要开发人员一行行去实现。当时该部门中的大部分开发同事的Web技能都比较薄弱,一些有经验的同时则每日被业务需求缠身无法顾及能力构建,因此引入外部的培训来填补这个空缺。 这个看起来是Web开发101的培训还有一些其他需求,比如用户故事拆分、自动化测试和TDD等等敏捷开发的基本内容。我为团队设计了一些循序渐进的例子作为培训的素材,并在后来的几轮迭代中进行了内容的删减和补充。培训的结果还是不错,有一半以上的同事对Web开发产生了兴趣,有人则开始意识到自动化测试(以及TDD)可以减少回归测试的工作量。 正如你所料,这个培训的一个副产品就是这本书的原型了。在培训结束之后我正好有了几周的beach时间,我用这些时间将内容变成一个教程:从一个简单的例子,逐步完善成一个前端应用。其中涉及了诸如Tasking,ATDD,用户故事等。 过程 初稿 原型是很容易的,素材是现成的,只需要将其以符合逻辑的方式连接起来即可。比如我想要描述通过TDD的方式开发一个应用的全过程,那么首先我需要讲清楚我们要做一个什么应用,此外我需要说清楚如何用TDD来完成这个应用。根据经验,人们喜欢循序渐进的方式来阅读,先做一个简单需求,然后逐步增强,并在过程中将学到的内容应用,然后推广到后续需求的开发中,并通过实现更加复杂需求习得我想要传递的知识/技巧。 TDD的101(通过例子来说明Tasking和测试驱动的过程) 介绍demo应用,搭建应用所需的环境 设计并实现一个简单需求 实现一个更复杂的需求 循序渐进…… 编辑初稿的过程中,正好有个掘金小册的编辑联系我有没有意向写个小册子。虽然最后由于篇幅和主题的选择方向没有合作,但是和编辑沟通的过程帮助我很好的梳理了草稿的结构。 英文版 在草稿写完之后,我找到几个同事做了快速的review并做了一些修改。到了2018年3月,我开始准备来澳洲的LTA,既然英语会是我接下来几年的主要语言,那么提升英文能力就成了优先级很高的事情。而学习语言的窍门就是:没有什么比实际使用一门语言更能提升语言能力的了。 于是我开始尝试把草稿翻译成英文版。开始的时候我还会保持双语版本的同步,到后来带宽不足的时候就只能把精力放到英文版上了。第一个完整的英文版发布于2018年5月,后面虽然陆续有些小的修改,主体部分没有太大的变化。 到了澳洲之后,读了很多英文原版的书籍/文章之后,发现了书中很多的语言错误,又在一个假期里集中修改过一轮,可读性有了一些提高。 重构 到了2019年的9月,经过了近1年2个纯React的项目后,我对与React及其生态的理解,以及在应用TDD(特别是和传统上认为的TDD很难在复杂/时间不允许的项目上实施)的认识上都有了新的发展。于是又将其中很多章节重写了,比如丢弃了pupeeteer改成cypress,采用react-testing-library而不是enzyme等等。另外,结构上也做了重新整理。 由于这些颠覆性的修改,我将其重新命名为Mastering Test Driven Development with React,并声明其为前一个版本的第二版。 到了2020年4月,由于covid-19在澳洲的肆虐,我们开始全面WFH。一方面突然有了很多时间,另一方面我意识到线上沟通时英文在有些时候还是会变成blocker,于是我又花费了一些时间来提升英文。于是又开始了一轮的re-wording。 在你今天阅读这本书的时候,你大约会惊叹于英文表达之地道,语法之准确以及用词之精准。这些都和我的英文水平没有太大关系。在5月的一天,一位澳洲同事Hannah Bourke写邮件给我,表示她通读了这本书,非常喜欢其中的讲述方式和实例以及节奏,她表示愿意帮我近一步润色。她通过PR的方式重新整理了本书的语言(目前已经完成了70%),由于Hannah本身就是前端Dev,所以很多表达方式也被重写为更容易被读者理解的方式。 一些收获 关于英文写作 语言的学习是个漫长而痛苦的过程,同样的内容,要从一门语言中的表述要翻译成另一门语言需要的更多的是重写而不是literal translation。从LTA开始我就开始刻意的用英文写作,还尝试把一些文章翻译并投稿给英文版洞见。 通过这些练习,我觉得我至少不再惧怕这件事情本身。英文表达当然有不地道的地方,但是读者也不是语言学家,大多数时候他们都可以准确无误的get到你的意思。即使有些复杂概念无法一次理解,通过评注或者提问等等,总是会搞清楚的。 关于自信构建 在这本书的写作过程中,我个人最大的收获应该是:当你制定了一个目标,不论这个目标开始开起来有多么的不切实际,一旦你开始细化这个目标并逐步实施,你就已经离这个目标不远了。当然,和每个任务一样,事情走到最后可能会和最开始的目标并不完全契合,但这大约是我们无法掌控的那部分了,就随他去吧。

July 1, 2020 · 1 min · 邱俊涛 | Juntao Qiu

一个输入框你要做一周?

How long does it take for adding a InputBox? When the Product Owner told you it’s a small change, don’t trust her. An estimation session After iteration planing meeting, after all the stories had been walked through, PO turned to you, pretending it was just a impromptu chat, asking how long does it take for adding a input box to one page. What he described was a “simple” input box for user to enter his/her address along with other personal information and persist to backend....

June 17, 2019 · 11 min · 邱俊涛 | Juntao Qiu

节奏大师:BA

节奏大师:BA 良好运作的团队都是相似的,而问题团队则各有各的问题 如果你走进任何一个流畅运转的敏捷团队,你事实上会发现人们做的事情都很简单,端到端的交付能力,清晰的验收条件,明确的优先级,充足但是不会让人焦虑的backlog,甚至还有友善的、喜欢开玩笑的团队成员。他们会从简单的事情入手,逐步的加强其功能,在过程中还会伴随着重构,甚至部分重写的发生,不过人们有充分的信心,代码的质量也由于一直在维护的大量测试保证。 如果你问这个敏捷团队里任何一个人这样一个问题:“你觉得敏捷的核心理念是什么?”,你会惊讶于答案的种类之多。有人认为各种工程实践比如结对编程,TDD,持续集成等至为关键;另一些人则认为迭代会议,故事墙,尽量频繁的showcase是重中之重;还有人会更抽象的将敏捷的核心描述为拥抱变化,响应变更等。这些回答当然都没有错,每个人在实施过程中,都自然会形成自己对敏捷实践的理解和看法。而在我眼中,敏捷的核心可以归纳成四个字:“渐进增强”。 渐进增强 这里的“渐进增强”可以理解为:先让一部分需求高优先级,而且想清楚了的需求先做起来,在做的过程中让团队建立起自己的节奏和工作文化,最后带动其他需求也被按部就班的完成,最终实现共同富裕……。而这篇文章要讨论的正是:如何让渐进增强在团队里变为可能?特别是在很多项目的各种范围都是固定的前提下。 要让这样的渐进增强变为可能,你事实上需要预先付出一些额外努力的,比如: 需求拆分 正确使用INVEST原则 过程可视化 文化建设 这些额外的努力事实上都需要团队里的BA作为主力来驱动的。就像田忌赛马一样,不同的拆分方法和需求的释放方式可能带来截然相反的结果。不过在进入如何实现的细节之前,我们先来看看节奏在任何一个团队中的重要作用。 反馈,节奏与心流 1975年,心理学家米哈里·齐克森米哈里(Mihaly Csikszentmihalyi)正式将心流概念化并通过科学的方式来研究。 心流(英语:Flow),也有别名以化境(Zone)表示,亦有人翻译为神驰状态,定义是一种将个人精神力完全投注在某种活动上的感觉;心流产生时同时会有高度的兴奋及充实感。 我在《反馈拯救世界》中讨论过反馈机制和心流(Flow)之间的关系。它是一种奇妙而值得追求的境界,或者心理状态,也是知识工作者所一直追求的状态。在这样顺畅的状态下工作,不但个人会获得空前的满足感,而且团队从客观上来看,会更加的高效,成员会更加的团结,不论你将什么样的需求交给他们,他们总是会顺利的将其完成。 要进入理想的,忘我的心流状态,齐克森米哈里提到至少需要满足这三点: 有清晰的目标 有明确且事实的反馈 能力和挑战的平衡(都处于比较高的状态) 既然节奏的建立如此关键,而BA又是建立这种机制的关键,那么如何在实际中实施呢?我们从一个典型的场景来入手 需求拆分 在我看来,通过传统的工具比如INVEST(+SMART)对需求进行合理的拆分,就已经可以在很大程度上确保在团队正确的道路上行进了。当然,前提是你选对了正确的工具,并且完成了正确的拆分。这里面其实包含了两个问题: 怎样就算把INVEST做对了? 按照教科书般的INVEST划分之后不工作怎么办? 对于INVEST的正确使用,包括诸如用户故事多大比较合适,常见的拆分模式如工作流,业务规则变种等相关的文章,已经可以算是前人之述备矣,此处不再赘述。在这里我只关注第二个问题:即,在你已经可以熟练运用INVEST拆分比较复杂需求,并且在大部分场景下都可以采用合适的模式,但是这种拆分和开发团队的能力结构又不很契合的场景。 前后端分离 有时候你会发现,你从书上读来的敏捷实践在你的团队里不工作。比如需求要纵向的、端到端的划分。然而实际运作中,在实际进入开发阶段之前,很可能最终的视觉设计已经基本定稿,甚至一些典型页面已经向客户(如果是产品的话,此处替换为产品经理)汇报过了。而且很多时候客户只关注最后结果,过程中的半成品性质的汇报往往只是走过场,最终的验收客户往往会产生新的想法,但是为时已晚。 在这种范围相对固定的场景下,似乎用前后端分离的拆分方式似乎可以更快完成任务,也更合乎直觉,毕竟有专门的UI Dev可以很轻松的将高保真转换为HTML/CSS/JS。而那些关注性能,关注高并发/高可靠的后端开发者似乎也没有必要参与其中。事实上,我见过的很多项目正是这样运作的,而且看起来这种分法在工作内容相对固定的项目中也是可以工作的。 当然,这种划分存在一些无法回避的问题: 前端为了不被阻塞,会开发一套mock 后端需要一个机制来确保实现之后通知前端以保持一致 需要额外的测试来保证集成的正确性 集成会被延后 需求无法端到端交付(必须至少等到最晚的一端完全实现) 如果操作不当,很容易出现前端做完在等后端,或者后端等前端的现象。由于变更的不透明性,又很容易产生相互指责,内部消耗。即使我们有着精湛的工程技巧,比如通过mock后端,契约测试等手段可以使得过程不至于太痛苦,但是在开发过程中,由于迟迟不能集成并做实际演示对于客户和开发团队来说,都会显得难以放心。 端到端交付 另一方面,如果你考虑实施端到端的拆分和交付方式,完整的交付一个功能点。不过这种方式的一个重要的blocker是团队成员能力的不均衡分配(也可能是团队成员的兴趣所在),而且这一矛盾随着前后端的不断精细化变得更加明显。在端到端的划分中,我们往往需要开发同时具备前后端开发的能力,退一步讲也应该具有与前/后端同事结对完成特性的能力。 此外,这种划分方式则需要面对另外一些问题: 各有专长的前后端开发如何合作 单个用户故事交付时间可能过长 开发人员能力磨合/提升需要时间 乍看起来,这两种做法看似互相矛盾,无法调和。甚至在很多情况下,如果从客观的结果上来看,两种做法可能产生的物理结果是一样的:都按时的,按质量的完成了需求。不过,我觉得前后端分离的拆分方法中忽略了一个重要的点:开发体验。就我自己而言,我痛恨那种上不着天,下不着地的开发体验:你负责的永远是系统的中间一环,你有依赖的上游,也有依赖你的下游,每个功能都永远无法真正知道有没有人用,会不会给人们带来价值。因此在项目中,我尽量会尝试端到端的贯穿一个需求,最好可以从界面到数据库表。 我觉得即使在极端的场景下,也应该采用端到端拆分和交付的方式来工作。首先,团队不再以技术为分界线来看待用户故事,而是以功能(或者说业务价值)来划分。毕竟,不管是Fixbid还是人天的项目,客户都是以功能收费的嘛。一个功能可能在实施的时候需要不同的技术细节来支撑,但是功能本身应该被作为原子级别的需求,而不是物理上前后端的割裂。其次,如果从项目交付的另一个成果:人员的能力提升来看,端到端交付方式的问题就反而会变成优势。在一个项目结束之后,前端掌握了一些后端语言/工具的使用,甚至Cloud的维护;而后端则从前端了解到JavaScript中的测试框架,组件化等知识。 此外,你事实上只需要做很小的调整,就可以让团队获得很好的开发体验。即使项目范围在一开始就基本固定,即使关键页面的设计稿都已经经过汇报。仅仅做好符合INVEST原则的将需求拆分就可以很大程度上帮助团队形成高效的,顺畅而稳定的交付节奏。 INVEST原则 INVEST是渐进增强的基础,没有合适粒度、相互独立的用户故事划分,要进行迭代式的渐进增强就成了空中楼阁。事实上,这个基本功需要在很多层次去刻意练习。INVEST事实上在敏捷实践中影响深远:过小的划分会引入更高的管理成本,而过大的划分则可能导致优先级难以界定,而且很容易影响士气:没有人愿意看到在墙上挂一周的卡。 和现实世界中的很多事情一样,对于一名BA来说,划分出合理大小的用户故事需要很多方面的平衡,有时候简直是一门艺术。我们可以通过一个简单的例子来稍作解释 个人主页 比如,我们要实现Jigsaw的个人主页,页面有很多个部分组成:导航,提示信息,项目历史清单,用户Profile入口等等: 假设我们的第一个用户故事:显示提示信息Heading(如下图红框圈定部分所示)。 这个用户故事需要从后台读取数据,并展现在客户端。数据可以从后端数据库中读取,也可以从后台文件中读取,这个取决于后台数据存储的技术有没有选定。作为第一个用户故事,它可能还会关联一个技术卡:搭建前后端的基础代码,比如用create-react-app创建一个前端工程,用gradle创建一个后端工程之类。要不要独立成一个单独的卡可能取决于团队的能力结构。 作为一个有业务价值的用户故事,这个需求需要满足: 端到端实现(即,连通从页面到数据库) UI和Mockup基本一致 另一个好处是它要求开发者在做的过程中建立基本的反馈机制,比如TDD、结对编程/Code Review Session等细节,并体验Kick Off,Desk Check等实践在团队里是如何工作的等等。换句话说,就是尝试从一个简单、实际的需求入手,建立一个可以运作的反馈机制。一旦熟悉了如何做一个用户故事,那么进一步稍微复杂的用户故事(还记得吗?控制节奏)就会相对顺畅很多。毕竟一回生二回熟嘛。...

December 19, 2018 · 1 min · 邱俊涛 | Juntao Qiu