网络寻租

Programmer, Gamer, Hacker

The Meaning of Life

| Comments

At some point in the life, we may ask ourselves: What’s the meaning of life? We seek answers from others, from social groups or religion groups, from books written by philosophers.

In the ancient times, philosophers ask bigger question: What is the meaning of humanity? Someone turns to the obvious answer: there must be the god, and god creates human for good. The question turns into: what god wants? Argument of it was through the history, and bring conflict and war.

Someone asks another question: If there is god, where is the god? They start to seek the proof, develop system of critical thinking, then the light of rationality shining, expulse the shadow of mysticism. And we got science, and we can identify facts, and we found the big discovery of evolution, with the proof of it. It turns out either there is no god, or the god is not concern about us, human is a kind of random generated chemical compound which can reproduce itself, specialized in alter environment with the help of a highly developed organ called brain random generated thousands of thousands years ago.

The big answer of human meanin is unveiled now, If human as a group has no meaning, what about each individual? Maybe no default meaning, we still can seek it ourselves. Without meaning, life is no more than an ordinary animal. With meaning, life of roaming turns into life of journey with porpose, great things can be done, ordinary can be extraordinary, and life can be meanful.

Information Sugar

| Comments

As a blogger for many years, creating new blog post is harder and harder for me.

So why it is harder? Because I consider quality of blog post more now.

To have a high quality blog post, it should have:

  • High information density. It should focus on one topic, with enough supportive information.
  • Depth. It should walk through the topic, view all the angles, dig deep into the essence, so reader can have a clear view.
  • New content. We should not discuss something already done.
  • Something inspiring. It can create spark which can enlighten reader’s mind.

World is filled with noise, and readers face more danger on the thing which I call information sugar: it has some value, but the time spending on reading, is more valuable than the value it contains. SNS and news sites filled with it, sweat to read, and lots of time wasted without notice.

Creating high quality information need lots of time, focus, hard working, and care. I hope I can provide more of it, other than the sweet information sugar.

Autoit介绍

| Comments

最近回到老家干IT,工作中遇到很多安装无聊软件的事情,为了能够自动化操作,我去寻找了一下类似按键精灵这种自动化工具,被我发现了autoit这个工具兼脚本语言。

简单介绍一下核心逻辑。比如说每次你希望每次打开记事本,都会自动输入一个抬头信息,比如”author: halida”,那么你可以写以下的autoit脚本:

Run('notepad.exe')
WinWaitActive("无标题 - 记事本", "")
Send("author: halida")

简单的三部曲。执行命令,等待特定窗口出现,发送内容给窗口。 autoit也可以直接发送内容和操作给特定的窗口中的控件。

一些核心特性:

  • 能够把脚本解释执行,或者编译成exe。exe非常小以及无其它依赖。
  • autoit脚本是完备的语言,控制流,函数,数据结构都有,可能不如现代动态语言那么强大,但是足够方便地编写程序了。
  • 带有丰富的API支持,随机数,进程处理,文件操作,窗口操作,网络,硬件,鼠标键盘,COM,声音,剪贴板。。应有尽有。
  • 可以用autoit来做简单和稍微有一些些复杂的GUI界面。
  • 足够大的社区支持。同时有官方社区中文社区

那么autoit可以做哪些事情呢?我觉得可以做的事情有:

  • 自动化windows下面的操作。节省人力。
  • 编写脚本来自动化软件安装和删除,方便运维管理。
  • 编写大型软件的加载页面,提升用户体验。
  • 写简单的windows程序,和复杂的MFC说再见。

对于我来说,可以填补windows下面自动化操作的空白,从此我在所有领域都不再担心不能自动化操作了。

那么如何学习呢?我的建议是按照下面的顺序:

  • 过一遍官方教程,按照官方教程写点简单的用例。
  • 过一遍官方文档,对于autoit能够干什么有概念。
  • 开始编写你自己需要的简单程序,巩固上面学习到的东西。
  • 然后多翻翻社区和wiki,收集一些最佳实践,成为一个靠谱的autoit开发者。

前3步我想任何一个程序员一周内都就可以搞定,带来的收益是节省下无数枯燥的重复操作时间。

针对手机端写网页的方法

| Comments

现在趋势是移动互联网,这方面的需求比较多,如何写一个适应手机的html页面?

