Actionary

A man is valued by his works, not his words!

驱魔人 ——《软件驱魔术》译者序

从《画皮》里孙俪饰演的降魔人,《倩女悠魂》里古天乐饰演的猎妖师,到《西游》里年轻的驱魔人陈玄奘(文章饰)。不知道为什么,每个故事的驱魔工作者们无一例外,都是蓬头垢面,衣衫褴褛的造型。我一直在想,是什么样的工作性质,让他们如此狼狈不堪:爬高山,钻洞穴,寂寞伴身,学会守候……

我本人所在项目的代码库里,包含了从上世纪八十年代到现在,跨度将近三十年的代码,这个样本都适合做代码考古了,而公司目前有几百人正在从事这套软件的维护工作,维护工作的绝大多数时间就是在与遗留代码战斗。他们需要深入代码洞穴,攀登代码树,在错综复杂的逻辑结构中跟踪每一步可能的分支结点;除了要抓到贻害一方的缺陷,并且还必须在有限的时间里完成这一切工作,这就像美剧里演的一样,一个人拿着枪指着你的头,掐着秒表,逼着你在秒表归零之前完成复杂的网络攻击任务。作者把软件维护工程师们比做软件驱魔人,这是多么贴切的比喻。我现在才惊醒,原来我身边的人本应如孙俪一样俊俏,像古天乐一样有型,似文章一般阳光清纯,而“伟大”的降妖除魔工作,却让他们一个个如降魔人,猎妖师和陈玄奘一般狼狈不堪。

最近听到一个真实的故事:有位1990年出生的女同事,为了解决一个BUG,不得不修改一段1993年编写的遗留代码。加班到晚上八九点之时,这位女同事大发感慨“当我还只有三岁的时候,就有一位怪叔叔写了一段代码,等20年后我长熟了再修改。” 在笑喷的同时,我们也在沉思,还有多少遗留代码是我们孩提时就已经存在,并且需要我们去修改的呢?或者,我们给正在成长的幼儿园宝宝们,又准备了多少的“遗产”呢?前人挖坑,后人填坑,子子孙孙无穷尽也,这会成为我们这些软件从业者的常态吗?

作者Bill Blunden试图通过Software Exorcism: A Handbook for Debugging and Optimizing Legacy Code,告诉程序员们如何预防掉入软件维护的泥潭,冠冕点的说法,叫做从源头抓起。如果一旦进入缺陷的修改,如何进行调试,针对软件性能的提升,又有什么比较好的方法。从整本书的组织角度来看,条理性比较强。作者不求面面俱到,但从实用性的角度,还是给出了比较多的方法介绍和建议,如防御性编程,单元测试,软件跟踪,调试,优化,甚至调试器的内部实现,都有提及。本书非常适合初入软件维护队伍的从业者,对维护行列的老手来说,则会略觉浅显,但系统性的总结也是一个不错的参考。当然,对于编写软件的从业者来说,这也是一部值得学习的图书,第一部分关于如何预防,防止再次编写难于维护的代码就是不错的建议,同时,关于调优部分也一样受用。

在市面上各种编程语言介绍之类的图书大行其道的当下,这样一部专门讲授如何维护遗留代码的图书就显得异外扎眼。作者并没有提及太过高深的理论或技法,让人的感觉是更多的内容都是来自作者一线维护工作中的点点滴滴的经验总结。

参加本书翻译的几位译者都是IT从业人员,有着近十年的一线软件研发和维护经验,书中的描写更能引起一些共鸣,这也是我们将此书介绍给国内读者的初衷。当然,译者们翻译经验有限谴词造句难免会有出入或生涩之处,请读者批评指正,多多包涵。

感谢华章图书的编辑谢晓芳,及其耐心细致的编辑工作,她是我们见过的最有耐心的一位编辑,容忍我们一次又一次的延迟交稿,如果没有她这些可贵的品质,本书不可能出版。

