Jul
20
纯粹记录一下。看不懂的绕行吧..
当客户端COMMIT成功以后,post-commit会被执行,调用时会传入两个参数,$1是repos的绝对路径,$2是REV,此次提交的版本号。
可以配合rsync用于分发各种东西。
$ mkdir repos
$ svnadmin create repos
$ ls repos/
conf db format hooks locks README.txt
$ ls repos/hooks/
post-commit.tmpl post-revprop-change.tmpl pre-commit.tmpl pre-revprop-change.tmpl start-commit.tmpl
post-lock.tmpl post-unlock.tmpl pre-lock.tmpl pre-unlock.tmpl
$ cd repos/hooks
$ cp post-commit.tmpl post-commit
$ chmod +x post-commit
$ vi post-commit
……
$ svnadmin create repos
$ ls repos/
conf db format hooks locks README.txt
$ ls repos/hooks/
post-commit.tmpl post-revprop-change.tmpl pre-commit.tmpl pre-revprop-change.tmpl start-commit.tmpl
post-lock.tmpl post-unlock.tmpl pre-lock.tmpl pre-unlock.tmpl
$ cd repos/hooks
$ cp post-commit.tmpl post-commit
$ chmod +x post-commit
$ vi post-commit
……
当客户端COMMIT成功以后,post-commit会被执行,调用时会传入两个参数,$1是repos的绝对路径,$2是REV,此次提交的版本号。
可以配合rsync用于分发各种东西。
Jul
19
前一阵和momo讨论到他的基于UDP的某个系统的设计时遇到这样一个问题:在一个局域网中有多台机器,有个消息是通过UDP广播发出的,且每台机器有多个进程需要监听同一个UDP端口,应该怎么办?
由于所知有限,当时我给的解决方案是,使用类似observer模式来建立一个稍复杂的服务(其实就是个转发,但是UDP进程数量未知)。后来momo发现,其实只要通过setsockopt设置SO_REUSEADDR属性之后,多个程序就可以绑定同一个端口了。
虽然问题是解决了,但是SO_REUSEADDR并没有上面提到的那么简单,因为momo遇到的问题正好是UDP广播/多播。否则上述模型就不适用了。这里有一篇文章,对其有更详细的注解,虽然是摘自《UNIX网络编程》的,但是给出了例子,很值得学习。
SO_REUSEADDR例解:http://www.cppblog.com/ace/archive/2006/04/29/6446.aspx
unix网络编程 第一卷:http://wenku.baidu.com/view/99a6cc38376baf1ffc4fad6f.html
由于所知有限,当时我给的解决方案是,使用类似observer模式来建立一个稍复杂的服务(其实就是个转发,但是UDP进程数量未知)。后来momo发现,其实只要通过setsockopt设置SO_REUSEADDR属性之后,多个程序就可以绑定同一个端口了。
虽然问题是解决了,但是SO_REUSEADDR并没有上面提到的那么简单,因为momo遇到的问题正好是UDP广播/多播。否则上述模型就不适用了。这里有一篇文章,对其有更详细的注解,虽然是摘自《UNIX网络编程》的,但是给出了例子,很值得学习。
SO_REUSEADDR例解:http://www.cppblog.com/ace/archive/2006/04/29/6446.aspx
unix网络编程 第一卷:http://wenku.baidu.com/view/99a6cc38376baf1ffc4fad6f.html
Jul
8
在不是用iframe测试iframe app的时候(就是在新窗口打开iframe的url)可以在地址栏执行用这种方式(注:$是jQuery里头的函数)javascript:$('#id')[0].style.visibility='hidden'; 可以让某个元素不可见,但是再次改为visible时不会需要重新载入。IE8、FF3.5、Chrome5测试通过。
FB.login(cb, {perms:'perm1,perm2,...'}) 给cb的参数response的属性perms 【如function cb(response){ alert(response.perms); }】 包含的是所有授权的perms列表,逗号分隔;无论这次login方法请求的perms是多少个。
javascript:FB.api({ method: 'Auth.revokeAuthorization' });
来取消所有已经取得的权限,包括Basic Info、Bookmark,当刷新apps.facebook.com/xxxx的时候会要求重新认证。再未重新认证时如果在非iframe的方式测试FB.ui({method:'bookmark.add'}, cb)会出现引用
An error occurred with APP_NAME. Please try again later.
API Error Code: 200
API Error Description: Permissions error
Error Message: Permissions error
API Error Code: 200
API Error Description: Permissions error
Error Message: Permissions error
FB.login(cb, {perms:'perm1,perm2,...'}) 给cb的参数response的属性perms 【如function cb(response){ alert(response.perms); }】 包含的是所有授权的perms列表,逗号分隔;无论这次login方法请求的perms是多少个。
Jul
8
facebook的javascript sdk因为需要完成比较多的功能,因此体积比较大(50K左右)。
如果每次都完整载入,必然会导致浪费过多带宽,因此缓存是必要的;但是缓存会导致BUG fix或者function enhancement无法即时更新到客户端。二者之间的矛盾调和可以用调整缓存时间来解决,但是这种解决方案并不够好,尤其是灵活性不够,有时候lib一天更新几次,有时候十天半个月甚至更久都不更新,这种解决方案的适应性就不够了。
facebook用的解决方案是,将sdk进行拆分,变成两块,第一块是loader,约2KB,缓存时间1小时;第二块是lib,约50KB,缓存时间一个月。开发者只需要用script标签载入loader即可,由loader来载入lib。lib的路径是带有版本号的,当facebook更新了lib以后,只需要修改loader中lib的版本。由于版本号不同了,路径也不同了,因此浏览器会重新请求新版本的lib。
该思路摘自facebook的wiki:http://wiki.developers.facebook.com/index.php/FeatureLoader.js.php
p.s. 这个是旧版的SDK。
如果每次都完整载入,必然会导致浪费过多带宽,因此缓存是必要的;但是缓存会导致BUG fix或者function enhancement无法即时更新到客户端。二者之间的矛盾调和可以用调整缓存时间来解决,但是这种解决方案并不够好,尤其是灵活性不够,有时候lib一天更新几次,有时候十天半个月甚至更久都不更新,这种解决方案的适应性就不够了。
facebook用的解决方案是,将sdk进行拆分,变成两块,第一块是loader,约2KB,缓存时间1小时;第二块是lib,约50KB,缓存时间一个月。开发者只需要用script标签载入loader即可,由loader来载入lib。lib的路径是带有版本号的,当facebook更新了lib以后,只需要修改loader中lib的版本。由于版本号不同了,路径也不同了,因此浏览器会重新请求新版本的lib。
该思路摘自facebook的wiki:http://wiki.developers.facebook.com/index.php/FeatureLoader.js.php
p.s. 这个是旧版的SDK。
Jul
7
在初始化FB对象之前必须要有一个id=fb-root的元素, 比如可以用同步或者异步的方式初始化FB对象。
同步:在head里头加入<script src="http://connect.facebook.net/en_US/all.js">,最好在</body>标签之前加入FB.init方法,这样可以保证网页的其他模块都已经正常载入。
异步:适合在<body>标签之后加入,这样可以和网页其他元素并行载入。参见:http://developers.facebook.com/docs/reference/javascript/
如果调用FB.init时指定了xfbml:true,那么当前页面中的XFBML元素都会被转换;如果没有指定,那么可以调用FB.XFBML.parse(),或者指定一个元素FB.XFBML.parse(document.getElementById('ooxx'));
FB.login(cb, {perms: 'perm1,perm2...'})方法用于获取用户权限,会有个Popup提示用户选择 允许 或 不允许。用户选择后会执行cb函数,给一个response对象,包含用户授权的权限列表(逗号分隔)。权限列表见http://developers.facebook.com/docs/authentication/permissions。可以通过FQL在permissions查所有的权限,包括查询用户是否添加了书签(bookmarked)。
FB.Event.subscribe(EventName, cb)方法用于订阅当前页面的某些事件,比如fb:like事件可以用FB.Event.subscribe('edge.create', callbackFunc)来订阅。当事件出现时会调用回调函数cb,给出事件对应的参数。
FB.Data.query方法用于执行FQL语句。FQL语句不能有换行(可以的),不能SELECT *,WHERE子句必须是能够索引的。查询是异步的,会立即返回一个query对象。query对象有wait方法,传入一个回调函数,当执行完毕后会调用该函数,传入一个数组,数组的每一行是一个查询结果对象,对象的每个属性就是SELECT出来的东西,比如SELECT id, url from object_url WHERE url="http://www.felix021.com",回调函数可以获得rows[0].id rows[0].url。
可以在 http://developers.facebook.com/docs/reference/rest/fql.query 测试FQL语句的执行。permissions这个表看似只列出了两个字段,但是实际上PERMISSION_NAME这个字段是泛指所有可以在http://developers.facebook.com/docs/authentication/permissions页面查到的权限名称,而且还包括bookmarked、tab_added两个不是权限的名称(很诡异吧?),详见http://wiki.developers.facebook.com/index.php/Permissions_(FQL)。
FB.ui方法可以用于显示一些对话框(iFrame或者Popup)。比如FB.ui({method:'bookmark.add'}, cb)可以用于显示添加书签(FB对应的APP)的iFrame,在添加成功/失败后会调用cb函数,传参response,response.bookmarked=0或1表示失败或成功。
可以在 http://fbrell.com/examples 看到更详细的例子,直接测试js的sdk。
FB的js的SDK里面 console/index.html 是个很不错的example合集,下面附上我自己写的一些example
引用
<div id="fb-root"></div>
同步:在head里头加入<script src="http://connect.facebook.net/en_US/all.js">,最好在</body>标签之前加入FB.init方法,这样可以保证网页的其他模块都已经正常载入。
异步:适合在<body>标签之后加入,这样可以和网页其他元素并行载入。参见:http://developers.facebook.com/docs/reference/javascript/
如果调用FB.init时指定了xfbml:true,那么当前页面中的XFBML元素都会被转换;如果没有指定,那么可以调用FB.XFBML.parse(),或者指定一个元素FB.XFBML.parse(document.getElementById('ooxx'));
FB.login(cb, {perms: 'perm1,perm2...'})方法用于获取用户权限,会有个Popup提示用户选择 允许 或 不允许。用户选择后会执行cb函数,给一个response对象,包含用户授权的权限列表(逗号分隔)。权限列表见http://developers.facebook.com/docs/authentication/permissions。可以通过FQL在permissions查所有的权限,包括查询用户是否添加了书签(bookmarked)。
FB.Event.subscribe(EventName, cb)方法用于订阅当前页面的某些事件,比如fb:like事件可以用FB.Event.subscribe('edge.create', callbackFunc)来订阅。当事件出现时会调用回调函数cb,给出事件对应的参数。
FB.Data.query方法用于执行FQL语句。FQL语句
可以在 http://developers.facebook.com/docs/reference/rest/fql.query 测试FQL语句的执行。permissions这个表看似只列出了两个字段,但是实际上PERMISSION_NAME这个字段是泛指所有可以在http://developers.facebook.com/docs/authentication/permissions页面查到的权限名称,而且还包括bookmarked、tab_added两个不是权限的名称(很诡异吧?),详见http://wiki.developers.facebook.com/index.php/Permissions_(FQL)。
FB.ui方法可以用于显示一些对话框(iFrame或者Popup)。比如FB.ui({method:'bookmark.add'}, cb)可以用于显示添加书签(FB对应的APP)的iFrame,在添加成功/失败后会调用cb函数,传参response,response.bookmarked=0或1表示失败或成功。
可以在 http://fbrell.com/examples 看到更详细的例子,直接测试js的sdk。
FB的js的SDK里面 console/index.html 是个很不错的example合集,下面附上我自己写的一些example
Jul
6
前一阵更新了Virtualbox到3.2.4,因为7788的原因,虚拟机配置丢失,于是重新建立,再用vboxmanage设置NAT端口转发。再次启动虚拟机,提示无法启动:
搜了一下,在这个页面:http://forums.virtualbox.org/viewtopic.php?t=7175 的回复中看到解答。
原来的vbox都是使用PCNET作为虚拟网卡,而3.2.4新建虚拟机的时候,虚拟的则是Intel的网卡。因此原先用于设置NAT的命令:
就不能再使用pcnet了。
然后再一查文档,发现3.2.4里头vboxmanage已经不用setextradata来设置Port Forwarding了,而是改成更简洁易懂的:
p.s. 端口转发的信息是存放在虚拟机的xml配置文件文件里了,需要重启(或休眠->恢复)以后才能重新载入
引用
Configuration error: Failed to get the "MAC" value.
VBox status code: -2103 (VERR_CFGM_VALUE_NOT_FOUND).
VBox status code: -2103 (VERR_CFGM_VALUE_NOT_FOUND).
搜了一下,在这个页面:http://forums.virtualbox.org/viewtopic.php?t=7175 的回复中看到解答。
原来的vbox都是使用PCNET作为虚拟网卡,而3.2.4新建虚拟机的时候,虚拟的则是Intel的网卡。因此原先用于设置NAT的命令:
引用
VBoxManage setextradata "Ubuntu" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/Protocol" TCP
VBoxManage setextradata "Ubuntu" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/GuestPort" 2222
VBoxManage setextradata "Ubuntu" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/HostPort" 22
VBoxManage setextradata "Ubuntu" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/GuestPort" 2222
VBoxManage setextradata "Ubuntu" "VBoxInternal/Devices/pcnet/0/LUN#0/Config/guestssh/HostPort" 22
就不能再使用pcnet了。
然后再一查文档,发现3.2.4里头vboxmanage已经不用setextradata来设置Port Forwarding了,而是改成更简洁易懂的:
引用
VBoxManage modifyvm "Ubuntu" --natpf1 "guestssh,tcp,,2222,,22"
vboxmanage 修改vm配置 虚拟机名(Ubuntu) nat_port_forwarding(第1个网卡) "端口转发名(guestssh),tcp,宿主机IP(略),宿主机端口2222,虚拟机IP(略),虚拟机端口22"
vboxmanage 修改vm配置 虚拟机名(Ubuntu) nat_port_forwarding(第1个网卡) "端口转发名(guestssh),tcp,宿主机IP(略),宿主机端口2222,虚拟机IP(略),虚拟机端口22"
p.s. 端口转发的信息是存放在虚拟机的xml配置文件文件里了,需要重启(或休眠->恢复)以后才能重新载入
Jun
28
对字符指针数组使用qsort排序时,strcmp强制类型转换后不能直接用于qsort, 需要进一步的纠结的。包装……
p.s. 对于字符串数组char a[100][100]; 就可以用strcmp。
p.s. 对于字符串数组char a[100][100]; 就可以用strcmp。
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef int (*cmp_func)(const void *, const void *);
int strcmp_for_qsort(const void *a, const void *b)
{
char *x = *(char **)a, *y = *(char **)b;
return strcmp(x, y);
}
void quicksort(void *p, int num, unsigned size, cmp_func cmp)
{
int i, j;
char *pos, *t = (char *) malloc(size);
if (t == NULL) exit(1);
for (i = 0; i < num; i++)
{
for (j = 0, pos = (char *)p; j < num - 1; j++, pos += size)
{
if (cmp(pos, pos + size) > 0)
{
memcpy(t, pos, size);
memcpy(pos, pos + size, size);
memcpy(pos + size, t, size);
}
}
}
free(t);
}
int main()
{
char *pos[5] = {"a", "c", "e", "b", "d"};
//qsort(pos, 5, sizeof(pos[0]), strcmp_for_qsort); // in stdlib
quicksort(pos, 5, sizeof(pos[0]), strcmp_for_qsort); //fake
for (int i = 0; i < 5; i++)
puts(pos[i]);
return 0;
}
#include <stdlib.h>
#include <string.h>
typedef int (*cmp_func)(const void *, const void *);
int strcmp_for_qsort(const void *a, const void *b)
{
char *x = *(char **)a, *y = *(char **)b;
return strcmp(x, y);
}
void quicksort(void *p, int num, unsigned size, cmp_func cmp)
{
int i, j;
char *pos, *t = (char *) malloc(size);
if (t == NULL) exit(1);
for (i = 0; i < num; i++)
{
for (j = 0, pos = (char *)p; j < num - 1; j++, pos += size)
{
if (cmp(pos, pos + size) > 0)
{
memcpy(t, pos, size);
memcpy(pos, pos + size, size);
memcpy(pos + size, t, size);
}
}
}
free(t);
}
int main()
{
char *pos[5] = {"a", "c", "e", "b", "d"};
//qsort(pos, 5, sizeof(pos[0]), strcmp_for_qsort); // in stdlib
quicksort(pos, 5, sizeof(pos[0]), strcmp_for_qsort); //fake
for (int i = 0; i < 5; i++)
puts(pos[i]);
return 0;
}
Jun
27
也许我有点悲观,但是在我心里对“成功”的尚未明晰的公式里,“技术”这个变量的权重减少了。当然,这个技术指的是计算机专业技能,而这里的成功,也算是很概念比较宽泛、理解比较狭隘的成功,比如说,有较大的影响力,有自己的事业,赚很多钱(最次)。
记得刚入学的时候,向04级的江学姐(当时她大三)取经,她说,信息安全专业有几个方向,比如网络攻防,密码学……那时虽然啥都不懂,但是还是看过些把黑客描绘得天花乱坠的一些文章,甚至我还存着些看不懂的黑客秘籍。于是我能感觉到自己是两眼放光地说,我对网络攻防很有兴趣。那时懵懵懂懂的,对那些能在网络上呼风唤雨的技术牛人无限葱白。转眼四年过去了,我发现我现在对网络攻防一点兴趣都没有。
作为一个计算机专业本科毕业生(我居然已经不是学生了!),在学校里摸打滚爬了三年多,上课,自学,混社团,接项目,又到公司去实习过半年,还跟几位曾经在IT公司打拼过的朋友保持或紧或松的联系,让我对技术有了新的理解。
技术是什么?这个问题可真是既宽泛又无趣,简直就像“傻逼有什么特征”。也许我可以给个对得上大多数人胃口的、更具体的、不怎么准备的回答:写得一手好代码,有扎实的算法和数据结构功底;开发得出像样的软件或游戏;能管理各种服务器,尤其是熟悉各种网络协议、设备;能用PS设计出精美的图片,能用Flash做出很酷的动画;熟知那些我看来很枯燥的理论,比如图形学或者密码学,发得出几篇论文……这里说到的各个方面每个都和我身边的某个人对应。他们都是大家熟知的牛人(相比之下,我就是个四不像)。
然而在现在的我看来,装B一点的说,我觉得以上都属于较低层次的技术,一个仅仅为吃饭准备的铁饭碗,与其他专业相比没什么值得炫耀的。倒是最牛的那些人,他们可以创造出新的数据结构和算法,比如KMP;他们可以设计(更重要的在于设计)出牛X的系统,比如Google的三驾马车;他们可以不再在某个机器的层次上纠结,甚至设计新的互联网,比如IPv6;他们可以在理论的路上走得更远,但是又不脱离实际。无论什么时候,我对这些牛人的葱白都不会真的减少,因为他们能把这当作自己的追求,实现自己的成功。但是我,也许在未来的某个时候,不会再朝着他们的方向前进。
《程序员的幸福生活之路》这张图片虽是恶搞,却也不乏辛酸的自嘲。在高中捣腾电脑的那阵,就已然听说程序员这活儿,吃的是青春饭,到了三十多岁吃不动了,就会被年轻人挤出来。所以网上传的那段子——“你程序员吧?" "你才程序员呢,你全家都程序员!"——可谓道尽老程序员的苦。当然,如果从二十来岁入行,到了三十多岁还在程序员的位子上原地打转,那也只能说明这人能力不行,优胜劣汰是必然的。然而就算能往上走呢?
能往上走,爬到金字塔的顶端,自然可谓成功。但是很多人都忽略了这前提,能吗?大中公司,诸如百度腾讯等,从一个底层程序员(职位美名为工程师)干起,想要爬到金字塔的中间都是比较困难的事情,何况就算爬到了,也不过是”赚还算比较多的钱“的层次;小公司,爬上去容易,但是大多数小公司无法负担远大的未来。由于信息源的缺失,以及难免的下意识信息过滤,大多数人都只看到成功的辉煌,而几乎没人关注失败者落寞的背影。所谓一将功成万骨枯,金字塔的顶端就P大的地方,想跟着别人从下面爬上去,没准早被别人踹死了。
所以有很多人觉得,爬上别人的金字塔,不如自己造一座,就像不胜数的硅谷梦创造的奇迹。这让我想起电影《雀圣》里面的一句话:都说香港遍地黄金,你知道黄金下面埋着多少尸骸!我们看到了google,看到了facebook,看到了twitter,却看不到被世纪之交那场泡沫淹没的那无数尸骸。那么多成功的典型,引着人们前仆后继。所幸的是,互联网的一波波新潮,带来无限的机会,团购,Dropbox,foursquare等新星的崛起又给人带来无限的希望。顺便说一句,facebook, twitter, dropbox, foursquare和大部分的google服务都被墙了,在目前的体制内想搞出点啥伟大的东西还真没啥希望。
于是话题终于转到了创业。一谈到创业,技术突然就变成很次要的因素了。这里有两篇文章(非常值得一看):《Dropbox 和 Xobni 如何在兩年內從 0 成長到 100 萬會員》 http://feedproxy.google.com/~r/MrJamie/~3/xUGw-48yJII/ 《Dropbox 和 Xobni 在兩年內突破百萬會員的七個關鍵》 http://feedproxy.google.com/~r/MrJamie/~3/RlRwIp_WDX8/ 。里面提到了两年前就让我大流口水的segway车。两年过去了,它离我还是那么遥远,就像摩托罗拉的铱星系统,把他们看成艺术品更合适。这两篇文章讲得很细,但是几乎就没有提起技术相关的事情,甚至还有"反技术"的倾向(Fake It Till You Make It)。其中点出了创业的三大要素:”優秀的團隊、正確的市場和非常好的執行力“。
这让我想起前一段时间参与的、由Ye发起的一个创业型的小项目,抄的是Aardvark的模式。Ye的社会关系比较丰富,找到了在创新工厂的人(Chen)推荐,希望能够拿到创新工厂的投资。由于项目本身还很不成熟,所以最后黄了,但是Ye、Feli他俩与Chen的聊天也透露出了很多信息。创新工厂对一个项目的评价标准并不是技术含量,而是前面提到的:团队、市场、执行力。尤其是在Web2.0的概念下,很难做出他人无法剽窃的核心竞争力了,这时团队和执行力几乎是成功的基本保障了。否则像马蜂一样扑面而来的400多家团购网站,会让人想死……
另一方面,前面顺便说到的那一句,是因为我对国内环境的失望。当年ZF没能意识到互联网的”危害“,放任自流,互联网才能有如此发展。现在发现网络的问题了,对政治监管不断加强加固加猛,忽视行业规范运作,反而放任国家队的进攻……所以本来就高风险的IT创业在国内更加难以捉摸——廉颇老矣,尚能"饭否"?
巴菲特的赚钱哲学是“投资而非投机”。曾有人问巴菲特为什么不投科技类的产业,巴菲特的答案是:“好的公司、不好的公司,是我花半天时间就能够看出来的,而那些花了半天时间看不出来的【比如科技类公司】,我也不会强迫自己花半个多月时间去看。我不会强迫自己花费很多时间在一个我不能“Figure out”的公司上。”在我看来,“投资”和”投机“,只是处理资金、时间等资源时冒险的程度不同。投资是将其投入低风险的领域,而投机则相反。从另一个角度来看,回报和风险又是成正相关关系的,所以这里头的关系还是有点纠缠,看来不是那么容易能说清的,暂且忽略。由于科技类公司通常都是高风险高回报的,更倾向于投机,因而巴菲特选择避开。而对于创业者,创业本身就是一种投资/投机,所以这就有个抉择:是选择科技类(如IT)的高风险高回报,还是选择实业型的稳扎稳打?
所以当我问起一个工作了好几年的朋友将来的打算时,他说,攒够资本,做实业。我想,这决定也许与年龄有关,年轻时冲劲比较大,有足够的时间资本,缺的是资金,只要能拉到,轰轰烈烈的干几年,即使失败也无妨;随着岁月逐渐流逝,梦想淡出,冲动渐冷,还是攒些养家养老的钱比较稳妥。
于我,"Niche First, World Later"正是我一直以来推崇的解决方案。下一步,加入magnetjoy这个创业型的团队,希望接下来三个月的实习能让我对以上提到的内容有新的、更进一步的认识。
记得刚入学的时候,向04级的江学姐(当时她大三)取经,她说,信息安全专业有几个方向,比如网络攻防,密码学……那时虽然啥都不懂,但是还是看过些把黑客描绘得天花乱坠的一些文章,甚至我还存着些看不懂的黑客秘籍。于是我能感觉到自己是两眼放光地说,我对网络攻防很有兴趣。那时懵懵懂懂的,对那些能在网络上呼风唤雨的技术牛人无限葱白。转眼四年过去了,我发现我现在对网络攻防一点兴趣都没有。
作为一个计算机专业本科毕业生(我居然已经不是学生了!),在学校里摸打滚爬了三年多,上课,自学,混社团,接项目,又到公司去实习过半年,还跟几位曾经在IT公司打拼过的朋友保持或紧或松的联系,让我对技术有了新的理解。
技术是什么?这个问题可真是既宽泛又无趣,简直就像“傻逼有什么特征”。也许我可以给个对得上大多数人胃口的、更具体的、不怎么准备的回答:写得一手好代码,有扎实的算法和数据结构功底;开发得出像样的软件或游戏;能管理各种服务器,尤其是熟悉各种网络协议、设备;能用PS设计出精美的图片,能用Flash做出很酷的动画;熟知那些我看来很枯燥的理论,比如图形学或者密码学,发得出几篇论文……这里说到的各个方面每个都和我身边的某个人对应。他们都是大家熟知的牛人(相比之下,我就是个四不像)。
然而在现在的我看来,装B一点的说,我觉得以上都属于较低层次的技术,一个仅仅为吃饭准备的铁饭碗,与其他专业相比没什么值得炫耀的。倒是最牛的那些人,他们可以创造出新的数据结构和算法,比如KMP;他们可以设计(更重要的在于设计)出牛X的系统,比如Google的三驾马车;他们可以不再在某个机器的层次上纠结,甚至设计新的互联网,比如IPv6;他们可以在理论的路上走得更远,但是又不脱离实际。无论什么时候,我对这些牛人的葱白都不会真的减少,因为他们能把这当作自己的追求,实现自己的成功。但是我,也许在未来的某个时候,不会再朝着他们的方向前进。
《程序员的幸福生活之路》这张图片虽是恶搞,却也不乏辛酸的自嘲。在高中捣腾电脑的那阵,就已然听说程序员这活儿,吃的是青春饭,到了三十多岁吃不动了,就会被年轻人挤出来。所以网上传的那段子——“你程序员吧?" "你才程序员呢,你全家都程序员!"——可谓道尽老程序员的苦。当然,如果从二十来岁入行,到了三十多岁还在程序员的位子上原地打转,那也只能说明这人能力不行,优胜劣汰是必然的。然而就算能往上走呢?
能往上走,爬到金字塔的顶端,自然可谓成功。但是很多人都忽略了这前提,能吗?大中公司,诸如百度腾讯等,从一个底层程序员(职位美名为工程师)干起,想要爬到金字塔的中间都是比较困难的事情,何况就算爬到了,也不过是”赚还算比较多的钱“的层次;小公司,爬上去容易,但是大多数小公司无法负担远大的未来。由于信息源的缺失,以及难免的下意识信息过滤,大多数人都只看到成功的辉煌,而几乎没人关注失败者落寞的背影。所谓一将功成万骨枯,金字塔的顶端就P大的地方,想跟着别人从下面爬上去,没准早被别人踹死了。
所以有很多人觉得,爬上别人的金字塔,不如自己造一座,就像不胜数的硅谷梦创造的奇迹。这让我想起电影《雀圣》里面的一句话:都说香港遍地黄金,你知道黄金下面埋着多少尸骸!我们看到了google,看到了facebook,看到了twitter,却看不到被世纪之交那场泡沫淹没的那无数尸骸。那么多成功的典型,引着人们前仆后继。所幸的是,互联网的一波波新潮,带来无限的机会,团购,Dropbox,foursquare等新星的崛起又给人带来无限的希望。顺便说一句,facebook, twitter, dropbox, foursquare和大部分的google服务都被墙了,在目前的体制内想搞出点啥伟大的东西还真没啥希望。
于是话题终于转到了创业。一谈到创业,技术突然就变成很次要的因素了。这里有两篇文章(非常值得一看):《Dropbox 和 Xobni 如何在兩年內從 0 成長到 100 萬會員》 http://feedproxy.google.com/~r/MrJamie/~3/xUGw-48yJII/ 《Dropbox 和 Xobni 在兩年內突破百萬會員的七個關鍵》 http://feedproxy.google.com/~r/MrJamie/~3/RlRwIp_WDX8/ 。里面提到了两年前就让我大流口水的segway车。两年过去了,它离我还是那么遥远,就像摩托罗拉的铱星系统,把他们看成艺术品更合适。这两篇文章讲得很细,但是几乎就没有提起技术相关的事情,甚至还有"反技术"的倾向(Fake It Till You Make It)。其中点出了创业的三大要素:”優秀的團隊、正確的市場和非常好的執行力“。
这让我想起前一段时间参与的、由Ye发起的一个创业型的小项目,抄的是Aardvark的模式。Ye的社会关系比较丰富,找到了在创新工厂的人(Chen)推荐,希望能够拿到创新工厂的投资。由于项目本身还很不成熟,所以最后黄了,但是Ye、Feli他俩与Chen的聊天也透露出了很多信息。创新工厂对一个项目的评价标准并不是技术含量,而是前面提到的:团队、市场、执行力。尤其是在Web2.0的概念下,很难做出他人无法剽窃的核心竞争力了,这时团队和执行力几乎是成功的基本保障了。否则像马蜂一样扑面而来的400多家团购网站,会让人想死……
另一方面,前面顺便说到的那一句,是因为我对国内环境的失望。当年ZF没能意识到互联网的”危害“,放任自流,互联网才能有如此发展。现在发现网络的问题了,对政治监管不断加强加固加猛,忽视行业规范运作,反而放任国家队的进攻……所以本来就高风险的IT创业在国内更加难以捉摸——廉颇老矣,尚能"饭否"?
巴菲特的赚钱哲学是“投资而非投机”。曾有人问巴菲特为什么不投科技类的产业,巴菲特的答案是:“好的公司、不好的公司,是我花半天时间就能够看出来的,而那些花了半天时间看不出来的【比如科技类公司】,我也不会强迫自己花半个多月时间去看。我不会强迫自己花费很多时间在一个我不能“Figure out”的公司上。”在我看来,“投资”和”投机“,只是处理资金、时间等资源时冒险的程度不同。投资是将其投入低风险的领域,而投机则相反。从另一个角度来看,回报和风险又是成正相关关系的,所以这里头的关系还是有点纠缠,看来不是那么容易能说清的,暂且忽略。由于科技类公司通常都是高风险高回报的,更倾向于投机,因而巴菲特选择避开。而对于创业者,创业本身就是一种投资/投机,所以这就有个抉择:是选择科技类(如IT)的高风险高回报,还是选择实业型的稳扎稳打?
所以当我问起一个工作了好几年的朋友将来的打算时,他说,攒够资本,做实业。我想,这决定也许与年龄有关,年轻时冲劲比较大,有足够的时间资本,缺的是资金,只要能拉到,轰轰烈烈的干几年,即使失败也无妨;随着岁月逐渐流逝,梦想淡出,冲动渐冷,还是攒些养家养老的钱比较稳妥。
于我,"Niche First, World Later"正是我一直以来推崇的解决方案。下一步,加入magnetjoy这个创业型的团队,希望接下来三个月的实习能让我对以上提到的内容有新的、更进一步的认识。