我爲何想而且要學習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基礎等等都有涉及,真巴不得一口吃成個大胖子。因爲時間和精力有限,因此如今知識消化很成問題,遲遲沒有進入學以至用的環節,只能先這樣紙上談兵了,好歹先把本身在學習過程當中的一些思考、看到的好東西先記載下來,以備未來之需。

相關文章
相關標籤/搜索