30 5 / 2014

这两天在看一本叫做《认知心理学》的书,这是一本教材的名字:http://book.douban.com/subject/1122236/

昨天花 10 元在旧书店买的。


这本书买了以后放在我的桌面上,由于桌面上没有其他的书,我总觉得自己应该快点把它给看完。

  1. 其实当桌子上待看的书多了以后,反而不会急着想把哪一本看完。

  2. 我也不懂这算不算强迫症,不过我觉得这也不算是一种坏习惯。下次我应该多把自己需要好好完成的任务,放在醒目的地方让自己看见,然后让自己赶紧把事情完成。


认知心理学是一门讲大脑机制的学科,里面有很多段落都让我想到人工智能方面的论述。作为一个计算机爱好者,看这书还是蛮有意思的。

这本书里面的各种心理实验我都觉得特别扯鸡巴淡,不过我还是决定接受它们的结论。

比如,我不打算深究大脑到底是如何进行相同模式的识别,以及如何存储信息的。

我只想让它告诉我,诸如<编码后的信息比原始信息更好记忆>这方面的知识。

举两个编码信息的例子,

  1. 对于数据的趋势和变化,图像比数字表格更直观。

    上面那幅图比下面这幅图要好理解也好记忆,虽然上图在具体数值的精确度上,还是得求助于下面的图。

  2. 在 短时记忆 这一章节中,有这样一个例子

    人类很难记忆 10100 01001 11001 这样一串数字。

    但我们如果对它每五位进行编码,变为十进制数,则是 20、9、25。

    显然,20、9、25 比那串数字容易记忆,且没有丢失任何信息。

10 5 / 2014

  1. Ruby 和 Python 都有 GIL。
  2. Python 的 thread 是 native thread。
  3. Ruby 在 1.9 之前是 green threads,1.9 之后也是 native thread。

04 5 / 2014

github issue 的方式不适合博客的留言互动,虽然我的博客也没什么互动。

28 4 / 2014

以后在 github 上面写博客,这个博客继续保留但是不更新了。

新的博客地址是:http://github.com/alsotang/blog

21 2 / 2014

今天再次尝试了一下 iOS 开发,比半年前的那次尝试要顺畅很多,对于 MVC 和 数据绑定 之类的理解看来比原来深入了。后来再去试了试 Ember.js,都 1.4.0 了。不过,唉,怎么说呢,前端的 MVC 开发始终不成熟啊。我一眼看下去,连代码结构应该怎么组织都没有头绪。

我觉得手机淘宝应该是做不大的,因为每个人打开淘宝之后,浏览器都会有十几二十个标签页,而手机淘宝一次只能看一个商品;且手机屏幕很小,看实物图都觉得憋屈。我觉得手机的应用,适合做

  1. 简短而实时的交流。不适合中型或大型篇幅的输入。

  2. 线性的输出,比如刷 timeline。而淘宝购物是需要处处对比,且用户无法专注地看大段文字介绍,看图又憋屈。

  3. 充分利用起移动的特性。比如打车软件的 GPS 定位,基于地理位置的交友等。

不能为了移动而移动,为了无线而无线。

打车软件我是非常喜欢的。天大地大的,大晚上司机和乘客互相找不到。而打车软件充分利用了 GPS 和 移动网络。不过我感到奇怪的是,为何打车软件不在一年多以前就爆发出现在的竞争形态?那时候各位的智能手机不也已经普及了吗?且这种软件要求开发技术也并不高,最近之所以突然火爆。也是因为营销宣传的力度比原来大了很多而已。

说起来,打车软件的战争。我觉得腾讯在战略上已经赢了。就凭手机支付宝的那种垃圾体验以及阿里一贯的产品基因,一旦后来钱烧完了。我觉得用户是得过去腾讯那边的。为什么说腾讯在战略上赢了?因为阿里在推的是线下支付,而腾讯追求微信的用户支付场景。支付宝跟腾讯一起带动大家线下用软件打车,最后是支付宝什么也没变,用户体验一样的差,而微信用户都绑上了银行卡。

