Expressjs三五事

最近在用Expressjs折腾后台,遇到一些坑(很多都不算坑,只怪我自己不会走路),也积累的一些tips,可以一记:

EXPRESS

框架本身的质量和成熟度还是比较高的,最出色/难得的一点是——十分的克制(连body-parser都要自己require),跟前辈RoR和Rjango相比,轻量的不像实力派。虽然支持View,但是没有任何默认的Render Engine;根本就没有任何连带的ORM或者类似的数据访问的组件,也就跟Model也沾不上啥边。

所以,你已经很难把Express定位为MVC Web Framework了,而更为准确的定位是——带middleware chain的router,仅此而已。

轻量带来的优点和缺点同样显而易见

Pros:

  1. 源码短,容易读,想要看清楚一个请求怎么来怎么去debug个10来次都能弄明白个大概
  2. 优化容易,iceberg少,能看到的东西基本上就是所有了
  3. 接口简单,学习成本和记忆成本少。(req, res, next) => {}就基本上你需要写的所有东西了。
  4. res和req只是在nodejs本来的request和response上封装的一层,该有什么就有什么
  5. app和router的设计真的是出色,各种sub-app和router的分离可以让每个请求走的middleware chain既清晰又精简

Cons:

  1. 各种middleware需要自己折腾,麻烦
  2. 各种middleware需要自己折腾,麻烦
  3. 各种middleware需要自己折腾,麻烦
  4. 各种middleware需要自己折腾,麻烦
  5. 各种middleware需要自己折腾,麻烦

开发

Nodemon

任何用到了node的项目,都该在package.json里有如下配置才对:

  "scripts": {
    "dev": "set DEBUG=zd:* & nodemon ./bin/www",
  },

Debug()

这是一个很有用的module:

  1. 不是所有所有代码都能用ide的debug搞定,比如时序相关的
  2. 很多时候也就是一个print就能搞明白的东西,何必要F5?
  3. 其他各种module,包括express自己也都是用的debug(),只要set DEBUG=*就能看到所有的print,岂不痛哉
  4. 关于nodejs的一切都是tj大神写的,这个也不例外

Promise

Promise是一味解决callback hell的好药,但并不能根治,还是希望await/async早点成为正式标准吧。promise的缺点,随便google一下多的是。

Sequelize

算是个合格的ORM,该有的功能都有,只是:

  1. 文档略渣
  2. 时区问题有点烦,需要在配置里加个+8:00,DB里存utc确实是解决globalization的好办法,但几个项目需要呢?
  3. migration的功能看起来很美,但是动不动就要drop table,你敢用?
  4. model里没定义的field,写在query的attributes里,并不会报错,你看debug信息里生成的sql也有,但最后的model就是没有,有点蛋疼
const foo = sequelize.define('foo', {
    a: DataTypes.STRING(512),
    //b: DataTypes.STRING(512),
});
     
db.foo.findOne({
    attributes: ['a', 'b']
}).then(ret => {
    // DEBUG: EXECUTE SQL: select a, b from foo
    ret.b === undefined;
});

Morgan

全局日志,没啥好说的。只是很多时候只能抛出Error: write after end,但实际上可能是读写permission的问题。不过这也怪不得实现,只能自己好生检查了。

部署

Serve Static

Expressjs自带的server static十分简单,就是单纯的每次读文件(304不用读,废话),正确的返回304或者200,也没有任何缓存(view engine的模板倒是有缓存)。静态资源还是应该放在专业的地方。

PM2

监控和部署全款它了,好用还是好用,只是:

  1. web上的监控服务收费,倒是无可厚非
  2. deploy localhost有点麻烦(需要把ecosystem.js里的host写成localhost之类的,google一下有很多人问过),因为设计初衷是部署到remote机器(确实是合理的)
  3. startup脚本用其他用户,必须要sudo pm2 startup --user other --hp /var/other,su到其他user,报一些风马牛不相及的error
  4. 执行deploy的目录必须要git init过 ???

nickyong

Newbie-thing

  • 非root用户无法bind 80端口:现在还没lbs,有了自然不会bind 80,看起来过得去的解决方案就只有iptable做本地转发了
  • 开发环境用crontab做些自动部署之类的东西挺方便的
  • shell script真不是人写的
END

熟练掌握javascript

超过半年没有写文章,也是懒得很。

