2011年12月4日

IE兼容性bug汇总

Filed under: 未分类 — cmpan @ 2011-12-04 19:20:08

项目最新版本的开发进入后期阶段,今天鼓起勇气打开IE Test,如我所料啊!页面在IE6下面目全非了,呜呜~~

现在开始修复IE的Bug(大部分是IE6,IE7 8也有一些),顺便记录下来。

1、png图片在IE6下出现透明或背景变灰的bug;

分析: 随处可见,遇到时就想好策略。

解决方法:1、使用滤镜,语法如下

.image-style { background-image: none;

filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=”filename.png”, sizingMethod=”scale”);

}

注意:使用滤镜需要性能损耗。

2、给IE6单独制作一张.gif图片,打上hack

.image-style{ background:transparent url(“filename.png”) no-repeat scroll 0 0;

_background-image:url(“filename.gif”);

}

这种方法只需要在切图时多存储一份.gif格式的图片,一般采用这种方法。

2、position:absolute定位在IE6下存在left和bottom相对最外层视窗(body)定位的bug:

分析: 由于在IE6下,相对定位的元素没有获得IE内部的haslayout属性,因此不创建新的定位上下文,所以绝对定位的元素相对于视口进行定位。

解决方法:1、设置height:1%;//小的高度不会对实际高度找出影响

2、相对定位的祖先元素设置过高度和宽度。

3、相对定位的祖先元素设置_zoom:1,用于触发元素的layout属性。

3、IE6下border不显示的bug

分析:对一个div定义border,但是却不显示。

解决方法:定义宽度;定义高度;清除浮动。

4、在 W3C 规范中 position 是可以使用在任何元素上的,但table元素的 position:relative 却有例外:

1
2
<strong>The effect of ‘position:relative’ on table-row-group, table-header-group, table-footer-group, table-row, table-column-group, table-column, table-cell, </strong>
<strong>and table-caption elements is undefined. </strong>

分析:经测试,在浏览器(IE 除外)中给 table 定义 position:relative 属性是无效的。如果的确需要在表格中使用该属性,建议在单元格中嵌套一个 div 元素,再在其上设置 position:relative 属性来模拟。

5、IE6下overflow:hidden失效bug

分析:在开发中经常使用overflow:hidden来清除浮动,也就是在浮动元素的父元素中使用这个属性,就相当于添加了一个clear元素。但是,这在IE6下不给力。

解决方法:只要在父元素中给定一个宽度就可解决这个bug;

6、IE6下的双空白边浮动bug

分析:这是一个常见的出名BUG,给IE6下的浮动元素定义margin-left或者margin-right,实际上是数值的两倍。

解决方法:把这个浮动元素设置为display:inline;

7、IE6下float元素如果没有定义宽度,在浮动时它会自动占满一行的bug

分析:即使对这个浮动元素内部的元素设置了宽度,也是无效的

解决方法:一般用于布局的浮动元素不会要求横向可自由拓展的,那么可以通过设置宽度来解决这个bug.

8、IE6下img元素底部留白的bug

分析:代码结构如下

<div>

<img src=”filename” alt=”图片” />

</div>

解决方法:把代码结构改成如下:

<div><img src=”filename” alt=”图片” /></div>

并设置img元素的display:block(img元素默认是一个display:inline的元素)

9、IE6 7下的浮动元素的父元素在拖动滚动条时出现的边框缺失bug

解决方法:设置zoom,使元素获得布局。

10、 IE(6 7 8) 的 z-index bug

分析:看代码

xhtml:
<div id=”container”>
<div id=”box1″>这个box应该在上面</div>
</div>
<div id=”box2″>
这个box应该在下面,IE浏览器会对定位元素产生一个新的stacking
context ,甚至当元素 z-index的为“auto”。
</div>
css:
container { position: relative; }
#box1 { position: absolute; top: 100px; left: 210px; width: 200px; height: 200px; background-color: yellow; z-index: 20; }
#box2 { position: absolute; top: 50px; left: 160px; width: 200px; height: 200px; background-color: green; z-index: 10; }

结果:ff/chrome显示为box1在box2上,而IE确实box2显示在了box1上

原因:IE浏览器会对定位的元素产生一个新的stacking context,并且从z-index:0开始

11、关于IE8的一些资料

12、IE6下的重复字符bug

分析:如下图所示

出现这个BUG的“机遇“其实并不大,要满足以下一个或者多个条件:

1.父元素的内部有多个浮动元素。

2. 最后一个浮动元素前有隐藏元素:包括html注释和display:none的元素

3.子元素的宽度和父元素相同,父元素的宽度减去子元素宽度小于3px

最终得出的结论是:溢出文字的字数=注释的条数 *2-1

这个变态BUG的最早文献是出现在2004年,这里可见

解决方法:

1.把浮动的子元素加上display:inline;属性(推荐)

2.去掉注释和所有隐藏元素(缺点:特殊情况下不一定可以删除)

3. 把浮动的子元素加上margin-right:-3px;属性(缺点:要加IE6的hack,也算是好方法)

4.在隐藏的DIV外嵌套一个DIV(缺点:增加的结果复杂性)

详解:http://www.cnblogs.com/javashi/archive/2010/05/08/1730504.html

13、IE6下的空div bug

分析:通常在实现可拓展的圆角框时,习惯在头尾使用两个空元素来放置背景图片如<div></div>,但是这个空元素在IE6下会莫名的产生一个高度,为原先定义的2倍。代码如下:

1
1
&lt;
1
div
1
class
1
=
1
"hd"
1
&gt;&lt;/
1
div
1
&gt;&lt;
1
br
1
&gt;&lt;
1
div
1
class
1
=
1
"bd"
1
&gt;content&lt;/
1
div
1
&gt;&lt;
1
br
1
&gt;&lt;
1
div
1
class
1
=
1
"ft"
1
&gt;&lt;/
1
div
1
&gt;&lt;
1
br
1
&gt;样式:&lt;
1
br
1
&gt; .hd{background:url("filename") transparent ...; height:5px;}

解决方法:为这个空元素设定line-height:0;font-size:1px;即可解决这个bug。

14、IE6下对position:fixed不支持的bug

分析:问题的原因是IE6下的fixed元素绝对定位位置是针对html元素的,而滚动条则是针对body元素的

解决方法:

body{background-image:(“xx.gif”);}/*一张不存在的图片*/
.fixed{_postion:absolute;expression(eval(document.documentElement.scrollTop+document.documentElement.clientHeight- this.offsetHeight))}//底部 

expression(eval(document.documentElement.scrollTop));/*头部*/
expression(eval(document.documentElement.clientHeight/2+document.documentElement.scrollTop-80));/*右侧*/

15、IE6下input/textarea/select元素继承父元素的水平margin的bug

分析:http://haslayout.net/css/Form-Control-Double-Margin-Bug

解决方法:这个bug在开发中是经常遇到的,解决方法就是在input或者textarea元素上使用负的margin,使元素重新布局。

16、IE6不支持min-height/max-height/min-width/max-width的bug

分析:无

解决方法:根据IE6的特性模拟出来

height:auto!important;
min-height: x px;/*需要的最小高度*/
height: x px

17、IE6下position:relative的bug

分析:在IE6下父层(或者上层)设置为position:relative且没有写宽度,而这个元素又被一个带有滚动条overflow:auto/scroll属性包含的时候,它将会表现出absulute,并且在鼠标移上去时,会在整个屏幕上滑动;

解决方法:找到了bug的原因后,事情就变得简单了,方法有两种

1、把父层(或者更上层)的relative删掉,但有时候这个relative是必须的,那就只能用第二种方法了;

2、不删除relative,但给这个元素设定一个宽度,可以是100%。

18、IE6下样式不表现

分析:通常一个页面需要载入2-3个样式文件,但其中有某个样式文件里的样式完全不表现,你或许怀疑这个文件没有被加载,这个时候打开IE Debug看文件的传输情况,很清晰的看到文件正常加载了,纳闷吧!后来找到了

原因,主要有两个:

1、这个文件的编码和页面定义的character编码不一致;

2、不正确的注释(这个也有可能是页面编码不正确,而注释是中文导致的)

解决方法:检查页面编码;去掉注释;

19、IE6浮动元素与非浮动元素间隔的3pxbug

分析:在IE下,一个浮动元素与一个非浮动元素相邻时候,中间会莫名的出现一个3px的间隔。

解决方法:1、由于明确知道是3px,所以可以使用负的margin,但是由于IE下不同的盒模式,又会导致宽度上的不同,浮动元素的宽度如果超出了父元素的宽度在IE下是会有bug的,所以不建议使用这种方法。

2、不让浮动元素和非浮动元素相邻,或者把非浮动元素也设置为浮动元素。

20、IE6下img元素底部出现5px的空白间隙bug

分析:

代码结构如下:

<li><a href=”#”><img src=”xxx.png” alt=”xxx”/></a></li>

在ie6下会出现5px的空白。

解决方法:

1、
ul li{display:block;font-size:0;}
img{vertical-align:bottom;}
2、img{_margin-bottom:-5px;}

21、IE下透明度无效bug

分析:在IE的所有版本中,父元素设置了透明度,而子元素如果有position:relative/absolute时,子元素无法继承父元素的透明度。

找了一些资料:http://younglab.blog.51cto.com/416652/431363

解决方法:除了资料中使用的方法(触发layout),还有个土方法,那就是在透明度比较小的区域中,使用具有透明度的图片和字体模糊。

22、IE下overflow:auto/scroll不起作用的bug

