最近的一些想法

最近有机会带着两个弟兄做一个老产品的技术改造。起因是测试发现产品的并发性很差,反馈回开发部门作下一个版本的改进。一查代码发现在网络通信时,原本异步的NIO,发送线程居然被强行加了wait同步等待远程返回。线程不能被释放,前端的请求被排队,吞吐量根本上不去。

这是root cause,其实进了代码里面的问题更多。于是产生了对这种feature driven development的怀疑。我曾经觉得列出 feature,做好代价估计,然后大家各自去实现的方式很理性很可控。如果宏观地看,黑盒地看,这种方式对项目管理很友好。但是最近看这种方式下开发出来的产品,问题还是很多的。当开发人员面对一个feature却缺少对产品整体架构的足够了解,他很容易倾向于用quick and dirty的方式\打补丁的方式解决问题,而忽略新feature对架构整体的挑战。长期下来,软件的功能不断演进,架构却停留在早期,维护成本越来越高,神秘的陷阱越来越多。这时,每次发布都要通过测试部门的蛮力测试,这个过程中除了修bug还要克服无数的invalid的bug。What the hell!!!

另一方面,从开发人员的角度,我认为Don’t repeat yourself是每个程序员必须牢记在心的编程行为准则。无论技术好坏,经验是否丰富,只要坚持这个原则,程序员总会趋向于做一些抽象做一些设计,我想是不会写出太让人发指的代码的。最近查看遗留代码,里面实在是太多copy/paste了。对新增的功能,甚至通过重载加copy/paste来实现。如果不能怀疑同事能力的话,只好认为这是工作态度问题了。管理者往往是不会看到这么细节的问题(其实是严重的问题)。

面对这样的系统,我最初的想法是通通推倒然后模块化。虽然考虑了工作量,可是尝试了一周还是发现老的基础根本无法剥离开,多年前的设计者根本就没有考虑模块化/解耦合的问题。有句话说得好: if you cannot split it, you cannot scale it. (对数据显而易见,对程序其实也一样)然而放弃这么大规模的久经考验的代码又不现实。这周开始又只好改变策略小步快跑,虽然不治本,但是就这个阶段来说,看到改造的效果对我们这个小组意义更大。这是在内心的洁癖和现实的局面间做的不难的取舍。

尽管困难重重,还是争取抓住这个机会能对自己有个提升。需要驱动弟兄们接受和实现自己的想法,和自个一个人闷头干是完全不同的。

ngeohash: node module for geohash algorithm

ngeohash是一个geohash的javascript实现,之所以叫做ngeohash是因为到了Publish的时候才发现已经有geohash这个module了。这么令人沮丧的事就不多说了。

安装
npm install ngeohash

使用
var geohash = require(‘ngeohash’);
sys.puts(geohash.encode(32.1717, 118.2342));

详细
访问github的相关页面:https://github.com/sunng87/node-geohash

Checkout my forked version of reddit-is-fun

每天上下班要花掉两个多小时,这一路只好浏览一些新闻、reddit以及HN。reddit的app相对来说不算多,找了一圈倒是在market里没找到的reddit-is-fun最好用,功能最全。HN的app最近添加的一个小功能非常实用,通过viewtext.org打开链接。使用这个服务,可以提取出页面的正文部分,既减少了流量又提高了阅读体验。于是我想到给reddit-is-fun添加这个功能。reddit-is-fun是个GPLv3的软件,程序本身就在github上,对Android一无所知的我花了两个小时完成了这个功能。感谢IDEA,感谢IDEA的Android插件。

给作者发了pull request,不过作者最近似乎没有什么实质性的动作。不等他了,今天先把包含这个功能的fork放出来,大家如果感兴趣可以下载安装。这个fork的版本为1.1.4-sunng0,应该不会影响未来升级的吧(我猜啊)。

可以通过这个码下载:
https://github.com/downloads/sunng87/reddit-is-fun/reddit_is_fun-sunng-fork.apk

