《Dive Into JavaScript》Session3之脚本与样式

No Comments

赶紧把第三次的session ppt发上来,本以为每个月讲两期,结果变成平均一个月一次了。。。让人心灰意冷啊。

这次讲的脚本与样式主要是介绍了样式在HTML文档中的存在形式,比如说样式对象CSSStyleSheet,规则对象CSSRule,还有我们经常接触的CSSStyleDeclaration对象,还有如何使用JavaScript对其进行访问和控制,其中当然要介绍大家经常使用的element.style属性。

显而易见,session的目的就是为了让大家能更加了解我们经常使用的样式赋值和取值的怎么回事,也能对像jQuery这样的库进行猜想其内部是怎么实现的,比如说使用频率很高的$(selector).css({…}) 方法。另外,由于大家对这些类库产生了依赖,很少专注于其实现,但是如果当使用库发现问题时,往往需要从基础的东西里面寻找答案,比如说在先测试的时候,css方法返回的样式在各个浏览器中也是不一样的,它并没有进行结果的同意merge,只是做了简单封装,而且它也没有必要做merge,错误是浏览器造成的,考虑过多的包容错误会使得开发人员自己很苦恼,但是对于一个前端工程师来说,我们应该知道它是怎么产生的。

PPT的地址在这里:http://winsonwq.github.com/ppt/JavaScript-Session3-Style-Script.html#/cover ,你也可以通过短地址访问http://bit.ly/diveintojavascript3访问,短连接同时支持前面两讲,改下最后的数字即可。

这次session内容不多,但是呢还是把大家给讲lost了,一句话,口才问题,Zation同志也给了feedback说我需要换一下讲的方式,据他观察我在讲的过程中,我讲话的间断性让大家乏味了,讲半句,停,继续讲。。。口长确实确实需要加强,我session前想的一些套路,或者说为了让大家更加有兴趣的语言在session过程里面都表现的不很好,这个应该归结于演讲技巧里面的,是时候找点书来琢磨琢磨了。

《Dive Into JavaScript》 Session 2之BOM和DOM简介

No Comments

上周五,我给大家分享了《Dive Into JavaScript》 之BOM和DOM简介。PPT传送门在http://winsonwq.github.com/ppt/JavaScript-Session2-DOM-BOM.html

– 搞了2个月了,才是第二讲,太掉链子了。

讲的过程中,有积极问问题的,有补充讲解的,有可能是完全lost了离场的,有犯困的,有闷闷的不吭声的,形形色色的童鞋都有,最后还包括讲着讲着发现PPT内容不合理的我。

关于Progressive Enhancement的思考

2 Comments

Progressive Enhancement(下文称为PE),渐进式增强是现在web开发中一个很流行的开发思想,目的是在以内容为核心的同时,可以渐进地提升体验,为用户提供更好的服务,随之而来的好处是,其网站或者web程序的最核心内容并没有改变,用户接受到的信息是完整的,而且能达到浏览器兼容的目的,这里提到的兼容并不是说网站的体验必须是一样的,这里的兼容指的是提供给用户的内容和功能是完整的,甚至在不兼容CSS和JS的浏览器上内容和功能也是完好的。

这里是两个比较好的了解PE的资源,《Understanding Progressive Enhancement》Nicholas Zakas: Progressive Enhancement 2.0(需要翻墙)。

最能体现PE思想的还是这个图:

渐进增强

说到这可能有人会问,为什么体验不一样也算兼容呢?那么我会反问你,谁说的一定要在每个浏览器上一模一样才算是兼容呢?我们的目标是尽可能的保持一样的体验。

以内容为核心,在保证内容的基础上,添加样式添加行为是最基础的开发思路,在其之上还会有更多的样式+行为添加上,增强开关是我用来控制增强的一种方式,我利用它可以控制应该针对那些浏览器或者哪些内容进行增强。对于PE,我有这样的思考。

现在的PE模型已经变成了这个样子了:

├─Level 4 ─ ...
├─Level 3 ─ JavaScript
├─Level 2 ─ CSS
├─Level 1 ─ JavaScript + CSS
└─ Basic  ─ Content

