肯特纳交易系统

我们三个人,即Stig,Krzysztof和Jakub,很高兴在2012年Iterate Code Camp中与Kent Beck一起度过了一周的时间,共同致力于一个项目并学习编程最佳实践。 我们想分享我们学到的宝贵经验,使我们成为更好的程序员(或者至少我们想思考)。

编程风格背后的价值观

我们学到的大多数东西都来自三个基本价值:沟通,简单和灵活性(按重要性顺序)。 我们将在这里简要介绍它们,您可以在Kent的《 实现模式》一书中找到更详细的描述,以及一些基本的实践,例如对称性的应用。

通讯

程序的阅读次数比编写的次数多,因此应清楚地传达其意图。 代码主要是交流手段。 (对于典型的企业系统,许多程序员将在5到15年的时间内修改很多代码,他们都需要理解它。)

简单

消除过多的复杂性。 在所有级别应用简单性。 简单性使程序更易于理解,从而有助于沟通。 通过使沟通更容易看出什么是多余的复杂性,通信可以简化工作。

灵活性

“今天做出可行的决策,并保持将来改变想法的灵活性,这是进行良好软件开发的关键。” —实施模式,肯特·贝克

程序应该以灵活的方式进行更改,应该使通用更改变得容易或至少容易。 复杂性通常可能源于过度的灵活性,但是如果不需要这种灵活性,那将是浪费。 最好的灵活性来自于简单性和广泛的测试。 在设计阶段或类似阶段尝试创建灵活性通常会以这种“复杂灵活性”告终。 大多数情况下,您没有足够的信息来就程序需要更改的位置做出正确的设计决策,因此将决策推迟到最后一个负责任时刻的精打细算是一种有效的方法。 那是您做出任何决定的最佳理由。

摘要

编写能很好地传达执行方式和执行原因的代码,以便您的同事和未来的维护人员可以接管它,而无需花费太多成本。 (然而,您必须在听众中假设一定水平的技能和知识。)您无法预见未来,因此请保持代码简单且足够灵活,以便代码可以不断发展。

重点学习 1.您将不需要它!

今天的演示是什么? 首先要进行什么测试?

在我们到达之前,我们定了一个我们认为很有趣和具有挑战性的话题。 我们决定尝试构建高度可扩展的分布式数据库的原型。 我们希望到达时花一些时间讨论如何实际实施此方法。 毕竟,有很多事情需要考虑:复制策略,一致的哈希,群集成员自动发现和冲突解决等。 如果只有5天,则需要计划如何以最简单的方式实施它。 该怎么办。 跳过什么。 对? 错误。 肯特没有做任何计划,只是问我们最后要展示的演示是什么。 他的下一个问题是要写什么测试。

事实证明这是一种非常明智的方法,因为我们实际上仅实现了可能功能的一小部分,并根据迄今为止的问题经验每天决定下一步要做什么。 从一开始的任何讨论超过10分钟,将浪费90%的时间。 这并不意味着计划是不好的(尽管所产生的计划通常是无用的 ),仅意味着我们通常会做比实际需要更多的工作。 要获得真实的反馈并将我们的决定基于真实数据,比任何猜测都更加实用和有价值。

因此,相对于大量的前期计划,更喜欢根据反馈和经验进行的计划。 问问自己:在下一个演示/会议/一天我要演讲什么? 要写什么测试来反映这一点,从而指导我的开发工作?

2.编写高级测试以指导开发

我们第二天的目标是复制,方法是通过写入一个实例,杀死它并从第二个实例读取(复制的)数据来演示。 我们从编写相应的测试开始,该测试几乎按照字面意义紧随以下步骤:

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

(当然,API后来演变为更通用的东西。)

现在有趣的是,这不是单元测试。 它本质上是一个集成测试,或者用一个不太专业的术语,是一个具有相当高级功能的故事测试。 客户感兴趣的功能。 单元测试告诉我“ 该类按预期工作”,而故事测试告诉我“该功能按预期工作”。

我曾经在单元/类级别上考虑过TDD,但这是更高级别上的TDD。 它具有一些有趣的属性:

  • 它有助于衡量项目的实际进度,因为它会执行一些实际上对客户有意义的事情(如果您允许我以某种模糊的方式使用此“客户”)
  • 它可以帮助您专注于交付业务功能(在其级别上)
  • 它可能保持大多数不变,并且比单元测试或实际上大多数代码库的生存期更长,因为它处于这样的概念级别

