关于Code Review, 从coolshell的一篇文章所想到的.

酷壳( coolshell.cn )是我个人非常喜欢的一个技术博客,创办者陈皓( @左耳朵耗子)在这个博客里面提供了很多非常有营养的文章,没看过的程序员朋友一定要看一看.

这篇博文源自于这篇文章:

从Code Review 谈如何做技术

看到作者这种大牛在阿里这种以工程师文化闻名的公司推行code review的时候遇到的种种阻力,想想自己从抵触到接受,到现在认为review完的代码才能commit,整个过程说出来我觉得多少还是有些意思的.

在工作的前5年里(shame),我基本上没有做过任何形式的code review,无论是让别人review我的代码,还是review别人的代码.原因太多了,公司没有强制规定,小组也没有形成氛围,在这种情况下,贸然请别人花时间review自己的代码,别人是不一定乐意的,自己自告奋勇review同事代码更是一种类似挑衅的行为.当然,如果有一段代码的处理逻辑非常复杂,我没有信心能够独自一人很顺利搞定的时候,我会向经理提出申请,邀请一个同事来和我一起写,对,就是类似敏捷提倡的那种”结对编程”的模式,只是多数时间是我在写,他则在旁边跟我聊聊天,在我脑子发热的时候一语中的的指出我的list中包含的到底是什么样的数据结构.也就是所谓的”当局者迷,旁观者清.”.一来这种非常复杂的开发工作不会天天有,而且开发时间不会特别长(一般不超过半天),二来坐在旁边看别人写代码其实是一个稍微轻松的事情,因此这种举动并没有引来经理和同事的反感和抵触.

首次接触”疑似”review是在前一家公司,我们开发的整套环境都是一个老家伙带着团队搭的(天知道他们积累了多久才搞了这么多玩意),从vim的配置,php开发框架,一直到上线分发的脚本都有,其中上线前最重要的部分就是将最新版本和线上版本的代码依次做vimdiff,只有都确认ok的时候才会上线.我所在的team只有我和另外一个老家伙具有上线权限.因此每次上线前,一个一个文件的查看diff,确认新的修改ok就成了必然的工作.当然,最开始我对此感到的是好奇和新鲜(从eclipse插件开发到php网站开发,一个月时间,如此跨度,不新鲜才怪),后来在发现了几个明显的拼写错误和几个隐蔽的逻辑bug之后,我意识到这么做原来真的可以发现这么多问题,就对这件事情逐渐重视起来.当然,甚是土鳖的我,当时必然是不知道review board这种高级玩意的存在的.

从前公司离职加入现在公司之后,开发语言从php又换回了老本行-java.我作为一个新人,首先肯定还是适应新的团队和环境,因此review这种事情就作为内心中一个隐隐的向往,就给放下了(其实作为程序员,我心中已经有很多类似的隐隐向往了,比如”我一定要重构XX模块,我一定要开发一个XX工具,我一定要努力把数学水平提高点….”,多一个不多).后来公司来了一个CTO,当然,还来了很多高大上公司的天才,如果没记错的话,Code Review是作为新技术管理团队的三把火工程提出来的.当然,经理层中有没有人为了这个事情把CTO微博拉黑我是不知道得:-),但是下面的一线程序员议论的还是有一些,讨论的主要内容和上面陈皓文章中写的差不多,人手不够工期紧blabla,但是讨论归讨论,毕竟因为这个事情跟经理闹翻的事情是不会有人做的.我在配置了reviewboard之后,立刻爱上了这个玩意.我擦原来还有这么高大上的东西.当然,作为三把火工程的配套工程,新团队还给了一些suggestion,比如关于代码规范性方面的建议,比如提review应该小步快跑,比如最好同时提给2个以上的人看等等.然后就是近似强制使用到现在.

个人总结一下code review带来的好处:

1.能缓解技术团队管理上的单点问题.共同维护一个大系统的程序员团队很容易成为某人负责某个模块的形式.不可否认这么分配效率是最高的,但是风险也很大,原因很简单,Single Point.纵然管理上一直在提敏捷,说所有人对所有代码负责,但是最终的结果基本上就是没人对别人的代码负责.但是如果强制的去要求团队成员轮流换模块开发,那么整个团队的开发效率又会有问题(尤其是项目规模稍大,且业务逻辑非常复杂的情况下,要每个人都非常清楚所有模块,确实不太可能).那么采用codeReview的形式,将2~3人分组,一个主力开发,另外的人负责review,那么至少会有人对代码熟悉.单点情况能缓解很多.

2.对于个人来说,当我知道我的代码必然会被别的同事审阅的时候,那么在无形中我就会更认真的对待.比如在变量命名上更仔细,或者在代码结构和运行效率上考虑的更多.那么当我review别人的代码的时候我也会更加注意同事的代码有没有疏忽和遗漏.当然,在经历了前几次扭捏之后,现在大家在review的时候提问题已经脸不变色心不跳了,毕竟都是就事论事,也算是加深了同事之间的相互信任吧.

