<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>IDEAL Garden &#187; Tech</title>
	<atom:link href="http://www.zhangkf.com/category/tech/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.zhangkf.com</link>
	<description></description>
	<lastBuildDate>Mon, 16 Jan 2012 14:02:17 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Team的一次Code Kata</title>
		<link>http://www.zhangkf.com/2012/01/code-kata/</link>
		<comments>http://www.zhangkf.com/2012/01/code-kata/#comments</comments>
		<pubDate>Mon, 16 Jan 2012 14:02:17 +0000</pubDate>
		<dc:creator>zhangkf</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[TW]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[pair programming]]></category>
		<category><![CDATA[TDD]]></category>
		<category><![CDATA[ThoughtBlogs]]></category>

		<guid isPermaLink="false">http://www.zhangkf.com/?p=1127</guid>
		<description><![CDATA[上周四的中午饭后，我们team坐下来完成了一次Code Kata练习。跟之前的几次邀请PwC team同事过来pair和coach不同，这次是我们组自己内部完成一次练习，题目来自Yuheng之前的一个练习：文曲星上的猜数字游戏。 题目规则很简单： 游戏开始后，系统会随机给出四个不重复的数字。由用户输入自己猜测的四个数字。 如果数字猜对而且位置也对，就是1一个A。 如果数字猜对但位置不对，就是一个B。 返回结果是如“2A1B”这样的字串。 猜错6次，游戏提示结束。重来。 开始提出的要求简单：用TDD驱动出实际代码。 大家抽签后开始pair，Yuheng还会一边计时一边催促，pair的气氛基本保持紧张有序。 在我和XuChen pair开始代码后，我们很容易写出第一个测试1，期望返回结果是&#8221;4A0B&#8221;，最简单的代码实现让测试变绿。 当我们试图写下第二个测试2，试图期望返回结果是“2A1B”时，我们发现不得不面对如何这个游戏规则的最核心算法，但可惜的是，猛然间对这个算法没有头绪。 局面一时僵住，停顿了有两分钟。 直觉和一点经验告诉我们，这时该拆解任务了。很容易想到，如果计算出几个A和几个B是很直白的拆分。 我们可以很容易写出一个测试3，测试猜测的四个数字跟事先给定的四个数字相比，有几个A类数字（循环比较），我们称之为perfect number。 也很容易写出另外一个测试4，测试猜测的四个数字跟事先给定的四个数字相比，有几个B类数字（在上个算法的基础上再循环比较），我们称之为good number。 写完针对测试3和4的实现代码，我们发现我们已经完成了最基本的算法，功能完成了。剩下的是重构代码。 从我们这次的经验看，我有一些收获和心得： 测试就是代码的设计，你看测试3和4导致的结果就是我们有了对应的两个计算方法。你打算怎么测，你的实现代码就会是怎样的。 印证了在Wikipedia中那段话，pair programming尤其适合面对一些challenging的任务（至少开始的时候是）。 分解任务是王道。我们在不同的level拆分任务，从story拆分成task，从大问题拆分成小问题，莫不如是。 囿于经验，不期望由端到端的测试能逐步甚至一下子推导出完整、完善的代码实现。而这样的练习，恰恰是我们锻造自己经验必不可少的过程。 我们在实现代码时，仍然欠缺的是： 对于测试方法名的命名，不够清晰直白。 对于算法代码的实现，简单粗糙，还需要重构。]]></description>
			<content:encoded><![CDATA[<p>上周四的中午饭后，我们team坐下来完成了一次Code Kata练习。跟之前的几次邀请PwC team同事过来pair和coach不同，这次是我们组自己内部完成一次练习，题目来自Yuheng之前的一个练习：文曲星上的猜数字游戏。</p>
<p>题目规则很简单：</p>
<ol>
<li>游戏开始后，系统会随机给出四个不重复的数字。由用户输入自己猜测的四个数字。</li>
<li>如果数字猜对而且位置也对，就是1一个A。</li>
<li>如果数字猜对但位置不对，就是一个B。</li>
<li>返回结果是如“2A1B”这样的字串。</li>
<li>猜错6次，游戏提示结束。重来。</li>
</ol>
<p>开始提出的要求简单：用TDD驱动出实际代码。</p>
<p>大家抽签后开始pair，Yuheng还会一边计时一边催促，pair的气氛基本保持紧张有序。</p>
<p>在我和XuChen pair开始代码后，我们很容易写出第一个测试1，期望返回结果是&#8221;4A0B&#8221;，最简单的代码实现让测试变绿。</p>
<p>当我们试图写下第二个测试2，试图期望返回结果是“2A1B”时，我们发现不得不面对如何这个游戏规则的最核心算法，但可惜的是，猛然间对这个算法没有头绪。</p>
<p>局面一时僵住，停顿了有两分钟。</p>
<p>直觉和一点经验告诉我们，这时该拆解任务了。很容易想到，如果计算出几个A和几个B是很直白的拆分。</p>
<p>我们可以很容易写出一个测试3，测试猜测的四个数字跟事先给定的四个数字相比，有几个A类数字（循环比较），我们称之为perfect number。</p>
<p>也很容易写出另外一个测试4，测试猜测的四个数字跟事先给定的四个数字相比，有几个B类数字（在上个算法的基础上再循环比较），我们称之为good number。</p>
<p>写完针对测试3和4的实现代码，我们发现我们已经完成了最基本的算法，功能完成了。剩下的是重构代码。</p>
<p>从我们这次的经验看，我有一些收获和心得：</p>
<ol>
<li>测试就是代码的设计，你看测试3和4导致的结果就是我们有了对应的两个计算方法。你打算怎么测，你的实现代码就会是怎样的。</li>
<li>印证了在Wikipedia中那段话，pair programming尤其适合面对一些challenging的任务（至少开始的时候是）。</li>
<li>分解任务是王道。我们在不同的level拆分任务，从story拆分成task，从大问题拆分成小问题，莫不如是。</li>
<li>囿于经验，不期望由端到端的测试能逐步甚至一下子推导出完整、完善的代码实现。而这样的练习，恰恰是我们锻造自己经验必不可少的过程。</li>
</ol>
<p>我们在实现代码时，仍然欠缺的是：</p>
<ol>
<li>对于测试方法名的命名，不够清晰直白。</li>
<li>对于算法代码的实现，简单粗糙，还需要重构。</li>
</ol>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2012/01/code-kata/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>本地搭建SVN服务</title>
		<link>http://www.zhangkf.com/2011/12/play-with-svn/</link>
		<comments>http://www.zhangkf.com/2011/12/play-with-svn/#comments</comments>
		<pubDate>Tue, 06 Dec 2011 14:09:31 +0000</pubDate>
		<dc:creator>zhangkf</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[SVN]]></category>

		<guid isPermaLink="false">http://www.zhangkf.com/?p=1105</guid>
		<description><![CDATA[别看用起SVN很熟，每天commit、revert很欢，真要自己在Mac上搭起来个SVN server，本地可以checkout，创建branch，merge，就没那么熟悉了。 查了查资料，过程如下： 1. 创建本地repo localhost:~ twer$ cd localhost:~ twer$ svnadmin create SVNRepo 2. 修改两个conf文件，打开访问权限，并添加授权用户 localhost:~ twer$ cd SVNRepo/ localhost:SVNRepo twer$ edit conf/svnserve.conf localhost:SVNRepo twer$ edit conf/passwd 3. 创建trunk目录 localhost:SVNRepo twer$ svn mkdir file:///Users/twer/SVNRepo/trunk -m "create trunk" 4. 创建测试文件，并import到trunk localhost:SVNRepo &#8230; <a href="http://www.zhangkf.com/2011/12/play-with-svn/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>别看用起SVN很熟，每天commit、revert很欢，真要自己在Mac上搭起来个SVN server，本地可以checkout，创建branch，merge，就没那么熟悉了。</p>
<p>查了查资料，过程如下：</p>
<p>1. 创建本地repo</p>
<pre>localhost:~ twer$ cd
localhost:~ twer$ svnadmin create SVNRepo</pre>
<p>2. 修改两个conf文件，打开访问权限，并添加授权用户</p>
<pre>localhost:~ twer$ cd SVNRepo/
localhost:SVNRepo twer$ edit conf/svnserve.conf
localhost:SVNRepo twer$ edit conf/passwd</pre>
<p>3. 创建trunk目录</p>
<pre>localhost:SVNRepo twer$ svn mkdir file:///Users/twer/SVNRepo/trunk -m "create trunk"</pre>
<p>4. 创建测试文件，并import到trunk</p>
<pre>localhost:SVNRepo twer$ touch test.file
localhost:SVNRepo twer$ edit test.file
localhost:~ twer$ svn import test.file file:///Users/twer/SVNRepo/trunk/test.file -m"import file"</pre>
<p>5. 启动svn server</p>
<pre>localhost:~ twer$ cd SVNRepo
localhost:SVNRepo twer$ svnserve -d</pre>
<p>6. 转移到working directory，checkout trunk</p>
<pre>localhost:working_dir twer$ svn checkout svn://localhost/Users/twer/SVNRepo/trunk trunk</pre>
<p>7. 新建branch</p>
<pre>localhost:SVNRepo twer$ svn copy svn://localhost/Users/twer/SVNRepo/trunk svn://localhost/Users/twer/SVNRepo/branch -m"create branch"</pre>
<p>8. checkout branch到新的branch目录</p>
<pre>localhost:working_dir twer$ svn checkout svn://localhost/Users/twer/SVNRepo/branch branch</pre>
<p>9. 修改test文件，提交</p>
<pre>localhost:branch twer$ edit test.file
localhost:branch twer$ svn ci -m"change test.file"</pre>
<p>10. 回到trunk目录，merge branch的变化</p>
<pre>localhost:trunk twer$ svn merge svn://localhost/Users/twer/SVNRepo/branch</pre>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2011/12/play-with-svn/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Mock, Stub, Fake</title>
		<link>http://www.zhangkf.com/2011/09/mock-stub-fake/</link>
		<comments>http://www.zhangkf.com/2011/09/mock-stub-fake/#comments</comments>
		<pubDate>Sat, 10 Sep 2011 14:01:43 +0000</pubDate>
		<dc:creator>zhangkf</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[mock]]></category>
		<category><![CDATA[stub]]></category>
		<category><![CDATA[test]]></category>
		<category><![CDATA[ThoughtBlogs]]></category>

		<guid isPermaLink="false">http://www.zhangkf.com/?p=1089</guid>
		<description><![CDATA[上次郑晔给大家做游戏，徐昊问到台上的咨询师，Mock、Stub和Fake的区别是什么？ 自己虽然心里有点印象，但还是下来搜了一下： Wikipedia的解释是这样： Some authors[1] draw a distinction between fake and mock objects. Fakes are the simpler of the two, simply implementing the same interface as the object that they represent and returning pre-arranged responses. Thus a fake object merely provides a set of method stubs. &#8230; <a href="http://www.zhangkf.com/2011/09/mock-stub-fake/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>上次郑晔给大家做游戏，徐昊问到台上的咨询师，Mock、Stub和Fake的区别是什么？ 自己虽然心里有点印象，但还是下来搜了一下： <a href="http://en.wikipedia.org/wiki/Mock_object#Mocks.2C_fakes_and_stubs">Wikipedia</a>的解释是这样：</p>
<blockquote><p>Some authors<sup id="cite_ref-0"><a href="http://en.wikipedia.org/wiki/Mock_object#cite_note-0">[1]</a></sup> draw a distinction between <em>fake</em> and <em>mock</em> objects. Fakes are the simpler of the two, simply implementing the same interface as the object that they represent and returning pre-arranged responses. Thus a fake object merely provides a set of <a title="Method stub" href="http://en.wikipedia.org/wiki/Method_stub">method stubs</a>. In the book &#8220;The Art of Unit Testing&#8221;<sup id="cite_ref-1"><a href="http://en.wikipedia.org/wiki/Mock_object#cite_note-1">[2]</a></sup> mocks are described as a fake object that helps decide if a test failed or passed, by verifying if an interaction on an object occurred or not. Everything else is defined as a stub. In that book, &#8220;Fakes&#8221; are anything that is not real. Based on their usage, they are either stubs or mocks. Mock objects in this sense do a little more: their method implementations contain <a title="Assertion (computing)" href="http://en.wikipedia.org/wiki/Assertion_(computing)">assertions</a> of their own. This means that a true mock, in this sense, will examine the context of each call— perhaps checking the order in which its methods are called, perhaps performing tests on the data passed into the method calls as arguments.</p></blockquote>
<p>这里还有<a href="http://stackoverflow.com/questions/346372/whats-the-difference-between-faking-mocking-and-stubbing">StackOverFlow的回答</a>。 扩展阅读：</p>
<ul>
<li><a href="http://www.infoq.com/cn/articles/thoughtworks-practice-partvi">Mock不是测试的银弹</a>，胡凯，InfoQ</li>
<li><a href="http://news.csdn.net/n/20060726/93003.html">不要把Mock当作你的设计利器</a>，李晓，CSDN</li>
<li><a href="http://martinfowler.com/articles/mocksArentStubs.html">Mocks Aren&#8217;t Stubs</a>，Martin Fowler</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2011/09/mock-stub-fake/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>DevOps之Puppet</title>
		<link>http://www.zhangkf.com/2011/05/devops-puppet/</link>
		<comments>http://www.zhangkf.com/2011/05/devops-puppet/#comments</comments>
		<pubDate>Sat, 28 May 2011 04:56:35 +0000</pubDate>
		<dc:creator>zhangkf</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[TW]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[puppet]]></category>

		<guid isPermaLink="false">http://kfzhang.thoughtworkers.org/?p=1057</guid>
		<description><![CDATA[Puppet在一款自动化系统配置管理的工具，它可以让你在很短的时间内对大量硬件和系统基本类似的系统，进行统一的系统配置管理。 说的简单点，就像开网吧，你需要对网吧的每一台机器安装操作系统，配置完全一样的软件，比如QQ和360，供网友上网，在系统和软件有损坏时，很简单的一个恢复操作就可以让机器回到刚刚安装好操作系统和软件的状态。 Puppet就是可以干这个事儿的，不同在于，Puppet是给网络管理员用的，而针对的系统多是*nix系统，因为Puppet目前对Windows支持的很少，但这不妨碍Puppet成为DevOps实现过程中的利器，另外一个类似的工具是Chef。 Puppet本身基于Ruby实现，但即使没有Ruby的经验也没甚大碍。Puppet自己提出了所谓Puppet Language，是一种DSL（Domain Specific Language）语言，用直白而描述性的语言，定义系统应该具有的状态，比如一个简单的例子tmpfile.pp： file { 'testfile': path =&#62; '/tmp/testfile',     ensure =&#62; present,     mode =&#62; 0640,     content =&#62; "I'm a test file.", } 在安装了Puppet了机器上运行： puppet apply tmpfile.pp 结果就会在/tmp下新增加一个testfile，内容是This is a test &#8230; <a href="http://www.zhangkf.com/2011/05/devops-puppet/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p><a href="http://projects.puppetlabs.com/projects/puppet" target="_blank">Puppet</a>在一款自动化系统配置管理的工具，它可以让你在很短的时间内对大量硬件和系统基本类似的系统，进行统一的系统配置管理。</p>
<p>说的简单点，就像开网吧，你需要对网吧的每一台机器安装操作系统，配置完全一样的软件，比如QQ和360，供网友上网，在系统和软件有损坏时，很简单的一个恢复操作就可以让机器回到刚刚安装好操作系统和软件的状态。</p>
<p>Puppet就是可以干这个事儿的，不同在于，Puppet是给网络管理员用的，而针对的系统多是*nix系统，因为Puppet目前对Windows支持的很少，但这不妨碍Puppet成为DevOps实现过程中的利器，另外一个类似的工具是<a href="http://en.wikipedia.org/wiki/Chef_(software)" target="_blank">Chef</a>。</p>
<p>Puppet本身基于Ruby实现，但即使没有Ruby的经验也没甚大碍。Puppet自己提出了所谓Puppet Language，是一种DSL（Domain Specific Language）语言，用直白而描述性的语言，定义系统应该具有的状态，比如一个简单的例子tmpfile.pp：</p>
<pre>file { 'testfile':
    path =&gt; '/tmp/testfile',
    ensure  =&gt; present,
    mode    =&gt; 0640,
    content =&gt; "I'm a test file.",
}</pre>
<p>在安装了Puppet了机器上运行：</p>
<pre>puppet apply tmpfile.pp</pre>
<p>结果就会在/tmp下新增加一个testfile，内容是This is a test file。<br />
这个例子太简单。除了file这种类型外，Puppet提供了<a href="http://projects.puppetlabs.com/projects/puppet/wiki/Core_Types_Cheat_Sheet/" target="_blank">大量的资源类型</a>，供对系统的状态进行描述，比如打开（如果不存在会自动下载）某项服务，自动增加一个用户。当管理的机器成百上千，这样的自动化服务达到的效果就很可观了。</p>
<p>puppet apply是Puppet在单机上运行和测试的工具，真实的使用情景会是，一台机器（master）专门保留所有机器配置管理的状态信息，而每台机器（agent）会在指定的时间向master发起查询，从而更新自己的系统状态，以期与指定状态保持一致。</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2011/05/devops-puppet/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>IFrame带来的Session问题</title>
		<link>http://www.zhangkf.com/2011/05/session-timeout-in-iframe/</link>
		<comments>http://www.zhangkf.com/2011/05/session-timeout-in-iframe/#comments</comments>
		<pubDate>Wed, 18 May 2011 15:04:04 +0000</pubDate>
		<dc:creator>zhangkf</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[IAS]]></category>
		<category><![CDATA[iframe]]></category>
		<category><![CDATA[ThoughtBlogs]]></category>

		<guid isPermaLink="false">http://kfzhang.thoughtworkers.org/?p=1023</guid>
		<description><![CDATA[客户原来有个Web App系统A，我们要基于A开发一个系统B，但不希望B对A依赖太重，所以B被实现为一个独立的Web App（war）。A和B部署在同一个Weblogic server上，在A中可以导航到B，两个系统看起来像是一个系统。 有个小需求是，在B中希望显示一个页面，根据参数能展示出不同的信息。这个页面在A中已经存在，所以自然而然最快的方法就是在B中创建一个iframe来指向那个A中的页面，配以不同的参数，多快好省！ 问题很快出来了，QA发现那个iframe中的A页面很快就会session timeout，然后会提示用户输入登陆用户名和密码，而iframe外的B session并未过期的。 问题在于A和B实际上还是两个Web App，各自有各自的session。因为不能简单地修改A的页面，让它保持session不会timeout，所以剩下的办法只好是控制B的session timeout时间要早于A了。还有什么更优雅的方法呢？ 如果给我一次重新实现的机会，我宁愿自己画一个属于B的页面，而扔掉iframe。 另外一个需求是，A和B是各自独立的Web App对于用户是透明的，用A的用户登陆进来可以直接进入B，反之则不可以。解决办法有点tricky，A的contextRoot设为/，B的contextRoot设为/XXX，这样二者的servletContext为同一个，即可实现A把自己的loginToken放到servletContext中后由B访问到，从而在请求B页面时，检查是否能取到servletContext中的loginToken，如果不能则转向到A的登陆页面，这点由Filter来实现。]]></description>
			<content:encoded><![CDATA[<p>客户原来有个Web App系统A，我们要基于A开发一个系统B，但不希望B对A依赖太重，所以B被实现为一个独立的Web App（war）。A和B部署在同一个Weblogic server上，在A中可以导航到B，两个系统看起来像是一个系统。</p>
<p>有个小需求是，在B中希望显示一个页面，根据参数能展示出不同的信息。这个页面在A中已经存在，所以自然而然最快的方法就是在B中创建一个iframe来指向那个A中的页面，配以不同的参数，多快好省！</p>
<p>问题很快出来了，QA发现那个iframe中的A页面很快就会session timeout，然后会提示用户输入登陆用户名和密码，而iframe外的B session并未过期的。</p>
<p>问题在于A和B实际上还是两个Web App，各自有各自的session。因为不能简单地修改A的页面，让它保持session不会timeout，所以剩下的办法只好是控制B的session timeout时间要早于A了。还有什么更优雅的方法呢？</p>
<p>如果给我一次重新实现的机会，我宁愿自己画一个属于B的页面，而扔掉iframe。</p>
<p>另外一个需求是，A和B是各自独立的Web App对于用户是透明的，用A的用户登陆进来可以直接进入B，反之则不可以。解决办法有点tricky，A的contextRoot设为/，B的contextRoot设为/XXX，这样二者的servletContext为同一个，即可实现A把自己的loginToken放到servletContext中后由B访问到，从而在请求B页面时，检查是否能取到servletContext中的loginToken，如果不能则转向到A的登陆页面，这点由Filter来实现。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2011/05/session-timeout-in-iframe/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>this in Selenium&#8217;s get_eval() method</title>
		<link>http://www.zhangkf.com/2011/05/this-in-get_eval/</link>
		<comments>http://www.zhangkf.com/2011/05/this-in-get_eval/#comments</comments>
		<pubDate>Tue, 10 May 2011 15:52:12 +0000</pubDate>
		<dc:creator>zhangkf</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[selenium]]></category>

		<guid isPermaLink="false">http://kfzhang.thoughtworkers.org/?p=1003</guid>
		<description><![CDATA[At Selenium Ruby site, there is a description for method get_eval(script), as following: Gets the result of evaluating the specified JavaScript snippet. The snippet may have multiple lines, but only the result of the last line will be returned. Note &#8230; <a href="http://www.zhangkf.com/2011/05/this-in-get_eval/">Continue reading <span class="meta-nav">&#8594;</span></a>]]></description>
			<content:encoded><![CDATA[<p>At <a href="http://selenium-client.rubyforge.org/" target="_blank">Selenium Ruby</a> site, there is a description for method <strong>get_eval</strong>(script), as following:</p>
<blockquote><p>Gets the result of evaluating the specified JavaScript snippet. The snippet may have multiple lines, but only the result of the last line will be returned.</p>
<p>Note that, by default, the snippet will run in the context of the &#8220;selenium&#8221; object itself, so <strong><tt>this</tt></strong> will refer to the <a href="http://selenium-client.rubyforge.org/classes/Selenium.html">Selenium</a> object. Use <strong><tt>window</tt></strong> to refer to the window of your application, e.g. <tt>window.document.getElementById(‘foo’)</tt> If you need to use a locator to refer to a single element in your application page, you can use <tt>this.browserbot.findElement("id=foo")</tt> where &#8220;id=foo&#8221; is your locator.</p></blockquote>
<p>The special thing here is the <strong>this</strong> reference, means when invoking method get_eval() to run some javascript snippet, the <strong>this</strong> reference in snippet would refer to (redicted?) caller Selenium object but not the original belonging object.</p>
<p>This does differ from what we already know for window.eval() method, in which javascript snippt this still refer to the original belonging object, see below demo code:</p>
<pre>var a = 0;
window.eval("this.a = 1"); <span style="color: #339966;">// this refers to window object</span>
alert(a); <span style="color: #339966;">// a=1</span>
alert(this.a == a) <span style="color: #339966;">// true</span></pre>
<p>Above code demos <strong>this</strong> is window object itself.</p>
<pre>function A(){};
A.prototype = {
  f1: function(){
    return "f1";
  },
  f2: function(){
    alert(this.f1());
  }
}
var a = new A();
window.eval("a.f2()"); <span style="color: #339966;">// equals to a.f2(), this in f2 refers to a.</span></pre>
<p><span style="color: #000000;">Above code demos </span><strong>this</strong> in a.f2() method still refers to a, but not window object.</p>
<p>Generally, eval() is an <a href="https://developer.mozilla.org/en/JavaScript/Reference/Global_Objects/eval" target="_blank">evil thing</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2011/05/this-in-get_eval/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>OO训练营第四五课</title>
		<link>http://www.zhangkf.com/2011/04/oo-bootcamp-4/</link>
		<comments>http://www.zhangkf.com/2011/04/oo-bootcamp-4/#comments</comments>
		<pubDate>Sat, 30 Apr 2011 15:05:25 +0000</pubDate>
		<dc:creator>zhangkf</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[OO]]></category>

		<guid isPermaLink="false">http://kfzhang.thoughtworkers.org/?p=979</guid>
		<description><![CDATA[徐X语录： Design Pattern是针对特定问题的特定解决方案。 是问题，而不是解决方案定义了Pattern。 模式之间存在相似性，比如Adapter和Bridge模式，只是量的差别。 先让问题再想着怎么解决 over 想清楚什么问题再下手。 面向接口编程破坏了Communication和Technical之间的平衡。会带来Communication debt。 真的需要抽取借口时，需要两个条件：1. Concret Class；2. Consumer for Interface 没有bad smell就不要重构。]]></description>
			<content:encoded><![CDATA[<p>徐X语录：</p>
<blockquote><p>Design Pattern是针对特定问题的特定解决方案。</p>
<p>是问题，而不是解决方案定义了Pattern。</p>
<p>模式之间存在相似性，比如Adapter和Bridge模式，只是量的差别。</p>
<p>先让问题再想着怎么解决 over 想清楚什么问题再下手。</p>
<p>面向接口编程破坏了Communication和Technical之间的平衡。会带来Communication debt。</p>
<p>真的需要抽取借口时，需要两个条件：1. Concret Class；2. Consumer for Interface</p>
<p>没有bad smell就不要重构。</p></blockquote>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2011/04/oo-bootcamp-4/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>Pair的节奏</title>
		<link>http://www.zhangkf.com/2011/04/pair-programming-rhythm/</link>
		<comments>http://www.zhangkf.com/2011/04/pair-programming-rhythm/#comments</comments>
		<pubDate>Sat, 30 Apr 2011 14:39:57 +0000</pubDate>
		<dc:creator>zhangkf</dc:creator>
				<category><![CDATA[Agile]]></category>
		<category><![CDATA[Tech]]></category>
		<category><![CDATA[TW]]></category>
		<category><![CDATA[pair]]></category>
		<category><![CDATA[ThoughtBlogs]]></category>

		<guid isPermaLink="false">http://kfzhang.thoughtworkers.org/?p=972</guid>
		<description><![CDATA[这篇只想说说我对Pair节奏的理解。 Pair是需要节奏的，为什么？最简单的回答是，没有节奏，两个人都会很累。我有体会，跟team另一个新TWer一起pair，两个人会不由自主地坐在屏幕前，切分任务，你写测试我写实现，一动不动坐了整个下午，除了上厕所的时间。可想而知，离开办公室的时候那个疲惫。 不是说Pair就会比一个人“裸奔”轻松，恰恰相反，Pair就会比较累，这是无数人经验证明的。但是我们仍然需要在Pair时控制一定的节奏，不仅仅是为了减轻疲劳。 最直觉的反应是，疲劳会影响对问题的考虑，测试的覆盖度，代码的质量，这在一对Pair都疲劳的状态下，也不能免俗。当疲劳把Pair能带来的那些个好处统统赶跑后，Pair还有何存在的意义？ 一般来说，对Pair经验比较少的人，节奏可以由Pair经验多的人来控制，如何划分任务，粒度以及驱动测试开发的频度如何，都可以依据Pair的双方的能力和经验对比进行安排。在划分任务和思考时，可以以提问的形式，互相提问回答，推动进度。实现代码时，可以以乒乓的形式，由一方来编写测试，另一方编写实现，并跨任务轮换，让双方都感觉到Story的实现在有条不紊地前进，充满自信。双方可以约定在一个小时左右的时间，进行一次短暂的休息，切换context，以确保有持续的精力投入后续的Pair。 因为Pair是两个人的事情，当一方因为某种原因感觉到疲劳，或者被第三方事情打扰，不能集中精力在pair中时，可以主动跟对方提出中断，以换取集中的注意力在Pair上。 如果Pair对于某个问题或技术都不熟悉，并且在可遇见的时间内无法解决，应该立即寻求有经验同事的帮助，或者暂时放下留待后期解决，坚持钻牛角尖无疑是破快Pair节奏的杀手之一。就我的经验看，Pair时钻牛角尖的几率很小，在一方出现端倪时，对方会明显感觉到并主动提出来跳出这个圈子，这应该时Pair时一个小小的好处吧。 至于可能破坏Pair节奏的另外一个杀手——两人就问题或技术有争执，一般会发上在没有较多Pair经验的人身上，这会是另外一个话题，涉及到Simple Design，徐叉教导我们，要用代码证明自己的观点，要反过来关注问题本身。]]></description>
			<content:encoded><![CDATA[<p>这篇只想说说我对Pair节奏的理解。</p>
<p>Pair是需要节奏的，为什么？最简单的回答是，没有节奏，两个人都会很累。我有体会，跟team另一个新TWer一起pair，两个人会不由自主地坐在屏幕前，切分任务，你写测试我写实现，一动不动坐了整个下午，除了上厕所的时间。可想而知，离开办公室的时候那个疲惫。</p>
<p>不是说Pair就会比一个人“裸奔”轻松，恰恰相反，Pair就会比较累，这是无数人<a href="http://xiaopeng.me/2008/12/%E6%95%8F%E6%8D%B7%E5%BC%80%E5%8F%91%E5%88%9D%E4%BD%93%E9%AA%8C-2/" target="_blank">经验</a>证明的。但是我们仍然需要在Pair时控制一定的节奏，不仅仅是为了减轻疲劳。</p>
<p>最直觉的反应是，疲劳会影响对问题的考虑，测试的覆盖度，代码的质量，这在一对Pair都疲劳的状态下，也不能免俗。当疲劳把Pair能带来的那些个好处统统赶跑后，Pair还有何存在的意义？</p>
<p>一般来说，对Pair经验比较少的人，节奏可以由Pair经验多的人来控制，如何划分任务，粒度以及驱动测试开发的频度如何，都可以依据Pair的双方的能力和经验对比进行安排。在划分任务和思考时，可以以提问的形式，互相提问回答，推动进度。实现代码时，可以以乒乓的形式，由一方来编写测试，另一方编写实现，并跨任务轮换，让双方都感觉到Story的实现在有条不紊地前进，充满自信。双方可以约定在一个小时左右的时间，进行一次短暂的休息，切换context，以确保有持续的精力投入后续的Pair。</p>
<p>因为Pair是两个人的事情，当一方因为某种原因感觉到疲劳，或者被第三方事情打扰，不能集中精力在pair中时，可以主动跟对方提出中断，以换取集中的注意力在Pair上。</p>
<p>如果Pair对于某个问题或技术都不熟悉，并且在可遇见的时间内无法解决，应该立即寻求有经验同事的帮助，或者暂时放下留待后期解决，坚持钻牛角尖无疑是破快Pair节奏的杀手之一。就我的经验看，Pair时钻牛角尖的几率很小，在一方出现端倪时，对方会明显感觉到并主动提出来跳出这个圈子，这应该时Pair时一个小小的好处吧。</p>
<p>至于可能破坏Pair节奏的另外一个杀手——两人就问题或技术有争执，一般会发上在没有较多Pair经验的人身上，这会是另外一个话题，涉及到<a href="http://blog.vincentx.info/2007/03/agile-101-pair-programming-simple-design/" target="_blank">Simple Design</a>，徐叉教导我们，要用代码证明自己的观点，要反过来关注问题本身。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2011/04/pair-programming-rhythm/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Automation Training For TW QA</title>
		<link>http://www.zhangkf.com/2011/04/automation-training-for-tw-qa/</link>
		<comments>http://www.zhangkf.com/2011/04/automation-training-for-tw-qa/#comments</comments>
		<pubDate>Sat, 23 Apr 2011 13:30:03 +0000</pubDate>
		<dc:creator>zhangkf</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[TW]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[automation]]></category>
		<category><![CDATA[javascript]]></category>
		<category><![CDATA[Ruby]]></category>
		<category><![CDATA[selenium]]></category>
		<category><![CDATA[testing]]></category>
		<category><![CDATA[ThoughtBlogs]]></category>
		<category><![CDATA[ThoughtWorks]]></category>

		<guid isPermaLink="false">http://kfzhang.thoughtworkers.org/?p=958</guid>
		<description><![CDATA[今天作为酱油党之一（徐X语，还有小刀和LeoShi同行）参加了徐X为TW QA开的Automation Training。 对于Ruby小白的我，跟着QA一起学了一把。 Ruby的包机制，应用的配置环境 Selenium RC的原理，包的四个变种。 在07年就提到过的Page Object 自动化测试具备怎样的特质，才能最大限度的减少QA手工测试的工作量？ Effective QA manageable 最后，徐X介绍了几个月前他研究出的Data Flow大法。简言之，测试不是要去测试事情本身，而是要测试事情结果的确发生。听着象废话，但那张精美手绘图却惊艳得不行。用以作为切分并归纳测试案例的依据。很受用，争取撺掇一篇文章出来。]]></description>
			<content:encoded><![CDATA[<p>今天作为酱油党之一（徐X语，还有<a href="http://iamxiaodao.com/" target="_blank">小刀</a>和LeoShi同行）参加了<a href="http://blog.vincentx.info/" target="_blank">徐X</a>为TW QA开的Automation Training。</p>
<p>对于Ruby小白的我，跟着QA一起学了一把。</p>
<ul>
<li>Ruby的包机制，应用的配置环境</li>
<li>Selenium RC的原理，包的四个变种。</li>
<li>在07年就提到过的<a href="http://www.infoq.com/cn/articles/domain-web-testing" target="_blank">Page Object</a></li>
</ul>
<p>自动化测试具备怎样的特质，才能最大限度的减少QA手工测试的工作量？</p>
<ol>
<li>Effective</li>
<li>QA manageable</li>
</ol>
<p>最后，徐X介绍了几个月前他研究出的Data Flow大法。简言之，测试不是要去测试事情本身，而是要测试事情结果的确发生。听着象废话，但那张精美手绘图却惊艳得不行。用以作为切分并归纳测试案例的依据。很受用，争取撺掇一篇文章出来。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2011/04/automation-training-for-tw-qa/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>不要混用IDE和命令行工具</title>
		<link>http://www.zhangkf.com/2010/09/%e4%b8%8d%e8%a6%81%e6%b7%b7%e7%94%a8ide%e5%92%8c%e5%91%bd%e4%bb%a4%e8%a1%8c%e5%b7%a5%e5%85%b7/</link>
		<comments>http://www.zhangkf.com/2010/09/%e4%b8%8d%e8%a6%81%e6%b7%b7%e7%94%a8ide%e5%92%8c%e5%91%bd%e4%bb%a4%e8%a1%8c%e5%b7%a5%e5%85%b7/#comments</comments>
		<pubDate>Tue, 21 Sep 2010 09:07:12 +0000</pubDate>
		<dc:creator>admin</dc:creator>
				<category><![CDATA[Tech]]></category>
		<category><![CDATA[Work]]></category>
		<category><![CDATA[eclipse]]></category>
		<category><![CDATA[Maven]]></category>
		<category><![CDATA[tomcat]]></category>

		<guid isPermaLink="false">http://www.zhangkf.com/?p=870</guid>
		<description><![CDATA[比如Eclipse和Maven。 从Maven去build，然后从Eclipse里面启动tomcat来运行build好的程序，这会死得不明不白。]]></description>
			<content:encoded><![CDATA[<p>比如Eclipse和Maven。<br />
从Maven去build，然后从Eclipse里面启动tomcat来运行build好的程序，这会死得不明不白。</p>
]]></content:encoded>
			<wfw:commentRss>http://www.zhangkf.com/2010/09/%e4%b8%8d%e8%a6%81%e6%b7%b7%e7%94%a8ide%e5%92%8c%e5%91%bd%e4%bb%a4%e8%a1%8c%e5%b7%a5%e5%85%b7/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