首先,所有问题的解决需要建立在持续性的沟通和改进上。

问题1:对于网站来说是谁来决定核心内容文字可能来自于BA和产品经理,进一步想,那么一个web程序,带有更强用户交互的网站功能的核心内容是什么呢?,比如UX会给于最终的界面效果,往往会是一个CSS+JS的混合体,而被掩盖的最基本的功能应该是我们思考的。

这是每一个UI开发都考虑的问题,我们开发一个功能是以功能效果作为导向呢还是以内容作为导向,如果是前者那么往往会忽略基本的HTML文档结构,语义,虽然效果是完成了,但是可扩展性变差了,当遇到体验变化时,需要推到从来,整个功能失效直到你的新体验完成,浏览器兼容性会变得很麻烦,因为有可能要hack很多浏览器已保证体验一样。而后者就不一样,在考虑内容的同时,HTML文档的结构简单,语义健全,而且还能保证基础功能是具备的,满足各种浏览器的基础功能,兼容性也是随之而来的,不必特意去考虑跨平台,因为出发点已经跨平台了,但是开发者首次需要做更多的effort不但要保持原有功能前后台功能,也要保证增强后的前后台功能以及增强的开关控制。

我们往往都会选择后者,什么是一个功能的核心内容,比如一个查询功能来说,不论其最终效果有多么绚丽多彩,那么开发者应该保持一个纯净的心灵,把它归结为一次form的get请求,查询的选项需要根据具体的查询内容而定具有语义的标签,比如是文字那么就选择input,甚至还可以选择type是search的input,如果是二者选择一那么选择下拉框select或者radio,如果是开关那么可以选择checkbox,这些都是最基本的元素,form提交那么可以选择submit按钮,而且能自动带上回车提交的功能。在最基础的get请求完成之后,再来考虑加上样式,我们的输入是否需要autocomplete,checkbox需不需要做成iphone样式等等才是正确的道路。

问题2:随着渐进增强的开发,体验甚至会形成一个从下到上的链式结构,那么如果最底层的内容改变的时候应该怎么处理建立在其上的所有增强呢?

当最初的基础内容改变的时候,怎么处理之后的所有增强呢,我想说这种情况是比较糟糕的一种,有点像需求改变了的重构。我还在寻找这个问题的答案,我能想到的是应该加强对每个增强的条件,每个增强的位置和条件,如果能知道这两个点,这个问题也迎刃而解,而且还能很好的控制增强的开关。除了这点,还需要加强对增强的测试,因为测试是保证重构的基本要素,也是程序功能质量的见证。最近遇到一个内容改变的需求,需求很简单,就是在新的页面显示中不需要看到没页面的title了,它是一个h2标签。我看到这个需求时候第一个想要问的这个title是不是核心内容一部分,我觉得是,但是需求是需要看不到它,我只好隐藏它,但是又没有新的体验去替代或者增强它,那它还属于核心内容的一部分么,我应该问谁,问BA和产品经理,他们要的是最终效果,就是看不到,我说可以让阅读器看到所以应该把它隐藏,和同事的讨论中,他们觉得既然没有替代品的话,说明已经不属于核心内容一部分了。最终,我很是纠结,不情愿的直接删除了。看到这个问题,我觉得我才刚上路呢,理解PE才是皮毛。

问题3:在增强过程中,选择适合的增强方式也是一个问题

选择适合的增强方式,我的原则是优先用CSS解决这个问题,然后在考虑JS解决,但是有趣的是,这里有了动态添加具有更多功能的CSS和JS的问题,针对不同的增强开关动态的加载样式和行为,而且要保证相互不影响,对于动态加载JS可以考虑使用AMD加载。另外,增强往往隐藏一些之前有的view,所以隐藏应该属于增强的一部分,在移除增强后原有view应该显示。动态加载js行为可能会引入更多的view,这些新的界面会有新的css,首先所有东西都应该是动态加载上的,然后view的DOM结构可以使用现在有的模板技术来处理,如果是简单的dom结构的话,也可以用DOM API生成。像jQuery UI/jQuery Mobile就是这样做的。