我们数据部门现在在做的事情,我倒感觉蛮有希望的。当然,永翎这方面的理解比我深入和广泛很多,只是偶尔听他给我介绍一下,我都会很认同我们现在在做的事。我们的产品如果起来以后,天然的壁垒就能形成,别人什么都能模仿,唯独我们的数据别人没有。

16 1 / 2014

每一门编程语言的作者都希望自己创造的语言是美的,而每门语言在发展的过程中的每个路口,都需要做出自己相应的选择。当越来越多这样的选择叠加在了一起之后,一门语言的独特的特性和味道就渐渐确定了。

这些个选择当中,有一些是值得赞美的,有些是应该回避的。但无论是前者还是后者,在该特性稳定之后就有对应的项目在使用它,于是出于兼容性的考虑以及对语言标准的实现,后者也没法从语言中去除出去。

众所周知,JS 的坑以及不确定行为相当多。所以为了写出美的 JS 代码来,就要求我们知道那些部分是 JS 中美的部分,哪些是不美的。具体参照《JavaScript: The Good Parts》就好了。

其实中国的语言文字——即中文,也不算是什么特别美的东西。网上的资料说,“1994年冷玉龙等的《中华字海》,收字数更是惊人,多达85000字”。而人们常用的汉字数目是 3000 个,如果把每个汉字都看成中文的一个特性的话,那么中文有用的特性只有 1/20。这多出来的 8w 多个汉字,里面的每一个字相信都可以用对应的 3000 字里面的汉字来做解释。且做这个解释的机会不多,我相信我读过的书不算很少,但其中出现的生僻字也并不多。

相比来说,JS 漂亮多了。


Node.js 真正美的东西是 NPM。在 Ruby 和 Python 中,它们的包管理工具都不如 NPM 好理解以及好用。Python 的包管理工具无论是 pip 还是 easy_install 都是个残废,这就不说了;Ruby 里面的话,bundle 并不像 NPM 一样可以每个包依赖固定的版本号,而是需要全部包都依赖相同的版本号,这就对包的兼容性提出了不小的挑战,所以也不如 NPM 优雅。NPM 虽然牺牲了不少的多余的硬盘空间,可是这年头谁在乎硬盘空间。就算多占用点内存空间都是小问题,人的时间虽然并不是越来越值钱,但机器的消耗确实是越来越廉价。

——

俗话说“一白遮三丑”,对应 JS 来说,则是“一快遮三丑”。很多时候,我遇到一些有关语言解析或者局部优化的问题,都喜欢用 JS 写测试代码来试试性能,而 v8 也从来没让我失望过。快得不可言喻。

15 1 / 2014

There are three frequently-use methods related to RegExp in JS:

String#match, RegExp#exec, RegExp#test

The two pitfalls mentioned in title are belong to String#match and RegExp, and they both relate to the g flag.

  1. String#match

    see some code:

    var str = ‘fooooo’;

    console.log(str.match(/o/));

    // => [ ‘o’, index: 1, input: ‘fooooo’ ]

    console.log(str.match(/o/g));

    // => [ ‘o’, ‘o’, ‘o’, ‘o’, ‘o’ ]

  2. RegExp#exec

    var str = ‘fooooo’;

    console.log(/o/g.exec(str));

    console.log(/o/g.exec(str));

    console.log(/o/g.exec(str));

    // =>

    // [ ‘o’, index: 1, input: ‘fooooo’ ]

    // [ ‘o’, index: 1, input: ‘fooooo’ ]

    // [ ‘o’, index: 1, input: ‘fooooo’ ]

    var o = /o/g;

    console.log(o.exec(str));

    console.log(o.exec(str));

    console.log(o.exec(str));

    // =>

    // [ ‘o’, index: 1, input: ‘fooooo’ ]

    // [ ‘o’, index: 2, input: ‘fooooo’ ]

    // [ ‘o’, index: 3, input: ‘fooooo’ ]

    When use exec method of a literal RegExp, the behavior is consistency.

    But if there is a RegExp variable, each time you call the exec of it, the variable would record the offset and resume from it.

