聊聊创业

如今来到喜讯已经整整三年了,这三年中经历了很多,也有很多的感想,期间也跟很多的朋友一起沟通过这个事情,有现在依然在喜讯共事的,有离开喜讯的,还有喜讯之外的一些朋友。

创业这个事情,在被各种媒体包装渲染之后,会让人觉得创业才是一个对事业有所想法的人的终极追求,如果能做到连环创业似乎会更被追捧。我并不知道这样的现象是好还是坏,因为在我没有加入创业团队之前,我也是每天看着这些报道,自己也会做创业相关的梦,也正是有这样的梦,我才来到了喜讯。

==== 分割线 ====

2010年5.1劳动节后,刘琪加入了喜讯无限(北京)科技有限责任公司,这里使用公司全称,我想说明的是从我加入公司之前,公司在法律和实质上都已经存在了。刘琪是我的大学室友,毕业之后我们依然是室友,在喜讯之前他在金山软件北京烈火工作室写代码。在他加入到喜讯之后,我那会儿正好在学习Android方面的东西,然后喜讯创业的方向是移动互联网,刚好公司需要有做Android的人,建议我去看看,在我一番矫情之后,请了半天的假去做了一个简单的面试,面试过程中老大和阿甘分别跟我聊了不久,老大就跟我聊了一些关于自己职业的想法(我记得当时说我三年到五年的目标是成为一个产品经理,那个时候产品经理还不是一个每个用微博和微信的用户嘴里的名词),老大追问了几句关于我关于产品经理所需要的素质和所需要做的事情,然后就聊开始聊了一些人生和编程的事情,因为老大曾经也是程序猿,所以就编程这个事情展开聊了不少,不过并不涉及实际的技术问题。之后是阿甘跟我聊,聊得最多的就是关于Android如何基于Linux通过Java将各种接口暴露给上层应用开发者,恰好这是我在超图一直做的方向JNI,所以聊得也还算顺畅。不过直到今天,我依然不知道我在阿甘那儿有木有过技术关。聊完之后,老大到电梯间我们聊天的地方,拍着我的肩膀说了句“兄弟,以后就看你的了。”。我就算是通过面试了,随时可以过来上班。

回到超图,花了半个月的时间办离职交接,期间也跟很多同事领导都沟通过关于离职这个事情,由于自己性格上的一些特点,在公司待的一年时间里,我除了自己本职工作之外,还做了几件可能让别人认识我的事情,就是参加公司每年的技术大会作为后勤保障组人员协助处理了很多琐碎的事情,包括布置会场,整理礼品,准备午餐等等;参加公司元旦晚会演出,并出演了一个哑剧的主角,获得第三名;参加研发中心组织的运动会并担任了总裁判。为什么要在谈创业的文章中描述这么多在之前公司的一些事情,貌似还故意搞得自己蛮牛逼的,为何捏?其实我只是想表达我之前在超图过得还算不错,有人缘,能干活,分内分外的都做得不错,有人愿意留下我。那么为什么我选择了离职呢?

这真的是一个非常非常好的问题,因为在我到喜讯之后的三年里,我也会不时地问自己,为何在那个时候选择里离职,而且选择了继续留在北京加入喜讯创业。回答这个问题还需要另一个背景,那就是在我打算离开超图之前我并没有打算留在北京继续工作,我非常希望能回到南方的某个城市,特别是能去杭州加入一个创业团队,特别是想加入虾米网这个团队,我在打算离开超图之时也确实向虾米网投递了一份比较煽情和二逼的简历,他们木有人屌我。

现在可以开始回到我选择离职加入喜讯的问题了,这个问题分两部分,第一部分,我为何离职,第二部分,我为何加入喜讯。

第一,在超图待了一年的时间,在这一年里我掌握了如何使用JNI技术来包装由底层类库组的同事们写的各种C/C++接口,通过Java层再将接口暴露给最终的SuperMap Objects for Java SDK用户。在这一年中,我学会了如何做事情,学会了如何与其他同事沟通,学会了如何写各种报告,开始学会了如何做一些简单的模块设计,这里需要感谢我之前的同事和组长。但是,我从他们身上,看到了不久之后的我,我想如果我继续在这里待下去,三年之后,五年之后我就是他们现在的这个样子,即便我比他们更努力,比他们更有智慧也罢更有运气也罢,情况应该相差不大。我无法接受在三年之后或者五年之后跟我之前的组长和同事是同样的状态,这个话我记得我在离职的时候跟我的组长沟通过,这并不是说我非常看不起他现在的状态或者鄙视对方的能力和成绩,我只是不希望成为那样。每个人都可以有每个人的选择,尊重他人的选择,做好自己的选择就好。那么如何改变我当时的状态呢,尽量让自己不要成为我不希望成为的那种状态呢?当然最直接的方式是离开,可是离开不能解决问题,离开只能帮助我不在超图变成那种状态,我也许会在另一个地方变成那种状态。因为我一直有阅读各种科技博客和技术博客的习惯,所以我会接触了一些关于创业公司文化的话题和文章,在我刚刚毕业一年的时间点上,对于各种创业的新闻报道足以对我的判断造成影响,我会直接地认为创业团队必然文化会宽松自由,每个人都可以畅所欲言,而且创业团队里头必然个个都是精英,如果我加入创业团队,假以时日我也会成为精英中的一员,因为我并不比别人笨,我也不比别人懒。抱着这个念头,我希望离开超图,加入一个创业团队,首先我选择向虾米投出了我唯一一份简历,结果是没有任何结果。