现在,根据测试金字塔 ,故事测试当然少于单元测试,并且故事测试不会测试所有可能的情况。 这是否意味着您需要进行所有这些故事测试,然后仅在较小的单元测试中再次进行? 不,那不是重点。 回到灵活性和事物变化的原理,仅在需要时才创建其他单元测试。 例如,当您遇到第一个故事测试实际上没有正确“捕获整个案例”的情况时,或者当您发现一个非常重要的极端情况时,或者当您想专注于实现整体解决方案的一部分时。 推测故障点可能与推测设计一样浪费。

3. [单元]测试的最佳实践,从头开始 编写测试

通常,我们会根据要验证的内容来开始测试,但是我们可能不确定如何到达那里。 因此,优良作法是首先表达我们所知道的结果,所需的最终结果。 我们以断言的形式执行此操作,然后才将重点转移到确定如何实现目标上。 这就是我们开始在Graft中进行复制测试的方式,如上所示。

这是重点关注原则的应用。

在测试中编写实现,稍后进行重构

您知道所需的功能,因此可以开始为其编写测试。 为何不考虑如何组织代码(要创建什么类,将它们放在何处,使用工厂类还是工厂方法),为什么不首先在测试方法中直接编写代码? 您以后总是可以将代码分解出来。 通过这种方式,您可以专注于真正重要的事情–通过测试描述所需的功能–而不必因次要因素而分心。 此外,通过推迟有关实施的内部组织的决定,您将在实际决定时获得更多知识,并且最终可能会得到更好的解决方案。

关键原则:专注,避免过早决策。

自下而上的设计

避免:

  • 假设太多,为时过早
  • 将自己锁定在特定的设计和过早的设计中
  • 限制自己(通常会得到您最初打算的设计)

从实现功能的一小部分开始。 然后将它们结合起来以形成更复杂的行为。 不要为依赖而分散注意力,为它们编写简单的存根,稍后将用实际的实现替换它们。 使用这种技术,您不必像“自上而下”方法那样一开始就设计决策。 它需要一些直觉和一些经验,但与TDD结合使用,有助于做出更好的设计和实现。

我们发现这项技术非常有用,因为我们一开始并不知道最终的解决方案。 在开发Graft时,我们没有预先设计整个应用程序。 我们在第一天就选择了一个用例,并加以实施,然后每天选择并实施其他用例。

在相同的抽象级别上行动和断言

我们的Graft DB具有类似于telnet的界面,用于接收来自用户的命令。 考虑一下addComment测试的以下两个(简化)变体:

// Test 1
Graft db = ...; this.subject = new CommandProcessor(db);
subject.process("addComment eventId my_comment");assertThat(subject.process("getComments eventId")).isEqualTo("my_comment");
// Test 2 (same setUp)
subject.process("addComment eventId my_comment");assertThat(db.getComments("eventId")).containsOnly("my_comment");

第一个测试在测试addComment命令时,使用另一个命令getComments来检查结果状态。 在整个测试过程中,它仅使用一个API入口点( 主题) 。 第二个测试直接访问基础数据库实例及其API以获取相同的数据,即除主题之外,它还使用基础db

因此,第一个测试不是真正的“单元”测试,因为它取决于被测类的另一种方法的正确性。 由于第二个测试直接访问目标数据结构并因此直接在源头执行检查,因此它的重点更加突出,并且编写起来可能更简单。

我们认为,像第一个这样的测试会更好,它可以在同一级别(即被测对象的公共API级别)执行所有操作。 这里的“更好”意味着更容易理解,更重要的是,更加稳定和可维护,因为它们没有与被测功能的内部实现耦合。 这些单元集成测试增加的复杂性(由于在每个测试中都依赖多种方法)所带来的代价是绝对值得的。

与第二种测试类似的测试仍然很常见,它们要么直接访问底层(对象,属性,数据库等),要么使用模拟来获得直接验证副作用的可能性。 这些技术通常会导致耦合测试且难以维护,因此应仅限于“私有单元测试”,如“ 从不混合公共和私有单元测试 ”中所描述和论证!

4.专注!

  • 将弹出的任务放在“稍后”列表中,而不是立即执行
  • 首先专注于测试的修复–但是难看又简单(然后重构)
  • 关注当前需求–无需过早抽象

