"More than 1 million COBOL programs run every second of every day.
Every time someone swipes a card or withdraws cash from an ATM, they're running COBOL."
— IBM Z Xplore
This project is part of the IBM Z Xplore Advanced Challenge (CBLH). It proves that I can work directly inside the technology that runs the global economy — mainframe systems.
In plain English: I took a JSON data file (think of it like a spreadsheet of grocery products), fed it into a COBOL program running on an IBM Z mainframe, and produced a beautifully formatted HTML grocery store flyer — complete with products, prices, images, and automatic 50% discount badges for expiring items.
This is not a toy project. The exact same architecture is used by the world's largest banks, insurance companies, and governments every single day.
| Detail | Value |
|---|---|
| 🏷️ Challenge Name | CBLH — Here for the Long Haul |
| 🏛️ Platform | IBM Z Xplore (Advanced Level) |
| ⚙️ Primary Language | COBOL (Common Business-Oriented Language) |
| 🖥️ Operating System | z/OS (IBM Mainframe OS) |
| 🛠️ Tools Used | VSCode, IBM Z Open Editor, Zowe CLI, JCL |
| 📦 Input | JSON data file |
| 📄 Output | HTML-formatted Grocery Store Flyer |
| ⏱️ Estimated Time | 16 steps / 150 minutes |
| 🎓 Certification | IBM Z Xplore Advanced Badge |
Imagine you're a bank. Every time a customer taps their debit card, a program needs to:
- Instantly check their balance
- Approve or decline the transaction
- Update hundreds of records simultaneously
- Do this millions of times per second, without ever failing
That program? It's almost certainly written in COBOL, running on an IBM Z mainframe.
💡 COBOL is not old and dusty — it's battle-hardened and irreplaceable.
The average COBOL developer is over 55 years old. Companies are desperately looking for engineers who understand this stack.
This project demonstrates that I can:
- Read and write COBOL programs from scratch
- Navigate and operate IBM Z mainframe infrastructure
- Debug errors at the system level (called "ABENDs" — abnormal program endings)
- Connect modern technologies (JSON, HTML) to legacy systems
- Use enterprise developer tools (Zowe CLI, JCL, VSCode with IBM extensions)
Here is how all the pieces connect — from raw data all the way to a finished, customer-ready flyer:
flowchart TD
A([🗃️ JSON Input File\nProduct catalog with names,\nprices & image URLs]) --> B
B[📋 JCL Script\nJob Control Language —\nthe mainframe's task runner] --> C
C{🔄 COBOL Program\nCBLJSON\nRunning on IBM Z} --> D
C --> E
D([✅ Completion Code 0000\nSuccess — program ran\nwithout errors]) --> F
E([❌ ABEND / Error\nAbnormal program end —\nmust be debugged]) --> G
G[🔍 Debug via\nZowe Explorer\nRead SYSOUT logs] --> C
F --> H([📄 Plain Text Flyer\nFirst output —\nno formatting yet])
H --> I[Add HTML Parameter\nvia JCL PARM field]
I --> J([🌐 HTML Flyer Output\nRich formatting,\ntables, images])
J --> K[💾 Save to USS\ncobol.html\nUnix System Services]
K --> L([🏆 Submit CHKACBLH\nFinal validation job —\nChallenge Complete!])
style A fill:#005073,color:#fff
style B fill:#6B2D8B,color:#fff
style C fill:#00C8FF,color:#000
style D fill:#00AA55,color:#fff
style E fill:#FF4444,color:#fff
style F fill:#00AA55,color:#fff
style G fill:#FF6B35,color:#fff
style H fill:#FFD700,color:#000
style I fill:#6B2D8B,color:#fff
style J fill:#00C8FF,color:#000
style K fill:#005073,color:#fff
style L fill:#FFD700,color:#000
Every step below was completed hands-on. Here's exactly what happened and why it matters.
The first step was installing and configuring the IBM Z Open Editor extension for VSCode — this gives COBOL syntax highlighting, error detection, and code navigation directly in the editor.
One of the first things I configured was Column Selection Mode. COBOL is a column-sensitive language — specific columns have specific meanings (columns 7–72 are for code, columns 73–80 are ignored by the compiler). Getting this right from the start prevents a whole category of subtle bugs.
Before writing a single line of code, I needed to create a Partitioned Dataset (PDS) on the mainframe — think of it like a folder on a remote server that the mainframe can compile and execute from.
# Check if COBOL library already exists
zowe files list data-set Zxxxxx.CBL -a
# Create one if missing
zowe files create pds Zxxxxx.CBL --data-class spds| Public Source Member | My Working Copy |
|---|---|
ZXP.PUBLIC.SOURCE(JSONCBL) |
Zxxxxx.CBL(CBLJSON) |
ZXP.PUBLIC.SOURCE(JSONJCL) |
Zxxxxx.JCL(JSONJCL) |
JCL (Job Control Language) statements can be up to 80 columns wide, but columns 73–80 are completely ignored by the compiler. Code that accidentally spills into those columns will silently vanish — a notoriously tricky bug.
I configured VSCode with a ruler at column 72 to prevent this:
"editor.rulers": [72]Opening the COBOL source file CBLJSON revealed two syntax errors in the Problems panel. I tracked down and fixed both before proceeding.
💡 This is exactly what a real mainframe developer does every day — read the compiler's error messages and surgically fix the code.
With the code clean, I submitted the JCL job to the mainframe. This triggers:
- Compilation — COBOL source code is turned into a machine-executable load module
- Execution — The compiled program runs using the JCL parameters
After the job runs, the mainframe returns a Completion Code (CC):
| Code | Meaning |
|---|---|
CC 0000 |
✅ Complete success — no errors |
CC 0004 |
|
CC 0008 |
❌ Error — logic problems, check output |
CC 0012+ |
🔥 Severe error — program likely failed |
ABEND Uxxxx |
💥 Abnormal End — crash, needs diagnosis |
The job returned an ABENDU4038 — an abnormal program end. This specific code means there was a mismatch between the COBOL program's file name and the DD name defined in the JCL.
Think of it like this: the COBOL program was looking for a file called FLYYFILE, but the JCL had defined it as FLYRFILE. One wrong letter, and the whole program crashes.
flowchart LR
A([COBOL program\nlooks for FLYYFILE]) -- ❌ Mismatch --> B([JCL defines\nFLYRFILE])
B -- Fix typo in JCL --> C([✅ FLYRFILE matches\nFLYRFILE])
C --> D([Program runs\nsuccessfully])
style A fill:#FF4444,color:#fff
style B fill:#FF6B35,color:#fff
style C fill:#00AA55,color:#fff
style D fill:#00C8FF,color:#000
After fixing the DD name mismatch, the program compiled and ran cleanly. The output file RUNPROG:FLYRFILE now contained a plain-text grocery store flyer.
Products expiring within the week automatically had a 50% discount applied — this logic was already built into the COBOL program.
The flyer was printing product data, but the store name "Corner Grocery Store" was missing from the title section. Digging into the COBOL code, I found the DATA DIVISION variable was defined but never moved to the output record before printing.
This is a classic COBOL pitfall: declaring data and forgetting to MOVE it into place before writing output.
The flyer worked in plain text, but grocery customers (and hiring managers) expect something prettier. The COBOL program had a built-in parameter to switch to HTML output mode.
I modified the JCL PARM field to pass the HTML flag:
// EXEC PGM=CBLJSON,PARM='HTML'The program's LINKAGE SECTION reads this parameter and switches the output format accordingly — a clean example of parameterised COBOL design.
After resubmitting, the output file now contained valid HTML markup:
But how do you preview HTML inside a mainframe file explorer? VSCode has the answer.
I installed the HTML Preview extension for VSCode to render the flyer output in real time without leaving the editor.
The output file was named .FLYRFILE — VSCode didn't know it was HTML. I configured the language association so VSCode treats it as HTML, enabling syntax highlighting and the live preview.
One click on "Open Preview to the Side" and the flyer rendered in the browser panel. It looked like a proper web page — but something was still wrong…
The prices were showing but the dollar signs were missing. In COBOL, the $ character has a special meaning (it's a currency symbol in PICTURE clauses), so it needs to be declared correctly in the SPECIAL-NAMES section:
SPECIAL-NAMES.
CURRENCY SIGN IS '$'.Without this declaration, the compiler strips the dollar sign from the output.
The JSON input file had URLs pointing to real product images, but the COBOL program's JSON parsing structure (the JSON-ITEMS working storage) didn't have a field mapped to the image URL.
I added the missing PRODUCT-IMAGE field to the JSON structure and rewired it into the HTML output template:
05 PRODUCT-IMAGE PIC X(200).After resubmitting — the flyer looked exactly like a real grocery store advertisement:
The final step was saving the HTML output to my USS home directory and submitting the CHKACBLH validation job to confirm completion.
| Technology | What It Does | Real-World Equivalent |
|---|---|---|
| COBOL | Core business logic — reads JSON, processes discounts, formats output | Java / Python in a bank's transaction engine |
| JCL | Tells the mainframe how to compile and run the COBOL program | A Makefile or CI/CD pipeline |
| z/OS | The mainframe operating system — enterprise-grade, 99.999% uptime | Linux, but for trillion-dollar workloads |
| IBM Z Open Editor | VSCode extension — COBOL syntax highlighting & error detection | ESLint / IntelliJ for enterprise code |
| Zowe CLI | Command-line access to mainframe datasets and jobs from your laptop | AWS CLI, but for IBM Z |
| JSON | Input data format — product names, prices, image URLs | A REST API payload |
| HTML/CSS | Final output format — styled grocery flyer rendered in a browser | A React component's rendered output |
| USS | Unix System Services — a Unix shell built into z/OS | Linux filesystem on the mainframe |
This challenge demonstrates skills that directly map to enterprise reliability requirements:
flowchart LR
A([Input Validation\nJSON field mapping\nin COBOL DATA DIV]) --> B([Error Handling\nABEND diagnosis\nvia SYSOUT logs])
B --> C([Job Control\nCC codes, restart\nlogic in JCL])
C --> D([Output Integrity\nFormatted HTML\nmatches spec])
D --> E([Automated Validation\nCHKACBLH job\nconfirms correctness])
style A fill:#005073,color:#fff
style B fill:#FF6B35,color:#fff
style C fill:#6B2D8B,color:#fff
style D fill:#00C8FF,color:#000
style E fill:#FFD700,color:#000
- Zero unhandled crashes — every ABEND was diagnosed and resolved with root-cause analysis
- Parameterised output — a single COBOL program produces both plain-text and HTML via JCL parameters, no code duplication
- Data integrity — the 50% discount logic runs automatically and accurately on all eligible items without manual intervention
- Validated completion — the final
CHKACBLHjob provides automated test verification of output correctness
Working with mainframe systems means operating in one of the most security-conscious environments in tech. Key concepts demonstrated:
| Security Layer | Implementation in This Project |
|---|---|
| Dataset Access Control | Working only within own Zxxxxx.* partitioned datasets |
| Job Submission Authority | JCL submitted under authenticated z/OS user credentials |
| USS File Permissions | HTML output saved to protected USS home directory |
| No Hardcoded Credentials | All access handled via Zowe secure credential store |
| Input Validation | COBOL DATA DIVISION enforces strict field-length and type constraints on JSON input |
💡 IBM Z mainframes handle over $10 trillion in financial transactions per year — the security model they use is the gold standard for enterprise computing.
For the technically curious, here is how the COBOL program is organised:
flowchart TD
A([IDENTIFICATION DIVISION\nProgram name, author, date]) --> B
B([ENVIRONMENT DIVISION\nFile assignments,\nspecial-names for currency]) --> C
C([DATA DIVISION\nFile section: FLYRFILE\nWorking storage: JSON structure,\nHTML templates, product fields]) --> D
D{PROCEDURE DIVISION\nMain Logic} --> E
D --> F
E([Read PARM parameter\nHTML or plain-text mode]) --> G
F([Open JSON input\nFLYYFILE → FLYRFILE]) --> G
G([Parse JSON fields\nProduct name, price,\nexpiry, image URL]) --> H
H{Expiry check\nExpiring soon?} --> I
H --> J
I([Apply 50% discount\nCompute SALE-PRICE]) --> K
J([Use regular price]) --> K
K([Format output line\nHTML tags or plain text]) --> L
L([Write to FLYRFILE\nUntil all products done]) --> M
M([Close files\nStop run])
style A fill:#005073,color:#fff
style B fill:#005073,color:#fff
style C fill:#6B2D8B,color:#fff
style D fill:#00C8FF,color:#000
style E fill:#FF6B35,color:#fff
style F fill:#FF6B35,color:#fff
style G fill:#FFD700,color:#000
style H fill:#FF4444,color:#fff
style I fill:#00AA55,color:#fff
style J fill:#00AA55,color:#fff
style K fill:#6B2D8B,color:#fff
style L fill:#005073,color:#fff
style M fill:#FFD700,color:#000
CBLH/
│
├── 📂 CBL/
│ └── CBLJSON ← Main COBOL source program
│
├── 📂 JCL/
│ └── JSONJCL ← Job Control Language — compiles & runs CBLJSON
│
├── 📂 JSON/
│ └── (embedded in JCL SYSIN) ← Product data: names, prices, image URLs
│
├── 📂 OUTPUT/
│ ├── FLYRFILE ← Generated grocery flyer (plain text or HTML)
│ └── cobol.html ← Final HTML flyer saved to USS home directory
│
└── 📂 images/ ← Screenshots from development walkthrough
If you have access to IBM Z Xplore, here are the exact steps to run this from scratch:
- ✅ IBM Z Xplore account (free at ibmzxplore.influitive.com)
- ✅ VSCode with IBM Z Open Editor extension installed
- ✅ Zowe CLI installed and connected to Z Xplore host
- ✅ Completed IBM Z Xplore Fundamentals track
# 1. Create your COBOL library
zowe files create pds Zxxxxx.CBL --data-class spds
# 2. Copy source members from public library
# (done via Zowe Explorer in VSCode)
# ZXP.PUBLIC.SOURCE(JSONCBL) → Zxxxxx.CBL(CBLJSON)
# ZXP.PUBLIC.SOURCE(JSONJCL) → Zxxxxx.JCL(JSONJCL)
# 3. Fix syntax errors (see Step 4 above)
# 4. Submit the job
# Right-click JSONJCL → Submit Job
# 5. Check completion code
# CC 0000 = success
# 6. Save HTML output to USS
# Copy FLYRFILE content → ~/cobol.html
# 7. Submit final validation
# ZXP.PUBLIC.JCL(CHKACBLH) → Submit JobThis project stretched across multiple disciplines simultaneously:
- Systems programming — understanding how mainframe jobs are structured, compiled, and executed
- Legacy system debugging — reading cryptic ABEND codes and SYSOUT logs without a debugger
- Data pipeline thinking — tracing data from a JSON structure through COBOL fields to HTML output
- Enterprise tooling — using Zowe CLI and IBM Z Open Editor the way real production teams do
- Patience with constraints — COBOL's column rules and fixed-format structure require careful attention to detail
I'm a Senior Full-Stack Engineer with 9+ years of experience building high-throughput backend systems — payment infrastructure, real-time WebSocket servers, and distributed data pipelines.
I'm deliberately expanding into mainframe development, cloud architecture, and enterprise systems because I believe the engineers who can bridge modern cloud stacks with legacy mainframe infrastructure are the most valuable people in tech right now. This project is one piece of that bridge.
Core stack: Go · Python · COBOL · SQL · AWS · Docker · Redis · z/OS · JCL



















