代码是如何被写短再写长的

需求是这样的:

写一个函数,根据结婚的次数给出婚假的天数。如果未婚,婚假天数当然是 0 天,如果是初婚,婚假天数为 15 天,如果是再婚或第 N 次结婚(N >= 2),则婚假天数为 3 天。

工作第一年

文件: main.js

很多人可能都写过这样的代码。可以看到,这个版本的代码非常简单,基本上就是需求的直接翻译,它没有错误,甚至性能也不错。很多时候这样的代码可能在某个系统中运行很多年,但也有些时候,由于需求变更,你或你的继任者不得不对其进行重构。

工作第三年

文件: main.js

工作一段时间,了解了更多语言上的技巧后,你可能会写出这样的代码。这个时期,你相信高手的标志之一是用最少的代码解决问题,比如能用一行代码解决的问题,绝对不用两行。

这个时间段你代码看起来非常精简,有时也不乏优美之作,但也有一些为了精简而抛弃了可读性,同时损失的还有代码的可维护性。比如,如果需求突然变为再婚有 10 天婚假,第三次或更多次结婚时才是 3 天婚假,这时你需要深入到 howLongMarryHolidays 方法的实现细节中,至少需要修改两处地方才可以完成需求。

工作第十年

文件: config.js

文件: main.js

在经历了无数次需求变更以及无数次熬夜加班之后,你逐渐意识到,写最少的代码并不能让你避免加班,代码的可维护性比精简长度更重要。经过分析,你发现这个简单的需求其实分为可变的配置项基本不会变的逻辑两部分,于是,代码也被自然地分解成了两个部分,——配置与逻辑进行分离。

现在,代码量的确有所增加,但收益是逻辑更清晰了,维护时的成本及出错率也都降低了。当需要改变婚假规则时,一般只要修改 config.js 中的配置即可,并且这个修改通常来说是安全的。

小结

这只是一个简单的例子,对这个小例子而言,三种方法没有太大的差异。但如果遇到更复杂的需求,也许可以像最后一个方法那样,将易变的部分与稳定的部分隔离开来。你的代码似乎变长了,但长期来看,你的工作变少了。

涂鸦之《年会绝技》

以前年会时,经常有吹气球比赛的环节,谁最先吹爆一个气球,谁就获得奖品。那时我常想,要是有人回去后苦练吹爆气球技能,那么下一年年会上这个环节的奖品大概就非他莫属了。不过,不知从什么时候起,这个环节似乎越来越少见了,今年我们部门的年会,干脆都没有吹气球,也没有奖品了,互动环节主要就是在手机上抢红包,于是便有了下面这个漫画。

吹气球

画完之后,老婆大人说故事感觉不是太好,于是我补充了另一个:

一指禅

欢迎转载。:)

SwitchHosts! 3

2011年时写了一个切换hosts的小工具SwitchHosts!,2012年时发布了第二版,一转眼3年过去了,在2015年即将结束之时,终于抽空编写了它的第三个版本

 

Logo with title

Capture 1

我在日常开发过程中经常会用到SwitchHosts!,第二版虽然能满足大部分需求,但还是有一些不方便的地方,第三版在功能上主要有如下变化:

允许方案多选

我们日常开发过程中,有时会有很多公用的hosts希望总是生效,第二版的处理方法是提出一个单独的公共方案,但在一些复杂组合的情况下,单独的公共方案常会显得力不从心,于是,这一次索性将方案改为允许多选。自然,这样也就不再需要一个单独的公共方案了。

点击行号快速切换某一行的注释

有时我们只时临时想关闭/开启某一条hosts规则,如果单独将它作为一个方案就有点太重了,手动在行首加“#”进行注释又太麻烦,因此有了这个功能,帮助用户快速切换某一行的注释状态,从而达到关闭/开启某一行的效果。如下图:

click to comment

 

除此之外,第三版的一个很大的变化是技术上放弃了Python + wxPython的架构,采用了MacGap来构建。