问题4:由于功能是渐进增强上去的,那么测试需要cover的点就会变多,被增强的部分可能增强后功能是好的但不见得增强之前的功能也是好的,即使增强前的版本没有人用到。这些多余的effort是值得做的么?

这个问题可以分两个部分,一个是我们发现PE对我们用处不大,反而带来了更多的effort,还值得不值得这么做,我的答案是应该要这么做,PE的好处不是局部的,而是随着项目的变大,长时间的坚持才能看到的,它在跨平台上给我们带来的好处是显而易见的,因为我们没有那么刻意的去追求它,它就是个附属品。另外PE以内容为核心,可以让我们的焦点永远都集中在应该给用户提供的内容上,内容才是业务的重中之重。第二个部分是关于我们需要花很大的effort来用测试保证增强前和增强后的功能么,我的想法是对于我们现在支持的所有功能,包括增强前后的功能,但是会有侧重,如果80%人都可以使用上chrome这样的浏览器,那么我们会加大最增强后的测试,它是用户使用驱动的。而我们可以花一部分精力去测试那些我们能想到的功能,但是不是主要功能,比如说阅读器、搜索引擎加载等等,我想这也是卓越软件追求的一个方面吧。

啰嗦说了很多我的想法,也表示我对PE也在学习研究中,还没有总结出来一套方法论。现在项目里面也要加强PE的引入,随时随地都要敏感的想到PE理论,最近还在看《Designing with Progressive Enhancement》,里面提到了很多各种增强的方法应该会帮到我。

感谢在工作中和我耐心讨论的同事们。

-完-

调用expressjs中compiler方法的问题

3 Comments

express.compiler方法是expressjs框架提供的一个动态编译源文件到目标文件的方法,每次GET请求相同名字的目标文件时,会去查找同名源文件来生成,这样对于整合sass、less、coffeescript十分有用。但昨天在整合sass到expressjs时候,发现了个配置sass的路径的问题。该方法调用方式如下:

app.use(express.compiler({
    enable : ['sass'],
    src : sourceUrl,
    dest : destinationUrl
}));

compiler方法接受3个参数,enable的编译器数组,src代表源文件路径,这里代表sass文件的路径,最后一个dest指的是目标路径,就是生成为css文件的路径。

现在我的项目结构如下:

myapp
├── app.js
├── public
│   └── stylesheets
│       └── main.css
├── sass
│   └── main.sass 
└── ...

想把myapp目录下的sass文件夹中的所有sass文件能动态的生成到public/stylesheets文件夹下,本以为看把compiler调用时的src路径设置为__dirname + ‘/sass’,然后dest的值设置为__dirname + ‘/public/stylesheets’ 便可以了,这是多么理想的状态啊。

// 理想情况,但是不work
app.use(express.compiler({
    enable : ['sass'],
    src : __dirname + '/sass',
    dest : __dirname + '/public/stylesheets'
}));

结果不行,换不同的路径试了很多次,有些时候能生成,还去stackoverflow上查询了很久,结果都没有想要的答案。我便看了下compiler方法的源码,原来生成原理是这样的。

每次GET请求一个文件的时候,例如http://localhost:3000/stylesheets/main.css时,此方法会生成两个路径,源文件路径和目标文件路径,根据代码来看,会根据当前的url来找到pathname,追加到调用方法时指定的src和dest的值上,此时找到的pathname就是/stylesheets/main.css,那么源文件路径就会是我指定的__dirname + ‘/sass/stylesheets/main.sass’,目标路径就成为__dirname + ‘/public/stylesheets/stylesheets/main.css’,很明显两个路径都错误了。怪就怪它是用pathname去追加,而不是只用/main.css追加。

现在搞清楚状况了,无奈的事情发生了,如果我真想在code里面使用http://localhost:3000/stylesheets/main.css这样的路径去请求css文件,那么原路径中需要包含stylesheets这个子文件夹。通过我有想过把它的方法修改了,但是它是个get方法,不能被修改。唯有委曲求全了。

现在把文件目录改成了:

myapp
├── app.js
├── public
│   ├── stylesheets
│   │   └── main.css
│   └── scripts
│       └── main.js
├── stylesheets // 不得已把sass变为stylesheets
│   └── main.sass 
└── scripts
    └── main.coffee

调用方式变成了:

// work,但是src和dest看上去都是很奇怪的配置
app.use(express.compiler({
    enable : ['sass'],
    src : __dirname,
    dest : __dirname + '/public'
}));

同样的方式也可以来配置coffeescript。虽然现在可以加载到目标文件,但是看起来不是那么舒服,还是有些遗憾,如果大家看了之后有其他更好的加载方式可以告诉我。Btw,如果你不想使用原生的compiler方法去生成css文件,那么你可以尝试下Stylus Middleware 貌似没有这个问题。

忙碌的一星期

11 Comments

上个星期主要就是两个活动,OOBC和TWI,前者是Programming培训,后者是TW针对社招的培训。

先来谈下OOBC吧,是个跨两个星期的training,大概六天,主要是pair利用TDD方式写程序,这次主要是包括头两天的长度计算程序和之后的停车场管理程序。每天都会有新需求,每个小需求给个15分钟的时间来实现,几乎每次都需要重构现有代码,目标是不break测试的前提下来重构。用大神@徐昊的话来说,手法是其中至关重要的,我们用的IDE是IntelliJ,对快捷键的掌握的同时,更重要的是重构思路,每当看到大神在重构时候,都会有膜拜的眼神,所以@Gavin,OOBC这个培训务必积极参加。当然,这个方面我还很欠缺,在这里还要对我的pair说声抱歉,我速度还真是有点慢。

OOBC这个星期的上课事件是周二到周四,其中两天和TWI有交集,TWI周三培训到周五,白天早上9点培训到下午5点左右,晚上又去参加OOBC,却是感觉到有些忙,OOBC布置的重构作业也只能做一半。一般来说,回到住的地方应该是9点半以后了,然后周四晚上和成都base的同事们去唱了K,周五晚上我们TEAM的release庆祝,也就是昨天,去了周董开的依然范特西KTV,耍到了11点半,那是相当的high了。

这是KTV包厢里面的微博墙,由于强哥明天要去澳洲出差,我发了条祝福。

TWI培训的三天内,主要包含了TW的历史、Agile内容、OP和PS的角色和责任、迭代计划、用户故事、XP极限编程、自动化测试。以上内容都是围绕着TW日常工作中的内容展开,效果可见一斑。

其中我感觉比较深的是TW的历史,在TW19年的历史中,有着辉煌的一面,比如selenium等的开源自动化测试工具的贡献(别的有点忘了,汗)。一直在使用行业内最先进的技术,比如第一个ROR的商业系统就是TW开发的,当然,还有敏捷软件开发的提出,敏捷宣言的制定都是由TW主导的,这还是比较振奋人心的。补充下,之前的Spring的IOC控制反转为什么之后会改名叫做DI呢,因为Martin Fowler觉得IOC是个很烂的名字,DI依赖注入更贴切,接着这个行业都用了新的称呼,可见当时TW和老马在行业内的影响力。

当时也有让人担心的一面,TW现在还欠外债4300万刀,关于这比债务,差点让TW关门,不过最高法院的判决让我们松了一口气,也让TW的所有员工真正能理解TW的价值观是什么,大概内容是“ThoughtWorks公司是由一群被叫做ThoughtWorker的人组成,整个公司最大的价值也是这群有志向的人,其公司本身并没有更大价值如果这群人走了的话”。

尤其现在这个行业竞争愈演愈烈,TW面对技术选择周期也变得越来越短,创新能力显得格外重要,面对的对手越来越多,我们必须要更加努力才能继续保持在行业的前列。敏捷开发的咨询工作是TW在中国的一个大方向,我们希望把这种新型的,好的开发思想传播出去,共同来为软件业做贡献。

