COBOL на инвалидной коляске

7 minute read

Все началось с обсуждения в баре о том, как информационные технологии развиваются и накапливают собственное историческое наследие. Когда человек получает высшее художественное образование, он обязательно изучает Историю Искусств(History of Art). Это имеет огромное значение, потому что современные достижения не возникают вдруг, они — результат долгого и сложного процесса эволюции. Аналогично и с информационными технологиями: их развитие - это эволюционный процесс. Каждая новая разработка опирается на опыт, накопленный предшествующими. Уже сегодня в учебных заведениях нужно преподавать не только Компьютерные Науки(Computer Science), но и Историю Компьютерных Технологий(History of Computer Science). Исследование старых вычислительных технологий может приносить не только удовольствие, но и быть источником идей для разработки чего-то нового.

Или нас ждет новая религия и поклонение технологиям древних

В конце концов, разговор в баре навеял воспоминания о проекте под названием “COBOL на инвалидной коляске”. Это джаст фор фан веб фреймворк на COBOL. Сегодня мы создадим на этом фреймворке бэкенд, который будет генерировать JSON. Такой бэкенд вполне пригодится для любого мобильного приложения. Посмотрим как технологии прошлого работают с технологиями современными.

Кратко про COBOL

COBOL расшифровывается как COmmon Business-Oriented Language. Язык программирования COBOL начал разрабатываться в 1959 году и был выпущен в 1969 году. На момент написания статьи ему исполнилось 65 лет. Обычно люди, которые умеют на нем программировать, примерно того же возраста. Несмотря на это, COBOL продолжает использоваться в некоторых крупных банках. Вполне возможно что код, который до сих пор обслуживает пользователей, пережил большинство своих создателей.

COBOL стал первым языком, который оказался идеально подходящим для своих задач. В определённом смысле COBOL стал той искрой, которая зажгла нашу современную компьютерную эру. До появления COBOL разработчики приходилось использовать к различные версии ассемблера, что не очень-то удобно.

В 1959 году программистка Мэри Хоуэс пришла к выводу, что отрасли требуется язык программирования, который позволит легко писать программы и будет универсально совместим с любой машиной. Для этого она организовала комитет экспертов, включая представителей только зарождающегося сектора бизнес-компьютеров, для работы над созданием такого языка под эгидой Министерства обороны. Цель заключалась в разработке языка, который мог бы быть понятен и доступен любому менеджеру компании, даже если он не имеет программного образования.

Спустя десятилетие работы, активно продвигаемой множеством женщин-суперзвёзд этой отрасли, например, пионеркой компьютерных наук Джин Саммет, был создан простой в понимании язык. Например, для сложения двух чисел можно было написать ADD Num1, Num2 GIVING Result. Чтобы выполнить вычисление три раза, нужно было написать PERFORM 3 TIMES.

Программы на COBOL

Начнем сразу с примера и попробуем разобраться что в этом примере происходит

1000100 IDENTIFICATION DIVISION.
2000200 PROGRAM-ID. HELLOWORLD.
3000300* --- Это пустая строчка. ---
4000400 ENVIRONMENT DIVISION.
5000500 DATA DIVISION.
6000600 PROCEDURE DIVISION.
7000700 BEGIN.
8000800          DISPLAY "Hello World!".
9000900          STOP RUN.

Начнем со строк в COBOL. Все строки программы состоит из 80 символов.

  • Символ 1-6: номер строки (необязателен)
  • Символ 7: “индикатор”
    • * — строка комментарий,
    • — строка “продолжение”,
    • D - строка debug.
  • Символ 8 – 11: Зона А. В ней должны начинаться DIVISION’ы, SECTION’ы, имена и заголовки параграфов, а также индикаторы и номера “уровней” (это все рассмотрим позже).
  • Символ 12-72: Зона Б. Тут непосредственно размещаются выражения “кода”.
  • Символ 73-80: Зона комментария. Не обрабатывается компилятором и полностью предоставлена програмисту.

Каждая программа на COBOL состоит из четырех разделов, которые называются DIVISION. Эти разделы расположены в строгом порядке и содержат определённые компоненты. Внутри DIVISION разделы делятся на секции (Section) и абзацы (Paragraph).

