“Three Times a Lady” is a 1978 single …

“Three Times a Lady” is a 1978 single from the funk/soul band the Commodores, from their 1978 album Natural High. It was produced by James Anthony Carmichael and the Commodores and it was the most popular track of the album.

In an appearance on The Early Show on June 12, 2009, Richie said he was inspired to write it by a comment his father made about his mother. Reportedly his father said to his mother “I love you. I want you. I need you. Forever” hence the three times. It became the Commodores’s first Billboard Hot 100 number-one hit, topping the chart for two weeks on August 12, 1978. [2]. It was also the only Motown song to reach the Top 10 that year. The song also spent three weeks at #1 on the adult contemporary chart. It was one of only a few Motown singles to reach the top spot in the UK. In the years since the Commodores had started in 1974 it has been one of their most emotional songs since “You Don’t Know That I Know” from the album Caught in the Act in 1975.

The original Commodores’ version of the song was included as the final track on Lionel Richie’s greatest hits compilation album Back To Front, released in 1992.

http://en.wikipedia.org/wiki/Three_Times_a_Lady

Macbook pro的DVD刻录失败,清除灰尘后修复

这两天要用我的MBP(Mid 2009 MC118)刻录一张DVD却总是失败,告诉我使用的DVD盘片不兼容,或者刻录速度太快(我试验了1, 2, 4, 8都不行),让我尝试其它品牌的盘片。但是之前我用的威宝的日产DVD-R一直没有这个问题,所以查看了一下system.log,发现报错的内容是这样的:

Disk Utility[378]: Disk Utility: Burn to DVD-R (TYG02) media in MATSHITA DVD-R   UJ-868 (KB19) via ATAPI failed with error 0x8002006D and sense (3/73/03 Medium Error, Power calibration area error).

Google到了很多信息,讨论的很复杂,大意就是光驱坏掉了,或者锁了区码。看到了这篇比较有用Can’t burn DVD’s with a MacBook Pro?,说先试试清理尘土。

然后就打开了MBP后盖在光驱的几个角和缝的地方用皮老虎吹了一下(如果你的嘴很有力且不乱喷吐沫星子,那么也可以用嘴吹,但是这样很危险……),尘土还是挺多的。而后开机刻录就好了。

ADSL被联通(北京网通)的“京城时讯”劫持!

最近发现我访问一些站点的时候(如昨晚访问www.apple.com的时候)我发现页面弹出广告,但问题是apple.com的英文网站是不可能弹出中文广告的。

网通“京城时讯”弹出广告的截图