还有一个有趣的故事,当初TW有个规定,就是每当你离开自己的笔记本电脑时,都需要锁屏,但是有一次一个COO忘记了锁屏,另外两个员工就把他的电脑密码改了,并提醒他离开时需要锁屏。当那位高高在上的COO发现之后,一怒之下把这两个人开除了,但是有趣的是,这位COO在第二天就被公司开了,并且把之前两个人请了回来,成为了两位TW史上最有面子的两位员工。COO被开,也体现了公司的价值取向,我们没有那么严格的上下级,我们员工之间重要的是合作关系。

我的记录比较零碎,现在想到的是公司的三大支柱。1、sustaining business(可持续的业务) 2、software excellence(追求软件卓越) 3、social justice(社会正义,但是主要指为社会做贡献)

TWI的三天培训非常有用,很多都是通过游戏的分组讨论的方式进行,感同身受,体会比较深。其中敏捷宣言学习、乐高怪兽模拟项目、你来画我来猜古诗词(我的古文水平太烂了)、分布式项目管理、retro的各种方式都是很有意思的。让我和TW之间又更近一步。BTW,来培训的各种讲师都是自愿来分享的,谢谢他们的付出,希望有一天我能参与到讲师行列中。除了这种理解之外,这次是首次和OP的人一起进行TWI培训,也然我更多的了解到了OP人们的工作内容,怎么样和我们配合的,能更多的相互理解。

好吧,就记录到这吧,附上我们的乐高怪兽和它的baby。哈哈。

还有那cosplay的雷锋照《那些年看过的测试驱动开发》

《Dive Into JavaScript》Session 1

No Comments

《Dive Into JavaScript》Session系列是我组织的一个JavaScript技术分享讨论会,属于我和给力的前端开发@Zation组织的前端分享平台的一部分,这个平台主旨是想把前端开发知识传播给更多人知道,希望有更多人加入前端开发来和我们一起探讨问题,追求最佳实践。

今天是第一次分享,ppt传送门在此,http://winsonwq.github.com/ppt/JavaScript-Session1.html#/cover。本来想按照语言介绍流程,先讲语法,接着讲下结构,比如if/else,switch,for/while怎么写之类的。讲这些有意思么?没有。在我看来,很多人都对JavaScript中prototype-based部分理解的不够深刻,甚至完全摸不着头脑,那我们今天就啃这块硬骨头,这样对之后的课程理解也有很大帮助。

在session,我的目的是让大家回答这么两个问题

  1. Object.prototype上扩展的属性和方法,为什么所有对象上都能感知到?
  2. Function.prototype上扩张的属性和方法,为什么只有方法对象能感知到?
    例如:Function.prototype.isAFunc = true; Array.isAFunc === true; // true

这次讲的主要内容:

  1. JavaScript/ECMAScript 简介
  2. JavaScript 对象Function, Object
  3. 三个重要属性介绍,constructor、prototype、__proto__
  4. 对象关系(包括方法对象)

有可能是直接第一次分享就讲较为复杂的部分,大家听下来都有点晕。但我觉得,晕了才能有不晕的一天,而且这次直接讲原型继承真是我用心良苦啊,希望大家在之后的讨论中能更快的理解。也非常欢迎大家给我feedback,期待中。(已经收到一些,下次会改进)

下次讨论将会在下下个星期,那天还不定,《Dive Into JavaScript》Session 2的内容可能是对象API的介绍、类式继承的介绍、随之而来的将会是BOM、DOM的介绍。之后还会有更多的惊喜,只愿给我一个平台我分享我所学。

上次会成都,徐昊(TW中国首席咨询师)问了我一个问题,你现在是UI开发,如果有一天,假如3年,大家自学或者受你影响,他们的UI水平和你差不多了,你会怎么办?我想了想,回答说,我希望有那么一天,他们来帮我一起做现在做的事情,提高效率的同时,我可以有更多的时间专研我想学的东西。

-完-

Mr.Async PPT 和两个例子

5 Comments

做了几个试验品,是丑是美也要拿出来溜溜,我准备先给小组内的几个人做个session,内容就是介绍Mr.Async.js对于异步问题的处理方式,大概就是传承老赵的Jecex的意志。我分两个阶段介绍Mr.Async.js,第一次就是介绍,并没有包含技术实现,如果效果好的话,再做技术实现的分析。

