前端代码的阻抗失配

Impedance Mismatch(阻抗失配)经常被用来比喻服务器端面向对象代码和关系型数据库存储模型之间的关系,先有ORM技术,后有NoSQL(Document based,Key-value store),都是解决这个阻抗失配的方案。

最近在做的一个项目,具有丰富的前端UI,简单的后台逻辑。应客户的要求,采用ExtJS4作为前端技术,利用它极具交互性的UI和号称优雅的MVC框架,来构造应用的所有页面。

不落俗套,在应用最初搭建阶段,是和ExtJS相处的蜜月期,“优雅”的MVC框架和清晰的封装让人眼前一亮。但是随着项目的进展,在功能需求没有显著增加的同时,客户对于前端交互友好性的需求却与日俱增,不可避免地让前端构造UI及交互的代码日益复杂。

出于面向对象和封装的考虑,对于页面上大大小小的控件,我们基本上都做了封装,而且封装还是嵌套的,在大控件内部还封装着小空间。每一个控件基本上都是满足ExtJS的MVC模式,即对应至少View、Controller两个“类”。

同样出于对架构腐化的担心和对它的不断思考和优化,我们在不断地调整不同类的封装,对事件和行为做一一调整,力争做到合适的封装、减少重复代码、易于理解,从而达到更好的可维护性。

这样最直接的后果就是,在每次我们需要深入代码去解决一些问题时,要费上好一番功夫,从大控件找到内部的小控件,从一个事件发送者搜索到事件的响应者,才能确定出问题的代码可能藏在某个犄角旮旯。

对于封装如此良好、层次如此清晰的前端“面向对象”代码,我的反应开始是:这是否就是解决前端实现或者说架构最优的选择呢?可惜的是,我在Stackoverflow和Delicious上没有找到相似的讨论,倒是发现了很多对于JavaScript MVC的讨论。

以下是我自己的一点想法:

前端代码用ExtJS或者Dojo这样的rich library构建,用程序员惯常的面向对象思维和成熟的MVC架构来实现,无可厚非。但实现的过程与前端页面的渲染并无简单直接的对应关系。程序员在用熟悉的建模和框架时,不会简单地推演出到正在实现的控件及其行为在页面渲染后将以怎样的结果出现。这里需要框架自身的技术支撑和程序员对框架的理解,框架加载脚本的顺序、对MVC实现的风格,不一而足。

浏览器是从页面的开头到结束完成页面的渲染,中间包括脚本的同步或异步的加载,包括框架对于富UI控件的渲染。在页面初始渲染成功后,由框架接手完成未来发生的所有的UI交互,直至页面重新刷新。

如果把浏览器页面的渲染结果,或浏览器内存中的DOM看作是结构、样式和数据的存储,类似于关系型数据中逐行的数据,这与前端实现所采用的面向对象和MVC相对应,同样存在模式的不匹配,即阻抗失配。

不同的是,程序员不用太关心数据库如何存储数据,但不得不清楚不同浏览器如何渲染页面,及框架如何完成帮助后续的交互。

Share
 

this in Selenium’s get_eval() method

At Selenium Ruby site, there is a description for method get_eval(script), as following:

Gets the result of evaluating the specified JavaScript snippet. The snippet may have multiple lines, but only the result of the last line will be returned.

Note that, by default, the snippet will run in the context of the “selenium” object itself, so this will refer to the Selenium object. Use window to refer to the window of your application, e.g. window.document.getElementById(‘foo’) If you need to use a locator to refer to a single element in your application page, you can use this.browserbot.findElement("id=foo") where “id=foo” is your locator.

The special thing here is the this reference, means when invoking method get_eval() to run some javascript snippet, the this reference in snippet would refer to (redicted?) caller Selenium object but not the original belonging object.

This does differ from what we already know for window.eval() method, in which javascript snippt this still refer to the original belonging object, see below demo code:

var a = 0;
window.eval("this.a = 1"); // this refers to window object
alert(a); // a=1
alert(this.a == a) // true

Above code demos this is window object itself.

function A(){};
A.prototype = {
  f1: function(){
    return "f1";
  },
  f2: function(){
    alert(this.f1());
  }
}
var a = new A();
window.eval("a.f2()"); // equals to a.f2(), this in f2 refers to a.

Above code demos this in a.f2() method still refers to a, but not window object.

Generally, eval() is an evil thing.

Share
 

Automation Training For TW QA

今天作为酱油党之一(徐X语,还有小刀和LeoShi同行)参加了徐X为TW QA开的Automation Training。

对于Ruby小白的我,跟着QA一起学了一把。

  • Ruby的包机制,应用的配置环境
  • Selenium RC的原理,包的四个变种。
  • 在07年就提到过的Page Object

自动化测试具备怎样的特质,才能最大限度的减少QA手工测试的工作量?

  1. Effective
  2. QA manageable

最后,徐X介绍了几个月前他研究出的Data Flow大法。简言之,测试不是要去测试事情本身,而是要测试事情结果的确发生。听着象废话,但那张精美手绘图却惊艳得不行。用以作为切分并归纳测试案例的依据。很受用,争取撺掇一篇文章出来。

Share