Про COBOL в баре

Post Thumbnail

Все началось с обсуждения в баре о том, как информационные технологии развиваются и накапливают собственное историческое наследие. Когда человек получает высшее художественное образование, он обязательно изучает Историю Искусств (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

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

000100 IDENTIFICATION DIVISION.
000200 PROGRAM-ID. HELLOWORLD.
000300* --- Это пустая строчка. ---
000400 ENVIRONMENT DIVISION.
000500 DATA DIVISION.
000600 PROCEDURE DIVISION.
000700 BEGIN.
000800          DISPLAY "Hello World!".
000900          STOP RUN.

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

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

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

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

        PROGRAM-ID. Helloworld.
        AUTHOR. Beginner.
        INSTALLATION. MyLocalCobolComputer.
        DATE-WRITTEN. 19/03/2011.
        DATE-COMPILED. 19/03/2011.
        SECURITY. Iwillnottellanybodythiscode.

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

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

  • CONFIGURATION 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. пользовательский параграф.

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

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

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

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

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

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

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

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

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

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

/controllers    <- тут вся логика на COBOL
/views          <- тут живут шаблоны для рендеринга

config.cbl      <- файл конфигурации для определения роутов
cow.cbl         <- основной код фреймворка CoW 
downhill.sh     <- скрипт для компиляции
the.cow         <- скомпилированный CoW проект

Роутинг

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

move 4 to nroutes.

move "/"                           to routing-pattern(1).
move "indexweb"                    to routing-destiny(1).

move "/showsum/%value1/%value2"    to routing-pattern(2).
move "showsum"                     to routing-destiny(2).

move "/example/%value"             to routing-pattern(3).
move "example"                     to routing-destiny(3).

move "/showname/%value"            to routing-pattern(4).
move "showname"                    to routing-destiny(4). 

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

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

Контроллеры

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

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

       identification division.
       program-id. hello.

       data division.
       working-storage section.

       01 the-vars.

          03  COW-vars OCCURS 99 times.
        
            05 COW-varname       pic x(99).
            05 COW-varvalue      pic x(99).    

       linkage section.

       01 the-values.

          05 COW-query-values           occurs 10 times.
            10 COW-query-value-name     pic x(90).
            10 COW-query-value          pic x(90).


       procedure division using the-values.


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

           call 'cowtemplate' using the-vars "hello.cow".

      
       goback.

       end program hello.

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

pic x(90)

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

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

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

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

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

<html>
	<head>
		<title>
			Hello {{username}}.
		</title>
	</head>
	<body>

		<h2> Hello {{username}}! </h2>	

	</body>
</html>

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

Рендерим JSON

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

{
    "name": "{{name}}"
}

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

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

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

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

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

Ссылки