介绍的PPT我已经完成了,花了两天时间,很注重细节,用的是impress.js,因为我正在做一个方便大家使用impress.js的一个页面工具。可以在这里访问到:Why not using Async in this way ?。技术细节的PPT可能会在此文件上继续修改,不过内容只会很浅,我觉得一个PPT上没有必要讲得非常细,还不如花时间更新使用文档,因为我都还没有更新github上的README,关于解释器的部分。呃。。。

PPT主要围绕什么是异步,结构上有什么缺陷,我们希望的代码方式是什么,Mr.Async.js的组成部分等等来讲述的。内容通过两个小例子来组织,第一个例子是带有动画的冒泡排序问题,第二个是老赵提到的当鼠标点击时输出下一个Fibonacci数字。通过这两个例子的传统写法和使用Mr.Async.js的写法说明异步方式是可以更加优雅得实现的。既然更好,为何不使用呢?:)

另外,在写例子的时候,无意间还发现了个bug,只能在Firefox上重现,测试用例也加上了,这下大家满意了吧。

两个例子的Mr.Async.js的实现可以在以下地址访问到:冒泡排序Fibonacci数列

2012-02-03

2 Comments

才与材

2 Comments

过了年了,长途跋涉又回到了西安,回成都遥遥无期,只有等待。

刚进TW,感觉很多东西要学,要饱读古今中外,各个行业的书籍才能平静下紧张的情绪,一听就是个N年才能做到的事情。说紧张并不表示无能,而是觉得怀才不遇,因等待发挥的机会而焦急,担心未懂的东西太多但项目里又要求快速上手而心慌。总不能一天吃成胖子,我每天都这么安慰自己。这一个月来,一直有个坚定的想法,就是成与不成就在于此公司了。

最近Mr上没有什么更新,都在搞iPhone上WebApp开发去了,前段时间和Diouf谈论的我要改动Mr.Async都还没有来得及改,改了虽然未必能用上,有个结束总归是个好事。

同事看我们Team在做WebApp但没用jQuery Mobile,就调侃说我要做一套WebApp的库,能做出来大小小于10K就佩服我什么什么的,搞得我都有点想让他佩服我一下了,不过一切都需要时间。

我猜测很多知道我的blog的人肯定刷新过而发现没有更新,其中大多都是我的好朋友,这段时间让大家失望了,以后会尽快更新,多多分享我的所见所闻。

Mr.Async中$await支持switch、property赋值

3 Comments

Mr.Async更新支持在switch,和property赋值语句中的$await等待语句,而且目前来说不打算支持try-catch-finally,因为还没有找到比较好的实现方式,麻烦如果哪位大虾知道怎样捕获异步异常的方式或者模型,多多赐教。

switch的case中使用

var i = 0, ret;
switch(i){
    case 0 :
        console.log('waiting for 1 second.');
        $await(delay());
        ret = 1;
        console.log('done.');
    default :
        console.log('waiting for 1 second.');
        $await(delay());
        ret = 2;
        console.log('done');
        break;
    case 1 :
        console.log('waiting for 1 second.');
        $await(delay());
        ret = 3;
        console.log('done');
        break;
}
console.log(ret);
 
// output
// waiting for 1 second.
// done.
// waiting for 1 second.
// done.
// 2

我挑选了switch testcase中一个特殊的例子,default块在中间,第一个case没有break并且匹配到变量i的值0。虽然在每个case里面都含有等待的$await,但是最终的console.log输出是在switch块执行完成之后才输出了,并且得到正确的值。

property(属性方式)赋值

之前只实现了var a = $await(delay()); 和 var a; a = $await(delay());方式的$await赋值语句,现在就支持属性赋值。如下:

var obj = { inner : {} };
// 等待delay操作,返回值为1
obj.inner.a = $await(delay());
console.log(obj.inner.a);
 
// output
// 1

以上加上的新功能都已经更新了testcase,可能还不足够,bug常常有,让它来得更加猛烈些吧。Mr.Async托管地址:https://github.com/winsonwq/Mr.Async

NEXT

下一步打算着手于基于NodeJS的AOT编译器,一步一步来。

Older Entries