首先要能够根据浏览器端的user-agent来判断设备是否是手机,有一个Gem mobile-fu来做这个事情。

然后是写对应的页面模板,要让页面的宽度适应屏幕。在header里面加上设置:

<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no,maximum-scale=1">

就是让页面宽度适应屏幕,同时锁定客户端不让屏幕缩放。

html里面的元素设置width: 100%,让它们自动撑大到整个屏幕范围。 同时最好设置一个max-width,这样万一电脑访问到这个页面,不至于显得太丑。

如果有一个标题图片,需要这样设置,保证根据屏幕大小自动等比例缩放:

img
  width: 100%
  height: auto

如果你觉得不要放得太大,可以加上一个max-width

chrome最新版本支持手机模拟,出来的结果就是这个样子:

参考文档:

2013总结与2014计划

| Comments

一个人真正拥有的资源是时间。人不能控制时间的获得和消逝。 在时间投入的方式上面,体现出每个人的水平: 用时间换取什么,以及换取的东西是否能够积累。

2013年总结

回到正题。2013年发生了一些改变,又好像什么都没有改变。 这一年里面决定了我的一些命运,可能需要过很多年我才能看清楚。

工作

我在年底离开了GuruDigger,被家里人拉回老家,进入了医院信息科。具体细节不便阐述。 因为创业,这一年没有收入,还贴了不少的钱。

在一年的开发过程中,我基本上面延续旧的老路,生产力总体不高,开发的效率还是很低。 观念上面加深了认识:项目管控要把握风险,做事情要细致认真。 在这几点上面我交了不少的学费。还有其他一些观念变更,我的学费没有交足。这里就不多说了。

技术

  • 上半年学了机器学习,但是没有成果,学习深度不够。
  • 继续开发网站,熟练度有提高,但是没有本质的提升。
  • 零零散散学了一些东西,比如D语言,动态规划,eventmachine等,但是都是一些点,没有形成实质的生产力。

谈朋友

  • 谈了两场,但是没有多久就草草收场了。以及因为工作和家里人的冲突,两个非常好的女生错过了。
  • 有遇到一些觉得合适的,但是都没有搞定。

回顾了一下,机会还是不少的,只是我执行力太差,把握不住。

健康

因为有一直运动,健康状况良好。并且自己在身材上面有了一定的自信心。 不过年底痔疮的状况还是不容乐观。

活动

参加了各种活动,包括暴走,各类技术聚会,各类其他类型聚会,去台湾等。 养成了出去娱乐交友的好习惯。生活变得更加有意思了。

看书

总体看了30本左右。比较杂,学到的东西:

  • 从方舟子这边学到中医不靠谱,科学方法论,韩寒假货。
  • lean startup 关于创业的一些常识:消除不确定性。
  • 选择的悖论里面了解了一些认知心理学的知识,对自己更了解了(以及自己看书多么不认真)。

英语

因为有看奶爸的英语教室,每天跟读,感觉英语发音上了一个台阶,但是后面还有很多路要走。 现在自己连熟练地回复英文邮件都做不到。

2014年计划

回顾2013年计划, 发现还是可以直接拉过来。因为几个目标都没有完成。

  • 技术。现在回到老家,白天的工作用不到技术。一定要强迫自己晚上钻研,不然真的废掉了。并且要和外面的人合作,自己学习效率非常低。计划年底能够继续技术领域的深入(能够做一些一流程序员做的事情,比如一些著名开源项目等级的事情,当然自己做不到那么好),在技术基础上面有信心(算法,开发能力),有一些能够写在自己简历里面的东西(给著名开源项目提交补丁,做出一些有业界声望的应用)。
  • 计划现有的医院信息科工作做稳定。医院这一块领域我觉得还是挺有意思的,未来行业前景也很大。就是信息科工作太杂了,做一年积累一些行业经验。
  • 英语。去年优先级放得非常低。今年一定要制定可行的目标和计划。目标是能够深入到外国技术圈中交流,能够和外国人网上语音对话,能够做英文演讲,能够写文章,保持英文邮件交流。今年不知道能够达成多少。
  • 健康。我有信心继续保持。加上上身训练。计划年底练出上身肌肉。
  • 找对象。回到老家见的人就多了,但是质量比较低。我想面100个,总归能够解决问题吧?保持两周相亲一个的节奏。
  • 钢琴。现在中午有时间了,每天练半小时,明年底应该可以弹简单的乐曲了。

