Ballerina Swan Lake:10個令人矚目的雲原生編程語言特性

{"type":"doc","content":[{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Ballerina誕生的背景"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"集成可以看作是一種編程類型,而且爲了簡化和抽離集成的複雜性,人們藉助不同的技術實現了集成的可視化表示。DSL已經變得非常流行,因爲它們提供了恰當的編程抽象,但也有一些侷限——很多時候,集成開發人員都不得不使用常規代碼來解決一部分問題。而且,集成編程實踐已經變成了孤島,開發人員要選擇一種集成工具進行集成編程,還必須使用另外一種工具或編程語言開發應用程序的其他部分。可視化表示還是很重要,我們可以藉此觀察端點之間的數據流和交互。此外,對於雲原生工程,集成系統現在運行在容器中,應用程序使用分佈在許多節點上的微服務來實現。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"如果有一種語言既能提供代碼集成能力,又能提供可視化工具,那豈不是非常有用?那樣,我們豈不是既可以克服DSL的侷限,又能夠保留軟件工程的最佳實踐?Ballerina 就是在這種想法下誕生的。其目標是創建一種現代化的編程語言,一種集編程語言、集成技術和雲原生計算優點於一體的、集成優化的、有潛力成爲主流的文本和圖形語言。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"下面讓我們逐條看下Ballerina 語言的關鍵特性。有些之前已經介紹過,有些在"},{"type":"link","attrs":{"href":"https:\/\/blog.ballerina.io\/posts\/announcing-ballerina-swan-lake-beta1\/","title":"","type":null},"content":[{"type":"text","text":"Swan Lake Beta"}]},{"type":"text","text":"版本中做了增強。從中我們可以理解,爲什麼Ballerina很適合創建網絡服務及實現分佈式系統集成。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"Ballerina的關鍵特性"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"1. Ballerina以應用程序語言的健壯性和可擴展性解決了腳本語言的大多數用例需求"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"你可以想象有這樣一個語言圖譜,從像Perl、Awk這樣的腳本語言到像Rust、C這樣的系統語言,中間是像Go、Java這樣的應用程序語言。程序可以是單行腳本,也可以是數百萬行代碼。在這個圖譜上,Ballerina 介於腳本語言和應用程序語言之間。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ballerina 獨有的特性使其非常適合小型程序。其他大多數爲小型程序設計的腳本語言與Ballerina 有很大的不同,它們是動態類型的,而且無法提供Ballerina 獨有的可擴展性和健壯性。在前雲時代,你用其他腳本語言解決的問題仍然是很重要的問題。只是現在會涉及到網絡服務;健壯性也比以往任何時候更重要。使用標準的腳本語言,一個50行的程序幾年後往往就會變成一個上千行的、難以維護的程序,而這還不是終點。Ballerina 可以用於解決腳本程序的問題,而且更具擴展性,更健壯,也更適合雲。此外,腳本語言通常也不提供任何可視化組件,但Ballerina 提供。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"2. Ballerina是面向數據的,而不是面向對象的"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在網絡交互中,面向對象的方法將數據和代碼綁在一起,在分佈廣泛的微服務和API網絡中,這並不是最佳的數據發送方式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在前雲時代,API是對路徑中庫函數的調用,你可以在調用中傳遞對象。但當API在雲上時,就沒法這樣做了。你會希望通過網絡發送的數據獨立於代碼,因爲你不想暴露代碼。雖然Java RMI和CORBA都曾設法支持分佈式對象,但前提是緊耦合,而且兩端同屬一個組織。在松耦合的雲上,分佈式對象就無法使用了。Ballerina 突出的是純數據,獨立於任何處理數據的代碼。雖然Ballerina 爲內部接口提供了對象,但它不是一種面向對象的語言。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"隨着雲上的服務越來越多,開發人員又多了在代碼中處理網絡資源的職責。編程語言本身必須提供相應的幫助。這就是爲什麼Ballerina 帶來了一個網絡友好的類型系統,提供了強大的在線數據處理功能。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/codefaster.substack.com\/p\/make-json-your-lingua-franca","title":"","type":null},"content":[{"type":"text","text":"JSON在Ballerina中是一種通用語言"}]},{"type":"text","text":"。Ballerina 中的數據類型非常接近JSON,數值、字符串、Map數組等基礎數據類型可以一一映射到JSON。Ballerina的普通內存數據值幾乎就是內存中的JSON。這樣,通過網絡傳輸過來的JSON負載可以立即由Ballerina處理,不需要轉換或序列化。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/io;\nimport ballerina\/lang.value;\n\njson j = { \"x\": 1, \"y\": 2 };\n\n\/\/ 以JSON格式返回表示j的字符串。\nstring s = j.toJsonString();\n\n\/\/ 解析JSON格式的字符串,返回它代表的值。\njson j2 = check value:fromJsonString(s);\n\n\/\/ 爲了兼容JSON,允許null值。\njson j3 = null;\n\npublic function main() {\n io:println(s);\n io:println(j2);\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"3. Ballerina有一個靈活的類型系統"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編程語言的類型系統是爲了讓你可以描述各部分是如何組合在一起的,而不僅僅是捕獲一類錯誤——這只是類型系統爲你做的一小部分工作。此外,它還有很大一部分工作是提供良好的IDE體驗。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"腳本語言是動態類型的,而應用程序語言則是傳統的靜態類型,像C++或Java。前文已經介紹過,Ballerina 是一種腳本語言,但它提供了一些應用程序語言的特性,其中就包括靜態類型系統。在靜態類型語言中,類型兼容性是在編譯時檢查的。通常,靜態類型語言更便於重構、更容易調試,也有助於創建更好的語言工具。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然Ballerina的類型系統是靜態的,但其類型比應用程序語言中的類型要靈活得多。Ballerina 語言的類型系統是結構性的,並且增加了對標明類型(nominal typing)的支持。也就是說,類型兼容性的認定考慮了值的結構,而不僅僅是依賴類型名稱。這不同於Java、C++、C#等擁有標明類型系統的語言,它們的類型兼容性受實際的類型名稱約束。這樣一來,我們付出的代價是有些東西可能在編譯時無法捕獲,但收穫了簡潔性和靈活性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"具體來說,你可以說它類似於XML 模式中的結構定義方式。如果程序收到的XML負載有變化或偏差,它仍然可以處理能夠識別的內容。它不是那麼嚴格,負載中有無法識別的變化也不一定會失敗。Ballerina的類型系統既可以作爲描述網絡數據的模式語言,也可以作爲操作內存值的程序的類型系統。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要了解關於Ballerina類型系統的更多信息,請移步"},{"type":"link","attrs":{"href":"https:\/\/ballerina.io\/learn\/why-ballerina\/flexibly-typed\/","title":"","type":null},"content":[{"type":"text","text":"這裏"}]},{"type":"text","text":"。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"4. Ballerina提供了強大的網絡數據處理功能"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ballerina 還提供了一套用於數據處理的語言特性,其中最突出的就是集成查詢。該特性讓你可以像下面這樣使用類似SQL的語法查詢數據。查詢表達式通過一組類似SQL的子句來處理數據。它們必須以from子句開頭,可以執行過濾、連接、排序、範圍、投影等操作。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/io;\n \ntype Employee record {\n string firstName;\n string lastName;\n decimal salary;\n};\n \npublic function main() {\n Employee[] employees = [\n {firstName: \"Rachel\", lastName: \"Green\", salary: 3000.00},\n {firstName: \"Monica\", lastName: \"Geller\", salary: 4000.00},\n {firstName: \"Phoebe\", lastName: \"Buffay\", salary: 2000.00},\n {firstName: \"Ross\", lastName: \"Geller\", salary: 6000.00},\n {firstName: \"Chandler\", lastName: \"Bing\", salary: 8000.00},\n {firstName: \"Joey\", lastName: \"Tribbiani\", salary: 10000.00}\n ];\n \n \/\/ 用於list解析的類SQL查詢,以from開始,以select結束。\n \/\/ order by子句根據姓氏對employees中的成員進行排序。\n Employee[] sorted = from var e in employees\n order by e.lastName ascending \n select e;\n io:println(sorted);\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ballerina 還提供了一個Table 數據類型,簡化關係型表格數據的處理。下面的代碼創建了一個表,其中是Employee類型的成員,每位成員使用name字段唯一標識。main函數通過鍵值John 檢索Employee,並增加每名員工的工資。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/io;\n\ntype Employee record {\n readonly string name;\n int salary;\n};\n\n\/\/ 創建一個表,其成員類型爲Employee,其中每位成員使用name字段唯一標識。\ntable key(name) t = table [\n { name: \"John\", salary: 100 },\n { name: \"Jane\", salary: 200 }\n];\n\nfunction increaseSalary(int n) {\n \/\/ 按指定的順序遍歷t中的行。\n foreach Employee e in t {\n e.salary += n;\n }\n}\n\npublic function main() {\n \/\/ 使用鍵值`John`檢索Employee。\n Employee? e = t[\"John\"];\n io:println(e);\n\n increaseSalary(100);\n io:println(t);\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要想了解更多關於Ballerina 集成查詢的信息,請移步"},{"type":"link","attrs":{"href":"https:\/\/ballerina.io\/learn\/why-ballerina\/data-oriented\/","title":"","type":null},"content":[{"type":"text","text":"這裏"}]},{"type":"text","text":"。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"此外,Ballerina內置了XML支持,其功能類似於XQuery,具有類似XPath的XML導航機制。這特別適合那些大量使用XML但又不想使用XML專用語言的人,因爲他們現如今要處理各種數據格式。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/io;\n\npublic function main() returns error? {\n xml x1 = xml `Sherlock Holmes`;\n xml:Element x2 = \n xml `
\n Sir Arthur Conan Doyle\n English\n `;\n\n \/\/ `+`做串聯。\n xml x3 = x1 + x2;\n\n io:println(x3);\n\n xml x4 = xml `Sherlock Holmes
\n Sir Arthur Conan Doyle\n English\n `;\n \/\/ `==`做深層相等比較。\n boolean eq = x3 == x4;\n\n io:println(eq);\n\n \/\/ `foreach`迭代每個數據項。\n foreach var item in x4 {\n io:println(item);\n }\n\n \/\/ `x[i]` 獲取第i項數據(如果沒有,則爲空序列)。\n io:println(x3[0]);\n\n \/\/ `x.id`訪問名爲`id`的屬性,如果屬性不存在,或者不是一個單元素項,則返回錯誤。\n xml x5 = xml `Hello`;\n string id = check x5.id;\n\n io:println(id);\n\n \/\/ `x?.id`訪問名爲`id`的可選屬性,如果屬性不存在,則結果爲`()`。\n string? name = check x5?.name;\n\n io:println(name is ());\n\n \/\/ 使用`e.setChildren(x)`轉換元素。\n x2.setChildren(xml `French`);\n\n io:println(x2);\n io:println(x3);\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在無縫處理不同數據類型的能力中,Ballerina還提供了一個decimal 數據類型。這是爲滿足商業需求而設計的浮點數,如標註價格。由於在一般的語言中,值都是用二進制表示的,所以並不能準確地表示所有實數。當位數超出了格式限制時,剩餘部分會被忽略——數值成了近似值,這會導致精度錯誤。真實世界是運轉在十進制數上的,這也是爲什麼我們會認爲這是Ballerina的一個強大能力。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/io;\n\n\/\/ `decimal`類型表示128位IEEE 754R十進制浮點數集合。 \ndecimal nanos = 1d\/1000000000d;\n\nfunction floatSurprise() {\n float f = 100.10 - 0.01;\n io:println(f);\n}\n\npublic function main() {\n floatSurprise();\n io:println(nanos);\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"5. Ballerina本來就是併發的,而且內置了併發安全性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在雲上,併發是一個基本需求,因爲網絡操作有高延遲。腳本語言對於併發的處理通常也不是很好。典型地,像JavaScript這樣的腳本語言使用異步函數,"},{"type":"link","attrs":{"href":"https:\/\/vegibit.com\/javascript-callbacks-vs-promises-vs-async-await\/","title":"","type":null},"content":[{"type":"text","text":"這比會回調稍微好點"}]},{"type":"text","text":",但也好不了多少。Ballerina提供了一個更簡單的編程模型,它提供的併發方法有異步函數的優點,但比異步函數更簡單、直觀。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"在Ballerina中,主要的併發概念是strand,類似於Go語言中的"},{"type":"link","attrs":{"href":"https:\/\/www.geeksforgeeks.org\/golang-goroutine-vs-thread\/","title":"","type":null},"content":[{"type":"text","text":"goroutine"}]},{"type":"text","text":"。Ballerina 程序運行在一個或多個線程上。線程可以與其他線程一起同時運行在一顆內核上,也可以與其他線程一起在一顆內核上執行搶佔式多任務。每個線程都可以分成一個或多個strand,這是由語言託管的邏輯控制線程。從程序員的角度來看,strand 像一個OS線程,但它不是——它更輕量級,開銷更小。Strand可以調度到單獨的OS線程上。Go採用了類似的方法,但這樣做的編程語言並不多。事實上,大部分動態腳本語言都不支持併發。例如,Python有一個全局鎖,所以它並不是真正支持併發執行。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ballerina 中的函數可以擁有命名“worker”,每個worker併發運行在一個新的strand上,函數的默認worker和其他命名worker如下所示:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/io;\n\npublic function main() {\n \/\/ 任何命名worker之前的代碼都會在worker啓動之前執行。\n io:println(\"Initializing\");\n final string greeting = \"Hello\";\n\n \/\/ 命名worker和函數的默認worker以及其他命名worker並行運行。\n worker A {\n \/\/ 在所有命名worker和函數參數之前聲明的變量都可以在命名worker中訪問。\n io:println(greeting + \" from worker A\");\n }\n\n worker B {\n io:println(greeting + \" from worker B\");\n }\n\n io:println(greeting + \" from function worker\");\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ballerina 還允許strand之間共享不可變狀態。通常,將併發和不可變狀態共享相結合會導致數據競爭,產生錯誤結果。這是動態語言通常不暴露線程的其中一個原因。不過,對於這個問題,Ballerina 提供了一個很好的解決方案,通過協作式多任務保證併發安全性。在Ballerina 中,同一線程上的所有strand都是以協作式多任務(而非搶佔式)方式執行,從而避免了鎖問題。這類似於異步函數,所有東西在一個線程上運行,但沒有複雜的編程模型。Strand 通過暫停來實現協作式多任務。當一個strand 在特定的”暫停點“暫停,運行時調度器就會掛起該strand的執行,將其線程切換爲運行另一個strand。我們還可以決定什麼時候並行運行strand——可以使用註解讓一個strand在一個單獨的線程上運行。這是因爲Ballerina 獨特的類型系統使它能夠確定服務何時已經鎖定,從而可以安全地使用多線程並行處理傳入的請求。雖然這看起來可能無法提供大量的並行執行,但也足以有效利用常見的雲實例類型了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":" import ballerina\/io;\n\n public function main() {\n\/\/ 每個命名worker都有一個“strand”(邏輯線程控制),strand只在特定的“暫停點”切換執行。\n worker A {\n io:println(\"In worker A\");\n }\n\n \/\/ 註解可以用於使一個strand在單獨的線程上運行。\n @strand {\n thread: \"any\"\n }\n\n worker B {\n io:println(\"In worker B\");\n }\n\n io:println(\"In function worker\");\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"6. Ballerina內置了圖形化視圖"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"處理併發和網絡交互是編寫雲程序固有的一部分工作。在Ballerina 中,每個程序都可以自動生成一個序列圖,通過圖形說明分佈式併發交互。Ballerina 程序中有等價的文本語法和序列圖表示。你可以在這兩種視圖之間無縫切換。Ballerina 獨有的圖形化視圖不是事後纔有的想法。事實上,Ballerina 在設計時就做了深入的考慮,爲的是在函數的網絡交互和併發使用方面提供真正的洞察力。序列圖是最適合這種情形的一種圖形。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"說明一下,Ballerina 的命名worker(第5點討論過)以及其他函數級併發特性描述了併發性,而客戶端和服務的語言抽象則描述了網絡交互。豎線,也稱爲生命線,表示worker和遠程端點。一個遠程端點是一個客戶端對象,它包含遠程方法,表示和遠程系統的出站交互。大部分語言都不區分遠程調用和常規方法調用,但Ballerina 提供了截然不同的遠程方法調用。橫線表示從一個函數的worker發送給另一個worker或是遠程端點的消息。這些方面在Ballerina 中很容易區分,它提供了高級視圖,用戶什麼都不需要做。Ballerina 之所以能做到這種程度,是因爲它從設計之初就加入了圖形化元素。這是其他任何語言都沒有的特性。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/ballerina-cloud-native-programming\/en\/resources\/1image001-1631565390059.jpg","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ballerina VSCode插件可以從源代碼動態生成序列圖。要生成上述Ballerina 代碼的序列圖,請"},{"type":"link","attrs":{"href":"https:\/\/ballerina.io\/learn\/tooling-guide\/visual-studio-code-extension\/quick-start\/","title":"","type":null},"content":[{"type":"text","text":"下載VSCode插件並啓動圖形查看器"}]},{"type":"text","text":"。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"7. Ballerina 是雲原生的,它提供了一個簡單的模型,用於生成和消費服務以及把代碼部署到雲上"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"除了具有網絡感知特點的類型系統外,Ballerina還提供了用於處理網絡服務的基本語法抽象。該語言還內置支持使用Docker和Kubernetes在雲上部署Ballerina應用程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"生成服務的服務對象"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ballerina 迎合了服務的概念,使用Ballerina 只需3、4行代碼就可以寫出一個服務。在Ballerina 中,服務基於3個概念:應用程序、監聽器和庫。應用程序定義服務對象,並將它們連接到監聽器。監聽器由庫提供。舉例來說,每種協議(HTTP、GraphQL等)都有一個監聽器,都由一個庫提供。監聽器接收網絡輸入,然後調用應用程序找到服務對象。服務對象支持以下兩種接口類型:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"bulletedlist","content":[{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"遠程方法——使用動態命名,支持RPC風格"}]}]},{"type":"listitem","attrs":{"listStyle":null},"content":[{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"資源——使用方法(如GET)加名詞定義,支持RESTful風格(用於HTTP和GraphQL)"}]}]}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"得益於Ballerina提供的服務方法以及獨特的面向連接的類型系統,你可以從Ballerina 代碼生成一個接口描述,可以是OpenAPI 規格的,也可以是GraphQL 規格的。這樣,你就可以實際編寫服務對象,並生成客戶端代碼了。這些特性組合在一起就使得雲集成可以順利進行了。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/http;\n \nservice on new http:Listener(9090) {\n resource function get greeting(string name) returns string { \n return \"Hello, \" + name; \n } \n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"消費遠程服務的客戶端對象"},{"type":"text","text":"出站網絡交互表示爲客戶端對象。客戶端中有遠程方法,表示和遠程系統的出站交互。客戶端對象是其中一個語法元素,讓我們可以繪製序列圖。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/email;\n\nfunction main() returns error? {\n email:SmtpClient sc\n = check new(\"smtp.example.com\",\n \"[email protected]\",\n \"passwd123\");\n check sc -> sendMessage({\n to: \"[email protected]\",\n subject: \"Ballerina\"\n body: \"Ballerina is pretty awesome!\"\n });\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"image","attrs":{"src":"https:\/\/imgopt.infoq.com\/fit-in\/1200x2400\/filters:quality(80)\/filters:no_upscale()\/articles\/ballerina-cloud-native-programming\/en\/resources\/1image003-1631565390059.png","alt":null,"title":null,"style":[{"key":"width","value":"75%"},{"key":"bordertype","value":"none"}],"href":null,"fromPaste":true,"pastePass":true}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"代碼上雲"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ballerina 支持從代碼生成Docker 和Kubernetes 工件,不需要任何額外的配置。這簡化了開發以及向雲上部署Ballerina 代碼的體驗。代碼上雲要先從代碼中獲取所需的值然後再構建容器和所需的工件。要了解詳細信息,可以看下"},{"type":"link","attrs":{"href":"https:\/\/ballerina.io\/learn\/by-example\/c2c-deployment.html","title":"","type":null},"content":[{"type":"text","text":"這個例子"}]},{"type":"text","text":"。要將代碼部署到不同的雲平臺上,如AWS和微軟Azure,可以使用服務對象註解輕鬆實現雲部署,如下所示。Ballerina 編譯器可以生成Dockerfile、Docker鏡像、Kubernetes YAML文件、無服務器函數等工件。例如,Ballerina 函數可以使用@azure_functions:Function註解部署到Azure上。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/uuid;\nimport ballerinax\/azure_functions as af;\n\n\/\/ 沒有身份驗證的HTTP請求\/響應。\n@af:Function\npublic function hello(@af:HTTPTrigger { authLevel: \"anonymous\" } string payload) returns @af:HTTPOutput string|error {\n\n return \"Hello, \" + payload + \"!\";\n\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"8. 顯式錯誤控制流"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"錯誤處理方法對於語言設計和使用有着深遠的影響。它會影響語言的方方面面。當你和網絡打交道時,錯誤是正常業務處理的一部分,尤其是考慮到"},{"type":"link","attrs":{"href":"https:\/\/ably.com\/blog\/8-fallacies-of-distributed-computing","title":"","type":null},"content":[{"type":"text","text":"分佈式計算的8大謬誤"}]},{"type":"text","text":"時。像Java、JavaScript、TypeScript等前雲時代的語言,使用異常作爲其錯誤處理方式。但並不是每種語言都遵循那種設計。像Go和Rust這樣的語言根本就沒有異常。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"使用異常,控制流是隱式的,代碼理解和維護的難度都比較大。當出現問題時,只是方便地拋出一個異常,就會使什麼東西都失控。爲了實現恰當的錯誤處理,你必須得仔細看下程序,弄清楚可能出現錯誤的地方是否有錯,以及控制流如何變化。所以,現在有一個相當強的趨勢,就是消除異常,迴歸一種更簡單的方法,錯誤是顯式的,使用正常控制流進行處理。Go、Rust、Swift都使用了這種方法。Ballerina 也使用了這一方法,讓開發人員可以使用error 數據類型,以及顯式的錯誤控制流。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/io;\n\n\/\/ 將bytes轉換成string,然後再轉換成int。\nfunction intFromBytes(byte[] bytes) returns int|error {\n\n string|error ret = string:fromBytes(bytes);\n\n \/\/ is操作符可以用於區分錯誤和其他值。\n if ret is error {\n\n return ret;\n } else {\n return int:fromString(ret);\n }\n}\n\n\/\/ main會返回一個error。\npublic function main() returns error? {\n\n int|error res = intFromBytes([104, 101, 108, 108, 111]); \n if res is error {\n \/\/ 可以使用`check`表達式來簡化這個判斷模式。\n return res;\n\n } else {\n io:println(\"result: \", res);\n }\n}\n"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"9. 將事務作爲語言特性"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"編寫使用事務的Ballerina 程序非常簡單,因爲事務是它的一個語言特性。Ballerina 提供的不是事務性內存,而是從根本上支持事務劃分。這樣就可以保證,事務總是包含begin、rollback或commit選項。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"Ballerina 程序正在運行的實例中包含一個事務管理器。它可能是和Ballerina 程序在同一個進程中運行,也可能是在一個單獨的進程中(連接網絡要可靠)。事務管理器維護了從每個strand 到事務棧(或者是分佈式上下文中的事務分支)的映射。當strand的事務棧非空時,我們就說它處於事務模式;strand事務棧最頂端的事務就是該strand當前的事務。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"codeblock","attrs":{"lang":"plain"},"content":[{"type":"text","text":"import ballerina\/io;\n\npublic function main() returns error? {\n \/\/ 編譯時會保證事務以begin開始,以commit或rollback結束。Transaction 語句\n \/\/ 會開啓一個新事務,並執行一個代碼塊。\n transaction {\n doStage1();\n doStage2();\n\n \/\/ 事務要使用commit語句顯式提交,這可能會導致一個錯誤。\n check commit;\n\n }\n}\n\nfunction doStage1() {\n io:println(\"Stage1 completed\");\n}\n\nfunction doStage2() {\n io:println(\"Stage2 completed\");\n}\n"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"爲了支持分佈式事務,Ballerina 中的事務還加入了網絡交互特性(即客戶端和服務)。用戶可以將服務的資源\/遠程方法以及客戶端對象的遠程方法聲明爲事務性的,從而創建客戶端和服務之間的事務流。"}]},{"type":"heading","attrs":{"align":null,"level":3},"content":[{"type":"text","text":"10. Ballerina提供了許多開發人員熟悉的特性,可謂Batteries Included"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"新語言大量出現表明人們還是很願意學習新語言。但是,企業似乎不太願意採用新語言,因爲他們會擔心招聘不到熟悉那門語言的人。因此,要重點說明一下,Ballerina 不僅提供了更好的做事方式,而且還提供了一組C語言家族程序員熟悉的特性,他們只需幾個小時甚至更少的時間就足以上手開發。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"廣爲流行的C語言家族(C、C++、Java、JavaScript、C#、TypeScript)有許多共同點。Ballerina 利用了這一點,許多事情都採用了同樣的方式。如果對於C語言家族中的任何一門語言,你有一定量的編程經驗,那麼使用Ballerina 編碼都會相當簡單。除了功能強大的語言特性外,Ballerina 還是“batteries included”的,即提供了豐富的"},{"type":"link","attrs":{"href":"https:\/\/lib.ballerina.io\/#stdlibs","title":"","type":null},"content":[{"type":"text","text":"標準庫"}]},{"type":"text","text":"(包括用於網絡數據、消息和通信協議的庫)、"},{"type":"link","attrs":{"href":"https:\/\/central.ballerina.io\/","title":"","type":null},"content":[{"type":"text","text":"包管理系統"}]},{"type":"text","text":"、結構化文檔、測試框架,它還爲流行的IDE(特別是Visual Studio Code)提供了擴展\/插件,以便使該工具支持這門語言。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"小結"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"雖然Ballerina 具備現代編程語言的所有通用功能,但它的優勢在於其提供了一些獨特的語言特性,讓開發人員可以更容易使用、組合和創建雲端網絡服務。開發人員現在可以構建富有彈性的、安全的、高性能的服務,消除分佈式計算的謬誤,並使用一種專門的編程語言將它們整合在一起創建雲原生應用程序。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要想快速瞭解在Ballerina中如何創建以及消費HTTP服務,可以觀看這個"},{"type":"link","attrs":{"href":"http:\/\/youtube.com\/watch?v=NxyIKoHl3Dw","title":"","type":null},"content":[{"type":"text","text":"錄屏視頻"}]},{"type":"text","text":"。如果你更喜歡通過示例進行學習,那麼"},{"type":"link","attrs":{"href":"https:\/\/ballerina.io\/learn\/by-example\/","title":"","type":null},"content":[{"type":"text","text":"這裏"}]},{"type":"text","text":"提供了許多代碼示例,從中你可以瞭解到Ballerina 的重要特性和概念。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","text":"要想深入瞭解Ballerina Swan Lake的語言特性,可以觀看Ballerina首席語言設計師James Clark提供的"},{"type":"link","attrs":{"href":"https:\/\/www.youtube.com\/playlist?list=PL7JOecNWBb0KX8RGAjF-oRknb_YIYN-dR","title":"","type":null},"content":[{"type":"text","text":"系列視頻"}]},{"type":"text","text":"。你還可以閱讀這篇"},{"type":"link","attrs":{"href":"https:\/\/www.blogger.com\/comment.g?blogID=3944976411672994427&postID=2828597875406135367&bpli=1&pli=1","title":"","type":null},"content":[{"type":"text","text":"博文"}]},{"type":"text","text":",瞭解Ballerina的設計原則。"}]},{"type":"heading","attrs":{"align":null,"level":2},"content":[{"type":"text","text":"作者簡介"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"Dakshitha Ratnayake"},{"type":"text","text":"目前在WSO2擔任Ballerina的項目經理。她擁有軟件工程的背景,在WSO2擔任軟件工程師、解決方案架構師和技術佈道師等職務,擁有超過10年的經驗。在此期間,她一直是WSO2 API管理、企業應用集成、身份和訪問管理、微服務架構、事件驅動架構和雲原生編程等領域的技術倡導者。與此同時,她還與不同的組織保持着技術關係,以理解業務需求,溝通技術戰略。"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"text","marks":[{"type":"strong"}],"text":"查看原文:"}]},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null}},{"type":"paragraph","attrs":{"indent":0,"number":0,"align":null,"origin":null},"content":[{"type":"link","attrs":{"href":"https:\/\/www.infoq.com\/articles\/ballerina-cloud-native-programming\/","title":"","type":null},"content":[{"type":"text","text":"Ballerina Swan Lake: 10 Compelling Language Characteristics for Cloud Native Programming"}]}]}]}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章