Trade Off

supercalifragilisticexpialidocious

OCP-talks

Good design should be open for extension and closed for modification. You can extend the module instead of modifying some working code.

Abstraction is the Key: for example, a Client should use an Server object that implemented some interfaces instead of a concrete Server object.

Interface’s name should be named more closely associated to the dependent side instead of the implement side.

A function that is closed for modification: if we add some changes for this function, it must be modified for working right, it may unconform OCP. For example, a function that draw all shapes in a shape list, it should be draw shapes one by one, and don’t care this shape should draw in this way, another shape should draw in that way, etc.

No matter how “closed” a module is, there will always be some kind of change against which it is not closed.

Abstraction may gain “closed” software entity(func, module, class, etc), but it also need trade off.

Use-change-event-on-checkbox

昨天在一个table的第一行放了一个checkbox, 想做一个效果:一开始这个table的每一行都是冻结状态,点击这一行就激活了,顺便会把checkbox选中,当然直接点checkbox也会激活这一行。可惜在bind event的时候,分别给tr和checkbox加了click事件,tr的click会trigger到checkbox上,这样导致的结果就是点tr会触发checkbox的click handler,但同时又触发了tr的click handler,循环导致最后js崩溃。

后来发现在tr的click handler中检查event.target可以不触发这种死循环,但在checkbox click handler中使用prop判断checked状态不准,在stackoverflow中找到解答:jquery1.8中的 click()和真实的click是不一样的,应该在checkbox上用change event,然后一切ok。

解答:http://stackoverflow.com/questions/7668826/jquery-triggerclick-not-firing-click-event-on-checkbox

Crontab a Python Script

今天用python写了个小程序检测网络是否通断,如果断了就弹出一个Notification,当然是Mac上的,并且弹出一个terminal,带着执行ping www.baidu.com。

一开始用Lingon加入到启动项中并且打算2分钟执行一次,几经折腾终于失败,弃之。打算用crontab弄。

好歹算是可用了吧,注意的是:script的开头写/usr/bin/python,crontab中写PATH没用,得写PYTHONPATH才管用,而且我还写了MAILTO(现在不知道管什么用)。由于在script中用了popen,可能这个需要依赖一些环境或者是tty(这是从stackoverflow上看来的,具体可以搜popen crontab),现在想来launchd是不是也因为如此没能成功启动呢?(总提示255退出代码)

crontab:

1
2
3
4
MAILTO="dawncold@me.com"
PATH=/Users/dawncold/.rvm/gems/ruby-1.9.3-p286/bin:/Users/dawncold/.rvm/gems/ruby-1.9.3-p286@global/bin:/Users/dawncold/.rvm/rubies/ruby-1.9.3-p286/bin:/Users/dawncold/.rvm/bin:/Library/Frameworks/Python.framework/Versions/2.7/bin:/usr/local/sbin:/usr/local/bin:/usr/bin:/bin:/usr/sbin:/sbin:/usr/local/bin:/opt/X11/bin:/usr/local/MacGPG2/bin
PYTHONPATH=/usr/bin
* * * * * /Users/dawncold/ping_test.py > /Users/dawncold/pt

Suds-literal-soap

SAP的接口就是和别人给的不一样,style为literal,最明显的地方就是operation中的参数是literal,原先的参数是一个object,按照原先的方法调用时发现传递过去的值都被放在了第一个参数中,很是不解。后来才知道这样的operation需要用keywords的那种传值方法——**suds_client.dict(object),用suds的client的dict方法把构造的对象变成dict,再用**

又被坑了一下。

搭建4pm.la的数据库服务器

原来用MySQL比较多,现在工作上主要用PostgreSQL,对于低级的应用来说,选什么数据库都差不多,但也要为以后发展做准备,不过我暂时看不到那么远,PG作为一个开源的数据库来说,还算是比MySQL有优势一点,所以就用这个了。

在Mac上安装的时候有个locale的选择,我选了这个:

locale select

然后下载了pgAdmin作为GUI工具,结合PG的CLI一起使用比较好。使用psql登陆数据库可以用:psql -h localhost -U postgres -W

其中
-h db host
-U db user
-W use password

pgAdmin用起来感觉超差,目测是java写的,有点小卡,远不如在Ubuntu上的体验。