之所以放弃wxPython,主要是因为这个UI框架更新比较慢,社区也相对不活跃,我遇到不少问题都无从下手,比如第二版在Retina屏下有一些问题,同时Mac版的编辑区无法使用中文输入法等。最终,我决定在新版本中采用Web技术来开发界面。

一开始,我尝试了Electron,并且做出了一个版本。但Electron生成的程序实在是太大了,无论Mac上还是Windows上都超过了100M。SwitchHosts!只是一个轻巧的小工具,虽然现在用户电脑的硬盘越来越大,但这么一个小工具要占用100M+的空间还是让我觉得不太合适,于是我转而尝试了MacGap。好处是现在的程序只有1M多点,坏处是第三版目前只适用于Mac了,Windows用户暂时只能继续使用第二版。

目前这个版本仍有不少可提升的地方,不过既然它已经是一个可用的版本,那就让我遵循MVP(minimum viable product)原则,先发布,再根据反馈进行迭代完善吧。

最后,贴一下项目主页:https://oldj.github.io/SwitchHosts/。欢迎下载试用反馈建议

HTML5塔防游戏小更新

5年前写过一个HTML5塔防游戏,写完之后,对JavaScript有了一些新的认识,也因此而结识了不少新朋友。曾经想不断完善它,打造一个正儿八经的塔防游戏出来,不过后来半途而废了。一转眼,已经有超过4年没有再更新过它。

前几天突然想起,又翻出来玩了下。以现在的目光来看,这个游戏的代码自然存在很多不好的地方,比如说多个JS模块的组织方式就极为原始,——当时AMD、CommonJS等规范才刚刚兴起,twitter等还在使用LAB.js加载模块,CMD规范尚未被提出,而我想打造一个完全不依赖第三方库的东西。不过,这些实现其实并不影响游戏的体验,最让现在的我难以忍受的是它不支持Retina屏幕,——它是基于Canvas绘制的,不是矢量图,因此在Retina屏幕上打开它时,图象会显得很模糊。

于是抽空做了4年来的第一次更新,让它在Retina屏幕上能显示得更清晰。

如何让Canvas支持Retina屏幕呢?原理其实非常简单,绘制一个2×2倍大的Canvas,再将它缩放至原始大小即可。更严谨一些的方式是先读取一下window.devicePixelRatio的值,再决定绘制时使用的放大倍数。

现在,在Retina屏幕上,这个5年前的老游戏也终于清晰了。:) 这或许是它的最后一次更新。

另外,也顺便感慨一下摩尔定律:5年前,这个游戏在初代iPad上,只能跑到大约8帧/秒,现在,同样的代码,跑在2年前的iPad 4上已经毫无延迟。

10

一个简单的JavaScript模块加载器

大型网站项目中,JavaScript 按需加载是一个常见的需求。几年前,LABjs 曾经流行过一段时间,它的主要原理是创建一个 type="text/cache"script 标签,并在需要的时候将其更改为 type="text/javascript",从而动态并行地加载 JS 并控制其执行时间。

使用 LABjs 时,被引入的 JS 几乎不需要更改,使用非常方便。但它也有不足,最大的问题是它只是一个加载器,没有模块管理功能,而后者对大型前端项目非常重要。很快,随着 CommonJSAMDCMD 等规范的流行,Require.JSSeaJS 等兼顾了 JS 文件按需加载以及模块化的加载器占据了更大的市场。LABjs 也在两三年前宣布停止开发,后来又说还会维护,只是不再添加新功能。

CommonJS 规范主要在 Node.JS 环境中使用,当然,现在也有 browserifywebpack 等工具可以让浏览器端的 JS 直接使用 CommonJS 规范。它们的原理一般是分析依赖关系,然后将所有依赖的 JS 打包为一个文件。(webpack 也可以实现动态按需加载。)

