簡介:如何有效地提高軟件開發的效率和品質,一直是軟體工程領域關心的問題。其中, 程式自動生成技術被認爲是提高軟件開發自動化程度和最終品質的重要方法,受到學術界和工業界的廣泛關注。程式自動生成技術指利用某些技術自動地爲軟體生成原始碼,達到根據使用者的需求機器自動程式設計的目的。極大程度地減輕了程式設計師的開發負擔, 使得程式設計師可以更加關注於業務價值賦能。
作者 | 妙淨
作者周婷婷(花名:妙淨,微信: weekendingting)是阿裡淘系技術部高階前端技術專家,視覺稿智慧生成程式碼 imgcook平臺負責人,阿裡經濟體前端智慧化方向重要成員,來自業內首個 AI 前端團隊淘系前端之 F(x) Team 。去年我們聚焦在設計稿智慧生成前端檢視程式碼領域,但對於邏輯程式碼的智慧生成也一直在不斷嘗試,本文介紹邏輯程式碼自動生成相關技術概述。
如何有效地提高軟件開發的效率和品質,一直是軟體工程領域關心的問題。其中, 程式自動生成技術被認爲是提高軟件開發自動化程度和最終品質的重要方法,受到學術界和工業界的廣泛關注。程式自動生成技術指利用某些技術自動地爲軟體生成原始碼,達到根據使用者的需求機器自動程式設計的目的。極大程度地減輕了程式設計師的開發負擔, 使得程式設計師可以更加關注於業務價值賦能。
學術界上,程式生成和程式碼補全是程式綜合 (program synthesis) 的重要分支, 其目的在於輔助甚至代替程式設計師編寫程式。回到(前)端程式碼的自動生成,分爲檢視程式碼和邏輯程式碼,檢視程式碼方面目前有類似基於設計稿自動生成 的方案(如 imgcook),本文重點講述邏輯程式碼的生成技術方案,常見的生成邏輯程式碼的方案包含基於視覺化編排生成、基於輸入輸出樣例生成、基於程式碼語料生成補全、基於功能描述生成等。
視覺化程式設計也發展了幾十年,其指的是藉助於一些元件化的整合程式碼視覺化平臺,一些不具備專業程式碼技能和開發經驗的「小白」人羣也能自主組織或參與應用開發,從而把程式碼開發由一項程式設計師專屬職能擴充到更廣泛的人羣。它主要是讓程式設計人員利用軟體本身所提供的各種控制元件,像搭積木式地構造應用程式的各種介面,視覺化編排更適合介面檢視程式碼的生成;目前國外主打視覺化程式設計、低程式碼程式設計的平臺至少有十幾家,其中最具代表性的可以說是 OutSystems、Mendix、Salesforce 等幾家,而且對於邏輯程式碼的視覺化方案也有很多,如下:
以上類 blockly 等適合比較簡單的邏輯程式設計,目前在少兒程式設計領域的應用不錯;一但邏輯複雜,搭建出來的積木也無比龐大。這樣的系統在大公司,如果給業務方直接用,太複雜需要有業務方有程式設計思維,和 PRD 思維完全不一樣,門檻較高;如果給程式設計人員用,只是用圖形來代替了程式語言,程式設計人員因熟悉程式語言和相關偵錯等配套環境,視覺化搭建的方式生成程式碼反而更低效。
其他主流的邏輯程式碼的視覺化的編排(如下圖),其優勢是突出「視覺化流」和複用邏輯節點帶來的高效,主體是大的流程,輸入輸出、邏輯處理等細節包含在每個節點的具體表單規則中。此方案適合複用邏輯非常多的場景,複用的邏輯可抽象成流程圖中的「節點」。節點的複用顆粒度大小是比較關鍵的,顆粒度大到一個功能服務,就是業務流程編排了,業務流程複用度比較高的場景是比較適合讓業務方直接所見所得編排使用的;顆粒度小到表達式級別可以看做是業務邏輯編排,太小顆粒度是需要使用者有程式設計思維,顆粒度太小的視覺化對於有程式設計思維的同學來說,可能直接寫程式碼效率更高。
小結:視覺化邏輯編排生成程式碼,其本身編排的成本還是比較高的複雜情況下甚至比手寫程式碼程式設計還要高,但在邏輯複用度非常高的場景是比較適合的,可抽象成可複用的邏輯節點去編排,節點的複用可以帶來部分提效。
基於輸入輸出的樣例,自動推導出生成的邏輯程式,也叫 PBE(Programming by Examples),其是 2016 年微軟在論文中提到的一種程式綜合(program synthesis)的技術方案。現實中比較成功的應用案例是,Excel 中有個功能相信大家應該熟悉,那就是自動填表(FlashFill),其可以根據幾個樣例快速的生成表格項公式,比如下圖中,根據 第一列的 2 和 4,就可以填充偶數;第二列根據 50 和 40 自動推導出等差數列公式的結果。
以更復雜的情況爲例:
上述的公式更復雜,現實情況,FlashFill 的正確率只有不到 50%,後來又在 PBE 的基礎上提出了 NPBE(neural programming by example) 完成 Excel 中的 45 種字串操作。NPBE 的意圖是讓模型從輸入輸出字串中學習相關的特徵, 並用學到的特徵來歸納正確的程式。一般 PBE 的技術實現過程如下:
隨着 github 的開原始碼的積累和深度學習的興起,基於原始碼理解(程式理解)應用比較多,如程式碼補全推薦、還有根據程式碼猜測程式碼片段的意思。
常用的整合開發環境中往往整合了程式碼補全工具, 一般限於關鍵字或基於語法的提示,比如在 tsx 檔案中 this. 會提示出當前可用的類屬性、方法;現有的智慧程式碼補全工具通常基於模型效能考慮一般簡單基於靜態詞頻統計。
比如我們共建團隊同事基於 javascript 程式碼語料庫,對比 GPT2 之後,採用 n-gram 概率模型開發的程式碼補全外掛。詳見這裏,其主要流程圖如下:
程式碼意圖生成指根據程式碼內容可以推測出程式碼的功能作用,業界較知名的開源的模型和服務有 code2vec 和 code2seq,其中 code2vec 是做 code summarization(程式碼功能概要);code2seq 做 code captioning (程式碼功能說明)。
code2vec 範例說明如下:根據左側的程式碼片段,分析程式碼的功能是,90.93%的概率是 contains,右側是對程式碼的分析視覺化過程,重點關注節點間的連線粗細,粗細用來表示決策的資訊權重大小。
code2seq 範例說明如下:根據左側的程式碼片段,分析此程式碼的功能說明是,save bitmap to file,右側是對程式碼的分析視覺化過程,同樣重點關注節點間的連線粗細,粗細用來表示決策的資訊權重大小。
其內部模型詳見:其目前開源的模型數據集大小爲 billon 級,也開源了基於 typeScript 的模型。
大家通常利用自然語言來描述程式功能, 從自然語言描述到程式的自動生成是極具挑戰性的問題。自然語言文字和程式的多樣性、文字的二義性以及程式碼的複雜結構, 使得建立文字和程式碼的聯繫成爲一個難題。目前業內有些探索,包括 NL2SQL、NL2TFTTT、基於功能描述生成程式碼。
Natural Language to SQL (NL2SQL) 是CUI(Conversation User Interface)的新興研究熱點,其研究目的是將使用者輸入的自然語言轉爲可用的 SQL 語句,提高使用者查詢數據的效率,現在阻礙大數據價值變現的最大難題就是存取數據門檻太高,依賴數據庫管理員寫複雜的SQL,而且中文的表述更加多樣複雜。此領域的國內外的研究非常多,目前 NL2SQL 領域比較有名的數據集是英文版的數據集,包括 WikiSQL、Spider、CoSQL 等。
NL2SQL 典型的三層架構如下:
NL2SQL分爲User query interface、Processing Unit、Database三部分,其中 Processing Unit 是整個架構的中心,也是語意解析的核心所在,打通了 User 與 Database 的互動通道,囊括智慧分詞、實體識別、知識檢索等各個技術要點。在上述研究中,Processing Unit 的內部演算法也在逐步朝着深度學習的方向進展。下面 下麪是中文 NL2SQL 大賽中冠軍團隊提出的 M-SQL 模型,在中文數據集上達到了92%的準確率。
業內 Google的 Analyza 採用的是語意解析和規則的方式構建的,這種方式可控性較強,但是需要人工維護一些規則進去。端到端的方案則是通過深度學習方法,採用 encoder-decoder 的方式進行 NL2SQL 的實現,整個演算法系統分成了對 SQL 幾個子句的識別,包括SELECT clause、WHERE clause,有時候還有 group by、limit 等操作符。每個部分還會涉及到很多細節,比如表識別、屬性識別等。不同演算法都是在這樣的框架體系下,在細節的地方做一些改動和優化,以取得一個比較好的效果。雖然端到端的 NL2SQL 方案能夠減少人力維護的成本,但是隻有在 wikisql 這種簡單場景下有一定效果,針對相對複雜一點的 spider 或 cosql 場景來說,準確率非常低,達不到商業應用的要求。公司內部的數小蜜團隊實際業務落地的方案與Google的Analyza方案很相似,同時也已經對端到端 nl2sql 方案進行了研究和實現,下一步期望能夠將 NL2SQL 和語意規則解析的方式融合到一起,來解決複雜場景的需求。【此部分結論來源內部小蜜團隊】
IFTTT 是什麼?意思是 if this then that;是一個新生的網路服務平臺,通過其他不同平臺的條件來決定是否執行下一條命令。例如「如果明天下雨,請今天通知我」「當有人在 Facebook 標記有你在內的相片時,就自動將那張照片備份到iPhone 的照片相簿中」,這滿足了使用者把 A 服務內容串連到 B 服務的需求,並且使用者不用自己動手, IFTTT 可以自動幫忙完成上述動作。
功能範例
如下面 下麪的應用:
其設定如下:
NL2IFTTT 就是通過自然語言生成如上 If-This-Then-That(IFTTT) 程式碼,IFTTT 程式相對於常用的程式語言來說, 其結構更加簡單, 也更容易學習其結構規則。IFTTT 基於任務的條件觸發,類似極簡版程式語言,即:「若 XXX 進行 YYY 行爲,執行 ZZZ」。每一個可以觸發或者作爲任務的網站叫做一個 Channel,觸發的條件叫做 Trigger,之後執行的任務叫做 Action,綜合上面的一套流程叫做 Recipe。
NL2IFTTT 方面的實踐,2016年, Liu等人提出了一種隱注意力機制 機製, 該機制 機製可以有效地學習自然語言中哪些詞對觸發器的預測更重要, 哪些詞對動作的預測更加重要。同年,Beltagy 等人將IFTTT 程式生成問題當做語意分析問題。
數據集範例
微軟有一份開源 IFTTT 樣本集,其樣本數據類似如下,可以方便大家更好地理解 NL2IFTTT 的問題定義:
相比於根據自然語言的功能描述生成 TFTTT 程式碼 和 SQL,根據自然語言的需求描述直接生成 python、java、javascript 這類的程式語言邏輯程式碼的難度要大的多。至今(2020.8)暫時沒有找到相關的線上可用服務,目前找到卡內基梅隆大學有相關研究產出 TranX,其可以做到單一功能描述 生成 表達式級的程式碼,類似根據單行程式碼註釋生成相應程式碼,見其網站 demo 如下。
TranX 功能範例
TranX 數據集範例
{
"intent": "Sending http headers with python",
"rewritten_intent": "sending http headers to `client`",
"snippet": "client.send('HTTP/1.0 200 OK\\r\\n')",
"question_id": 8315209
},
{
"intent": "Python -Remove Time from Datetime String",
"rewritten_intent": "Format a datetime string `when` to extract date only",
"snippet": "then = datetime.datetime.strptime(when, '%Y-%m-%d').date()",
"question_id": 26153795
},
{
"intent": "How do I split a multi-line string into multiple lines?",
"rewritten_intent": "split a multi-line string `inputString` into separate strings",
"snippet": "inputString.split('\\n')",
"question_id": 172439
},
{
"intent": "How do I split a multi-line string into multiple lines?",
"rewritten_intent": "Split a multi-line string ` a \\n b \\r\\n c ` by new line character `\\n`",
"snippet": "' a \\n b \\r\\n c '.split('\\n')",
"question_id": 172439
},
TranX 模型範例
程式語言有嚴格的語法,它不能容忍拼寫錯誤和語法錯誤;此模型針對 AST 構建基於 Tree 的新型模型,能完整表達程式語言的所有語法;同時相應的語料標註是非常昂貴和耗時的,標記樣本的有限可用性是監督模型的瓶頸,此模型引入了 STRUCTVAE,一種用於半監督的自動編碼模型,它可以從有限的樣本中學習,又能從現成未標記的 NL 語言中學習。論文模型詳見:
功能描述生成程式碼的應用,還有基於 GPT3.0 的 debuild 平臺;目前演示網站關閉,從宣傳出來效果圖來看,可以看到從功能描述生成程式碼新的可能性。其可以根據佈局語言描述生成相應的佈局程式碼;也能根據簡單高階的功能描述生成相應的程式碼。
debuild 功能範例
debuild 模型範例
此平臺使用的模型基於 openAI 的 GPT3.0,作者表示自然語言生成程式碼基於 GPT3.0 讓之前不敢想象的的 50 年之後能生成程式碼 提前到 5 年內,目前的版本還是偏試驗,更多是偏簡單功能描述生成高階(封裝好的元件庫、模組庫等)的功能程式碼,感興趣的可以試試 GPT 3.0。
總體來看,基於深度學習爲自動生成程式程式碼是趨勢,但當前利用深度學習技術的程式生成和程式碼補全還處於起步階段。利用深度學習生成程式程式碼和程式碼補全與傳統方法相比有了較大的提升, 而程式生成技術還沒有用於工業化。其主要面臨着以下的挑戰:
1) 訓練語料的品質參差不齊。常見工作中, 用來訓練深度學習模型的語料大致可以分爲兩類:一類是基於 DSL 人爲構造出的程式; 另一類是從開源社羣, 如 GitHub 等網站上爬取的專案。基於 DSL 的程式往往語法較爲簡單, 程式長度較短, 易於訓練和測試, 但同時, 針對 DSL 設計的模型也難以推廣到其他語言上使用; 而開源社羣上爬取的專案雖然更接近於實際軟件開發, 但是也難以保證程式碼的品質——低品質、不規範的程式碼會給神經網路帶來額外的噪聲, 而使用不同程式設計規範的程式碼則會使神經網路模型在訓練和預測時產生混淆。如何獲取統一規範的高品質程式語料庫也是一項挑戰。
2)使用者自定義邏輯生成後的泛化能力弱。程式程式碼尤其是邏輯程式碼,很多都是業務閉域的邏輯程式碼,需要很多業務閉域的邏輯物料,需要對現有業務的所依賴的各種服務進行高階理解,新業務需要結合自己的物料庫訓練自己的模型;但往往全新的業務依賴的服務也需要從 0 開始開發,新物料的提供比較難,除非所有依賴的服務是不可拆分的原子服務。所以邏輯模型的普適性比較難,但方法論可以相互借鑑有普適性。
3)功能描述和程式程式碼資訊不對稱。如果真的做到極致,功能描述由 PRD 直接提供,可直接生成相應的程式程式碼;需求描述比一般的功能描述還要高階和抽象化,需求描述->功能描述-程式碼描述->程式程式碼,這其中每一個環節都會有很多資訊損耗,這些損耗目前都是程式設計師通過業務經驗和程式設計經驗補上的。功能描述直接生成程式碼解決辦法大致有 3 種,一種是端到端的從需求描述並生成 AST,如果 PD 對軟體功能的描述足夠精確,相當於創造了一個更高階的描述語言; 第二種是後面的鏈路部分(功能描述-程式碼描述->程式程式碼)封裝抽象成顆粒度較大的功能塊描述,目前大部分是基於這種的可行性比較高(如 NL2TFTTT 等);第三種是真正深入到每一個業務域中,上述每一個環節都讓模型去一層層理解最後逐步生成程式碼,語料庫的品質和最後的模型準確度效果是比較大的挑戰。
爲了減輕程式設計師的開發負擔, 提高軟件開發的自動化程度, 提高軟件開發的效率和品質, 學界和工業界都不斷嘗試研究程式自動生成技術。隨着深度學習技術的快速發展, 相信在將來, 越來越多的重複性的程式開發將由機器代替, 程式設計師將更關注於底層架構和上層業務價值賦能。
對於邏輯程式碼的智慧生成,目前阿裡前端智慧化團隊內部正在進行各維度的試驗,歡迎交流。
關注「Alibaba F2E」
把握阿裡巴巴前端新動向
原文鏈接:https://developer.aliyun.com/article/770311?
版權宣告:本文內容由阿裡雲實名註冊使用者自發貢獻,版權歸原作者所有,阿裡雲開發者社羣不擁有其著作權,亦不承擔相應法律責任。具體規則請檢視《阿裡雲開發者社羣使用者服務協定》和《阿裡雲開發者社羣智慧財產權保護指引》。如果您發現本社羣中有涉嫌抄襲的內容,填寫侵權投訴表單進行舉報,一經查實,本社羣將立刻刪除涉嫌侵權內容。