1:使用分布式的版本管理系统

如果你觉得不需要使用版本管理系统,那我们沟通会有代沟,如果你是cvs、svn的粉丝,或者由于某种原因没有使用过分布式版本管理系统,比如git,那强烈建议你去看一下“why git is better than x”。

2:一键式发布

这里发布的目标位置,既可以是开发机,做本地测试;也可以是测试机,为QA准备好捉虫游戏的森林;还可以是生产环境(或者beta环境),供用户直接访问。

如深度xp一键恢复系统一样,一键式发布需要自动完成很多工作:代码自动化测试(开发阶段),打包压缩,编译(测试阶段),数据同步(外网)。也许还有很多工作要加入进来,但核心是是否能通过一个脚本的执行就全部完成所有流程,这点至关重要。如果中间多出几个环境,那将来一定会引入发布的灾难。

3:TDD / BDD 请对你自己写的代码负责

不要为了TDD/BDD而TDD/BDD,只要能及时获得自己写的代码运行情况的反馈就行,也无需一次把test case都覆盖全。对于没有任何单元测试的代码,将来想引入单位测试,将举步维艰!如果,你认为测试完全是QA的事情,那你就花大笔的钱去招聘一个规模庞大的QA集团吧,期望他们能让你偷懒。

4:使用靠谱的bug记录工具

人脑的潜力虽然无限,但大脑皮层只会对进入缓存区的数据做高效的反应。记忆再好的开发,也可能被各种牛魔鬼怪折磨的忘记了昨日的痛(曾经产生的bug)。所以,从团队第一次提测,就应该使用靠谱的bug记录工作。所谓好记性不如烂笔头就是这个道理。

那一个靠谱的bug记录工具应该要记录这些数据:

  1. bug复现的整个操作流程
  2. 产品需求中的正常情况
  3. 出现bug后,变成为什么情况
  4. 谁将负责修复这个bug
  5. bug最后修复没有

至于怎么修复的bug,是重新设计还是漏提交了代码,我觉得无关紧要。如果一个bug修复的经验值得分享,可以单独做一次团队的技术分享,而这往往是由于对现有产品的(技术或者其他的)信息获取不够导致的。

5:尽快修复bug

我的开发经验告诉我,一个bug越晚修复,被修复的可能性越小,将来产生危害的可能性越大。试想,你刚提测或者发布的代码,出现的bug,往往你能最快得到解决它需求的时间,而时间在项目管理上是非常重要的。反之,如果积累了很多bug,且有一定时间了,那修复它就需要对所有相关的系统进行了解,这将花费大量你可以用来度假,娱乐的美好时光。所以,从团队一开始就贯彻这点,可以释放成员修复bug的压力。

6:给团队成员一个安静的环境

最近很多同学告诉我,白天基本上没有什么效率,总是受到各种骚扰。我们做一个假设:假如A同学进入最佳状态需要30分钟,那么如果他比较惨,在30分钟间隔内,他总是被打断,那么他一天都无法最高效的工作。又或者同学B google查询一个技术问,花费2分钟可以解决,但问同学A只要20秒钟(好吧,同学A表达很清晰)。这样同学B节省了100秒钟,而同学A至少损失了30分钟。

从这个假设,我们不难发现,如果能避免团队成员受到外来信息的骚扰,他就有可能更加高效的工作,从而写出更好的产品。而常识告诉我们,人不可能一直高效的工作,所以,我们应该利用好无法集中精力的时间去进行一些沟通。但分出这个界限显然十分困难,所以我觉得不妨这样:规定每天的安静时间段,在这个时间段,其他人都不能来打扰这位同学,而在非安静时间段,可以随意访问,从而让这位同学形成一个新的生物钟(人体的自我调节能力是非常强悍的)。

7:给员工最好的工具

做同样一件事情,如果使用工具A,消耗的时间为5分钟,而使用工具B,消耗的时间为1分钟,那我一定给员工提供B工具,即使B工具的价格是A工具的5倍。因为,假如人在连续高效工作中的抵抗干扰时间为1分钟,那么意味着B工具能保证高效工作的时间连续,而A将可能分散了用户精力,导致需要更多的时间才进入最佳状态。事实上,之所以要更好的cpu,更大的内存,更好的编译器,更好的编辑器,多显示器,都是让程序员尽快能回到核心业务上来,而在等待上花费更少的时间

同时,别忘了,一把好的椅子也是维持更长高效工作时间的保证,所以,别吝啬,给员工更好的椅子吧,他们会感到你的温怀。

rake 带参数就这么做

Posted: May 17, 2011 in Ruby
Tags: ,
task :t1, :a1, :a2, :needs => [:t2, :t3] do |t, args|
  args.with_defaults(:a1 => 'default_1 in task t1', :a2 => 'default_2 in task t1')
  puts t.name
  puts args
