Из вышеприведенного материала становится ясна технология разработки программ на языках низкого уровня – непосредственно в машинных кодах (как правило, в шестнадцатеричных числах) или на более удобном языке программирования – ассемблере, в котором числовой код команды заменен некоторым буквенным сокращением, мнемокодом (например, команду перехода можно обозначить goto или, от англ. jump – прыжок, – JMP), а числа (или операнды) сохраняют свою шестнадцатеричную форму представления. Очевидны и неудобства такого программирования – общая логика программы абсолютно непрозрачна даже для разработчика, поэтому процесс создания достаточно больших программ очень трудоемок. Но существуют и преимущества – программы, написанные таким образом, отличаются минимальным количеством программного кода и максимальным быстродействием.
Как правило, при разработке серьезного программного обеспечения минимум одну или более подпрограммы (они носят название процедур или функций) приходится писать на низкоуровневом языке программирования. Знание ассемблера также очень желательно при отладке ПО. Но, вообще говоря, для разработки программ на языках высокого уровня знание ассемблера не является обязательным. Отметим только, что это очень интересный материал, которому посвящено большое количество научно-технической литературы, например [7]. Но в данном учебном пособии вопросы низкоуровневого программирования не рассматриваются.
Продолжим исследование предпосылок возникновения программирования на языках высокого уровня. Уже использование мнемокодов потребовало дополнительных программных средств – программы, которая как бы "переводила" команды ассемблера непосредственно в машинные коды. Этот процесс получил название компиляции, а подобная программа соответственно была названа компилятором. Для языков высокого уровня компилятор – очень важная часть общего пакета среды программирования. С его помощью создаются так называемые исполняемые файлы программного обеспечения, которые обычно имеют расширение "exe". Существуют также библиотеки кода или библиотеки подпрограмм, обычно имеющие расширение "dll" (или специфичные для Delphi bpl-файлы). Именно в исполняемых файлах и библиотеках хранится код программы, т.е. алгоритмы тех операций, благодаря которым программные средства реализуют какие-либо действия, требующиеся пользователю.
Алгоритмом называют способ решения какой-либо задачи (не обязательно вычислительной), точно предписывающий, как и в какой последовательности получить результат, однозначно определяемый исходными данными.
Существует и другой вариант работы программного обеспечения. Пусть в памяти машины хранится программа на языке высокого уровня, которая выполняется по отдельным операторам (группам операторов). Такую программу удобно представить в виде листинга, где каждый оператор расположен на отдельной строке, а строки пронумерованы. Тогда можно сказать, что программа выполняется построчно. Вместо компилятора в этом случае необходим интерпретатор, выполняющий те же функции преобразования операторов в машинный код. Вообще операции построчного выполнения программы необходимы для отладки ПО и при выявлении ошибок. Принципиальная разница между компиляцией и интерпретированием в том, что при компилировании создается как минимум один дополнительный исполняемый exe-файл программы. Интерпретируемый программный код выполняется существенно медленнее.
Соответственно и языки программирования высокого уровня разделяют на компилируемые и интерпретируемые. Не останавливаясь подробно на истории развития языков программирования высокого уровня, можно отметить три, ставших де-факто основными языковыми системами – Бейсик (Basic), Паскаль (Pascal) и Си (C).
Принципиально все языки программирования высокого уровня похожи. Основными элементами каждого являются некоторый список зарезервированных (служебных) слов и определенные правила записи операторов и операндов. Зарезервированные слова – это в основном операторы, инструкции и элементы структурирования программы. Исторически сложилось так, что в этом качестве используются слова английского языка, а также некоторые знаки пунктуации. Правила записи операторов и операндов лучше всего воспринимать как грамматические правила – в том смысле, что строка программы должна быть построена таким и только таким образом. В противном случае компьютер "не поймет" программу, т.е. она с языка программирования высокого уровня или не будет переведена в машинный код, или это преобразование будет осуществлено некорректно, т.е. разработанное программное обеспечение окажется неработоспособным.
С точки зрения электронно-вычислительной машины безразлично, какой из языков программирования используется. "Понятность" языка для ЭВМ определяется компилятором, а основным фактором, определяющим "понятность" или "приемлемость" языка программирования, является человеческое мышление, т.е. язык программирования высокого уровня в первую очередь должен быть понятен и близок использующему его человеку – программисту.
Первым из языков программирования высокого уровня был разработан Бейсик. Изначально это был интерпретируемый язык, отличающийся простотой и понятностью. Несомненно, многие люди, связанные с программированием (включая и автора данного учебного пособия), будут благодарны разработчикам этого языка за те новые возможности (по сравнению с программированием в машинных кодах), реализацию которых он обеспечивал. Но его достоинства – простота и понятность – с течением времени оказались и его недостатками настолько, что программирование на Бейсике стало ассоциироваться с чем-то примитивным и несерьезным. Авторы языка (компания Microsoft) пытались с этим бороться, разрабатывали различные версии, сделали язык компилируемым, но в конечном итоге были вынуждены признать его "мертвым" языком программирования и разработать на его основе Visual Basic, который мало чем отличается от версии Quick Basic, и, сохраняя простоту и понятность, имеет тем не менее существенные ограничения, и едва ли может быть рекомендован для разработки серьезных программных продуктов.
Вторым фундаментальным языком программирования высокого уровня стал Паскаль. Фирма Borland (ныне Inprise) изначально ставила задачу разработать альтернативный Бейсику язык, компилируемый, ориентированный на создание структурно сложных программных средств. И ей это в полной мере удалось. Современный объектно-ориентированный вариант Паскаля – Object Pascal – абсолютно заслуженно снискал наибольшую популярность как у начинающих, так и у опытных программистов. Синтаксис языка прост и ясен, возможности практически ограничены имеющимися ресурсами. К тому же это строго типизированный язык программирования, что позволяет повысить скорость разработки ПО и уменьшить число ошибок. Примеры и рекомендации для разработки программных средств, которые в данном учебном пособии будут приведены далее, ориентированы на среду проектирования Delphi, основу которой составляет именно Object Pascal.
Единственное, чего по-настоящему не хватало в Паскале – это свободы, свободы для программистов реализовывать свои собственные (иногда абсолютно фантастические) замыслы, программные структуры и т.п. Именно желание уйти от строгой типизации данных, от раз и навсегда оговоренной грамматики привели к разработке языка Си и его современного варианта С++. Программы, написанные на нем, отличаются большой эффективностью. Язык поддерживается ведущими лидерами в области разработки ПО (Microsoft и Inprise), широко распространен, доступен на всех платформах. Но с другой стороны, его эффективное использование требует от программиста очень высокой профессиональной подготовки и некоторой нестандартности мышления. По оценкам специалистов [8], скорость разработки приложений на языке Си в несколько раз меньше, чем при использовании более простых языков программирования Object Pascal и Visual Basic.
Вернемся к функциональным принципам работы компьютера. Было отмечено, что программа, начиная выполняться с определенной ячейки памяти, выполняется последовательно по управляющим инструкциям до своего завершения. Другими словами, программа является совокупностью последовательно выполняемых операций (процедур) и может рассматриваться как код, воздействующий на данные. Для программиста это означает следующее: любые инструкции программы будут выполняться по ходу программы немедленно и именно в последовательности, определенной при программировании. Такая модель построения программы называется процессорно-ориентированной, а языки программирования, реализующие подобный подход – процедурными [8].
Еще одной особенностью процессорно-ориентированной модели является то, что параллельная работа двух разных программ невозможна. До того, как на выполнение будет запущена следующая программа (фактически это означает загрузку в оперативную память), предыдущая должна завершиться. Такой вариант работы поддерживается, например, в операционной среде MS DOS (Microsoft Disk Operating System) и носит название однозадачного режима работы.
Стиль разработки ПО в рамках процессорно-ориентированной модели получил много различных определений – "процедурное программирование", "программирование под MS DOS", "линейное программирование", "работа в режиме командной строки" (в том смысле, что командная инструкция выполняется сразу после ввода). Программирование в подобном стиле достаточно просто и доступно для понимания, программисту не требуется пространственно-временного мышления. С другой стороны, уровень подавляющего большинства программ, разработанных таким образом, в настоящее время едва ли можно считать удовлетворительным.
Переход к современному стилю программирования – событийному – осуществлялся постепенно. В работе Ч. Петзолда "Программирование для Windows 95" приведено сравнение, что программисты, работающие в рамках MS DOS, сами "вырыли себе яму" использованием резидентных программ – программ, которые все время находились в памяти компьютера, но не проявляли себя до определенных действий пользователя. (Самым типичным примером является программа, выполняющая копию экрана при нажатии определенного сочетания клавиш, допустим "Alt + W").
В приведенном примере факт поступления в центральный процессор кода нажатой пользователем клавиши можно назвать событием, и это неплохая иллюстрация принципов событийного программирования. Понаблюдайте внимательно: что делает большинство программ при их активации в операционной системе Windows (да, пожалуй, и в любой другой современной операционной системе)? Они рисуют свое окно, меню, панели управления, могут открыть и показать некоторый заданный файл и… И все! Далее они ожидают команд (действий) пользователя – необходимо нажать какую-либо кнопку, выбрать пункт меню, кликнуть где-нибудь мышкой – другими словами, для дальнейшей работы программе необходимо возникновение события. Реакцией на каждое событие будет отработка соответствующего программного кода.
Такая модель построения программы называется объектно-ориентированной в том смысле, что программа рассматривается как совокупность фрагментов кода (объектов) [8]. Программист при разработке подобной программы даже с малой долей вероятности не в состоянии предсказать однозначную последовательность выполнения кода программы. Объектно-ориентированные программы можно охарактеризовать как данные, управляющие доступом к коду. Если добавить сюда возможность параллельной работы нескольких приложений (многозадачный режим), графический интерфейс, использование одного и того же программного кода несколькими приложениями и многие другие возможности – то преимущества событийной функциональности приложения в современных операционных системах не подлежат сомнению. Однако такой стиль программирования требует значительно большей квалификации программиста.
Совместно со словосочетанием "событийное программирование" используется термин визуальное программирование или технология RAD (Rapid Application Development – быстрая разработка приложений). Все это означает разработку ПО в специальной инструментальной среде и основывается на визуализации процесса создания программного кода. Средства быстрой разработки приложений основываются на компонентной архитектуре. При этом компоненты являются объектами, объединяющими данные, свойства и методы. Компоненты могут быть как визуальными, так и невизуальными; атомарными и контейнерными (содержащими другие компоненты); низкоуровневыми (системными) и высокоуровневыми.
При визуальном проектировании пользователю предоставляется возможность выбора необходимых компонентов из некоторого набора (палитры) с последующим заданием их свойств. Для обозначения инструментов визуального проектирования используется широкий набор терминов [8], включающих: конструктор компоновки, конструктор форм, визуальный редактор, проектировщик экрана, проектировщик форм, конструктор графического пользовательского интерфейса и т.д. Процедура разработки интерфейса средствами RAD сводится к набору последовательных операций, включающих:
размещение компонентов интерфейса в нужном месте;
задание моментов времени их появления на экране;
настройку связанных с ними атрибутов и событий.
Отметим, что эффективность визуального программирования определяется не столько наличием самих визуальных компонентов, сколько их взаимосвязью и взаимодействием традиционными средствами. Даже если среда программирования не содержит достаточного количества требуемых компонентов, она все равно будет востребована, если позволяет самостоятельно разрабатывать необходимые компоненты или использовать имеющиеся средства сторонних производителей, альтернативные отсутствующим в ней.
Другими словами, технология быстрой разработки программных средств основывается на интегрированной среде программирования, с помощью которой выполняются процессы проектирования, отладки и тестирования прикладных программных продуктов.
Программы, работающие на компьютере, можно условно разделить на три категории [10]:
прикладные программы, непосредственно обеспечивающие выполнение необходимых пользователю действий: расчетов, редактирование текста и графики, просмотр и обработку массивов информации и т.д.;
системные программы, выполняющие различные вспомогательные функции, например, создание копий используемой информации или проверку работоспособности устройств компьютера. Особую роль среди всех системных программ играет операционная система – программа, управляющая компьютером, запускающая все другие программы и выполняющая для них различные сервисные функции;
инструментальные системы (системы программирования), обеспечивающие возможность разработки новых программных средств.
Из этих категорий, согласно тематике данного учебного пособия, наиболее интересна первая. Прикладные программы за полвека своего развития прошли путь от выполнения элементарных логических и арифметических действий до самых сложных систем автоматизации инженерных и экономических расчетов, управления технологическими процессами и промышленными предприятиями. В прикладном ПО всегда можно было выделить два основных направления:
выполнение вычислений;
накопление и обработка информации.
Реализация второго направления привела к выделению технологии разработки информационных систем практически в самостоятельную область программирования [8]. Такое ПО предназначено для сбора, хранения и обработки различных информационных структур. В основе, как правило, лежит определенная среда работы с данными (СУБД – система управления базой данных). Ориентированы подобные программы на пользователя, не обладающего высокой квалификацией в области применения ЭВМ. Поэтому серьезное внимание приходится уделять надежности работы программы, доступности и понятности интерфейса пользователя, а также дополнительной разработке информационного обеспечения или возможности визуализации информации о стандартах, классификаторах, тенденциях, методиках и т.п. – словом, о предметной области, на которую ориентировано разработанное ПО [3]. Последнее роднит информационные системы со стандартным прикладным расчетным ПО, которое, вообще говоря, также не предполагает эксплуатацию пользователем, квалифицированным в области применения вычислительной техники.