Давным-давно, когда мир был юн, и компьютеры в нем были в новинку, я учился по программе на младшего сотрудника (Associate Degree) по обработке данных – программ по «компьютерным наукам» тогда не было – и в рамках этой программы преподавались бухгалтерское дело, математика, статистика, а также три языка программирования: ассемблер IBM/360, FORTRAN и COBOL. К 80-м студентам уже рассказывали, что COBOL мертвый язык, и никто его больше не изучают.
Ныне государственные учреждения и банки умоляют прислать им COBOL-щиков, специалистов по языку, который не хочет умирать.
Лора Келли, губернатор Канзаса, сказала:
По всей стране еще осталось множество служб занятости, чьи системы по-прежнему работают на COBOL. Знаете, такая очень-очень старая технология,” – говорит Келли, - “Наша служба занятости признает эту проблему и инициировала модернизацию, но, к сожалению, модернизация – как раз такой процесс, на который требуется время. Потом все планы смешал этот вирус, и пришлось прекратить работы по переходу на гораздо более надежную систему. Поэтому они пользуются по-настоящему древними программами
Губернатор Нью-Джерси Фил Мерфи выступил по телевидению, умоляя COBOL-программистов о помощи.
Итак, как же выучить COBOL, срубить на этом кучу денег, спасти множество госслужб, которым нужен новый код, чтобы справиться со всеми этими программами государственного стимулирования?
Давайте разберемся.
COBOL? Какой такой COBOL?
COBOL означает COmmon Business Oriented Language (бизнес-ориентированный язык общего назначения). Это один из первых высокоуровневых языков программирования, был спроектирован группой, финансируемой Министерством Обороны. Их задачей было разработать общий язык для решения бизнес-задач. Эту группу прозвали CODASYL— «Комитет по языкам систем обработки данных» — и группа подготовила спецификацию «бизнес-ориентированного языка общего назначения», опираясь на идеи из языка FLOW-MATIC, разработанного Грейс Хоппер, а также на идеи других языков, в том числе, AIMACO из компании Univac и COMTRAN, применявшегося в IBM. Получившийся у них язык был несколько раз пересмотрен, но быстро занял доминирующую позицию в деле построения бизнес-систем и не утратил этого лидерства до сих пор.
COBOL пользуется множество компаний, среди которых - IBM, UPS и Cigna. Марио Себальос, программист из Cigna, рассказывает: “Синтаксис оставили простым, чтобы не-программисты (“Бизнес”) могли читать и понимать его. В COBOL все выражается явно, чтобы не оставалось места ни для каких допущений.”
Разумеется, были у него и критики. Известно, как в 1975 году Эдсгер Вибе Дейкстра провозгласил, что “Использование COBOL калечит ум. Его преподавание, следовательно, должно рассматриваться как уголовное преступление [sic].” Несомненно, это поспособствовало отказу от преподавания COBOL в университетах, но он оставался доминирующим бизнес-языком.
Но найти людей со знанием COBOL бывает сложно. «Мейнфрейм – платформа, на которой сложно учиться, и все дело в цене», - говорит Себальос. – «у разработчика-одиночки нет денег, чтобы взять в аренду мейнфрейм. Очень в немногих вузах читают курсы по мейнфреймам и COBOL. Когда IBM стала осваивать удаленную работу и аутсорсинг, они прекратили стимулировать американские вузы преподавать курсы по мейнфреймам и COBOL. Специалистов стали выбирать из-за рубежа. Любой талантливый американец обошелся бы слишком дорого, учитывая, сколько он берет за консультации.”
Почему COBOL по-прежнему в цене
COBOL отличается от типичных языков программирования, используемых сегодня, и в некоторых отношениях он очень ограничен: в нем не поддерживается динамическое выделение памяти, не так легко обратиться к низкоуровневым возможностям операционной системы или конкретной архитектуры компьютера. В самых распространенных вариантах этого языка неприменима рекурсия. На COBOL никому не захотелось бы написать компилятор. Если показать COBOL студенту-информатику, его это просто заденет.
В данном случае допускается категорийная ошибка. На самом деле, COBOL – это предметно-ориентированный язык, специфичный для конкретной области бизнес-программирования. Роберт Гласс показал, в каких именно отношениях COBOL лучше подходит для бизнес-программирования, чем более универсальные языки. Например, вот по каким причинам:
1) В бизнес-ориентированном языке нужно объявлять неоднородные данные, управлять и оперировать ими. В бизнес-программах перемежаются строки фиксированной и переменной длины, бок о бок применяются целые числа, числа с плавающей точкой и десятичные данные, а также с диким энтузиазмом ставятся сложные структуры-записи, зачастую – с переменными частями. Программисты баз данных знакомы с некоторыми из этих проблем, и инструменты для объектно-реляционного отображения регулярно натыкаются на такие сложности.
2) Бизнес-данные и финансовая информация должны управляться с применением истинно десятичных типов данных. Системы бухгалтерского учета должны давать результат, точный до последнего десятичного знака, и при этом в точности воспроизводить результаты вычислений, сделанных вручную. Обычные числа с плавающей точкой провоцируют сложности и ошибки.
3) Бизнес-ориентированный язык должен обращаться к большим объемам данных, структурированных в форме записи и оперировать ими, притом, что эти данные поддерживаются извне.
Конечно, сегодня все это в пределах возможностей универсальных языков программирования. Но для COBOL это родная возможность.
Можно спорить о том, нужен ли COBOL, но есть факт: на COBOL существуют сотни миллиардов строк кода, и попытки мигрировать с COBOL на другой язык в целом не были успешны.
Ваша первая программа на COBOL
Исходный код – это просто текстовые файлы. В COBOL не менее, чем в любом другом языке, важно иметь удобный редактор с поддержкой языка – если не более. Начинающему проще всего будет пользоваться Visual Studio Code, единственным редактором со времен EMACS, который мне по-настоящему понравился.
Удивительно, насколько много есть VSCode-расширений для COBOL. В настоящее время я пользуюсь bitlang, обеспечивающим подсветку кода, а поддержку языка нашел в Broadcom COBOL. Есть еще множество инструментов, ориентированных на тех, кто программирует под мейнфреймы, но такие редакторы слишком сложны, и во вводной статье, такой, как эта, они излишни.
Итак, вот что нужно сделать, чтобы приступить к экспериментам с COBOL:
1. Скачайте и установите Visual Studio Code, если еще не сделали этого.
2. Установите расширения bitlang.cobol и Broadcom COBOL Language Support.
3. Установите GnuCOBOL. (Честно, если с чем-то у вас и возникнут неприятности, то с этим. Версия Homebrew под MacOS работала нормально, а других систем, на которых можно было ее протестировать, у меня не было. Под Windows есть программа MicroFocus, в которой предусмотрен бесплатный пробный период для Visual Studio COBOL и поддержка Azure для экспериментов.)
Вот вы и установили все, что нужно и готовы написать вашу первую программу на COBOL. По традиции начнем с азов, то есть, с программы “Hello, world”.
Вот и первый повод удивиться для COBOL-новичка: в COBOL важно, в каком столбце находится ваш код. В традиционной программе на COBOL в исходнике несколько компонентов:
Столбцы 1-6 – для порядкового номера. Столбец 7 называется «областью индикатора»; в нем обычно обозначаются комментарии, для этого в данный столбец ставится астериск ‘*’. Далее в столбцах 8-72 идет код, а столбцы 73-80 программист обычно вправе использовать по собственному усмотрению.
Такая структура восходит к тем временам, когда мы записывали наш исходный код в 80-столбчатые перфокарты.
Современные компиляторы для COBOL также принимают и свободный формат, не обязывающий вас втискивать код в такой 80-столбцовый корсет, но весьма значительная часть актуального кода по-прежнему существует в таком перфокартном формате. Пока давайте продолжать работу с образами перфокарт.
Крепитесь: COBOL структурируется не поблочно, как почти все прочие языки, которыми вы могли пользоваться. С самого начала одна из основных целей проектирования COBOL заключалась в том, чтобы он был «самодокументируемым» и походил по синтаксису на английский язык. Тут нет никаких функций, подпроцедур и блоков, а есть разделы, секции, абзацы и утверждения. (Почти полная подпроцедура – это глагол PERFORM, который встретится нам ниже.)
Да, кстати, у нас же есть глаголы для операторов COBOL.
Вот программа “Hello, World” на COBOL:
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY "Hello, world".
END PROGRAM HELLO.
Она довольно многословна по сравнению с программами на других языках, но определенно не так плоха. Сравним ее с простой версией на Java:
public class Hello {
public static void main(String[] args){
System.out.println("Hello, world!");
}
}
Как и все “Hello, world”-подобные программы, она ничего не делает. Но, если вам говорили, что для создания простейшей программы на COBOL нужно написать 90 строк, то, конечно же, вас ввели в заблуждение.
Теперь давайте в качестве первого примера разберем эту программу “Hello world”.
Первая строка:
IDENTIFICATION DIVISION.
В программах на COBOL всегда есть как минимум идентификационный раздел и процедурный раздел. В идентификационном разделе есть важный абзац, PROGRAM-ID
. Здесь вы должны дать программе имя. Это имя не обязательно должно соответствовать имени файла или вообще, чему бы то ни было, кроме того случая, когда ваша программа на COBOL вызывается из другой программы на COBOL. Это делается при помощи глагола CALL
, который мы разбирать не будем.
Нам обязательно понадобится ID программы, поэтому добавим
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
Есть еще множество вещей, обычно присутствующих в идентификационном разделе. Приведу пару типичных примеров.
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
AUTHOR. CHARLES R MARTIN.
DATE-WRITTEN. 2020-APR-11
В современных средах все это – комментарии.
Кстати, если речь зашла о современных средах – COBOL не требует все писать капслоком, как делаю здесь я. GnuCOBOL полностью удовлетворится.
identification division.
program-id. tut2.
author. charlie martin.
procedure division.
display "hello, world".
end program tut2.
Просто я немного грущу и ностальгирую.
Не судите строго. Итак, давайте добьем наш “Hello, world.” Та часть программы, в которой выполняется код COBOL, называется процедурным разделом.
IDENTIFICATION DIVISION.
PROGRAM-ID. HELLO.
PROCEDURE DIVISION.
DISPLAY "Hello, world".
END PROGRAM HELLO.
Здесь есть еще один отголосок перфокартного формата. Обратите внимание на отступы `DISPLAY “Hello, world”`, здесь четыре столбца. Дело в том, что на отрезке от 8 до 72 на самом деле две части: раздел A, столбцы 8-11 и раздел B, от столбца 12 и далее. Разделы, секции и абзацы должны начинаться в зоне A; утверждения в коде должны начинаться в зоне B.
Расширенный пример на COBOL
Разумеется, по “Hello, World” не составишь качественного впечатления о каком-либо языке, поэтому давайте немного углубимся в COBOL и разберем пример, который хотя бы немного напоминает реальную бизнес-программу. Пример будет самый простой: рассчитаем зарплатную ведомость для работника с почасовой оплатой, с учетом необходимых налогов.
Сделав это, могу признаться, что не так-то это и просто, налоговые таблицы сложны и таинственны. Поэтому примем ставку федерального налога за 16,4 процента, налог штата за 7 процентов, а ставку FICA зафиксируем на уровне 6,2 процента, при этом тщательно выберем ставку оплаты и количество отработанных часов, чтобы не упереться в пороговое значение FICA. Мы учитываем только рабочих, которым оплачивается почасовой труд, а рабочие часы сверх 40 в неделю рассчитываем как переработки и оплачиваем их с коэффициентом 1,5.
Идентификационный раздел здесь повторять незачем. Перейдем к разделу окружения, на его основе собирается интерфейс между программой COBOL и внешним миром.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TIMECARDS
ASSIGN TO "TIMECARDS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
Опять же, мы потренируемся работать с некоторыми аспектами COBOL, которые могут быть удивительны для программиста, не писавшего код в таблично-ориентированном мире обработки данных. В UNIX, Linux, MacOS или Windows запись – это текстовая строка, которая заканчивается некоторым завершающим символом или символами. Для традиционного COBOL это проблема, но компиляторы COBOL реализуют нестандартное расширение, чтобы справиться с этим: ORGANIZATION IS LINE SEQUENTIAL
.
В разделе ввода-вывода файлу просто присваивается символьное имя (TIMECARDS
), соединяющее его с файлом из внешнего окружения.
Следующая часть программы описывает те данные, с которыми мы работаем. В COBOL обычно предполагается, что все данные будут содержаться в записях фиксированного формата. Структура этих записей иерархическая, отмечается номерами уровней: уровень 01 самый верхний, а дальнейшие подразделы получают более высокие номера. Я использовал 02, 03 и так далее, но это произвольный выбор; мы часто применяли нумерацию 01, 05 и так далее, поскольку так было проще вставлять новые карты, не перепробивая все остальные.
Но теперь введем еще один раздел, который называется раздел данных. Как вы уже, наверное, догадались, он для данных. Здесь используются две секции. Сначала идет файловая секция.
DATA DIVISION.
FILE SECTION.
FD TIMECARDS.
01 TIMECARD.
02 EMPLOYEE-NAME.
03 EMP-FIRSTNAME PIC X(10).
03 EMP-SURNAME PIC X(15).
02 HOURS-WORKED PIC 99V9.
02 PAY-RATE PIC 99.
Это наш ввод, который находится в фиксированном формате; строкой FD
мы соединяем его с файлом TIMECARDS
. Далее идет секция рабочего хранилища. Если вы ранее не работали с COBOL, оно может показаться немного непривычным, но на самом деле я просто объявляю здесь переменные, которые буду далее использовать в программе.
WORKING-STORAGE SECTION.
* временные переменные, используемые при вычислениях
* промежуточные значения для расчета зарплаты с учетом переработок
01 REGULAR-HOURS PIC 9(4)V99 USAGE COMP.
01 OVERTIME-HOURS PIC 9(4)V99 USAGE COMP.
01 OVERTIME-RATE PIC 9(4)V99 USAGE COMP.
01 REGULAR-PAY PIC 9(4)V99 USAGE COMP.
01 OVERTIME-PAY PIC 9(4)V99 USAGE COMP.
* вычисленные элементы зарплатной ведомости
01 GROSS-PAY PIC 9(4)V99 USAGE COMP.
01 FED-TAX PIC 9(4)V99 USAGE COMP.
01 STATE-TAX PIC 9(4)V99 USAGE COMP.
01 FICA-TAX PIC 9(4)V99 USAGE COMP.
01 NET-PAY PIC 9(4)V99 USAGE COMP.
Незнакомая часть этого кода – это условие PIC
(или PICTURE
). COBOL вообще не отличается сильной типизацией. Напротив, как в C, каждое объявление в нем соответствует участку памяти; PIC
сообщает COBOL, как интерпретировать этот участок памяти с «картинкой». В данном случае 9(4)v99
говорит COBOL, что упомянутый участок памяти, например, REGULAR-HOURS
, должен интерпретироваться как шестизначное число, в котором есть десятичная точка (V
), предшествующая двум последним знакам. USAGE COMP
приказывает COBOL использовать внутренний формат, приспособленный для быстрых арифметических операций. На самом деле, этот формат довольно гибкий и зависит от архитектуры – то есть, вам самим лучше не зависеть от соблюдения этого формата на всех платформах.
Если хотите быть в этом уверены, не используйте USAGE COMP
, что приведет вас к другой части данных – формату вывода. Эти поля используются по умолчанию и выводятся на экран, а USAGE COMP
нет.
01 PAYCHECK.
02 PRT-EMPLOYEE-NAME PIC X(25).
02 FILLER PIC X.
02 PRT-HOURS-WORKED PIC 99.9.
02 FILLER PIC X.
02 PRT-PAY-RATE PIC 99.9.
02 PRT-GROSS-PAY PIC $,$$9.99.
02 PRT-FED-TAX PIC $,$$9.99.
02 PRT-STATE-TAX PIC $,$$9.99.
02 PRT-FICA-TAX PIC $,$$9.99.
02 FILLER PIC X(5).
02 PRT-NET-PAY PIC $*,**9.99.
Здесь по-настоящему интересно лишь то, что у нас появилось несколько новых форматов PIC
: у $,$$9.99
есть ведущий символ доллара, всегда предшествующий самой левой цифре, а также $*,**9.99
, служащие заполнителем между знаком доллара и первыми цифрами.
Скоро покажу всю программу, но сначала хочу продемонстрировать, как в COBOL делается математика, например, в COMPUTE-GROSS-PAY
:
COMPUTE-GROSS-PAY.
IF HOURS-WORKED > 40 THEN
MULTIPLY PAY-RATE BY 1.5 GIVING OVERTIME-RATE
MOVE 40 TO REGULAR-HOURS
SUBTRACT 40 FROM HOURS-WORKED GIVING OVERTIME-HOURS
MULTIPLY REGULAR-HOURS BY PAY-RATE GIVING REGULAR-PAY
MULTIPLY OVERTIME-HOURS BY OVERTIME-RATE
GIVING OVERTIME-PAY
ADD REGULAR-PAY TO OVERTIME-PAY GIVING GROSS-PAY
ELSE
MULTIPLY HOURS-WORKED BY PAY-RATE GIVING GROSS-PAY
END-IF
Да, в стандартном COBOL нужно все проговаривать.
А теперь вся программа целиком.
IDENTIFICATION DIVISION.
PROGRAM-ID. PAYCHECKS.
AUTHOR. CHARLES R. MARTIN.
DATE-WRITTEN. 2020-APR-15.
ENVIRONMENT DIVISION.
INPUT-OUTPUT SECTION.
FILE-CONTROL.
SELECT TIMECARDS
ASSIGN TO "TIMECARDS.DAT"
ORGANIZATION IS LINE SEQUENTIAL.
DATA DIVISION.
FILE SECTION.
FD TIMECARDS.
01 TIMECARD.
02 EMPLOYEE-NAME.
03 EMP-FIRSTNAME PIC X(10).
03 EMP-SURNAME PIC X(15).
02 HOURS-WORKED PIC 99V9.
02 PAY-RATE PIC 99.
WORKING-STORAGE SECTION.
* временные переменные, используемые при вычислениях
* промежуточные значения для расчета зарплаты с учетом переработок
01 REGULAR-HOURS PIC 9(4)V99 USAGE COMP.
01 OVERTIME-HOURS PIC 9(4)V99 USAGE COMP.
01 OVERTIME-RATE PIC 9(4)V99 USAGE COMP.
01 REGULAR-PAY PIC 9(4)V99 USAGE COMP.
01 OVERTIME-PAY PIC 9(4)V99 USAGE COMP.
* вычисленные части зарплатной ведомости
01 GROSS-PAY PIC 9(4)V99 USAGE COMP.
01 FED-TAX PIC 9(4)V99 USAGE COMP.
01 STATE-TAX PIC 9(4)V99 USAGE COMP.
01 FICA-TAX PIC 9(4)V99 USAGE COMP.
01 NET-PAY PIC 9(4)V99 USAGE COMP.
* print format of the check
01 PAYCHECK.
02 PRT-EMPLOYEE-NAME PIC X(25).
02 FILLER PIC X.
02 PRT-HOURS-WORKED PIC 99.9.
02 FILLER PIC X.
02 PRT-PAY-RATE PIC 99.9.
02 PRT-GROSS-PAY PIC $,$$9.99.
02 PRT-FED-TAX PIC $,$$9.99.
02 PRT-STATE-TAX PIC $,$$9.99.
02 PRT-FICA-TAX PIC $,$$9.99.
02 FILLER PIC X(5).
02 PRT-NET-PAY PIC $*,**9.99.
* Tax rates -- 77 level aha!
77 Fed-tax-rate Pic V999 Value Is .164 .
77 State-tax-rate Pic V999 Value Is .070 .
77 Fica-tax-rate Pic V999 Value Is .062 .
* 88 уровень – для условий
01 END-FILE PIC X.
88 EOF VALUE "T".
PROCEDURE DIVISION.
BEGIN.
PERFORM INITIALIZE-PROGRAM.
PERFORM PROCESS-LINE WITH TEST BEFORE UNTIL EOF
PERFORM CLEAN-UP.
STOP RUN.
INITIALIZE-PROGRAM.
OPEN INPUT TIMECARDS.
PROCESS-LINE.
READ TIMECARDS INTO TIMECARD
AT END MOVE "T" TO END-FILE.
IF NOT EOF THEN
PERFORM COMPUTE-GROSS-PAY
PERFORM COMPUTE-FED-TAX
PERFORM COMPUTE-STATE-TAX
PERFORM COMPUTE-FICA
PERFORM COMPUTE-NET-PAY
PERFORM PRINT-CHECK
END-IF.
COMPUTE-GROSS-PAY.
IF HOURS-WORKED > 40 THEN
MULTIPLY PAY-RATE BY 1.5 GIVING OVERTIME-RATE
MOVE 40 TO REGULAR-HOURS
SUBTRACT 40 FROM HOURS-WORKED GIVING OVERTIME-HOURS
MULTIPLY REGULAR-HOURS BY PAY-RATE GIVING REGULAR-PAY
MULTIPLY OVERTIME-HOURS BY OVERTIME-RATE
GIVING OVERTIME-PAY
ADD REGULAR-PAY TO OVERTIME-PAY GIVING GROSS-PAY
ELSE
MULTIPLY HOURS-WORKED BY PAY-RATE GIVING GROSS-PAY
END-IF
.
COMPUTE-FED-TAX.
MULTIPLY GROSS-PAY BY FED-TAX-RATE GIVING FED-TAX
.
COMPUTE-STATE-TAX.
* Compute lets us use a more familiar syntax
COMPUTE STATE-TAX = GROSS-PAY * STATE-TAX-RATE
.
COMPUTE-FICA.
MULTIPLY GROSS-PAY BY FICA-TAX-RATE GIVING FICA-TAX
.
COMPUTE-NET-PAY.
SUBTRACT FED-TAX STATE-TAX FICA-TAX FROM GROSS-PAY
GIVING NET-PAY
.
PRINT-CHECK.
MOVE EMPLOYEE-NAME TO PRT-EMPLOYEE-NAME
MOVE HOURS-WORKED TO PRT-HOURS-WORKED
MOVE PAY-RATE TO PRT-PAY-RATE
MOVE GROSS-PAY TO PRT-GROSS-PAY
MOVE FED-TAX TO PRT-FED-TAX
MOVE STATE-TAX TO PRT-STATE-TAX
MOVE FICA-TAX TO PRT-FICA-TAX
MOVE NET-PAY TO PRT-NET-PAY
DISPLAY PAYCHECK
.
CLEAN-UP.
CLOSE TIMECARDS.
END PROGRAM PAYCHECKS.
Вот файл с данными:
Charlie Martin 41015
Terry Lacy 32007
А вот вывод:
$ cobc -x paycheck.cob
$ ./paycheck
Charlie Martin 41.0 15.0 $622.50 $102.09 $43.57 $38.59 $**438.25
Terry Lacy 32.0 07.0 $224.00 $36.73 $15.68 $13.88 $**157.71
$
Где учить COBOL
На самом деле, есть немало курсов и книг по COBOL.
Я купил и проработал этот курс Udemy, он весьма хорош. А среди электронных книг для Kindle мне нравится Beginning COBOL for Programmers Майкла Кафлана. На YouTube уйма видео, из которого я посмотрел лишь некоторые. Вот это кажется хорошим, но, если поискать по COBOL, можно найти гораздо больше.
Конечно, на подходе и новые материалы. IBM и Open Mainframe Project анонсировали совместный проект, призванный объединить специалистов с навыками COBOL и учить программированию на этом языке. Здесь есть несколько ресурсов, в частности, новостная площадка для COBOL-программистов, желающих вернуться к делам, а также первые наработки опенсорсного курса по COBOL.
Почему у COBOL дурная слава
Как понятно из этого небольшого примера, COBOL не слишком похож на привычные языки программирования. На COBOL не напишешь ни компилятор, ни модуль ядра, да и синтаксис – явно не такой, как вы ожидали увидеть. Но давайте сравним его с другим распространенным предметно-ориентированным языком: SQL. Там синтаксис также довольно причудлив, а семантика определяется реляционным исчислением.
“Программируя на мейнфрейме, можно подсмотреть, как раньше делался софт,” – говорит Себальос. — “С ним современный программист словно открывает капсулу времени. Многие черты COBOL кажутся весьма кустарными по сравнению с современными приемами DEVOPS и автоматизации.”
Автор:
Sivchenko_translate