设为首页收藏本站

LUPA开源社区

 找回密码
 注册
文章 帖子 博客
LUPA开源社区 首页 业界资讯 技术文摘 查看内容

跟极限编程创始人Kent Beck学编程

2012-9-28 14:47| 发布者: 红黑魂| 查看: 4387| 评论: 0|来自: CSDN

摘要: 我、Stig、Krzysztof、Jakub和Kent Beck在2012年的Iterate Code Camp花了一个星期时间一起做了个项目,进行最佳实践性的编程学习。我们想和大家分享一下我们在这个过程中学习到的宝贵经验及教训,以使我们能成为更好 ...

我、Stig、Krzysztof、Jakub和Kent Beck在2012年的Iterate Code Camp花了一个星期时间一起做了个项目,进行最佳实践性的编程学习。我们想和大家分享一下我们在这个过程中学习到的宝贵经验及教训,以使我们能成为更好的程序员(或者至少我们是这样认为的)。

编程风格背后的价值观

在整个实践过程中,我们渐渐学会了遵守编程最基本的三个价值观:沟通、简单和灵活(按照重要性进行排序),这三个价值观应该被所有开发人员所铭记。在下面我们将会对它们进行简单介绍,另外你也可以在Kent的《实现模式》(Implementation Patterns)一书中找到更详细的说明以及一些基本的实践。

沟通