分析:在IE下overflow不起作用,但是在火狐下是正常显示的,IE下overflow如同虚设,内容是表现出来了,但是确实在区域的下面显示,滚动条也无法使用。

解决方法:对设置了overflow的元素设定高度和宽度(一般使用滚动条的都会设置这些属性),然后给这个元素进行position定位,relative或者absolute都是可以的

23、IE6 7 8下元素重叠bug

分析:页面操作过程中对一组li元素做remove()或者hide()时,被移除的li的下一个兄弟元素会往下偏移,从而发生元素重叠。

解决方法:js中对这个li元素的父元素加上toggleClass(“ie-hack”);//ie-hack为不存在的class。
原因不明。

24、IE6/7/8下直接对input输入框使用背景图片,当输入值冲出背景图片宽度时,背景图片会随字符滑动

解决方法:在input框外加一个div,在这个div上设置背景

25、去掉a链接难看外框的方法:

IE下设置hideFocus=true,其他浏览器设置:outline:none

<a href=”…” hideFocus=”true” title=”..”/>
a{
outline:none
}
还有一种是用expression的方法,但是耗性能,原因是每秒钟执行了很多次。不推荐是用
a{
blr:expression(this.onFocus=this.blue())
}

未完待续。。

转自:http://www.cnblogs.com/svage/archive/2011/02/12/1952704.html

2011年11月29日

使用HTML5开发安卓应用入门

Filed under: 未分类 — cmpan @ 2011-11-29 00:55:03

开发工具安装包下载及安装
1、Eclipse Classic
下载Eclipse Classic版解压 http://www.eclipse.org/downloads/
下载并安装Android SDK http://developer.android.com/sdk/index.html
下载Android Eclipse插件 ADT http://developer.android.com/sdk/eclipse-adt.html
下载HTML5转手机应用构建工具phonegap http://phonegap.com/download-thankyou

安装eclipse插件小插曲:
拜于天朝的超级局域网,我2M宽带安装插件时速度一直不能达到10K,让我得以挑战人类忍耐的极限。还好用vps做代理后有50K左右的速度,人品好的时候还能到200K+,终于安装上了adt插件。

phonegap官方入门教程:http://phonegap.com/start#android

问题及解决:
解决–emulator.exe 遇到问题需要关闭。把C:\Documents and Settings\Administrator\.android\目录删除,重新创建svd。
phonegap 的ajax不存在跨域问题。

2011年11月27日

IE下类似firebug的调试工具DebugBar

Filed under: 未分类 — cmpan @ 2011-11-27 04:59:34

下载地址:http://www.debugbar.com/download.php
该网站还提供ie下使用的仿firebug-lite的CompanionJS:http://www.my-debugbar.com/wiki/CompanionJS/HomePage
比较有名的IETester也是该站出品:http://www.my-debugbar.com/wiki/IETester/HomePage

解决ie下JS提示“尚未实现 ”错误

Filed under: CSS » JS — cmpan @ 2011-11-27 04:43:48

鼠标经过链接的时候,总提示JS 1行、第xx个字符,错误信息是:“尚未实现 ”。从js入手调试了半天,解决不了问题。想到是不是css里的expression引起的,把链入的样式去掉,果真是。css的expression调用了ie不支持的方法引起js错误提示。IE这SB只知道第1行、第xx个字符出错了,不可信。

2011年11月16日

敏捷测试的方法和实践

Filed under: 开发方法 » 敏捷 — cmpan @ 2011-11-16 02:50:37

有一次,当开发人员完成当前Sprint 任务的代码之后,测试人员与开发人员、产品经理一起来浏览产品、从头到尾走一边,产品经理发现了问题,认为需要对功能进行比较大的修改。这时开发人员估计 需要两天时间才能完成代码,但测试人员反对这样做,我们本来只有5天测试时间,加上这次新做的功能比较多、开发代码质量不高,验收测试已经很紧张。如果再 延迟两天,测试没法完成。产品经理说,你们不是在用敏捷测试方法,应该测得很快,三天应该能完成测试工作啊!

什么是敏捷测试呢?敏捷测试当然不能简单地理解测得更快,绝对不是比以前用更少时间进行测试,也不是将测试的范围缩小了或将质量降低来减少测试任务。也有人说,只有敏捷开发,没有敏捷测试。

1.下面我们就要讨论一下

1.1究竟什么是敏捷测试?

2.2敏捷测试有哪些流程改进?

3.3测试人员如何面对敏捷测试的挑战?

4.4在敏捷测试中如何制定相应的自动化测试策略?

等等各种问题。 1. 什么是敏捷测试 假如将过去传统的测试流程和方法硬塞入敏捷开发流程中,测试工作可能会事倍功半,测试人员可能会天天加班,而不能发挥应用的作用。敏捷测试应该是适应敏捷 方法而采用的新的测试流程、方法和实践,对传统的测试流程有所剪裁,有所不同的侧重,例如减少测试计划、测试用例设计等工作的比重,增加与产品设计人员、 开发人员的交流和协作。在敏捷测试流程中,参与单元测试,关注持续迭代的新功能,针对这些新功能进行足够的验收测试,而对原有功能的回归测试则依赖于自动 化测试。由于敏捷方法中迭代周期短,测试人员尽早开始测试,包括及时对需求、开发设计的评审,更重要的是能够及时、持续的对软件产品质量进行反馈。简单地 说,敏捷测试就是持续地对软件质量问题进行及时地反馈,如图1所示。


2. 敏捷测试流程的优化
在敏捷方法中,需求变化比较快、产品开发周期很短,我们目前采用四周时间,也就是每个月发布一个新版本。开发周期短,功能不断累加,给软件测试带来很大 的挑战,软件测试流程要做相应的调整。例如,我们原有的测试规范明确规定,首先要建立项目的主测试计划书,然后再建立每个功能任务的测试计划书,测试计划 书有严格的模板,而且需要和产品经理、开发人员讨论,并和测试团队其他人员(包括测试经理)讨论,最终得到大家的认可和签字才能通过,仅测试计划经过“起 草、评审和签发”一个完整的周期就需要一个月。在敏捷方法中,不再要求写几十页的测试计划书,而是在每个迭代周期,写出一页纸的测试计划,将测试要点(包 括策略、特定方法、重点范围等)列出来就可以了。

在原有测试规范中,要求先用Excel写出测试用例,然后进行讨论、评审,评审通过以 后再导入测试用例库(在线管理系统)中。在敏捷测试中,可能不需要测试用例,而是针对use case 或user story直接进行验证,并进行探索性测试。而节约出来的时间,用于开发原有功能的自动化测试脚本,为回归测试服务。自动化测试脚本将代替测试用例,成为 软件组织的财富。原有测试规范还要求进行两轮回归测试,在敏捷测试中,只能进行一轮回归测试。综合这些考虑,敏捷测试的流程简单有效,如下图2所示。

在敏捷测试流程中,如前所述,测试是一个持续的质量反馈过程,测试中发现的问题及时反馈给产品经理和开发人员,而且某些关键方面也要得到我们足够的关注,主要有:
l 测试人员不仅要全程参与需求、产品功能设计等讨论,而且要面对面地、充分地讨论(包括带语言、视频的即时通讯),仅仅通过邮件是不够的。

参与代码复审(code review),并适当辅助开发人员进行单元测试。

在流程中增加一个环节“产品走查(Product work-through)”——测试人员和产品经理、开发人员等在一起,从头到尾将新功能看一遍,可直观、快速地发现问题。

3. 新功能的测试和回归测试策略
测试任务简单地可分为新功能测试和回归测试。在敏捷方法中,针对这两部分的测试建立相应的策略,以提高测试的效率,最大限度地降低质量风险。新功能测试的策略主要有:

不需要测试用例,直接基于用例、基于对需求的理解来完成新功能的验证。即使要写测试用例,只要保证各个功能点被覆盖,不要过于详细(大颗粒度)。持续地进 行验证,一旦某块新代码完成(code drop), 就开始验证,而不是等到所有代码完成后才开始测试。这也包括参与到单元测试和集成测试中。实施端到端(end-to-end)的测试,确保完整的业务流程 的实现,同时,也容易发现业务逻辑不够清晰、不够合理等各方面的问题。阅读代码来发现问题,可以和开发人员工作保持同步,消除测试周期的压力。基于经验, 可以实施更多的探索性测试、组合交互性(interoperation)测试和用户场景(user scenario)测试,更有效地发现埋藏较深的缺陷。

回归测试是敏捷测试中需要面对的难点。每次迭代都会增加新的功能,一个产品可能会经过十几次、甚至几十次迭代,回归测试范围在不断增大,而每次迭代周期没 变,可能还是一个月。这样验收测试的时间非常有限,所以回归测试很大程度上依赖于自动化测试,因为很难将回归测试控制在非常有限的范围内。当然,还是有些 办法可以帮助我们减少回归测试的范围,例如:

通过执行code diff来了解代码变动的所有地方,再做代码关联分析,就可以明确知道要进行哪些地方的回归测试,回归测试范围会大大缩小。基于风险和操作面分析来减少回 归测试的范围,例如回归测试只是保证主要功能点没有问题,而忽视一些细节的问题。持续测试的过程,只要有时间,就进行测试,包括开发人员、产品设计人员都 参与到日常的试用和测试中来

4 自动化测试策略
由于开发周期短,需求、设计等方面沟通也需要花费很多时间,没有足够时间开发自动化测试脚本,至少对新功能的测试很难实现自动化测试。这时候,就需要正确 的策略来提高自动化测试的效益,如图30-3所示,并说明如下