肯特真正引起我们注意的一件事是他随时关注自己的工作。 专心致志意味着专注于完成您当前正在做的一件事,而不会被其他问题分散注意力,无论这些问题多么重要或容易解决。 (附带说明:永不说永不。)测试失败时,无论(临时)解决方案多么丑陋或“偷工减料”,都应专注于使其Swift通过。 如果您在一路上注意到需要做的其他事情-给方法一个更好的名字,删除无效的代码,修复不相关的错误-不要这样做,将其放在任务列表中,然后再做。 否则,您可能会失去注意力和当前环境。 一次做一件事。 在进行测试通过时,请仅关注此点,并留出诸如良好代码之类的问题,直到后续的重构(应该很快进行)。 (这让我想起了用于大型重构的Mikado方法 ,其主要目的还在于保持焦点并且不会在很多旁白中迷失方向。)

一种相关的做法是在实现功能时将重点放在当前需求上,而不必为未来的需求(可能实际上是明天)进行投机性设计。 专注于当前所需的内容,以完成当前任务,并使解决方案变得简单,从而可以轻松地重构和扩展已知和不可预见的未来需求。 正如肯特(Kent)在实现模式(以及其他模式)中所说的那样,我们在投机设计上非常不擅长,即未来的需求通常与我们期望的完全不同,因此最好创建简单且灵活的解决方案。 您当然需要对未来的需求有所注意,但远远少于我们的预期。 承认自己无法预测未来。 即使您知道还需要什么,您又怎么知道没有新的要求会改变或延迟(直到无限期)?

我们学习了 并行设计的 一些其他知识

并行设计意味着在更改设计时,您将尽可能保留旧设计,同时逐渐添加新设计,然后逐渐切换到新设计。 这既适用于大规模,也适用于(令人惊讶地)小规模。 虽然这很昂贵,但您必须弄清楚如何同时运行它们,并且需要更多的精力才能使它们同时运行,但它通常会有所回报,因为它更安全并且可以恢复可重构,如下所述。

高级并行设计的一个示例是用NoSQL数据库替换RDBMS。 您将首先实现用于写入新数据库的代码,然后使用它并同时写入旧数据库和新数据库,然后还开始读取新数据库(也许将结果与旧代码进行比较)以验证其正确性),同时仍使用旧数据库的数据。 接下来,您实际上将开始使用NoSQL DB的数据,同时仍然要写入/读取旧的DB(以便您可以轻松地切换回去)。 只有当新数据库证明自己时,您才逐渐删除旧数据库。

微观并行设计的一个示例是用方法参数(消息等)替换为来自(边缘)的对象,就像我们对notifyComment所做的那样 :