14 1 / 2014

无论是 CoffeeScript,Jade 还是 Stylus,都喜欢追求极简:用最少的代码和尽可能少的标点符号来表达事物。

尽可能少的代码我是认同的,很多常用的操作如果被抽象成了更短的表达方式,确实可以有效减少击键。

但尽可能少的标点符号则不一定是合适的。在 JS 中,由于标点符号的存在,很容易可以通过视觉来判断出代码的结构来;但是到了 CoffeeScript 的话,无论是代码块还是 for 循环还是 Object 字面量甚至是函数调用,都可以不加符号地写出来。一眼看去,密密麻麻全是 ascii 字符。

Jade 也有同样的问题,但 HTML 写起来确实心烦。所以我一般用 Zen Coding 来写代码,但输出时还是成 HTML。

一份代码,人既要去输出它,也要输入它。代码作为字符串的存在,人脑遇到它时也是需要在脑中先分析词法语法然后建立抽象语法树的。 没有了标点的辅助,输出代码时虽然由于击键少而方便了点,但输入代码时就成问题了。

05 1 / 2014

JS 美不美?大体上不美。

但如果抛去那些不美的地方来看的话,很美。《JavaScript: The Good Parts》也是这么认为的。

0

0 是个 Number。在 JS 中,没有 int 和 float 之分,数值类型只有一个,就是 Number。这个 Number 呢,也不是可以表现无限大的,它有范围。在内部实现上,每个 Number 貌似是存在一个 52 bits 的空间里,我记不太清。

所以在 JS 中,Math.pow(2, 53) == Math.pow(2, 53) + 1 是返回 true 的。

多数场景下,不需要考虑精度的问题。但一旦碰上,蛋都要碎。比如 0.1 + 0.2 === 0.3 是 false。

String

JS 是个搞 Web 开发的,很多时候它不必接触太复杂的数据结构或是算法,而是花很多的时间在与各种 String 打交道。这个 String 有可能是 JSON string,也可能是 HTTP Form string,也可能就是 HTTP 协议本身。每个 String 通过不同的骨架表现着不同的意义,而 JS 也相应地通过不同的刀法来解析这些意义。

在 JS 中,String 是不可变的。

忘了说,Number 也是不可变的。

大可放心地随意传递它们。

Hash-style Object

Hash-style Object 这个词是我临时想到的,之前我貌似也没在别的地方见过这种说法。

之所以发明了这个词,是因为现在有着越来越多的语言声称自己“一切皆对象”了。在 JS 中,很多时候,很多数据是 instanceof Object 的,包括任意一个 Function。而我只是想表述 Object 被用来当做其他语言中 Hash 的用法的那一面。

JS 中,Hash 即 Object,Object 即 Hash,这两者是不分的。所以有时也会出现误会。

我印象中,我至少碰过三个项目。它们在判断一个用户是否 admin 时,用到了 config.admins[username] 这样的判断。大家应该理解我的意思吧,也就是:在 config.js 中,保存了一个 admins 值,这里面填写着属于 admin 组用户的用户名。

有一次,在其中的一个项目中,我注册了一个用户,名叫 constructor ,于是我就成了 admin。这是因为,每个对象,都有它的 constructor 属性。而如果 JS 中有 Hash 类型存在的话,这个漏洞就不会发生。当然,后来这些 config.admins[username] 都改成了 config.admins.hasOwnProperty(username) 判断,终止了这个漏洞(不过后来据 @fengmk2 说,还是不保险。但他最近一排时间一直忙结婚,没有给我回复)。

Array

Array,任何语言都不可缺少的一个组成部分。无论任何形式的编码,所要触碰的数据中,总有同质的数据是可以分为一个共同的小组来管理的。我们会对这些个小组,进行各种循环,各种 map,各种 reduce。这个存放相似数据结构的小组,就是所谓的 Array。

Array 好像没什么好说的,据说 []new Array() 效率要高,好像是《JavaScript: The Good Parts》说的。

