Cheney Jin
Reading makes a full man, conference makes a ready man, and writing makes an exact man
2012年8月15日
为什么我不认可Xmind之类的脑图软件?
2012年6月21日
分类信息源
- 需要思考消化的信息 —— 不需要思考消化的信息
- 内容质量高的信息 —— 内容质量不高的信息
# 还有一些其他纬度,比如历史信息(按时间线分类),亲友信息(按地区或亲友的远近分类),领域分类(体育、文化、专业技能、学术等),但这些都不是最重要的纬度。
信息是否需要思考消化,需要多大程度的思考消化,对于阅读者当前的心态预期是有决定性影响的。我们很难在阅读了3条快餐信息后立即调整状态阅读一条需要深入思考消化的信息,这会让人的很多身体本能出现混乱状态(切身体会,没有理论依据)。 每人每天的可用时间很不固定,所以整理出信息质量的高低由高往低阅读非常必要。但是,这里更准确的做法应该是一种排序而非分类,没有谁理应被分为高中低三档之一,你只能根据当前现状大致给予一个在其众兄弟中的排位,这个排位是允许随时变换的,这样在改变其顺位的决策中能够比分类处理减少相当可观的心理负担。这一点在《Rework》中有过提示,有兴趣可以继续深入思考其在GTD中的应用。
以前整理过数次GReader的RSS源,每次都尝试了当时自认为更切合实际的分类方式。但实际使用下来效果总是不满意。原因于我一直没有把思考消化的纬度放至最重要的位置。处理方式是先使用领域分类,再经由思考消化分类,于是最后的内容质量分类经常有心无力虎头蛇尾,而且也不便于阅读。
另外,需要思考消化的信息在GReader越来越狭小的阅读空间中已经不合时宜,90%的情况我会打开原地址阅读,除了视野能更开阔以外也能消除GReader中分类栏的信息干扰。所以我决定把它们的阅读体验分离出GReader,经过试用比较后我选择了pocket这款产品,首先它的客户端非常完备,支持iPad、iPhone、android、android Pad;其二,它的阅读体验绝对处于上乘,与Instapaper不相上下;其三它的发送渠道也非常完备,通过一个简单的配置,即可以快速保存GReader的item。在非常封闭的iOS Safari中,它也能通过快速发送邮件的方式保存网页,非常细心贴心。
具体实施:
- 所有信息来源依然在GReader中管理,但是首先会把倾向于需要思考消化的信息源分至一个文件夹,名叫ThinkIn。ThinkIn文件夹的信息源不需要领域分类(因为每条item的阅读周期都比较长,没有信息之间连贯穿插的需求),只需要处理内容质量的排序。预期5分钟之内消化的信息直接阅读,其他的信息根据当日时间状况从上到下保存至pocket。在任意时间地点设备中消化完成pocket的内容。无法消化的打上await标签。
- 倾向于快餐新闻的信息源放置在Info文件夹,因为完全不需要思考,所以也不做领域分类,仅做内容质量排序。
- 剩余的信息源再使用领域分类分至4-5个文件夹,内部同样做内容质量排序。提供给自己某一领域信息的深入挖掘。通常来说比较少打开这里的信息,可以根据自身时间、心态和工作状况弹性调整。
- 放弃GReader的标签、加星功能,减少负担。需要Archive的内容全部存档至Onenote。+1功能偶尔使用在特别优秀的item上。
2012年3月6日
工程化前端开发
首先必须感谢这么多伟大的开源项目:
Alice、Sass、Bootstrap、sass-twitter-bootstrap-rails、YUI Compressor 它们共同构成了我的zic-css。
seajs、UglifyJS、jQuery、backbone、coffeescript、mustache、Underscore.js、es5-shim、Closure Compiler 它们共同构成了我的zic-js。
关于zic-css: sass是实现工程化的基础,我真的太爱这个玩意儿了,变量、Mixin可以被复写即可以保证所有在继承链顶端的第三方代码可以不被修改地快速更新版本,比如sass-twitter-bootstrap-rails出了新版本,直接拷贝过来即可,并不会影响当前网站设定的所有颜色,图片路径等规则,另外要特意提一下Alice的样式库解决方案和样式库构建模板,都是对技术很好的沉淀。
关于zic-js: 实现工程化的关键在于seajs,是淘宝前端玉伯的成果,这是一个令人非常欣喜的项目,虽然至今还有很多不成熟(主要是在文档方面),但它给我所带来的javascript架构模式上的改变已经足够令人钦佩。我知道国外也有一些相对成熟的模块化开发框架,如RequireJS,但经过比较后我非常清晰的感觉到seajs才是我想要的,它遵循了kiss原则的轨迹。另外一个不得不提的是coffee-script,其扎实的成果已经打动了很多人,当然也包括我,这是建议所以javascript码农都必学的一门语言。关于js的压缩,UglifyJS因为非常精彩的设计得到了很高的性能,适合在开发阶段经常编译检测的需求,而Closure Compiler拥有最好的压缩比和配置能力,所以是最终部署时的不二选择。
最后不得不提的是Git,最近才开始使用它的子模块功能,然后发现一切都是那么顺手,我的两个前端项目可以作为任何web项目的子模块,从而及时更新或被更新或合并代码。不需要像最初使用seajs模块库那样经常痛苦地手动合并各处的更新。
2012年2月29日
google tasks
- 永远展开list分类列表
- 增加detial页面的textarea框大小,并且可自定义伸缩(默认被锁死)
- 在detial页面按‘q’键可以返回list
- 双击list中的item标题即可以进入其detial页面。
2012年2月5日
幸福
- 不存在纯正的“真理”,普世理解的“真理”只是人类追求的能够自我解释的一套感知,它可以是完全虚幻的。
- 科学是为了“方便”,方便理解运用改进这套感知。
- 活着的意义就是幸福 —— 自己、他人以及整个社会的幸福。
- 幸福是对美的体验。
- 三个需求层次:1生存,2自我完善、财富自由,3体验并创造美。
- 幸福和需求密切相关。如果生存需求得不到满足,就不可能长期拥有幸福感。自我完善和财富自由很大程度上是为了让自己有资本去体验未曾体验过的新的美,为第三层服务。
- 生存需求、以及对自我完善和财富自由需要优良的“活法”观念支持,否则会步履蹒跚,比如诚实、谦虚、积极主动等。
- 各种宗教都在宣扬一种活法。
- 除了个人内心的欲求,需求还不得不受外在环境的影响。房子、车子、孩子可能并非你的初始欲求,但在社会环境影响下,实实在在改变了你对需求的定义。能不受影响的人少之又少,而且会伤害到身边受此影响的人。(这里与原文稍有不同)
- 面对外在环境,保持顺流而活的心态,可以让幸福来得更容易。保留自己对他人无害的特色,但不要追求过于惹人厌的特别。(这里与原文有差异,我认为一定程度内的特立独行有易于实现第二层需求。)
- 想拥有幸福,就需要好好地去思考如何管理自己的需求。让需求真真切切地贴近自己的内心,大胆地剔除掉一切虚妄的欲求,比如攀比欲求,以及抢劫、淫邪、控制他人等最终无法得到美的欲求。(这里与原文的“有悖当下社会普适道德的欲求”也有差异,有悖普世不一定得不到你需要的美)
- 美可以在“真”的追求中,美可以在“善”的行动中,美可以在“爱”的情感中。只要你会体验,它无所不在。活得不幸福。不是因为没有幸福,而是因为幸福如空气,风起来时,我们能感受到凉爽,云淡风清时,我们却经常忽略了自己的呼吸。
2011年7月11日
值得称赞的Sass
很早就想尝试这个HAML团队的杰作,放在todo-list里一直做冷板凳,最近手头时间比较宽松终于能拿出来了。
用了半天时间,把当前手上一个项目的css全部转换为scss(是个较大的项目,估计有上2千行),可见其转换过程并不痛苦,我自己感觉也是比较顺畅的,这彻底打消了我在less和scss间做选择的纠结。
语法很简单,看完Tutorial就没问题了,Documentation 基本上都不用看。
相比较而言,前段时间尝试的coffescript给我的感觉过于嚣张啦~~
在好多没必要的地方过份包装,不符合我最看重的kissy原则(只做最需要去做的事情),完全把javascript扔到了脑后,让使用者找不到写js的感觉了,可能是作者太喜欢ruby了吧。
我觉得coffescript应该秉承一条核心使命,它并需要把js来一个彻底的华丽转身,因为js社区的基础已经非常雄厚,很多人的相关编码经验没必要抛弃。coffescript的使命应该只有一条最简单的:减少javascript的代码行数!
从今年开始,node.js社区的发力,seajs的出世,coffescript、sass项目的成熟标志着前端开发在这一年进入了新的加速期。如果这些好项目都今后能够健康发展,未来我们可以称今年为二次元年吗?
最后,放一个我用scss实现的一个kissy框架双飞翼布局中的代码生成功能。以前生成双飞翼布局的代码都要跑这个页面去,非常不coder,现在用scss即能够亲松实现代码生成:
/*#region Grids */
body{text-align:center;}
.wapper{margin:0 auto;width:960px;position:relative;text-align:left;}
.col-main {float: left;width: 100%; min-height: 1px;}
.col-sub, .col-extra {float: left;}
.layout:after, .main-wrap:after, .col-sub:after, .col-extra:after {content: '\20';display: block;height: 0;clear: both;}
.layout, .main-wrap, .col-sub, .col-extra {zoom: 1;}
@mixin grid-sxm0($scol) {
.main-wrap { margin-left: $scol*40px; }
.col-sub { width: $scol*40 - 10px; margin-left: -100%; }
}
.grid-s4m0{@include grid-sxm0(4);}
.grid-s5m0{@include grid-sxm0(5);}
.grid-s6m0{@include grid-sxm0(6);}
.grid-s7m0{@include grid-sxm0(7);}
@mixin grid-m0sx($scol) {
.main-wrap { margin-right: $scol*40px; }
.col-sub { width: $scol*40 - 10px; margin-left: $scol*40 - 10px; }
}
.grid-m0s6{@include grid-m0sx(6);}
.grid-m0s7{@include grid-m0sx(7);}
.grid-m0s8{@include grid-m0sx(8);}
.grid-m0s9{@include grid-m0sx(9);}
.grid-m0s10{@include grid-m0sx(10);}
@mixin grid-exm0sx($ecol, $scol) {
.main-wrap { margin: 0 $scol*40 0 $ecol*40; }
.col-sub { width: $scol*40 - 10px; margin-left: -($scol*40 - 10px); }
.col-extra { width: $ecol*40 - 10px; margin-left: -100%; }
}
.grid-e6m0s5{@include grid-exm0sx(6,5);}
@mixin grid-m0sxx($xx) {
.main-wrap { margin-right: $xx + 10px; }
.col-sub { width: $xx; margin-left: -$xx; }
}
.grid-m0s220{@include grid-m0sxx(220);}
/*#endregion Grids */
2011年6月30日
《狗镇》:我们是如何走到今日的?
公元前399年,哲学家苏格拉底被判死刑。死于全体雅典公民之手,雅典公民民主投票的结果是:280:221。
当年的古希腊是号称民主的起源地,通俗的讲就是纯粹的民主,纯粹的人民意志。
很好听的词儿是吧?其实这里还有个完全相等的词儿:人民暴政。
即等于纯粹的民主。
随着时代的发展与变迁,特别是经历了法国大革命的洗礼,人们终于逐渐学会了,民主是需要控制的(想学学如何控制?推荐这篇贱文:民主共和宪政和黑手党政治),并且越小的集体越容易出现民主暴政,简单的讲就是多数人欺负少数人。如果只有三个人投票,1.8米以上身高的人多争收100%的个税,那三人中另外两个1.8米以下的人会放过这个议案吗?
在人数少的时候,负面道德压力变得更小,而正面道德压力永远都是差不多大,因为,那几乎只是你一个人的内心。
《狗镇》这部电影用最为纯粹、血淋淋的故事,警告了我们一定要看清人性。
其实,当年的鲁迅真的洞悉人性,,,只不过太多的中国人读鲁迅的书只当吃了碗泡面,还自夸自己吃过中国最牛的泡面。
人性之恶已经让我们无数个伟大的思想家,艺术家,政治家吃了鳖。千万别说什么死后被平反之类的事儿。
《狗镇》就像一片刺眼的烈日,虽然说不出的难受,但是,它确实照亮了我们身前身后的道路,虽然这两道风景都是鲜血淋漓。
所有对这个世界抱着天真幻想的人都应该去看看,接受它的洗礼。
那些教会过我们什么叫做恨的人,让我们终于摆脱了愚蠢的傲慢和瞎眼的善良。它让我们知道自己是如何活下来,又将如何活下去。
PS:民主与共和的相互劫持坐庄是目前人类所能探索到的最平整的前进道路……
2011年5月5日
read jquery.js
抽空读了读jquery代码,确实颇有收获。首先放上整体代码结构:
(function (window, undefined) {
var document = window.document;
var jQuery = (function() {
var jQuery = function( selector, context ) {
return new jQuery.fn.init( selector, context, rootjQuery );
};
jQuery.fn = jQuery.prototype = {
constructor: jQuery,
init: function (selector, context, rootjQuery) {
// ...
if (selector.nodeType) {
this.context = this[0] = selector;
this.length = 1;
return this;
}
// ...
},
// ...
};
jQuery.fn.init.prototype = jQuery.fn;
jQuery.extend = jQuery.fn.extend = function() {
// ...
};
jQuery.extend({
noConflict:function(){},
Ready:function(){},
// ...
});
// ...
return jQuery;
})();
jQuery.extend({
});
// ...
window.jQuery = window.$ = jQuery
})(window);
首先为何会有两层(function…)()自执行函数的疑问我觉得应该解释为为了更好的模块化开发,在github中有模块化的源码
看过《javasctipt权威指南》应该能更好的理解new语法到底为何物,也就自然能理解为何在jquery中new $()与执行$()结果一模一样
重点:
jQuery.prototype
=== jQuery.fn
=== jQuery.fn.init.prototype
逻辑上此处有矛盾,fn与fn.init.prototype形成了循环包含,但这也正体现了js为值对象语言的特征,一切皆为值拷贝(jQuery.fn.init.prototype = jQuery.fn)
PS:$.extend使用深度copy突破了值拷贝障碍,下节分析,目前$.extend的可读性并不好,充斥着魔鬼数字。
jquery.fn的成员:
- init - 初始化
- constructor - 手动指定构造函数,因为默认是 jQuery.fn.init
- length - 让这个对象更接近一个原生的数组
- size - 返回 length
- toArray - 通过 Array.prototype slice 实现生成数组
- get - 即 this[ num ] 参数索引的处理。
- pushStack - 加入一个元素
- ready – DOM文档加载后执行
- end - 返回保存的 prevObject 对象
- each - 循环执行
平常的 $("#id") 就是 new jQuery.fn.init("#id");
init函数中,返回值this附加上context、length等参数后再附带上jQuery.fn.init.prototype(即jQuery.fn)返回给调用者
以下为init函数注释代码:
init: function( selector, context, rootjQuery ) {
// 参数: selector 选择器
// context 上下文
// rootjQuery 父节点
// 处理 $("")、 $(null) 和 $(undefined)
if ( !selector ) {
return this;
}
// 处理 $(DOMElement)
if ( selector.nodeType ) {
// 直接扔数组中, 就搞定了。
this.context = this[0] = selector;
this.length = 1;
return this;
}
// 处理 $("body") body 元素只存在一次,单独找它
if ( selector === "body" && !context && document.body ) {
// 同样扔数组中, 顺便把 selector 更新更新。
this.context = document;
this[0] = document.body;
this.selector = "body";
this.length = 1;
return this;
}
// 处理 $(HTML 代码 或者是 css 选择器)
if ( typeof selector === "string" ) {
match = quickExpr.exec( selector );
// 检查是否正确匹配
if ( match && (match[1] || !context) ) {
// 处理: $(html) -> $(array)
if ( match[1] ) {
// 获取正文,默认 document
context = context instanceof jQuery ? context[0] : context;
doc = (context ? context.ownerDocument || context : document);
// 如果传入简单的 "<标签>", ( /^<(\w+)\s*\/?>(?:<\/\1>)?$/)
ret = rsingleTag.exec( selector );
// 返回 createElement("tag")
return jQuery.merge( this, selector );
// 处理: $("#id")
} else {
elem = document.getElementById( match[2] );
// 因为有的浏览器 getElementById 不只返回 id匹配的,所以做检查。
return this;
}
// 处理 $("标签")
} else if ( !context && !rnonword.test( selector ) ) {
this.selector = selector;
this.context = document;
selector = document.getElementsByTagName( selector );
return jQuery.merge( this, selector );
//处理: $(选择器, $(...))
} else if ( !context || context.jquery ) {
return (context || rootjQuery).find( selector );
// 处理: $(选择器, 上下文)
// (相当于: $(上下文).find(选择器)
} else {
return this.constructor( context ).find( selector );
}
} else if ( jQuery.isFunction( selector ) ) {
//如果是函数,则执行$(document).ready,这样$(document).ready(func)简为$(func)
return rootjQuery.ready( selector );
}
// 略。
// 如果传入的是一个 Dom列表 ( getElementsByTagName 结果 ) 则转为 jQuery 数组。
return jQuery.makeArray( selector, this );
}
$.extend({
mm: function () { alert('mm'); }
});
$.mm();
$.fn.mm = function () {
alert(this.text());
}
$.fn.extend({
mm: function () { alert(this.text()); }
});
$('h2').mm();
2与3方案一模一样,1与3方案为同一个extend函数,1方案执行宿主会被extend自动判断为不带context的$对象
var opts = $.extend({
val: false
}, options);
返回俩参数合并后的对象,后者覆盖前者 // 可见extend函数有多复杂
贴一下$.extend函数代码:
jQuery.extend = jQuery.fn.extend = function() {
var target = arguments[0] || {}, // 第一个参数是目标
i = 1, length = arguments.length, deep = false, options;
if (target.constructor == Boolean) {// 第一个参数是bool型的
deep = target;// 深度copy
target = arguments[1] || {};// target指向第二个参数
i = 2;
}
// target 是string 型的或?
if (typeof target != "object" && typeof target != "function")
target = {};
if (length == i) {// 只有一个参数?或deep copy 时,两个参数
target = this;// 目标为this
--i;
}
for (;i < length; i++)
if ((options = arguments[i]) != null)
for (var name in options) {
var src = target[name], copy = options[name];
if (target === copy)// 防止死循环
continue;
// 深度copy处理,最深为元素
if (deep && copy && typeof copy == "object" && !copy.nodeType)
target[name] = jQuery.extend(deep, src
|| (copy.length != null ? [] : {}), copy);
else if (copy !== undefined)// 直接copy
target[name] = copy;
}
return target;
};
extend不但支持深度clone,还能支持多个参数的对象clone到一个指定对象,而不是jquery中。
2011年4月28日
构建前端MVC,seajs,underscore.js,backbone.js 等琐碎的其他
这两天完成了前端MVC的完整构建demo,算是一个小里程碑吧。
-
backbone.js确实是好东西,但还有些别扭的约定,比如el对象的不可控造成设定el的特殊属性比较麻烦。但一切皆权衡,没有完美,总体而言是非常优秀的架构。
-
模块管理引用了还在pre期间的seajs,非常cool,几乎是我一直以来梦寐以求的架构。相信能借此规避掉很多很多不必要的麻烦。
-
今天看了完整的underscore.js源码,代码质量相当高。在backbone.js模型中M层个C层都不应该使用jquery,只有在V层才需要它。但js在工具型类库方法上的薄弱还是会很让人头痛,underscore.js是js最好的“tux”,而绝不应该是jquery。
-
压缩引擎使用closure-compiler,并且使用了IKVM项目在.NET环境中执行,这样可以自动化部署在TFS的team building环节中。
-
CssGaga功能很强,非常强,但工具的易用性有待加强,至今提交的一个无解bug依然没有回复,不过相信我最终会用好它的,因为它实在太“可爱”了。
2011年3月20日
小结,重整旗鼓
最近比较烦,但我不想责怪任何人,也确实没有理由责怪任何人,还是自己不够,,,那叫什么来着?,,,成熟?
去他娘的。
大概在一年多前,我开始习惯写日记,不是那种写在博客上的“日记”,是写在OneNote中给只自己看还犯贱加了个密码的日记,每天至少一句话(也基本上只有一两句),每周末还会总结一下把觉得写的不错的打个标签方便翻阅。
曾经我以为我的这个做法很成功,人最重要的高级特征之一就是自审嘛。但是现在我发现这很扯蛋,或者说强迫自己自审很扯蛋,自审很可能只能是由内而生的。
我觉得,人之所以活着必须是为了在追求某些东西,这些东西说好听了叫梦想,往俗里面说就是欲望,,,人烦的时候,无非就是感觉自己完全不在追求这些东西的路上,而是被其他乱七八糟的原因牵制住,并且一时间看不到改变现状的可能性。
所以呢,烦就烦吧,因为我也清楚,这只是一时间看不到改变现状的可能性而已,肯定不是永远。太多太多次了,回首以前,一件件大事儿都变成了小事儿,小事儿都成了屁事儿。
PS:就在今天, 我已经下定决心改变了现状。