图3 自动化测试的策略

4.1构建一个灵活的、开放的自动化测试框架,如基于关键字驱动的自动化框架,使测试脚本的开发简单易行,脚本维护也方便。

4.2针对稳定的产品特性开发自动化测试脚本,也就是针对前期完成的已有功能开发自动化测试的脚本,而大部分新功能测试采用手工测试。

4.3集中精力在单元层次上实现自动化测试,主要由开发人员实施,测试人员提供单元测试框架,并辅助完成一些所需的基础工作。

4.4在产品设计、编程时就很好地考虑了自动化测试的需求,使全面的、自动化的底层测试、接口测试成为可能,尽量避免用户界面(UI)的自动化测试。

4.5良好的IT基础设施,包括自动化构建软件包、自动化版本验证(BVT)、自动化部署、覆盖率自动产生等。

5 敏捷测试工具
自动化测试依赖于测试工具,所幸的是,目前已有很多敏捷测试工具。由于篇幅所限,这里只是简单地列出一些常用的敏捷测试工具,不再深入讨论了。

5.1 单元测试工具:TestNG、xUnit家族(如JUnit 、NUnit)、JMock、BizMock等。

5.2 功能测试自动化:ThoughtWorks Twist。

5.3 Web功能测试(frontend):Selenium IDE/RC、WatiR、WatiN。

5.4 Web service测试工具(backend):soapUI 。

5.5 性能测试:JMeter+BadBoy。

5.6 验收测试框架:Fitnesse、Tellurium。

5.7 敏捷测试过程管理工具:微软的Visual Studio 2010,包括TFS 2010、Scrum模板(MS VS Scrum 1.0)、Test Manager 2010、Coded UI Test等。

5.8 业务智能(BI)应用的测试框架:Oraylis BI.Quality (+ NUnit)。

5.9 其它一些协作工具等,如TestLink、BugZilla、BugFree、wiki、ant等。

6 测试人员在敏捷方法中的价值
在敏捷方法中,开发人员的主导作用更明显,系统设计、编程实现、单元测试、重构等看似关键的一些任务都落在开发人员身上,测试人员容易被边缘化。那么,在敏捷方法中,测试人员的价值又如何体现呢?

6.1 在需求和功能设计讨论上,测试人员可以站在客户角度上来阐述自己的观点,扮演“用户代表”角色,强调用户体验,真正体现测试人员和开发人员的互补作用。

6.2测试人员不仅扮演“用户代表”角色,而且通过需求讨论、代码复审等各种活动及时地提供质量反馈,包括代码质量、接口一致性等,保证在产品构造的整个过程中质量受到足够的关注,以提高质量改进的持续性和可视性。

6.3 测试人员应积极参与单元测试,即使不参加单元测试,也应督促开发人员进行单元测,确保单元测试达到80%以上覆盖率,确保开发出具有良好可测试性的代码。

6.4在敏捷方法中,往往将一个大的系统开发分解成多个小的子系统(模块或组件),集成测试和端到端(end-to-end)测试显得更为重要,测试人员在这些测试上能发挥更大的作用。

6.5 产品发布前,验收测试和回归测试依然不可缺少,这更是测试人员的用武之地。

6.6 一个迭代周期结束后,对缺陷根本原因进行分析、总结规律,帮助开发人员建立良好的习惯,预防缺陷,从根本上提高产品质量。

理想情况下,测试人员掌握设计模式、具有很好的编程能力,可以和开发人员进行角色互换,如在当前版本开发(/迭代周期)中担任测试人员角色,在下一个版本 开发(/迭代周期)中则担任开发人员角色。这样双方对不同角色的工作有着更深刻的认识,消除沟通的障碍,开发的效率和质量会有进一步的提高。

小结
根据上面的讨论和我们的实践,最后针对敏捷测试进行一个简单的总结,就是:
l 敏捷测试就是持续测试、持续反馈,扮演“用户代表”角色,确保产品满足客户的需求。

敏捷功能测试 = 新特性的手工测试 (use case验证和探索性测试) + 原有功能的自动化测试 (回归测试)

敏捷测试人员和开发人员的区别越来越小,理想情况下,敏捷方法中,测试人员和开发人员在不同的迭代周期可以互换。

敏捷测试流程依据不同的团队特点、不同产品的特点而不同,因地制宜,适合才是最好。

2011年11月12日

软件架构模式的种类

Filed under: 架构 — cmpan @ 2011-11-12 09:40:07

在做软件架构设计时,根据不同的抽象层次可分为三种不同层次的模式:架构模式(Architectural Pattern)、设计模式(Design Pattern)、代码模式(Coding Pattern)。

架构模式是一个系统的高层次策略,涉及到大尺度的组件以及整体性质和力学。架构模式的好坏可以影响到总体布局和框架性结构。

设计模式是中等尺度的结构策略。这些中等尺度的结构实现了一些大尺度组件的行为和它们之间的关系。模式的好坏不会影响到系统的总体布局和总体框架。设计模式定义出子系统或组件的微观结构。

代码模式(或成例)是特定的范例和与特定语言有关的编程技巧。代码模式的好坏会影响到一个中等尺度组件的内部、外部的结构或行为的底层细节,但不会影响到一个部件或子系统的中等尺度的结构,更不会影响到系统的总体布局和大尺度框架。

架构模式(Architectural Pattern)

一个架构模式描述软件系统里的基本的结构组织或纲要。架构模式提供一些事先定义好的子系统,指定它们的责任,并给出把它们组织在一起的法则和指南。称之为系统模式。

•MVC模式,一个架构模式常常可以分解成很多个设计模式的联合使用。MVC模式常常包括调停者(Mediator)模式、策略(Strategy)模式、合成(Composite)模式、观察者(Observer)模式等。

•Layers(分层)模式,有时也称Tiers模式

•Blackboard(黑板)模式

•Broker(中介)模式

•Distributed Process(分散过程)模式

•Microkernel(微核)模式

架构模式常常划分成如下的几种:

一、 模块结构(From Mud to Structure)型。帮助架构师将系统合理划分,避免形成一个对象的海洋。包括Layers(分层)模式、Blackboard(黑板)模式、Pipes/Filters(管道/过滤器)模式等。

二、分散系统(Distributed Systems)型。为分散式系统提供完整的架构设计,包括像Broker(中介)模式等。

三、人机互动(Interactive Systems)型,支持包含有人机互动介面的系统的架构设计,例子包括MVC(Model-View-Controller)模式、PAC(Presentation-Abstraction-Control)模式等。

四、Adaptable Systems型,支持应用系统适应技术的变化、软件功能需求的变化。如Reflection(反射)模式、Microkernel(微核)模式等。

设计模式(Design Pattern)

一个设计模式提供一种提炼子系统或软件系统中的组件的,或者它们之间的关系的纲要设计。设计模式描述普遍存在的在相互通讯的组件中重复出现的结构,这种结构解决在一定的背景中的具有一般性的设计问题。

设计模式常常划分成不同的种类,常见的种类有:

创建型设计模式,如工厂方法(Factory Method)模式、抽象工厂(Abstract Factory)模式、原型(Prototype)模式、单例(Singleton)模式,建造(Builder)模式等

结构型设计模式,如合成(Composite)模式、装饰(Decorator)模式、代理(Proxy)模式、享元(Flyweight)模式、门面(Facade)模式、桥梁(Bridge)模式等

行为型模式,如模版方法(Template Method)模式、观察者(Observer)模式、迭代子(Iterator)模式、责任链(Chain of Responsibility)模式、备忘录(Memento)模式、命令(Command)模式、状态(State)模式、访问者(Visitor)模式等等。

以上是三种经典类型,实际上还有很多其他的类型,比如Fundamental型、Partition型,Relation型等等。设计模式在特定的编程语言中实现的时候,常常会用到代码模式。比如单例(Singleton)模式的实现常常涉及到双检锁(Double-Check Locking)模式等。

代码模式(Coding Pattern)

代码模式(或成例)是较低层次的模式,并与编程语言密切相关。代码模式描述怎样利用一个特定的编程语言的特点来实现一个组件的某些特定的方面或关系。

较为著名的代码模式的例子包括双检锁(Double-Check Locking)模式等

2011年11月11日

用Flash理跨域上传或异步请求不能传Cookie的解决方案

Filed under: PHP » PHP » 实践经验 — cmpan @ 2011-11-11 03:09:00

用flash上传或flash做代理异步请求的时候,因为flash不能直接传递浏览器中的cookie到服务器,引起SESSION无法识别身份。想当年刚碰到这个问题的时候会非常头痛。其实在PHP里面,解决时很容易的。

客户端:把cookie变量添加到URL

1
2
3
4
5
6
7
    var url = 'http://www.vkas.net/index.php?user/account/getInfo';
    if(document.cookie.length > 0) {
        var cookies = document.cookie.split(';');
        for(var i in cookies) {
            url += '&' + encodeURI(cookies[i].replace(/^\s+|\s+$/g, ''));
        }
    }

服务器端:把URL中传的cookie.session.name设置到session id。这个过程必须在session_start()之前做。

1
2
3
4
    // 解决Flash不能传Cookie
    if (!empty($_GET[session_name()])) {
        session_id($_GET[session_name()]);
    }

2011年11月1日

一种以ID特征为依据的数据分片(Sharding)策略

Filed under: 未分类 — cmpan @ 2011-11-01 00:21:23

