<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/">
  <channel>
    <title>TDD on I Code It</title>
    <link>https://icodeit.org/categories/tdd/</link>
    <description>Recent content in TDD on I Code It</description>
    <generator>Hugo -- gohugo.io</generator>
    <lastBuildDate>Wed, 01 Jul 2020 00:00:00 +0000</lastBuildDate><atom:link href="https://icodeit.org/categories/tdd/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>我的第一本英文技术书</title>
      <link>https://icodeit.org/2020/07/how-to-write-a-english-book/</link>
      <pubDate>Wed, 01 Jul 2020 00:00:00 +0000</pubDate>
      
      <guid>https://icodeit.org/2020/07/how-to-write-a-english-book/</guid>
      <description>2021年6月更新 不知不觉已经过去快一年了，我来更新下这篇的后续。
首先我想分享给大家的是：这本书的纸质版已经由APress出版社正式出版了！
从原来的博客发布至今的近一年中，这本书经历了很多次的编辑和重构。事实上，在这本书有了初稿之后，我就曾请求同事Martin Fowler帮我review并提供一些早期的反馈，不过他当时还在忙于《重构》第二版的审校工作，所以只是放入了他的backlog里，直到去年7月才review完成。Martin的批注非常仔细，从目录结构，到遣词造句，再到实例与主题的关联度，以及参考文献等等方面，差不多有近10页。我根据这些批注重新组织了书的结构，并删减了差不多1/4的内容，使得结构和内容更聚焦。此外，Hannah又在此基础上进行了英文的编辑和润色，以及对一些代码实例的建议。
去年圣诞前后，APress的编辑找到我，表示他们有讲此书出版为纸质书并在他们平台上发售的意向。在经历了数个月的编辑，审校，勘误之后，这本书终于出版为纸质版本。在上周末我收到了出版社寄来的几本样书。看到自己的名字印刷在封面上是一种奇妙的感觉，开心当然是有的，不过随之而来的又是一些隐约的担忧：担心书中技术终会过时，担心有不好的comments等等。不过该来的终觉会来，这大约也是出版的一部分吧。
另外，感谢那些鼓励我的、默默提供勘误的、报告bug的人们，没有你们的帮助，这本书不会最终成为可能。
 我的第一本英文技术书 太长不读 我写了一本关于React+TDD的英文书，你可以从这里免费获得(更新：和APress出版社的合同中明确要求需要从其他渠道将其下线)。在我写这篇文章的时候，读者大约是1000+。虽然读者不算多，但是通过一些渠道收集到的反馈还算不错，已经超出我自己预期很多了。如果你读完觉得还不错，而且愿意帮我宣传一下我会非常感激，如果你想要做一些修订甚至翻译的话那就更棒了（有一个俄罗斯小伙在帮我翻译俄文版，不过他貌似拖稿十分严重）。