第二,在我有离职的想法之时,刘琪同学,我多年的好基友从金山烈火工作室离开了,加入了喜讯,开始创业。刘思家,我多年的好基友,在从超图离职后(他在超图时与我同组,我们背靠背坐着)加入金山烈火工作室后,在金山烈火工作室解散后,随部分人加入珠海西山居工作室,离开北京了。在刘琪入职喜讯之后,我们有过多次的沟通,多次沟通的过程中,刘琪对我传达了关于我们老大的很多信息,我觉得这个老大人相当靠谱,属于实干型和理想主义者,跟我个人风格非常像。我甚至自己有的时候都萌生过,妈的要是我也能加入该多好。可是那个时候,喜讯刚刚组建,所有人的研发重心还在Symbian智能手机上,我个人的技术背景中没有可匹配的地方。那个时候,刚刚好我开始真正接触Android开发,其实最早接触Android SDK时,我们还在中南大学南校区13-225住着,那个时候泡JavaEye(如今已经更名为ItEye)时关注过一段时间LordHong这个哥们的兴趣点,在那个时候接触过一些Android SDK的东西,但是没有真正做过一行代码的开发。说起这个事情,我觉得很有意思,直到我在2010年再次接触Android开发时,我才明白为何08年我折腾Android SDK时,那个模拟器一直在那儿启动,启动了5分钟以上都没有进入系统,那是因为我的机器真的是很烂,那个时候的模拟器效率也真的是很低,如果我尝试等了半个小时,也许我做研发的路线还真会有些不一样了。回到正题,在我投递简历给虾米之后,我已经打算提出离职了,但是还没有正式提出离职时,刘琪跟我聊到喜讯也正打算在Android上面做些事情了,然后他跟老大聊起过我,说让我过去聊聊。那个时候我不知是出于神马原因,竟然非常作地跟刘琪打起了官腔,说我都没有打算和考虑过这个事情,还不知道怎么跟公司这边请假,记得当时刘琪很气愤地说了一些话,大体的意思是“人家一个大Boss都愿意腾出时间来见你,你就请个假那么难吗?我都跟我们老大说好了。”其实,我当时一是没有底气,二是有点埋怨刘琪在跟老大沟通之前没有跟我说明事情,认定我非常想加入喜讯,其实那个时候我是有一点这个想法,但是并没有那么强烈。在被刘琪数落了一番之后,我也就想管他呢,去就去吧。第二天请假就去了,然后就发生了上面聊的关于面试的一些事情。但是这个还没有谈到,我为什么会加入喜讯,那么为什么呢?

首先,我认为创业会给我带来巨大的财富,这是我加入创业团队之前在各种新闻报道中所获得的一些认知,那时候我认为我只能加入一个创业团队,期待创业大成之后,获得巨大的物质财富。

其次,我认为老大是个靠谱的头,有可能带着我们这帮人取得不错的成绩。

第三,能加入一个新兴的行业做一些更有挑战的事情,让我有一些兴奋,而且团队的感觉还算比较好。

最后,在我想离职加入创业团队时,喜讯刚好出现了,我想这样算是缘分。

那么对于我加入喜讯是否就顺理成章了呢?其实并不是这样的,我在大学毕业找工作时做过一次决定,没有跟任何人沟通过,那么就是加入超图。工作后,加入喜讯又是在没有跟任何人沟通过的情况下作出的决定。这两个决定都是在我没有跟父母、朋友以及我的女友沟通的情况下作出的。我的父母在我上高中之后从未干扰过我做任何决定,至于我来北京工作,二老并没有任何的不愿意,只是会觉得孩子离家太远了,我女友只是觉得我并没有再去争取其他可能更好的工作机会,而只是得过且过见好就收,并没有在求职这个事情上做很大的努力。关于我来到北京工作之后,其实跟父母以及女友都有过多次沟通,都明确地表示过自己会离开北京,不会在北京待太久,很有可能会去杭州就业,女友和父母也都蛮支持这个想法,女友都想好了毕业之后如何去杭州就业的事情(那时她还在学校读研究生)。在我不告知他们的情况下,我又作出了人生中很重要的一个决定,就是留在北京加入一个创业团队,在当时还是蛮纠结的,包括跟我的父母和女后沟通都费了很长的时间和很多的精力,甚至都发生过一些冲突。但是最终大家都接受了,我的女友现在也来北京就业了。

就这样,我正式加入喜讯开始了创业。但是实际上,那个时候的我,并不知道什么是创业,只是跟着别人在做一些事情。三年的时间里,我能明显感受到自己身上的变化。

刚刚进入喜讯,开始做小游戏,身上有着很多奇怪的小毛病,自己碰到的问题放在那儿,期望着有别人来解决。WTF,这尼玛是神马情况啊?我也不知道,我害得我们老大跟我一起在那儿调试Bug,直到凌晨4点,我们老大的心脏不太好,那天旁边陪着我们一起加班的同事发现老大脸色不对才建议说今天先回去吧。

喜讯的初创团队大部分都是之前从烈火工作室出来的,我是第一个从外面招聘进来的人,我是第一个有试用期的员工,对于这一点,在那个时间点,我很不爽,我非常想向老大证明,我并不比别人差,我能做得比其他人更好。在我成功克服了,上面我说到的将自己置身事外的毛病之后,我开始喜欢去搞定各种问题了,而且通过产品(喜讯天天)在不断地向喜讯所有的同事们证明我是可以的,我想我做到了,我也得到了大家的认可,这让我开始有了一些主人翁的快感。

当我接触更大的项目(画说和MARK)之时,我已经开始可以参与一些系统和产品的设计了,这个时候我开始觉得我在主宰和推动一些事情了,我的责任更大了。当产品推出之后,接触到最终的用户之时,跟用户之间的沟通,会让我清楚地明白,这是我在做的产品,用户会将情绪直接表达出来,其中会有一些赞美和肯定,不过吐槽和谩骂也不会少。因为你知道的,当一个人被惹恼的时候,他更愿意告诉你他的感受。在跟用户通过Email,站内信和电话沟通的过程中,我需要直接代表公司,代表我们的开发团队。这个时候,我明白了这个世界上没有什么问题是用户的问题,尼玛用户碰到的所有问题都是我的问题,如果我们没有能力解决用户碰到的问题,那么我们就会被淘汰,因为会有其他的人和团队愿意来解决用户的问题。所以不要说“在我这里是好的啊”“没有问题啊”类似的话,根本毫无意义,我们要跟我们的用户去解释“这是您机器显卡型号不支持的原因”吗?靠,如果你知道是这个问题,为何不在产品中做一个特殊处理,这个版本没有解决,那么下个更新尽快解决。跟直接用户直接地沟通,让我体会到了我对于用户的价值,我能解决他们的什么问题,更让我明白了我在公司中的角色,我需要在公司中解决哪个环节的问题,这样我们的公司我们的团队才能走得更远走得更好。