假如您有一个应用程序,随着业务越来越有起色,系统所牵涉到的数据量也就越来越大,此时您要涉及到对系统进行伸缩(Scale)的 问题了。一种典型的扩展方法叫做“向上伸缩(Scale Up)”,它的意思是通过使用更好的硬件来提高系统的性能参数。而另一种方法则叫做“向外伸缩(Scale Out)”,它是指通过增加额外的硬件(如服务器)来达到相同的效果。从“硬件成本”还是“系统极限”的角度来说,“向外伸缩”一般都会优于“向上伸 缩”,因此大部分上规模的系统都会在一定程度上考虑“向外”的方式。由于许多系统的瓶颈都处在数据存储上,因此一种叫做“数据分片(Database Sharding)”的数据架构方式应运而生,本文便会讨论这种数据架构方式的一种比较典型的实现方式。
(全文 …)

2011年10月28日

多些时间能少写些代码

Filed under: 未分类 — cmpan @ 2011-10-28 17:35:23

在现在这个浮躁的时期,再加上敏捷咨询师们念的歪经,他们让人感觉上就像是软件产品是可以在很短的时间内高质量的完成的,这令那些管理者们很兴奋, 就像巴甫洛夫的条件反射实验中的狗看到了肉就会流口水那样兴奋。他们使用TDD,快速迭代,不断重构,持续集成直至持续部署的方法在进行软件开发。

软件开发真是这样的吗?难道不需要花时间去思考吗?对此,有些观点在Todd的《“品质在于构建过程”吗?》以及《Bob大叔和Jim Coplien对TDD的论战》中谈到过了。我只想想表达下面的观点:

  • 软件的精髓在于设计,设计是一件很费大脑的事件。对于软件来说,设计没有完美的,它总是一件需要取舍需要权衡 的事,比如:时间换空间,空间换时间,TCP或UDP,同步还是异步,数据冗余还不冗余等等。那怕是一个小小的observers模式是pull方式还是 push方式 都需要仔细讨论。这些的东西需要时间和做前期尝试。
  • TDD快速原型和迭代可能会对软件和团队产生负面影响。在一开始,你需 要花很大的精力来让你的软件从无到有(做过软件的人都知道,从零开始写代码是很痛苦的事),但是因为你没有想好,先做再说,所以,后期你会面临更多的质量 问题而让你需要花更多的时间精力。当然,那些咨询师会让你用持续集成和持续部署这样的方法。但我想告诉你,这并不解决你软件设计的缺陷。举个例子—— TDD、迭代、原型只关注功能性需求,其不会关注非功能性需求,比如性能问题,高可用性问题,系统维护问题(模块的耦合问题),等等。而这些问题往往都可 以让你的软件设计重新来过。
  • 重构是恶梦,重构应该越少越好。当你维护一个复杂的系统时你会知道重构是一件多么恐怖的事情(参看《重构代码的7个阶段》)。如果一开始没有想好,你要面临的不单单是re-design, re-architect,还要面对时间和人力成本的增加,最难的是你还要面对的是团队士气因为不断的rework而逐渐低落并产生厌倦和懈怠情绪。

 

所以,如果你能有多一些时间去和客户讨论一下需求和未来可能的变化,去调查一下实现的技术难点和细节,去和其他有经验的人讨论并推敲一下架构和设 计,去思考设计上的缺陷,那么,你的coding会变得非常地直,直到你一眼就看到尽头,你的测试案例也会写得非常地好,你会几乎不需要重构,于是,你会 在未来少写很多代码,从而你的软件开发会越来越轻松,直到技术开始换代。

我现在在做的项目,花了几乎4个月的时间来做设计,在这个过程中,我们反复思考、讨论和权衡若干种实现方法,并尽可能地穷举所有的场景和细节以及未 来可能的变化(那怕是那些简单的模块),有个模块被重写了至少三次,每次都是写到一半就被推翻重写,我们整个团队不断地在和其它团队讨论,并在对系统不断 地认识中对系统进行简化和优化,并力求达到完美。现在看来,没有贸然使用Scrum是明智的。

这就好像我们修路造桥一样,我们需要花大量的时间勘测地形地质,分析数据,思考可能出现的各种问题(各种自然灾害),评估不同的设计方案,而不是先尽快建好再说。

所以,多一些时间,不是让你多做几次迭代,多完成几个模块,而是可以让你少写一些代码,更快的交付一个更好的产品

我相信你会有很多疑问,下面是我觉得你可能会有下面的一些观点,让我一条一条来回复:

  • 首当其冲的一定会是项目的deadline,或是那种你没有活语权的项目。比如做那种“甲乙方合同式的项目”,我把这种项目统一认为是“外包项目”,在这种项目性质下,你很难有话语权。对此,我觉得,1)作为乙方的你还是应该和甲方在项目计划上争取一下,晓之以情,动之以理。2)如果不行,只能在时间、需求范围和质量上做一个权衡。另外,在这种情况下你要找一个方法,把你的压力和痛苦分担给用户和领导。(找到这个方法的前提需要你找到用户和领导他们害怕什么,嘿嘿)
  • 过度设计和纸上谈兵。有人说会不会设计太多,造成过度设计,或是在设计上花太多的时间。这有可能。我上一家公 司的一个项目团队就花了1年多的时间来不停不停的开会和做设计,结果release的时候还有1000多个bug。这个问题的原因是,这个团队的设计是在 纸上谈兵,开会是开神仙会,讨论的设计都是浮云。所以,设计并不是讨论和思考,还需要去尝试,我认为当你的设计完成的时候,你的骨干核心代码都基本完成了。
  • 我的团队成员水平太差,不会思考。首先,先恭喜你找到一堆码农,当然,这不怪你,这是中国教育和大环境的问题,让人不会思考。对于这样的情况,我有两个建议,1)量力而行,使多大的碗就吃多少饭。2)鼓励思考,那怕那些想法很不靠谱,因为如果不开始,那么将永远不会思考。
  • 必需使用快速迭代。很多公司都在强行上敏捷,他们希望产品越快release越好,而没有充分的时间思考和讨论。对于这种项目,我的建议是,1)找有丰富经验的人来做。2)迭代过程中力求架构和程序逻辑的简单,简单,再简单,力求代码间的高内聚,低耦合。不然,重构的时候你就好玩了。
  • 创业团队必需要快。做得快就是做得好吗?很多时候,不是谁快谁就能笑到最后的。这样的例子太多了。第一个做出来的人并不一定就会占领市场,其很有可能会成为先驱。
  • 有钱的公司才会让团队用更多的时间去思考。错了,你们没有见过有钱的公司,有钱的公司可以招一堆干不成活的人,可以把事搞乱了再新来过,甚至可以把做失败的项目换个名字再重新立项。这些真正的有钱的公司只求快,只求人多,不怕做错决定。像我们这些没钱的人,干什么事都是小心翼翼地,生怕做错决定。

 

转自:http://coolshell.cn/articles/5686.html

 

2011年10月26日

对于PHP大型开发框架的看法

Filed under: PHP » PHP » 实践经验 — cmpan @ 2011-10-26 10:00:09

PHP从诞生以来就受到广大编程爱好者的喜欢,成为中小站长的好帮手,并培养了大量的PHP编程人员,但是随着PHP的应用越发广泛,很多时候已不限于从事中小网站的应用,一些大型PHP项目也屡见不鲜。

 

当我们选择PHP开发大型项目时,就不得不考虑开发效率、开发规范、后期维护等问题,这时大家往往会选择一款人们所认可的开发框架,目前所流行的Zend Framework、Yii、Symfony、CodeIgniter、CakePHP等都声称有着开发大型应用的能力。

 

新框架层出不穷,但当我们真正应用这些框架去实现产品又总是会有各种不同的问题产生:

一、大型框架的背后往往有着较为深厚的结构理论,最熟悉的莫过于MVC、ORM这样耳熟能详的理论术语,还有很多深度面向对象方面的知识,但是真正了解这些的人却为数不多,使得应用门槛急剧攀升;除此大型框架中的应用细节更是纷繁复杂,学习成本也相对较高,这对于原本只是定位中小应用的PHP变得尤为尴尬。

 

二、PHP做为一门脚本语言,它的运行往往基于宿主进程(如:apache、php-fpm),在单次请求上经历创建进程、初始化环境、编译脚本、运行引擎、输出、资源回收、进程销毁等一系列过程,在编程语言层面综合运行效率上要比编译型语言慢上2-3个数量级,伴随着消耗大量的系统资源,在此基础上我们还要搭建及加载复杂的开发框架更是增加了其运行成本。而在大型应用中从不缺乏特殊需求,有时PHP加大型框架的运行效率就是致命的。

 

三、大型框架所考虑的因素过多,开发人员在应用时需要额外关注代码以外的细节过多,如:非标准约定、冗长的手册、琐碎的配置、复杂的文件目录结构、难以限制的合理性约束、千姿百态的类库等等,使得大多数程序员开发过程屡糟困惑,提高开发效率也成了空话。

 

四、最致命的一点,框架作者不断地寻找银弹,试图制作出一个满足所有需求的怪物。大型应用对系统的松散耦合性要求很高,通常不可能在开发层面直接对数据进行操作,见一个简单的SOA模型(附图),数据层和业务层几乎是物理隔离的,而在业务层的开发上只针对数据层提供的服务接口进行访问。从目前的PHP开发框架来说(特别是MVC模型),通常使用ORM来直接对数据库表进行抽象,并直接加以CRUD操作,靠谱的大型应用是不会这做的(或许适合VPS,但大型应用会选择VPS ??)。

 