end

task :t2, :a1, :a2 do |t, args|
  args.with_defaults(:a1 => 'default_1 in task t2', :a2 => 'default_2 in task t2')
  puts "this is t2"
  puts args
end

task :t3, :a1, :a2 do |t, args|
  args.with_defaults(:a1 => 'default_1 in task t3', :a2 => 'default_2 in task t3')
  puts "this is t3"
end

可以执行rake t1[1,2]或者rake t1试试

本文是我读完第二章--《七个习惯概论》的心得体会。

人的行为总是一再重复。因此卓越不是单一的举动,而是习惯。 --Aristotle

因此,想要追求卓越就需要有好的习惯,而要改变坏的习惯更是困难,需要在“知识”(做什么,为何做)、“技巧”(如何做)和“意愿”(想要做)三个方面努力。我个人觉得往往在开始的时候,是想要做的,但往往遇到了困难或者其他的诱惑就有可能不想或者不那么想要做了,这个时候更要提醒自己坚持才能取得胜利。

本章还提到了一个全书都特别重要的概念:效能。效能的高效在于产出和产能的平衡。我觉得现实中,我们往往忽视了产能,而一味的过份追求产出。所以,我觉得有必要多讲讲对产能的理解。

个人的产能

对于我们个人而言,我们的产能取决于自己的知识和经验的储备。如果你不持续学习新的知识,和积累经验,你分析问题的视野就会变得狭隘,同时也只能在目前的职位上踏步,每天忙忙碌碌,经济上一直受制于现在的老板。试想,在这种情况下,你何谈高效?

同时,我们自己的身体也是宝贵的产能。“身体是一切革命的本钱”,如果条件允许还是尽可能的少熬夜,多吃素食,并合理运动。(目前这点我就做得不好,从现在开始要好好调整,也希望大家能注意保重身体)

团队的高效

老板往往希望员工从每天下一个金蛋变为二个,而后三,越多越好,如果员工某天的产出少了,就会令自己很不舒服,觉得花了这么多钱,没有让员工overload(就好像现在很多小公司都希望自己的服务器cpu高负荷运转,什么xen都是为了实现这个目的),很不划算。

然而,人远不同于机器,对机器的运维经验,用到人身上就大相径庭了。你可以回答以下两个问题:

  • 你雇佣一名员工,希望他对于公司的产品热忱吗?
  • 你雇佣一名员工,希望他更多帮你去思考和解决问题吗?

钱不是万能的,买不到员工的心也买不到他的头脑。而心是忠诚与热忱的根源,头脑才是创造力与智慧的源泉。谈到这里,我不由的想说,其实很多小公司里,部分同学还是很有创造力的,只是超负荷的加班,已经逐渐让他变得呆滞。而一些牛叉的公司里,由于企业特别在意团队的产能,给出了各种团队成员提高产能的资源(比如培训,高效的电脑设备,舒适的环境),自然进入的员工会一直保持一种很好的状态,从而公司也变得伟大。

由内而外全面造就自己

Posted: March 31, 2011 in Reading
Tags: ,

以前就读过《高效能人的七个习惯》,这七个习惯分别是:积极主动、以始为终、要事第一、双赢思维、知彼解己、综合综效、不断更新。但现在回头看看,这些习惯并没有很好的融入到自己的日常工作和生活当中,我想是因为当时读得太快,太过功利了吧。

最些在公司被一些损人利己的事和人所烦恼,心情实在不爽。昨天也和好友保平聊到了一些公司的事情,他最近在读这本书,也推荐我再温习一下。今天在上班地铁里便开始读了起来。

这里记录我读的第一章--《由内而外全面造就自己》的心得体会。

品德是这个年代特别容易被忽视的珍宝,很多时候,良好的品德本身就是一种特别好的个人魅力。而往往很多人,忽视他,追求速成,拉帮结派,甚至为了个人的利益做出一些伤天害理的事情,为达目的不择手段,过于结果导向。

而为什么那么容易放弃品德呢?这是因为缺乏一些基本的,放之四海皆准的原则作为指导。我个人认为要坚持以下原则:

  • 诚信
  • 正直
  • 服务:即贡献自我
  • 追求卓越

图片感知实验,反应了思维定式这一事实,我们必须要认识到这点,在工作中审视自己的定式和接受别人的意见,打开自己的视野。

“一颗邪恶的大树,砍它枝叶千斧,不如砍它根基一斧头。” --梭罗

要想有实质性的变化,还是要靠思维的转换,但这点是很难做到的,我觉得只有不断学习、实践,并积极的思考才能不断的转换自己的思维,一次次打破固有的定式。

“如果我们时时忙着展现自己的知识,将何从忆起成长所需的无知?” --梭罗