缘起 实话实说，写这本书纯属意外之举，最开始的时候对于内容和形式是完全没有计划的，更不用说用另外一门语言作为载体了。应该是在2017年年末的时候，我在华为的无线部门做一个网管产品的Web化，人员能力提升显然是Web化的核心了 &amp;ndash; 毕竟功能需要开发人员一行行去实现。当时该部门中的大部分开发同事的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到你的意思。即使有些复杂概念无法一次理解，通过评注或者提问等等，总是会搞清楚的。
关于自信构建 在这本书的写作过程中，我个人最大的收获应该是：当你制定了一个目标，不论这个目标开始开起来有多么的不切实际，一旦你开始细化这个目标并逐步实施，你就已经离这个目标不远了。当然，和每个任务一样，事情走到最后可能会和最开始的目标并不完全契合，但这大约是我们无法掌控的那部分了，就随他去吧。</description>
      <content:encoded><![CDATA[<h2 id="2021年6月更新">2021年6月更新</h2>
<p>不知不觉已经过去快一年了，我来更新下这篇的后续。</p>
<p>首先我想分享给大家的是：这本书的纸质版已经由APress出版社正式出版了！</p>
<p><img loading="lazy" src="/images/2020/07/tdd-with-react.png" type="" alt="tdd-with-react.png"  /></p>
<p>从原来的博客发布至今的近一年中，这本书经历了很多次的编辑和重构。事实上，在这本书有了初稿之后，我就曾请求同事<code>Martin Fowler</code>帮我review并提供一些早期的反馈，不过他当时还在忙于《重构》第二版的审校工作，所以只是放入了他的backlog里，直到去年7月才review完成。Martin的批注非常仔细，从目录结构，到遣词造句，再到实例与主题的关联度，以及参考文献等等方面，差不多有近10页。我根据这些批注重新组织了书的结构，并删减了差不多1/4的内容，使得结构和内容更聚焦。此外，Hannah又在此基础上进行了英文的编辑和润色，以及对一些代码实例的建议。</p>
<p>去年圣诞前后，APress的编辑找到我，表示他们有讲此书出版为纸质书并在他们平台上发售的意向。在经历了数个月的编辑，审校，勘误之后，这本书终于出版为纸质版本。在上周末我收到了出版社寄来的几本样书。看到自己的名字印刷在封面上是一种奇妙的感觉，开心当然是有的，不过随之而来的又是一些隐约的担忧：担心书中技术终会过时，担心有不好的comments等等。不过该来的终觉会来，这大约也是出版的一部分吧。</p>
<p>另外，感谢那些鼓励我的、默默提供勘误的、报告bug的人们，没有你们的帮助，这本书不会最终成为可能。</p>
<hr>
<h2 id="我的第一本英文技术书">我的第一本英文技术书</h2>
<h3 id="太长不读">太长不读</h3>
<p>我写了一本关于<code>React+TDD</code>的英文书，<del>你可以<a href="https://leanpub.com/mastering-tdd-with-react">从这里免费获得</a></del>(更新：和APress出版社的合同中明确要求需要从其他渠道将其下线)。在我写这篇文章的时候，读者大约是1000+。虽然读者不算多，但是通过一些渠道收集到的反馈还算不错，已经超出我自己预期很多了。如果你读完觉得还不错，而且愿意帮我宣传一下我会非常感激，如果你想要做一些<strong>修订甚至翻译</strong>的话那就更棒了（有一个俄罗斯小伙在帮我翻译俄文版，不过他貌似拖稿十分严重）。</p>
<h3 id="缘起">缘起</h3>
<p>实话实说，写这本书纯属意外之举，最开始的时候对于内容和形式是完全没有计划的，更不用说用另外一门语言作为载体了。应该是在2017年年末的时候，我在华为的无线部门做一个网管产品的Web化，人员能力提升显然是Web化的核心了 &ndash; 毕竟功能需要开发人员一行行去实现。当时该部门中的大部分开发同事的Web技能都比较薄弱，一些有经验的同时则每日被业务需求缠身无法顾及能力构建，因此引入外部的培训来填补这个空缺。</p>
<p>这个看起来是<em>Web开发101</em>的培训还有一些其他需求，比如用户故事拆分、自动化测试和TDD等等敏捷开发的基本内容。我为团队设计了一些循序渐进的例子作为培训的素材，并在后来的几轮迭代中进行了内容的删减和补充。培训的结果还是不错，有一半以上的同事对Web开发产生了兴趣，有人则开始意识到自动化测试（以及TDD）可以减少回归测试的工作量。</p>
<p>正如你所料，这个培训的一个副产品就是这本书的原型了。在培训结束之后我正好有了几周的beach时间，我用这些时间将内容变成一个教程：从一个简单的例子，逐步完善成一个前端应用。其中涉及了诸如<code>Tasking</code>，<code>ATDD</code>，用户故事等。</p>
<h3 id="过程">过程</h3>
<h4 id="初稿">初稿</h4>
<p>原型是很容易的，素材是现成的，只需要将其以符合逻辑的方式连接起来即可。比如我想要描述<em>通过TDD的方式开发一个应用的</em>全过程，那么首先我需要讲清楚我们要做一个<strong>什么应用</strong>，此外我需要说清楚<strong>如何用TDD</strong>来完成这个应用。根据经验，人们喜欢循序渐进的方式来阅读，先做一个简单需求，然后逐步增强，并在过程中将学到的内容应用，然后推广到后续需求的开发中，并通过实现更加复杂需求<strong>习得</strong>我想要传递的知识/技巧。</p>
<ul>
<li>TDD的101（通过例子来说明<code>Tasking</code>和<em>测试驱动</em>的过程）</li>
<li>介绍demo应用，搭建应用所需的环境</li>
<li>设计并实现一个简单需求</li>
<li>实现一个更复杂的需求</li>
<li>循序渐进……</li>
</ul>
<p>编辑初稿的过程中，正好有个掘金小册的编辑联系我有没有意向写个小册子。虽然最后由于篇幅和主题的选择方向没有合作，但是和编辑沟通的过程帮助我很好的梳理了草稿的结构。</p>
<h4 id="英文版">英文版</h4>
<p>在草稿写完之后，我找到几个同事做了快速的review并做了一些修改。到了2018年3月，我开始准备来澳洲的LTA，既然英语会是我接下来几年的主要语言，那么提升英文能力就成了优先级很高的事情。而学习语言的窍门就是：没有什么比<strong>实际使用一门语言</strong>更能提升语言能力的了。</p>
<p>于是我开始尝试把草稿翻译成英文版。开始的时候我还会保持双语版本的同步，到后来带宽不足的时候就只能把精力放到英文版上了。第一个完整的英文版发布于2018年5月，后面虽然陆续有些小的修改，主体部分没有太大的变化。</p>
<p>到了澳洲之后，读了很多英文原版的书籍/文章之后，发现了书中很多的语言错误，又在一个假期里集中修改过一轮，可读性有了一些提高。</p>
<h4 id="重构">重构</h4>
<p>到了2019年的9月，经过了近1年2个纯<code>React</code>的项目后，我对与<code>React</code>及其生态的理解，以及在应用TDD（特别是和传统上认为的TDD很难在复杂/时间不允许的项目上实施）的认识上都有了新的发展。于是又将其中很多章节重写了，比如丢弃了<code>pupeeteer</code>改成<code>cypress</code>，采用<code>react-testing-library</code>而不是<code>enzyme</code>等等。另外，结构上也做了重新整理。</p>
<p>由于这些颠覆性的修改，我将其重新命名为<code>Mastering Test Driven Development with React</code>，并声明其为前一个版本的<strong>第二版</strong>。</p>
<p>到了2020年4月，由于covid-19在澳洲的肆虐，我们开始全面<code>WFH</code>。一方面突然有了很多时间，另一方面我意识到线上沟通时英文在有些时候还是会变成blocker，于是我又花费了一些时间来提升英文。于是又开始了一轮的<code>re-wording</code>。</p>
<p>在你今天阅读这本书的时候，你大约会惊叹于英文表达之地道，语法之准确以及用词之精准。这些都和我的英文水平<strong>没有</strong>太大关系。在5月的一天，一位澳洲同事Hannah Bourke写邮件给我，表示她通读了这本书，非常喜欢其中的讲述方式和实例以及节奏，她表示愿意帮我近一步<code>润色</code>。她通过PR的方式重新整理了本书的语言（目前已经完成了70%），由于Hannah本身就是前端Dev，所以很多表达方式也被重写为更容易被读者理解的方式。</p>
<p><img loading="lazy" src="/images/2020/07/diff.png" type="" alt="image-20200701120458263"  /></p>
<h3 id="一些收获">一些收获</h3>
<h4 id="关于英文写作">关于英文写作</h4>
<p>语言的学习是个漫长而痛苦的过程，同样的内容，要从一门语言中的表述要翻译成另一门语言需要的更多的是重写而不是<code>literal translation</code>。从LTA开始我就开始刻意的用<a href="https://juntao-qiu.medium.com/">英文写作</a>，还尝试把一些文章翻译并投稿给<a href="https://www.thoughtworks.com/insights/blog/seven-principles-pair-programming-etiquette">英文版洞见</a>。</p>
<p>通过这些练习，我觉得我至少不再惧怕这件事情本身。英文表达当然有不地道的地方，但是读者也不是语言学家，大多数时候他们都可以准确无误的get到你的意思。即使有些复杂概念无法一次理解，通过评注或者提问等等，总是会搞清楚的。</p>
<h4 id="关于自信构建">关于自信构建</h4>
<p>在这本书的写作过程中，我个人最大的收获应该是：当你制定了一个目标，不论这个目标开始开起来有多么的不切实际，一旦你开始细化这个目标并逐步实施，你就已经离这个目标不远了。当然，和每个任务一样，事情走到最后可能会和最开始的目标并不完全契合，但这大约是我们无法掌控的那部分了，就随他去吧。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>反馈拯救世界</title>
      <link>https://icodeit.org/2018/01/feedback-saves-the-world/</link>
      <pubDate>Sat, 13 Jan 2018 00:00:00 +0000</pubDate>
      
      <guid>https://icodeit.org/2018/01/feedback-saves-the-world/</guid>
      <description>心流 你可能有过这样的体验：在玩一个很有趣的游戏时，时间会飞快的流逝，等你终于通关之后才发现已经是凌晨，而你的午饭和晚饭还都没吃。虽然可能饿着肚子，但是你内心却有一种很兴奋，很神清气爽的感觉。而当你在做一些不得不完成的工作/作业时（比如写年终总结报告），时间又会过得很慢，你的心情也常常变得焦虑或者暴躁。
通常来说，人的心情总是会在各种情绪中起伏不定，不过毋庸置疑，我们都希望永远或者至少是尽可能多的保持第一个场景中的状态。
这种精神高度集中，通过自己的努力不断完成挑战，并常常会有忘记时间流逝，甚至忘记自身存在，只剩下“做事情”本身的状态，在心理学上被称之为心流（Flow）。人们虽然很早就发现了这种现象，但是直到1975年，心理学家米哈里·齐克森米哈里（Mihaly Csikszentmihalyi）才将其概念化并通过科学的方式来研究。
 心流（英语：Flow），也有别名以化境(Zone)表示，亦有人翻译为神驰状态，定义是一种将个人精神力完全投注在某种活动上的感觉；心流产生时同时会有高度的兴奋及充实感。
 进入心流之后会有很多特征：
 愉悦 全身心投入 忘我，与做的事情融为一体 主观的时间感改变  心流被普遍认为是一种绝佳的精神体验。根据齐克森米哈里的理论，与心流对应的，还有一些其他的心理状态：
当自身能力很高，但是做的事情很简单的话，你做起来会比较无聊；而当能力不足，要做的事情很困难的话，你又会陷入焦虑。有意思的是，如果你技能不足，而做的事情又比较简单的话，并不会产生“心流”体验。恰恰相反，这种状态（apathy）是很消极的，做事情的过程中，你既没有运用任何技能，也并没有接受到任何的挑战。
如何进入心流状态 齐克森米哈里要进入心流状态，需要满足至少三点：
 有清晰的目标 有明确且事实的反馈 能力和挑战的平衡（都处于比较高的状态）  比如，玩游戏的时候，目标是明确的，不论是简单的通过策略消灭对方，还是将三个同一颜色的宝石移动到同一行）；反馈也是实时的，同色宝石连在一起是发出的声音以及屏幕上闪过的炫目的光芒，敌人在被你手中武器杀死时的惨叫，你自己的血槽等等；最后，游戏不能过于简单，如果太简单，你很快会觉得无聊，又不能太难，这样你会觉得挑战太大。
不过要在工作上进入心流状态，远远比玩游戏要复杂。比如不明确的目标，冗长的反馈周期，能力与挑战的不均衡等等。
基于反馈的开发 2014年底，我在ThoughtWorks组织3周3页面工作坊的时候，发现了一个很有意思的现象：通常公司内部的培训/工作坊都会出现这种现象：报名的人很多，前几次课会来很多人，慢慢的人数会减少，能坚持到最后的人很少，能完成作业的就更少了。而在3周3页面中，参加的人数越来越多，而且作业的完成率非常高（接近100%）。
回想起来，我在培训的最开始就设置了一些机制，保证学员可以有一个非常容易沉浸其中的环境：
 通过watch、livereload等机制，保证每次修改的CSS/HTML都可以在1秒钟内在浏览器上自动刷新 通过对比mockup和自己实现的样式的差异，来调整自己的目标 将这些工具做成开箱即用的，这样经验不足者不至于被技术细节阻塞 做完之后，学员们的作品直接发布到github的pages上  事实上，这些实践恰好满足了上述的几个条件：
 目标明确 快速且准确的反馈 技能与挑战的平衡  由于工作坊是在周内下班后（8点结束），我见到很多学员在课后（很晚的时候）还在写代码、调样式，完全沉浸其中，忘记时间。到最后，参加培训的学员们被要求通过设计原则自己实际一个Web Site，很多没有前段开发背景的同事也做出了非常有“设计感”的作品。
编程语言的壁垒 使用JavaScript或者Ruby这种解释型语言的开发人员，在第一次接触之后就会深深的爱上它，并再也无法回到编译型语言中去了。想一想要用Java打印一行Hello World你得费多大劲？
解释型语言中，你很容易可以采用REPL环境，写代码会变成一个做实验的过程：函数名写错了，参数传错了，某个函数没有定义等等错误/手误，都可以在1秒钟内得到反馈，然后你再根据反馈来修正方向。
举个小例子，写一个字符串处理函数：将字符串”qiu,juntao”转换成“Qiu Juntao”，你会怎么做？你大概知道有这样一些原生的API：
 String.indexOf String.replace 大小写转换 正则表达式（可选）  如果用JavaScript来实现的话，你可以在Chrome的DevTools中完成大部分的工作：
注意这里的每次操作的反馈（特别是出错的情况），你可以在1秒钟内就知道明确的反馈，而不是等等待漫长的编译过程。DevTools里的console提供的REPL（read-eval-print-loop）可以帮助你建立流畅的编码体验。
如果用Java来做，你需要一大堆的准备工作，抛开JDK的安装，JAVA_HOME的设置等，你还需要编译代码，需要定义一个类，然后在类中定义main方法，然后可能要查一些API来完成函数的编写。而每一个额外的步骤都会延长反馈的时间。
测试驱动开发 那么在编译型语言中如何获得这种体验呢？又如何缩短反馈周期呢？答案是使用测试驱动开发（Test Driven Development）！
通常TDD会包含这样几个步骤：
 根据用户故事做任务分解 根据分解后的Task设计测试 编写测试 编写可以通过测试的实现 重构  步骤3-5可能会不断重复，直到所有的Task都完成，用户故事也就完成了。如果仔细分析，这些步骤也恰好符合产生心流的条件：</description>
      <content:encoded><![CDATA[<h3 id="心流">心流</h3>
<p>你可能有过这样的体验：在玩一个很有趣的游戏时，时间会飞快的流逝，等你终于通关之后才发现已经是凌晨，而你的午饭和晚饭还都没吃。虽然可能饿着肚子，但是你内心却有一种很兴奋，很神清气爽的感觉。而当你在做一些不得不完成的工作/作业时（比如写年终总结报告），时间又会过得很慢，你的心情也常常变得焦虑或者暴躁。</p>
<p>通常来说，人的心情总是会在各种情绪中起伏不定，不过毋庸置疑，我们都希望永远或者至少是尽可能多的保持第一个场景中的状态。</p>
<p><img loading="lazy" src="/images/2018/01/playing-game-resized.png" type="" alt=""  /></p>
<p>这种精神高度集中，通过自己的努力不断完成挑战，并常常会有忘记时间流逝，甚至忘记自身存在，只剩下“做事情”本身的状态，在心理学上被称之为<a href="https://en.wikipedia.org/wiki/Flow_(psychology)">心流（Flow）</a>。人们虽然很早就发现了这种现象，但是直到1975年，心理学家米哈里·齐克森米哈里（<a href="https://en.wikipedia.org/wiki/Mih%C3%A1ly_Cs%C3%ADkszentmih%C3%A1lyi">Mihaly Csikszentmihalyi</a>）才将其概念化并通过科学的方式来研究。</p>
<blockquote>
<p>心流（英语：Flow），也有别名以化境(Zone)表示，亦有人翻译为神驰状态，定义是一种将个人精神力完全投注在某种活动上的感觉；心流产生时同时会有高度的兴奋及充实感。</p>
</blockquote>
<p>进入心流之后会有很多特征：</p>
<ul>
<li>愉悦</li>
<li>全身心投入</li>
<li>忘我，与做的事情融为一体</li>
<li>主观的时间感改变</li>
</ul>
<p>心流被普遍认为是一种绝佳的精神体验。根据齐克森米哈里的理论，与心流对应的，还有一些其他的心理状态：</p>
<p><img loading="lazy" src="/images/2018/01/300px-Challenge_vs_skill.svg.png" type="" alt=""  /></p>
<p>当自身能力很高，但是做的事情很简单的话，你做起来会比较无聊；而当能力不足，要做的事情很困难的话，你又会陷入焦虑。有意思的是，如果你技能不足，而做的事情又比较简单的话，并不会产生“心流”体验。恰恰相反，这种状态（<strong>apathy</strong>）是很消极的，做事情的过程中，你既没有运用任何技能，也并没有接受到任何的挑战。</p>
<h3 id="如何进入心流状态">如何进入心流状态</h3>
<p>齐克森米哈里要进入心流状态，需要满足至少三点：</p>
<ul>
<li>有清晰的目标</li>
<li>有明确且事实的反馈</li>
<li>能力和挑战的平衡（都处于比较高的状态）</li>
</ul>
<p>比如，玩游戏的时候，目标是明确的，不论是简单的通过策略消灭对方，还是将三个同一颜色的宝石移动到同一行）；反馈也是实时的，同色宝石连在一起是发出的声音以及屏幕上闪过的炫目的光芒，敌人在被你手中武器杀死时的惨叫，你自己的血槽等等；最后，游戏不能过于简单，如果太简单，你很快会觉得无聊，又不能太难，这样你会觉得挑战太大。</p>
<p>不过要在工作上进入心流状态，远远比玩游戏要复杂。比如不明确的目标，冗长的反馈周期，能力与挑战的不均衡等等。</p>
<h3 id="基于反馈的开发">基于反馈的开发</h3>
<p>2014年底，我在<code>ThoughtWorks</code>组织<a href="http://icodeit.org/3-pages-in-3-weeks/">3周3页面</a>工作坊的时候，发现了一个很有意思的现象：通常公司内部的培训/工作坊都会出现这种现象：报名的人很多，前几次课会来很多人，慢慢的人数会减少，能坚持到最后的人很少，能完成作业的就更少了。而在<a href="http://icodeit.org/3-pages-in-3-weeks/">3周3页面</a>中，参加的人数越来越多，而且作业的完成率非常高（接近100%）。</p>
<p>回想起来，我在培训的最开始就设置了一些机制，保证学员可以有一个非常容易沉浸其中的环境：</p>
<ul>
<li>通过watch、livereload等机制，保证每次修改的CSS/HTML都可以在1秒钟内在浏览器上自动刷新</li>
<li>通过对比mockup和自己实现的样式的差异，来调整自己的目标</li>
<li>将这些工具做成<a href="https://github.com/abruzzi/design-boilerplate">开箱即用</a>的，这样经验不足者不至于被技术细节阻塞</li>
<li>做完之后，学员们的作品直接发布到<a href="https://pages.github.com/">github的pages</a>上</li>
</ul>
<p><img loading="lazy" src="/images/2018/01/3p3w-resized.png" type="" alt=""  /></p>
<p>事实上，这些实践恰好满足了上述的几个条件：</p>
<ul>
<li>目标明确</li>
<li>快速且准确的反馈</li>
<li>技能与挑战的平衡</li>
</ul>
<p>由于工作坊是在周内下班后（8点结束），我见到很多学员在课后（很晚的时候）还在写代码、调样式，完全沉浸其中，忘记时间。到最后，参加培训的学员们被要求通过设计原则自己实际一个Web Site，很多没有前段开发背景的同事也做出了非常有“设计感”的作品。</p>
<p><img loading="lazy" src="/images/2018/01/3p3w-showcase-resized.png" type="" alt=""  /></p>
<h3 id="编程语言的壁垒">编程语言的壁垒</h3>
<p>使用<code>JavaScript</code>或者<code>Ruby</code>这种解释型语言的开发人员，在第一次接触之后就会深深的爱上它，并再也无法回到编译型语言中去了。想一想要用<code>Java</code>打印一行<code>Hello World</code>你得费多大劲？</p>
<p>解释型语言中，你很容易可以采用<a href="https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop">REPL</a>环境，写代码会变成一个做实验的过程：函数名写错了，参数传错了，某个函数没有定义等等错误/手误，都可以在1秒钟内得到反馈，然后你再根据反馈来修正方向。</p>
<p>举个小例子，写一个字符串处理函数：将字符串”qiu,juntao”转换成“Qiu Juntao”，你会怎么做？你大概知道有这样一些原生的API：</p>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/indexOf">String.indexOf</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/replace">String.replace</a></li>
<li><a href="https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/String/toUpperCase">大小写转换</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">正则表达式</a>（可选）</li>
</ul>
<p>如果用JavaScript来实现的话，你可以在<code>Chrome</code>的<code>DevTools</code>中完成大部分的工作：</p>
<p><img loading="lazy" src="/images/2018/01/chrome-dev-tools-resized.png" type="" alt=""  /></p>
<p>注意这里的每次操作的反馈（特别是出错的情况），你可以在1秒钟内就知道明确的反馈，而不是等等待漫长的编译过程。DevTools里的console提供的REPL（read-eval-print-loop）可以帮助你建立流畅的编码体验。</p>
<p>如果用<code>Java</code>来做，你需要一大堆的准备工作，抛开<code>JDK</code>的安装，<code>JAVA_HOME</code>的设置等，你还需要编译代码，需要定义一个类，然后在类中定义main方法，然后可能要查一些API来完成函数的编写。而每一个额外的步骤都会延长反馈的时间。</p>
<h3 id="测试驱动开发">测试驱动开发</h3>
<p>那么在编译型语言中如何获得这种体验呢？又如何缩短反馈周期呢？答案是使用<strong>测试驱动开发</strong>（Test Driven Development）！</p>
<p>通常<code>TDD</code>会包含这样几个步骤：</p>
<ol>
<li>根据用户故事做任务分解</li>
<li>根据分解后的<code>Task</code>设计测试</li>
<li>编写测试</li>
<li>编写可以通过测试的实现</li>
<li>重构</li>
</ol>
<p><img loading="lazy" src="/images/2018/01/tasking-resized.png" type="" alt=""  /></p>
<p>步骤3-5可能会不断重复，直到所有的Task都完成，用户故事也就完成了。如果仔细分析，这些步骤也恰好符合产生心流的条件：</p>
<ul>
<li>划分任务</li>
<li>清晰每一个小任务</li>
<li>通过测试得到快速而明确的反馈</li>
</ul>
<p>虽然对上边字符串转换的例子来说，<code>TDD</code>的方式还是比较重量级，不过反馈更明确，你可以在写完一个函数之后立即得到测试成功或者失败的反馈（编译过程并没有省略，不过我们通过测试的红和绿来不断强化反馈）。</p>
<p>而且这种方法的好处在于：对于更加复杂的需求来说，它仍然适用。如果开发者的技能和需求的难度都比较高的话，这种方式很容易达到心流的状态。</p>
<h3 id="小结">小结</h3>
<p>要想在工作中让自己过得更舒服一些，你需要创造条件让自己进入心流状态。在这些条件中，最重要的是要建立其一套快速反馈的机制，这个机制可以是：</p>
<ul>
<li>一个可以自动运行的测试套件</li>
<li>一个可以迭代的页面原型</li>
<li>一个watch所有HTML/SCSS的脚本+live-reload</li>
<li>一个和你一起写代码的同事（结对编程）</li>
</ul>
<p><img loading="lazy" src="/images/2018/01/gulp-serve-resized.png" type="" alt=""  /></p>
<p>另一方面，你需要不断的学习和练习，提升自己的技能，这样在遇到新的问题时才可能比较从容应对。不要忘了，<strong>更熟练的技能</strong>本身也是进入心流的重要条件之一。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>测试驱动开发实例</title>
      <link>https://icodeit.org/2014/11/tdd-step-by-step/</link>
      <pubDate>Sun, 09 Nov 2014 00:00:00 +0000</pubDate>
      
      <guid>https://icodeit.org/2014/11/tdd-step-by-step/</guid>
      <description>示例的需求描述 今天我们需要完成的需求是这样的：
对于一个给定的字符串，如果其中元音字母数目在整个字符串中的比例超过了30%，则将该元音字母替换成字符串mommy，额外的，在替换时，如果有连续的元音出现，则仅替换一次。
如果用实例化需求(Specification by Example)的方式来描述的话，需求可以转换成这样几条实例：
 hmm经过处理之后，应该保持原状 she经过处理之后，应该被替换为shmommy hear经过处理之后，应该被替换为hmommyr  当然，也可以加入一些边界值的检测，比如包含数字，大小写混杂的场景来验证，不过我们暂时可以将这些场景抛开，而仅仅关注与TDD本身。
为什么选择这个奇怪的例子 我记得在学校的时候，最害怕看到的就是书上举的各种离生活很远的例子，比如国外的书籍经常举汽车的例子，有引擎，有面板，但是作为一个只是能看到街上跑的车的穷学生，实际无法理解其中的关联关系。
其实，另外一种令人不那么舒服的例子是那种纯粹为了示例而编写的例子，现实世界中可能永远都不可能见到这样的代码，比如我们今天用到的例子。
当然，这种纯粹的例子也有其存在的价值：在脱离开复杂的细节之后，尽量的让读者专注于某个方面，从而达到对某方面练习的目的。因为跟现实完全相关的例子往往会变得复杂，很容易让读者转而去考虑复杂性本身，而忽略了对实践/练习的思考。
TDD步骤 通常的描述中，TDD有三个步骤：
 先编写一个测试，由于此时没有任何实现，因此测试会失败 编写实现，以最快，最简单的方式，此时测试会通过 查看实现/测试，有没有改进的余地，如果有的话就用重构的方式来优化，并在重构之后保证测试通过  它的好处显而易见：
 时时关注于实现功能，这样不会跑偏 每个功能都有测试覆盖，一旦改错，就会有测试失败 重构时更有信心，不用怕破坏掉已有的功能 测试即文档，而且是不会过期的文档，因为一旦实现变化，相关测试就会失败  使用TDD，一个重要的实践是测试先行。其实在编写任何测试之前，更重要的一个步骤是任务分解(Tasking)。只有当任务分解到恰当的粒度，整个过程才可能变得比较顺畅。
回到我们的例子，我们在知道整个需求的前提下，如何进行任务分解呢？作为实现优先的程序员，很可能会考虑诸如空字符串，元音比例是否到达30%等功能。这当然没有孰是孰非的问题，不过当需求本身就很复杂的情况下，这种直接面向实现的方式可能会导致越走越偏，考虑的越来越复杂，而耗费了几个小时的设计之后发现没有任何的实际进度。
如果是采用TDD的方式，下面的方式是一种可能的任务分解：
 输入一个非元音字符，并预期返回字符本身 输入一个元音，并预期返回mommy 输入一个元音超过30%的字符串，并预期元音被替换 输入一个元音超过30%，并且存在连续元音的字符串，并预期只被替换一次  当然，这个任务分解可能并不是最好的，但是是一个比较清晰的分解。
实践 第一个任务 在本文中，我们将使用JavaScript来完成该功能的编写，测试框架采用了Jasmine，这里有一个模板项目，使用它你可以快速的启动，并跟着本教程一起实践。
根据任务分解，我们编写的第一个测试是：
describe(&amp;#34;mommify&amp;#34;, function() { it(&amp;#34;should return h when given h&amp;#34;, function() { var expected = &amp;#34;h&amp;#34;; var result = mommify(&amp;#34;h&amp;#34;); expect(result).toEqual(expected); }); }); 这个测试中有三行代码，这也是一般测试的标准写法，简称3A：
 组织数据（Arrange） 执行需要被测的函数（Action） 验证结果（Assertion）  运行这个测试，此时由于还没有实现代码，因此Jasmine会报告失败。接下来我们用最快速的方法来编写实现，就目前来看，最简单的方式就是：</description>
      <content:encoded><![CDATA[<h3 id="示例的需求描述">示例的需求描述</h3>
<p>今天我们需要完成的需求是这样的：</p>
<p>对于一个给定的字符串，如果其中<code>元音</code>字母数目在整个字符串中的比例超过了30%，则将该<code>元音</code>字母替换成字符串<code>mommy</code>，额外的，在替换时，如果有连续的元音出现，则仅替换一次。</p>
<p>如果用<code>实例化需求</code>(<a href="http://specificationbyexample.com/">Specification by Example</a>)的方式来描述的话，需求可以转换成这样几条实例：</p>
<ol>
<li><code>hmm</code>经过处理之后，应该保持原状</li>
<li><code>she</code>经过处理之后，应该被替换为<code>shmommy</code></li>
<li><code>hear</code>经过处理之后，应该被替换为<code>hmommyr</code></li>
</ol>
<p>当然，也可以加入一些边界值的检测，比如包含数字，大小写混杂的场景来验证，不过我们暂时可以将这些场景抛开，而仅仅关注与TDD本身。</p>
<h4 id="为什么选择这个奇怪的例子">为什么选择这个<code>奇怪的</code>例子</h4>
<p>我记得在学校的时候，最害怕看到的就是书上举的各种离<code>生活</code>很远的例子，比如国外的书籍经常举汽车的例子，有引擎，有面板，但是作为一个只是能看到街上跑的车的穷学生，实际无法理解其中的关联关系。</p>
<p>其实，另外一种令人不那么舒服的例子是那种纯粹为了示例而编写的例子，现实世界中可能永远都不可能见到这样的代码，比如我们今天用到的例子。</p>
<p>当然，这种纯粹的例子也有其存在的价值：在脱离开复杂的细节之后，尽量的让读者专注于某个方面，从而达到对某方面练习的目的。因为跟现实完全相关的例子往往会变得复杂，很容易让读者转而去考虑复杂性本身，而忽略了对实践/练习的思考。</p>
<h4 id="tdd步骤">TDD步骤</h4>
<p>通常的描述中，<code>TDD</code>有三个步骤：</p>
<ol>
<li>先编写一个测试，由于此时没有任何实现，因此测试会失败</li>
<li>编写实现，以最快，最简单的方式，此时测试会通过</li>
<li>查看实现/测试，有没有改进的余地，如果有的话就用重构的方式来优化，并在重构之后保证测试通过</li>
</ol>
<p><img loading="lazy" src="/images/2014/11/tdd.png" type="" alt="tdd"  /></p>
<p>它的好处显而易见：</p>
<ol>
<li>时时关注于实现功能，这样不会跑偏</li>
<li>每个功能都有测试覆盖，一旦改错，就会有测试失败</li>
<li>重构时更有信心，不用怕破坏掉已有的功能</li>
<li>测试即文档，而且是不会过期的文档，因为一旦实现变化，相关测试就会失败</li>
</ol>
<p>使用<code>TDD</code>，一个重要的实践是<code>测试先行</code>。其实在编写任何测试之前，更重要的一个步骤是<code>任务分解</code>(Tasking)。只有当任务分解到恰当的粒度，整个过程才可能变得比较顺畅。</p>
<p>回到我们的例子，我们在知道整个需求的前提下，如何进行任务分解呢？作为<code>实现优先</code>的程序员，很可能会考虑诸如空字符串，元音比例是否到达30%等功能。这当然没有孰是孰非的问题，不过当需求本身就很复杂的情况下，这种直接面向实现的方式可能会导致越走越偏，考虑的越来越复杂，而耗费了几个小时的设计之后发现没有任何的实际进度。</p>
<p>如果是采用<code>TDD</code>的方式，下面的方式是一种可能的任务分解：</p>
<ol>
<li>输入一个非元音字符，并预期返回字符本身</li>
<li>输入一个元音，并预期返回<code>mommy</code></li>
<li>输入一个元音超过30%的字符串，并预期元音被替换</li>
<li>输入一个元音超过30%，并且存在连续元音的字符串，并预期只被替换一次</li>
</ol>
<p>当然，这个任务分解可能并不是<code>最好的</code>，但是是一个比较清晰的分解。</p>
<h3 id="实践">实践</h3>
<h4 id="第一个任务">第一个任务</h4>
<p>在本文中，我们将使用JavaScript来完成该功能的编写，测试框架采用了<a href="http://jasmine.github.io/2.0/introduction.html">Jasmine</a>，这里有一个<a href="https://github.com/abruzzi/tdd-boilerplate">模板项目</a>，使用它你可以快速的启动，并跟着本教程一起实践。</p>
<p>根据任务分解，我们编写的第一个测试是：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">describe</span><span class="p">(</span><span class="s2">&#34;mommify&#34;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
	<span class="nx">it</span><span class="p">(</span><span class="s2">&#34;should return h when given h&#34;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
		<span class="kd">var</span> <span class="nx">expected</span> <span class="o">=</span> <span class="s2">&#34;h&#34;</span><span class="p">;</span>

		<span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">mommify</span><span class="p">(</span><span class="s2">&#34;h&#34;</span><span class="p">);</span>

		<span class="nx">expect</span><span class="p">(</span><span class="nx">result</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="nx">expected</span><span class="p">);</span>
	<span class="p">});</span>
<span class="p">});</span>
</code></pre></div><p>这个测试中有三行代码，这也是一般测试的标准写法，简称<code>3A</code>：</p>
<ol>
<li>组织数据（Arrange）</li>
<li>执行需要被测的函数（Action）</li>
<li>验证结果（Assertion）</li>
</ol>
<p>运行这个测试，此时由于还没有实现代码，因此Jasmine会报告失败。接下来我们用最快速的方法来编写实现，就目前来看，最简单的方式就是：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">mommify</span><span class="p">()</span> <span class="p">{</span>
	<span class="k">return</span> <span class="s2">&#34;h&#34;</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>可能有人觉得这种实现太过狡猾，但是从<code>TDD</code>的角度来说，它确实能够令测试通过。这时候，我们需要编写另外一个测试来<code>驱动</code>出正确的行为：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">it</span><span class="p">(</span><span class="s2">&#34;should return m when given m&#34;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">expected</span> <span class="o">=</span> <span class="s2">&#34;m&#34;</span><span class="p">;</span>

    <span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">mommify</span><span class="p">(</span><span class="s2">&#34;m&#34;</span><span class="p">);</span>

    <span class="nx">expect</span><span class="p">(</span><span class="nx">result</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="nx">expected</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div><p>这样，我们的实现就不能仅仅返回一个&quot;h&quot;了，就现在来看，最简单的方式是输入什么就返回什么：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">mommify</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">return</span> <span class="nx">word</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>很好，这样我们的第一个<code>任务</code>已经完成了！我们已经经历了<code>失败-成功</code>的循环，这时候需要<code>review</code>一下代码，以保证代码是干净的：实现上来说，并没有可以优化的地方，但是我们发现两个测试用例其实测试的是同一件事情，因此可以删掉一个。</p>
<p>是的，测试代码也是代码，我们需要小心的维护它，以保证所有的代码都是干净的。</p>
<h4 id="第二个任务">第二个任务</h4>
<p>我们可以开始元音字母的子任务了，很容易想到的一个测试用例为：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">it</span><span class="p">(</span><span class="s2">&#34;should return mommy when given a&#34;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">expected</span> <span class="o">=</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>

    <span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">mommify</span><span class="p">(</span><span class="s2">&#34;a&#34;</span><span class="p">);</span>

    <span class="nx">expect</span><span class="p">(</span><span class="nx">result</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="nx">expected</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div><p>测试失败之后，能想到的最快速的方式是做一个简单的判断：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">mommify</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span><span class="p">(</span><span class="nx">word</span> <span class="o">==</span> <span class="s2">&#34;a&#34;</span><span class="p">)</span> <span class="p">{</span>
    	<span class="k">return</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>
    <span class="p">}</span>
	<span class="k">return</span> <span class="nx">word</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>这样测试又会通过，接下来就是重复5个元音的场景，不过使用JavaScript可以很容易的将这5个场景归为一组：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">it</span><span class="p">(</span><span class="s2">&#34;should return mommy when given a vowel&#34;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">expected</span> <span class="o">=</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>

	<span class="p">[</span><span class="s2">&#34;a&#34;</span><span class="p">,</span> <span class="s2">&#34;e&#34;</span><span class="p">,</span> <span class="s2">&#34;i&#34;</span><span class="p">,</span> <span class="s2">&#34;o&#34;</span><span class="p">,</span> <span class="s2">&#34;u&#34;</span><span class="p">].</span><span class="nx">forEach</span><span class="p">(</span><span class="kd">function</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	    <span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">mommify</span><span class="p">(</span><span class="nx">word</span><span class="p">);</span>
    	<span class="nx">expect</span><span class="p">(</span><span class="nx">result</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="nx">expected</span><span class="p">);</span>
    <span class="p">});</span>
<span class="p">});</span>
</code></pre></div><p>而实现则对一个的会变成（记住，用最简单的方式）：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">mommify</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span><span class="p">(</span><span class="nx">word</span> <span class="o">==</span> <span class="s2">&#34;a&#34;</span> <span class="o">||</span> <span class="nx">word</span> <span class="o">==</span> <span class="s2">&#34;e&#34;</span> <span class="o">||</span> <span class="nx">word</span> <span class="o">==</span> <span class="s2">&#34;i&#34;</span> <span class="o">||</span> <span class="nx">word</span> <span class="o">==</span> <span class="s2">&#34;o&#34;</span> <span class="o">||</span> <span class="nx">word</span> <span class="o">==</span> <span class="s2">&#34;u&#34;</span><span class="p">)</span> <span class="p">{</span>
    	<span class="k">return</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>
    <span class="p">}</span>
	<span class="k">return</span> <span class="nx">word</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>好了，测试通过了。又是进行重构的时间了，现在看看实现，简直不忍卒读，我们使用JavaScript的字符串的<code>indexOf</code>方法可以简化这段代码：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">mommify</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span><span class="p">(</span><span class="s2">&#34;aeiou&#34;</span><span class="p">.</span><span class="nx">indedOf</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
    	<span class="k">return</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>
    <span class="p">}</span>
	<span class="k">return</span> <span class="nx">word</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>好多了！我想你现在已经或多或少的体会到了<code>TDD</code>中<code>任务分解</code>的好处了：进度可以掌握，而且目标非常明确，每一步都有相应的产出。</p>
