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