当项目开始需要加入新的人手之时,我开始需要学会面试,招聘和培养新的伙伴了。首先我需要承认的是,我在喜讯三年,带过三个伙伴一起做事情,但是目前三个伙伴均已离开喜讯,其中不乏我的影响。所以,我可以说在这个事情上,我让公司损失很大,我们花费了不少的精力和财力来培养这些伙伴,但是他们未能跟我们一起走下去,我很惭愧,我可以认为我首先对不起公司,对不起现在还在公司的所有伙伴们,同样我也对不起那些已经离开的伙伴们。在创业团队中,选择伙伴非常重要,不只是需要选择能跟自己共事的伙伴,跟需要能跟公司一起走下去的伙伴。在做出选择之后,更是要做恰当的引导,否则对于每个人都是伤害。

当公司战略方向发生改变时,并且与我个人兴趣出现不匹配时,我要如何做判断和选择就更加重要了。喜讯之前定位的是要做社区,要做移动互联网上的社区。对于做应用和社区,我个人一直都有非常浓厚的兴趣,这也是我在之前的喜讯天天、画说和MARK中能找到自己位置的重要原因。而对于游戏,我个人一直都不是很感冒,甚至都会有排斥。前几天跟刘琪一起吃饭,刘琪还说我曾经说过“如果喜讯最终要做游戏,我就会选择离开”,如今喜讯开始做游戏了,我没有离开,而他已经离开一年多了。为什么我没有离开?我之前说过的话是否就跟放屁一样?当然可以这么认为,不过显然我自己不是这么想的。当我在喜讯已经待了三年之多,跟所有的同事合作得相当顺畅之时,我显然不会轻易选择离开,这是关于一个舒适领域的问题,也就是说我目前在喜讯整体的环境中,我生活得非常自在我不会轻易作出离开这样的决定。另外一个,从技术和兴趣角度上来讲,游戏一直离我很远,但是公司整体团队的基因其实是做游戏的(烈火是金山的一个游戏工作室),那么公司整体转向做游戏其实也是一件蛮靠谱的事情,另外从自己待惯了的技术领域跳出来进入到一个并不熟知的领域,虽然会有不舒适的感觉,但是对于我个人的成长来讲其实是非常有帮助的。很多人说三年是一个坎,五年是一个坎,我已经过到第四年了,目前看来还算正常,但是还需要更大的挑战更多的磨练,恰好进入到一个自己不熟悉的领域中是一个很大的挑战,同时成为游戏项目的经理更是对于我个人在管理项目和团队上是一个前所未有的挑战。以前,我一个人冲锋陷阵,最多就带上一两个伙伴一起,而且是在自己熟悉的阵地,打得还算从容,虽然没有大成绩,但是起码自己不发慌,现在不一样了,情况更复杂,团队人员数目也更多,需要跟更多的人沟通,关键是自己对于核心的技术和模块没有任何认知,心里首先就会有个疙瘩在那儿。不过这恰恰是我现在需要去解决的问题,公司未来能否成长得更快更好,就是取决于我们这些在做具体事情的人,每个人都能成为精英,公司才能顺利地走下去。

所以公司战略发生改变并不会对我个人的判断产生影响,而且因为我需要承担得更多,我也希望自己承担得更多,我选择必须迎头赶上。在公司战略方向改变的过程中,如果我们过多地顾及个人情绪和兴趣,那么留给我们的只能是失望,因为大船已经掉头往其他方向航行,我们如果继续坚持不跟随作出改变,带来的只能是负作用,对个人对团队都是如此。

加入喜讯创业已经有三年时间了,三年时间里经历了不少,成绩不多。明白了一些事情,也错过了一些事情。

有一个靠谱的团队,执行力过硬,具体做什么事情和什么方向相对而言已经不是那么重要了。

一个靠谱的点子(不论是否新颖独创),其实对于创业团队来讲只是最基本条件,决定性作用根本不在点子的好坏,在于能否执行下去。

创业团队的文化,会有前期创业团队成员深刻的烙印,当然这些前期团队成员必须承担得足够多,否则影响力和其加入团队时长没有任何正相关的关系。

初创企业的人胜过一切,不要试图通过理想或者物质来煽动你的伙伴,摆事实讲规划做执行,让伙伴看到过程和结果。

创业过程中,我们肯定会错过很多的好机会和好点子,不要后悔自己当初的判断,如果想不后悔,那么从下一个机会或点子开始,一定要努力抓住,通过你的双手去抓住,而不是通过你的嘴去抓住。

 

==== 分割线 ====

当我跟我的伙伴们早上跟同在一栋大楼里上班的人一起乘坐电梯的时候,我们多次听到类似“还有三分钟,今天肯定不会迟到”“8点31分不算迟到”类似的话,当我们从电梯出来之后会心一笑时,我觉得在喜讯我们已经做好了一些事情,我们正在往正确的路上走,我喜欢这种感觉,我的伙伴同样喜欢这种感觉,我想这就足够我兴奋一段时间了。

关于strlen的小迷惑

首先,说明一下,我不是一个C程序猿,也不是一个C++程序猿,我从入门开始真正学习的编程语言以及正经用过的变成语言,也就是Java和C#,虽然我对其他的语言都非常感兴趣,同时也写过一些Python的脚本和C的代码(主要集中在JNI)。