<h4 id="第三个任务">第三个任务</h4>
<p>和之前一样，我们还是从测试开始：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">it</span><span class="p">(</span><span class="s2">&#34;should mommify if the vowels greater than 30%&#34;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">expected</span> <span class="o">=</span> <span class="s2">&#34;shmommy&#34;</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">mommify</span><span class="p">(</span><span class="s2">&#34;she&#34;</span><span class="p">);</span>

    <span class="nx">expect</span><span class="p">(</span><span class="nx">result</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="nx">expected</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div><p>现在有一点点挑战了，因为我们的实现上一直都是单一的字符串，现在有多个了，不过没有关系，我们先按照最简单的方式来实现就对了：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">mommify</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>
	<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">word</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span><span class="p">(</span><span class="s2">&#34;aeiou&#34;</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">])</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
			<span class="nx">count</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="kd">var</span> <span class="nx">str</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>

	<span class="k">if</span><span class="p">(</span><span class="nx">count</span><span class="o">/</span><span class="nx">word</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;=</span> <span class="mf">0.30</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">word</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
			<span class="k">if</span><span class="p">(</span><span class="s2">&#34;aeiou&#34;</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">])</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
				<span class="nx">str</span> <span class="o">+=</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>
			<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
				<span class="nx">str</span> <span class="o">+=</span> <span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="nx">str</span> <span class="o">=</span> <span class="nx">word</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="nx">str</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>无论如何，测试通过了，我们首先计算了<code>元音</code>所占的比重，如果超过30%，则替换对应的字符，否则直接返回传入的字符串。</p>
<p>从现在来看，函数<code>mommify</code>中已经有了较多的逻辑，而且有一些重复的判断出现了（<code>&quot;aeuio&quot;.indedOf</code>），是时候做一些重构了。</p>
<p>首先将相对独立的计算元音比重的部分抽取成一个函数：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">countVowels</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">count</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span>

	<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">word</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span><span class="p">(</span><span class="s2">&#34;aeiou&#34;</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">])</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">)</span> <span class="p">{</span>
			<span class="nx">count</span> <span class="o">+=</span> <span class="mi">1</span><span class="p">;</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="nx">count</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>然后，将重复的<code>&quot;aeiou&quot;.indexOf</code>部分抽取为一个独立函数：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">isVowel</span><span class="p">(</span><span class="nx">character</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">return</span> <span class="s2">&#34;aeiou&#34;</span><span class="p">.</span><span class="nx">indexOf</span><span class="p">(</span><span class="nx">character</span><span class="p">)</span> <span class="o">&gt;=</span> <span class="mi">0</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>这样本来的代码就被简化成了：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">mommify</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">count</span> <span class="o">=</span> <span class="nx">countVowels</span><span class="p">(</span><span class="nx">word</span><span class="p">);</span>
	<span class="kd">var</span> <span class="nx">str</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>

	<span class="k">if</span><span class="p">(</span><span class="nx">count</span><span class="o">/</span><span class="nx">word</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;=</span> <span class="mf">0.30</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">word</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
			<span class="k">if</span><span class="p">(</span><span class="nx">isVowel</span><span class="p">(</span><span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">]))</span> <span class="p">{</span>
				<span class="nx">str</span> <span class="o">+=</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>
			<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
				<span class="nx">str</span> <span class="o">+=</span> <span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
			<span class="p">}</span>
		<span class="p">}</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="nx">str</span> <span class="o">=</span> <span class="nx">word</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="nx">str</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>如果细细读下来，就会发现发现对于元音是否超过30%的判断比较突兀，这里确实了一个<code>业务概念</code>，就是说，此处的<code>if</code>判断并不表意，更好的写法是讲它抽取为一个函数：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">shouldBeMommify</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">count</span> <span class="o">=</span> <span class="nx">countVowels</span><span class="p">(</span><span class="nx">word</span><span class="p">);</span>
	<span class="k">return</span> <span class="nx">count</span><span class="o">/</span><span class="nx">word</span><span class="p">.</span><span class="nx">length</span> <span class="o">&gt;=</span> <span class="mf">0.30</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>并且，替换元音的部分，我们也可以从主函数中挪出来，得到一个小函数：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js">
<span class="kd">function</span> <span class="nx">replace</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">str</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>

	<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">word</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span><span class="p">(</span><span class="nx">isVowel</span><span class="p">(</span><span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">]))</span> <span class="p">{</span>
			<span class="nx">str</span> <span class="o">+=</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>
		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
			<span class="nx">str</span> <span class="o">+=</span> <span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="nx">str</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>这样，主函数得到了进一步的简化：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">mommify</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="k">if</span><span class="p">(</span><span class="nx">shouldBeMommify</span><span class="p">(</span><span class="nx">word</span><span class="p">))</span> <span class="p">{</span>
		<span class="k">return</span> <span class="nx">replace</span><span class="p">(</span><span class="nx">word</span><span class="p">);</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="k">return</span> <span class="nx">word</span><span class="p">;</span>
	<span class="p">}</span>