这么大个时间上的断层,免不了想总结回顾一下:

  • 代码:这段时间写的最多的还是Unity和javascript,当然除了写还有学,写到哪儿学到哪儿(托了没那么忙的福,可以想看就花个一天看到底)
  • 代码:helloworld('elixir') helloworld('go')
  • 代码:最终还是入了vim的邪教,看个网页都想jjjjjj
  • 看书:fiction和non-fiction一半一半,non-fiction把两本简史看了,小说看了一堆,感觉越看越快
  • 其他:积累管理经验??(/nickyoungface)

好了,列完list就算是自我安慰完了(时光没虚度),接下来说正题


刺激到我想写文章的原因有两个:一是见识了个“写代码就是要用vim并且不能有任何提示所有方法都要自己背下来才是写得好”的技术总监,不以为然;二是看了You Are Not Google这篇文章,深以为然。

技术(不单止computer science)的存在都是为了解决问题,解决问题的先决条件在于正确识别问题

写代码(单指输入源代码)要解决的首要问题是能否默写出方法名么?并不是,而是如何更快更简单地用代码描述出你的思路!背诵方法名并不能辅助我思考,反而是completion能帮助我更快的输入,留出更多时间给思考。也让我在10dd(删除10行)了以后能心情好点,不受再次背诵之苦。

使用某个特定技术要为了解决某个特定的问题,你的问题(可能是只有3个程序员,需要做一个不知道有没有用户的APP试水)和Google的问题(有世界上最好的工程师团队,需要以毫秒级的响应速度完成数千万用户的请求)相距甚远,有多大概率你们问题的答案却刚好是同一个?

正确的识别问题,接下来,才更有可能完美的解决问题。

举个例子——javascript


这里说的javascript,不是指language层面的js,language层面的js连它的creator都承认过在前几个版本就是失败的存在(个人认为es4及以前的版本都是渣)。不过话又说回来,有哪个大家广泛认可的主流语言能在一个月里设计出来的?deadline才是产品最大的敌人!

runtime层面的javascript,确实是一个正确识别问题并解决问题的成功案例。要注意的是,这里的runtime并不单指V8,而是V8加上跟V8配套的browser或者nodejs的实现。就像同样也称得上成功的Unity,完整的runtime应该是mono加上底层更为复杂的render和control flow的实现。

各个runtime的实现可能有差异,但核心原理却大同小异,我们从用V8引擎的nodejs的intro开始:

Node.js uses an event-driven, non-blocking I/O model

Single-thread

虽然intro里的关键字是event-driven和non-blocking,但第一个keyword,还应该是单线程。

单线程要解决的是什么问题?答:复杂性。

就像前面说到的,V8只负责javscript的执行,且只是以单线程执行javascript。在完整的Runtime中,V8还需要跟其他功能协同作业,比如网络、比如绘制。如果javascript的执行环境就是个复杂的多线程模型,那么整个Runtime的复杂度将会是M * N而不是M + N,直接呈指数级增长。而且选择单线程模型,还有个额外的好处(也可能是设计者觉得最大的好处)—— 不容易犯错,毕竟普通意义上的多线程编程,跟正常人类的思维逻辑就有些相悖,并不是每个程序员都能驾驭的。(君不见现在的新语言都会把多线程用coroutine或者是actor之类的模型包装起来,不直接暴露给使用者)。

解决了复杂性的问题,V8的职责倒是单一明了了,那需要parallel的场景怎么办?

异步!

Event-driven & non-blocking

这两个关键字加在一起,共同支持了javascript的并行,我们先从non-blocking说起。

看一个blocking的反例:

while(1) {
    block();
    render();
}

如果block一直执行不完或者是花了很长时间才执行完,那么render就会一直等待,你的浏览器可能就会出现“掉帧延迟”甚至无法响应各种鼠标键盘的输入,因为在render下面,可能还有响应各种事件和中断的函数在。

如何直接让任意blocking的方法变成non-blocking的,简单:

// 这段代码本身是错误的,并没有解决问题
non-block = function() {
    setTimeout(block, 0);
}

Javascript具有functional programming的特性,理论上所有blocking的函数都可以当成callback传给其他切换异步的方法。

OK,那是不是有了setTimeout是不是就万事大吉了?启个操作系统的timer,到时间了把该调用的callback都调一下就完事?

你忘了还有一类天天都能遇到的代码:

foo.on('click', clickCb);