数据类型和数据结构

JS 中,记住一句话,可以不吃亏:无论黑数据,白数据,脏数据,干净数据,能被 JSON.stringify 的,就是好数据。

恰好,无论 Number, String, Hash, Array 以何种方式组合,都能被完美地 JSON.stringify。所以在 JS 中,我们很多时候不去创建什么类啊,不去搞什么面向原型编程啊。在需要管理同质化数据时,一个 Array 包裹他们;在需要管理非同质数据的 key-value 结构时,一个 Object 字面量包裹他们。

在 Java 或者 C++ 中,如果想要得到一个可以具有自定义属性的结构,定义一个新的类将是一件愉快的事。但在 JS 中,字面量的 Object 实在太方便了,所以也就不必定义类了。动态语言的灵活经常使得某些旧有的设计模式过时,这不算少见。

有一次一个朋友说,他很喜欢 JS 这样的面向原型编程,一想到 Java 的各种类就很烦。后来我随便答复了两句,感受到,他或许只是想表达他喜欢 JS 中方便的字面量 Object,而不关乎面向原型或是面向对象什么事吧。

相信我,跟 JS 打交道打得越多,你所使用的数据类型和数据结构就会越局限于上述那四种类型。这也不算是坏事,就我的观察来看,他们组合在一起确实很足以表达这个世界了。

var

var 做了它该做的 70% 的工作,留下了 30% 的坑。但也不算很坑,代码习惯好的人还不定踩得进这坑。

Function

我熟悉 Python Ruby 和 JS,在这三门语言中,我觉得 Function 只在 JS 中是作为 first-class citizen 的。Ruby 由于沿袭了 Smalltalk 的消息传递机制,更是限制了 Function 在其中作为第一公民的便利。Python 嘛,匿名函数用得太差,列表解析只在一定程度上弥补了这个不足,Ruby 的 block 倒是很赞。

jQuery

jQuery 是 JS 的好伙伴。

每当想起它,我都想到 Ruby 和 Rails 的关系。有个段子是这么说的:Matz 发明了 Ruby,and then DHH rename Ruby to Rails,并把 Rails 发明光大。确实,在 Ruby 的世界中,没有 DHH 的 Rails,就没有今天的 Ruby。

虽然说如果没有 jQuery,JS 照样活得好好的,并且目测不会影响后来 Node 和 V8 这类汹涌澎湃的技术诞生。但看看现在有多少人离开了 jQuery 就不会操作 HTML DOM,就可以看出 jQuery 在 JS 世界中的地位了。

$ 这个符号,我认为,代表了——对于多种常用 DOM 操作的极简抽象,更是用最原始的方式带来了元编程的理念。

何谓元编程,就是用代码来代码。在语言提供的原生组件之上,以更高层面的目光来看待代码。

JS 本身的元编程能力比较差,jQuery 就通过 $ 符号,通过接受不同字符串的方式,对不同的字符串进行解析,来实现元编程的目的。

传入 $ 符号的字符串,无论是 <div></div> 或是 ‘#some-id’ 或是 ‘{}’,都不仅仅只是对 $ 的一种函数调用了。它们只是通过字符串的形式,在玩元编程。

除了 jQuery,我还真想不起来是否有另外的库也是这么玩元编程的。

Underscore, Lo-Dash

  1. 关于集合的那些操作,弥补了 JS 标准库的残废状态,也大大发扬了 JS 匿名函数的威力

  2. Functions 那部分,更是在特定情况下使 JS 的匿名函数更具威力

  3. Objects 那部分,有些我觉得应该划分到 Utilities 部分去。比如:isArray、isArguments 那类的。纯粹是为了弥补 JS 的残废。

异步控制,Async、EventProxy

要不是现在我所在的团队广泛而大量地使用 EventProxy,以及它的作者本身就在我们团队,我可能是不会去接触这些国人发明和维护的库的,这个偏见说来就话长了。

不过就目前来看,我倒是慢慢喜欢上了 EventProxy 的用法。