感谢我们团队的小伙伴们,他们利用晚上的闲暇时光,帮助我们一起审读译稿,感谢公司给我们创造了一个开放宽松的学习实践环境,我们可以将书中所学传播到工作中,践行各种策略、方法和实践。

我们的小伙伴们:郑建琴,王刚,余鹰伟,周峰,凌建发,宓媛珊,吴恩平(排名不分先后),感谢你们。

译者

于杭州, 2014年下雪的春天 - End -

一群IT屌丝成为高富帅的故事 ——《孵化Twitter: 从蛮荒到IPO的狂野旅程》读书笔记

这是一本闲书,适合枕边阅读,看这本书,就像看电视剧一样,每个场景描述得就像真的出现在眼前一样,一群IT屌丝的欢声笑语与恩怨情仇。如果要给这本书一个更恰当的副标题的话,就是“一群IT屌丝成为高富帅的故事”。

作者也有意的在书中给每位角色给出前后反差的描写:

  • Evan从一个小农场的小农民,成为身价数十亿美金的高富帅;一直心量想得多,就是对别人好,也不会说出来,典型的国内IT群里好男人的形像,理想是想做个好大哥;
  • Jack从一个邋遢,就算辞职也要戴鼻环的IT黑客,成为一个追求时尚装扮的商人;我觉得他是作者描写得最腹黑的一位;
  • Biz Stone最后为了Evan的职位而怒发冲冠,完全颠覆了老好人的形像;
  • Noah则从原来的闹腾的大男孩,如何变成了一位沉默的人,默默地注视,默默地离去;他应该是最不得志的人了。

作者从几任CEO的维度来组织描写,下图是我从时间的维度给出的一个简介。

Alt text

从书中总结的几点:

  • 千万不要和朋友一起创业,除非你们能一直Align彼此的想法;
  • 什么创始人,什么技术并不重要,资本在公司才有至高的权力;
  • 对立的想法,并不会阻碍孕育成功的产品;
  • 成功的产品应该是集众人所长之大成;
  • 资本是逐利的;
  • 坚持自己的想法;
  • 重视身边的副产品。

这是最好的电影素材,如果搬上银幕,千万不要让我失望。

-End-

Build CI Environment With Gerrit, Jenkins and Subverison

1. Overview

1.1. Purpose

This idea is addressed by Simon and I during discussion. And we found Andriod open source community is using this way for a long time. So I’d like mark my practice notes here.

  • Gerrit is git repository management tools, more external reference you can read about the benefits of git
  • Gerrit provides good source code review web UI
  • Gerrit is easier to integrate with jenkins

So, from developer perspective of view, he/she can focus on source code changing/implementation, no more interruption from process manager or quality manager. From process manager view, he/she can define the source code commit and review process easier via gerrit configuration. From quality manager view, he/she can easier get the source code and review quality metrics which via developed metrics system (cooperate with jenkins and gerrit through REST query API).

Of cause, if your organization still using subversion, you can use subgit to sync the changes between subversion and gerrit.

1.2. Architecture

Alt text

Team can use subgit mirror the project to team owned gerrit server, and then team member clone the project to their local disk. Any changes making will be happen in local repository, after changes done. Developer can push the changes to remote repository (i.e., the gerrit server git repository). Once the changes is pushed to the server, gerrit will trigger jenkins to verify the changes (Compiling, unit testing, regression testing etc. CI jobs will be ran), and meanwhile, gerrit will send the review request mail to dedicated reviewer. After the reviewer approved the changes and jenkins verified okay, the source code changes can be merged into project master which is located in gerrit git repository. Otherwise, developer shall rework and push new patch again.

2. Gerrit Deployment

2.1. Installation

gerrit@gerrit-Workstation:~/gerrit$ java -jar gerrit-2.6.1.war init -d review_site

Once finish the installation of gerrit, it will be started automatically, or you can switch to $(ROOT)/bin folder, and execute command