由于这些年来的编程习惯,我认为字符串都应该会有自动获取其长度的方法,在前几天的工作中就碰到需要使用这个方法的场景了。由于我对strlen()使用的不慎,导致程序输出时而正确时而错误,最终定位到是因为使用strlen()方法获取字符串长度在多次执行后的输出不等,导致程序出现了不可控的情况。

那么是否是因为strlen()方法的问题呢,我自己首先十分肯定绝对不会是这个方法的问题,这些方法在时间和实践中都尼玛得到过太多的验证,且看Linux中的实现:
[c light=”true”]
#ifndef __HAVE_ARCH_STRLEN
/**
* strlen – Find the length of a string
* @s: The string to be sized
*/
size_t strlen(const char * s)
{
const char *sc;

for (sc = s; *sc != '\0'; ++sc)
/* nothing */;
return sc – s;
}
#endif
[/c]
这么简洁的实现,多么漂亮啊。肿么可能会出错捏?好吧,实际的应用场景是我需要将一个从C#运行时托管层将一个byte数组传入Native层,在Native层面做一些操作的时候呢,我直接使用了strlen()函数来确认当前byte数组的长度,尼玛脑残啊。托管层byte数组虽说可以认为是Native层的unsigned char数组,但是我并木有意识到C层的字符串都是需要’\0’来作为终止符滴,显然从托管层传入的数组中不会自行添加这个到数组中。所以才会出现偶尔内存中该数组后面确实没有任何值,那么strlen()函数在刚好读取到数组后的值为空时,那么其长度刚好正确,在某些时候该数组后连续的内存地址中并不为空,那么strlen()就会返回一个错误的长度,而我的逻辑代码又依赖于该长度,所以你只到的,Just Fucked Up!

所以在托管层申请的内存,传入Native层面时,一定要注意两个平台下对某些概念处理的不一致,否则到时候又得吃自己的狗屎了。WTF。

数字消费碎碎念

前几日将《重来》这本书给看完了,书中提到需要将自己的知识分享出去,分享你的知识能获得的将远远大于你付出的东西。自己深有同感,所以尝试重新开始写作,记录,先从非技术类开始吧。

我是一个程序猿,入行如今已经有四年时间了。从入行开始到现在,我个人在数字消费上的额度日渐上涨。其中包含的类别也蛮多,有购买软件的,有购买服务的,还有捐赠的。

记得第一次购买正版软件是在超图实习的时候,那时自己找朋友借钱买了个新的笔记本,当时机器拿回来之后安装了360安全卫士,当时看到有Nod32的促销,自己当时就直接购买了一年的正版服务,加上当时360促销的半年,应该是为期一年半的时间,具体价格忘了,应该是蛮便宜的,应该在50块钱以内。记得当时有一次不经意的聊天中,同组有个同事提到他购买了一个正版的杀毒软件服务时,我也顺口说了一嘴。旁边其他的同事当时觉得我俩很奇怪,我也觉得他们很奇怪。这是我第一次数字消费,Nod32也一直在我的机器上跑了一年多。直到我将笔记本的主要工作系统换成Ubuntu时,我在电脑上装了一个盗版的Win7,然后购买了3年的卡巴斯基,到今天还剩100多天的可用服务时长。这是我毕业之后在安全软件上的支出。

在超图实习期间,自己想架设一个自己的WordPress博客,也就是这个站点。然后正式工作的时候,就打算建起来,记得当时是在胡戈戈的店里买的一年的空间,域名还是胡戈戈帮忙给申请的,非常感谢他。记得当时两个费用加起来不到两百块钱,虽然在当时我一个月试用的工资只有2800块钱,但是我觉得100多块钱显然完全能够接受。

在超图工作的近一年的时间中,慢慢地我们伟大的GFW越来越厉害了,作为技术人员我显然不愿意被拦住,那个时候总是在网上找一些代理和第三方的应用来上Twitter,直到我使用的大部分应用和代理都无法正常使用了。这个时候我开始购买了一个名叫Puff的服务,购买了一年的服务。在Windows上有客户端,当时Puff还不能支持VPN连接,只能通过其客户端来完成连接,所幸的是它的客户端在Ubuntu下通过Wine可以完美运行,所以那个时候Puff帮助了我很多,感谢Puff的作者。

之后来到喜讯之后,身边有同事是做服务器的,刚好之前购买了为期一年的空间到期了,当时他建议将我的博客搬到他的VPS上面,然后免费蹭了半年。刚好公司搬家到天居园,那时候AWS刚好有一个EC2的活动,可以创建一个Instance免费使用一年时间,当时公司所有程序猿果断都申请了AWS帐号,创建了一个Instance,将自己的博客搬过去之后,也没有做什么其他的事情,这个时候我购买的Puff一年期服务也到期了,有了EC2就不愁神马翻墙不翻墙了,直接一个ssh连接就搞定了。这段时间内是自己学习最快的时候,这个EC2帮了很多的忙,感谢Amazon。顺便提一句,我是Amazon忠实的粉丝,能在Amazon上购买的东西,包括书和数码产品,从来不再别的地方购买。

在EC2免费到期之后,由于EC2年收费确实太贵,我们几个同事合租了一个VPS,之前用的是国外的某家VPS,目前是使用的42区的,非常不错,速度很好也很稳定,ssh很少会掉线。大家几个人平摊,每年每个人也就三四百块钱,物超所值。

另外由于很多Android设备不支持直接设置Http代理(小米手机的MIUI是可以),在当时测试Facebook接口的时候,我购买了一个VPN,当时选择的是一个名叫Runoz的VPN,目前使用了快一年,速度非常棒,客服响应速度更是超快。一年收费才尼玛100块钱还是多少,反正是非常便宜啦。一个帐号可以同时登录5台设备(我购买的时包年套餐),不限速不限流量,看什么Youtube根本不在话下,貌似除了迅雷等P2P软件会被禁,某些服务器上不建议经常下载,其他的限制根本就没有。