今天我又重现了这个问题,仔细看了下出问题的原因,页面的url没有变,dns也是正常的。应该只是http请求被劫持。可恨的是它不是注入式的劫持(也就是将广告的代码插入到</body>之前,而是使用了非常简单的iframe劫持,这种初级的劫持手段会造成很多网站访问不正常。可恨的是,在这样的劫持下你的个人隐私就完全没有保证了。代码是这样的:


<html>
<meta http-equiv='Pragma' content='no-cache'><head><title></title>
<script LangUage='JavaScript'>
try{var tmp=parent.window.location.href}catch(e){window.location.reload();}
</script>
</head>
<frameset framespacing=0 border=0 rows='*,0' frameborder=0 onload="window.lxmainframe.location='http://61.172.192.88/city/index.html?url='+window.location;"><frame name='lxmainframe' src='about:blank' scrolling='auto'><frame name='lxblankframe' src='about:blank' scrolling='no'></frameset>
</html>

作为一个mac user,我显然不是中病毒了。google一下也发现很多人都遇到了“京城时讯”的绑架。我刚才给10010打电话投诉,还好虽然停机保号但是可以拨10010。先是被转到网络部,让我自己到www.jcxinxi.com自己注销,让我挂电话。我马上试验,发现根本找不到她说的登录的地方,让她们告诉我详细注销步骤,她让我等了有3分钟左右才告诉我需要点那个“会员注销”。然后我又继续让她转接专门负责投诉的“上级”,那个上级向我解释了“给我看广告是为我好,这个服务是免费赠送以后”,我只能告诉他我办包年服务的时候的单子上面没有说网通可以免费赠送给我这个服务的时候才客气的让我留下联系方式说再联系。我知道这种事情“don’t blame the people, blame the game.”,所以我接受人家的电话服务。把这倒霉的该死的差劲ADSL服务Blame到底,投诉到底!

我投诉的时候提了几个理由:

  1. 联通在没有最终用户许可的情况下私自给我绑服务。
  2. 你们嵌入网站的iframe的方式直接造成很多网站访问不了。
  3. 给我看商业广告,jcxinxi可以从后向商户收费。侵犯了我这个最终用户的利益。尤其是我是有偿使用ADSL服务且我从来没有同意接收广告。
  4. 你们窃取我的HTTP Request是严重的侵犯我的隐私。
  5. 你们影响了我访问网站的显示效果,也是对第三方利益的侵犯。

周六日重构OpenParty App中发现的一些问题

Open Party App是我们在为OpenParty开发的新网站,上面集成了会员注册报名参加活动等功能。我们把他放在Google Code上面以开源crowd sourcing的方式开发。Django我是业余水平,在这个项目里面继续磨练。上周末正好有空开发,顺便重构了一下代码,我把其中发现的一些bad smell纪录下来,给和我们一样的Django业余团队参考。

  1. {% ifequal event.is_upcoming 1%}

    这是错误的,本意是{% if event.is_upcoming %},因为它本身就是个Boolean

  2. <a class=”gray_link”>看看谁参加了活动</a>

    gray_link是一个为样式命名的css class,但是css class的名字应该是一个结构语义的东西。也就是说css class应该是What it is而不是How it looks like。可以命名为<a class=”who-participated”>看看谁参加了活动</a>

  3. views.py里面return render_to_response(‘core/topic.html’, locals(), context_instance=RequestContext(request))

    使用locals()我上次就发过邮件,这样做是不好的。因为locals会鼓励你创建很多没有意义的本地变量,将它们一股脑的传递到template。造成template里面由很多的判断逻辑,但是这些逻辑本身应该是在models层搞定的。当你从template重构这些晦涩复杂的判断逻辑的时候,你会发现问题可能就出在views.py里面那一个locals()。没错,我说的就是topics.html这个模版,看看判断是否可以投票的那部分逻辑,实在是太复杂了,我不得不给他写测试,花了不少的时间重构。在模版里面你总是会思考一些措辞和样式的问题,而忘记了分支逻辑的复杂,这种代码经常是有很多的bug的,而且它们非常难于维护和修复。一定要将这种复杂度封装在model层并进行测试才可以。

  4. 没有意义的判断

    我看到很多if model.is_accepted == True: return True; else: return False这样的代码。我是在不理解为什么可能出现这样的代码……请注意这个和错误1差不多,都属于非常坏的重复代码。

  5. 测试

    请注意,我们没有赶时间。我们不太需要临时性的代码,要随时注意代码的可维护性,因为我们是一个团队。测试就是代码的文档,请注意尽量尝试测试先行,如果不行也注意让你的model得到充分的测试。当你发现Event和Topic这两个Model的创建需要费这么多的周折的时候,你是否发现你的Model抽象有问题?你是否有重构的冲动,将它们的创建行为变得更简单。

  6. 命名

    is_arranged这样的命名可能不太容易理解,注释上面写的是”’该话题是否已经加入到活动,并且活动尚未开始”’。那么如果keep stupid的话我觉得,is_arranged_in_coming_event是不是更容易理解呢?

    is_shown,注释”’该话题所属活动是否正在进行或已经结束”’,这个就很难理解了。因为你看到“应该显示”这样一个名字的时候,知道后面的意思是活动正在进行或结束了么?is_arranged_event_started_or_closed也许更容易理解?

这都是一些重构建议,有一部分问题我已经重构过了。大家都在参加OpenParty的Coding Dojo,一起持续重构吧!

在Mac下的Pydev里面几个常用的快捷键 Cmd+e切换tab,配合输入tab…

在Mac下的Pydev里面几个常用的快捷键

Cmd+e
切换tab,配合输入tab文件的名字的前几个可以快速在上下文中切换tab
Cmd+d
删除本行
Cmd+Option+上
复制本行一次(Duplicate this line)
Cmd+Shift+R
快速打开文件,注意没有通配符也不是smart匹配……
Cmd+Shift+F11
Rerun,常用在运行当前的单元测试
Cmd+Option+r

Rename refactory,重命名重构,非常实用。不过少数情况下这个重构不安全,注意diff
Cmd+Shift+O
自动import,缺点是它会搅乱你精心设计的import顺序,不在乎的朋友非常方便,可以让你的coding工作变得非常流畅。不过如果你开启auto import以后这个快捷键就不需要了,但是auto import的副作用就是它经常import那些明明不需要import的东西,如self、len它都会傻傻的import。
Cmd+Shift+F
在当前Folder搜索,前提是你在文件浏览部分选中了一个Folder

刚才写了一个识别网站charset的正则,因为目前写一个网页抓取的工具,里面对中…

刚才写了一个识别网站charset的正则,因为目前写一个网页抓取的工具,里面对中文url做encoding的时候需要先识别页面的编码,可惜UrlEncoding没有强制使用UTF-8编码,真是烦人。下面是一个python下的正则表达是的字面文本。

r'<meta.*(?:(?:charset\s*=\s*["|\']?)|(?:charset.*content\s*=\s*["|\']\s*))([\d|\w|\-]+)[;|"|\'|\s]'

我的.profile里面的alias,之前使用kill $(ps auwx | …

我的.profile里面的alias,之前使用kill $(ps auwx | grep qTfnNC | grep -v grep | awk ‘{ print $2 }’)的方法放在.profile里面就不好用了,所以最近就一直没有使用它。既然还是反复在用它(连接断开vpn以后经常需要重启ssh代理),所以还是修正它好了。

alias px="ssh -qTfnNC -D 7777 yourdomain.com"
alias kpx="(ps auwx | grep qTfnNC | grep -v grep | awk '{ print $2 }')|xargs kill;px"

看到这段话,来自这里: Recently I discovered that l…

看到这段话,来自这里

Recently I discovered that learning a foreign language teaches you two things: how to communicate in that language and how to communicate in your own language to non-native speakers. You learn that simple grammatical structures and shorter sentences are easier to understand. You get a feeling for when someone’s following you and which words in the sentence are most important to pronounce clearly.

感觉说的很好。你需要知道如何和没有熟练掌握这门语言(或者领域)的人交流,你需要知道如用简单的表述,清晰的表达你的意思。

Refactory in Python: 使用受控类型而不是Hash和tuple

《Clean Code》中提到了函数传递的参数不应该超过3个,如果超过三个推荐将它们变为符合数据结构。
在Python的应用中,对于这个场景,我看到一般的做法就是使用Hash。其实Hash就是一种Key-Value store,是一种弱类型的结构,好比一个没有shema的object。这样做起初看来是很舒服的,因为它自然的让你可以访问到一个复合数据结构。可是据我观察这一般都是Bad smell。缺点在于:

  • 你不知道这个Hash中有哪些key,经常会造成需要翻看很多代码才能知道key有哪些,从哪里来的。
  • 由于Hash是弱数据类型,你很有可能把Key写错,如有的地方用了”User”有的地方是”user”,就有可能发生由于误解造成的bug。
  • 因为Hash是一个开放数据结构,所以你无法控制它被get和set,这容易造成你的hash在多次传递过程中被意外的覆盖,这是非常危险的一种bug。
  • 如果使用了Hash,随着时间的推移它很有可能成为垃圾桶。就是一个全局的Hash被传递很多层,大家都依赖它并向里面插入自己的数据。由于这样的Hash根本不可能知道自己的数据属于哪些领域模型,所以它可能会承载多个领域模型的部分数据结构。这对复杂度来说是一个灾难,由于数据和行为分离,它会鼓励系统模块间函数的拷贝和粘贴,最后造成一团存在大量重复的乱麻。如果你的代码发展到这个地步,那它基本上是维护和重构的地域。
  • python中hash的访问方式不好看,你需要hash[“user”]这样去访问。:D

对于以数据为中心的系统,你看到一个Hash被传递于超过一次函数调用,那么你最好对它马上进行重购。将它处理为一个可控的数据类型(如Class和Namedtuple)。
非受控类型还有另外一种表现形式,那就是tuple。tuple让python变得强大,尤其是它被用在平行赋值的情况下,如:

def fucntion_a():
    a, b = 10, 20
    return a, b

def function_b():
    price, amount = function_a()

这种情况下它有很不错的表现力。但是在非平行赋值的情况下使用tuple传递数据结构就是一种Bad smell了。如:

def function_a():
     my_tuple = ('tin', 'male', 28)
     return my_tuple

def function_b():
     a_tuple = function_a()
     name = a_tuple[0]
     age = a_tuple[2]
     .....

这种情况的邪恶是使用了顺序来约定数据结构,它比起hash来说明显的问题就是僵化、不容易阅读。僵化是说当你发现需要传递更多数据的时候你需要在顺序中添加新的元素,此时如果你像插入在前面几个元素之间,你会面临大量的index修改操作,非常容易造成bug。不容易阅读是,如果不在同一个文件中,你怎么知道0, 1, 2分别是哪个属性的index,为此你肯定花大量力气写注释,而且这个注释需要随你的修改而修改,非常恼人,遗漏了就是bug。所以它们那是明显的bad smell。
上面两种情况属于同样一种情况,那就是使用非受控数据结构表示结构化数据。那么如何“使用受控类型而不是Hash和tuple”呢?一般来说很简单。一种是写一个数据结构的Class,这种情况是你发现这里的数据结构是潜在的领域模型的时候非常有用:

class BusinessLogData:
    date = datetime.now()
    username = 'Unknow user'
    business_type = ''
    .....

好处是当你发现系统中围绕这个数据结构的算法或者说行为的时候你马上就有一个地方存放这些逻辑了,会让你很舒服。而且逐渐的你的领域模型就会清晰了,这对没有使用领域模型驱动的系统进行重构的时候很有用。另外一种情况,你可能知道没有什么逻辑在数据结构上,它就是给算法访问的纯数据type。那么可以使用namedtuple。它实际上是一种元编程。官方的例子是这样的。

Point = namedtuple('Point', 'x y', verbose=True)
p1 = Point(11, y=22)
p2 = Point._make((11, 22))

我个人认为namedtuple非常方便,很象ruby中的struct。它对于已经使用tuple传递数据的系统的重构非常有效,因为_make这样使用tuple创建namedtuple实例的方法非常适合重构,可以马上消除0, 1, 2这样的index magic number。而且在使用sql的时候它也是非常有用的工具,官方例子:

EmployeeRecord = namedtuple('EmployeeRecord', 'name, age, title, department, paygrade')

import csv
for emp in map(EmployeeRecord._make, csv.reader(open("employees.csv", "rb"))):
    print emp.name, emp.title

import sqlite3
conn = sqlite3.connect('/companydata')
cursor = conn.cursor()
cursor.execute('SELECT name, age, title, department, paygrade FROM employees')
for emp in map(EmployeeRecord._make, cursor.fetchall()):
    print emp.name, emp.title

OK,到这里这个重构实践就阐述完毕了。下面我会继续讨论Refactory in Python这个话题。