3.有助于培养团队整体的代码风格.每个人都有自己的代码风格,那么某种自己熟悉的写法如果受到团队其他成员的一致差评(破窗户被第一次发现),那么这个问题下一次一定会被纠正过来的(立刻被修补).反之,阅读别人代码时,我也会有惊喜:原来还有这么牛叉的api和用法, 下次我也用!

 

对于还没有接触过code review的同学,我再给出一点小建议:

1.无论团队有没有code review的习惯,自己在commit之前,重新diff一遍,认真的读一遍自己的代码是绝对有好处的.

2.在团队中开发中,自己可以偷偷的check下来同事的两个相邻的版本,然后看看diff,一来可以了解一下业务,二来培养一下自己阅读代码的水平,毕竟读开源代码所花费的精力远超过阅读自己天天接触的系统的代码.

AWK 简明教程

之前对awk的使用一直停留在截取某列打印出来的水平上,最近简单学习了一下awk,发现这个东西还是比较强大的,这里总结一下.

awk的基本使用

awk是一个非常好的行文本处理器,支持从标准输入接收数据,结果输出至标准输出.比如我们可以这么用:

cat a.txt|awk '{print $2}'

上面这行的意思是将每行的第二列打印出来.默认分隔符是空格或者tab.当然我们可以通过F参数来修改.

cat a.txt|awk -F , '{print $2}'

上面这行就将分隔符改为了逗号.
观察awk后面的部分,可以明显看出,这就是一段脚本.既然是脚本,那么当脚本过长,在命令行直接编写肯定是不够方便的.
所以awk支持指定某一个脚本文件来处理.比如我们可以这么干:
新建一个文件,名字为awktst,内容如下:

{print $2}

我们可以将上面的脚本改为:

cat a.txt|awk -F , -f awktst

awk的基本结构

awk是基于行文本的处理工具,当我们将文本流输入awk的时候,awk其实是在不停的重复处理同一行.其结构主要分为三部分:Begin,body,END.
处理的过程伪码如下:

BEGIN{
     #init something before start text reading
 }
 while((line = readline())!=null){
     body{
         #the main awk process is here
     }
 }
 END{
     #do something after read end
 }

 

我们只需要编写BEGIN,body和END过程就好了.

每部分都用大括号来标识自己的代码块.需要注意的是,awk的变量作用域是全局的,而和代码块没关系.

还是上面的例子,我们可以再将awktst改写的更高端一些:

BEGIN{FS = ","} #FS是awk的一个默认变量,代表标示符
#下面这个其实就是body
{print $2}

我们执行的命令就可以改为:

cat a.txt|awk -f awktst

awk的参数和变量

可以看到,上面我们用到了$2来表示第二列,其实awk在分割上还有两个常用的变量,既
$0 表示整行
$NF 倒数第一列

我们也能自己定义参数,定义很简单:

a = 1
a = 'a'
a = "abcd"
a[b]=c #map形式

awk的语法

awk语法和c/java非常像,下面有个小例子,看一下应该就明白

k1 = "Chris";
k2 = "John";
age[k1] = 30;
age[k2] = 29;
 
for (ke in age){
    if (ke == "Chris"){
        val = age[ke];
        print "Hello Chris , your age is ",val;
    }
}

一个简单的例子:

#这是一个处理java异常日志的小脚本.作用是将今天的异常全部输出.
#java异常文件是一个第一列为日期的时间顺序文件,所以我们只要找到第一个今天的异常,然后将剩下的直接输出即可.

BEGIN {"date +%Y-%m-%d"|getline now;nowStart = 0}
{
    if($1 == now){
        nowStart = 1
    }
    if(nowStart == 1){
        print
    }
 
}

这是另外一个简单的例子

#有文件类似:
name salary age
chris 1000 30
john 1100 24
#我们希望获取薪水总和,平均年龄

BEGIN{
    personCount = 0;
    salarySum = 0;
    ageSum = 0;
    rowCount = 0;
}
{
    if(rowCount != 0 ){#第一行是表头,不处理
        salarySum += $2;
        ageSum += $3;
        personCount ++;
    }
    rowCount ++;
 
}
END{
    print "Total salary is :",salarySum;
    print "Average age is :",(ageSum/personCount);
}
$ cat person | awk -f awktst
Total salary is : 2100
Average age is : 27

从Ubuntu迁移至OS X.

前些日子把Ubuntu从1204升级至1304后,问题多多.
教训就是Ubuntu最好一直用LTS,如果实在要升级,建议重装,在原系统上Update实在不是一个好建议.

之前就一直很心仪OS X,这次就趁着机会入手了Macbook pro.

到目前用了一个礼拜,现在说说和ubuntu的区别.

1.OS X对文件的”剪切”不是特别提倡,拖动到另外一个文件夹的默认动作是拷贝.

2.OS X对于复制文件夹的目标目录中,假如存在同名文件夹的默认处理很怪异,它会删掉原文件夹,再把新的拷贝进去.而不是windows和ubuntu默认的那样是合并两者.