当然这些年陆续的域名续费肯定是要的,每年也就19.99美金,目前手上就两个域名,还算能接受。

作为一个程序猿,在解决了墙的问题之后,个人生产力已经明显得到了提升。在此之余,我们总不会放弃任何一个还有可能提升个人生产力的途径滴。在持续使用了一年多Ubuntu之后,我将工作环境切换到了Mac OSX上了,因为我是一个有轻微强迫症的人,我在使用Ubuntu的一年多时间内,尝试安装了很多新奇的软件,每次系统提示有更新,我都会毫不犹豫地选择更新,从来不等到第二天,而Ubuntu总是会在某次升级之后导致某些很小的功能会出现一些小问题,而我又是一个强迫症,很多时候要求我全心全意来工作去解决问题的时候,我的工具竟然让我不爽,很显然这个我是无法忍受的。

切换到Mac OSX上之后,发现了很多原本没有接触过的小软件,有付费的有免费的,下面列举一些我每天都在使用的,大部分都非常的棒。

Cnich,用于完成Win7下默认窗体自动最大化的功能

Dash,程序猿查看API文档神器,有了她之后生活更美好,该软件是共享软件,你可以免费一直使用,但是可以支持作者购买正版授权,这款软件是我迁移到Mac OSX下的第二天发现的软件,当天试用了1个多小时,直接购买了正版授权,也不算贵当时是半价,忘了是19.99美金还是9.99美金,应该没有超过100块钱。

1Password,因为工作中会涉及到一些公司帐号的密码,通过密码管理软件来管理总比直接放到Excel和Txt文件中靠谱,何况这款软件做得也是十分的良心,虽然比较贵,不过购买Family License还算划算,可以跟同事一起分担费用,Family License同时支持激活5台设备。

EuDic,有免费版的,付费后可以开启自定义词典的高级功能,虽然这些自定义词典大部分都是网络上开源的或是免费的资源,但是必须开启该功能后方可使用。售价不高,因为目前自己尚不需要暂时未购买该功能,之前一直使用StarDict,不过在Mac下EuDict将Mac的各种特性发挥得非常到位,你值得拥有。

MenuMate,在使用双屏环境时,经常需要将鼠标从屏幕二移动回主屏幕来操作Menu菜单,有了MenuMate之后就可以在任何地方直接呼出当前应用程序的Menu菜单了。当时做活动时购买的,花了0.99美金

Timing,一个每天默默在后台为你自动记录你在电脑上不同的软件上耗费的时间,可以非常快的判断你这周在电脑上将时间花在了开发、浏览网页、游戏上,活动时购入,也是0.99美金。

TextMate,目前我还不算真正会使用这个工具,只是作为简单的文本编辑器来使用的。

MacVim,有些操作还是习惯在Vim下完成,MacVim不仅有Vim的完整功能,同时又加入了一些更友好的特性,在Mac下非常贴心。

Sublime Text 2,神器一般的存在,目前使用得不多,只在写python脚本的时候会用一用,因为其在Linux环境下不支持中文也让我蛮纠结,另外使用频率太低,目前我还木有欲望来购买其正版授权(70$有点小多啊)

Parallels Desktop,因为某些网银的问题有的时候还是需要通过Windows下的IE来完成,所以这个你懂的,这个直接购买中文版即可,人民币239元,不贵好使。

Mou,Mac下Markdown文档编辑神器,作者也算神人了,凭一人之力完成了很多Mac下优质的软件,这是他开发的众多软件中的某款共享软件,目前我在写各种文档的首选就是Mou,我相信Markdown未来会是程序猿首选的文档交流格式。

Remote Desktop,这是目前我购买最贵的一款软件直接将Parallels Desktop给爆了,售价99美金,不过貌似购买了之后会自动获得iPhoto和GarageBand。这其实就是Mac OSX下的远程桌面连接功能,卖得可真够贵的,不过工作中需要从某台机器上去操作另一台机器,关键是还一定要进入图形环境,所以好吧,我选择妥协。

就在我写这篇文章的时候,微信公众号『Mac技巧』发布了一个MacHeist的Mac软件包打折的消息,我去看了一下,里头有一个是我非常想要的工具,那就是xScope,之前因为自己需要一个屏幕尺子,而在Mac下并没有找到免费的趁手的(FreeRuler体验已经非常不错,但是还无法达到我的要求),单独购买一个尺子委实太贵(Mac App Store中大部分尺子售价都在12人民币以上)。除了xScope之外还有一个神器就是PathFinder,虽然较Windows平台下的Total Commander稍逊一筹,但是也有其过人之处,关键是打包购买总共才9.99美金,尼玛的活动主办方还要将收入的10%捐赠出去,尼玛你还可以自行选择捐给哪个慈善组织,我默认选择平均捐给所有可选的慈善组织了。

MacHeist软件包如下:

xScope

iStopMotion

Totals

Clarify

AirServer

Fantastical

CleanMyMac 2

Little Inferno

Path Finder

Money(需此次活动售出份额超过55K才会解锁,童鞋们加油吧)

此次购买纯属巧合,昨天该活动结束之后,主办方貌似又追加了3天时间,我昨天就在还剩一分钟的时候才点击下单的,这个1分钟当然不是我在犹豫导致滴,其实时我得知这个事情的时候打开网页就只剩下45分钟了,但是我并木有看到这个消息,在告知同事有这个优惠活动之后,我就开始了当天的工作,想着中午吃饭的时候下单,当时我并没有意识到这个有时间限制,然后在上班过程中突然想起『Mac技巧』提到还剩13个小时,赶紧回到页面,刷新一下发现时间就剩1分钟了。尼玛果断下单付款之后,回到活动页面刷新,果真落下帷幕了,不过还好现在又延长了3天时间,大家购买的时候就不用像我这般如此仓促了。

