<?xml version="1.0" encoding="utf-8" ?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Mockee Nodes</title>
<subtitle>Happiness only real when shared.</subtitle>
<link href="http://mockee.com" />
<updated>2012-11-06T01:17:22+08:00</updated>
<author><name>mockee</name></author>
<id>urn:uuid:0d041aa4-fb75-491c-b79f-3ba50794c0d2</id>
<entry>
<title>Mailr Released</title>
<link href="http://mockee.com/2012/11/06/mailr-released/" />
<id>urn:uuid:a9f10f76-6485-4004-8712-32951e200111</id>
<updated>2012-11-06T01:17:22+08:00</updated>
<content type="html" xml:base="http://mockee.com" xml:lang="en"><![CDATA[<a href="http://appfn.com" title="appfn"><img width="300" height="100" src="http://static.mockee.com/uploads/2012/11/24f3f82422a6e3cab77f7858773ef69c.png" /></a><br><br>距离上一次和几个要好的朋友一起利用闲暇时间鼓捣点儿有意思的东西已经过去六七年的时间了，我很怀念那些时光，那些人。旧事不再重提，如今和 <a href="http://douban.com/people/godlikejay">@J</a>, <a href="http://douban.com/people/tifaqu">@Tifa</a> 一起组队做 app 确实也让我找回了几分当年的感觉，只是时过境迁，少了学生时代的自在和洒脱。<br><br>尽管如此，我们依然乐在其中。一年的时间不算短，但真正能开工的时间少之又少，赶项目、必要的充电、交流分享、翻译阅读、陪伴家人... 我们通常会在 skype 上牢骚几句，然后默契地停工一段时间。这一年中，Trello 是用得最得手的协作工具，我们在上面跟踪进度、共享资源、记录灵感。日子就这样一天天过去。但项目总还是要上线，为了给付出一个交代，我们以一年整为底线设定一个了 Deadline。收尾的过程紧张刺激，所幸如期上架。<br><br><a href="http://douban.com/people/godlikejay">@J</a> 是 Mailr 的核心力量，没有 J 就没有 Mailr，其学习能力也真心令我叹服，作为码农，和强手作伴是人生一大快事。<a href="http://douban.com/people/tifaqu">@Tifa</a> 则是设计方面的最佳吵伴;) 其设计的整个迭代过程只能用惊喜不断来形容。OK, Special Thanks  到此，鸡皮疙瘩一地了。我想说的其实是，有这样的队友，无论平日工作还是业余合作都无比舒心，我很幸运。<br><br>Mailr 可能是第一个专门为豆邮设计的手机客户端，你可以到 <a href="http://appfn.com/mailr">http://appfn.com/mailr</a> 下载试用。我们用心在做，但同时更期待大家来找茬儿，帮助我们改进：<a href="http://www.douban.com/group/437504/">Mailr 豆瓣小组 VIP 入口</a>]]></content>
</entry>
<entry>
<title>NodeCat 开发笔记</title>
<link href="http://mockee.com/2011/09/15/nodecat-dev-notes/" />
<id>urn:uuid:b99c8b3c-60da-4a53-928a-0120b58baddf</id>
<updated>2011-09-15T17:23:18+08:00</updated>
<content type="html" xml:base="http://mockee.com" xml:lang="en"><![CDATA[<a href="http://storify.com/_nw_/nodejs-logo" title="node turtle"><img width="450" height="356" src="http://static.mockee.com/uploads/2011/09/5d3476944ceff9b64cc0f49a1e894305.png" /></a><br><br>简单记录下开发中遇到的一些问题与解决办法，方便日后查阅：<br><br><strong>中间件与框架</strong><br><br>NodeCat 使用 <a href="https://github.com/visionmedia/express" title="express">Express</a> 框架搭建完成，当然也可以说是 <a href="https://github.com/senchalabs/connect" title="Connect">Connect</a> 这个中间件系统协助完成了大部分工作并让整个开发过程变得简单轻松——<a href="https://github.com/visionmedia/express" title="express">Express</a> 基于 <a href="https://github.com/senchalabs/connect" title="Connect">Connect</a> 构建，中间件的设置方法与其基本一致，比如协助将客户端 post 的内容放入 req.body 的 bodyParser()、处理用 POST 伪装的 HTTP 方法（PUT 和 DELETE 等）的 methodOverride() 以及用于错误处理的 errorHandler()、请求日志的 logger() 等等。此外，<a href="https://github.com/senchalabs/connect" title="Connect">Connect</a> 在借鉴 Rack（介于 Ruby web 框架与 Ruby 运行时之间的中间层，类似于 <a href="https://github.com/visionmedia/express" title="express">Express</a> 与 node.js 之间的 <a href="https://github.com/senchalabs/connect" title="Connect">Connect</a>） 和 ejsgi 后所提出的分层处理 HTTP 请求和响应的想法更是令开发灵活多变。<br><br><a href="https://github.com/senchalabs/connect" title="Connect">Connect</a> 1.7.0 提供了一个位于 static() 之上名为 staticCache() 的新的中间件作为 memory cache 服务，ApacheBench 结果显示它比单独使用 static() 中间件或 <a href="https://github.com/cloudhead/node-static" title="node-static">node-static</a> 的性能都出色：<br><br><blockquote cite="http://tjholowaychuk.com/post/9682643240/connect-1-7-0-fast-static-file-memory-cache-and-more">Then we have the new staticCache() middleware paired with static() serving ~5000rps, a 24% increase over node-static (which also performs memory caching), and ~52% over static() alone.</blockquote><br>同样可以为 <a href="https://github.com/visionmedia/express" title="express">Express</a> 加入 staticCache：<br><br><pre class="sh_javascript">app.use(express.staticCache());</pre><br><br>在 <a href="https://github.com/visionmedia/express" title="express">Express</a> 中实现图片上传功能很简单，利用表单数据解析模块 <a href="https://github.com/felixge/node-formidable" title="formidable">node-formidable</a> 以及中间件 <a href="https://github.com/visionmedia/connect-form" title="connect-form">connect-form</a> 就可以轻松完成。存放图片的路径通常是根据当前日期来设定，所以就会有个多级目录的创建问题，当然这并不困难，引入 path 与 fs 模块写个递归就可以解决（或者直接用 <a href="https://github.com/substack/node-mkdirp" title="connect-form">node-mkdirp</a>），需要注意的是创建目录时的权限问题。<br><br><strong>模板引擎与 CSS 语言</strong><br><br><a href="https://github.com/visionmedia/jade">jade</a> 可以选择将 HTML 压成一行，但并不包括行内脚本；<a href="http://stackoverflow.com" title="stackoverflow">stackoverflow</a> 上有人提出使用 <a href="https://github.com/mishoo/UglifyJS" title="UglifyJS">UglifyJS</a> 并为 <a href="https://github.com/visionmedia/jade">jade</a> 增加一个 filter 的方法来处理，可行，但却修改了 jade lib 中的文件，所以我并没有在实际项目中使用这个方法。好在 nodecat 的行内脚本大多只进行模块的组织工作并不涉及业务逻辑，代码量小，手动压缩即可。如果你不喜欢 jade，可以随时将 <a href="https://github.com/visionmedia/express" title="express">Express</a> 的 view engine 换掉，比如使用熟悉的 <a href="http://mustache.github.com/" title="Mustache">Mustache</a>，有个名叫 <a href="https://github.com/fat/stache" title="Stache">Stache</a> 的项目可以帮你在 <a href="https://github.com/visionmedia/express" title="express">Express</a> 中实现：<br><br><pre class="sh_javascript">app.set('view engine', 'mustache')<br>app.register(".mustache", require('stache'));</pre><br><br>从功能上来说，<a href="https://github.com/LearnBoost/stylus" title="stylus">Stylus</a>、<a href="https://github.com/nex3/sass" title="Sass">Saas</a>、<a href="https://github.com/cloudhead/less" title="LESS">LESS</a> 都很强大，但更偏爱语法简洁的 <a href="https://github.com/LearnBoost/stylus" title="stylus">Stylus</a>，搭配 <a href="https://github.com/visionmedia/nib" title="nib">nib</a>（如果你使用 <a href="https://github.com/cloudhead/less" title="LESS">LESS</a>，<a href="http://lesselements.com">LESS Elements</a> 也是很好的选择）可以有条理地规划并高效地书写 CSS（在过去的很长一段时间内，前端工程师都在为处理浏览器兼容性以及不可避免地堆砌冗余样式耗费着大量时间）。有关 <a href="https://github.com/LearnBoost/stylus" title="stylus">Stylus</a> 的配置（compress, debug）和常用方法（function, arithmetic, mixin）都可以在 <a href="https://github.com/LearnBoost/stylus/tree/master/examples">example</a> 中找到。<br><br><strong>数据存储</strong><br><br>在 <a href="https://github.com/visionmedia/express" title="express">Express</a> 中，session 中间件默认使用 <a href="https://github.com/senchalabs/connect" title="Connect">Connect</a> 内置的内存存储方式，但除此之外还有很多其他的选择，比如使用 <a href="https://github.com/masylum/connect-mongodb" title="connect-mongodb">connect-mongodb</a> 将 MongoDB 作为 session 的存储介质等。由于我在 NodeCat 中同时使用了 <a href="https://github.com/LearnBoost/mongoose" title="Mongoose">Mongoose</a>，所以换用 <a href="https://github.com/kcbanner/connect-mongo" title="connect-mongo">connect-mongo</a> 更方便（Stack 上也有人提到 <a href="http://stackoverflow.com/questions/6819911/nodejs-expressjs-session-handling-with-mongodb-mongoose">同样的问题</a>）：<br><br><pre class="sh_javascript">var mongoose = require('mongoose'),<br>    mongoStore = require('connect-mongo');<br>// configure<br>app.use(express.session({<br>    secret: 'nodecat',<br>    store: new mongoStore({ url: app.set('connection') })<br>}));<br>// connect to mongodb a second time using mongoose<br>mongoose.connect(app.set('connection'));</pre><br><br>NodeCat 中没有文章分类功能，相较分类我更喜欢标签（tag）这种细粒度的泛描述。每篇笔记（每个 Note Schema 的实例）都有自己对应的 tags 数组，这样，根据具体 tag 的名字就可以方便地找出包含此 tag 的所有文章，如果数据量大，可以为 Note Schema 建立 tags 的索引。<br><br>网站首页右侧有个最近回复列表，需要显示最近回复者的名字以及被回复文章的标题和链接。之前对 MongoDB 了解不多，在设计 Note Schema 的时候把 Comments 对象也塞了进去，导致取数据时绕了弯子，后经同事点拨，为 Comment 单独建立了 Schema，将笔记与回复分离，用 id 做关联，这样按创建时间获取回复数据自然就是“最近回复”了。<br><br>曾考虑用 <a href="http://disqus.com/" title="disqus">disqus</a> 作评论系统，省事省心，速度也不错，但最终还是放弃了，毕竟不是本土服务，链接被重置的情况随时可能发生，伤不起。正如你看到的，目前 nodecat 没有在评论部分多费精力，对于自用的东西多少有些放纵——我假设来到这里的朋友都可以正确地使用自己的名字与 email 并对言论负责。<br> <br>评论中的用户头像都是通过被 <a href="https://github.com/brainfucker/hashlib" title="lib for node which makes hashes">hashlib</a> 模块 md5 加密过的 email 到 <a href="http://gravatar.com" title="Gravatar">Gravatar</a> 换取的，<a href="http://mongoosejs.com" title="Mongoose">Mongoose</a> 的 <a href="http://mongoosejs.com/docs/virtuals.html">virtual attributes</a> 可以方便地将这个过程封装起来供 comment 实例调用而不必单独存储 avatar 到 mongodb：<br><br><pre class="sh_javascript">Comment.virtual('gravatar').get(function () {<br>    var gravatarHost = 'http://www.gravatar.com/avatar/';<br>    return gravatarHost + hashlib.md5(this.email) + '.jpg?s=' + 32;<br>});</pre><br><br>除此之外还有很多地方都用到了 virtual，比如输出被 <a href="https://github.com/andris9/node-markdown" title="node-markdown">node-markdown</a> 解析过的正文与评论、格式化日期和 url 等。同时不免还要用到  <a href="http://mongoosejs.com/docs/methods-statics.html" title="methods statics">Methods</a>，比如 password virtual 的 set function 中将密码掺入 salt 后加密的 encryptPassword method：<br><br><pre class="sh_javascript">User.method('encryptPassword', function (str) {<br>    return crypto.createHmac('sha1', this.salt).update(str).digest('hex');<br>});</pre><br><br><strong>服务器</strong><br><br><a href="https://github.com/LearnBoost/cluster" title="Cluster">Cluster</a> 是目前正在使用的服务器管理模块，它可以利用服务器的多核心来动态实现简单的负载均衡以确保网站可以无间断地提供服务。修改 node 程序后无须重启服务就可生效是 <a href="https://github.com/LearnBoost/cluster" title="Cluster">Cluster</a> 的特性之一，其丰富的扩展还可以协助完成优雅停机、重启、杀进程、监控网站状况等操作。昨天我还尝试使用了另一个插件 <a href="https://github.com/visionmedia/cluster-live">cluster-live</a>，它可以进行实时管理与统计并通过 canvas 绘制动态图表。下面这张是在我本地测试时的截图，小清新风格：<br><br><img src="http://static.mockee.com/uploads/2011/09/4f8a5635a24d6f835776ac77c1154508.png" alt="nodecat with cluster live" width="747" height="347 "/><br><br><strong>代码部署</strong><br><br>平时工作中规定使用 SVN 和 Mercurial 来对代码进行版本控制，但我更喜欢 Git，个人的小项目也都放在自己的 Git 仓库中，NodeCat 也不例外。除了代码管理，还可以使用 Git 的 hook 协助完成远程 checkout 实现网站的自动部署。如果部署后网站没有变化，可以检查下是否使用了 <a href="https://github.com/senchalabs/connect" title="Connect">Connect</a> 的 staticCache 或 nginx（如果用到了的话）的某些配