现代化历险记:策略+将COBOL转换为Java的示例
在Keyhole Software,我們在很大程度上是一家現代化公司。 我們擁有一些顧問,他們專門研究將舊的代碼遷移到新的,翻新的殘舊代碼庫,并為大多數已經被供應商鎖定的企業設計更光明的未來。
作為這些經驗的有趣的副作用,我們遇到了一些重復的模式和策略,以了解如何實現遺留系統的現代化。
在此博客中,我們將介紹一種看起來非常流行的策略Re-Platforming ,并將用我們開發的Keyhole Labs產品進行演示。 這篇文章的基本流程是:
- 現代化概論
- 重新平臺戰略的高層定義
- 使用Keyhole語法樹變壓器進行重新平臺化的示例
- 結束語
- 摘要
“我要進行一次現代化……不等,也許要兩個……”
當我們第一次圍繞現代化主題吸引客戶時,我們會看到他們在此過程中實際想要完成的工作的定義各不相同。 這些范圍包括從大型機應用程序退出,從ESB /經典SOA架構過渡到基于云的PaaS實施,再到從供應商鎖定/分層架構遷移到DevOps /微服務架構。
隨著十年前最近更新其技術堆棧的公司遇到成功運營或成長的一些關鍵問題,所有這些情況的發生頻率越來越高:
- 部署問題:所有內容都必須作為一個單元進行部署,這是一個痛苦的過程,并且/或者與其所有基礎架構緊密耦合
- 可伸縮性問題:可伸縮性的垂直極限受到了打擊–這意味著機器無法足夠快地變大以應對容量的增加
- 性能問題:系統中消息/事務的數量正在增加延遲,在某些情況下會導致級聯故障
- 資源問題:使用此系統的工程師和計算機科學家本來就不在或即將退休,并且不再在學校教授編程語言
因此,請進入現代化計劃。 讓我們首先回顧一下Re-Platforming策略及其優缺點。
這就像修理我的靴子嗎?”
重新平臺有時也稱為升降機。 從根本上講,重新平臺是將一種代碼語言轉換為另一種代碼語言,即進行翻譯。 作為現代化策略,這意味著將較舊的代碼語言轉換為較新的代碼語言。
由于各種原因,大型機在一些大型企業中仍然很普遍,因此,像COBOL這樣的舊代碼庫也仍然存在。 擺脫這些較舊的代碼庫和大型機的原因通常是以下之一:
- 資源問題(如上所述):大型機程序員正變得稀缺,并且這些語言集在任何現代課程中都沒有涉及。 招聘新開發人員比較困難,尤其是在快速變化和技術選擇日趨廣泛的情況下。 更少的員工愿意研究某些被淘汰的技術。
- 對于任何規模的企業而言,大型機都是一筆巨額費用,而垂直增長則是唯一的增長選擇,有時這是昂貴的。
大多數現代體系結構中常見的災難恢復和高可用性策略可能會對大型機造成成本上的限制。 - 程序語言構造(OOP,函數式編程,反應式編程等)中不能輕易利用更新的編程模式-因此限制了選擇的范圍。
- SDLC的變化–即從瀑布過渡到敏捷過程以保持競爭力。
因此,長話短說-說“重新平臺化”實際上是什么意思?
在此過程中,將分析較舊的代碼庫以確定代碼庫中的語法或模式。
一旦定義了語法樹或一組代碼模式,便會通過某些單步或多步編譯器軟件運行原始代碼庫(即COBOL),以將舊代碼轉換為所需的最終狀態-通常是Java, C#或更高版本的等效語言。
從業務角度來看,這可能非常有吸引力。 無需讓產品所有者和開發人員組成團隊來逐步用新語言重新編寫每個舊代碼位,此方法有望通過幾次按鈕操作來完成所有繁重的工作。 聽起來不錯!
好吧,教授,請稍等片刻–在繼續之前,這種方法存在一些固有的問題,需要提到。 最難的事情是:
代碼翻譯不一定能解決技術問題!
在某些情況下,這些舊代碼庫可能已經存在了20多年。 這可能是20多年的錯誤決定,或者是特定于大型機的決策被納入您的代碼中。
所有的翻譯過程都將為您提供那些潛在的代碼地雷,這些地雷現在正在使用新的語言,它們可能無法從大型機的慷慨和能力中受益。
代碼看起來可能比大型機差!
在此過程中運行代碼有時可能最終看起來像是被削木機扔掉了。 一些大型機和遺留代碼構造/行為無法很好地轉換或根本無法轉換成較新的代碼庫。 (例如:在一個最近的客戶處,我們找到了一個示例,其中在一個代碼庫中x / 0的數學運算返回0!)
即使代碼可以轉換并看起來不錯,這也不意味著它將始終運行!
僅僅翻譯成另一種語言并不能保證執行成功–一次成功的翻譯通常并不意味著語法錯誤。
可能需要一些調整,其他基礎結構來幫助代碼工作和構建。
運行中!=執行中
同樣,如果我們讓它運行并構建起來,那么在我們的試點轉換中,一切似乎都很棒。 一旦我們處理了數百萬筆交易并進行了記錄,您就會發現存儲桶中的所有漏洞。
這個過程很可能不會降低復雜性!
在此過程中,您很可能會從處理其所有復雜性的過程(在某些情況下幾乎沒有或沒有I / O損失)過渡到對資源的??慷慨解囊。
將這些代碼庫轉移到較新的語言中,通常涉及一些關注點分離:
- 數據訪問層與嵌入式SQL語句相對
- 與基于文件的數據存儲相反的潛在新關系數據存儲
- 與UI代碼相反的表示層
- 服務/業務邏輯層作為其自己的層
可能需要一些其他基礎架構來處理大型機免費提供的功能
像消息傳遞,容器或虛擬機編排,隊列和AD / LDAP / OAuth集成等。
因此,現在您可能會感覺就像您剛走進一家醫藥商業廣告,我在那兒說道:
“這種小藥丸可以解決您所有的背痛和黃色的趾甲問題。 潛在的副作用可能包括嘔吐,眼睛和/或耳朵出血,暫時性視力喪失,自發性脫發以及對字母“ A”的痛苦敏感性。”
但是,如果您專注于以下方面,這可能是一個成功的旅程:
如果您選擇一個可以將語法樹用于初始轉換的過程,則……
您只需調整語法并重新運行即可快速調整和調整更新后的輸出。
有時,基于模式的轉換是唯一的選擇。 但是,在許多情況下,可以生成語法樹–然后您只需調整語法即可,而不是一次性調整輸出或單個模式。
Keyhole的Syntax Tree Transformer及其專有的COBOL語法分析器基于語法,并且可以做到這一點!
這是使您分階段實施的可行選擇。
特別是如果您的組織沒有人員來處理可能將數千個程序轉換為新堆棧的工作。
通過在短時間內轉換所有舊代碼,您可以更快地淘汰舊技術。 然后,您可以重新分配這些資源,以分析和重新編寫或清理具有最大業務價值和ROI的代碼部分。
這使組織可以對業務真正重要的方面做出更有目的的決策。
提供對您的代碼庫中應用的業務邏輯的寶貴見解和分析。
在某些情況下,業務邏輯可能與代碼庫一樣古老,并且不再適用。 大多數客戶從中發現了很多價值,最終僅通過分析活動就將他們的代碼庫減少了10-25%。
有機會引入DevOps作為轉換的一部分。
根據所需的代碼最終狀態,在轉換過程之外,有機會引入DevOps作為轉換的一部分可能會有所幫助。 有時,“有能力”站起來使用一些工具或實施新流程最終會成為注入最佳實踐的機會,而無需經歷過多繁瑣的工作或走閘。
這些新的流程和工具可以被業務的其他領域所利用,并通過提高敏捷性和引起某些文化轉變來增加價值。
這個過程可以是短期預算雙贏。
由于可以快速轉換和淘汰大型機和較舊的技術,因此可以收回資本支出和維護成本。
使代碼進入轉換后狀態的總開發成本通常比手動團隊重寫要小。
需要注意的是,從長遠來看,這可能是一項更昂貴的工作,因為現在新語言和基礎架構中的代碼量很大–可能需要新的/額外的資源來維護和擴展代碼庫。 –但是至少您應該能夠找到它們!
該策略的要旨是:
如果您確定自己意識到該流程實際上可以做什么,并且選擇了一個強大的基于語法的工具(例如Keyhole語法樹變形器和我們的Parser –只是說出來),那么您將獲得非常可預測的結果,從而可以節省預算和時間勝。
既然我們已經了解了實施此策略的定義和利弊,那么實際上讓我們輕描淡寫吧。 本文的用例將使用Keyhole語法樹轉換器從COBOL轉換為JAVA。
“讓我們已經重新平臺!”
為了開始這個示例,我們將從COBOL的樣本位開始,該樣本已被我們的專有語法解析器轉換為JSON語法樹。 COBOL程序僅讀取DB2數據存儲并返回員工列表。 我們將不會顯示COBOL到JSON的實際轉換-而是從已經轉換的COBOL程序開始。
(對不起,這是博客文章的秘訣–因此,我們將以這種烹飪表演的方式,從昨晚已經準備好的火雞開始!如果您對組織的流程感興趣或想要演示–請與我們聯系 )。
首先,我們需要介紹幾個設置項目:
- 對于此示例,您將需要克隆此存儲庫: https : //github.com/in-the-keyhole/khs-syntax-tree-transformer
- 您將需要使用支持Docker的機器(Windows 10,各種版本的Linux,Mac)。 這是針對DB2示例的,如果您不想弄混Docker,則在回購中有一個簡單的COBOL示例。
- 這是一個人為的例子! 它并不意味著可以治愈任何疾病或在任何生產環境中使用! 它旨在演示該機制,并說明如何從語法樹到Java應用程序。
好的,讓我們開始吧!
步驟1:
克隆存儲庫后,將其作為Maven項目導入Eclipse,STS或Intellij。
第二步:
使用JSON輸入文件的命令行參數和發出的Java包名稱執行main方法。 像這樣:
這將在項目目錄中生成一個發出的Program.java program :
package khs.res.example.Programpublic class Program {private Double CONST-PI = null; private Double WORK-1 = 0; private Double WORK-2 = 0; private Double PRINT-LINE = null; public void static main(String[] args) {Program job = new Program ();job.A-PARA ();} public void A-PARA () {WORK-1 = 123.46WORK-2 = WORK-2+2WORK-2 = WORK-3*3C-PARA()}public void B-PARA () {CONST-PI = Math.PI;EDT-ID = ZERO}public void C-PARA () {B-PARA()}}以下是程序將使用的秘密醬汁分析器創建的輸入demo.json :
{"name" : "Program","typeName" : "CLASS","variables" : [ {"name" : "CONST-PI","typeName" : "VARIABLE","value" : null,"isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]}, {"name" : "WORK-1","typeName" : "VARIABLE","value" : "ZERO","isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]}, {"name" : "WORK-2","typeName" : "VARIABLE","value" : "ZERO","isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]}, {"name" : "PRINT-LINE","typeName" : "VARIABLE","value" : null,"isLocal" : false,"isWorking" : true,"isArray" : true,"fileLevel" : null,"variables" : [ {"name" : "EDT-ID","typeName" : "VARIABLE","value" : "SPACES","isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]}, {"name" : "FILLER","typeName" : "VARIABLE","value" : "' Perimeter '","isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]}, {"name" : "EDT-3-15-CIR","typeName" : "VARIABLE","value" : null,"isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]}, {"name" : "FILLER","typeName" : "VARIABLE","value" : "' Radius '","isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]}, {"name" : "EDT-3-15-RAD","typeName" : "VARIABLE","value" : null,"isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]}, {"name" : "FILLER","typeName" : "VARIABLE","value" : "' Pi '","isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]}, {"name" : "EDT-1-15-PI","typeName" : "VARIABLE","value" : null,"isLocal" : false,"isWorking" : true,"isArray" : false,"fileLevel" : null,"variables" : [ ]} ]} ],"functions" : [ {"name" : "A-PARA","typeName" : "FUNCTION","methods" : [ {"name" : "123.46TOWORK-1","typeName" : "METHOD","type" : {"name" : null,"typeName" : "MOVE","varName" : "WORK-1","value" : "123.46"}}, {"name" : "2TOWORK-2","typeName" : "METHOD","type" : {"typeName" : "ADD","value" : "2","var1" : "WORK-2","var2" : null}}, {"name" : "3GIVINGWORK-3","typeName" : "METHOD","type" : {"typeName" : "MULTI","value" : "3","var1" : "WORK-2","var2" : "WORK-3"}}, {"name" : "C-PARA","typeName" : "METHOD","type" : {"name" : "C-PARA","typeName" : "CALL"}} ]}, {"name" : "B-PARA","typeName" : "FUNCTION","methods" : [ {"name" : "PITOCONST-PI","typeName" : "METHOD","type" : {"name" : null,"typeName" : "MOVE","varName" : "CONST-PI","value" : "PI"}}, {"name" : "ZEROTOEDT-ID","typeName" : "METHOD","type" : {"name" : null,"typeName" : "MOVE","varName" : "EDT-ID","value" : "ZERO"}} ]}, {"name" : "C-PARA","typeName" : "FUNCTION","methods" : [ {"name" : "B-PARA","typeName" : "METHOD","type" : {"name" : "B-PARA","typeName" : "CALL"}} ]} ] }DB2示例
現在,在持久性方面邁出了一步,我們將轉換簡單的DB2程序以演示使用DB2 Express的Java代碼。
這是示例DB2 Cobol應用程序:
* -------------------------------------------------------------- * Selects a single employee into a record's detail fields, and * then displays them by displaying the record. * * Demonstrates Cobol-to-Java translation of a DB2 SELECT INTO * the detail fields of a parent record. * * Java has no native notion of a record aggregate. A SQL * SELECT INTO similarly lacks a record construct. * * Lou Mauget, January 31, 2017 * --------------------------------------------------------------IDENTIFICATION DIVISION.PROGRAM-ID. COBOLDB2.DATA DIVISION.WORKING-STORAGE SECTION.EXEC SQLINCLUDE SQLCAEND-EXEC.EXEC SQLINCLUDE EMPLOYEEEND-EXEC.EXEC SQL BEGIN DECLARE SECTIONEND-EXEC.01 WS-EMPLOYEE-RECORD.05 WS-EMPNO PIC XXXXXX.05 WS-LAST-NAME PIC XXXXXXXXXXXXXXX.05 WS-FIRST-NAME PIC XXXXXXXXXXXX.EXEC SQL END DECLARE SECTIONEND-EXEC.PROCEDURE DIVISION.EXEC SQLSELECT EMPNO, LASTNAME, FIRSTNMEINTO :WS-EMPNO, :WS-LAST-NAME, :WS-FIRST-NAME FROM EMPLOYEEWHERE EMPNO=200310END-EXEC.IF SQLCODE = 0DISPLAY WS-EMPLOYEE-RECORDELSEDISPLAY 'Error'END-IF.STOP RUN.使用我們的Antlr解析器已將其轉換為JSON語法樹。 使用khs.transformer.CommandLine.java對象將語法樹JSON轉換為以下Java應用程序。
/*** Java source, file COBOLDB2.java generated from Cobol source, COBOLDB2.cbl** @version 0.0.3* @author Keyhole Software LLC*/ public class COBOLDB2 {private static Logger Log = LoggerFactory.getLogger("COBOLDB2");// SQLCAprivate int sqlcode;// Level 05private String v_ws_empno;// Level 05private String v_ws_last_name;// Level 05private String v_ws_first_name;// Level 01private InItem[] v_ws_employee_record = new InItem[]{ () -> v_ws_empno, () -> v_ws_last_name, () -> v_ws_first_name };// Procedure division entry:public static void main(String[] args) {try {COBOLDB2 instance = new COBOLDB2();instance.m_procdiv();} catch (Exception e) {e.printStackTrace();}}private void m_procdiv () throws Exception {final String sql = "SELECT EMPNO, LASTNAME, FIRSTNME FROM EMPLOYEE WHERE EMPNO=200310";final OutItem[] into = new OutItem[]{s -> v_ws_empno = (String)s,s -> v_ws_last_name = (String)s,s -> v_ws_first_name = (String)s};sqlcode = Database.getInstance().selectInto( sql, into );if ( sqlcode == 0 ) {Display.display( v_ws_employee_record );} else {Display.display( "Error" );}// EXIT ...System.exit(0);}}以下步驟描述了如何設置DB2以執行該應用程序。 DB2 Express在Docker容器中運行。 沒有池連接。 這只是一個演示。 ?
Docker DB2 Express容器
確保您有權訪問Docker 。
使用此Docker映像進行初始DB2綁定: https : //hub.docker.com/r/ibmcom/db2express-c/
docker run --name db2 -d -it -p 50000:50000 -e DB2INST1_PASSWORD=db2inst1-pwd -e LICENSE=accept -v $(pwd)/dbstore:/dbstore ibmcom/db2express-c:latest db2start docker exec -it db2 bash創建運行中的Docker DB2 Express容器守護程序,并登錄到bash會話,如上所示。
發行su db2inst1
發出db2sampl (花一些時間來創建數據庫“ SAMPLE”)。
完成煙霧測試安裝后:
以Java運行: khs.transformer.CheckDb2Connection
控制臺上顯示以下內容:
一旦在Docker容器上安裝并驗證了數據庫,就可以執行轉換后的Cobol / DB2到Java程序khs.res.db2demo.COBOLDB2.java 。 一旦執行該程序,我們將得到以下輸出:
基本上是魔術!
同樣,這是人為的,但是我們采用了一個COBOL程序,該程序被轉換為JSON語法樹,然后最終得到了一個Java應用程序,該程序從DB2數據庫返回了我們的數據–正是COBOL程序所做的!
結論
希望在本文和上面的示例之后,我們都對重新平臺戰略有了更好的了解。 此策略是否適合您的組織是另一個話題(順便提一下,我們很樂意與您聯系)。
我要打動的重點是,即使聽起來很酷,代碼轉譯也不是遺留代碼狼的靈丹妙藥! 我還想告訴您,雖然充滿了危險,但是如果正確使用正確的方法并使用可靠的工具(ahem – 鎖Kong語法樹變壓器和解析),這可能是一個非常可行的策略。
“那么,我們在這里完成了什么?”
總而言之,我們涵蓋了以下內容:
- 現代化簡介
- 回顧現代化的重平臺戰略
- 使用Keyhole語法樹變壓器的重新平臺示例
- 關于此策略的價值/風險的其他總結想法
我們肯定希望您能像我們一樣喜歡它。 請,如果您有任何問題或反饋,請在下面發布或直接與我們聯系。
謝謝,記得負責任地現代化!
資源/參考:該演示也可以在這里找到: https : //github.com/in-the-keyhole/khs-syntax-tree-transformer
翻譯自: https://www.javacodegeeks.com/2017/02/adventures-modernization-strategy-example-converting-cobol-java.html
總結
以上是生活随笔為你收集整理的现代化历险记:策略+将COBOL转换为Java的示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: perl大骆驼和小骆驼_你好骆驼:自动文
- 下一篇: 免费好用电脑清理优化工具推荐(免费又好用