除了各种浏览器event,还有network相关的地方,也需要回调的存在来共同完成异步这件事。怎么统一管理这些回调?

这就需要event-queue了(event-driven的核心)

直接从nodejs的网站上抄一段来,看下nodejs的event-queue都处理了些啥(once again:event-queue是V8之外的功能)

timers: this phase executes callbacks scheduled by setTimeout() and setInterval().
I/O callbacks: executes almost all callbacks with the exception of close callbacks, the ones scheduled by timers, and setImmediate().
idle, prepare: only used internally.
poll: retrieve new I/O events; node will block here when appropriate.
check: setImmediate() callbacks are invoked here.
close callbacks: e.g. socket.on(‘close’, …).

可以看到,event-queue为了解决异步模型,做了远比你想象多的事情。

简单来说,一个完整的event-loop分成了不同的phrase,每个phrase都是一个小队列,塞入了各种不同类型的回调,让V8执行回调,然后dequeue,当小队列为空或者达到threshold(callstack.length == max),再处理下面的phrase,直至走完所有phrase,完成一次loop。

这些复杂性,对于V8或者使用javascript的程序员来讲,都是黑盒子,但却很好的解决了异步的问题(event queue + non-blocking callback),从而进一步解决了并行的问题。让你的浏览器能够“一边”执行js代码、“一边”渲染、“一边”进行网络IO。

Compilation

单线程是好,但是从本质上,他无法利用多核的优势(虽然runtime的其他功能可以充分利用多核,nodejs也有cluster模式),可能代码的执行会不够“快”。

那要怎么解决这个问题?那就让他更快!

javascript编译器/VM给出的完整的答案十分的复杂,从对象模型到内存分配再到垃圾回收,无所不用其极。我能力有限,只取两点来讲:

no bytecode

我自己有很长一段时间好奇过,为什么从来不见有文章写javascript的bytecode的?因为在我的认知中,所有有VM和JIT的语言,比如C#/Ruby/Python,都该有bytecode,要不然怎么做JIT,怎么做进一步的优化呢?

这就是典型没想清楚问题的例子。

别忘了Javascript诞生之初,是为了给浏览器使用的。

有bytecode的执行过程是怎样的?

       parse      parse           JIT
source -----> AST -----> bytecode ----> executable

没有bytecode呢?

       parse      JIT              
source -----> AST ---->  executable

少了一个parse的步骤,在代码少的时候(早些年的js可不是动不动就好几十K,好几万个function哦),最后执行的总时间只快不慢,别忘了,javascript最开始可是以文本的方式下载到本地的。而且,javascript早年间都是很有大概率“一次加载一次执行”的,而不像是Ruby/Python的代码“一次加载多次执行”,缓存一份bytecode,就只用一次,实际上就是一种浪费。

但是,早些年是早些年,不巧现在不光浏览器的javascript越来越复杂,还出现了nodejs这种“幺蛾子”。

这种情况下,还能不更快?

hot optimazation

当然可以,如果nodejs在干跟RoR一样的事情了,那把bytecode再捡回来不就好了?

不过V8还是没有传统意义上的bytecode。因为所谓bytecode,跟LLVM的IR一样,其实就是多了一个中间地带来方便做一些“动态”的优化。V8也会做动态的优化,但并不是特别需要额外的特别地带,只需要一个从javascript function到executable的mapping就行。实际上V8会多开一个runtime profiler的线程,监视代码里运行次数最多(hottest)的函数,然后重点优化这些函数,直接替换最开始(第一次明显还需要有一个全量的编译,先让代码跑通,才能找到跑的最多的地方啊)生成的executable。

full compilation + hot optimazation 就是V8面对怎么才能让javascript跑的更快的答案。


恩,以上就是我觉得能在简历上写 熟练掌握javascript 应该达到的水平。


TL;DR : 先问,再答,是道。

END

My Tool Chain Part2

开篇先吐一槽:上一篇的名字就起的不对,明明该叫My Tool Kit,然而脑袋一抽写成了Tool Chain。结果回过头再读一遍,着实想不到就那几个tool要怎么才能凑个chain出来。

算了,看在命名的连贯性上,继续错下去好了:

Sublime

这次写插件:

Package Control

没这个玩意,就不用谈插件了。只说一个良好的体验——这个插件带了Enable/Disable和Remove/Install两组功能,意义在于——后悔的时候不用再去下载,前提是用不上的时候,你不会冲动的先删为敬。

Evernote