- public void notifyComment(String message, String eventName, String user) {
-    notifications.add(user + ": commented on " + eventName + " " + message);
---
+ public void notifyComment(Edge target) {
+    notifications.add(target.getTo().getId() + ": commented on " + target.getFrom().getId() + " " + target.get("comment"));

步骤是:

  1. 将Edge添加为另一个参数(重构–更改方法签名)
  2. 将原始参数的用法一一替换为目标Edge的属性(每次更改后,Infinitest将自动运行无限次测试以确认我们仍然不错)
  3. 最后删除所有原始参数(重构–更改方法签名)

好消息是您的代码始终有效,并且您可以随时提交或停止。

可恢复的重构

如果在执行大规模重构时应用下面描述的实践,那么您的代码将始终是可构建的,并且您将能够在重构过程中停止并在以后的任何时间继续(或不继续)。

这些实践是并行设计,并且以小的安全步骤(即,事实证明不会破坏任何步骤)进行。 从本质上讲,这是保持监督和控制,在每一步中您都确切地知道所做的工作破坏了测试,并且通过这种方式,您不仅可以快速使应用程序恢复工作状态,而且还可以快速地了解导致故障的确切原因。问题。

(上面提到的Mikado方法对于重构系统是一个很好的指南,其中每个更改都揭示了使之成为可能的其他许多更改。当然,重构遗留系统的最终资源是Michael Feathers的《有效使用旧版代码》 )。

随意重构绿色

教条主义的TDD从业人员声称,除非经过某些测试迫使您这样做,否则您无法更改生产代码的行为。 因此,即使没有测试要求通过通用化,听到肯特毫不犹豫地将代码通用化 (例如通过用真实的实现替换伪造品),可能会令人耳目一新。

另一方面,这并不意味着通过测试强制推广是一件坏事,或者您不应该这样做。 这基本上是软件开发的经济学问题,是在成本(编写和维护测试)与收益(缺陷和回归预防)之间取得平衡的问题。 这是涉及的风险以及您对编码技能的信心的问题。 肯特理所当然地比我们中的许多人对他的编码技巧(以及更多的使用经验)更有信心。 根据过去的经验,我们的信心很低,因此,我们可能会继续通过测试来强制概括。

我们将通过引用Kent谈论要做多少测试来结束本主题:

我从有效的代码而不是测试中获得报酬,所以我的理念是尽可能少地测试以达到给定的置信度(我怀疑与行业标准相比,此置信度高,但这可能只是自负) 。 如果我通常不会犯某种错误(例如在构造函数中设置错误的变量),那么我不会对其进行测试。 我确实倾向于理解测试错误,所以当我有复杂条件的逻辑时我要格外小心。 在团队中进行编码时,我会修改策略以仔细测试我们共同容易出错的代码。

基于这种哲学,不同的人会有不同的测试策略,但是鉴于对测试如何最好地适合于编码内循环的理解还不成熟,这对我来说似乎是合理的。 从现在起的十到二十年,我们可能会有一个更为通用的理论,即要编写哪些测试,不编写测试以及如何区分差异。 同时,实验似乎是有序的。

代码中的对称性

对称性是一个抽象的概念,比交流,简单和灵活的价值更具体,但仍然相当笼统。 在实现模式中,Kent将对称性称为编程原则。

具有对称性的代码比不对称的代码更易于掌握。 它更容易阅读和理解。 那么,更具体地说,对称代码是什么? 再次引用肯特:

代码中的对称性是指在代码中出现的相同思想以相同的方式表达。

想象一下一个代码,其中多次实现了一些想法,例如“从数据库中获取最新的更新文档”。 如果方法名称不同,如果它们以不同的顺序执行操作,并且方法之间存在重要区别,则代码是不对称的。 当您问自己“此方法的作用”时,尽管存在所有差异,但对所有方法得出的答案几乎都是相同的,那么您就有些违反对称性。 代码中对称性的一个示例是,像方法一样,在代码块内保持抽象级别一致。 如果该块是低级分配和方法调用的混合,则可能需要查看是否可以使用方法来抽象分配。 精明的读者可能已经注意到,一致性是对称性的很大一部分:与抽象级别一致,与方法命名一致等等。 但是对称性更加抽象,因为它更多地涉及思想而不是规则(例如,类和方法名应采用驼峰式的规则)。

而且您知道什么,甚至更多……

  • 管理您的能量 –注意您的能量并在疲倦之前停下来。 不要忘记休息一下。 休息的开发人员的生产力比疲倦的开发人员高出好几倍。 ( 《软件设计经济学》中的 JB Rainsberger分享了他的工作量如此之大,以至于他变得精疲力竭且完全没有生产力的故事)。
  • 结对编程是一种必须自觉学习的技能 (对某些人格类型可能更具挑战性,应予以尊重)
  • 将IDE的重构优先于手动更改 –f.ex。 肯特(Kent)一直都在使用“内联”重构。 一旦您掌握了重构,它们将比手动更改具有更高的效率,而且更重要的是,它们避免了很小但非零的破坏某件事的可能性(请记住,墨菲说的话–可以打破的东西会破裂)

您可以在GitHub上找到Iterate Code Camp 2012的代码– bit.ly/codecamp2012

结论

我们希望您,亲爱的读者,从中发现一些有趣的想法,并像我们一样受到启发,在您的日常实践中尝试它们。

相关资源

  • Jakub的博客文章“创建可维护和可演化测试的原则”总结了他从肯特中学到的编写测试的一些补充原则。
  • Rich Hickey: 简单易用 –精彩的演讲解释了“简单”(相对于复杂)与“简单”之间的关键区别,以及我们的语言和工具如何不如应有的那样简单,通常是因为它们试图做到简单

参考: The Holy Java博客上的编程,就像 JCG合作伙伴 Jakub Holy的Kent Beck一样 。

翻译自: https://www.javacodegeeks.com/2012/09/programming-like-kent-beck.html

肯特纳交易系统

肯特纳交易系统_像肯特·贝克一样编程相关推荐

  1. 股票交易系统推荐杨方配资_股票交易系统_杨方配资平台_

    股票交易系统_杨方配资平台_日前人研究澳国在英员通巨型自然<志>杂讯发站上网表论文称,能有可最大致澳导型亚巨利绝物灭动是原因的化候变气,类非人而活动. 洲国非我控瘟防猪得作取工成段性阶0. ...

  2. 按键精灵怎么打地鼠_和大家聊少儿编程,什么时候学最佳?怎么选课?

    今天接着来和大家聊少儿编程.这是我们一个全家都特别感兴趣的话题. 这不,逃逃最近就正在编码.调试,忙活他的科学项目作业. 美国这边从小学1年级开始就开设有编程课,各种校内外的编程俱乐部也很热.所以到了 ...

  3. python多线程编程模块不包括_python 学习_第四模块 并发编程(多线程)

    python 学习_第四模块 并发编程(多线程) 一  开启线程方式 from threading importThreadimporttimedefsay(name): time.sleep(2)p ...

  4. 麦肯锡三部曲_天云数据副总裁李从武 | 数据中台三部曲

    天云数据副总裁李从武受邀在大数据与AI中台论坛发表"数据中台三部曲"主题演讲. 2011年5月,麦肯锡发表研究报告:<大数据:下一个创新.竞争和生产率的前沿>,八年时间 ...

  5. java交易系统_基于SSM框架的JAVA二手交易系统

    最近了解了二手交易系统项目,在这个平台记录一下这个二手交易系统项目,方便以后再次使用或学习的时候能够及时的翻阅.在完成这个项目的时候,考虑了很多框架.最终决定选用SSM(MYECLIPSE),该框架具 ...

  6. 斯皮尔 皮尔森 肯德尔_一起来学应用统计学(全部)(二)持续更新

    应用统计基本内容(简略版) 描述统计:统计图表,集中趋势(平均数,中数,众数),离散趋势(极差,离均差,平均差,方差,标准差,差异系数,z分数) 数学基础(概率论基础,抽样分布理论) 推断统计:参数估 ...

  7. 斯皮尔 皮尔森 肯德尔_失焦图像的无参考质量评价

    刘玉涛 赵德斌 Abstract: Images are vulnerable to different kinds of distortions, such as blur, noise, bloc ...

  8. 麦肯锡三部曲_《学会提问:麦肯锡工作法》—读书笔记导图分享

    本文字数4194,预计阅读时间3分钟. 阅读使人充实,分享使人愉悦.文章结尾附有思维导图,帮你梳理文中脉络精华.欢迎阅读,你离知识又近一步. 今天分享的书籍是<学会提问:麦肯锡工作法>. ...

  9. 麦肯锡三部曲_越拼命工作,越不快乐?麦肯锡“提问式思维”帮你发现问题本质...

    01提问是一种非常实用的工具 上个月,因为一个新任务,我天天加班,累死累活,才勉强完成任务.原本以为领导会因此给涨工资,结果工资不升反降.那一瞬间,我有了辞职的想法. 夜深人静时,想起自己毕业几年也没 ...

最新文章

  1. 关于java文件下载文件名乱码问题解决方案
  2. 解读:MR多路径输入
  3. OpenCASCADE:使用扩展数据交换 XDE之特性
  4. 【转】判断五张牌是不是一个顺子
  5. 用 .NET 3.5 创建 ToJSON() 扩展方法
  6. Ubuntu 修改默认的PDF打开方式
  7. java.sql.SQLException: Value'0000-00-00'异常解决办法
  8. Acer 4750 安装黑苹果_自己安装黑苹果,其实黑苹果也没那么难~
  9. 多线程篇三:线程同步
  10. visual studio 编译器在辨异 C/C++ 程序时的注意事项
  11. Linux 性能测试工具 sysbench 的安装与简单使用
  12. Java Web程序设计——JSP技术(一)
  13. DNS资源纪录(Resource Record)介绍
  14. 基于JAVA的游戏补丁共享网站实现
  15. html的中性标签,HTML的figcaption标签
  16. 绘制CAD图纸的过程中CAD快捷键失灵了怎么办?
  17. 安卓开发中必备的那些神器APP
  18. 鞍部在哪里_等高线地形图中鞍部的高度怎么看
  19. 开源免费录屏和直播软件OBS Studio教程(02)
  20. ipad iphone开发_如何自定义您的iPhone或iPad的控制中心

热门文章

  1. 新手看完学会,5分钟教你制作吸引人的片头片尾,操作简单
  2. 直播类APP功能及技术难点
  3. 王小二切饼 C 2050
  4. [源码和文档分享]一元多项式的表示和相加
  5. 【原创】MarkDown-常用模板
  6. 项目“恶意APK检测系统”——安卓逆向部分学习
  7. python 双色球 输出到txt_python3 - 写一个生成双色球号码的一个程序,生成的号码写到文件里面...
  8. 计算机桌面图标管理,让桌面干干净净!桌面图标管理不用愁
  9. html5可滑动的文本框,html5 input type=range实现拖拉滑条功能
  10. 刷脸时代的安全防护体系到位吗?