mobl:针对移动Web开发的DSL

本文涉及的产品
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
简介:   简介  现在,针对移动设备像智能手机和平板电脑的应用开发很流行。Apple公司的AppStore(针对iPhone、iPod和iPad)拥有超过350,000种应用,而Android的marketplace也快速追赶上来,现在已经拥有超过200,000种应用。

  简介

  现在,针对移动设备像智能手机和平板电脑的应用开发很流行。Apple公司的AppStore(针对iPhone、iPod和iPad)拥有超过350,000种应用,而Android的marketplace也快速追赶上来,现在已经拥有超过200,000种应用。然而,Android和iOS并非是仅有的两种移动平台。BlackBerry也是有力的竞争者,此外还有Nokia。最近Microsoft发布了Windows Phone 7,HP也发布了新的WebOS设备。这样,对于用户来说有了多种选择,但对我们这些开发者来说却是个噩梦。我们应该针对哪种平台来开发应用程序呢?

  在移动平台之间共享代码极度困难。每种平台都选择了自己的开发框架,还有自己的语言和API。对于iOS开发,你需要使用Objective-C和CocoaTouch API;对于Android开发,你要使用Java和Android API;对于Windows Phone 7,你需要使用.NET和Silverlight API。

  然而,我们还是拥有一种解决方案:Web开发,特别是:Webkit。我们会看到,所有主要的移动平台供应商(除了Microsoft之外)都在Webkit之上构建了他们的移动浏览器,而Webkit是当前最新的、速度最快的开源浏览器引擎。Webkit支持多种移动应用所需要的HTML5 特性,包括侦测触摸手势(轻击、强击和缩放)、定位API(确定用户的位置),并且支持本地数据库(浏览器中的SQLite数据库,用于在本地缓存数据)。

  当前,在Android、iOS、WebOS以及BlackBerry OS的六款浏览器中,都对这些特性提供了本地支持。对于不包含基于Webkit的浏览器的设备,我们还可以使用PhoneGap。PhoneGap让我们可以使用web技术(包括HTML5)开发本地应用程序,并把应用程序包装成为本地应用程序,那样就可以分发给用户了(例如,通过平台的应用程序市场)。如果平台还没有内建的WebKit浏览器,那么PhoneGap就会为其提供。PhoneGap应用程序可以在六种不同的移动平台上运行。

  JavaScript框架厂商注意到了这是个机会,于是就构建了多种能够在移动Web上运行的框架。jQuery Mobile和Sencha Touch都是比较典型的例子。这些框架很容易给人留下深刻的印象,因为对于当前的开发者来说,使用它们来为移动网络开发应用程序是一种不错的方式。然而,它们还都是基于JavaScript、HTML和CSS的,它们的目的都不是要开发应用程序,而是要开发包含超链接文档的网络应用。各种框架试图对这些语言进行调整,从而适合他们的新角色,但是这会引起你的思考,专门为开发移动应用程序 而设计的语言应该是什么样子的呢?

  如果我们想要设计这样的一种语言,需要解决什么样的问题呢?

  • 首先要解决的就是工具的支持。从事企业级开发的开发者(比方说Java和.NET的开发者)习惯使用像Eclipse之类的IDE特性,像在键入的时候就能够突出显示错误、代码自动完成、引用解析、代码大纲以及重构等等。JavaScript和HTML在本质上就是动态的,这让它们很强大,但是也让工具厂商很难为其创建出Eclipse和InteliJ那种级别的IDE。对于当前所有语言来说,良好的IDE支持都是前提条件。
  • 第二个要解决的问题是简洁。例如,用户界面框架经常会包含大量类似的代码,它们的作用就是把数据从数据库中复制到用户界面,或者把界面上的数据复制回数据库。我们的新语言应该减少开发者所需要编写的样板化代码。
  • 第三个问题是JavaScript的异步编程模型。在浏览器中,JavaScript是单线程的,开发者需要使用回调机制来执行数据库查询之类耗费资源的操作,比方说,我们不会编写像下面这样的同步代码:
     
       
    var results = tx.executeQuery( " SELECT * FROM User " );
    for ( var i = 0 ; i < results.length; i ++ ) {
    ...
    }
    我们需要使用回调函数来编写代码:
     
       
    tx.executeQuery( " SELECT * FROM User " , function (results) {
    for ( var i = 0 ; i < results.length; i ++ ) {
    ...
    });
    当在大型应用程序中使用回调函数,就会导致编写出很难阅读的意大利面条式代码。我们的新语言应该支持对于开发者更友好的异步编程模型

  我们的研究小组(软件工程研究小组,位于荷兰代尔夫特理工大学)专注于编程的转换与实现。当前,我们主要专注于领域特定语言。对于当前移动领域的开发,我们觉得有一个很好的机会,可以为移动Web开发出一种领域特定语言。我们自问:如果从头开始的话,一门专注于开发移动Web应用程序的语言,应该是什么样子的呢? 结论就是mobl。

  mobl:从10,000英尺高处俯瞰

  mobl是一种文本式的、静态类型、编译的语言,主要是通过它的Eclipse插件应用。这个插件提供了语法高亮显示、内嵌的错误突出显示、引用解析以及代码自动完成。mobl编译器(集成在IDE中)会在每次保存的时候把mobl模块编译成HTML、JavaScript和CSS的组合。mobl应用程序不依赖于任何特定的服务端技术,而只会处理应用程序的客户端部分。我们可以使用AJAX的方式调用(JSON)Web服务。

  mobl语言有大量特性,目的都是为了提高移动开发者的生产率:

  1. 声明式的用户界面:使用mobl定义的用户界面是以一种声明式的方式指定的,并且会对应用程序状态的改变做出响应,这与其它方法不同,在那些方法中状态和视图是严格分离的。
  2. 透明的数据持久性:mobl拥有使用实体定义来定义数据模型的语言结构。对实体对象做出的变更会自动实体化到数据库中。对数据的查询也是在实体级别完成的,而并不需要字符串嵌入式的SQL查询,这和很多其它框架都是类似的。
  3. 原则上是静态的,在需要的时候可以是动态的:mobl语言是静态类型的语言,支持像错误突出显示、引用解析和代码自动完成等IDE特性。尽管如此,正如类型推论所说,在很多情况下我们不需要显式指定类型。有些情况下,动态类型更方便,我们可以使用Dynamic类型,从而可以对Dynamic变量的属性和方法进行任意地访问。
  4. 同步编写脚本:我们可以在脚本语言中编写应用程序的逻辑,那看起来和带有类型的JavaScript非常相似。代码是以同步的风格编写的,并且会由编译器使用持续传递的样式转换(continuation-passing style transform)将其自动转换为异步的JavaScript代码。

  简单的To-do列表

  为了真正了解mobl是什么样子的,我会在这个部分演示如何实现一个简单的to-do列表管理器。

  首先我们要在Eclipse中创建一个新的mobl项目,这样会得到mobl项目的基本框架,其中有唯一的应用程序文件,我们把它命名为todo.mobl

 
 
application todo

import mobl::ui::generic

screen root() {
header(
" todo " )
}

  这个mobl模块的第一行定义这是一个application模块。mobl有三种不同类型的模块:

  1. application模块:通常每个项目有一个,这是应用程序的主要入口点。
  2. regular模块:这是一个定义的库,通常会由一个或者多个其他(应用程序)模块导入。
  3. configuration模块(config.mobl):定义应用程序的配置选项。

  application和regular模块包含任意数量的定义:用户界面、数据模型、样式、web服务接口和函数等等。

  首先,让我们来使用entity定义来定义一个数据模型。实体的实例会持久化到移动设备本身的本地数据库中。我们的to-do应用程序只需要唯一一个实体,名称为Task。对于每个task对象,我们都希望能够记录它的名称,以及任务是否已经完成。

 
 
entity Task {
name : String (searchable)
done : Bool
}

  对于每个属性我们都会指定名称和类型,并有选择地加上一个或者多个注解。mobl支持两种类型的注解:inverse注解(定义反向的关系)和searchable(在全文搜索中包含字段)。尽管这个应用程序不需要,但我们还是可以指定多个实体以及它们之间的关系,包括一对一、一对多和多对多的关系。

  接下来,我们对root屏幕进行改写,从而显示我们能够勾选和取消勾选的任务列表。在mobl中,用户界面是用screencontrol定义的。通常screen会通过组合大量control来定义实体屏幕布局。这样,control会定义更小的用户界面元素,像按钮、标签和表格等等。此外,屏幕或者控件也能够定义本地状态(使用变量),并使用控件结构来对集合进行迭代,从而根据条件显示用户界面的各个部分。

  下面是我们的root屏幕的最初定义(当程序运行时所显示的第一个屏幕)。它使用了大量mobl::ui::generic库中的控件,包括header(渲染出屏幕的标题)、group(对一个或者多个item进行分组)和checkBox

 
 
screen root() {
header(
" Tasks " )
group {
list(t
in Task.all()) {
item { checkBox(t.done, label
= t.name) }
}
}
}

  list控件的结构与for-each循环类似:它会遍历一个集合,对于集合中的每个项目,它都会进行渲染。checkBox与两个Task对象属性绑定:donename。数据绑定会在应用程序状态(例如本地变量或者实体属性)和用户界面之间创造出同步的关系。例如,当用户选择复选框或者取消对它的选择时,t.done的值就会据此更新。类似地,当应用程序的某些其他部分更新任务tname属性时,复选框也会自动更新它的标签。这被叫做反应性编程(reactive programming),这也是根本的mobl特性之一:用户界面会对应用程序状态的改变做出反应

  最初时,数据库是空的,从而在我们的列表中不会显示任何任务。我们怎样才能添加任务呢? 为了这个目的,我们定义了addTask屏幕:

 
 
screen addTask() {
var newTask = Task()
header(
" Add " ) {
button(
" Done " , onclick = {
add(newTask);
screen
return ;
})
}
group {
item { textField(newTask.name, placeholder
= " Task name " ) }
}
}

  使用var结构我们可以创建嵌入在特定屏幕中的状态。在这种情况下,我们定义了变量newTask,并使用新建的Task实体实例对其进行初始化。我们把textField控件与newTasksname属性绑定。当用户输入完任务的名称时,他就会点击显示在应用程序标题处的Done按钮。按钮拥有名为onclick的参数,它的值是Callback,当事件发生的时候,就会执行一段命令式的应用程序逻辑。在这个特定的情况下,发生了两件事情:

  1. 向数据库添加了newTask对象。这会在后台对Task.all()集合做出改变,使得新建的任务被自动添加到root屏幕的list中。
  2. 然后用户会返回当初的屏幕(screen return和函数中的return类似)。

  然而,尽管我们定义了rootaddTask屏幕,但没有办法从一个屏幕跳转到另一个。我们需要做的就是向root屏幕添加一个Add按钮,它会带我们跳转到addTask屏幕。因此,我们需要在root中把对header控件的调用调整为下面这样:

 
 
header( " Tasks " ) {
button(
" Add " , onclick = { addTask(); })
}

  正如你所看到的,对屏幕的调用和对一般函数的调用类似,事实上,和函数一样,屏幕也能够返回值。

  现在我们的应用程序的功能已经基本完备。我们还要添加最后一个特性:搜索。在我们的数据模型中,我们对Taskname属性使用了(searchable)注解。利用,我们就可以使用搜索来过滤任务列表(从而更快地找到我们想要查找的任务)。

  我们需要把root屏幕调整为下面这样:

 
 
screen root(){

var phrase = ""
header(
" Tasks " ) {
button(
" Add " , onclick = { addTask(); })
}
searchBox(phrase)
group {
list(t
in Task.searchPrefix(phrase)) {
item { checkBox(t.done, label
= t.name) }
}
}
}

  我们向屏幕中添加了新的本地变量phrase,可以在其中存放查询的短语。我们使用searchBox,并将其与phrase绑定。然后,我们并没有遍历list中的Task.all(),而是遍历了搜索集合Task.searchPrefix(phrase)。在运行的时候,当我们在搜索查询中输入内容时,搜索结果的列表就会更新。此时用户界面会再一次根据应用程序的状态(这种情况下是phrase变量)自动调整。

  现在我们已经完成了包含搜索功能的基本to-do列表应用程序的构建工作,接下来可以部署了。当我们保存mobl模块的时候,同时也会把它们编译成JavaScript、HTML和CSS,这些文件位于Eclipse项目的www/目录下。我们可以把这些生成的文件部署到任意一个能够为静态文件提供服务的web服务器上(例如:Apache、IIS或者Tomcat),mobl完全不需要后端程序。

  To-do列表之外

  当然,to-do列表只是个玩具一样的例子,它只使用了一些简单的控件,像groupitembuttontextField。mobl的标准库还提供了一些高级的控件,像标签组、主从视图、上下文菜单以及可扩展的列表等等。

  除了定义用户界面、数据模型以及应用程序逻辑的语言结构之外,mobl还拥有以下结构:

  • 定义样式,在此它使用一种与CSS非常类似的语言。
  • 对Web服务的访问。从服务器拉入数据并缓存在本地。在将来,mobl还会支持透明的数据同步。

  想要了解这些特性,你可以查看mobl站点上的教程。

  使用DSL还是不使用DSL

  我们可以把mobl描述为一种领域特定语言(DSL),也就是一种针对特定应用程序领域的语言。在传统上,DSL的领域很有限。例如,HTML是一种定义结构化Web页面的DSL。SQL是用来解释数据库查询的DSL。移动应用程序的领域比上述要大得多。事实上,它非常大,以至于需要大量你通常只能在一般目的的语言或者GPL像Java、Python和Ruby中才能够找到的特性。这些典型的GPL特性包括面向对象编程、if指令和for循环等等。既然mobl拥有GPL特性,那么它还是一种DSL吗?

  我们觉得是,因为它拥有语言结构,这些结构都特别地适合数据驱动的移动Web应用程序领域。例如,如果我们使用一种带有样式支持的一般目的语言,编写的是用于处理科学计算的程序,那么就不太合理了。而把screen结构应用于服务端计算也不是很合理。像实体、屏幕、控件、样式以及Web服务等语言特性并不针对一般目的它们都是针对特定领域的。

  mobl不仅仅是针对移动开发的DSL。类似的还包括Applause和由此衍生的Applitude。然而,这些DSL的灵活性都有限。它们都拥有一系列的内建控件、内建函数,一旦这些都无法满足你的需求,你就需要重新使用Objective-C或者Java来编码了。mobl的目标就是,既要灵活,又要具备较强的表达能力。

  为了达到这个目的,我们让这门语言尽可能小,并且通过使用mobl本身编写库来增加功能。例如,我们用来构建to-do列表应用程序的控件都没有内建在语言之中。相反,它们都是从mobl库导入的,而这个库本身又是使用mobl定义的。在最低层级上,对控件的实现使用了低级的HTML标签和CSS样式。一般用户只会使用高级别的概念控件,像标题或者按钮等等,而专家级的开发者能够通过调整库中的底层HTML代码来精确地设计按钮的显示样式。

  mobl除了能够在库中定义控件之外,它还拥有暴露了大量HTML5 API的库,包括集合定位、使用Canvas进行2D绘图以及WebSockets等等。这些库只是封装了已存在的JavaScript API,而mobl API使用mobl的本地接口,这使得它能够调用本地JavaScript代码。这样,mobl就可以通过库机制进行扩展,这让用户可以扩展平台,而不需要扩展语言和编译器本身。

  在特定的情况下,mobl会为特定的库添加句法的特性。例如,对于查询,mobl暴露了Collection类型,它拥有对实体对象的集合进行过滤、排序和分页的方法。我们可以像下面这样来调用这些方法:

 
 
var doneTasks = Task.all().filter( " done " , " = " , true )
.order(
" date " , false ).limit( 10 );

  很明显,这些语法有些麻烦。因此,mobl为查询添加了句法特性,让我们可以把上面的查询写成这样:

 
 
var doneTasks = Task.all() where done == true
order by date desc limit
10 ;

  这不仅更加简洁,而且现在IDE可以检查事实上Task是否拥有donedate属性,并且提供了恰当的代码自动完成功能。

  结论

  mobl没有在已存在的语言基础之上构建框架,而是从头开始,构建了一种外部DSL。这种方法有优点也有缺点。缺点在于用户需要学习新语言、新库以及新的工具。优点在于,选择这种语言来进行设计,可以显著减少开发者所要编写的代码。在mobl中,我们保持它的语法与语义与JavaScript类似,从而让开发者觉得这种语言很熟悉。此外,mobl能够集成到现有的Eclipse IDE和外围工具中,提供在输入时检测错误、引用解析、代码自动完成和保存时编译等功能。

  mobl还是一种很年轻的语言。第一次公开发布是在2011年1月。它的编译器、工具和文档还在逐步完善中。尽管如此,我们觉得它已经显示出在移动领域使用DSL的潜力。

  英文原文:mobl: a DSL for Mobile Web Development

目录
相关文章
|
2月前
|
XML JSON API
ServiceStack:不仅仅是一个高性能Web API和微服务框架,更是一站式解决方案——深入解析其多协议支持及简便开发流程,带您体验前所未有的.NET开发效率革命
【10月更文挑战第9天】ServiceStack 是一个高性能的 Web API 和微服务框架,支持 JSON、XML、CSV 等多种数据格式。它简化了 .NET 应用的开发流程,提供了直观的 RESTful 服务构建方式。ServiceStack 支持高并发请求和复杂业务逻辑,安装简单,通过 NuGet 包管理器即可快速集成。示例代码展示了如何创建一个返回当前日期的简单服务,包括定义请求和响应 DTO、实现服务逻辑、配置路由和宿主。ServiceStack 还支持 WebSocket、SignalR 等实时通信协议,具备自动验证、自动过滤器等丰富功能,适合快速搭建高性能、可扩展的服务端应用。
158 3
|
1月前
|
设计模式 前端开发 数据库
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第27天】本文介绍了Django框架在Python Web开发中的应用,涵盖了Django与Flask等框架的比较、项目结构、模型、视图、模板和URL配置等内容,并展示了实际代码示例,帮助读者快速掌握Django全栈开发的核心技术。
171 45
|
15天前
|
前端开发 安全 JavaScript
2025年,Web3开发学习路线全指南
本文提供了一条针对Dapp应用开发的学习路线,涵盖了Web3领域的重要技术栈,如区块链基础、以太坊技术、Solidity编程、智能合约开发及安全、web3.js和ethers.js库的使用、Truffle框架等。文章首先分析了国内区块链企业的技术需求,随后详细介绍了每个技术点的学习资源和方法,旨在帮助初学者系统地掌握Dapp开发所需的知识和技能。
2025年,Web3开发学习路线全指南
|
22天前
|
存储 前端开发 JavaScript
如何在项目中高效地进行 Web 组件化开发
高效地进行 Web 组件化开发需要从多个方面入手,通过明确目标、合理规划、规范开发、加强测试等一系列措施,实现组件的高效管理和利用,从而提高项目的整体开发效率和质量,为用户提供更好的体验。
27 7
|
26天前
|
开发框架 搜索推荐 数据可视化
Django框架适合开发哪种类型的Web应用程序?
Django 框架凭借其强大的功能、稳定性和可扩展性,几乎可以适应各种类型的 Web 应用程序开发需求。无论是简单的网站还是复杂的企业级系统,Django 都能提供可靠的支持,帮助开发者快速构建高质量的应用。同时,其活跃的社区和丰富的资源也为开发者在项目实施过程中提供了有力的保障。
|
25天前
|
开发框架 JavaScript 前端开发
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势
TypeScript 是一种静态类型的编程语言,它扩展了 JavaScript,为 Web 开发带来了强大的类型系统、组件化开发支持、与主流框架的无缝集成、大型项目管理能力和提升开发体验等多方面优势。通过明确的类型定义,TypeScript 能够在编码阶段发现潜在错误,提高代码质量;支持组件的清晰定义与复用,增强代码的可维护性;与 React、Vue 等框架结合,提供更佳的开发体验;适用于大型项目,优化代码结构和性能。随着 Web 技术的发展,TypeScript 的应用前景广阔,将继续引领 Web 开发的新趋势。
35 2
|
1月前
|
前端开发 API 开发者
Python Web开发者必看!AJAX、Fetch API实战技巧,让前后端交互如丝般顺滑!
在Web开发中,前后端的高效交互是提升用户体验的关键。本文通过一个基于Flask框架的博客系统实战案例,详细介绍了如何使用AJAX和Fetch API实现不刷新页面查看评论的功能。从后端路由设置到前端请求处理,全面展示了这两种技术的应用技巧,帮助Python Web开发者提升项目质量和开发效率。
52 1
|
1月前
|
XML 安全 PHP
PHP与SOAP Web服务开发:基础与进阶教程
本文介绍了PHP与SOAP Web服务的基础和进阶知识,涵盖SOAP的基本概念、PHP中的SoapServer和SoapClient类的使用方法,以及服务端和客户端的开发示例。此外,还探讨了安全性、性能优化等高级主题,帮助开发者掌握更高效的Web服务开发技巧。
|
1月前
|
安全 数据库 开发者
Python Web开发:Django框架下的全栈开发实战
【10月更文挑战第26天】本文详细介绍了如何在Django框架下进行全栈开发,包括环境安装与配置、创建项目和应用、定义模型类、运行数据库迁移、创建视图和URL映射、编写模板以及启动开发服务器等步骤,并通过示例代码展示了具体实现过程。
59 2
|
2月前
|
设计模式 测试技术 持续交付
开发复杂Web应用程序
【10月更文挑战第3天】开发复杂Web应用程序
44 2
下一篇
DataWorks