总结,PHP大型框架真的还处于很尴尬的地位,但是从另一方面来说,好的PHP大型框架真的是一个值得很多人学习的好榜样,其中蕴涵了大量的设计理念、设计模式、代码优化、语言特性、软件工程等知识体系,融汇php精髓但又远超PHP本身。

最后还是要对这些大型PHP框架说一流行话,“学之者生,用之者死”。

 

 

转自:http://www.cnblogs.com/lajabs/archive/2011/10/14/2212704.html

2011年10月16日

从敏捷宣言理解敏捷交互设计

Filed under: 架构 — cmpan @ 2011-10-16 18:45:08

敏捷交互设计是敏捷方法论向交互设计领域的延伸,它提倡让所有相关人参与到设计过程中,迭代演进式地进行交互设计。从2010年开始,已经有越来越的团队在不同程度上使用敏捷交互设计的方法,而放弃了流程化的传统产品设计过程。

事实上,敏捷交互设计方法在很多方面都充分体现了敏捷价值观,因此,理解敏捷交互设计实践的最好方法是从记录在敏捷宣言中的价值观开始。

个体和交互胜过流程和工具

一个传统交互设计的流程一般分成以下几个步骤进行:

  1. 任务分析:任务分析基于功能列表(一般来自于客户的功能说明书)──在功能性需求的基础上拆分出人物流程和场景;
  2. 页面流程:根据任务分析的结果,为每一个大任务下的子任务中覆盖的功能制作页面流程;
  3. 信息建模:根据页面流程的设计出一套完整的信息框架,满足用户所有功能性需求;
  4. 原型设计:基于信息建模,设计出低保真原型,交给美工进行页面美化;
  5. 视觉设计:基于原型设计,对页面进行美化,最终产出高保真原型,同时编写设计说明;

在传统流程中,我们可以看到非常细致的分工──产品经理负责功能的拆解和分类,以及页面流转;交互设计师设计信息架构和具体交互行为;视觉设计师负责美化页面;前端开发人员负责高保真原型。

你是否体看见了传统瀑布式开发的影子?弊端显而易见:

  1. 分工造成的局限性──每个人都用自己的视角进行工作,无法形成统一的产品视角(Vision);
  2. 分工造成的“不可评价性”──你没权利对产品经理的功能拆解有异义,因为你不是这方面的专家;
  3. 需求在传递中产生了失真的风险──需要靠大量文档进行记录;
  4. 客户没法说不──当客户需要到整个流程的最后看到一个或者两个大而全的设计方案时,他无法提出任何有价值的反馈,这本身就是用一个贵重的半成品绑架客户;

跟软件交付中的敏捷实践一样,敏捷交互设计倡导全功能团队,避免过于明显的分工,和基于分工特有的流程。仅有的流程是基于产品逐步清晰化的过程,而非基于人员的技能,所有人都应该参与到这个过程中来。敏捷交互设计主要分以下几个步骤:

  1. 寻找产品方向(Inspire):抛开需求列表,从目标人群的期待体验出发,寻找可能存在的产品方向;
  2. 定位产品需求(Identify):定位本产品需要提供什么样的消费者体验;
  3. 设计产品体验(Ideate):对决定的目标体验进行设计;
  4. 验证产品设计(Implement):快速制作原型,并频繁进行用户测试,迭代式改进。

图1. 从体验中寻找交付范围,把功能列表放在一边

除了流程简化和分工融合,在工具的选择上,敏捷交互设计也与传统方式有所不同──对于交互的推崇高于对特定工具的选择。

所有在敏捷交互设计中使用的工具,都应该遵循一条原则:它必须推动设计团队成员间的交互,而不是简单提升单个成员的工作效率。

基于此,敏捷交互设计中推崇各种轻量级工具,而不是大型的第三方软件,例如纸质原型Paper Protityping而非Visio或Axure此类原型工具。过于精细的结果往往会增加协作和反馈的门槛,虽然可能提升单个成员工作效率,却达不到鼓励交互的目的。

图2. 使用轻量级的工具进行交互设计

可工作的软件胜过完备的文档

敏捷软件交付过程中,每个迭代的核心产出是不足够完美,但却满足一个完整业务场景的软件──端到端流程的可完成,而不需要面面俱到的完美。

而传统开发方式中在长时间内只是各个功能模块中功能的堆砌,无法在短时间内实现端到端场景,那么文档便成为串联各个功能保证有序开发的必需品。

传统交互设计也存在这个问题。往往一个标准交互设计阶段的文档分三个方面,它们是:

  1. 内容方面(Content):内容的层次和整体信息架构设计;
  2. 视觉方面(Visual):整站风格的视觉设计文档;
  3. 交互方面(Interaction):整站高保真交互设计原型;

仔细分析这些文档的生产过程,我们不难发现以下特点:

  1. 它们都是以整站为目标,试图覆盖所有使用场景;
  2. 它们的生产过程是线性的,直到三者全部完成才能够指导开发;
  3. 正因为每个环节的过程是孤立的,无法形成统一的认识,文档传递经常发生失真;
  4. 一个完美的东西很难得到产品方向性的关键反馈;

敏捷交互设计试图在解决以上问题。

敏捷交付的核心在于尽早地交付出可进行端到端测试的代码,而非完备文档,而敏捷交互设计的核心则在于尽早地交付出可以进行端到端可测试的原型,同样亦非完备文档。

而这里说的“端到端可测试的原型”包含以下含义:

  1. 端到端:必须设计出符合合理使用场景的端到端流程,这个流程会覆盖一个典型用户最核心的使用场景,所有的交互设计应该第一时间收敛在这个端到端场景周围,而非“整站”功能的分割展示;
  2. 可测试原型:不需要完美的原型,只需要所设计端到端场景中涉及到的原型,同时,原型的完备性上必须达到内容、视觉、交互三者细致力度一致,在测试中,三者力度的不一致往往会隐藏问题,例如,如果测试的原型视觉上过于完美,就会减弱用户在交互上的关注;

假设我们把交互设计的四周拆分成每周一个迭代,每周交付一个覆盖端到端场景,且在内容、视觉和交互方面都相对完备的原型收集反馈或进行测试,和传统项目相比,我们是否可以更早地得到客户反馈,是否可以让设计过程更透明,是否毋须完备的过程文档?答案自然是肯定的。

图3 逐步细化的原型,不停进行用户测试

当然,这样的过程必然需要多模块(这里的模块指技能的差别)之间的融合,实现全团队的运作。

你会问我,这是否意味着我们的交互设计师需要学会使用IIlustrtor进行视觉设计?或者视觉设计师需要学会HTML+CSS+jQuery制作高保真原型?

是的,在很多情况下,敏捷交互设计团队中的设计师确实需要具备多种功能的T型人才──他们有专业的技能,也可以在其他方面有足够的贡献。

分工的结果只能导致能力的停滞不前、产品视角的缺失、职能不可替代的风险、协作软的低效、沟通的浪费等等,而唯一的好处在于,可以更快和“更不被抱怨(如德鲁克说过程文档的价值在于管理抱怨)”产生一堆堆相互分裂且无法让客户挑错的文档。

客户协作胜过合同谈判

让我们举例说明在传统交互设计阶段出现的场景:一份标书、一份功能列表、一份到处使用的所谓用户体验调查问卷,在交互设计的开始阶段,我们和客户在 一起进行“需求调研”,其实这些不重要,我们只需要对比我们之前的产品都有哪些功能可能有重复,类似产品有哪些可以借鉴,调研往往只是形式,关键还是未来 的二至四周;

然后最后一次见客户也许就是最终文档提交的那天,给客户看一套精美的PSD文档,一般我们会做出A和B方案,其中不乏我们臆想出来的需求,有时只为让那个区域看起来不那么空,客户高兴地选择了其中的一套方案后,交付正式开始。

这就是基于合同进行设计的典型场景,谁也不知道合同中的功能列表意味着什么,而对于客户来说,它确实是购物单,真正交付时已忘记为什么需要。

但这不妨碍交互设计师进行设计,大部分时候他们并没有仔细思考这个功能真正的使用场景,而是把它“画”出来,让它看起来很美,却不管它如何实现和如何被用户使用。

这是基于合同进行设计自然而然的结果,在每个功能上,设计师都希望当成对自己的挑战,他们绞尽脑汁收集类似产品类似功能,尽可能取悦客户,说服他们采用更炫更丰富的交互方式,而作为不对交付负责的人他们毋须承担责任。

而敏捷交互设计希望打破这种基于合同或者换言之,基于功能列表的设计模式。它希望在设计的全过程将客户参与进来,让客户了解某个标书上的功能也许没 有意义,或者不是当下应该解决的问题──一个交付项目范围的最好确定时机就是在交互设计过程中客户的全程参与。客户参与的优势有以下几点:

  1. 过程的透明化提升客户的安全感,随时保持对设计进度的了解;
  2. 最好的反馈模式就是让客户亲身参与设计过程;
  3. 了解最终用户和业务模式的是客户,客户是不可多得的资源;
  4. 当设计结果是功能列表的重新确认,对于合同中的内容便达成了新的共识;
  5. 客户参与的过程是建立信任的最佳机会,良好的信任关系应该在最开始就建立;
  6. 在产品设计方向上和客户达成一致,而不是仅靠标书或者访谈结果的支言片语;
  7. 提升参与感有助于培养更负责的客户,在交付阶段,之前的努力将会获得巨大的回报;
  8. 有效控制设计的变化,当客户亲身参与设计决定过程时,很多盲目的设计变化会减少很多;