链接地址:
https://github.com/downloads/sunng87/reddit-is-fun/reddit_is_fun-sunng-fork.apk

Update on HeatCanvas and gefr

HeatCanvas的百度地图扩展

感谢@lbt05姐的无私贡献,现在HeatCanvas又增加了百度地图API支持。你可以在你的百度地图中使用heat map了。详情可以参考@lbt05姐撰写的文档,而这里是一个简单的live demo。此外,@lbt05姐还贡献了GoogleMap扩展的patch,帮助我解决了地图拖动后Canvas无法覆盖viewport的bug。再次感谢@lbt05姐。

百度地图支持已经汇入主干,可以在github找到它。

Gefr新增 Jetty WSGI Bridge

昨天为gefr新增了Jetty服务器的支持,这样你可以将自己的Python WSGI程序运行在成熟的Jetty服务器上。性能是大家关心的因素,下面是在我的本机(32位CentOS,双核2.8GHz,4G内存)上一个粗略的测试结果:

100并发,20000请求:

Server Software: gefr-jetty/0.3dev
Server Hostname: localhost
Server Port: 8088

Document Path: /
Document Length: 19 bytes

Concurrency Level: 100
Time taken for tests: 3.120827 seconds
Complete requests: 20000
Failed requests: 0
Write errors: 0
Total transferred: 2584515 bytes
HTML transferred: 380665 bytes
Requests per second: 6408.56 [#/sec] (mean)
Time per request: 15.604 [ms] (mean)
Time per request: 0.156 [ms] (mean, across all concurrent requests)
Transfer rate: 808.44 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 4 114.1 0 3000
Processing: 0 7 18.5 5 1776
Waiting: 0 6 18.5 4 1776
Total: 0 12 115.8 6 3015

Percentage of the requests served within a certain time (ms)
50% 6
66% 7
75% 8
80% 8
90% 10
95% 13
98% 70
99% 74
100% 3015 (longest request)

如果打开KeepAlive,吞吐量可以达到10000以上:

Server Software: gefr-jetty/0.3dev
Server Hostname: localhost
Server Port: 8088

Document Path: /
Document Length: 19 bytes

Concurrency Level: 100
Time taken for tests: 1.749189 seconds
Complete requests: 20000
Failed requests: 0
Write errors: 0
Keep-Alive requests: 20000
Total transferred: 3062142 bytes
HTML transferred: 380266 bytes
Requests per second: 11433.87 [#/sec] (mean)
Time per request: 8.746 [ms] (mean)
Time per request: 0.087 [ms] (mean, across all concurrent requests)
Transfer rate: 1709.36 [Kbytes/sec] received

Connection Times (ms)
min mean[+/-sd] median max
Connect: 0 0 0.8 0 23
Processing: 0 8 8.0 6 85
Waiting: 0 8 8.0 6 85
Total: 0 8 8.1 6 85

Percentage of the requests served within a certain time (ms)
50% 6
66% 7
75% 8
80% 9
90% 11
95% 20
98% 41
99% 43
100% 85 (longest request)

你可以根据gefr的文档安装它。

jip.embed: On-the-fly classpath resolution for Jython

jip 0.7 introduces a module called jip.embed, which allows you to add libraries to your code in the runtime as you declare them. With jip.embed, you don’t have to download jars manually and append them to your -Dpython.path. You just pick your editor, import jip.embed, code your business, then save and run it.

Code example:

import jip.embed
jip.embed.require('commons-lang:commons-lang:2.6')
from org.apache.commons.lang import StringUtils

print StringUtils.reverse('jip rocks')

Output:

skcor pij

(jip will print some log here if dependencies are included for first time)

So please check out my new released jip, 0.7:
https://github.com/sunng87/jip

For virtualenv user, you can install full-featured jip via pip:
$ pip install jip

To install jip globally, download the package from python cheese shop and run:
$ jython setup.py install