创建一个网站用的用户,可以用createuser这条命令,或者连上PG后写CREATE USER这种SQL,官方文档介绍两者没什么差别。createuser只是包装了一下SQL而已。(官方文档

createuser -dEeP -h localhost -U postgres -W xxx

其中
-d can create db
-E encrypted user's password
-e echo SQL command
-P can not create role

创建一个数据库,同样可以用包装了CREATE DATABASE的createdb。(官方文档

createdb -e -E UTF8 -l zh_CN.UTF-8 -O OWNER -h localhost -U postgres -W DBNAME

其中
-e echo SQL command
-E use encoding
-l set locale, included LC_COLLATE and LC_CTYPE
-O db's owner

看到篇不错的文章,介绍PG的ROLE、USER、SCHEMA、TABLESPACE、DATABASE等概念的关系:这里

生产环境用的Ubuntu12.04.2,在创建数据库的时候制定locale,但没有zh_CN这个locale,于是需要安装:/usr/shard/locales/install-language-pack zh_CN,安装完了最好能重启机器,不然的话好像createdb一直会报错说zh_CN.UTF-8这个locale不正确。重启了之后再创建db就ok了,但告诉你说collection你选了zh_CN的,和默认模板template1的en_US冲突,提示是换成template0模板,于是加了参数-T:createdb -e -E UTF8 -l "zh_CN.UTF-8" -O :OWNER -T template0 -h localhost -U postgres -W :DBNAME

Lazy-load-if-image-in-background

自从发现background-position在各个浏览器下表现良好之后就在网站首页几个地方用了,可惜有个问题也出现了,只要是在background中的图一般会等到页面所有img中的图片加载完之后才会被加载,无论这个image是在html中的什么位置。在一般的网站首页可能还好,没那么多img,放在background中的image慢一点加载可能看不出异常,不过在我们网站,那个首页超多images的网站,就真的能看到差别(只要没有cache)。

现在的做法要效仿twitter,它的首页是一张巨大背景图,是用img加载进来后css调整得像是background。

还有个图片上传的功能需要改改,原先让编辑们把两张图拼在一起,现在我竟然要用PIL把它们再分开,为了不让他们察觉到和以前不一样,并且要让他们传两张图当然还不如让他们传一张来得简单。

Nginx-upload-file-without-backend

以前用了nginx-upload-module,不过这个module的作者不打算继续更新了,导致nginx版本高于1.3.9就无法使用这个module来处理上传文件。本着不引入更多依赖并且使用一个比较成熟方法的前提,只有client_body_in_file_only,这是nginx buildin方法。

原本用upload-module的时候在location / 中有个if,如果发现有multipart就会处理一下,再pass回去。处理完后会多出两个参数,比如image.name和image.path,其中image是file input的name。然后back-end就直接那path和name来处理文件了,临时文件会放在一个固定的地方。

由于client_body_in_file_only只能放在server、http、location中,得专门建立一个location而不能放在if中。

1
2
3
4
5
6
7
8
9
10
11
12
location ^~ /upload/ {
  client_body_temp_path      /tmp/;
  client_body_in_file_only   on;
  client_body_buffer_size    128K;
  client_max_body_size       1000M;

  proxy_pass_request_headers on;
  proxy_set_header           X-FILE $request_body_file; 
  proxy_set_body             off;
  proxy_redirect             off;
  proxy_pass                 http://backend/
}

这样以upload开头的就会做这样处理,上传的文件path会放在header中,至于name该怎么办,我是把name的值作为query string拼在了form的action中,在上传开始前得到文件名,然后拼上去。

需要注意的是,client_body_in_file_only不支持RFC2388,也就是说multipart不管用,你可以考虑用ajax上传插件来做上传,注意插件里的multipart设为false。上传插件推荐JQuery-File-Upload。

依赖,越少越好。

Some-sed-work

博客内容是从wordpress转过来的,不可避免有很多地方没转换好,当时懒得弄,今天得空学习Shell编程,讲到了sed,就又搞了一下,基本满意了。

以前用sed替换过分类等简单的文字错误,今天主要是把一些html给替换掉了。

<p>删掉,在删掉</p>以及<br />后面加换行等:

sed -i "" -e 's;</p>;\'$'\n;g' *.markdown

sed -i "" -e 's;<br />;\'$'\n;g' *.markdown

需要注意的是Mac OS中的sed和我看到的很不一样,所以这个替换都是特殊的,来自这里

Pushd-and-popd

amazoing的两个命令,pushd和popd

相关介绍:pushd & popd

pushd /etc可以到etc目录下,工作完了后再用popd就回到了刚刚离开的目录。