DSL的演進(轉 infoQ)

閱讀: 235 評論: 0 做者: 周 金根 發表於 2010-05-19 13:39 原文連接php

     

< AddThis Button END >

簡介

領域特定語言(DSL) 是針對特定問題領域的編程語言,而非通用語言。要建立「不重複本身」(Don't Repeat Yourself)、「業務用戶可讀」的代碼,DSL但是個好方法。在過去的幾年裏,有關DSL的文章比比皆是。html

建立一種領域特定語言並不是難事。但咱們對領域的理解老是不斷深刻,要讓DSL長期有用,咱們就須要一種不斷完善DSL的策略。若是你正在開發一個大型項 目,或是一條軟件產品線(SPL), 在很長一段時間內都須要使用DSL的話,那你最好考慮清楚該如何處理DSL的演進。ruby

從藉助版本化實現的向後兼容性,到語句的自動轉換,本文將着眼於不斷簡化DSL演進過程的DSL構建方法。架構

避免問題

在第三代編程語言(3GL)的世界裏,語言設計者很是清楚向後兼容性的重要性。不管Java的下一個版本會有哪些變化,都不太可能破壞先前版本中添加的任 何功能。不過使用DSL時,隨着咱們對問題空間的進一步探索,咱們對領域的理解會發生完全改變。在單獨項目中,業務專家每每會在後期提出新的領域概念,這 就迫使你要追根溯源,從新考慮怎樣才能最好地爲領域建模。軟件產品線裏的每一個新項目都會帶來不一樣的需求,這些需求則會對DSL的優化設計產生影響。app

過去,咱們始終建議你們在進行領域特定建模(DSM)時,只有在業務規則頻繁變化、而領域結構卻相對穩定時再引入DSL(兩個條件分別是爲了提升開發 DSL及其相關工具的投資回報率,減小改進DSL結構時遇到的問題),從而減小這些問題。不過DSL如今應用得愈來愈普遍,理解與DSL演進相關的問題、 處理這些問題的一些策略就很是重要了。dom

問題是什麼?

有些類型的DSL演進根本不是問題。若是你想增長一個新的領域概念,或是給概念新增一個可選特性【譯註】,你只用擴展DSL語法就能夠了,而這並不會破壞任何已有的代碼。但在有些狀況下,你必須考慮語法的這些變化會對已有的語句產生什麼影響。這些狀況有:eclipse

  • 刪除一個概念或特性
  • 添加一個特性,不一樣語句須要的特性值可能會有所不一樣
  • 將特性連同其子特性轉變爲一個獨立的概念
  • 增長一項新的約束,而已有的語句可能並不知足該約束

抽象語法(Abstract Grammar)vs. 具體句法(Concrete Syntax)

有一個重要的DSL概念能讓接下來的討論稍微簡單一些,那就是抽象語法和具體句法之間的差別。DSL的抽象語法描述了有效語句的結構,也包括全部相關的約 束。具體句法則描述瞭如何在DSL中正確編寫語句的細節問題。編程語言

舉例來講,假設有一個描述狀態機的DSL,它可能包括一個這樣的概念:一個對象能有多個狀態。抽象語法只能傳達「一個對象能有多個狀態」,(還有全部的約束,好比每一個對象至少要有一個狀態、給定對象的每一個狀態都應該有惟一的名稱)。具體句法則多是建模工具裏的圖、XML文檔、GroovyRuby這些DSL自己的代碼、電子表格、基於DSL的數據庫 Schema,或者是自定義的文本句法。儘管在特定的具體句法中對DSL的某些內容做出改進會更具備挑戰性(好比處理與圖形化語言相關的位置和圖形數據),但咱們仍是要着眼於抽象語法,來討論大部分問題和DSL演進帶來的影響,要明白表述語句的具體句法只是個次要問題。

進行DSL演進的方法

在已經有DSL語句的系統中,進行DSL演進的常見方法有三個:

  • 依靠向後兼容
  • 語言進行版本化
  • 自動進行語句轉換

向後兼容性

解決問題最簡單的方法就是迴避問題。對DSL語法的修改堅定不能破壞已有語句。人們使用DSL一段時間後,每每會演進DSL語法,卻不關心修改是否會破壞已有的語句。最終,用例會在這些演進的地方忽然出現問題。

語言版本化

對於可能會破壞已有語句的DSL演進來講,最快捷的解決辦法是對DSL進行版本化。不管你使用的是某種內部DSL的內置分析,仍是「外部DSL+顯式的解 析器」(或許是ANTLRXtext,也多是使用XML具體語法時用到的XML解析器), 當你須要作重大更改時,你只用發佈解析器的新版本、確保你的系統支持多版本,在語句須要利用後續版本中可用的擴展語法時,只要更新語句就能夠了。這個方法 在必定程度上能夠說是至關不錯的,但對語言多版本進行維護、支持、調試的開銷最終會變得難以承受。

語句轉換自動化

理想的解決辦法是能對DSL語句進行自動演進,只要你修改了語法,(若是可能)語句就能夠自動更新。最簡單的處理方法之一就是將轉換應用到語法,而後使用 腳本語言或是XSLT、ATLAS這種容許模型到模型(M2M)轉換的語言編寫腳本,將一樣的改變運用於DSL語句。

轉換示例

假設咱們使用XML這一具體句法來描述應用中領域對象的DSL。最初,咱們可能有兩個領域類——User和Product,如清單1所示。

清單1:User和Product領域對象的XML句法。

 

很快,咱們決定添加Property的概念,並且每一個domainObject能夠有0到n個屬性。這個轉換並不會破壞現有的語句。它只涉及「添加概念」 和「添加可選關係」,也就是說,咱們增長了一個新的概念——屬性,以及一個新的可選關係(每一個領域有n個屬性,但屬性並非必需的)。清 單2是帶有Property概念的語句:

清單2:帶有屬性的領域對象。

  
 
  




 






如今再添加一條——屬性能夠有一條驗證規則。這樣我 們就有了「添加可選特性」的轉換,這裏咱們要爲屬性添加可選的「validationRule」特性。一樣,因爲特性是可選的,先前的語句仍然有效,因此 對語法應用了這一轉換以後,咱們並無破壞當前的DSL語句,也就不須要對語句作什麼處理了。

比方說咱們就這樣工做了一段時間,XML最終就像清單3所顯示的那樣。

清單3:帶有驗證規則的領域對象屬性。

  
 
  




 






不過如今咱們意識到,有些狀況下,咱們要爲一個屬性 關聯多個驗證規則。這一問題有不少解決辦法。讓咱們看看其中之一。首先,咱們能夠只改變validationRule,使其成爲以逗號分隔的驗證規則列 表。這一變動不須要對現有語句進行任何修改(假設當前全部的驗證規則中都沒有逗號)。但語言中會出現容易讓人誤解的特性,由於 validationRule支持以逗號分隔的規則列表並非很容易理解。

接下來可能會採用的轉換是「爲特性重命名」。將validationRule重命名爲validationRuleList,你會有一個從語義上來講更有意義的特性名稱。要作到這一點,你要有方法將這類轉換應用於已有的語句。最佳方法因使 用的具體句法而不一樣,但XML具體句法(或是任何能與XML工程互相轉換的內容)要作到這點仍是相對容易的,這只是舉了個例子。

咱們繼續擴展應用,不幸的是咱們發現驗證規則須要更復雜的參數。例如咱們有一個規則,用戶在網站上註冊時密碼和確認密碼必須匹配。這個驗證規則能夠寫成清單4所示的XML片斷。

清單4:帶有密碼和確認密碼屬性的驗證規則。

  
 
  
firstPropertyName="Password" secondPropertyName="PasswordConfirmation" />

咱們如今的問題是要將「特性應用到關聯的概念轉換上 去」。讓咱們分析一下。首先,這個特性要「轉換概念」,由於咱們將validationRule做爲屬性使用,而如今要替換爲單獨的 validationRule概念,這一律念在XML具體語法中用單獨的XML元素表示。這個特性還要「轉換爲關聯的概念」,由於我決定在 語言裏用獨立的片斷來描述這些規則,而這些規能被不一樣的屬性重用。舉例來講,若是FirstName和LastName都是必需的屬性,那它們就能夠用同 一個「Required」驗證規則。更適合這些狀況的替代方法是使用「轉換爲組合概念的特性」——每一個屬性能夠包含規則。

XML片斷使用「組合概念」的特性會是清單 5所示的樣子。

清單5:帶有「組合概念特性」的領域對象。

  
 
  






 










清單6顯示了使用轉換爲關聯概念的特性後,XML的樣子。

清單6:帶有「關聯概念特性」的領域對象。

  
 
  







 










一樣,這些轉換均可以自動應用於已有的DSL語句。

自動化的侷限性

固然,有一些轉換是不能自動進行的。當你想應用「刪除概念」或「刪除特性」的轉換時,你使用的工具頗有可能會自動掃描已有的語句,但不管你是必須基於轉換腳本提供的報告進行手工修改,仍是不得不使用「deprecate」來代替「刪除」轉換,每當工具發現這些條目,不讓你添加新條目、卻又不會強迫你移除那些條目時,這些工具可能都會讓你以爲至關痛苦。

一樣的,若是你想用「添加必要特性」的轉換爲全部屬性添加一個數據類型特性的話,除非你能給出缺省值(沒特殊說明就是字符串)或一些智能的腳本規則,不然自動化工具最好能提供一個高效的UI,能爲歷史語句填充全部的條目。

內部DSL vs. 外部DSL

認識到內部DSL的侷限性是很重要的。在「最終用戶可讀性」方面,內部DSL提供了不少好處,不過對於那些使用某種語言內置DSL編寫的語句來講,自動應用轉換一般會比較棘手。內部DSL很好,但你要是在大型項目或軟件產品線中普遍使用這些內部DSL的話,就要確保你要有一個將轉換應用到這些DSL上的策略。不然在項目的生命週期裏,爲外部DSL建立工具所花的那點兒時間與使用內部DSL相比來講可能更划得來。

結論

本文最重要結論的是,只要你的DSL是成功的,那你最終會有許多使用這些DSL的語句。要真是這樣,若是你確實須要演進你的DSL,你最好是有一個處理這些語句轉換的策略。

此外,認識到這個問題尚未解決也很重要。這一領域還須要不少工做要作,除了來自MetaCase的MetaEdit+以外,大部分領域特定建模工具都不能很出色地處理元模型演進。

引用

關於做者

Peter Bell是SystemsForge的 CEO兼CTO。他開發了生成自定義Web應用的軟件產品線,該產品線融合了特徵建模、產品線工程和領域特定建模。他的文章和演講遍及全球,內容涉及領域 特定建模、代碼生成、精益/敏捷開發,以及Groovy和CFML等JVM上運行的動態腳本語言。他的Blog爲:http://appgen.pbell.com/

查看英文原文:DSL Evolution

評論: 0 查看評論 發表評論

滬江網招聘ASP.NET開發工程師


最新新聞:
· 谷歌收購廣告公司Invite Media(2010-06-02 22:16)
· AT&T擬推新數據計劃 iPad 3G用戶再也不享有無限(2010-06-02 21:36)
· 支持ARM架構:新版嵌入式Windows 7 CTP發佈(2010-06-02 19:51)
· Apple的平臺之路(三)(2010-06-02 19:27)
· Ubuntu 10.04可支持iPhone(2010-06-02 18:14)

編輯推薦:關於Java與.NET的討論

網站導航:博客園首頁  我的主頁  新聞  閃存  小組  博問  社區  知識庫

相關文章
相關標籤/搜索