我为何想而且要学习Scala

为何学习函数式编程

在阅读DDD巨著《Patterns, Principles, and Practices of Domain-Driven Design》的过程当中,Scott在第5章提到了使用函数式编程语言配合贫血模型去实践DDD的一种思路,这激发了个人无限遐想。html

在软件开发领域,咱们已经拥有了许多的抽象方法论和大量的实现技术。但我我的认为,这一切归根结底,都是人类思惟在软件开发领域的具体表达方式。而人类在认识和分析软件所要解决的业务领域问题时,思考的内容不外乎由两个部分组成:『业务流程』『业务规则』。前者,回答了业务活动中先作什么后作什么的问题;后者,则回答了遇到什么状况时应该怎么作的问题。二者结合后,获得咱们须要的业务结果,或者叫做“实现业务目标”。java

再想一想目前学习和掌握的面向对象的一系列方法,又是如何将上述思惟结果映射到软件中去的呢?我认为是这样的:git

  • 对于业务流程,咱们将其表达为若干对象之间的合做,好比UML里序列图的对象与消息,进而具化为具体的类及其职责,好比类及其若干业务方法。
  • 对于业务规则,咱们将其表达为若干的判断逻辑,好比UML流程图里的判断分支,进而具化为业务方法里的if-else语句,或者再复杂一点,表达为工厂、策略等设计模式的实际运用。

而后,我认为,对于复杂业务规则的梳理,能够象数学概括法同样进行演绎:假设一个函数y=f(x),给定x的定义域,肯定y的值域。特别是在排列组合等方面的一些问题,也常常采用递归的方式来解决。因此,从这个角度讲,函数式编程更贴近人类思惟习惯,因此让我天然而然地把目光转向了它。github

为何选择Scala

在选择具体的函数式编程语言时,我首先想到的是它最好是同时能支持面向对象编程的。由于即使LISP做为函数式编程语言的先祖,诞生已长达半个世纪,但单纯的函数式编程语言与面向对象编程语言相比,在抽象领域概念、组合系统模块、实现信息隐蔽等方面存在必定的差距,因此一直没有成为软件开发的主流。正则表达式

信息隐蔽原理:在西安电子科大蔡希尧与陈平老师于1993年合做出版的《面向对象技术》一书中是这样描述的:把需求和求解的方法分离;把相关信息——数据结构和算法,集中在一个模块之中,和其余模块隔离,它们不能随便访问这个模块内部的信息。算法

其次,因为个人语言路线是从Pascal → C → C++ → C#,因此我但愿能选择一种风格近似于C、强类型的函数式编程语言。在比较了F#、R、ErLang等几种常见的函数式编程语言以后,我最终选择了Scala。编程

Scala有何优点

注:如下内容,节选翻译或参考自《Programming in Scala》第1章、第3章,《Programming Scala》第6章,不算完整意义上的我的心得。设计模式

函数式编程的优点

  • 纯的函数是没有反作用的。不管什么时候何地,对于一个函数y=f(x),给定x一定获得y,不会所以产生二义结果。所以不管对于代码测试仍是并发,因为给定输入一定获得预期输出,而不受其余因素干扰,因此能有效减小Bug产生。
  • 在函数式编程里,大量使用immutable的值。这意味着函数运算的结果总会建立一个新的实例,避免了一般并发环境下为防止数据共享冲突而采起的保护机制。尽管这须要额外的Copy操做,但Scala针对性地提供了高效的Copy实现,以及延迟计算等弥补机制。
  • 函数是一等公民。函数做为表达式的一部分,能够借由函数之间的嵌套、组合,实现复杂的判断逻辑。

Scala语言自己的优点

  • Scala是面向对象与函数式编程的混合语言,因此能有效结合两者的优势。
  • Scala属于Java生态圈,能够在JVM平台上与Java一块儿编译运行,因此许多Java的框架、工具均可以直接应用于Scala语言编写的项目。
  • Scala视一切数据类型皆为对象,且支持闭包、lambda、by-name参数等特性,语法简洁明快。
  • Scala使用Actor做为并发模型,与Akka框架天然契合。这是一种区别于传统的、基于数据共享、以锁为主要机制的并发模型,其特色在于以Actor为基本单位、没有数据共享、基于消息传递实现Actor之间的协做,所以能够有效避免死锁、减小竞争。
  • 最后,若是有朝一日要转向大数据领域,有Spark这样的大型框架做为支撑。知乎:与 Hadoop 对比,如何看待 Spark 技术?

Scala对实践DDD有何意义