图4 和客户一起进行设计

拥抱变化胜过遵循计划

当你的设计不能和客户一起进行,你只是个标书需求列表的简单执行者,需求的变化便是理所当然的事情。

在有些传统交互设计流程里甚至出现“需求冻结”这样的流程──如果你已经对某个环节的文档进行进行签收,就不能在“需求冻结”后改变主意。这样的结果无非两个:一尽量不要签收那个环节的文档;二在需求没有冻结的时候抓紧机会改变主意。

从敏捷宣言的角度来看,之前的三句话是最后一句话的基础,如果不能做到对个体和交互的尊重,把可用软件当作产生核心价值的东西,并且努力和客户进行协作,谈拥抱变化只是空话。在敏捷交互设计中,遵循同样的道理:

对个体和交互的尊重──当需求发生变化时,因为在新的流程中对产品视角的重视,可首先对需求变化的价值进行判断,即它是不是匹配达成一致的产品视 角;真正需求变化时,因为分工的模糊以及流程的简化,可更灵活地调配资源进行处理;再者因为大量使用轻量级的工具,修改成本大大降低;

关注可工作的软件──因为我们把可进行的端到端场景测试作为敏捷交互设计过程中最重要的目标,当出现需求变化时,可通过审视变化本身“是否包含在端 到端场景中?如果不产生这样的变化,用户因此有何种损失”来判断需求变化本身的价值;同时,因为能够尽早的得到端到端场景原型设计,需求本身往往来自于用 户测试的结果,这样的需求变化往往是有价值的,有理可依的;

客户协作的重要性──需求变化往往来自于客户的不确定性,很多情况下这种不确定又来自于一个新产品背后业务模式的不确定,客户协作帮助在设计过程中及早发现和解决这种来自业务方面的不确定,同时,客户协作对客户责任感的培养也大大减少了来自于客户不负责任的需求摆动。

这就是敏捷交互设计可以很好的管理用户需求的根本原因。

从敏捷推行到现在,在交付领域已经走向成熟,越来越多的团队开始采用敏捷方法进入开发,但从软件交付的全流程来看,早于交付的交互设计环节目前依然以传统设计方式为主。

随着消费型软件大行其道,用户对软件使用体验的要求越来越高,同时新产品的推陈出新对快速产品设计提出新的要求,这样的背景使得传统交互设计流程不 得不做出一些新的调整以拥抱更加频繁的变化,这也是为什么很多交互设计团队开始努力尝试具有敏捷价值观的敏捷交互设计进行产品设计的主要原因。

最后,让我们来比较一下传统交互设计方法和敏捷交互设计方法的区别:

传统交互设计 敏捷交互设计
没有交付团队的参与;客户参与度低;设计团队中各职能分工明确; 交互设计师、用户研究者、视觉设计师、前端开发者、客户代表、以及开发团队代表都完整参与整个交互设计的过程,并只有能力区分而弱化职责分工;
客户需求文档中的功能列表是贯穿设计过程的主线; 基于终端使用者期待体验的设计过程,往往客户功能列表只作为参考;
各自有各自对产品的理解,无法达成共识; 对产品设计方向的形成共识是贯穿整个交互设计阶段;
使用大型的交互设计软件; 鼓励使用白板、海报、贴纸、手绘等轻量级的工具;
客户只在开始和结束参与项目; 客户全程参与设计活动;
主要以文档制作为主; 主要以Workshop工作坊活动为主,高互动过程;
设计师单独和封闭工作; 设计师合作式的工作,随时把工作的产出物展示,接受反馈;
设计师能力专一; 鼓励T型人才;
缺少用户测试; 在不同精细度的原型上快速进行用户测试,迭代式演进设计;
大而全的设计; 只设计足够的交互;
远离客户以避免变化; 和客户在一起鼓励变化;
不对交付负责,肆意发挥; 对交付负责,在成本接受的范围内创新;

转自:http://www.infoq.com/cn/articles/xzc-agile-interaction-design

深入浅出REST

Filed under: 架构 — cmpan @ 2011-10-16 18:43:33

不知你是否意识到,围绕着什么才是实现异构的应用到应用通信的“正确”方式,一场争论正进行的如火如荼:虽然当前主流的方式明显地集中在基于 SOAP、WSDL和WS-*规范的Web Services领域,但也有少数人用细小但洪亮的声音主张说更好的方式是REST,表述性状态转移(REpresentational State Transfer)的简称。在本文中,我不会涉及争论的话题,而是尝试对REST和RESTful HTTP应用集成做实用性的介绍。以我的经验,有些话题一旦触及就会引来众多的讨论,当涉及到这方面话题的时候,我会深入详细地阐述。

REST关键原则

大部分对REST的介绍是以其正式的定义和背景作为开场的。但这儿且先按下不表,我先提出一个简单扼要的定义:REST定义了应该如何正确地使用 (这和大多数人的实际使用方式有很大不同)Web标准,例如HTTP和URI。如果你在设计应用程序时能坚持REST原则,那就预示着你将会得到一个使用 了优质Web架构(这将让你受益)的系统。总之,五条关键原则列举如下:

  • 为所有“事物”定义ID
  • 将所有事物链接在一起
  • 使用标准方法
  • 资源多重表述
  • 无状态通信

下面让我们进一步审视这些原则。

为所有“事物”定义ID

在这里我使用了“事物”来代替更正式准确的术语“资源”,因为一条如此简单的原则,不应该被淹没在术语当中。思考一下人们构建的系统,通常会找到一 系列值得被标识的关键抽象。每个事物都应该是可标识的,都应该拥有一个明显的ID——在Web中,代表ID的统一概念是:URI。URI构成了一个全局命 名空间,使用URI标识你的关键资源意味着它们获得了一个唯一、全局的ID。

对事物使用一致的命名规则(naming scheme)最主要的好处就是你不需要提出自己的规则——而是依靠某个已被定义,在全球范围中几乎完美运行,并且能被绝大多数人所理解的规则。想一下你 构建的上一个应用(假设它不是采用RESTful方式构建的)中的任意一个高级对象(high-level object),那就很有可能看到许多从使用唯一标识中受益的用例。比如,如果你的应用中包含一个对顾客的抽象,那么我可以相当肯定,用户会希望将一个指 向某个顾客的链接,能通过电子邮件发送到同事那里,或者加入到浏览器的书签中,甚至写到纸上。更透彻地讲:如果在一个类似于Amazon.com的在线商 城中,没有用唯一的ID(一个URI)标识它的每一件商品,可想而知这将是多么可怕的业务决策。

当面对这个原则时,许多人惊讶于这是否意味着需要直接向外界暴露数据库记录(或者数据库记录ID)——自从多年以来面向对象的实践告诫我们,要将持 久化的信息作为实现细节隐藏起来之后,哪怕是刚有点想法都常会使人惊恐。但是这条原则与隐藏实现细节两者之间并没有任何冲突:通常,值得被URI标识的事 物——资源——要比数据库记录抽象的多。例如,一个定单资源可以由定单项、地址以及许多其它方面(可能不希望作为单独标识的资源暴露出来)组成。标识所有 值得标识的事物,领会这个观念可以进一步引导你创造出在传统的应用程序设计中不常见的资源:一个流程或者流程步骤、一次销售、一次谈判、一份报价请求—— 这都是应该被标识的事物的示例。同样,这也会导致创建比非RESTful设计更多的持久化实体。

下面是一些你可能想到的URI的例子:

http://example.com/customers/1234

http://example.com/orders/2007/10/776654

http://example.com/products/4554

http://example.com/processes/salary-increase-234

正如我选择了创建便于阅读的URI——这是个有用的观点,尽管不是RESTful设计所必须的——应该能十分容易地推测出URI的含义:它们明显地标识着单一“数据项”。但是再往下看:

http://example.com/orders/2007/11

http://example.com/products?color=green

首先,这两个URI看起来与之前的稍有不同——毕竟,它们不是对一件事物的标识,而是对一类事物集合的标识(假定第一个URI标识了所有在2007年11月份提交的定单,第二个则是绿颜色产品的集合)。但是这些集合自身也是事物(资源),也应该被标识。

注意,使用唯一、全局统一的命名规则的好处,既适用于浏览器中的Web应用,也适用于机对机(machine-to-machine,m2m)通信。

来对第一个原则做下总结:使用URI标识所有值得标识的事物,特别是应用中提供的所有“高级”资源,无论这些资源代表单一数据项、数据项集合、虚拟亦或实际的对象还是计算结果等。

将所有事物链接在一起

接下来要讨论的原则有一个有点令人害怕的正式描述:“超媒体被当作应用状态引擎(Hypermedia as the engine of application state)”,有时简写为HATEOAS。(严格地说,这不是我说的。)这个描述的核心是超媒体概念,换句话说:是链接的思想。链接是我们在HTML中常见的概念,但是它的用处绝不局限于此(用于人们网络浏览)。考虑一下下面这个虚构的XML片段:

<order self="http://example.com/customers/1234">
   <amount>23</amount>
   <product ref="http://example.com/products/4554">
   <customer ref="http://example.com/customers/1234">
</customer> </product></order>