本来该是一个H3,但大部分时候我用Evernote都是在Sublime里使用,所以放在这一级写也没有什么不妥。

首先,你得承认,你还是需要一个云笔记应用的,因为现在我们能用到/必须用到的端确实是越来越多了。

那么墙内可选的,稳定+大牌的产品就只有有道云笔记和印象笔记了。有道云笔记试用了一下体验也还不错,特别是内容直接支持markdown这个特性,简直是programmer-friendly。

只是,有道没有提醒功能!根据搜索引擎的历史,似乎之前的版本是提醒功能的,不知为何现在的版本砍掉了这个功能。这就蛋疼了,要知道我在手机上的使用场景,一半都是提醒相关的(并不想用闹钟,我就想要all in one的note)。

在pc和mac上,你就需要Evernote这个插件了。本地生成一个key文件,由插件帮你使用(封装&隐藏)Evernote官方提供的web API,就直接可以read和write你的所有笔记和笔记本了。笔记内容支持markdown编辑,而同一份笔记在移动端/网页端/官方客户端查看的时候则是html。

然后,这套note就完全符合我的需求了:能便捷输入的时候(有键盘),可以更好的格式化和编辑内容;不能便捷输入的时候(移动端),只要直观的查看,而且能添加定时提醒。

最后,一点启示:要做大平台,web API真的只是标配

Hex Viewer

我不想装ultra editor,我有时候需要直接查看二进制,就只能依靠这个插件了。

Markdown Preview

用了一段时间的Markdown Editing,发现并不是很喜欢那种“半所见即所得式”的模式。我多半时间只是想要基本写完了看下最后的效果罢了,所以这个只需要一个命令在浏览器中看到最后效果的插件就很适合我了。

良心的是,这插件还专门提供了输出成Github Style的选项。



其他杂七杂八的插件,多数都是一些语言相关的语法增强和格式化的工具,没什么好说的,用到时候去下个最热门download最多的就好。

虽然将来可能会被VS Code取代(3~5 yrs i guess),但现在sublime确实还是我的文本编辑器首选。


docker

不管其他人怎么吹docker(docker是真的吊,我懂),对我来说docker就只是个工具,是我们这种“低端懒鬼型”程序员的救命神器。

最近装个deeplearning处理图像的应用,断断续续装了我一个礼拜你敢信?当然网络问题是最大的锅,但各种dependency的issue也是足够让人头痛。

我真的就只是想要binary罢了,我真不相信我的环境特殊到独一无二啥都要我自己build。

以前倒是真的干过为了玩某个linux上的东西下了一整个虚拟机的镜像的事,事后感觉就像是为了吃KFC的番茄酱买了个全家桶似得。

既然能虚拟化一个Runtime,何苦要去虚拟化整个OS?这正是docker厉害的地方,强就强在这个概念了!(似乎docker不是最先提container这个概念的,不过能炒到最火也是一种能力啊)

反正就效果来说,我想玩一下Jenkins什么的,再也不用去step1step2step99(我丝毫不关心你的依赖,也不关心makefile是怎么写的,真的),也不用去下虚拟机镜像了。我只需要优雅的打开我的docker,高贵的在docker hub上搜索一下,然后冷艳的等待下载启动container,最后,开整!

小小的自来水一发daocloud,免费提供墙内的镜像和加速,自然是极好的。


revealjs

简单概括就一句话:用markdown做基于浏览器的ppt。

只要是程序员,上手都会很快。最后的效果还不算太差,大部分的场景绝对都足以应对了。

如果你想,revealjs也能做到跟powerpoint一样支持演讲者视图,只是要就用到nodejs了,麻烦了不少。

我自己也fork了一个直接clone了就能开干的版本

END

谁说UV只能<1

先说结论:UV在实际应用中并不一定小于1,OpenGl对texture进行采样的时候,专门有一个参数来控制对UV坐标大于1的部分如何处理——详见这个链接的wrapping部分。

也就是说,对于obj文件:

v  -44.036751 0.000000 47.681671
v  42.139252 0.000000 47.681671
v  -44.036751 0.000000 -38.494034
v  42.139252 0.000000 -38.494034
# 4 vertices

vt  0.0 0.0 0
vt  2.0 0.0 0
vt  0.0 2.0 0
vt  2.0 2.0 0
# 4 texture vertices