说了那么多,个人根本目的仍是要将Scala做为实现DDD的主要武器。那么试想一下,Scala在咱们实现DDD的过程当中能有哪些帮助呢?我暂且胡侃乱诌以下:数据结构

  • 表示值对象、领域事件等元素更直观。值对象、领域事件在DDD里都应该是immutable的,以往多采起POCO形式表示,如今改用Scala里的val以及case class表示,在语法层面就直观地代表是不可修改的。
  • 在类的方法层面实现CQRS时有语法支持。用Scala里的Function(返回类型为非Unit)对应CQRS里的Query,保证类的方法没有反作用;用Procedure(返回类型为Unit)对应CQRS里的Command,明确代表这一类方法会产生修改状态等反作用。这一样从语法层面就能对两者进行明确区分。
  • 模式匹配丰富了函数操做。除了正则表达式,Scala形式多样的模式匹配语法,为提取数据、完成数据分组聚合等运算、实现逻辑判断提供了强大支持。好比定义def sum_count(ints:Seq[Int) = (ints.sum, ints.size)这样一个函数后,咱们能够这样调用,以获得一个1至6的整数序列的整数值合计,及该序列的尺寸: val(sum, count) = sum_count(List(1, 2, 3, 4, 5, 6))
  • 为实现DSL提供有力支持。Scala自带有解析框架,加上灵活的函数语法支持,要本身实现一套DSL及其相应的语法解析器将再也不困难。好比在配置文件里这样的一条配置语句,表示退休条件为年龄达到60周岁或者工龄届满30年:retire = (Age >= 60) || (ServiceLength >= 30)。以往的方式是本身写一个语法解析器,把这条文本转换成相应的Specification对象,而后扔给聚合去使用。如今有了Scala的帮助,就使编写语法解析器这一环节的工做量大大减小。
  • 合理的高阶函数设计,使规则编写获得简化。好比打折规则、费用报销规则,以往可能须要若干层的if-else嵌套,如今则将经过高阶函数获得大幅简化。对此,我强烈推荐刘光聪先生的视频Refactoring to Functions,你会在刘先生的重构过程当中发现高阶函数的强大。
  • Actor为高效并发打下基础。Actor内部彻底自治,自带用于存储消息的mailbox,与其余Actor只能经过消息进行交互,每一个Actor都是并发的一个基本单位。这些特色,很是适合于采起Event Sourcing方式实现的DDD。每一个聚合都比如一个Actor,在聚合内部始终保持数据的强一致性,而在聚合之间交互的领域事件则比如Actor之间的消息,聚合之间借由领域事件和Saga保证数据的最终一致性。
  • Trait成为AOP利器。Trait是Scala的另外一大特点,它就象AOP织入同样,能动态地给某个类型注入方法或者结构。好比配合类Circuit和with后面那4个Trait的定义,val circuit = new Circuit with Adders with Multiplexers with Flipflops with MultiCoreProcessors这样就建立了一个带有加法器、乘法器、触发器和多核处理器的元件。
  • 隐式实现为类型扩展提供支持。对应C#里的静态扩展方法,Scala经过implicit为实现数据类型的方法扩展提供了便捷,成为Trait以外的另外一个功能扩展手段。
  • 能下降常见BDD框架的学习成本。尽管这一点可能比较牵强,但我正在努力摸索如何将BDD与DDD结合,而常见的Cucumber、Spock等一些BDD框架,其语法与Scala比较相近,因此我才有如此一说。

有哪些Scala学习资料

如下是我目前主要的学习资料,并衷心欢迎各位留言补充。闭包

书籍

  • Programming in Scala:由Scala语言的设计师Martin Odersky编写,按部就班,配合了大量实例,入门必读吧。
  • Programming Scala:视角与上面那本有点不同,没有Scala语言基础会感受很困难,适合掌握了基本语法后温故而知新。

在线文档与视频

社区

  • Scala 中文社区:不算活跃,缘由你懂的。
  • Scala User:Scala入门者汇集地,没有Stack Overflow那么严格,但也须要点爬墙的身手。

SDK及IDE

写在最后

最近读的书不少也很杂,DDD、BDD、Scala、Cucumber以及Java基础等等都有涉及,真巴不得一口吃成个大胖子。因为时间和精力有限,因此如今知识消化很成问题,迟迟没有进入学以至用的环节,只能先这样纸上谈兵了,好歹先把本身在学习过程当中的一些思考、看到的好东西先记载下来,以备未来之需。

相关文章
相关标签/搜索