如果你观察文档中product和customer的链接,就可以很容易地想象到,应用程序(已经检索过文档)如何“跟随”链接检索更多的信息。当然,如果使用一个遵守专用命名规范的简单“id”属性作为链接,也是可行的——但是仅限于应用环境之内。使用URI表示链接的优雅之处在于,链接可以指向由不同应用、不同服务器甚至位于另一个大陆上的不同公司提供的资源——因为URI命名规范是全球标准,构成Web的所有资源都可以互联互通。

超媒体原则还有一个更重要的方面——应用“状态”。简而言之,实际上服务器端(如果你愿意,也可以叫服务提供者)为客户端(服务消费者)提供一组链 接,使客户端能通过链接将应用从一个状态改变为另一个状态。稍后我们会在另一篇文章中探究这个方面的影响;目前,只需要记住:链接是构成动态应用的非常有 效的方式。

对此原则总结如下:任何可能的情况下,使用链接指引可以被标识的事物(资源)。也正是超链接造就了现在的Web。

使用标准方法

在前两个原则的讨论中暗含着一个假设:接收URI的应用程序可以通过URI明确地一些有意义的事情。如果你在公共汽车上看到一个URI,你可以将它输入浏览器的地址栏中并回车——但是你的浏览器如何知道需要对这个URI做些什么呢?

它知道如何去处理URI的原因在于所有的资源都支持同样的接口,一套同样的方法(只要你乐意,也可以称为操作)集合。在HTTP中这被叫做动词 (verb),除了两个大家熟知的(GET和POST)之外,标准方法集合中还包含PUT、DELETE、HEAD和OPTIONS。这些方法的含义连同 行为许诺都一起定义在HTTP规范之中。如果你是一名OO开发人员,就可以想象到RESTful HTTP方案中的所有资源都继承自类似于这样的一个类(采用类Java、C#的伪语法描述,请注意关键的方法):

class Resource {
     Resource(URI u);
     Response get();
     Response post(Request r);
     Response put(Request r);
     Response delete();
}

由于所有资源使用了同样的接口,你可以依此使用GET方法检索一个表述(representation)——也 就是对资源的描述。因为规范中定义了GET的语义,所以可以肯定当你调用它的时候不需要对后果负责——这就是为什么可以“安全”地调用此方法。GET方法 支持非常高效、成熟的缓存,所以在很多情况下,你甚至不需要向服务器发送请求。还可以肯定的是,GET方法具有幂等性[译 注:指多个相同请求返回相同的结果]——如果你发送了一个GET请求没有得到结果,你可能不知道原因是请求未能到达目的地,还是响应在反馈的途中丢失了。 幂等性保证了你可以简单地再发送一次请求解决问题。幂等性同样适用于PUT(基本的含义是“更新资源数据,如果资源不存在的话,则根据此URI创建一个新 的资源”)和DELETE(你完全可以一遍又一遍地操作它,直到得出结论——删除不存在的东西没有任何问题)方法。POST方法,通常表示“创建一个新资 源”,也能被用于调用任过程,因而它既不安全也不具有幂等性。

如果你采用RESTful的方式暴露应用功能(如果你乐意,也可以称为服务功能),那这条原则和它的约束同样也适用于你。如果你已经习惯于另外的设计方式,则很难去接受这条原则——毕竟,你很可能认为你的应用包含了超出这些操作表达范围的逻辑。请允许我花费一些时间来让你相信不存在这样的情况。

来看下面这个简单的采购方案例子:

Sample Scenario

可以看到,例子中定义了两个服务程序(没有包含任何实现细节)。这些服务程序的接口都是为了完成任务(正是我们讨论的 OrderManagement和CustomerManagement服务)而定制的。如果客户端程序试图使用这些服务,那它必须针对这些特定接口进行 编码——不可能在这些接口定义之前,使用客户程序去有目的地和接口协作。这些接口定义了服务程序的应用协议(application protocol)。

在RESTful HTTP方式中,你将通过组成HTTP应用协议的通用接口访问服务程序。你可能会想出像这样的方式:

Sample Scenario, done RESTfully

可以看到,服务程序中的特定操作被映射成为标准的HTTP方法——为了消除歧义,我创建了一组全新的资源。“这是骗人的把戏”,我听见你叫嚷着。 不,这不是欺骗。标识一个顾客的URI上的GET方法正好相当于getCustomerDetails操作。有人用三角形形象化地说明了这一点:

Knobs one can turn

把三个顶点想象为你可以调节的按钮。可以看到在第一种方法中,你拥有许多操作,许多种类的数据以及固定数量的“实例”(本质上和你拥有的服务程序数 量一致)。在第二种方法中,你拥有固定数量的操作,许多种类的数据和许多调用固定方法的对象。它的意义在于,证明了通过这两种方式,你基本上可以表示任何 你喜欢的事情。

为什么使用标准方法如此重要?从根本上说,它使你的应用成为Web的一部分——应用程序为Web变成Internet上最成功的应用所做的贡献,与 它添加到Web中的资源数量成比例。采用RESTful方式,一个应用可能会向Web中添加数以百万计的客户URI;如果采用CORBA技术并维持应用的 原有设计方式,那它的贡献大抵只是一个“端点(endpoint)”——就好比一个非常小的门,仅仅允许有钥匙的人进入其中的资源域。

统一接口也使得所有理解HTTP应用协议的组件能与你的应用交互。通用客户程序(generic client)就是从中受益的组件的例子,例如curl、wget、代理、缓存、HTTP服务器、网关还有Google、Yahoo!、MSN等等。

总结如下:为使客户端程序能与你的资源相互协作,资源应该正确地实现默认的应用协议(HTTP),也就是使用标准的GET、PUT、POST和DELETE方法。

资源多重表述

到目前为止我们一直忽略了一个稍微复杂的问题:客户程序如何知道该怎样处理检索到的数据,比如作为GET或者POST请求的结果?原因是,HTTP 采取的方式是允许数据处理和操作调用之间关系分离的。换句话说,如果客户程序知道如何处理一种特定的数据格式,那就可以与所有提供这种表述格式的资源交 互。让我们再用一个例子来阐明这个观点。利用HTTP内容协商(content negotiation),客户程序可以请求一种特定格式的表述:

GET /customers/1234 HTTP/1.1
Host: example.com
Accept: application/vnd.mycompany.customer+xml

请求的结果可能是一些由公司专有的XML格式表述的客户信息。假设客户程序发送另外一个不同的请求,就如下面这样:

GET /customers/1234 HTTP/1.1
Host: example.com
Accept: text/x-vcard

结果则可能是VCard格式的客户地址。(在这里我没有展示响应的内容,在其HTTP Content-type头中应该包含着关于数据类型的元数据。)这说明为什么理想的情况下,资源表述应该采用标准格式——如果客户程序对HTTP应用协 议和一组数据格式都有所“了解”,那么它就可以用一种有意义的方式与世界上任意一个RESTful HTTP应用交互。 不幸的是,我们不可能拿到所有东西的标准格式,但是,或许我们可以想到在公司或者一些合作伙伴中使用标准格式来营造一个小环境。当然以上情况不仅适用于从 服务器端到客户端的数据,反之既然——倘若从客户端传来的数据符合应用协议,那么服务器端就可以使用特定的格式处理数据,而不去关心客户端的类型。

在实践中,资源多重表述还有着其它重要的好处:如果你为你的资源提供HTML和XML两种表述方式,那这些资源不仅可以被你的应用所用,还可以被任意标准Web浏览器所用——也就是说,你的应用信息可以被所有会使用Web的人获取到。

资源多重表述还有另外一种使用方式:你可以将应用的Web UI纳入到Web API中——毕竟,API的设计通常是由UI可以提供的功能驱动的,而UI也是通过API执行动作的。将这两个任务合二为一带来了令人惊讶的好处,这使得 使用者和调用程序都能得到更好的Web接口。

总结:针对不同的需求提供资源多重表述。

无状态通信

无状态通信是我要讲到的最后一个原则。首先,需要着重强调的是,虽然REST包含无状态性(statelessness)的观念,但这并不是说暴露功能的应用不能有状态——
事实上,在大部分情况下这会导致整个做法没有任何用处。REST要求状态要么被放入资源状态中,要么保存在客户端上。或者换句话说,服务器端不能保持除了 单次请求之外的,任何与其通信的客户端的通信状态。这样做的最直接的理由就是可伸缩性—— 如果服务器需要保持客户端状态,那么大量的客户端交互会严重影响服务器的内存可用空间(footprint)。(注意,要做到无状态通信往往需要需要一些 重新设计——不能简单地将一些session状态绑缚在URI上,然后就宣称这个应用是RESTful。)

但除此以外,其它方面可能显得更为重要:无状态约束使服务器的变化对客户端是不可见的,因为在两次连续的请求中,客户端并不依赖于同一台服务器。一 个客户端从某台服务器上收到一份包含链接的文档,当它要做一些处理时,这台服务器宕掉了,可能是硬盘坏掉而被拿去修理,可能是软件需要升级重启——如果这 个客户端访问了从这台服务器接收的链接,它不会察觉到后台的服务器已经改变了。

理论上的REST

我承认:以上我所说的REST不是真正的REST,而且我可能有点过多地热衷于简单化。但因为我想有一个与众不同的开场,所以没有在一开始就介绍其正式的定义和背景。现在就让我们稍微简要地介绍一下这方面的内容。

首先,先前我并没有明确地区分HTTP、RESTful HTTP和REST。要理解这些不同方面之间的关系,我们要先来看看REST的历史。

Roy T. Fielding在他的博士学位论文(实际上你应该访问这个链接——至少对于一篇学术论文来说,它是相当易读的。此论文已被翻译成中文) 中定义了术语REST。Roy曾是许多基本Web协议的主要设计者,其中包括HTTP和URIs,并且他在论文中对这些协议提出了很多想法。(这篇论文被 誉为“REST圣经”,这是恰当的——毕竟,是作者发明了这个术语,所以在定义上,他写的任何内容都被认为是权威的。)在论文中,Roy首先定义一种方法 论来谈论架构风格——高级、抽象的模式,来表达架构方法背后的核心理念。每一个架构风格由一系列的约束(constraints)定义形成。架构风格的例子包括“没有风格”(根本没有任何约束)、管道和过滤器(pipe and filter)、客户端/服务器、分布式对象以及——你猜到它了——REST。

如果对你来说这些听起来都太抽象了,那就对了——REST在本质上是一个可以被许多不同技术实现的高层次的风格,而且可以被实例化——通过为它的抽 象特性赋上不同的值。比如,REST中包含资源和统一接口的概念——也就是说,所有资源都应该对这些相同的方法作出反应。但是REST并没有说明是哪些方 法,或者有多少方法。

REST风格的一个“化身”便是HTTP(以及一套相关的一套标准,比如URI),或者稍微抽象一些:Web架构自身。接着上面的例子,HTTP使 用HTTP动词作为REST统一接口的“实例”。由于Fielding是在Web已经(或者至少是大部分)“完善”了之后才定义的REST风格,有人可能 会争论两者是不是100%的匹配。但是无论如何,整体上来说Web、HTTP和URI仅仅是REST风格的一个主要实现。不过,由于Roy Fielding即是REST论文的作者,又对Web架构设计有过深远的影响,两者相似也在情理之中。

最后,我在前面一次又一次地使用着术语“RESTful HTTP”,原因很简单:许多使用HTTP的应用因为一些理由并没有遵循REST原则,有人会说使用HTTP而不遵循REST原则就等同于滥用HTTP。 当然这听起来有点狂热——事实上违反REST约束的原因通常是,仅仅因为每个约束带来的设计权衡可能不适合于一些特殊情况。但通常,违背REST约束的原 因可归咎于对其好处认知的缺乏。来看一个明显的反面案例:使用HTTP GET调用类似于删除对象的操作,这违反了REST的安全约束和一般性常识(客户程序不应为此负责,服务器端开发人员大概不是有意而为之)。但在随后的文 章中,我会提及更多这样或那样的对HTTP的滥用。

总结

本文试图对REST(Web架构)背后的概念提供快速的介绍。RESTful HTTP暴露功能的方式与RPC、分布式对象以及Web Services是不相同的;要真正理解这些不同是需要一些心态的转变。不管你构建的应用是仅仅想暴露Web UI还是想把API变成Web的一份子,了解下REST的原则还是有好处的。

Stefan Tilkov是InfoQ SOA社区的首席编辑,并且是位于德国和瑞士的innoQ公司的共同创始人、首席顾问和REST狂热分子首领。

查看英文原文A Brief Introduction to REST

转自:http://www.infoq.com/cn/articles/rest-introduction

2011年10月12日

HTML的base标签在ie6下的问题解决

Filed under: WEB » 前端设计 — cmpan @ 2011-10-12 17:33:52

当我们用url重写的时候,用base标签可以使页面中的链接、图片地址等网址相关的元素基于我们设置的链接,如下

但是发现在ie6下页面中的图片都不出来了,这是ie的一个bug,解决方案:
1)base的href属性使用完整的路径,如使用,不使用
2)base标签和标签之间不要有任何html标签