如何阅读ruby源码

| Comments

最近阅读ruby源码非常顺手,这里整理一下阅读心得。

首先,为什么要阅读源码?因为几点:

  1. 用到的工具,一定要清楚实现,这样遇到问题能够处理。我在rails开发过程中,遇到一些诡异bug,调试了很久, 最后定位问题到了第三方gem上面。如果我对于它们的代码足够熟悉,可以很快定位到问题点,不需要浪费那么多的时间。

  2. 熟悉实现也是一个学习的过程。在看源码的过程中,我对于ruby的使用,如何做架构,都有了更深刻的认识。 写代码水平靠自己磨练,同时借鉴别人的代码也必不可少。很多知识和技巧自己悟出来就慢了,看别人的东西能够学到更多。

然后是重点:如何阅读。

读懂代码之前,我们要把项目的文档看一遍,知道如何使用它。 使用方法是项目的接口,熟悉它们,我们就把“未知”限定在项目的源代码之内, 对于理解源码有了坚实的基础。

之后我们要熟悉源代码的文件树结构。好的项目的文件安排是模块化的, 一个文件就是一个系统模块,ruby项目,一般是一个文件一个类。 这样一个复杂项目,就被切分成一小块一小块人能够理解的部分了。

在这里要停一下,回顾前面看到的文档,列出一些核心的入口, 然后基于这些入口,对于项目的实现提出一些猜想, 然后从这些入口出发,寻找对应的函数,一步步顺着方法调用,看对应的代码。

举个实际的例子。 我看sinatra源码的时候,关注了几个入口:get/post方法,如何被rack调用。 我会列出猜想:get/post代码应该是记录这些block到一个内部的数据结构中, 在代码里面,有针对rack做一个接口,调用的时候会去解析http请求,分发到对应的block里面。

然后我开始用findgrep寻找get,遇到函数调用,就用同样的方法一路看过去。 最后发现get方法实际上是给类创建了一个方法:#{verb} #{path},然后绑定它。 和我想的不太一样,并不是用一个数据结构。

然后我又去看rack调用过程,最后弄清楚了如何分发请求,如何调用请求,以及在执行中快速跳出, 并且学到了一个小技巧

在阅读源码的过程中,我弄清楚了:调用栈,数据结构,类架构,以及验证了阅读代码前的各种猜想, 通过了解里面一些看不懂的部分,学到了新的知识。整个顺藤摸瓜过程是非常愉快的。

对了,最后还有一点,记得记笔记。研究过程不记录就白研究了,下次你是绝对想不起来的。 我会把上面跟踪函数调用栈中遇到的核心区块记录下来,整理成一个执行过程文档, 下次需要的时候直接看这个文档就可以了。这是一个示例(当然只有我自己才看得懂啦):

1
2
3
4
5
6
7
8
9
call => dup.call! 复制自己一份。。
call!(env) =>
@request  = Request.new(env)
@response = Response.new
invoke { dispatch! } => route!
route! =>
base.routes 遍历
returned_pass_block = process_route(...) 
process_route 里面检查pattern是否匹配,返回对应的block

Too Old to Program

| Comments

There is a common myth in China: After programmer turns 30, he is too old to keep programming, need change direction, to management or other domains.

It may not make any sense for the programmers outside of China, there are many talent old programmer out there, still doing great job. But this myth reflect something need to worry about, In short words: programming is easy to learn, hard to improve.

With the greatness of internet and hard working of programmers, knows how to programming, is just a matter of time. Dozens of websites tells you how to build a website or GUI tool, thousands of books give you a detailed walk through, from novice to expert. You can create a website on your own, under 1 month, even though has no IT background.

So it bring down the threshold, and for the domain with low requirements, employees there are under heavy competition, easy to be replaced.

And programmer’s job brings low benefit. They are isolated inside digital world (some of us forced to be more socialize for keep balance), investment of time on new tech devaluation fast, repeating doing jobs of CURD, domain specific knowledge which cannot scale or be reused, and need lots of brain power to finish the job so leave less energy on self improvement after work.

Then after several years of hard working, programmer may found that he is less competitive with the newbies, and aging issue came out, make old programmer hard to follow new trend, hard to focus the mind on solving coding problems, and it will lead to decrease of the salary income.

There still are some way out:

Tech Management. People who can lead a tech team is always rare. It require good understanding of programming and problem domain, social skills to communicate with team members with different background, and good control of project schedule.

IT consultant. With all these years of working, the programmer has deep understanding of the information system, and how business works. Organization need he to maintain and improve the system, he will become part of the system.

CS expert. Programmer has deep understanding of computer science, and smart enough to solve tech relevant issues which others can’t. They can bring great value to the organization, either create core competition, or keep complex system work smoothly.

All these positions are hard to archive, only few of us did. Average forks will remain average, face the hard cold winter.

关于输入法

| Comments

关于输入法,有几点我觉得可以分享的。

首先是输入法的安全性。如果你是采用第三方的输入法工具,因为所有你键盘的输入都会经过输入法, 你的隐私信息,包括行为,密码,帐号,都会被输入法厂商收集。 你可能觉得他们大厂商,不会专门来对付自己一个普通人, 但是要利用隐私数据的方法太多了,他们也许不会用这些信息来窃取你的金钱和私密, 但是私人邮箱收到垃圾邮件,私人手机受到垃圾短信,或者诈骗电话就免不了的了。

我原先是采用搜狗输入法的,最近考虑到这个状况,越想越觉得危险, 赶紧卸载掉,安装了开源的rime输入法。

然后是选择什么输入方式。我是重度的输入法用户,经常在各个地方留言, 输入的效率很重要。对于普通人来说,思考的方式是采用语音的,拼音输入法更为适合。 而普通拼音输入法的信息冗余太多,韵母都是固定组合,却要敲击多个按键,比如inuang等。 所以我去学习了双拼,学习大概十几分钟,一周的时间就能够熟练掌握, 按照减少的键盘敲击数量,输入的效率可以提高一倍,强烈建议大家掌握。

双拼怎么学习?看半页纸就能学懂, 选择自然码双拼输入法,练习敲几篇文章,肌肉记忆半个小时就能够学会了。 我不分平舌音和翘舌音,因此加上了模糊音,不需要记忆zh/ch/sh的键位,学习起来更快一些。

rime不是那么容易设置的,安装之后需要自己调整设置文件。 安装之后,选择rime输入法,配置菜单里面选择设置,然后会进入一个文件夹, 修改里面的default.yaml这里告诉你如何设置输入法, 这里告诉你如何做一些细化的配置。 如果你和我一样采用双拼加上模糊音,需要修改double_pinyin.schema.yaml, 在algebra:区块(就是具体设置双拼方案的区块)的- erase/^xx$/(重置所有设置)后面加上:

1
2
3
4
- derive/^([zcs])h/$1/             # zh, ch, sh => z, c, s
- derive/^([zcs])([^h])/$1h$2/     # z, c, s => zh, ch, sh
- derive/([ei])n$/$1ng/            # en => eng, in => ing
- derive/([eia])ng$/$1n/           # eng => en, ing => in, ang => an

Librr介绍

| Comments

librr是我最近离职休息玩的小项目,用处是给本地文档做一个索引,然后想查什么就可以搜索到。 实现原理很简单,监控文件夹改动,有变化就把文件一行行读取出来,丢给solr进行索引。

使用上面首先设置你要索引的文件夹:

librr add ./gtd

然后等一会让索引完成,就可以搜索数据了:

librr search emacs

我用它来索引自己的本地文档库,以后考虑索引一些大文件,比如csdn泄漏密码,酒店泄漏信息什么的。

架构

因为有文件夹监控,维护搜索进程等功能,librr需要跑一个后台进程, 一个命令行工具作为后台进程的前端。

后台进程有几个功能:

  • 监控文件夹中的文件改动
  • 响应命令行工具的http请求
  • 管理solr进程

可以用多线程或者多进程来做,不过我选择了eventmachine,采用异步无阻塞的架构。 目的一个是熟悉eventmachine,一个是看看异步无阻塞的架构写起来如何。

具体细节

命令行和后台通讯

命令行参数的解析交给CmdParser完成,利用了库ThorCmdParser解析出来的参数交给CmdClient传递给后台进程。 如果后台进程没有起来,CmdClient会调用ServerController,启动一个后台进程。 后台进程里面的CmdServer模块有一个CmdServerHandler,响应命令行过来的http请求, 通知对应的后台模块处理,返回执行结果。

后台架构

