Web框架正如前面所说,当我们选择Spray作为REST框架时,完全可以选择诸如AngularJS或者Backbone之类的JavaScript框架开发Web客户端。客户端能够处理自己的逻辑,然后再以JSON格式发送请求给REST服务端。这时,我们将模型视为资源(Resource),视图完全在客户端。JS的控制器负责控制客户端的界面逻辑,服务端的控制器则负责处理业务逻辑,于是传统的MVC就变化为VC+R+C模式。这里的R指的是Resource,而服务端与客户端则通过JSON格式的Resource进行通信。 若硬要使用专有的Web框架,在Scala技术栈下,最为流行的就是Play Framework,这是一个标准的MVC框架。另外一个相对小众的Web框架是Lift。它与大多数Web框架如RoR、Struts、Django以及Spring MVC、Play不同,采用的并非MVC模式,而是使用了所谓的View First。它驱动开发者对内容生成与内容展现(Markup)形成“关注点分离”。 Lift将关注点重点放在View上,这是因为在一些Web应用中,可能存在多个页面对同一种Model的Action。倘若采用MVC中的Controller,会使得控制变得非常复杂。Lift提出了一种所谓view-snippet-model(简称为VSM)的模式。 View主要为响应页面请求的HTML内容,分为template views和generated views。Snippet的职责则用于生成动态内容,并在模型发生更改时,对Model和View进行协调。 大数据大数据框架最耀眼的新星非Spark莫属。与许多专有的大数据处理平台不同,Spark建立在统一抽象的RDD之上,使得它可以以基本一致的方式应对不同的大数据处理场景,包括MapReduce,Streaming,SQL,Machine Learning以及Graph等。这即Matei Zaharia所谓的“设计一个通用的编程抽象(Unified Programming Abstraction)。 由于Spark具有先进的DAG执行引擎,支持cyclic data flow和内存计算。因此相比较Hadoop而言,性能更优。在内存中它的运行速度是Hadoop MapReduce的100倍,在磁盘中是10倍。 由于使用了Scala语言,通过高效利用Scala的语言特性,使得Spark的总代码量出奇地少,性能却在多数方面都具备一定的优势(只有在Streaming方面,逊色于Storm)。下图是针对Spark 0.9版本的BenchMark: 由于使用了Scala,使得语言的函数式特性得到了最棒的利用。事实上,函数式语言的诸多特性包括不变性、无副作用、组合子等,天生与数据处理匹配。于是,针对WordCount,我们可以如此简易地实现: file = spark.textFile("hdfs://...")file.flatMap(line => line.split(" ")) .map(word => (word, 1)) .reduceByKey(_ + _) 要是使用Hadoop,就没有这么方便了。幸运的是,Twitter的一个开源框架scalding提供了对Hadoop MapReduce的抽象与包装。它使得我们可以按照Scala的方式执行MapReduce的Job: class WordCountJob(args : Args) extends Job(args) { TextLine( args("input") ) .flatMap('line -> 'word) { line : String => tokenize(line) } .groupBy('word) { _.size } .write( Tsv( args("output") ) ) // Split a piece of text into individual words. def tokenize(text : String) : Array[String] = { // Lowercase each word and remove punctuation. text.toLowerCase.replaceAll("[^a-zA-Z0-9\\s]", "").split("\\s+") }} 测试虽然我们可以使用诸如JUnit、TestNG为Scala项目开发编写单元测试,使用Cocumber之类的BDD框架编写验收测试。但在多数情况下,我们更倾向于选择使用ScalaTest或者Specs2。在一些Java开发项目中,我们也开始尝试使用ScalaTest来编写验收测试,乃至于单元测试。 若要我选择ScalaTest或Specs2,我更倾向于ScalaTest,这是因为ScalaTest支持的风格更具备多样性,可以满足各种不同的需求,例如传统的JUnit风格、函数式风格以及Spec方式。我的一篇博客《ScalaTest的测试风格》详细介绍了各自的语法。 一个被广泛使用的测试工具是Gatling,它是基于Scala、AKKA以及Netty开发的性能测试与压力测试工具。我的同事刘冉在InfoQ发表的文章《新一代服务器性能测试工具Gatling》对Gatling进行了详细深入的介绍。 ScalaMeter也是一款很不错的性能测试工具。我们可以像编写ScalaTest测试那样的风格来编写ScalaMeter性能测试用例,并能够快捷地生成性能测试数据。这些功能都非常有助于我们针对代码或软件产品进行BenchMark测试。我们曾经用ScalaMeter来编写针对Scala集合的性能测试,例如比较Vector、ArrayBuffer、ListBuffer以及List等集合的相关操作,以便于我们更好地使用Scala集合。以下代码展示了如何使用ScalaMeter编写性能测试: import org.scalameter.api._object RangeBenchmarkextends PerformanceTest.Microbenchmark { val ranges = for { size <- Gen.range("size")(300000, 1500000, 300000) } yield 0 until size measure method "map" in { using(ranges) curve("Range") in { _.map(_ + 1) } }} 根据场景选择框架或工具比起Java庞大的社区,以及它提供的浩如烟海般的技术栈,Scala技术栈差不多可以说是沧海一粟。然而,麻雀虽小却五脏俱全,何况Scala以及Scala技术栈仍然走在迈向成熟的道路上。对于Scala程序员而言,因为项目的不同,未必能涉猎所有技术栈,而且针对不同的方面,也有多个选择。在选择这些框架或工具时,应根据实际的场景做出判断。为稳妥起见,最好能运用技术矩阵地方式对多个方案进行设计权衡与决策。 我们也不能固步自封,视Java社区而不顾。毕竟那些Java框架已经经历了千锤百炼,并有许多成功的案例作为佐证。关注Scala技术栈,却又不局限自己的视野,量力而为,选择合适的技术方案,才是设计与开发的正道。 作者简介
|