2011年09月30日

nginx 使用 ssl

Filed under: Nginx — cmpan @ 2011-09-30 11:46:31

使用如下命令并根据提示输入信息,生成证书
cd /usr/local/nginx/conf

openssl genrsa -des3 -out localhost.key 1024 #创建密钥
openssl req -new -key localhost.key -out localhost.csr
openssl rsa -in localhost.key -out localhost_nopass.key # 生成浏览器浏览网页时不需要输入密码的密钥
openssl x509 -req -days 365 -in localhost.csr -signkey localhost.key -out localhost.crt #生成证书

在nginx的server配置中加如下配置使用证书

ssl on;
ssl_certificate localhost.crt;
ssl_certificate_key localhost_nopass.key;

现在生成的证书是不受信任的,如果需要受信任的证书,需要证书颁发机构颁发(需要用钱解决)。
免费的证书颁发机构:http://www.startssl.com/ 较低版本的ie浏览器可能不支持。

2011年09月29日

最丑陋的PHP命名空间

Filed under: PHP » PHP » 实践经验 — cmpan @ 2011-09-29 13:12:29

PHP5.3加入了命名空间,很高兴有了这个特性,把自己写的框架改成使用命名空间的,发现很不爽。

写了个没有命名空间的函数 function myFnc(){}
调用的时候如果页面里声明了命名空间,就必须用 \myFnc() 来调用。
写了一个没有命名空间的类 class MyClass {}
调用的时候如果页面里声明了命名空间,就必须用 new \MyClass() 来调用。

为什么声明了命名空间就不能直接用 myFnc()、new MyClass() 类调用全局函数和类呢?
万恶之源在于画蛇的时候添了一足。
那条足在哪呢?
就是相对命名空间

我定义了如下命名空间
namespace sp\A;
namespace sp\A\B;
namespace sp\A\B\C;

在namespace sp\A;中,我可以使用 use B\ClassName、use B\C\ClassName来使用命名空间 namespace sp\A\B和namespace sp\A\B\C下的类,这是使用相对命名空间来访问命名空间,这造成混乱不少。
有相对就会有绝对,而绝对访问方式是:
use \spA\B\ClassName;
use \sp\A\B\C\ClassName;

看见use中的开头的反斜杠“\”了吗?他就是万恶之源中的万恶之源。

为什么一定要搞个相对命名空间出来而不统一直接用
use spA\B\ClassName;
use sp\A\B\C\ClassName;

如果这样我们没有命名空间的类可以直接用 new MyClass(),而不用 new \MyClass(),
调用没有命名空间的函数就可以直接用 muFnc(),而不必用 \myFnc()

画蛇何必添足呢!

2011年09月17日

PHP数据类型隐性转换的陷阱

Filed under: PHP » PHP » 实践经验 — cmpan @ 2011-09-17 05:45:04

之前写过一篇《PHP的动态特性》总结了部分PHP的特性,因为动态语言的特性,我们使用PHP时倍感便利,但是便利的同时会引来一些陷阱,不得不防。
(全文 …)

2011年09月9日

PHP命名空间

Filed under: PHP — 标签:, , , — cmpan @ 2011-09-09 13:04:18

命名空间用来解决在编写类库或应用程序时创建可重用的代码如类或函数时碰到的两类问题。

  • 用户编写的代码与PHP内部的类/函数/常量或第三方类/函数/常量之间的名字冲突。
  • 为很长的标识符名称(通常是为了缓解第一类问题而定义的)创建一个别名(或简短)的名称,提高源代码的可读性。

(全文 …)

2011年09月6日

Windows平台用Netbeans7开发PHP5.3应用开发环境配置

Filed under: PHP — 标签:, , , — cmpan @ 2011-09-06 11:27:20

之前写过ZendStudio调试环境的设置 见 http://wiki.yulans.cn/php/%E8%B0%83%E8%AF%95
一直对eclipse的界面不感冒,更喜欢netbeans的简洁,所有现在用netbeans来做J开发。不想再开个ZDE,配置一下PHP5.3+Netbeans7的开发环境。
(全文 …)

2011年09月1日

架构:豆瓣网技术架构变迁-大型网站架构 (转载)

Filed under: 未分类 — cmpan @ 2011-09-01 18:42:26

罗马不是一天建成的,豆瓣的技术架构也是随着用户规模的增长一直在持续变化中。洪强宁,2002年毕业于清华大学,现任北京豆瓣互动科技有限公司首 席架构师。洪强宁和他带领的技术团队致力于用技术改善人们的文化和生活品质,在网站架构、性能、可伸缩性上进行深入研究。豆瓣网曾获软件中国2006年度 最佳技术应用网站。

(全文 …)

Apache Thrift入门1-架构&介绍

Filed under: 架构 — 标签: — cmpan @ 2011-09-01 18:40:04

Thrift  是什么?
Thrift源于大名鼎鼎的facebook之手,在2007年facebook提交Apache基金会将Thrift作为一个开源项目,对于当时的 facebook来说创造thrift是为了解决facebook系统中各系统间大数据量的传 输通信以及系统之间语言环境不同需要跨平台的特性。所以thrift可以支持多种程序语言,例如:  C++, C#, Cocoa, Erlang, Haskell, Java, Ocami, Perl, PHP, Python, Ruby, Smalltalk. 在多种不同的语言之间通信thrift可以作为二进制的高性能的通讯中间件,支持数据(对象)序列化和多种类型的RPC服务。Thrift适用于程序对程 序静态的数据交换,需要先确定好他的数据结构,他是完全静态化的,当数据结构发生变化时,必须重新编辑IDL文件,代码生成,再编译载入的流程,跟其他 IDL工具相比较可以视为是Thrift的弱项,Thrift适用于搭建大型数据交换及存储的通用工具,对于大型系统中的内部数据传输相对于JSON和 xml无论在性能、传输大小上有明显的优势。
(全文 …)

Older Posts »
Copyright © 2009 流水孟春 版权所有
Web技术,LAMP,Nginx,Web2.0,前端技术
Powered by WordPress & UI Designed by 流水孟春