IDENTIFICATION DIVISION. — описывает программу и содержит такие параграфы, как

1        PROGRAM-ID. Helloworld.
2        AUTHOR. Beginner.
3        INSTALLATION. MyLocalCobolComputer.
4        DATE-WRITTEN. 19/03/2011.
5        DATE-COMPILED. 19/03/2011.
6        SECURITY. Iwillnottellanybodythiscode.

Содержимое этих параграфов представляет собой обычный комментарий и в принципе записать туда можно хоть “2024 год от Рождества Христова”.

ENVIRONMENT DIVISION как следует из названия, описывает среду, в которой создаётся программа. Этот раздел включает в себя две секции.

  • CCONFIGURATION SECTION включает в себя параграфы SOURCE-COMPUTER, OBJECT-COMPUTER и SPECIAL-NAMES. Первые два параграфа выполняют комментирующую функцию, указывая, на каком компьютере написана программа и для какого компьютера она предназначена. Параграф SPECIAL-NAMES представляет собой более сложную тему, которую тут мы рассматривать не будем(или вы можете самостоятельно поискать информацию на эту тему).
  • INPUT-OUTPUT SECTION описывает процессы ввода-вывода. Эта секция является крайне необходимой и важной. В рамках этой статьи мы ее тоже не коснемся, но можно посмотреть реализацию в самом фреймворке. Она включает в себя параграфы FILE-CONTROL и I-O-CONTROL.

DATA DIVISION. содержит описания всех переменных. Включает в себя 4 секции:

  • FILE SECTION. описывает структуру файлов.
  • WORKING-STORAGE SECTION. описывает переменные.
  • LOCAL-STORAGE SECTION. описывает переменные, которые создаются и инициализируются каждый раз при выполнении (поподробней в следующие разы).
  • LINKAGE SECTION. описывает данные, которые мы получаем при вызове других программ.

PROCEDURE DIVISION включает в себя основную часть программы. Эта часть состоит из пользовательских секций и параграфов, которые содержат сами выражения. В нашем случае имеется только один параграф:

BEGIN. пользовательский параграф.

1        DISPLAY "Hello World!".
2        STOP RUN. Собственно сами выражения.

Кстати, в COBOL 300 ключевых слов. Для сравнения, в Go всего 25

И напоследок. Каждое выражение должно заканчиваться “точкой”, а регистр выражений не важен.

REST для динозавров

Мы уже овладели искусством написания простых программ на языке COBOL, сделали первые уверенные шаги в этом направлении. Пора перейти к изучению того, на что способен фреймворк COBOL on Wheelchair. На этом этапе, для того чтобы начать работать с фреймворком, необходимо сперва скопировать проект на свой компьютер. Это позволит нам с головой окунуться в изучение его возможностей и потенциала.

1git clone https://github.com/azac/cobol-on-wheelchair

Дальше можно воспользоваться инструкцией и настроить .htaccess в Apache самостоятельно. Но кто в 2024 помнит как настраивать Apache? Нам повезло и в проект уже добавили Dockerfile. Достаточно просто собрать и запустить контейнер

1docker build -t cobol .
2docker run --rm -p 8888:80 cobol:latest

Как все это организовано? Apache использует модуль mod_cgid, чтобы через CGI (Common Gateway Interface) запускать как скрипты, так и скомпилированные программы. Если в начале 2000-х годов вы создавали сайты на PHP, то у вас, вероятно, сейчас возникают флешбэки из тех времен. Могу вас понять.

Посмотрим структуру базового проекта

1/controllers    <- тут все логика на COBOL
2/views          <- тут живут шаблоны для рендеринга
3
4config.cbl      <- файл конфигурации для определения роутов
5cow.cbl         <- основной код фреймворка CoW 
6downhill.sh     <- скрипт для компиляции
7the.cow         <- скомпилированный CoW проект

Роутинг