Runner负责启动eventmachine,初始化IndexerDirMonitorCmdServer这几个核心模块。 因为模块初始化是有依赖的,它们的初始化方法start都可以传进去一个block,初始化完成后执行,这样可以按照顺序进行初始化。

监控文件夹功能

DirMonitor.get_monitor会根据当前的操作系统,生成对应的监控对象。

OSX下面的OsxDirMonitor, 会去跑一个利用系统API FSEvents生成的可执行文件,管道输出获取结果。

linux下面的LinuxDirMonitor 用基于linux inotify API的ruby绑定rb-inotify。 因为可以获得一个文件句柄,可以直接丢给eventmachine进行管理。

索引和搜索功能

Indexer是针对索引和搜索功能的包装, 内部有一个SolrManager来管理solr进程,方式是用EM.popen,开启一个新的进程。 索引文件夹因为用时很长,把逻辑拆成了异步来做,让后台进程能够同时去做其他的事情。

经验体会

首先,整个项目耗时比我预期的要多出来很多,一个原因是用到新技术必然会跳无数的坑, 另一个原因是稍微复杂一些的项目考开发人员的细致程度,一点点的错误就会消耗无数的调试开发时间, 而我开发的时候并没有进入非常投入的状态。

然后是异步项目,需要把平常顺序执行的操作,用回调拆分得支离破碎, 这样代码看起来不容易理解,执行异步不容易理清当前代码所在的环境也容易引入bug。 并且开发模块的时候,要用用回调的方式来考虑问题,如果顺序依赖的话,需要准备对应的完成后事件的callback接口。 这一块的调试花费了我好些时间。

一个小项目,需要引入那么多正规项目需要有的东西: 文档,项目管理,标准化代码文件结构,日志系统测试,功能模块化,配置管理发布方式多平台支持。 真是不容易啊。不过这种代码主要消耗在架构上面的项目写起来真的是非常有成就感。

既然你都看到这里了,那么就试用一下librr吧,欢迎提交issue给我

记一次调试ruby内存问题

| Comments

最近我自己开发一个小项目librr玩,是一个本地索引文件夹的工具,在这个项目里面我用到了eventmachine,用来同时跑一个http服务器,监控两个进程。

开发过程中遇到一个bug:很多时候会发生CPU冲高的现象,并且内存消耗会快速变大。 这个问题可以重现,所以是好bug, 但是没有找到办法绕过去,如果不解决,这个项目就废了。

这种没有数据提供的问题一般相对难解一些, 如果是报错,就可以定位到问题所在, 如果数据结果有问题,可以二分法定位出错位置。 为了能够调查原因,我研究了如何在ruby下调试内存泄漏。 用这个方法,我发现在出现问题的进程里面,创建了无数的Proc对象:

1
2
3
4
5
6
{
  Proc=>1233820,
  RubyVM::Env=>1277897,
  String=>23125,
  ...
}

采样几个Proc,用proc.source_location,定位到了是eventmachine里面run_deferred_callbacks中的一个地方,但是为什么会发生这种现象?我走到了死胡同里面。

run_deferred_callbacks是eventmachine的核心方法,用来处理回调方法,我于是修改了librr的代码, 一个个去掉回调,看看哪里有问题,结果发现,所有的回调都去掉了,还是有这样的问题发生, 那么应该是跑evenmachine的主线有问题了。 然后我用二分法隔离代码,终于发现问题的所在点,这是一个最小重现代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
require 'eventmachine'

def run
  EventMachine.run do
    EM.next_tick{ puts "12" }
  end
end

def main
  begin
    raise
  rescue Exception
    run
  end
end

main

在异常捕捉里面跑eventmachine,同时调用回调,就会出现问题。修改之后,问题不再发生。

如果有时间的话,我可能会研究一下eventmachine源码,定位到核心地点,这个bug才算真正解决掉。 但是现在我要先把librr做完,先提交了一个bug,如果他们没有受理的话,我再继续寻找核心问题所在。

总结一下学到了什么:

  • 二分法是定位bug的核心方法。
  • 这个bug消耗了我半周的时间,占据了开发过程中很大一部分比例,bug是项目的时间黑洞。
  • debug需要的是逻辑思考,数据越多,脑子越清醒,思路越开阔,bug解决就越快。
  • 各种debug工具,比如gdb,perftools.rb,帮助了解状况,验证猜想,极大地提升效率。