虽然 Async 和 EventProxy 都可以轻易实现对于各种异步并发以及异步逻辑顺序的控制,但它们确实是两套思维在里面的。

  1. Async 就像一只大手,掌控着局面;EventProxy 是个通讯兵,随叫随到为您服务。Async 插入式地在控制,EventProxy 悠哉地呼叫闭包之外。

  2. 用了 Async,代码稍显局促;用 EventProxy 的话,战线可以随意拉长。

  3. 还记得 if 和 goto 之争吗?没错,Async 是 if,EventProxy 是 goto。两者虽能实现同样逻辑,但后者需要更深内力。

我想着重说说第三点。

我是个编程世界的后来者,我并没有接触过 goto 遍地的那个年代,自从我接触编程开始,goto 和 label 这两个关键词除了在某些语言的 for 结构中还能见到之外,已经销声匿迹了。

但伴随着是EventProxy 的滥用,goto 又回来了。

什么是 goto?就是在代码任意的一个地方,定义一个 label,在你觉得有必要时,goto 过去。

EventProxy 又怎么用呢?在你需要的地方,定义 something.on(‘hehe’, function)。在你高兴时,something.emit(‘hehe’, data)。代码逻辑乱跳。

它们一样的。

我们很需要谨慎这种对于事件机制的滥用。

V8

没有 V8 和 Chrome 以及几年前的 JS 引擎大战的话,很多 HTML5 的幻想都只能是个幻想。V8 的速度实在是太快了,快得无法言喻。

光是 V8 的这种快,就足够成为好好学习 JS 的一个理由了。

Node.js

各领域,各平台,都由于 Node 的出现而有了对于 JS 这门语言的支持。JS 本来就图灵完全并且群众基础广泛,一旦有人发明了 Node 填平了 JS 与各种文件 IO 以及网络 IO 之间的沟壑时,现在 Node 社区如此火爆的热闹场面也就不足为奇了。

Node 的 module.exports 实在巧妙,通过局部 mutable 变量 module 的穿梭,无缝地使 JS 得以模块化。

Node 能够如此方便地实现高并发以及并发取数据这两点,在某些应用场景下是很具优势的。少数的一些 CPU 密集场景,通过 add-on 的方式也很容易转为异步解决。

随着 Node 生态圈的日益成熟,Node 还是很有前途的。现在就已经是很不错的了。

24 12 / 2013

今天帮 nodeclub 加入了 OAuth 登陆的功能。之前 nodeclub 由于受到某个很牛逼的可以穿越验证码的发帖机的影响,暂时关闭了新用户的注册功能。而其实说起来,以个人之力跟 spammer 斗是很无谓的行为,所以干脆让新用户通过 GitHub 来登陆。这样一来,nodeclub 与 spammer 的矛盾就转移成 spammer 与 GitHub 之间的矛盾了。

我相信 spammer 还是斗不过 GitHub 的,顺便 GitHub 还起到了过滤小白的作用。

——

在今天开发的过程中,我是先写代码,然后才打算写测试的。原因在于,我今天写的代码所会导致行为我不能确定,在写代码的过程中,也确实遇到了不同程度的重构。而在行为不确定时,边写测试边写代码,只是更多地增加了写代码的负担,而不是保证了代码的行为。

那么在什么时候该测试先行或者测试并行,什么时候应该测试后行呢?

分两种情况:

1 行为确定时,测试先行是个好选择

我之前看过一篇介绍 BDD 的文章,这篇文章主要测的是一个可以将阿拉伯数字转为罗马数字的函数。它先是通过测试,确定好了转换所需的效果以及各种边界情况:

XVI     16
XVII     17     
XVIII     18     
XIX     19     

然后一步一步地完善函数,直到测试通过,把函数行为固定。

这个例子中,由于所期待的行为非常确定,所以测试先行在这里是个好选择。

2 行为不确定时,可以选择测试后行

测试这东西,一是有驱动开发的作用,一是有固定行为的作用。

如果测试后行的话,驱动开发的作用自然是没有了,但固定行为的作用仍在。