在作为一个二逼程序猿的同时,我还是一个纸制品重度爱好者,阅读爱好者(注意,我木有使用重度了),只要有可能,我想拥有一切我看到过的优美的纸制品,想阅读所有我看到的好的书。有人说我很文艺,我觉得我一点都不,只是我喜欢的东西跟大家不太一样,内里我依然很土逼。既然咱们今天聊数字消费,还是回到正题吧。

我一直非常钟爱纸质书,纸质书的味道和编辑的品味是能让读者有一个很直接的感官的刺激的,不过这并不妨碍我同样喜欢阅读电子书。我购有一个Bambook,虽然使用频率不高,但是其在阅读Txt类的武侠小说的体验上绝对是最棒的(这些Txt电子书应该是有版权问题的,我确实无耻地看过很多类似的武侠小说)。我在电子书上其他的消费,全部是在我转向使用多看阅读这款软件开始的,之前我在Android平台上一直使用iReader这款软件,就因为我当时购入的Google Galaxy Nexus手机系统是Android 4.0,而iReader会不时地导致我的机器重启,无奈之下我只得寻找替代品,之前听说雷总投资了多看,然后Google了一下多看的相关资料,顿时感觉相见恨晚,果断装上。之后的电子阅读,百分之九十都是在多看上完成的,在我购买了一本《黑客与画家》纸质版本之后,多看阅读在数月之后推出了电子版,当时售价是¥12.00。那时刚好电子书炒得比较热,包括当时红极一时的唐茶的出现,我也非常想尝试一下电子书的消费是一种什么样的感觉和流程。Android版本的多看支付实在是方便,直接点用支付宝快捷支付服务,在不到1分钟的时间内,我就购买成功了。在我购买电子书之时,家中的纸质版本我才看到大概5~7页的样子,但是我在手机上花了不到2周的时间,这本书我就读完了,我那些上下班路上以及其他的碎片时间中,大部分时间都是在阅读该书。

初体验非常完美,价格合适,适合碎片化阅读,后续又购买了若干本。因为多看定期会推出很多限免书籍,我也会选择性的下载,不过购买的书籍阅读的概率明显偏高,因为我购买的书籍肯定是我当下非常想看的,限免的书籍也有不错的,更多都是图免费下载的,看的可能性并不是很大,最近已经不再下载自己不可能会看的限免书籍了。在多看上购买的书籍有:

《黑客与画家》

《公司的力量》

《凡客不凡》(这是购买公司的力量获赠的)

《煲一碗靓汤》(这是多看3.8妇女节活动获赠的)

《重来:更为简单有效的商业思维》,这本书真的只花了1周的时间竟然看完了,这一周竟然还是我这半年来最忙的一周,可想而知碎片时间阅读的产出能有多高。

《极简欧洲史》

 

在此之余,在App Store上还购买了一个游戏《战神之怒》(老比说的好,尼玛做游戏的,不玩别人游戏不太现实,该花的钱还是得花)。

回过来说说捐赠,原本捐赠不应该当作消费的,不过在我个人看来没有很大的区别,帮助别人并没有那么高尚,更何况所尽之力非常微薄。纯粹的数字捐款有几回,给Wikipedia捐过两次,数额不大,给去年的刷票助手也捐了很小的一点钱。至于其他的捐款还是不要说了,离这个主题太远了。

数字消费如此顺畅,不得不感谢为此做了很多事情的一些公司和组织啊。首先,信用卡发卡行和Visa,让我们在海外网络消费支付上完全不成问题,购买各种软件和服务,消费比国内使用支付宝都尼玛方便。其次,支付宝让购买电子书非常方便快捷。正是这些公司和组织不断地优化了很多的流程,我们才能如此顺畅又舒服地做各种数字消费啊,真心感谢招行、Visa和支付宝。

CentOS 64位机器安装配置Jenkins集成编译Android项目

之前一直想在公司搭建一个集成编译的环境,一直没能成行,这次终于着手去做了,发现之前的Hudson已经演变成了如今的Jenkins,关于Oracle跟各个开源社区以及其他厂商的一些关于商标的纷争真的很有意思,我觉得未来有可能的话,真的可以专门写一些关于这个话题的东西。具体可以参考wikipedia上的介绍

因为Jenkins是基于Java Servlet实现的,所以需要依赖于某个Servlet Container来运行,我选择的是Apache Tomcat。Tomcat也是基于Java实现的,那么开始第一步吧。

第一步 安装SDK

自行下载JDK,安装配置环境变量,如下:
[bash light=”true”]
export JAVA_HOME=/usr/local/jdk1.6.0_29
export PATH=$JAVA_HOME/bin:$PATH
export CLASS_PATH=$JAVA_HOME/lib/dt.jar:$JAVA_HOME/lib/tools.jar:.
[/bash]

第二步 安装配置Tomcat

下载tomcat安装包,直接解压,配置环境变量:
[bash light=”true”]
export CATALINA_HOME=/root/apache-tomcat-7.0.33
[/bash]
在CentOS的/etc/sysconfig/iptables配置文件中加入规则:

-A INPUT -p tcp -m state --state NEW -m tcp --dport 8080 -j ACCEPT

通过$CATALINA_HOME/bin/startup.sh启动tomcat,找个浏览器试试能否访问,http://your_centos_server_ip:8080

确认tomcat能正常访问之后,开始第三步

第三步 安装配置Jenkins

Jenkins的主页下载Jenkins的war文件,将该文件拷贝至$CATALINA_HOME/webapps目录下,tomcat会自动将war文件解压并部署,找个浏览器试试能否访问这个地址 http://your_centos_server_ip:8080/jenkins,如果可以的话那么Jenkins就算是部署好了。

第四步 配置Android SDK和NDK环境

这一步可能会稍微多一些,可以参考我的这篇文章,CentOS 64位机器配置Android SDK和NDK环境