vn  0.000000 1.000000 -0.000000
vn  0.000000 1.000000 -0.000000
vn  0.000000 1.000000 -0.000000
vn  0.000000 1.000000 -0.000000
# 4 vertex normals

g Plane01
s 1
f 3/3/3 1/1/1 2/2/2 4/4/4

g

如果用GL_REPEAT来对材质采样并渲染模型,会得到一个垂直于Y轴的平面(四个v坐标很容看出来),且对应材质会均匀的平铺四次(vt刚好是(0,1)的两倍),如下图:

2x2

对应在u3d中,只要把texture的wrap mode设为repeat就行(还有一个选项是clamp,实际对应的是GL_CLAMP_TO_EDGE)。

事实证明,0 < UV < 1这个定义永远成立只是我一厢情愿的想法罢了,在实际应用当中,UV > 1恰恰是个解决repeat问题的最佳方案。不过这个方案还是存在缺陷的——需要repeated的材质无法跟其他材质一起打成atlas了。

又涨姿势了。

END

The Good Code

回家在XP上写东西,惊喜的发现连国产软件也都开始嫌弃和逐渐放弃XP和IE了。恩,慢归慢,只要不倒车,车轮总还是向前走的。

技术总是在飞速的更新。但无论技术怎么革新、新概念如何吹嘘,一行行的源代码始终是整个软件生态系统中最重要的根基。就像猎命师靠收命格,海贼靠热血,绝地武士靠原力,写代码才是程序员安身立命之本。

写了差不多五年代码,多多少少能沉淀一点跟《Clean Code》和《Refactoring》不太一样的东西了。

一记:

read more

Functional Thinking

标题起得有点大。

说不上来到底是幸运还是不幸,总之就是年底有空超前完成了一下明年的KPI——Learning Haskell。完成度还算满意,就连传说中的monad也算是有个感性的认识了。

强推这个教程,基本上是我所有看过的教程里最良心的了。

第一次听说Functional Programming还是好几年前刚刚开始写代码营生的时候,那时的我还是初级代码搬运工,冷不丁搬运到了.Where(=>).Select(=>).ToArray()这种第一眼看不明白多看两眼又觉得好厉害的代码,瞬间就惊为天人。这好几个for都写不出来的代码,一个chain就做完了。顺手多google了一下linq的东西,也就无可避免的学到了一个新单词——Functional Programming

平凡人类认知那些first impression不错新事物,大多会经历从overestimate到underestimate的一个或多个反复。反正我对C#中的linq的认知是经历了“linq == silver bullet”和“linq == performance hit”的起伏的,现如今再看,当然是能明白具体问题具体分析才是重点,只是写过的那些代码里就不免一时都是linq又一时连using System.Linq都不见。

不过对于FP的好感一直是有,一是因为不懂,二是因为直观看来代码确实精简。这两年给自己安排的KPI都是FP相关的(去年是lisp,今年的lua相关性弱一点,之后的haskell可是自喻为pure FP呢),嗯,这叫IDL(Interest Driven Learning)。

今年眼看就要结束,总算是能沉淀一些在我看来能算作是Thinking的东西,还挺好的。

read more

Reading Lua (1) 准备工作

如果说后面几篇对lua源码的分析是干货的话,这一篇应该可以说是“废话”了。但事实上,看完了这篇,后面几篇你都不用看了。
因为这一篇跟后面几篇的关系——简单来说就是——渔和鱼。
在这一篇,我只写自己是怎样读代码的,而不提具体的代码。之所以把自己<b>了,是想要强调此处的渔是非常主观和个人化的东西,必须不适合所有人,就权当自己的经验总结和采坑大全了。

想要来一顿美味的Lua源码阅读大餐,你需要准备以下食材:

  1. 一个Visual Studio (不是说GDB不好,只是在断点的时候直接就转到上下文中函数的定义或实现,这种体验谁用谁知道)
  2. 一份原汁原味的Lua5.1.4源代码(这个版本可参考的资料最多,虽然Lua各种总的loc都不多,但简单而完备的版本看起来肯定更爽)
  3. 各种参考资料适量(云风的GC系列文章、ANoFrillsIntroToLua51VMInstructions、Mike Paul在各种地方留下的阅读指引)
  4. 足量的耐心
  5. 足量的时间

有了以上几种食材,烹饪的过程就异常简单了——F5!

没错,是他,是他,就是他:

F5