3.OS X默认没有类似apt-get或者yum这样的工具,可以安装ports或者homebrew,我看很多人都推荐brew,所以就跟大流了.用起来brew install XXX,除了不用sudo,其他和apt-get没什么区别.

4.mac把我们熟悉的ctrl键的功能拆成了commad和control,平时用起来command用的比较多.比如command-C,command-V,command-S,command-A,所以也没什么太大区别.但是,但是,对于我这个用惯了vim的同学来说,稍微有点分裂,因为在别的应用都是用command多,而到了vim中,又要大量的使用control,还是要适应一段时间,反正这一个礼拜了,现在用起来还得很刻意的注意一下到底是该用command还是control,没有之前用ubuntu那么行云流水.

5.OS X上软件质量都很高,远超ubuntu,对比windows也毫不逊色.对于非windows程序员来说,用这个完成日常工作问题不大.IDE,数据库管理器都有很好的软件.(虽然正版价格昂贵,但是破解版挺容易找,罪过罪过)

6.虽然OS X也是unix大家族的一员,但是有些在linux上好好的开源软件到OS X上可能会有问题,而且开源社区解决的速度远不如linux~比如今天就遇到的thrift 0.9.1在OS X最新的Mavericks上build失败的问题,社区说将留到0.9.2解决,我看了一眼bug,现在还是unresolved状态,鬼知道什么时候能搞定.

7.开发人员拿到OSX的第一件事最好是装X Code.里面集成了很多有用的东西,省的自己一个一个装,比如svn.

8.OS X默认读取的是~:.bash_profile,而不是ubuntu默认的~:.bashrc.经测试ubuntu的配置文件拷过来改个名字就能用.

———————————————————-

最后推荐一些我觉得mac上还不错的软件:

QQ,旺旺,QQ音乐,有道笔记,迅雷,有道词典,百度云同步盘.

iterm2 用来替代原生的终端.

textmate用来替代原生的文本编辑器(据说最新版已经开源).

Navicat数据库神器~

通过命令行提交bugzilla

python-bugzilla 是一个用于操作Bugzilla的命令行工具。
如何安装
以RHEL6为例

# wget ftp://rpmfind.net/linux/epel/6/x86_64/python-bugzilla-0.9.0-1.el6.noarch.rpm
# yum install python-magic
# rpm -ivh python-bugzilla-0.9.0-1.el6.noarch.rpm

除此之外还需要python的bugzilla和requests的module

解压后,到各自的目录执行:

sudo python setup.py build

sudo python setup.py install

安装好之后就有一个命令行工具 /usr/bin/bugzilla
如何使用
Bugzilla有非常多的功能,具体功能请 man bugzilla,这里仅以创建新Bug为例说明用法:

# bugzilla –bugzilla=http://bugzilla.youserver.com/xmlrpc.cgi –user=xxxx –password=xxxxx new –product=test-website –version=unspecified –component=test –summary=”test python bugzilla” –comment=”create bug for test”

JS实现无服务器交互的table表格CSV下载

工作需要提供一个表格的下载,常规的实现方式有如下2种:

一.将表格的查询排序条件重新提供给服务端,服务端重新查询数据并通过set http header的方式进行下载.缺点是1,页面需要对用户的排序行为进行记录,比较繁琐.2.服务器需要重新查询,如果查询比较复杂,效率是有问题的.

二.js将表格内容直接生成csv,然后将整个csv回推给服务端,服务端生成http头并将内容原封不动的返回.缺点是要进行一次服务器交互,且个人感觉服务端代码没有必要.

后来在网上查找更优方案的时候发现了data uri (Wiki),然后找了一些资料,最终完成了js直接通过页面的table元素生成csv并无服务端交互的下载.

主要步骤:

1.通过js构造csv

2.构造data uri并模拟a.click事件. 这里面在做的时候发现了一点问题,就是当直接对csv的string下载的时候,换行符会消失掉,考虑到data uri对base64的支持比较好.所以我就用了一个偷懒的办法-将字符串先encode为base64,然后将base64data作为参数.

firefox 25, chrome 25测试通过, safari对于a连接的download标签支持(影响下载后默认的文件名)有问题,下载内容没问题.

代码如下:

function downloadCSV(){                                                
    var data = $("#tableContent_").table2CSV({delivery:'value'})       
    var base64data =  base64encode(utf16to8(data))//if not utf16to8,chinese char will error                     
    var uri = 'data:application/csv;base64,' + base64data              
    var downloadLink = document.createElement("a");                    
    downloadLink.download = "mytabledata.csv"                         
    downloadLink.href=uri;                                             
    document.body.appendChild(downloadLink);                           
    downloadLink.click();                                              
    document.body.removeChild(downloadLink);                           
}

 

 

参考资料:

js table 2 csv

http://www.kunalbabre.com/projects/table2CSV.php

js base64 encode/decode

http://www.cnblogs.com/ricksun/archive/2012/08/27/2658654.html