违背自然的成长过程,只会让你平添失望和挫败感。要想获得成功,必须要从内而外的进行锻造,遇到问题多从主观上找原因,而不是先把问题归结于客观环境。

More powerful vim

Posted: March 19, 2011 in VIM
Tags:

Try the code below, you’ll get good luck!

for i in ~/.vim ~/.vimrc ~/.gvimrc; do [ -e $i ] && mv $i $i.old; done
git clone git://github.com/hujinpu/janus.git ~/.vim
cd ~/.vim
rake

Wait a moment or drink a cup of coffee 🙂

mvim ~/.vimrc.local

copy and paste:

inoremap <Esc> <nop>
inoremap jj <ESC>

nnoremap <leader><space> :noh<cr>

set statusline=%F%m%r%h%w%=%{fugitive#statusline()} (%{&ff}/%Y) (line %l/%L, col %c)

" Searching
nnoremap / /v
vnoremap / /v

set textwidth=79
set formatoptions=qrn1
set colorcolumn=85

nnoremap <up> <nop>
nnoremap <down> <nop>
nnoremap <left> <nop>
nnoremap <right> <nop>
inoremap <up> <nop>
inoremap <down> <nop>
inoremap <left> <nop>
inoremap <right> <nop>

:Edit ~/.gvimrc.local

copy and paste:

if has("gui_macvim")
  set guifont=Menlo:h18
endif

Goooooooooooood Luck!

Single table inheritance in Rails3

Posted: March 18, 2011 in Rails
Tags: ,

Active Record allows inheritance by storing the name of the class in a column that by default is named “type” (can be changed by overwriting Base.inheritance_column). This means that an inheritance looking like this:

class Company < ActiveRecord::Base; end
class Firm < Company; end
class Client < Company; end
class PriorityClient < Client; end

When you do Firm.create(:name => “37signals”), this record will be saved in the companies table with type = “Firm”. You can then fetch this row again using Company.where(:name => ’37signals’).first and it will return a Firm object.

If you don’t have a type column defined in your table, single-table inheritance won’t be triggered. In that case, it’ll work just like normal subclasses with no special magic for differentiating between them or reloading the right type with find.

Note, all the attributes for all the cases are kept in the same table. Read more: singleTableInheritance

input’s difficult event handle

Posted: March 16, 2011 in ECMAScript
Tags:

When user drag and drops the text directly into the Input control, the onkeyup event is not fired as no keyboard is involved.
You can use onfocus event to fix the problem. Like this:

function processInput() {
  // your logic
};
var $element = document.getElementById('elementid');
$element.onfocus = $element.onkeyup = processInput;

also you should use input event in firefox and chrome

How to detect right mouse click + paste using JavaScript?

Using route to fuck gfw!

Posted: March 16, 2011 in GFW, Uncategorized
Tags: ,

You can use route command to smart your vpn traffic.

add some rules to your pptp /etc/ppp/ip-up:

#!/bin/sh
export PATH="/bin:/sbin:/usr/sbin:/usr/bin"

LOCALGATEWAY=`netstat -nr | grep '^default' | grep -v 'ppp' | sed 's/default *([0-9.]*) .*/1/'`


if [ ! -e /tmp/pptp_localgateway ]; then
    echo "${LOCALGATEWAY}" > /tmp/pptp_localgateway
fi

dscacheutil -flushcache


route add 1.12.0/14 "${LOCALGATEWAY}"
route add 1.24.0/13 "${LOCALGATEWAY}"
route add 1.45.0/16 "${LOCALGATEWAY}"

and /etc/ppp/ip-down:

#!/bin/sh
export PATH="/bin:/sbin:/usr/sbin:/usr/bin"


if [ ! -e /tmp/pptp_localgateway ]; then
        exit 0
fi

LOCALGATEWAY=`cat /tmp/pptp_localgateway`


route delete 1.12.0/14 ${LOCALGATEWAY}
route delete 1.24.0/13 ${LOCALGATEWAY}
route delete 1.45.0/16 ${LOCALGATEWAY}
route delete 1.48.0/14 ${LOCALGATEWAY}

rm /tmp/pptp_localgateway

Notice: Do not forget to add 192.168.0/16 to your local gateway(maybe eth0, ppp0 for vpn gateway)

ipv4list

Just some notes after reading “Eloquent Ruby” chapter two.

  • use unless in place of if not
  • use until in place of while not

You should think that do sth in the unless or until block unless/until condition is true.

Use each, Not for

Case statements use the === operator to do the comparisons. Since classes use === to identify instances of themselves, you can use a case statement to switch on the class of an object. And you can use a case statement to detect a regular expression match.

only false and nil are treated as false, you should avoid testing for truth by testing for specific values.

@first_name ||= '' shorter than @first_name = '' unless @first_name

http://www.dustindiaz.com/klass/