第五步 创建一个Jenkins的Job

完全按照Jenkins的提示和帮助一步步进行下午,非常简单。

  1. 给Project设置名称
  2. 配置获取最新代码的方式,Jenkins目前自带了CVS和SVN的插件,如果你的代码是通过git来管理的,只需要安装一个git的插件即可,Jenkins有非常丰富的插件,Jenkins => Manage Jenkins => Manage Plugins,进入插件管理页面,打开Available的Tab页面,在Filter中输入git,然后找到 Jenkins GIT plugin,勾选前面的复选框,之后点击页面下方的Download now and install after restart,让它自己安装然后重启吧,重启之后就可以配置通过git来获取代码了
  3. 设置编译触发器规则,应该是完全和Linux cron的规则一致,可以google之。
  4. 配置如何编译方法,在服务器上我们肯定是脱离ADT环境的,通常我们会使用Ant来进行编译,自行下载并配置Ant的环境变量,确保ant命令可以正常使用
  5. 先通过android命令更新当前需要编译的项目,确保ant能找到正确的sdk路径和其他的配置,需要编译release包的话,可以在project.properties中配置好用于签名的keystore文件,具体可以参考这篇文章,然后在Jenkins中配置shell中输入 android update project -p $WORKSPACE -n 工程名 -t 编译目标
  6. 配置Ant编译目标为release
  7. 点击Save之后,回到Job的首页面,点击Build Now,开始编译吧。可以通过查看Console Output来看所有编译的输出信息,有错就一一排查吧。

CentOS 64位机器配置Android SDK和NDK环境

做个小备忘。

因为工作上的一些需要,需要在CentOS 64位机器上搭建一个编译Android项目的环境,Android SDK的环境还比较好搭建,直接下载android-sdk包即可,下载页面链接在这里http://developer.android.com/sdk/index.html,我下载的是sdk only包,体积比较小不包含ADT包(在服务器上用不着这些东西),因为是在服务器上,所以是木有任何桌面环境的,也就木有桌面浏览器啦。用wget或者curl下载即可。下载成功后,解压,可是目前目录下面只有tools目录,没有platform-tools目录,这个目录下的东西可不少哦,神马aapt、dx等等非常重要的工具都可是在这个里头哦,通常我们都是直接通过android命令就可以启动Android SDK Manager的界面管理工具,通过勾选不同平台就可以选择性地更新哪个版本的sdk了。服务器上木有swt环境啊(Android SDK Manager是基于SWT实现的),肿么办捏?程序员做的东西肯定是有命令行界面的嘛。come你的on,google一下吧,结果在这里,万能的google,程序员的福音stackoverflow上已经有人解决了该问题。大体就是通过

android list sdk

这个命令来查看有哪些sdk可以更新,你可以可以通过

android --help list sdk

来查看其他的一些选项,例如通过

android  list sdk --extended --all

来查看所有的可用的(包括Android认为已经过时的,例如2.3.3之类的各个android版本的SDK,而且会将名字给你写出来哦),例如:

id: 61 or “extra-android-support”
Type: Extra
Desc: Android Support Library, revision 11
By Android
Install path: extras/android/support

这个指的是就是Android的suppor-library,其他的各个名称也很直观啦,这些名字可以用的地方呢就是我们在使用
android update -u
命令进行SDK更新的时候可以通过设置filter来选择我们需要安装哪些包,例如下面这个命令:
android update sdk -u –filter extra-google-google_play_services
执行之后,就会选择Google Play Service这个包来下载更新,同理其他的都素一样的啦。例如通过
android update sdk -u –filter platform-tool
会自动下载platform-tools目录,你要是加上platform,使用
android update sdk -u –filter platform-tool,platform
就会下载所有版本的platform文件,其他的命令自己一个个尝试就好了。等下载完成之后,配置PATH变量吧
export ANDROID_SDK_HOME=/root/android-sdk-linux
export PATH=$ANDROID_SDK_HOME/tools:$ANDROID_SDK_HOME/platform-tools:$PATH
配置完SDK,那么开始配置NDK吧,毕竟很多时候我们在开发的过程中还是很有可能会使用到NDK的,那么开始吧,先下载NDK包吧,下载页面在这里,选择对应平台下载链接下载吧,下载成功后解压缩之后,配置环境变量吧:
export ANDROID_NDK_HOME=/root/android-ndk-r8c
export PATH=$ANDROID_NDK_HOME:$PATH
配置好环境变量,加载一下环境变量,然后开始测试一下能否编译吧,cd到samples/hello-jni/jni目录下,直接执行ndk-build命令,提示错误
./../../ndk-build: /root/android-ndk-r8c/prebuilt/linux-x86/bin/make: /lib/ld-linux.so.2: bad ELF interpreter: No such file or directory
提示缺少某个依赖文件,Google之后得知,通过命令
yum install glibc.i686
装上glibc库即可,再次尝试ndk-build,依然提示错误
/root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/../lib/gcc/arm-linux-androideabi/4.6/../../../../arm-linux-androideabi/bin/as: error while loading shared libraries: libz.so.1: cannot open shared object file: No such file or directory
提示缺少zlib库文件依赖文件,Google之后得知,通过命令
yum install zlib.i686
装上zlib库文件之后,继续ndk-build,这次能顺利编译出so文件了,也成功将文件拷贝到对应的libs/armeabi目录下了,可以有这么一个警告信息:
/root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-strip: /lib/libz.so.1: no version information available (required by /root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-strip)
大体的意思就时因为/lib目录下的libz.so.1版本信息不对,导致arm-linux-androideabi-strip命令无法正常执行,这个会带来神马问题捏?我们来看看吧。其实就是/root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/下的arm-linux-androideabi-strip命令没有办法执行呗,那么这个命令是用来干嘛的,直接运行一下看看usage:
Usage: /root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-strip <option(s)> in-file(s)
Removes symbols and sections from files
大体的意思就是通过这个命令可以将我们编译出来的so文件中的一些不必要的符号和片段给移除掉,可以让这个二进制文件更紧凑一些,运行效率会高一些?这个我真不知道,因为自己对于编译和链接这一块儿懂得真是太少了所以也就没有什么发言权啦。闲话少说,既然看到有问题,当然这个so肯定是可以用的(因为ndk-build并没有出错,而且还将so文件install到libs下对应的armeabi目录下了,我想Android开发团队肯定不会坑爹地将一个可能出错的编译输出文件install到该目录下的,所以说这个问题应该不大,肯定可以正常运行),只是看到这个警告信息让我非常的不爽,或者移除了这些符号和片段会让你的二进制文件运行起来更爽,或者可以让别人无法通过反编你的so来查看你调用了什么函数之类的,具体原因不明,反正我就是不爽,我要让这个警告信息给我消失。怎么办呢?