gerrit@gerrit-Workstation:~/gerrit/review_site/bin$ ./gerrit.sh start
Starting Gerrit Code Review: OK

to start it.

2.2. LDAP Configuration

To support the LDAP authentication, you have to change the gerrit configuration under $(ROOT)/etc/gerrit.config, so that, you can use the LDAP type to authenticate the gerrit login and git operates.

[auth]
        type = LDAP
        gitBasicAuth = true  #This option means user can push source via ldap authentication during execute git related comments.
[ldap]
        server = ldap://ldap-server-address:389 #fill yours
        username = cn=BOOTMAN_Acc,ou=SystemUsers,ou=Accounts,o=... #fill yours
        accountBase = ou=People,o=xxx #fill yours
        accountPattern = (uid=${username})

2.3. Create a new project

Login the gerrit web UI

Type the http address of gerrit service on browser, in this case, it’s http://192.168.1.100:8081/, sign in with your account which stored in the ldap.

Create new project

Create new project, and “Rights Inherit From” shall be “All-Projects”, it means current you created project configuration(such as access control) will inherit from “All-Projects” project, of cause, you can select inherit from empty, or define your project owned properties by yourself.

Alt text Figure 1-1

After create this project, it means create a new project git repository under gerrit git repositories folder. In this case, the new project git repository is http://192.168.1.100:8081/gameoflife_java. You can clone this project in your local PC by execute this command.

client@client-Workstation:~/workspace$ git clone http://192.168.1.100:8081/gameoflife_java
Cloning into 'gameoflife_java'...
warning: You appear to have cloned an empty repository.

Now you have cloned the repository, because this repository is empty, so there is warning prompted.

client@client-Workstation:~/workspace/gameoflife_java$ git remote -v
origin  http://192.168.1.100:8081/gameoflife_java (fetch)
origin  http://192.168.1.100:8081/gameoflife_java (push)

2.4. Client works

As developer, the most of works are done in client site, since your local git repository will cooperate with remote gerrit git repository, we have to do some initial step firstly.

Get the commit-msg which is used for generate the changed-id:
client@client-Workstation:~/workspace$ cd gameoflife_java/
client@client-Workstation:~/workspace/gameoflife_java$ curl -o .git/hooks/commit-msg http://192.168.1.100:8081/tools/hooks/commit-msg
  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100  4276  100  4276    0     0   3515      0  0:00:01  0:00:01 --:--:--  4341
client@client-Workstation:~/tmp/gameoflife_java$ chmod u+x .git/hooks/commit-msg
client@client-Workstation:~/tmp/gameoflife_java$ 
Configure the git user properties:
client@client-Workstation:~/workspace/gameoflife_java$ git config remote.origin.push HEAD:refs/for/master
client@client-Workstation:~/workspace/gameoflife_java$ git config user.name erizhang
client@client-Workstation:~/workspace/gameoflife_java$ git config user.email eric.zhang@xxx.com
client@client-Workstation:~/workspace/gameoflife_java$ 

Okay, from here, you can execute general git command to commit and push your source code changes.

client@client-Workstation:~/workspace/gameoflife_java$ vim README.md 
client@client-Workstation:~/workspace/gameoflife_java$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#   README.md
nothing added to commit but untracked files present (use "git add" to track)
client@client-Workstation:~/workspace/gameoflife_java$ git add .
client@client-Workstation:~/workspace/gameoflife_java$ git commit -m 'add README.md to initialize this repository'
[master (root-commit) 585f136] add README.md to initialize this repository
 1 file changed, 18 insertions(+)
 create mode 100644 README.md

Execute above command, we have already commit the source code changes in local git repository, and then we have to push them to our gerrit server git repository:

client@client-Workstation-Workstation:~/workspace/gameoflife_java$ git push origin
Username for 'http://192.168.1.100:8081': erizhang
Password for 'http://erizhang@192.168.1.100:8081': 
remote: Processing changes: new: 1, refs: 1, done    
remote: 
remote: New Changes:
remote:   http://192.168.1.100:8081/1
remote: 
To http://192.168.1.100:8081/gameoflife_java
 * [new branch]      HEAD -> refs/for/master