AMD、CMD 规范则是完全为浏览器端 JS 设计的。它们的设计细节不同,不过最基本的原理一样:通过类似 JSONP 的方式加载 JS 并隔离不同模块的变量。当然,在具体实现过程中还有很多问题需要考虑,比如模块依赖关系等。另外,SeaJS 等还会用正则匹配出用户在代码中直接用 require 等“关键字”加载的模块并自动加入依赖。

下面是我参考 AMD 规范实现的一个极简的 JavaScript 模块加载器(源码),去掉注释和空行差不多100行的样子。

你可以在 GitHub 上查看它的源码及示例 。需要说明的是,它只实现了 AMD 规范的一个子集,并且把 require 改为了 myloader.use,同时对循环依赖等情况也没有做处理。不过除了这些,它已经是一个可以使用并且兼容各大浏览器的 JavaScript 模块加载器了。

最后,现在流行的各种 AMD、CMD 加载器,在不久的将来也会像 LABjs 一样被人慢慢忘记,因为它们都只是为了解决某一个特定历史阶段的某一类技术问题而诞生的,随着相关技术的发展,它们也将慢慢完成历史使命,退出前端舞台。比如,基于 jspm 等项目,我们现在已经可以使用 ES6 中的模块加载方法:

一道数学题及其证明

今天在朋友圈里看到一道数学题以及一个巧妙的证明方法。

题目是这样的:是否存在两个无理实数ab,使得a^b是有理数?

那个证明非常巧妙。

答案是存在。证明如下:

考察,它是个有理数吗?有两种情况:

情况一:是有理数,这种情况下问题就被解决了:a = 554330.pngb = 554330.png就是一组解。

情况二:不是有理数,那么,就令 a = b = 554330.png。此时,ab 都是无理数,但是有 155376.png,这是一个有理数。

这个证明的漂亮之处在于我们自始至终都不知道究竟是不是有理数,但是这并不妨碍我们得到最终结果。

907565.jpg

《代码英雄传》

曾经在网上看到过一个都市武侠的故事,篇幅不长,但很有趣,讲述了一群身怀绝技的普通人在现代都市中的生活。之后我就把这个故事忘了,直到很久以后突然想起,我问自己:如果我们生活在一个武侠世界,我们的生活可能会是什么样的?于是便有了《代码英雄传》这个故事。

故事不长,两万字左右,一般阅读速度约一小时能读完。内容纯属虚构,不过也有一些现实中的影子,比如故事中的三大诸侯分别以现实中的BAT三巨头为原型(当然,仅仅是原型,没有黑哪家的企图 ^_^)。

这是一个普通的武侠故事,当然,如果你了解一些编程,同时还对目前国内主要互联网公司有一定了解,或许会从中发现更多的笑(槽)点。

最后,地址如下:

1、简书地址

2、GitHub地址

3、PDF版下载地址

希望你喜欢这个故事,也欢迎吐槽指正。:)

涂鸦之老婆大人

2014 12 25 00 40 02

2014年基本上一整年都在加班,很多原本想做的事都没有做,博客也几近荒废了,临近岁末,回首这一年,却似乎没有特别值得记下的东西。如果说今年有什么要特别感谢的,那就是老婆大人,在我加班的时候,默默地打理好家里大大小小的事,在背后给予我坚实的支持。

2014年,准备说再见!

查IP归属地的Chrome插件

日常学习和工作中,我经常需要查询某个IP地址的归属地,每次都打开查询网站比较费事,于是便做了一个Chrome插件,你可以使用Chrome浏览器访问这儿安装。使用很简单,如下面图片所示:

Search by right click

可以在页面上选中一个IP,然后在右键菜单中选择查询,也可以点击浏览器插件栏图标,在弹出菜单中查询。

Search by popup window

IP来源自第三方,目前使用了IP138QQ IPIP.cn的服务,将来可能会有所调整。

插件的代码是开源的,见https://github.com/oldj/SearchIP。欢迎fork一起完善。