肯定先google啦,google了很多,看了一些文档,大体得出结论是这个libz.so.1的版本比较低,而android这个命令可能比较新,依赖的库的版本比当前我的机器上/lib目录下的libz.so.1的版本要高,好吧,那就去下载源码自己编译吧。可以到这个zlib的官方页面上的这个下载地址(WTF,竟然需要翻墙)。下载后解压之后,cd到zlib目录下,三步走
./configure
make
make install
整个过程很顺利,编译后的文件都被放到/usr/local/lib下了,这个可以通过编译安装输出看出来
[root@helihua zlib-1.2.7]# make install
cp libz.a /usr/local/lib
chmod 644 /usr/local/lib/libz.a
cp libz.so.1.2.7 /usr/local/lib
chmod 755 /usr/local/lib/libz.so.1.2.7
cp zlib.3 /usr/local/share/man/man3
chmod 644 /usr/local/share/man/man3/zlib.3
cp zlib.pc /usr/local/lib/pkgconfig
chmod 644 /usr/local/lib/pkgconfig/zlib.pc
cp zlib.h zconf.h /usr/local/include
chmod 644 /usr/local/include/zlib.h /usr/local/include/zconf.h
然后将/lib/libz.so.1文件先备份一下,将/usr/local/lib目录下的libz.so.1链接到/lib目录下,因为arm-linux-androideabi-strip这个命令链接的路径中依赖的/lib目录下的libz.so.1,当然我们也可以通过修改LD_CLASSPATH的方式来让arm-linux-androideabi-strip这个命令加载/usr/local/lib目录下的libz.so.1文件,可惜我现在不想这么麻烦,因为我现在也不知道具体做法,我懒得去Google了,我的方法是直接将该文件链接到/lib目录下,替换系统原有的libz.so.1
mv /lib/libz.so.1 /lib/libz.so.1_backup
ln -s /usr/local/lib/libz.so.1 /lib/libz.so.1
但是童鞋们啊,这还是不够滴,因为现在的系统捏是尼玛64位滴,而该死的Android都是基于32开发的,它依赖的是32位的libz,你现在执行ndk-build不出意外的话,你会碰到这个错误信息:
[root@helihua jni]# ../../../ndk-build
Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
Install : libhello-jni.so => libs/armeabi/libhello-jni.so
/root/android-ndk-r8c/toolchains/arm-linux-androideabi-4.6/prebuilt/linux-x86/bin/arm-linux-androideabi-strip: error while loading shared libraries: libz.so.1: wrong ELF class: ELFCLASS64
make: *** [/root/android-ndk-r8c/samples/hello-jni/libs/armeabi/libhello-jni.so] Error 127
make: *** Deleting file `/root/android-ndk-r8c/samples/hello-jni/libs/armeabi/libhello-jni.so’
唉,那么就只好开始编译32位的咯,怎么编呢,还是Google吧,程序员福音stackoverflow上又有对应的问题,在这里,通过
export CFLAGS=-m32
指定当前编译目标平台位32位滴,直接在bash下使用该命令只会在当前bash会话期间有效,不会影响到其他bash会话和下次你重新登录bash时的编译环境设置,非常有用,我们只需要在这次编译libz时才需要如此,正中下怀啊。果断重复上面的三步走啊:
./configure
make
make install
这次执行./configure就不会那么顺利了,会出现这样一个错误:
./configure
Checking for gcc…
.
.
.
Looking for a four-byte integer type… Not found.
如果这个时候你选择继续make的话,显然会出错滴,错误如下:
/usr/include/gnu/stubs.h:7:27: error: gnu/stubs-32.h: No such file or directory
通过该命令:
yum install glibc-devel.i386
安装对应的开发环境,重新执行上面的三步,
成功后再重复设置/lib目录的操作:
mv /lib/libz.so.1 /lib/libz.so.1_backup
ln -s /usr/local/lib/libz.so.1 /lib/libz.so.1
然后再尝试执行ndk-build命令,这次就不再提示任何警告和信息了,输出干净多了:
Gdbserver : [arm-linux-androideabi-4.6] libs/armeabi/gdbserver
Gdbsetup : libs/armeabi/gdb.setup
Install : libhello-jni.so => libs/armeabi/libhello-jni.so
回过头来再想想,为什么会出现这些问题呢?
前两个问题是因为Android NDK中的某些命令依赖于系统的一些库,没有直接安装就好了,这个没有过多讨论的余地,后面那个出现版本不一致导致的警告信息,我个人的理解是这样的,因为我们直接使用的都是Android NDK prebuild的命令,而这些命令可能在Google的编译服务器上依赖的是更高版本的库,所以导致在我们的环境中会出现版本不一致的问题。因为NDK中带着源码,我倒是觉得可以通过在自己的机器上编译一个NDK出来,应该就可以解决这个问题,当然前提是NDK的源码中没有引用到更高版本的一些头文件,另外编译源码可能需要我们安装很多的开发环境(就是很多的库和头文件),点到为止,有机会可以一试。