<span class="p">}</span>
</code></pre></div><p>太好了，现在<code>mommify</code>就更加清晰了，并且每个抽取出来的函数都有了更具意义的名字，更清晰的职责。</p>
<h4 id="第四个任务">第四个任务</h4>
<p>经过了第三步，相信你已经对如何进行<code>TDD</code>有了很好的认识，而且也更有信心进行下一个任务了。同样，我们需要先编写测试用例：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="nx">it</span><span class="p">(</span><span class="s2">&#34;should not mommify if there are vowels sequences&#34;</span><span class="p">,</span> <span class="kd">function</span><span class="p">()</span> <span class="p">{</span>
    <span class="kd">var</span> <span class="nx">expected</span> <span class="o">=</span> <span class="s2">&#34;shmommyr&#34;</span><span class="p">;</span>
    <span class="kd">var</span> <span class="nx">result</span> <span class="o">=</span> <span class="nx">mommify</span><span class="p">(</span><span class="s2">&#34;shear&#34;</span><span class="p">);</span>

    <span class="nx">expect</span><span class="p">(</span><span class="nx">result</span><span class="p">).</span><span class="nx">toEqual</span><span class="p">(</span><span class="nx">expected</span><span class="p">);</span>
<span class="p">});</span>
</code></pre></div><p>现在的问题关键是需要判断一个字符串中的前一个是否元音，由于我们之前已经做了足够的重构，现在需要修改的函数就变成了<code>replace</code>子函数，而不是主入口<code>mommify</code>了：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">replace</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">str</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>

	<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">word</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="k">if</span><span class="p">(</span><span class="nx">isVowel</span><span class="p">(</span><span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">]))</span> <span class="p">{</span>
			<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">isVowel</span><span class="p">(</span><span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]))</span> <span class="p">{</span>
				<span class="nx">str</span> <span class="o">+=</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>
			<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
				<span class="nx">str</span> <span class="o">+=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>
			<span class="p">}</span>
		<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
			<span class="nx">str</span> <span class="o">+=</span> <span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">];</span>
		<span class="p">}</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="nx">str</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>测试通过之后，我们可以大胆的进行重构，抽取新的函数<code>next</code>：</p>
