用hg已有多日,下面的这个法子是前段时间摸索出来的偷懒招数。
问题是这样:项目中有两个代码库分支:trunk和1.2。每个代码库都超过500M。我的C盘剩余空间已经不多,没法同时保留两个分支的本地副本。平时我主要在trunk上工作,有时要修1.2的bug就得把分支切换到1.2上。重新checkout整个代码库很慢,怎么办呢?
既然是分支,那它们肯定在某一点之前共享相同的历史。所以我只需要先回溯到这个基点,再获取1.2分支上自从这一点后所有的历史即可!
具体做法:
1. 执行hg out ${url_of_1.2},得到trunk分支上与1.2不同的最早的节点,记为revision1
2. 执行hg strip revision1,删除以revision1为根的所有版本
3. 重复步骤1,检查是否还有1.2分支上不存在的版本;如有,则重复步骤3
4. 至此,本地副本上的所有版本都是1.2上的版本;这时可以执行hg pull ${url_of_1.2}获取1.2上的新的版本
5. 大功告成,你已经得到一个与中心库上1.2分支完全一致的代码库
2009年2月11日星期三
Inline parameter
受Derek同学的启发,我想把我们在实践中总结下来的一些重构小技巧记录下来。
我们自己在实际中经常用到Extract Parameter这个重构功能,感觉非常方便。但可惜的是没有这个功能的反向功能。比如说一个方法接受三个参数,但检查这个方法所有的调用处发现,第三个参数完全可以由前两个参数(或者其他可视范围内的值)计算得出。这时你就需要一种重构来把这个参数的计算过程推到方法内部,然后删除这个参数。
遗憾的是IntelliJ不提供这样的自动化重构功能。我们可以手动来做,但如果代码很多,就有风险。怎么尽量降低这种风险呢?
我想到了一种方法。假设目标方法为foo,我们想要删除的参数为bar。步骤如下:
1. 对计算bar的表达式提取方法(IntelliJ能自动检测到相同代码片段并提示自动替换)
2. 在方法foo的所有调用处,把参数bar替换为对新方法的调用
3. 修改foo方法的代码,在第一行将bar赋值为对新方法调用的返回值
3. (在foo方法内,)内联bar(,然后bar在foo方法内部已没有引用)
4. 修改foo方法的签名,安全删除bar(所有调用处用于生成bar的表达式即自动删除)
我们自己在实际中经常用到Extract Parameter这个重构功能,感觉非常方便。但可惜的是没有这个功能的反向功能。比如说一个方法接受三个参数,但检查这个方法所有的调用处发现,第三个参数完全可以由前两个参数(或者其他可视范围内的值)计算得出。这时你就需要一种重构来把这个参数的计算过程推到方法内部,然后删除这个参数。
遗憾的是IntelliJ不提供这样的自动化重构功能。我们可以手动来做,但如果代码很多,就有风险。怎么尽量降低这种风险呢?
我想到了一种方法。假设目标方法为foo,我们想要删除的参数为bar。步骤如下:
1. 对计算bar的表达式提取方法(IntelliJ能自动检测到相同代码片段并提示自动替换)
2. 在方法foo的所有调用处,把参数bar替换为对新方法的调用
3. 修改foo方法的代码,在第一行将bar赋值为对新方法调用的返回值
3. (在foo方法内,)内联bar(,然后bar在foo方法内部已没有引用)
4. 修改foo方法的签名,安全删除bar(所有调用处用于生成bar的表达式即自动删除)
2009年1月22日星期四
Fix Google Reader显示问题
早就觉得Google Reader的段落排版有问题了。字体太小,排版紧凑,对眼睛很不友好!
以往每次看文章,都得敲两次=,放大字体,但还是解决不了间距的问题。密密麻麻的,看着不舒服。
今天终于用firefox的user css解决了这个问题。
只需把下面这段代码放到firefox的profile\chrome下的userContent.css里:
Firefox3的profile目录在Windows下是:%APPDATA%\Mozilla\Firefox\Profiles\xxx.default
参考:Site specific stylesheet in Mozilla
以往每次看文章,都得敲两次=,放大字体,但还是解决不了间距的问题。密密麻麻的,看着不舒服。
今天终于用firefox的user css解决了这个问题。
只需把下面这段代码放到firefox的profile\chrome下的userContent.css里:
@-moz-document url-prefix(http://www.google.com/reader/view/) {
.entry-body { font-size: 1.4em; line-height: 1.5em; }
}
Firefox3的profile目录在Windows下是:%APPDATA%\Mozilla\Firefox\Profiles\xxx.default
参考:Site specific stylesheet in Mozilla
2009年1月3日星期六
Parallelize your tests with Test-Load-Balancer
With the fact that Cruise runs jobs in parallel to make long running test suites go faster, you can simply split your long running test suite into multiple suites and create jobs for each one. Given enough build agents, Cruise can run all jobs within a specified stage simultaneously, which means your long running testing can be done in a snap.
But wait, why do I need to manually split my test suites?
For example, I have a unit-test target in my ant build script which include more than 100 tests. Those tests are organized by corresponding packages, so it's hard to split them in an easy way. It's a burden to most of Cruise users.
That's why we have Test-Load-Balancer now.
What is test-load-balancer?
TLB(Test-Load-Balancer) is a tool that can split test suites for you in Cruise. With TLB, you can simply specify how many pieces you want to split for a specific job using an easy, intuitive way. TLB can automatically work out how many pieces and which piece that current job should do. For example, you have a unit test job running on Linux environment named 'ut-linux', it has 100 tests and costs 10 minutes. Now you want to split it to three jobs, what you need to do is just replace the old 'ut-linux' job with three jobs: 'ut-linux-1', 'ut-linux-2', 'ut-linux-3'. Then you can run unit tests on Linux in three pieces simultaneously, and get benefits of reducing time cost to one third of the old cost.
How to use it?
First, download test-load-balancer jar file and add it to the classpath of ant build script.
Then, change your build.xml as following:
<typedef name="filter-fileset" classname="com.googlecode.tlb.support.junit.FilterFileSet" classpathref="classpath"/>
<junit>
<batchtest todir="target/test-results">
<filter-fileset dir="target/test-classes" includes="**/*Test.class"/>
</batchtest>
<classpath refid="classpath" />
</junit>
Third, change your Cruise configuration to use TLB style jobs such as ut-linux-1, ut-linux-2, ut-linux-3 ...
Then you can get the benefits of faster run.
Further information about test-load-balancer.
A video demonstration about TLB:
But wait, why do I need to manually split my test suites?
For example, I have a unit-test target in my ant build script which include more than 100 tests. Those tests are organized by corresponding packages, so it's hard to split them in an easy way. It's a burden to most of Cruise users.
That's why we have Test-Load-Balancer now.
What is test-load-balancer?
TLB(Test-Load-Balancer) is a tool that can split test suites for you in Cruise. With TLB, you can simply specify how many pieces you want to split for a specific job using an easy, intuitive way. TLB can automatically work out how many pieces and which piece that current job should do. For example, you have a unit test job running on Linux environment named 'ut-linux', it has 100 tests and costs 10 minutes. Now you want to split it to three jobs, what you need to do is just replace the old 'ut-linux' job with three jobs: 'ut-linux-1', 'ut-linux-2', 'ut-linux-3'. Then you can run unit tests on Linux in three pieces simultaneously, and get benefits of reducing time cost to one third of the old cost.
How to use it?
First, download test-load-balancer jar file and add it to the classpath of ant build script.
Then, change your build.xml as following:
<typedef name="filter-fileset" classname="com.googlecode.tlb.support.junit.FilterFileSet" classpathref="classpath"/>
<junit>
<batchtest todir="target/test-results">
<filter-fileset dir="target/test-classes" includes="**/*Test.class"/>
</batchtest>
<classpath refid="classpath" />
</junit>
Third, change your Cruise configuration to use TLB style jobs such as ut-linux-1, ut-linux-2, ut-linux-3 ...
Then you can get the benefits of faster run.
Further information about test-load-balancer.
A video demonstration about TLB:
2008年12月28日星期日
我的TDD实践总结
加入TW一年多,也是实践了TDD一年多。一开始是跟着别人照猫画虎,最近开始总结出来点意思了。
这个转变是我们组的Tech Lead——Chris Stevenson给我带来的。
跟Chris一起pair时,一个印象深刻的事情是他写代码,如果发现需要的东西还不存在,比如需要某个对象提供某个方法,甚至需要一个新的对象封装某些逻辑,他是直接敲出这样的方法,完成当前需要的逻辑,然后借助IDE的自动修正功能生成所需的方法。
这种编写代码的过程,就好像是一个类的方法,都是由它的客户们的需求驱动出来的。而且因为方法名都是在编写客户代码时编写出来的,那些名字在客户代码环境中看起来非常贴切,可读性非常好。
对比起我之前的编码习惯,可以发现一些有意思的结论。我之前开始写程序时,会先想出一个我需要的类,然后基于这个类的数据成员构思出它应该对外提供的方法接口。有时候甚至会反复斟酌很久,以图设计出一个看上去“完美”的接口。其实最后那些精心设计出来的方法,有多少是集成后保留下来的(或者经过了某些修改),仔细想想其实并不乐观。
而Chris的这种习惯,基本上一个类的接口,都是在实际需要时才被创建出来,这样做出的类的接口非常紧凑,而且更贴近需求。
看到这里,熟悉TDD的人应该已经看出来了,其实这就是TDD的思想——从需求出发,思考一个类封装什么样的职责,需要提供什么样的接口。
现在,我正实践着这种编程方式,而且正从中获益。
这个转变是我们组的Tech Lead——Chris Stevenson给我带来的。
跟Chris一起pair时,一个印象深刻的事情是他写代码,如果发现需要的东西还不存在,比如需要某个对象提供某个方法,甚至需要一个新的对象封装某些逻辑,他是直接敲出这样的方法,完成当前需要的逻辑,然后借助IDE的自动修正功能生成所需的方法。
这种编写代码的过程,就好像是一个类的方法,都是由它的客户们的需求驱动出来的。而且因为方法名都是在编写客户代码时编写出来的,那些名字在客户代码环境中看起来非常贴切,可读性非常好。
对比起我之前的编码习惯,可以发现一些有意思的结论。我之前开始写程序时,会先想出一个我需要的类,然后基于这个类的数据成员构思出它应该对外提供的方法接口。有时候甚至会反复斟酌很久,以图设计出一个看上去“完美”的接口。其实最后那些精心设计出来的方法,有多少是集成后保留下来的(或者经过了某些修改),仔细想想其实并不乐观。
而Chris的这种习惯,基本上一个类的接口,都是在实际需要时才被创建出来,这样做出的类的接口非常紧凑,而且更贴近需求。
看到这里,熟悉TDD的人应该已经看出来了,其实这就是TDD的思想——从需求出发,思考一个类封装什么样的职责,需要提供什么样的接口。
现在,我正实践着这种编程方式,而且正从中获益。
订阅:
博文 (Atom)