Конечно, в COBOL мы не можем просто замапить наши модели и получить готовый REST как в какой-нибудь Java. Нам придется описывать каждый роут отдельно, как в Go. Все роутны описываются в файле config.cbl

 1move 4 to nroutes.
 2
 3move "/"                           to routing-pattern(1).
 4move "indexweb"                    to routing-destiny(1).
 5
 6move "/showsum/%value1/%value2"    to routing-pattern(2).
 7move "showsum"                     to routing-destiny(2).
 8
 9move "/example/%value"             to routing-pattern(3).
10move "example"                     to routing-destiny(3).
11
12move "/showname/%value"            to routing-pattern(4).
13move "showname"                    to routing-destiny(4). 

Таблица роутов может хранить 99 элементов. В первой строке move 4 to nroutes указываем сколько роутов будет в нашей программе.

routing-pattern - тут хранятся все наши паттерны путей outing-destiny - а туту все обработчики роутов. По сути, это названия програм, который описаны в файлах .cbl в папке controllers

Контроллеры

COBOL — это несложный язык, однако требует внимания к некоторым его особенностям. Например, все переменные должны быть определены в строго определённых частях программы, а изменение структуры самой программы невозможно. Но как только мы адаптируемся к этим ограничениям, разработка веб-приложений на COBOL будет похода на написание стихотворений.

Посмотрим на самый простой контроллер example.cbl

 1       identification division.
 2       program-id. hello.
 3
 4       data division.
 5       working-storage section.
 6
 7       01 the-vars.
 8
 9          03  COW-vars OCCURS 99 times.
10        
11            05 COW-varname       pic x(99).
12            05 COW-varvalue      pic x(99).    
13
14       linkage section.
15
16       01 the-values.
17
18          05 COW-query-values           occurs 10 times.
19            10 COW-query-value-name     pic x(90).
20            10 COW-query-value          pic x(90).
21
22
23       procedure division using the-values.
24
25
26           MOVE "username" to COW-varname(1).
27           MOVE COW-query-value(1) to COW-varvalue(1).   
28
29           call 'cowtemplate' using the-vars "hello.cow".
30
31      
32       goback.
33
34       end program hello.

Постараемся разобраться что тут происходит. Начнем с секции working-storage section. Тут мы получаем переменные из запроса и складываем их в таблицу COW-query-values. Ключ этой таблицы COW-query-value-name, а значение COW-query-value. Всего таблица может содержать 10 переменных

1pic x(90)

Это код выделяет память под строку на 90 символов. В COBOL мы указываем не размерность типа в битах, а количество символов, которые будут хранится в этой переменной. Например, операция pic x(90) говорит, что переменная будет содержать строку в 10 символов, а pic 9(3) говорит что в переменной будет хранится число с 3 разрядами.

Теперь перейдем к секции working-storage section. Тут мы определяем таблицу переменных, которые будут рендерится в шаблоне. В этой таблице COW-varname - это название переменной, а COW-varvalue - это значение.

Нам нужно перенести значение из переменных запроса в переменные для рендеринга. Для этого выполняем инструкции

1MOVE "username" to COW-varname(1).
2MOVE COW-query-value(1) to COW-varvalue(1).

Теперь все наши переменные можно передать в шаблон и использовать их для рендеринга. Мой пример шаблона называется example.cow

 1<html>
 2	<head>
 3		<title>
 4			Hello {{username}}.
 5		</title>
 6	</head>
 7	<body>
 8
 9		<h2> Hello {{username}}! </h2>	
10
11	</body>
12</html>

Все эти сложности с таблицами нужны, чтобы можно было удобно использовать названия в шаблонах

Рендерим JSON

Чтобы сделать что-то похожее на API, достаточно отрендерить данные в JSON шаблон. Тут ничего сложного. Создаем файл example-json.cow и готовим будущий JSON:

1{
2    "name": "{{name}}"
3}

Чтобы браузер понял что нам нужно, необходимо правильно отдавать заголовок. Для этого в файле cow.cbl нужно найти строку

1"content-type: text/html; charset=utf-8"

И заменить ее на нужный заголовок:

1"content-type: application/json; charset=utf-8"

Теперь у нас есть все, чтобы построить на COBOL стильное, модное и молодежное API

Ссылки