<div class="highlight"><pre class="chroma"><code class="language-js" data-lang="js"><span class="kd">function</span> <span class="nx">next</span><span class="p">(</span><span class="nx">current</span><span class="p">,</span> <span class="nx">previous</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">next</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>

	<span class="k">if</span><span class="p">(</span><span class="nx">isVowel</span><span class="p">(</span><span class="nx">current</span><span class="p">))</span> <span class="p">{</span>
		<span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="nx">isVowel</span><span class="p">(</span><span class="nx">previous</span><span class="p">))</span> <span class="p">{</span>
			<span class="nx">next</span> <span class="o">=</span> <span class="s2">&#34;mommy&#34;</span><span class="p">;</span>
		<span class="p">}</span>
	<span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
		<span class="nx">next</span> <span class="o">=</span> <span class="nx">current</span><span class="p">;</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="nx">next</span><span class="p">;</span>
<span class="p">}</span>

<span class="kd">function</span> <span class="nx">replace</span><span class="p">(</span><span class="nx">word</span><span class="p">)</span> <span class="p">{</span>
	<span class="kd">var</span> <span class="nx">str</span> <span class="o">=</span> <span class="s2">&#34;&#34;</span><span class="p">;</span>

	<span class="k">for</span><span class="p">(</span><span class="kd">var</span> <span class="nx">i</span> <span class="o">=</span> <span class="mi">0</span><span class="p">;</span> <span class="nx">i</span> <span class="o">&lt;</span> <span class="nx">word</span><span class="p">.</span><span class="nx">length</span><span class="p">;</span> <span class="nx">i</span><span class="o">++</span><span class="p">)</span> <span class="p">{</span>
		<span class="nx">str</span> <span class="o">+=</span> <span class="nx">next</span><span class="p">(</span><span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="p">],</span> <span class="nx">word</span><span class="p">[</span><span class="nx">i</span><span class="o">-</span><span class="mi">1</span><span class="p">]);</span>
	<span class="p">}</span>

	<span class="k">return</span> <span class="nx">str</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div><p>最后，如果你想看完整的/最新的代码，可以<a href="https://github.com/abruzzi/mommifier">在github上</a>找到。</p>