程序的可读性往往高于程序如何去写,任何一个程序员都能写出机器读得懂的代码,而一个优秀的程序员应该写出别人可以理解的代码。代码作为传达设计理念的工具,在编写的时候应该清楚地表达出设计思想。(就拿典型的企业系统来说,在5——15年内代码都会被大量修改,而每次去执行修改的人肯定不会是同一个人,因此代码要更加通俗易懂,这样修改起来才轻松。

简单

消除不必要的复杂性,各级应用都应该以简单为原则。简单可以使程序更容易理解和更利于沟通;通过沟通更容易实现简单。

灵活

现在做出一个可行的决定,并保留可以将来修改它的灵活度,这是好的软件开发的关键。——Kent Beck的《Implementation Patterns》

程序应该灵活地修改,使一些常见的修改变得简单,至少要比现在简单。复杂性通常来自于过度的灵活性,但是如果没有灵活性,那么它就如同垃圾。最好的一种灵活性就是来自简单广泛的测试。试图通过设计phases之类行为来增加灵活度,最终得到的通常是“复杂的灵活”。大多数时候,对于程序哪些地方需要被修改,在没有足够信息的前提下很难做出正确的决定。所以适当地推迟决定,直到最后判断正确后再做出一个有效和有用的决策

概括

编写简单、通俗易懂的代码,会让你的工作伙伴或者未来的系统维护人员花很少的精力就可以轻易代码。(当然,这也需要一定的技能等级和专业知识。)你无法预见需求变化,所以保持代码简单、灵活,使其演变可以跟上需求的变化和时间的推移。

学习要点1 你并不需要它

今天将演示什么?测试开始时做什么?

在开始之前,我们设立了一个非常有趣和富有挑战的主题。我们决定尽最大的努力尝试一个高伸缩性的、分布式数据库。我们花了几个小时讨论如何实现,毕竟这里有许多事情需要考虑:同步策略、哈希一致、集群成员自动发现、冲突解决方案等等。如果只有5天时间,你需要计划如何用最简单的方式实现。需要做什么?如何跳过?对吗?错,Kent只是问我们在最后一天将演示什么和如何测试。

这最终会被证明是个非常聪明的做法,因为我们实际上可实现的功能只有一个小小的子集,对迄今遇到的问题进行总结,然后再进一步做出更加理智的决策。我们发现,任何超过10分钟以上的讨论90%的时间都被浪费啦!但这并不意味那个计划就是失败的(虽然产生的计划一般都是无用的),它只是意味着我们要做的会比实际需要多。

因此,我们宁愿选择不断接受反馈和经验来完善前期计划。问问自己:在下次我将要展示什么?写什么样的反馈能够反映自己,指导我今后的开发工作。

学习要点2 编写高级测试来指导开发

我们第二天的目标是通过编写一个实例进行同步和演示,忘掉第一个实例然后直接从第二个实例中解读(复制)数据。我们仅仅跟随着这些步骤编写相应的测试

  1. List<Graft> grafts = Graft.getTwoGrafts();  
  2. Graft first = grafts.get(0);  
  3. Graft second = grafts.get(1);  
  4. first.createNode().put("key", "value")  
  5. first.kill();  
  6. assertNotNull(second.getNodeByProperty("key", "value")); 

(当然,这个API之后会变得普通)

现在有意思的是,这并不是个单元测试,它是个基本的集成测试,少用点技术术语就是一个故事驱动的高层次功能测试,是客户比较喜欢的功能。如果是一个单元测试,那么它会告诉你,这个类和预期打算的一样,而如果是一个故事测试,那么结果会是:“此功能和预期的一样”。

我一直认为TDD只适合单元/类级别的测试,这样的观点被证明是错误的,TDD还适合更高级别的测试。它包含了一些非常有意思的属性:

  1. 衡量项目进度,给“客户”的练习都是非常有意义的,因此每次得到的反馈信息也更真实可靠。
  2. 这可以帮助你专注于提供业务功能
  3. 它很有可能保持不变并且比单元测试或大多数代码存在的更长久,因为它是一个概念层次的东西。

现在,根据测试金字塔来看,故事测试用例明显要比单元测试要少,而且故事测试用例并不会测试所有可能性。难道这意味着需要在测完所有的故事测试用例后,再在小规模的单元测试中重复一遍?答案是否定的,那是完全没有意义的。回到灵活性原则和改变方式上,只有当你需要的时候才会构建额外的单元测试,例如在这几种情况下:第一个故事测试没有完全捕捉正确、发现一个非常重要的特殊案例、你想专注于整个解决方案里面的一部分。猜测故障点跟猜测设计一样,完全是在浪费时间。

学习要点3 单元测试的最佳实践

通常,会为了验证某个想法而开始一段测试,但我们并没有十足的把握能确保成功。因此,提供一个最佳实践来指导或帮助你实现最终结果。首先,提出一个要求,然后在集中精力去考虑如何实现。这就是我们在Graft项目中进行同步策略测试的最佳实践方法。

在测试里面写实现方法

确定功能后再开始编写测试用例,而不是提前思考如何组织(创建哪些类?在哪里进行整合?是否使用一个工厂类或工厂方法),为什么不直接在测试方法里面写代码?上面提到的那些因素可以以后分析。这样你就可以一心一意地撰写功能测试报告。此外,通过推迟内部组织实施,你将会有更多的时间去思考和决定,最后你会得到一个非常好的解决方案。

关键原则:重点、避免过早决策

自底向下的设计

避免:

  • 过早过多假设
  • 思维固定在某个特定的、不成熟的设计中
  • 限制思维(通常会以第一个计划来结束设计)

从小到大,先从一小部分的功能开始实现,然后再一步步整合形成一个复杂的模块。不要因为各个模块间的依赖关系而感到心烦意乱,在真正实现整合和替代之前先给它们进行简单地备份。使用这种技术就无需在最初的时候与设计方案相绑定。在这个过程中,不仅需要经验还需根据点直觉,连同TDD会有更好的设计和实现方案展现出来。

在没有形成最终解决方案的时候,我们发现这个方法非常有用。在开发Graft时,我们并没有预先设计好整个应用程序。在第一天我们只是挑选了一个用户案例去实现,然后在接下的日子里,我们也是在挑选案例然后进行实现。


酷毙

雷人

鲜花

鸡蛋
1

漂亮

刚表态过的朋友 (1 人)

  • 快毕业了,没工作经验,
    找份工作好难啊?
    赶紧去人才芯片公司磨练吧!!

最新评论

关于LUPA|人才芯片工程|人才招聘|LUPA认证|LUPA教育|LUPA开源社区 ( 浙B2-20090187 浙公网安备 33010602006705号   

返回顶部