跟广为流传的MikePaul推荐的Reading Order不同的是,我觉得还是一上来就F5靠谱的多。默念函数名也是读F10也是读,running code总是比plain code更生动易懂(还有一种可能是我水平太low,大神都是可以直接通读脑中构建running state的上下文的)。当然,所谓“F5读代码大法”,并不是直接在main的第一行打上一个断点以后就不停的F10F11就行了。而是要在了解源代码大体结构(下一篇具体来写)的基础上:

  1. 确定一个feature
  2. 根据初读代码和猜测(怎么猜?靠函数名和变量名呗),在大致的位置打上断点
  3. 构造Lua代码
  4. 观察程序是不是会跑到这个断点
  5. 验证feature,整理整个流程

For example: 我想研究Lua的GC,看文章,大致Scan代码,发现GC是分好几个步骤的比如GCSsweepstringGCSsweep,那么当垃圾不包含string的时候,在一次GC里还会执行GCSsweepstring这个步骤吗?

构造lua代码如下:

local foo = {}
for i=1,1000 do
	foo[i/10] = { a = i, b = i+1 }
end

断点当然是打在lgc.c的这个位置:

	case GCSsweepstring: {
		lu_mem old = g->totalbytes;
		sweepwholelist(L, &g->strt.hash[g->sweepstrgc++]);

然后,F5走起。到断点了么?Callstack是什么样的?LuaState相关的field都是怎样的?解答自己的疑惑,再不停发问,继续解答。如此递归,就离这道大餐上桌的时间不远了。

一些PS:

  • VS中的Compile as C Code或者Command Argument怎么设置,google一下就知道
  • 宏没法打断点,实在搞不懂里面的实现就只能手动inline了,记得ctrl+z回来就好,虽然不改回来也没什么大问题
  • 接上一条,大胆的改代码做实验写注释,弄坏重新下一份源代码就好
END

Reading Lua (0)

跟去年的Learning Lisp遥相呼应,作为今年自我KPI完成的总结文来写,这次逼格高点,第一次在Blog写个series。

计划的Content Table如下:

  1. 准备工作
  2. 代码结构
  3. Lua有AST么
  4. 此VM非彼VM
  5. GC
  6. TODO

还有一些泛泛的感悟,放在这一篇抒发比较合适:

Lua的源代码写的太DIAO了!Lua的源代码写的太DIAO了!Lua的源代码写的太DIAO了!重要的事情说三遍。跟原来读了好多次都没读下去的Ruby源代码不一样,一共就50+的文件和20000W左右注释详细结构清晰的CodeBase,给人心里压力小太多了。虽然语言的复杂程度不是一个量级的,但麻雀虽小五脏俱全,Lua作为一门完美实现了设计初衷的语言,代码肯定是同样值得一读的。
Lua的实现没有任何依赖,而是用的是纯的Ansi-C!终于不用在Mac上make了,终于在Windows上也能out-of-the-box的跑起来了,对我们这种Windows低端程序员来说——太!开!心!了!
指针对我们这种低端程序员来说还是好难,虽然终究能看懂,但是花时间略久。Macro虽然写的很花哨,但我会手动inline,所以也还好。

END

Remove Vs RemoveAll

有个feature需要比较高频率的从集合中移除一部分元素,稍微脑洞了一下,感觉用for-loop+Remove应该比RemoveAll要快(可能是RemoveAll的example里用了lambda,影响了判断)。

BUT,test dont lie,写了个测试试了下:

var list = new List<int>();
for (int i = 0; i < 1000; i++)
{
    list.Add(i % 3);
}

var iter = 1000;

Profile("Remove", iter, () => 
{
    var l = list.ToList();

    for (int i = l.Count - 1; i > -1; i--)
    {
        if (l[i] == 0)
        {
            l.RemoveAt(i);
        }
    }
});

Profile("Remove All", iter, () => 
{
    var l = list.ToList();

    l.RemoveAll(item => item == 0);
});

结果RemoveAll效率要比Remove高好几倍,找了源代码扫了一下:RemoveAllO(n)且只有一次Array.ClearRemoveAt却每次都要Array.Copy(压缩空隙的操作),结果显而易见。严格来说,我是在Unity做的测试,但读的是.Net的源代码,好像有点不严谨

So,Once More:Test dont lie,Code dont lie。

END

My Tool Chain

timediff(now, lastpost).month > 6

这半年其实收获良多,各种language和各种runtime加上各种platform玩来玩去,想写的能写的值得一写也挺多,不急,慢慢来,记着就好。

念念不忘,必有回响。再拖拉我还是会写

这篇的主题是ToolChain——也可以叫——当我重装Windows/Mac时我弄些什么。

Alfred/Launchy

Alfred已经太有名了,无需多言。在windows上我能找到的(用过的)最好的替代品就是Launchy了。
实话实说,win7点了win键以后输入程序名相对xp来说已经有了很大提升了,但比起launchy这种专业的软件来说还是差了一大截。
特别是可以自定义程序搜索路径和记住最近打开的程序(e.g:我现在alt+space | c就是conemu,alt+space | ch就是chrome,alt+space | u就是unity)这两个feature,真心好用。
关于这种全局快捷键app的必要性,上古大神Alan Kay(可能记错)就说过:newbie用鼠标,frequent user用快键盘+鼠标,pro只用键盘。不用鼠标带来的效率逼格可以详询*nix over Windows党。
最后再说一个Launchy的好:donate只要2$,对比起sublime的70$(我觉得sublime也很好,但是没有好到35倍 || 如果我的工资发的不是¥而是$我就买),就是买买买啊。

Chrome

也算做过一段时间的web开发,各种浏览器出于工作也好个人喜好也罢,都用过一圈了,最后还是觉得Chrome最顺手(这类软件没有什么最好,只有最顺手)。
好像原来的原来还写过firefox plugin的post,插件这玩意也就是锦上添花,firefox现在跟Chrome比已经算不上了。
具体的有多就不表了,现在必须的只有手势这一朵了(还是稍微一提:Chrome的帐号系统确实好用,至少不用像以前的firefox一样每次重装都折腾一次插件了)。

VisualStudio/Sublime

Visual Studio出了community版本以后,Windows上最强的IDE基本就没任何争议了,随着MS越来越拥抱开源,其在社区里的口碑也越来越好了,现在我黑MS的欲望都越来越弱了。
Sublime作为Mac/Windows上都通用的Editor,对于我们这类小白开发(大神的Vi/Emacs都是比VS还厉害难用的多呢),着实是比其他文本编辑器好用了一大截。
这两个共同的优点就是1.feature多 2.插件多 3.GUI功能也很好用。诚然用鼠标的效率比不上用键盘,但鼠标悬停显示各种变量怎么也比用printpp让人愉快很多吧。

Python/Ruby/Github

Python和Ruby优先级高于其他运行时(Mac预装了)的原因在于很多小工具都是基于这两个runtime的,其他lua lisp node什么的就看心情了。关于ruby gem有个小tips:

gem sources --remove https://rubygems.org/    
gem sources -a https://ruby.taobao.org/    
gem sources -l

必须要赞一下taobao,在国内的开源界确实比其他公司走的要早要远。
Github for Windows这个GUI我觉得比tortoise还要好用,for Mac就更不用说了,Mac能战的SVN GUI根本就没有。

ConEnu

在Windows下——支持tab页+自定义font+支持ctrlc+ctrlv+最大化窗口的命令行工具——就我用过的——只此一家,所以没得选了。

What’s More

TODO

END

Learning Lisp

(MEMBER `TRY `(DO DO-NOT))

QQ签名从["do","do not"].include? "try"改成了上面的,眼看今年给自己的KPI——learning a language every year完成在即,心情大好。感觉自己编程功力又上升了一个小段位,下半年剩下的时间好好啃下SICP (看亚马逊评论说中文翻译的不太好,看来又只有原版走起了),争取能给自己打个S。

Lisp,逼格最高的编程语言之一(比他逼格更高的没人出来炫耀,比他逼格低的那就太多了)。在没TRY过之前,我觉得我肯定也是DO-NOT了。好好看了下,发现对我们这些C语系出身的程序员来说,Lisp真心可以算的上是mind-blowing了。极简的规则(上面那个quote已经包含了Lisp语法中所有最基本的元素了),一切都是list,而一切又都是执行(evaluating)。道生一,这似乎在哲学上更容易生出万物,也更有道法自然的感觉。

对lisp理解还停留在感性层面,道的出的牛逼也只有上面这些了。

Talk is cheap, show me the code。我懂,这个repo里有四个版本(Lisp Javascript Ruby C#)的代码,都只在干一件事情——计算一个多层嵌套的数组的和。先只贴Lisp的版本出来:

(DEFVAR *L* `(1 2 3 (1 (2 3))))

(DEFUN SUM-ALL (LIST)
       (COND ((ENDP LIST) 0)
             ((NUMBERP (FIRST LIST))
              		(+ (FIRST LIST) (SUM-ALL (REST LIST))))
             (T (+ (SUM-ALL (FIRST LIST)) (SUM-ALL (REST LIST))))))

(SUM-ALL *L*)

这段简单的递归能很好的体现出Lisp的表现力。平心而论,对于C#这种不支持异构数组的强类型语言来说,这对比似乎不怎么公平,因为C#版本里很大部分篇幅都用来构造数组了。而且递归这种东西好像本来就是从Lisp来的,写递归函数不就是在扬长避短么。对于你们这种怀疑我专门用特别的实例厚此薄彼的行为,我只想说,泥垢了

再次总结一下,现阶段Lisp于我来说炫酷得没朋友的特性就两点:极简的定义&&自顶向下的表现力。

PS1:入门看的是德国某大学的Common Lisp的在线教程,整个课程的设计简直是良心,还有statistic:

learn_lisp_statistic

PS2:Lisp的方言选择也是装逼活门艺术,以后就用Scheme了。我又不需要practical(我的武器库很牛逼,不要惹我),Common Lisp对我来说就太大了点。

SICP我来了。

END

Embedding Mono

前后折腾了好几天,终于把Demo跑起来了,全部的代码见这个repo,虽然行数不多,基本意思算是表达的比较清楚了(cpp里的注释都用心在写了,在我大Windows上跑起来的方法见上一篇post)。在天天用.NET的时期找了各种借口一直都没好好研究过hosting,这次用Mono做了个demo,算是把这个念想给圆了。

嗯,念念不忘,必有回响。

心得我只捡重要的,一个OL说完好了:

  1. 学好C很重要,不看Linux (实际上是看不懂),看个ruby mono什么的还是需要的。还是觉得#define什么的好难懂,想吐槽都不知道从何吐起。
  2. 对比unity的MonoBehavior,觉得我的Lib的设计更合理啊!毕竟virtual不就是干这个的吗,而且,在子类写完override就能出智能提示也要比光靠记忆去写Start()更科学啊。unity这样设计,应该是出于简单的考虑(这性能的提升可以忽略不计吧)?

  3. 在unmanaged的环境里去找method其实跟在managed环境里用反射做的事情和做的结果都挺相似的,当然,如果有很多假设(custom code的命名方式命名规则等等),就会少了很多读metadata的麻烦事儿。

  4. 设计framework/library确实比application要难得多,抽象和设计的重要性/关键性是做application比不了的。

  5. 开源就是好,你在想知道细节的时候可以去看,而不是猜。

  6. unity studio更像是photoshop而不是visual studio,没的辩。unity用mono做script engine也就是看上了它的跨平台而已,如果ruby python什么的跨平台做的足够好,可能也轮不到mono了。

做这个Demo感觉经验值涨了不少,不过还是要过两天用build on mono的形式写个一样功能的Demo,才算圆满。

END

为啥Unity3d没xx.designer.cs

winform时代,在vs的designer里拖啊拖啊,总是可以自动生成一个designer.cs,够(xiang)叼(si)的话你还能自己去改designer里的代码,运气好了vs的designer还能正常的识别,然后再继续拖拖拖。

unity3d的designer没有生成.cs,简直是,耍!流!氓!

先猜个原因再来做点实验:

前方高能预警(纯YY向)

read more

Callbacks 和(han) Promise 和 Rx*

想想还有几个月就去台湾了,心里还有点小激动呢,标题卖个萌。


回头看了一下,发现自己最近几个月对callback和async这些玩意儿出奇的关心。原因无它,各种callback和async操作实在是太反 人 类了(此处人类特指地球上某统治级灵长类生物中跟其祖先最接近的一群——程序猿,BTW,反正都扯蛋了就多扯两句:人人都知道user-friendly重要,但却没有人比微软更注重programmer-friendly,就这一点,简直要为M$点赞,以后蛋疼了一定要写一篇关于大微软爱护程序员的软文),而如何抽象这些反人类的东西,正是计算机和编程领域里最有魅力的部分。

read more

六月七日

写点啥

正好六月七号,按高考作文的套路来——总分总,记叙文,安全牌,力保上40。

总:莫忘初心,莫失匠心。

分:对不住,语文老师,我要开始散文了。

read more