面向領域專家的語言,而不僅僅是程式設計師的語言

banq發表於2024-10-25

特定領域專家使用的程式語言,而不僅僅是為程式設計師設計的。這些語言可能旨在幫助領域專家(如生物學家、物理學家、金融分析師等)更有效地進行資料分析、建模和自動化任務,而無需深入瞭解程式設計的複雜性。

當 DSL 與問題領域緊密結合時,可以實現更好的結果——將抽象提升到程式碼之外。此類語言可以促進協作,使領域專家能夠驗證和確認他們的設計,並且在許多情況下,允許生成程式碼、配置、測試、報告等。

例子
讓我用醫學領域的一個例子來說明這一點。想象一臺設計用於透過混合過程製造定製藥物的機器。這臺機器有一個沿著傳送帶移動的針頭,三個用於在混合過程中在內部振動杯中混合的成分的輸入杯,以及兩種可在使用成分時使用的過濾器。有時,針頭也需要清潔。

在這種情況下,作為領域專家的醫生、護士或實驗室技術人員可以這樣描述某種特定藥物混合過程的一部分:“用過濾器 A 從第二個杯子中取出 5 個單位,將 2 個單位放入 6 號杯子中,將 3 個單位放入 7 號杯子中,然後清潔針頭。”

move(-3); filt(1); suck(5); 
move(4); filt(0); blow(2); 
move(1); blow(3); 
move(-3); suck(30);
move(1); blow(30);

語言是否解決了問題領域?
這種文字 DSL 只有四種命令型別,與傳統程式語言相比,它簡單明瞭,明顯提高了抽象程度。 但是,它仍有侷限性。 例如,它要求使用者記住指標的位置並手動計算要移動的單位。

更糟糕的是,這種 DSL 允許建立毫無意義甚至危險的混合過程,例如:
suck(10); move(-3); suck(5);    /* => 在針頭上塗抹清潔液 */ 
suck(10); move(6); blow(10);     /* => 成藥含有清潔液 */

類似的問題還有很多:
比如用清潔液毀壞過濾器、針頭撞上安全快門、在針頭中仍含有藥物時清洗針頭,甚至指定一個永遠不會產生任何有效藥物的混合過程。

這種語言在很大程度上忽略了問題領域。 雖然我們可以期望測試能發現上述問題,但其中有些問題需要特定領域的知識。例如,我們能否在向內部杯子新增配料時應用過濾器,還是隻應用於輸出杯子? 還是取決於原料的型別?

針對問題領域的語言
針對問題領域的優秀特定領域語言包含領域規則,透過使許多典型錯誤無法指定來減少測試需求。

更重要的是,與問題領域緊密結合的 DSL 能讓領域專家驗證、確認甚至直接指定所需的功能。

那麼,針對問題領域的 DSL 應該是什麼樣的呢?

為了實現協作並確保領域專家能夠參與其中,該語言必須使用與醫生和實驗室技術人員相同的術語,如 "取 "和 "清潔"--就像前面引用的原始問題描述一樣。 它指定了前面討論過的同一混合過程。 最有可能的是,任何熟悉機器的領域專家都能讀取該模型,並檢查混合過程的準確性。
面向領域專家的語言,而不僅僅是程式設計師的語言

此外,這種語言還能執行前面提到的許多領域規則,例如,如果之前的操作是將藥物注入針頭,那麼就不能對針頭進行清潔。 根據這個模型,我們仍然可以生成程式碼,包括前面展示的文字 DSL。

雖然這種語言改善了情況,但它仍然有侷限性。 使用者仍然需要手動計算針頭的位置,確保接下來使用正確的杯子,並驗證該過程是否真的會產生任何結果--藥品。

由於還有進一步改進的空間,我們可以透過提出類似下面的語言來進一步提高抽象程度。

面向領域專家的語言,而不僅僅是程式設計師的語言

這個 DSL 描述的混合過程與前面的示例相同,但現在不需要計算位置了,而且明確顯示了杯子,使領域專家對模型一目瞭然。 同樣重要的是,透過提高抽象程度並在語言中嵌入領域規則,模型變得更容易建立和修改。 例如,以前的 DSL 需要為小型混合過程指定 16 個專案,而這個版本只需要 8 個。 第一個文字 DSL 有 12 條命令和 12 個引數。

雖然這個例子很小,但這種語言可以擴充套件到處理更大的流程。 它還可以根據領域的其他特徵進行擴充套件,例如等待時間、強制安全程式(例如,關閉安全百葉窗以防止有人在機器執行時進入機器內部)等等。 下圖展示了一個稍大的混合流程,根據這個模型,還可以自動生成程式碼和其他工件。

面向領域專家的語言,而不僅僅是程式設計師的語言

透過提高抽象層次,使其更接近問題領域,建立所需功能的工作就會變得更快。 協作也變得更容易,因為領域專家可以閱讀、驗證和確認模型。 在許多情況下,根據具體情況和 DSL,他們甚至可以自己建立模型。

建立特定領域語言的努力?
在所有三種情況下,使用 DSL 建立的規範都可以轉化為執行中的程式程式碼。 建立這三種小型 DSL 和工具所需的時間都不到 1 小時,但它們所能提供的結果卻截然不同。如果只有你一個人使用 DSL,這並不重要,但如果有多個人需要遵循領域規則,或者你希望領域專家能更好地參與開發,那麼就應該為問題領域而不是解決方案領域建立語言。

醫學混合的例子只展示了一種小型語言,但這個想法可以擴充套件到比它大 100 倍的語言,自然也可以擴充套件到其他領域。 根據我在各種案例中積累的經驗,在適當的工具支援下實現真實世界的 DSL 所需的時間大約為 1-3 周。

下面是四個來自不同領域的例子,它們使非程式設計師也能讀取、驗證、確認甚至建立用於生成程式碼的形式化規範:

  • 1) 供暖系統(左上)
  • 2) 裝配線自動化(右上),
  • 3) 養魚場自動化系統(左下)
  • 和 4) 網路應用程式測試。

這些語言以圖表和地圖的形式展示,因為它們所解決的問題很容易用這些表示法來表達,但語言也可以以矩陣、表格、文字或它們的混合形式展示模型--這一切都取決於問題領域。

面向領域專家的語言,而不僅僅是程式設計師的語言

工具支援
特定領域語言需要工具--無論是定義語言還是使用語言。 在為領域專家建立 DSL 時,期望他們使用程式設計師通常使用的整合開發環境或工具是不現實的。

相反,他們需要易學易用的工具。 這一點尤為重要,因為與使用程式語言的開發人員不同,領域專家通常並不一定每天都要與他們的 DSL 進行互動。

領域專家還希望 DSL 中的協作、審查和變更管理更簡單,更符合問題領域,而不是透過檔案中的字元級差異來跟蹤和合並變更。

從這個意義上說,無論是 DSL 及其工具,還是使用流程,都需要根據領域專家的具體需求量身定製。

結論
特定領域語言已被廣泛使用,但它們往往只關注解決方案領域,而不是問題領域。 由於建立 DSL 和構建其工具所需的努力是相同的,我們應該優先考慮為領域專家而不僅僅是程式設計師建立語言。

當語言與問題領域緊密結合時,許多典型的開發任務(如需求規格、檢查和驗證)都可以由領域專家來處理。

事實上,領域專家往往可以自己建立規範,然後用於生成程式碼、配置、測試、部署說明等。 這種方法可以提高質量,實現早期反饋,並顯著改善協作和生產率--就像提高抽象層次一直以來所做的那樣。

相關文章