交付用户想要的软件
让客户做决定
在设计方面, 做决定的时候好必须有开发者参与. 可是, 在一个项目中, 它们不应该做所有决定, 特别是业务方面的决定.
Decide what you shouldn't decide.
开发者 (及项目经理) 能做的一个最重要的决定就是: 判断哪些是自己决定不来的, 应该让企业主做决定. 你不需要自己给业务上的关键问题做决定. 毕竟那不是你的事情. 如果遇到了一个问题, 会影响到系统的行为或者如何使用系统, 把这个问题告诉业务负责人. 如果项目领导或经理试图全权负责这些问题, 要委婉地劝说他们, 这些问题最好还是和真正的业务负责人或客户商议.
当你和客户讨论问题的时候, 准备好几种可选择的方案. 不是从技术的角度, 而是从业务的角度, 介绍每种方案的优缺点, 以及潜在的成本和利益. 和他们讨论每个选择对时间和预算的影响, 以及如何权衡. 无论他们做出了什么决定, 他们必须接受它, 所以最好让他们了解一切之后再做这些决定. 如果时候他们又想要其他的东西, 可以公正地就成本和时间重新谈判.
毕竟, 这是他们的决定.
具体技巧
记录客户做出的决定, 并注明原因. 好记性不如烂笔头, 但你选择的记录方法不能太笨重或太繁琐.
不要用过于具体和没有价值的问题打扰繁忙的业务人员. 如果问题对他们的业务没有影响, 就应该是没有价值的.
不要随意假设具体的问题不会影响他们的业务. 如果能影响他们的业务, 就是有价值的问题.
如果业务负责任回答 "我不知道", 这也是一个称心如意的答案. 也许是他们还没有想到那么远, 也许是他们只有看到运行的实物才能评估出结果. 尽你所能为他们提供建议, 实现代码的时候也要考虑可能出现的变化.
让设计指导而不是操纵开发
"设计" 是软件开发过程不可缺少的步骤. 它帮助你理解系统的细节, 理解不见和子系统之间的关系, 并且指导你的实现.
一些成熟的方法论很强调设计, 他们希望在开始编码之前, 先有完整的设计和文档. 另一方面, 敏捷方法建议你早在开发初期就开始编码. 是否那就意味着没有设计呢? 不, 绝对不是, 好的设计仍然十分重要. 画关键工作图是必不可少的, 因为要使用类及其交互关系来描述系统是如何组织的. 在做设计的时候, 你需要画时间去思考各种不同选择的缺陷和益处, 以及如何做权衡.
然后, 下一步才考虑是否需要开始编码. 如果你在前期没有考虑清楚这些问题, 就草草地开始编码, 很可能会被很多意料之外的问题搞晕. 但是, 即使之前已经提交了设计文档, 也还会有一些意料之外的情况出现, 时刻谨记, 此阶段提出的设计知识基于你目前对需求的理解而已. 一旦开始了编码, 一切都会改变. 设计及其代码实现会不停地发展和变化.
Design should be only as detailed as needed to implement.
严格的需求 - 设计 - 代码 - 测试开发流程源于理想化的瀑布式开发方法, 它导致在前面进行了过度的设计. 这样在项目的生命周期中, 更新和维护这些详细的设计文档变成了主要工作, 需要时间和资源方面的巨大投资, 却只有很少的回报.
如果你自己都不清楚所谈论的东西, 就根本不可能精确地描述它.
设计可以分成两层: 战略和战术. 前期的设计属于战略, 通常只有在没有深入理解需求的时候需要这样的设计. 更确切地说, 它应该只描述总体战略, 不应深入到程序方法, 参数, 字段和对象交互精确顺序的具体细节. 那应该留到战术设计阶段, 它应该在项目开发的时候再具体展开. 这时更适合讨论如何设计类的职责. 因为这仍然是一个高层次, 面向目标的设计. 事实上, CRC(类 - 职责 - 协作)卡片的设计方法就是用来做这个事情的.
如何知道一个设计上好的设计, 或者正合适? 代码很自然地为设计的好坏提供了最好的反馈. 如果需求有了小的变化, 它仍然容易去实现, 那么它就是好的设计. 而如果小的需求变化就带来了一大批基础代码的破坏, 那么设计就需要改进.
具体技巧
"不要再前期做大量的设计" 并不是说不要设计, 只是说在没有经过真正的代码验证之前, 不要陷入太多的设计任务. 当对设计一无所知的时候, 投入编码也是一件危险的事. 如果深入编码只是为了学习或创造原型, 只要你随后能把这些代码扔掉, 那也是一个不错的办法.
即使初始的设计到后面不再管用, 你仍需设计: 设计行为说无价的."计划说没有价值的, 但计划的过程说必不可少的." 在设计过程中学习说有价值的, 但设计本身也许没有太大的用处.
白板, 草图, 便利贴都是非常好的设计工具. 复杂的建模工具只会让你分散精力, 而不是启发你的工作.
合理地使用技术
Blindly picking a framework is the having kids to save taxes.
在考虑引入新技术或框架之前, 先要把你需要解决的问题找出来. 你的表述方式不同, 会让结果有很大差异. 找到了需要解决的问题, 接下来就要考虑:
这个技术框架真能解决这个问题吗? 要确保它能解决你的问题, 并没有任何的毒副作用. 如果需要, 先做一个小的原型.
你将会被它拴住吗? 有些技术缺乏可取消性, 当条件能发生变化时, 这可能对项目有致命打击. 我们要考虑它时开放技术还是专利技术, 如果是开发的技术, 那又开放到什么程度?
维护成本是多少? 会不会随着时间的推移, 它的维护成本会非常昂贵? 毕竟, 方案的花费不应该高于要解决的问题, 否则就是一次失败的投资.
具体技巧
也许在项目中真正评估技术方案还为时太早. 那就好. 如果你在做系统原型并要演示给客户看, 也许一个简单的散列表就可以代替数据库了. 如果你还没有足够的经验, 不要急于决定用什么技术.
每一门技术都会有优点和缺点, 无论它是开源的还是商业产品, 框架, 工具或者语言, 一定要清楚它的利弊.
不要开发那些你容易下载到的东西. 虽然有时需要从最基础开发所有你需要的东西, 但那时相当危险和昂贵的.
提早集成, 频繁集成
在产品的开发过程中, 集成是一个主要的风险区域. 让你的子系统不停地增长, 不去做系统集成, 就等于一步一步把自己置于越来越大的风险中, 潜在的分歧会继续增加. 相反, 尽可能早地集成也更容易发现风险, 这样风险及相关的代价就会相当低. 而等的时间越长, 你也就会越痛苦.
你能集成并且独立
集成和独立不是相互矛盾的, 你可以一边进行集成, 一边进行独立开发.
使用 mock 对象来隔离对象之间的依赖关系, 这样在集成之前就可以先做测试. 用一个 mock 对象模拟真实的对象(或者子系统).mock 对象就是真实对象的替身, 它并不提供真实对象的功能, 但是它更容易控制, 能够模仿需要的行为, 使测试更加简单.
你可以使用 mock 对象, 编写独立的单元测试, 而不需要立刻就集成和测试其他系统, 只有当你自信它能工作的时候, 才开始集成.
当早期就进行集成的时候, 你会看到子系统之间的交互和影响, 你就可以估算它们之间通信和共享的信息数据. 相反, 如果你推迟集成的时间, 解决这些问题就会变得很难, 需要大量和大范围地修改代码, 会造成项目延期和一片混乱.
具体技巧
成功的集成就意味着所有的单元测试不停地通过.
通常每天要和团队成员一起集成代码好几次, 比如平均每天 5~10 次, 甚至更多. 但不要过于频繁了.
如果你集成的问题很大, 那一定是集成得不够频繁.
对那些原型和实验代码, 也许你想要独立开发, 而不要想在集成上浪费时间. 但是不能独立开发太长时间. 一旦你有了经验, 就要快速地开始集成.
保持可以发布
Checked-in code is always ready for action.
在团队里工作, 修改一些东西的时候必须很谨慎. 你要时刻经济, 没错改动都会影响系统的状态和整个团队的工作效率. 下面是一个简单的工作流程, 可以防止你提交破坏系统的代码:
在本地运行测试. 先保证你完成的代码可以编译, 并且能通过所有的单元测试. 接着确保系统中的其他测试都可以通过.
检出最新的代码. 从版本控制系统中更新代码到最新的版本, 再变异和运行测试. 这样往往会发现让你吃惊的事情: 其他人提交的代码和你的代码发生了冲突.
提交代码.
最好的办法是你有一个持续集成系统, 可以自动集成并报告集成结果. 持续集成系统就是在后台不停地检出, 构建和测试代码的应用. 你可以自己使用脚本快速实现这样的方式, 但如果你选择已有的免费, 开源的解决方案, 它们会提供更多的功能且更加稳定.
具体技巧
有时候, 做一些大的改动后, 你无法花费太多的时间和精力去保证系统一直可以发布. 如果总共需要一个月的时间才能保证它一周之内可以发布, 那就算了. 但这只应该是例外, 不能养成习惯.
如果你不得不让系统常去不可以发布, 那就做一个 (代码和架构的) 分支版本, 你可以继续进行自己的实验, 如果不行, 还可以撤销, 从头再来. 千万不能让系统既不可以发布又不可以撤销.
提早实现自动化部署
系统能在你的机器上运行, 或者能在开发者和测试人员对机器上运行, 当然很好. 但是它同时也需要能够部署在用户的机器上, 如果系统能运行在开发服务器上, 那很好, 但是它同时也要运行在生产环境中.
QA should test deployment.
这就意味着, 你要能用一种可重复和可靠的方式, 在目标机器上部署你的应用. 如果现在你还是手工帮助质量保证人员安装应用, 花一些时间, 考虑如何将安装过程自动化. 这样只要用户需要, 你就可以随时为它们安装系统. 要提早实现它, 这样让质量保证团队既可以测试应用, 又可以测试安装过程.
有了自动化部署系统后, 在项目开发的整个过程中, 会更容易适应互相依赖的变化. 很可能你在安装系统的时候, 会忘记添加需要的库或组建 -- 在任意一台机器上运行自动化安装程序, 你很快就会知道什么丢失了.
从第一天起就开始交付
一开始就进行全面部署, 而不是等到项目的后期, 这会有很多好处. 事实上, 有些项目在正式开发之前, 就设置好了所有的安装环境.
在我们公司, 要求大家为预期客户实现一个简单的功能演示 -- 验证一个概念的可行性. 即使项目还没有正式开始, 我们就有了单元测试, 持续集成和基于窗口的安装程序. 这样, 我们就可以更容易更简单地给用户交互这个演示系统.
在签约之前, 就能提供出如此强大的演示, 这无疑证明了我们非常专业, 具有强大的开发能力.
具体技巧
一般产品在安装的时候, 都需要有相应的软硬件环境. 这些环境的不同很可能导致很多技术支持的电话. 所以检查这些依赖关系, 也是安装过程的一部分.
在没有询问并征得用户的同意之前, 安装程序绝对不能删除用户的数据
部署一个紧急修复的 Bug 应该很简单, 特别是在生产服务器的环境中. 你不想在压力之下, 凌晨三点半还在手工部署系统.
用户应该可以安全并且完整地卸载安装程序, 特别是在质量保证人员的机器环境中.
如果维护安装脚本变得很困难, 那很可能是一个早起警告, 预示着很高的维护成本.
如果你打算把持续部署系统和产品 CD 或者 DVD 刻录机连接到一起, 你就可以自动地为每个构建制作出一个完整且有标签的光盘. 任何人想要最新的构建, 只要从架子上拿最上面的一张光盘安装即可.
使用演示获得频繁反馈
Requirements are as fluid as ink.
没有人的思想和观点可以及时冻结, 特别是项目的客户. 就算算他们已经告诉你想要的东西了, 他们的期望和想法还是在不停地进化 -- 特别是当他们在使用新系统的部分功能时, 他们才开始意识到它的影响和可能发生的问题. 这就是人的本性.
此处省略了数值分析中偏微分方程的例子......
应该定期地, 每隔一段时间, 例如一个迭代, 就与客户会晤, 并且演示已经完成的功能特性. 如果你能与客户频繁协商, 根据他们的反馈开发, 每个人都可以从中受益. 客户会清楚你的工作进度. 反过来, 他们也会提炼需求, 然后趁热反馈到你的团队中. 这样, 他们就会基于自己进化到期望和理解为你导航, 你编写的程序也就越来越接近他们的真实需求. 客户也会基于可用的预算和时间, 根据你们真实的工作进度, 排列任务的优先级.
维护项目术语表(Wiki 规格)
不一致的术语是导致需求误解的一个主要原因. 企业喜欢用看似普通浅显的词语来表达非常具体, 深刻的意义.
团队中的程序员们使用了和用户或者业务人员不同的术语, 最后因为 "阻抗失调" 导致 Bug 和设计错误. 这样的事情经常发生.
为了避免这类问题, 需维护一份项目术语表. 人们应该可以公开访问它, 一般是在企业内部网或者 Wiki 上.
在项目开发过程中, 从术语表中为程序结构 -- 类, 方法, 模型, 变量等选择合适的名字, 并且要检查和确保这些定义一直符合用户的期望.
跟踪问题(工作项)
随着项目的进展, 你会得到很多反馈 -- 修正, 建议, 变更要求, 功能增强, Bug 修复等. 要注意的信息很多, 随机的邮件和潦草的告示帖上无法应付的. 所以, 要有一个跟踪系统记录所有这些日志.
具体技巧
当你第一次试图用这种方法和客户一起工作的时候, 也许他们被这么多的发布吓到了. 所以, 要让他们知道, 这些都是内部的发布(演示), 时为了他们自己的利益, 不需要发布给全面的最终用户.
一些客户, 也许会觉得没有时间应付每天, 每周甚至时每两周的回忆. 毕竟, 他们还有自己的全职工作. 所以要尊重客户的时间. 如果客户只可以接受一个月一次会议, 那么就定一个月.
一些客户的联络人的全职工作就是参加演示会议. 他们巴不得每隔一小时就有一次演示和反馈. 你会发现这么频繁的回忆很难应付, 而且还要开发代码让他们看. 缩减次数, 只有在你做完一些东西可以给他们演示的时候, 大家才碰面.
演示时用来让客户反馈的, 有助于驾驭项目的方向. 如果缺少功能或者稳定性的时候, 不应该拿来演示, 那只能让人生气. 可以及早说明期望的功能: 让客户知道, 他们看到的是一个正在开发中的应用, 而不是一个最终已经完成的产品.
使用短迭代, 增量发布
统一过程和敏捷方法都使用迭代和增量开发. 使用增量开发, 可一次开发应用功能的几个小组. 每一轮的开发都是基于前一次的功能, 增加为产品增值的新功能. 这时你就可以发布或者演示产品.
迭代开发式是, 你在小且重复的周期里完成各种开发任务: 分析, 设计, 实现, 测试和获得反馈, 所以叫做迭代.
Show me a detailed long-term plan and I will show you a project that's doomed.
对付大项目最理想的办法就是小步前进, 这也是敏捷方法的核心. 大步跳跃大大的增加了风险, 小步前进才可以帮助你很好地把握平衡.
大部分用户都希望现在就有一个够用的软件, 而不是在一年之后, 得到一个超级的好软件, 确定使产品可用的核心功能, 然后把它们放在生产环境中, 越早找到用户的手里越好.
询问用户哪些是产品可用且必不可少的核心功能, 不要为所有可能需要的华丽功能而分心, 不要沉迷于你的想象而去做那些华而不实的用户界面. 有一堆的理由, 值得你尽快把软件交到用户手中: 只要交到用户手里, 你就有了收入, 这样就有更好的理由, 继续为产品投资了. 从用户那里得到的反馈会让我们进一步理解什么是用户真正想要的, 以及下一步该实现哪些功能. 也许你会发现一些过去认为重要的功能, 现在已经不再重要了.
使用短迭代和增量开发可以让开发者更加专注于自己的工作, 如果别人告诉你有一年的时间来完成系统, 你会觉得时间很长, 如果目标很遥远, 又很难让自己去专注于他. 在这个快节奏的社会, 我们都希望更快地得到结果, 希望更快的见到有形的东西. 这不一定是坏事. 相反, 他会使一件好事, 只要把它转换成生产率和正面的反馈.
具体技巧
关于迭代时间长短一直是一个非常有争议的问题, 没有规定说迭代必须要紧挨着下一个迭代.
如果每个迭代的时间都不够用, 要么上任务太大, 要么是迭代的时间太短, 把握好自己的节奏.
如果发布的功能背离了用户的需要, 多半是因为迭代的周期太长了. 用户的需要, 技术和我们对需求的理解都会随着时间的推移而变化, 在项目发布的时候, 需要清楚地反映出这些变化. 如果你发现自己工作时还带有过时的观点和陈腐的想法, 那么很可能你等待太长时间做调整了.
增量的发布必须是可用的, 并且能为用户提供价值, 你怎么知道用户会觉得有价值呢? 这当然要去问用户.
固定的价格就意味着背叛承诺
A fixed price guarantees a broken promise.
固定价格的合同会是敏捷团队的一大难题, 我们一直在讨论如何用持续, 迭代和增量的方式工作. 但是现在却有些人跑过来, 想提早知道他会花费多少时间及多少成本. 软件项目, 天生就是变化无常的, 不可重复. 如果要提前给出一个固定的价格, 就几乎肯定不能遵守开发上的承诺.
根据自己的处境, 选择不同的战略.
主动提议先构建系统最初的, 小的和有用的部分, 挑选一系列小的功能, 这样完成第一次交付差不多六到八周. 向客户解释, 这时候还不是要完成所有的功能, 而是要足够一次交付, 并能让用户真正使用.
第一个迭代结束时, 客户有两个选择: 可以选择一系列新的功能, 继续进入下一个迭代; 或者可以取消合同, 仅需支付第一个迭代的几周费用. 他们要么把现在的成果扔掉要么找其他的团队来完成它.
如果他们选择继续前进, 那么这时候, 应该就能很好地预测下一个迭代工作. 在下一次迭代结束的时候, 用户仍然有同样的选择机会: 要么现在停止, 要么继续下一个迭代.
对客户来说, 这种方式的好处是项目不可能会死亡. 他们可以很早的看到工作的进度或者不足之处. 他们总是可以控制项目, 可以随时停止项目, 不需要缴纳任何违约金. 他们可以控制先完成哪些功能, 并能精确的知道需要花费多少资金. 总而言之客户会承担更低的风险.
具体技巧
如果你对答案不满意, 那么看看你是否可以改变问题.
如果你是在一个基于计划的非敏捷环境中中工作, 那么要么考虑一个基于计划且非敏捷的开发方法, 要么换一个不同的环境.
如果你在完成第一个迭代开发之前, 拒绝做任何评估, 也许你会失去这个合同, 让位于那些提供了评估的人, 无论他们做了多么不切实际的承诺.
敏捷不是意味着开始编码, 我们最终会知道何时可以完成, 你仍然需要根据当前的知识和猜想, 做一个大致的评估, 解释如何才能到达这个目标, 并给出误差范围.
如果你现在别无选择, 你不得不提供一个固定的价格, 那么你需要学到真正好的评估技巧.
也许你会考虑在合同中确定每个迭代的固定价格, 但迭代的数量是可以商量的, 它可以根据当前的工作状况进行调整.
来源: http://www.bubuko.com/infodetail-3162502.html