<h4 id="结束">结束（？）</h4>
<p>重构是一个永无止境的实践，你可以不断的抽取，简化，重组。比如上例中对于常量的使用，对于JavaScript中的for的使用等，都可以更进一步。但是你需要权衡，适可而止，如果不小心做的太过，则可能引起过渡设计：引入太过的概念，过于简化的接口等。</p>
<p><code>TDD</code>是一种容易付诸实践的开发方式，在小的，简单的例子上如此，在大的，复杂的场景下也是如此。它优美且高效的地方在于：不假设任何人可以一次就写出完善的应用，而是鼓励小步前进，快速反馈，快速迭代。而演化到最后，得到的往往就是孜孜以求的优美设计。</p>
]]></content:encoded>
    </item>
    
    <item>
      <title>Interllij里的测试驱动开发</title>
      <link>https://icodeit.org/2012/10/simplified-tdd-by-using-interllij/</link>
      <pubDate>Mon, 15 Oct 2012 00:00:00 +0000</pubDate>
      
      <guid>https://icodeit.org/2012/10/simplified-tdd-by-using-interllij/</guid>
      <description>In my last post, I mentioned to how to setup a intellij project by using gradle. and today we are going to talk about how to using intellij to write a demo java project from scratch(right after the gradle idea command).
To begin with TDD in java, we need some packages for that:
 junit hamcrest  Let&amp;rsquo;s all of those dependencies in build.gradle:
repositories { mavenCentral() } dependencies { testCompile &amp;#39;junit:junit:4.</description>
      <content:encoded><![CDATA[<p>In my last <a href="">post</a>, I mentioned to how to setup a intellij project by using gradle. and today we are going to talk about how to using intellij to write a demo java project from scratch(right after the <em>gradle idea</em> command).</p>
<p>To begin with TDD in java, we need some packages for that:</p>
<ul>
<li>junit</li>
<li>hamcrest</li>
</ul>
<p>Let&rsquo;s all of those dependencies in build.gradle:</p>
<div class="highlight"><pre class="chroma"><code class="language-groovy" data-lang="groovy">    <span class="n">repositories</span> <span class="o">{</span>
        <span class="n">mavenCentral</span><span class="o">()</span>
    <span class="o">}</span>

    <span class="n">dependencies</span> <span class="o">{</span>
        <span class="n">testCompile</span> <span class="s1">&#39;junit:junit:4.8.2&#39;</span>
        <span class="n">testCompile</span> <span class="s1">&#39;org.hamcrest:hamcrest-core:1.2.1&#39;</span>
    <span class="o">}</span>
</code></pre></div><p>and rerun the <em>gradle idea</em> command.</p>
<p>After intellij .ipr file generated, we can open it by intellij, and then create a project, let&rsquo;s say the basic structure of the project is like this:</p>
<pre><code>└── src
    ├── main
    │   ├── java
    │   │   └── org
    │   │       └── icodeit
    │   │           └── library
    │   │               ├── Book.java
    │   │               └── Library.java
    │   └── resources
    └── test
        ├── java
        │   └── org
        │       └── icodeit
        │           └── library
        │               ├── BookTest.java
        │               └── LibraryTest.java
        └── resources
</code></pre>
<p>Basically, we are going to build a simple library which allow user to add/borrow/return books to/from.</p>
<p>We simply devide it to the following tasks:</p>
<ul>
<li>User can add book to library</li>
<li>User can get all books in a specific category</li>
<li>User can know how many books left in library</li>
<li>User can borrow book from library</li>
<li>User can return book when he/she finished</li>
<li>User can be told whether there are books he/she want left in library</li>
</ul>
<p>Let&rsquo;s do it step by step, by following the TDD way. Of course, we need to add tests at vert first:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java">    <span class="nd">@Test</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">shouldAddBookToLibrary</span><span class="o">(){</span>
        <span class="n">Library</span> <span class="n">library</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Library</span><span class="o">();</span>
        <span class="n">Book</span> <span class="n">book</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Book</span><span class="o">(</span><span class="s">&#34;The ruby programming language&#34;</span><span class="o">,</span> <span class="s">&#34;Development&#34;</span><span class="o">);</span>
        <span class="n">library</span><span class="o">.</span><span class="na">addBook</span><span class="o">(</span><span class="n">book</span><span class="o">);</span>

        <span class="n">assertThat</span><span class="o">(</span><span class="n">library</span><span class="o">.</span><span class="na">getTotalBookNumber</span><span class="o">(),</span> <span class="n">is</span><span class="o">(</span><span class="n">1</span><span class="o">));</span>
    <span class="o">}</span>
</code></pre></div><p>This is a test used for test add book functionality, after the addition, we can tell by invoke <em>getTotalBookNumber</em> method (Of course, we need to make sure the project can be compiled, just add a new class Book.java and some fake methods in the Library.java). So, first we run the test (<em>Ctrl-Shift-F10</em>), and the test will fail.</p>
<p>Then we add the implementation of those functionalities:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java">    <span class="kd">public</span> <span class="kd">class</span> <span class="nc">Library</span> <span class="o">{</span>
        <span class="kd">private</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">Book</span><span class="o">&gt;</span> <span class="n">books</span><span class="o">;</span>

        <span class="kd">public</span> <span class="nf">Library</span><span class="o">()</span> <span class="o">{</span>
            <span class="n">books</span> <span class="o">=</span> <span class="k">new</span> <span class="n">LinkedList</span><span class="o">&lt;</span><span class="n">Book</span><span class="o">&gt;();</span>
        <span class="o">}</span>
        <span class="c1">//...
</span><span class="c1"></span>    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">addBook</span><span class="o">(</span><span class="n">Book</span> <span class="n">book</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">books</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">book</span><span class="o">);</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getTotalBookNumber</span><span class="o">()</span> <span class="o">{</span>
        <span class="k">return</span> <span class="n">books</span><span class="o">.</span><span class="na">size</span><span class="o">();</span>
    <span class="o">}</span>
</code></pre></div><p>Now we can get a green test. TDD is in a form of &ldquo;Red-Green-Refactor&rdquo;, so far we&rsquo;ve got nothing to refactor, let&rsquo;s add one more test:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java">    <span class="nd">@Test</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">shouldGetBooksByCategory</span><span class="o">(){</span>
        <span class="n">Library</span> <span class="n">library</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Library</span><span class="o">();</span>
        <span class="n">Book</span> <span class="n">book1</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Book</span><span class="o">(</span><span class="s">&#34;The ruby programming language&#34;</span><span class="o">,</span> <span class="s">&#34;Development&#34;</span><span class="o">);</span>
        <span class="n">Book</span> <span class="n">book2</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Book</span><span class="o">(</span><span class="s">&#34;The python programming language&#34;</span><span class="o">,</span> <span class="s">&#34;Development&#34;</span><span class="o">);</span>
        <span class="n">Book</span> <span class="n">book3</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Book</span><span class="o">(</span><span class="s">&#34;The lean startup&#34;</span><span class="o">,</span> <span class="s">&#34;Business&#34;</span><span class="o">);</span>

        <span class="n">library</span><span class="o">.</span><span class="na">addBook</span><span class="o">(</span><span class="n">book1</span><span class="o">);</span>
        <span class="n">library</span><span class="o">.</span><span class="na">addBook</span><span class="o">(</span><span class="n">book2</span><span class="o">);</span>
        <span class="n">library</span><span class="o">.</span><span class="na">addBook</span><span class="o">(</span><span class="n">book3</span><span class="o">);</span>

        <span class="n">assertThat</span><span class="o">(</span><span class="n">library</span><span class="o">.</span><span class="na">getBookByCategory</span><span class="o">(</span><span class="s">&#34;Development&#34;</span><span class="o">).</span><span class="na">size</span><span class="o">(),</span> <span class="n">is</span><span class="o">(</span><span class="n">2</span><span class="o">));</span>
    <span class="o">}</span>
</code></pre></div><p>Then the implementation:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java">    <span class="kd">public</span> <span class="n">List</span><span class="o">&lt;</span><span class="n">Book</span><span class="o">&gt;</span> <span class="nf">getBookByCategory</span><span class="o">(</span><span class="n">String</span> <span class="n">category</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">List</span><span class="o">&lt;</span><span class="n">Book</span><span class="o">&gt;</span> <span class="n">grouped</span> <span class="o">=</span> <span class="k">new</span> <span class="n">LinkedList</span><span class="o">&lt;</span><span class="n">Book</span><span class="o">&gt;();</span>
        <span class="k">for</span><span class="o">(</span><span class="n">Book</span> <span class="n">book</span> <span class="o">:</span> <span class="n">books</span><span class="o">){</span>
            <span class="k">if</span><span class="o">(</span><span class="n">book</span><span class="o">.</span><span class="na">getCategory</span><span class="o">().</span><span class="na">equals</span><span class="o">(</span><span class="n">category</span><span class="o">)){</span>
                <span class="n">grouped</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">book</span><span class="o">);</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">grouped</span><span class="o">;</span>
    <span class="o">}</span>
</code></pre></div><p>And what if the logic cames more complex, say:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java">    <span class="nd">@Test</span>
    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">shouldCanReturnBookToLibrary</span><span class="o">(){</span>
        <span class="n">Library</span> <span class="n">library</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Library</span><span class="o">();</span>
        <span class="n">Book</span> <span class="n">originBook</span> <span class="o">=</span> <span class="k">new</span> <span class="n">Book</span><span class="o">(</span><span class="s">&#34;The ruby programming language&#34;</span><span class="o">,</span> <span class="s">&#34;Development&#34;</span><span class="o">);</span>
        <span class="n">library</span><span class="o">.</span><span class="na">addBook</span><span class="o">(</span><span class="n">originBook</span><span class="o">);</span>
        
        <span class="n">assertThat</span><span class="o">(</span><span class="n">library</span><span class="o">.</span><span class="na">getBookCount</span><span class="o">(</span><span class="s">&#34;The ruby programming language&#34;</span><span class="o">),</span> <span class="n">is</span><span class="o">(</span><span class="n">1</span><span class="o">));</span>
        
        <span class="n">Book</span> <span class="n">borrowed</span> <span class="o">=</span> <span class="n">library</span><span class="o">.</span><span class="na">borrowBook</span><span class="o">(</span><span class="s">&#34;The ruby programming language&#34;</span><span class="o">);</span>
        
        <span class="n">assertThat</span><span class="o">(</span><span class="n">library</span><span class="o">.</span><span class="na">getBookCount</span><span class="o">(</span><span class="s">&#34;The ruby programming language&#34;</span><span class="o">),</span> <span class="n">is</span><span class="o">(</span><span class="n">0</span><span class="o">));</span>
        
        <span class="n">library</span><span class="o">.</span><span class="na">returnBook</span><span class="o">(</span><span class="n">borrowed</span><span class="o">);</span>

        <span class="n">assertThat</span><span class="o">(</span><span class="n">library</span><span class="o">.</span><span class="na">getBookCount</span><span class="o">(</span><span class="s">&#34;The ruby programming language&#34;</span><span class="o">),</span> <span class="n">is</span><span class="o">(</span><span class="n">1</span><span class="o">));</span>
    <span class="o">}</span>
</code></pre></div><p>When user borrowed a book from library, others can not borrow it any more of course, until the previous user return it back.</p>
<p>We can tell the specification by reading the test itself, and we don&rsquo;t care about the code in this prespective. On the other hand, when we try to implement the logic, we can focus on the small piece of code and get it done:</p>
<div class="highlight"><pre class="chroma"><code class="language-java" data-lang="java">    <span class="kd">public</span> <span class="kt">int</span> <span class="nf">getBookCount</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
        <span class="kt">int</span> <span class="n">bookCount</span> <span class="o">=</span> <span class="n">0</span><span class="o">;</span>
        <span class="k">for</span><span class="o">(</span><span class="n">Book</span> <span class="n">book</span> <span class="o">:</span> <span class="n">books</span><span class="o">){</span>
            <span class="k">if</span><span class="o">(</span><span class="n">book</span><span class="o">.</span><span class="na">getName</span><span class="o">().</span><span class="na">equals</span><span class="o">(</span><span class="n">name</span><span class="o">)){</span>
                <span class="n">bookCount</span><span class="o">++;</span>
            <span class="o">}</span>
        <span class="o">}</span>
        <span class="k">return</span> <span class="n">bookCount</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="n">Book</span> <span class="nf">borrowBook</span><span class="o">(</span><span class="n">String</span> <span class="n">name</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">Book</span> <span class="n">book</span> <span class="o">=</span> <span class="kc">null</span><span class="o">;</span>

        <span class="k">if</span> <span class="o">(</span><span class="n">getBookCount</span><span class="o">(</span><span class="n">name</span><span class="o">)</span> <span class="o">==</span> <span class="n">0</span><span class="o">)</span> <span class="o">{</span>
            <span class="k">return</span> <span class="kc">null</span><span class="o">;</span>
        <span class="o">}</span>

        <span class="k">for</span> <span class="o">(</span><span class="kt">int</span> <span class="n">i</span> <span class="o">=</span> <span class="n">0</span><span class="o">;</span> <span class="n">i</span> <span class="o">&lt;</span> <span class="n">books</span><span class="o">.</span><span class="na">size</span><span class="o">();</span> <span class="n">i</span><span class="o">++)</span> <span class="o">{</span>
            <span class="k">if</span> <span class="o">(</span><span class="n">books</span><span class="o">.</span><span class="na">get</span><span class="o">(</span><span class="n">i</span><span class="o">).</span><span class="na">getName</span><span class="o">().</span><span class="na">equals</span><span class="o">(</span><span class="n">name</span><span class="o">))</span> <span class="o">{</span>
                <span class="n">book</span> <span class="o">=</span> <span class="n">books</span><span class="o">.</span><span class="na">remove</span><span class="o">(</span><span class="n">i</span><span class="o">);</span>
                <span class="k">break</span><span class="o">;</span>
            <span class="o">}</span>
        <span class="o">}</span>

        <span class="k">return</span> <span class="n">book</span><span class="o">;</span>
    <span class="o">}</span>

    <span class="kd">public</span> <span class="kt">void</span> <span class="nf">returnBook</span><span class="o">(</span><span class="n">Book</span> <span class="n">book</span><span class="o">)</span> <span class="o">{</span>
        <span class="n">books</span><span class="o">.</span><span class="na">add</span><span class="o">(</span><span class="n">book</span><span class="o">);</span>
    <span class="o">}</span>
</code></pre></div><p>As you can see, the princple is really easy to follow:</p>
<ul>
<li>Tasking (spearate the goal to some smaller parts)</li>
<li>Testing</li>
<li>Coding</li>
<li>Refactoring</li>
</ul>
<p>The benefit is obverisly: there is no isolated code any more. Actually, the shorter of the code, the cleaner it will be.</p>
]]></content:encoded>
    </item>
    
  </channel>
</rss>