client@client-Workstation-Workstation:~/workspace/gameoflife_java$ 

Please notice that there is remote: http://192.168.1.100:8081/1, for this change, there is change-id generated, and developer can distribute this URL to reviewer for source code review. Let’s open this link with our web browser: Alt text

Okay, reviewer or project owner can review this source code changes, approve the change and submit the change to master. Based on current basic configuration, only project owner and gerrit administrator have permission to approve the changes and submit the changes. In reality, the project process is not easy like that, we decide to nominate a group of people to take the key reviewer role of our project, only key reviewer can approve the final review.

2.5. Create ReviewBoard group and access control

Create ReviewBoard group and add the members

Login gerrit web UI with administrator, select “People” -> “Create New Group” Alt text

Access control of the new create group

Select our created project, there is “Access”, click and edit it. “Add reference” for refs/heads/* and refs/meta/config separately, see below diagram illustrate: Alt text

Till now, we have create new Group named “ReviewBoard”, and all members in this group have “Label Review” access control, in another words, they can approve the source code review. More information about access control, you can refer the gerrit official document Access Control section.

3. Jenkins deployment

3.1. Install Jenkins

jenkins@jenkins-Workstation:~/gerrit/jenkins$ wget -q -O - http://pkg.jenkins-ci.org/debian/jenkins-ci.org.key | sudo apt-key add -
jenkins@jenkins-Workstation:~/gerrit/jenkins$ sudo sh -c 'echo deb http://pkg.jenkins-ci.org/debian binary/ > /etc/apt/sources.list.d/jenkins.list'
jenkins@jenkins-Workstation:~/gerrit/jenkins$ sudo apt-get update
jenkins@jenkins-Workstation:~/gerrit/jenkins$ sudo apt-get install jenkins

3.2. Start jenkins

If you want to start jenkins with another port rather than default port 8080,you can modify below configuration file, and set the httpPort to your prefer:

jenkins@jenkins-Workstation:~$ sudo vim /etc/default/jenkins

Start jenkins:

jenkins@jenkins-Workstation:~$ sudo /etc/init.d/jenkins start
 * Starting Jenkins Continuous Integration Server jenkins                                                   [ OK ]
jenkins@jenkins-Workstation:~$

4. Gerrit Trigger

4.1. Install the Gerrit Trigger Plugin

Open your browser, and type the jenkins address, here we use http://192.168.1.200:8080, in the dashboard, choose “Manage Jenkins” -> “Manage Plugin”, and then you can find the Gerrit Trigger in the “Available” tab.

NOTE: If there is empty in the “Available” tab, maybe you should select “Advanced” tab, and click “Check Now” which locates the right-bottom of the page. Of cause, if you encounter the problem of connect internet, perhaps you have to configure the proxy under “Advanced” tab as well.

Select the plugin, and install without restart, the process which shows like this.

Alt text

4.2. Generate jenkins needs ssh-key for Gerrit Trigger usage

Since jenkins will operate gerrit via SSH protocol, to Gerrit, there will be a gerrit user account represents jenkins. So, this step is generate rsa key first.

jenkins@jenkins-Workstation:/var/lib/jenkins$ sudo ssh-keygen                                   -t rsa -C "jenkins@xxx.com"
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): /var/lib/jenkins/.ssh/i                                  d_rsa
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /var/lib/jenkins/.ssh/id_rsa.
Your public key has been saved in /var/lib/jenkins/.ssh/id_rsa.pub.
The key fingerprint is:
8d:e6:0c:42:cf:3b:d6:52:63:e8:a0:d7:9a:7b:5f:bd jenkins@xxx.com
The key's randomart image is:
+--[ RSA 2048]----+
|                 |
|                 |
|    .            |
|   . o . o       |
|    o = S .      |
|   . = X . .     |
|  . . B + . .    |
|   . +.o .   .   |
|    +o ..   E    |
+-----------------+

4.3. Create jenkins user account for jenkins

In jenkins server, generate the jenkins rsa public key by this command:

Create a new gerrit user jenkins

jenkins@jenkins-Workstation:~/gerrit/review_site/bin$ ssh -p 29418 erizhang@192.168.1.100 gerrit create-account --ssh-key - jenkins < /var/lib/jenkins/.ssh/id_rsa.pub
Enter passphrase for key '/home/erizhang/.ssh/id_rsa':
jenkins@jenkins-Workstation:~/gerrit/review_site/bin$ 

Now we have create a new gerrit account jenkins, this account will be used for the gerrit automatically trigger jenkins job purpose. Of cause, you can use gerrit set-account command to change the or add the account properties.

4.4. Configure Gerrit Trigger

Select “Manage Jenkins” –> “Gerrit Trigger”, you can enter into the Gerrit Trigger pages. Fill your Gerrit server host address, user name which represents jenkins to access gerrit, ssh keys etc., and click “Test Connection”. It will show success or not. See below diagram shows.

Alt-text

After then, save your settings and restart the connection in the “Control” section at the bottom of the page:

Alt-text

4.5. Add Label Verified Access Control to jenkins account

Firstly, please make sure, there is Label Verified of the project access control, by default, gerrit does not have this access control. You can refer the post How to edit the project.config for all projects in Gerrit to implement it. Here we add the “Label Verified” access control, and then any projects which inherited form All-Projects will have this access control label.

client@client-Workstation:~/tmp/a$ git init
Initialized empty Git repository in /home/erizhang/tmp/a/.git/
client@client-Workstation:~/tmp/a$ git remote add origin ssh://erizhang@192.168.1.100:29418/All-Projects
client@client-Workstation:~/tmp/a$ git fetch origin refs/meta/config:refs/remotes/origin/meta/config
remote: Counting objects: 4, done
remote: Finding sources: 100% (4/4)
remote: Total 4 (delta 0), reused 0 (delta 0)
Unpacking objects: 100% (4/4), done.
From ssh://192.168.1.100:29418/All-Projects
 * [new branch]      refs/meta/config -> origin/meta/config
client@client-Workstation:~/tmp/a$ ls
client@client-Workstation:~/tmp/a$ git config user.email eric.zhang@xxx.com
client@client-Workstation:~/tmp/a$ git config user.name erizhang
client@client-Workstation:~/tmp/a$ ls
client@client-Workstation:~/tmp/a$ git co meta/config
Branch meta/config set up to track remote branch meta/config from origin.
Switched to a new branch 'meta/config'
client@client-Workstation:~/tmp/a$ ls
groups  project.config

Open project.config, and append below lines into the file.

[label "Verified"]
       function = MaxWithBlock
       value = -1 Fails
       value =  0 No score
       value = +1 Verified

Execute below commands, to update the configuration.

client@client-Workstation:~/tmp/a$ git commit -a -m 'add verified label'
[meta/config 09b3910] add verified label
 1 file changed, 6 insertions(+)
client@client-Workstation:~/tmp/a$ git push origin meta/config:meta/config
Counting objects: 5, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 395 bytes, done.
Total 3 (delta 1), reused 0 (delta 0)
remote: Resolving deltas: 100% (1/1)
remote: Processing changes: refs: 2, done
To ssh://erizhang@192.168.1.100:29418/All-Projects
   7fa7742..09b3910  meta/config -> refs/meta/config
client@client-Workstation:~/tmp/a$

4.6. Create VerifyBoard Group and add jenkins user account in this group

Can follow section 2.5 to implement it.

4.7. Create the jenkins job

If you have already finished above steps, now you can follow the Gerrit Trigger official guideline to create the jenkins job. I’m not going to repeat it in this post again.

Further reading

Gerrit Code Review - A Quick Introduction

– EOF –