Введение в программные системы и их разработку

Инструментальное ПО

Показывать лекцию целиком

4.1. Языки программирования

Язык программирования можно определить как формальную знаковую систему, предназначенную для записи программ, которые задают алгоритм в форме, понятной для исполнителя (например, компьютера). Язык программирования определяет набор лексических, синтаксических и семантических правил, используемых при составлении компьютерной программы. Он позволяет программисту точно определить, на какие события будет реагировать компьютер, как будут храниться и передаваться данные, а также какие именно действия следует выполнять над этими данными при различных обстоятельствах.

Со времени создания первых программируемых машин человечество придумало уже более восьми с половиной тысяч языков программирования [28]. Каждый год их число пополняется новыми языками. Некоторыми языками умеет пользоваться только небольшое число их собственных разработчиков, другие становятся известны миллионам людей. Профессиональные программисты иногда применяют в своей работе более десятка разнообразных языков программирования. Современные прикладные и системные программы, в том числе операционные системы и системы программирования, в основном разрабатываются на алгоритмических языках или языках высокого уровня, которые обеспечивают удобство и высокую производительность работы программиста.

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

Вместе с тем такой способ разработки обеспечивал программисту просто неограниченные возможности работы с компьютером. Становилось возможным использование таких хитроумных алгоритмов и способов организации программ, которые не используют (а некоторые и не знают) многие современные программисты. Например, могла применяться такая возможность, как самомодифицирующийся код. Знание двоичного представления команд позволяло иногда не хранить некоторые данные отдельно, а встраивать их в код как команды. И это далеко не полный список приемов, владение хотя бы одним из которых сейчас сразу же продвигает программиста до уровня экстра-класса [15].

С развитием аппаратного обеспечения компьютеров увеличивалась скорость обработки и емкость памяти. Это привело к изменениям в языках программирования – они стали проще и понятнее для людей. Языки программирования в своем развитии прошли практически те же стадии, что и сами компьютеры. Диаграмма на рис.4.1 показывает, как происходило развитие языков программирования вместе с поколениями компьютеров за последние 50 лет. Основная тенденция – увеличение простоты взаимодействия пользователя с аппаратным и программным обеспечением компьютеров.

(рис 4.1) Развитие языков программирования

Первым значительным шагом был переход к языку ассемблера (assembly language, или assembler). Не очень заметный, казалось бы, шаг – переход к символическому кодированию машинных команд – имел на самом деле огромное значение. Программисту не надо было больше вникать в хитроумные способы кодирования команд на аппаратном уровне. Более того, зачастую одинаковые по сути команды кодировались различным образом в зависимости от своих параметров.

Известный пример из мира современных компьютеров – кодирование инструкции mov в процессорах Intel. Существует несколько совершенно поразному кодируемых вариантов команды. Выбор того или иного варианта зависит от операндов, хотя суть выполняемой операции неизменна: поместить содержимое (или значение) второго операнда в первый. Появилась также возможность использования макросов и меток, что также упрощало создание, модификацию и отладку программ. Появилось даже некое подобие переносимости – существовала возможность разработки целого семейства машин со сходной системой команд и некоего общего ассемблера для них, при этом не было нужды обеспечивать двоичную совместимость.

Вместе с тем, переход к новому языку таил в себе и некоторые отрицательные (на первый взгляд) стороны. Становилось почти невозможным использование всяческих хитроумных приемов, подобных упомянутым выше. Кроме того, впервые в истории развития программирования появились два представления программы: в исходных текстах и в откомпилированном виде. Сначала, пока ассемблеры только транслировали мнемонические коды в машинные, одно легко переводилось в другое и обратно, но затем, по мере появления таких возможностей, как метки и макросы, дизассемблирование (перевод из машинного кода в ассемблер) становилось все более и более трудным делом [21].

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

В 1954 году в корпорации IBM группой разработчиков во главе с Джоном Бэкусом (John Backus) был создан язык программирования Fortran. Значение этого события трудно переоценить. Это первый язык программирования высокого уровня. Впервые программист мог по-настоящему абстрагироваться от особенностей машинной архитектуры. Ключевой идеей, отличающей новый язык от ассемблера, была концепция подпрограмм.

Напомним, что это современные компьютеры поддерживают подпрограммы на аппаратном уровне, предоставляя соответствующие команды и структуры данных (стек) прямо на уровне ассемблера, а в 1954 же году это было совершенно не так. Поэтому компиляция Fortran'а была процессом отнюдь не тривиальным. Кроме того, синтаксическая структура языка была достаточно сложна для машинной обработки, в первую очередь, из-за того, что пробелы как синтаксические единицы вообще не использовались. Это порождало массу возможностей для скрытых ошибок.

Язык Фортран использовался (и используется сейчас) для научных вычислений. Он страдает от отсутствия многих привычных языковых конструкций и атрибутов, компилятор практически никак не проверяет синтаксически правильную программу с точки зрения семантической корректности (соответствие типов и др.). В нем нет поддержки современных способов структурирования кода и данных. Это осознавали и сами разработчики. По признанию самого Бэкуса, перед ними стояла задача скорее разработки компилятора, чем языка. Понимание самостоятельного значения языков программирования пришло позже.

Появление Фортрана было встречено еще большей критикой, чем внедрение ассемблера. Программистов пугало снижение эффективности программ за счет использования промежуточного звена в виде компилятора. И эти опасения имели под собой основания: действительно, хороший программист, скорее всего, при решении какой-либо небольшой задачи вручную напишет код, работающий быстрее, чем код, полученный как результат компиляции. Через некоторое время пришло понимание того, что реализация больших проектов невозможна без применения языков высокого уровня. Мощность вычислительных машин росла, и с тем падением эффективности, которое раньше считалось угрожающим, стало возможным смириться. Преимущества же языков высокого уровня стали настолько очевидными, что побудили разработчиков к созданию новых языков, все более и более совершенных.

Вторым в истории высокоуровневым языком программирования стал Lisp. Он использовался и по сей день используется в основном для разрешения сложных задач. Датой рождения Лиспа был 1958 год, известность к нему пришла чуть позже. В 1960 в журнале Communications of the ACM вышла статья Джона Маккарти (автора Лиспа) с подробным описанием нового языка. Он стал отцом не только Лиспа, но и основоположником всего функционального программирования. Язык Lisp – язык для обработки списков. Получил достаточно широкое распространение в системах искусственного интеллекта. Имеет несколько потомков: Planner (1967), Scheme (1975), Common Lisp (1984). Многие его черты были унаследованы современными языками функционального программирования.

В 1960 году в США был создан язык программирования Cobol. Он был рассчитан специально для создания коммерческих приложений. На Коболе написаны тысячи прикладных коммерческих систем. Отличительной особенностью языка является возможность эффективной работы с большими массивами данных, что характерно именно для коммерческих приложений. Популярность Кобола столь высока, что даже сейчас, при всех его недостатках (по структуре и замыслу Кобол во многом напоминает Фортран), появляются новые его диалекты и реализации. Так, недавно появилась реализация Кобола, совместимая с Microsoft .NET, что потребовало, вероятно, внесения в язык некоторых черт объектно-ориентированного языка.

В 1960 году командой во главе с Петером Науром (Peter Naur) был создан язык программирования Algol. Этот язык дал начало целому семейству алголоподобных языков (важнейший представитель – Pascal). В 1968 году появилась новая версия языка – Algol 68. Она не нашла столь широкого практического применения, как первая версия, но была весьма популярна в кругах теоретиков. Язык был достаточно интересен, так как обладал многими уникальными на тот момент характеристиками.

К середине 60-х годов прошлого века в США резко возросла потребность в обучении программированию не только специалистов в области вычислительной техники, но и широкого круга пользователей. Это было связано с резким увеличением количества компьютеров в бизнесе. Два профессора Дартмутского колледжа – Томас Курт и Джон Кемени – для обучения студентов программированию создали язык Бейсик (BASIC). Свое название язык получил по первым буквам английских слов "Beginner's All-purpose Symbolic Instruction Code" – универсальный код символических инструкций для начинающих.

Есть и другой перевод – базовый, основной, что хорошо соответствовало сложившемуся положению дел в программировании для бизнеса. Язык предназначался для обучения программированию и получил широкое распространение в виде различных диалектов, прежде всего, как язык для домашних микрокомпьютеров. Впоследствии большая часть критики этого языка строилась на том, что после Basic'а нормально программировать человек не может, и исправить это уже не удастся. Как бы то ни было, в 1963 г. язык был создан и получил имя Dartmouth BASIC.

Настоящую популярность этот язык получил в 1975 году. Тогда Microsoft (в то время только два человека – Билл Гейтс и Пол Аллен) написали интерпретатор бейсика для компьютеров Altair 8800, названный Altair BASIC. Язык стремительно разветвился на множество диалектов. Например, Apple II базировался на одной из его версий, а для операционной системы CP/M был написан BASIC-80. Заметим, что второе (или даже третье) дыхание развитию Basic дал опять же Microsoft. Произошло это в начале 90-х годов прошлого столетия, когда был выпущен Visual Basic, уже совсем не похожий на своего предка.

В 1964 году же корпорация IBM создала язык PL/1, который был призван заменить Cobol и Fortran в большинстве приложений. Язык обладал исключительным богатством синтаксических конструкций. В нем впервые появилась обработка исключительных ситуаций и поддержка параллелизма. Надо заметить, что синтаксическая структура языка была крайне сложной. Пробелы уже использовались как синтаксические разделители, но ключевые слова не были зарезервированы. В силу таких особенностей разработка компилятора для PL/1 была исключительно сложным делом. Язык так и не стал популярен вне мира IBM, однако широко использовался в бывшем Советском Союзе и странах социалистического содружества. Причина этого заключается в производстве этими странами ряда программно совместимых моделей компьютеров ЕС ЭВМ, которые практически были скопированы с компьютеров IBM/360.

Создание каждого из вышеупомянутых языков (за исключением, может быть, Algol'а) было вызвано некоторыми практическими требованиями. Эти языки послужили фундаментом для более поздних разработок. Все они представляют одну и ту же парадигму программирования. Следующие языки пошли существенно дальше в своем развитии, в сторону более глубокого абстрагирования.

В 1970 году Никлаус Вирт создал язык программирования Pascal [19]. Язык замечателен тем, что это первый широко распространенный язык для структурного программирования (первым был Алгол, но он не получил столь широкого распространения). Впервые оператор безусловного перехода перестал играть основополагающую роль при управлении порядком выполнения операторов. В этом языке также внедрена строгая проверка типов, что позволило выявлять многие ошибки на этапе компиляции.

Отрицательной чертой языка было отсутствие в нем средств для разбиения программы на модули. Вирт осознавал это и разработал язык Modula-2 (1978), в котором идея модуля стала одной из ключевых концепций языка. В 1988 году появился язык Modula-3, в котором были добавлены объектно-ориентированные черты. Логическим продолжением Pascal и Modula являются язык Oberon и Oberon-2. Они характеризуются движением в сторону объектной и компонентной ориентированности. В этом плане интересно рассмотреть С-подобные языки.

В 1972 году Керниганом и Ритчи был создан язык программирования C [22]. Он создавался как язык для разработки операционной системы UNIX. Язык С часто называют "переносимым ассемблером", имея в виду то, что он позволяет работать с данными практически так же эффективно, как на ассемблере, предоставляя при этом структурированные управляющие конструкции и абстракции высокого уровня (структуры и массивы). Именно с этим связана его огромная популярность и поныне. И именно это является его ахиллесовой пятой. Компилятор C очень слабо контролирует типы, поэтому очень легко написать внешне совершенно правильную, но логически ошибочную программу.

В 1986 году Бьярн Страуструп создал первую версию языка C++, добавив в язык C объектно-ориентированные черты, взятые из Simula (см. ниже), и исправив некоторые ошибки и неудачные решения языка. C++ продолжает совершенствоваться и в настоящее время, так в 1998 году вышла новая (третья) версия стандарта, содержащая в себе некоторые довольно существенные изменения. Язык стал основой для разработки современных больших и сложных проектов. У него имеются, однако же, и слабые стороны, вытекающие из требований эффективности.

В 1995 году в корпорации Sun Microsystems Кеном Арнольдом и Джеймсом Гослингом был создан язык Java. Он наследовал синтаксис C и C++ и был избавлен от некоторых неприятных черт последнего. Отличительной особенностью языка является компиляция в код некоей абстрактной машины, для которой затем пишется эмулятор (Java Virtual Machine) для реальных систем. Кроме того, в Java нет указателей и множественного наследования, что сильно повышает надежность программирования.

В 1998–2001 годах в корпорации Microsoft группой инженеров под руководством Андерса Хейлсберга в компании был создан язык C#. Он в достаточной степени схож с Java (и задумывался как альтернатива последнему), но имеет и отличительные особенности. Язык C# ориентирован, в основном, на разработку многокомпонентных интернет-приложений. Это основной язык разработки приложений для платформы Microsoft.NET. Компилятор с C# входит в стандартную установку самой .NET, поэтому программы на нем можно создавать и компилировать даже без инструментальных средств, вроде Visual Studio.

В 1983 году под эгидой Министерства обороны США был создан язык Ada. Он замечателен тем, что очень много ошибок может быть выявлено на этапе компиляции. Кроме того, поддерживаются многие аспекты программирования, которые часто отдаются на откуп операционной системе (параллелизм, обработка исключений). В 1995 году был принят стандарт языка Ada 95, который развивает предыдущую версию, добавляя в нее объектную ориентированность и исправляя некоторые неточности. Оба этих языка не получили широкого распространения вне военных и прочих крупномасштабных проектов (авиация, железнодорожные перевозки). Основной причиной является сложность освоения языка и достаточно громоздкий синтаксис (значительно более громоздкий, чем Pascal).

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

В 1957 году была предпринята попытка создания языка для описания математической обработки данных. Язык был назван APL (Application Programming Language). Его отличительной особенностью было использование математических символов (что затрудняло применение на текстовых терминалах; появление графических интерфейсов сняло эту проблему) и очень мощный синтаксис, который позволял производить множество нетривиальных операций прямо над сложными объектами, не прибегая к разбиению их на компоненты. Широкому применению помешало, как уже отмечалось, использование нестандартных символов как элементов синтаксиса.

В 1962 году появился язык Snobol (а в 1974 – его преемник Icon), предназначенный для обработки строк. Синтаксис Icon напоминает С и Pascal одновременно. Отличие заключается в наличии мощных встроенных функций работы со строками и связанная с этими функциями особая семантика. Современным аналогом Icon и Snobol является Perl –язык обработки строк и текстов, в который добавлены некоторые объектно-ориентированные возможности. Считается очень практичным языком, однако ему недостает элегантности.

В 1969 году был создан язык SETL – язык для описания операций над множествами. Основной структурой данных в языке является множество, а операции аналогичны математическим операциям над множествами. Язык полезен при написании программ, имеющих дело со сложными абстрактными объектами.

В последнее время, в связи с развитием интернет-технологий, широким распространением высокопроизводительных компьютеров и рядом других факторов, получили распространение так называемые скриптовые языки. Эта языки первоначально ориентировались на применение в качестве внутренних управляющих языков во всякого рода сложных системах. Многие из них, однако же, вышли за пределы сферы своего изначального применения и используются ныне в совсем иных областях. Характерными особенностями данных языков являются, во-первых, их интерпретируемость (компиляция либо невозможна, либо нежелательна), во-вторых, простота синтаксиса, а в-третьих, легкая расширяемость. Таким образом, они идеально подходят для работы в часто изменяемых программах, очень небольших программах или в случаях, когда для выполнения операторов языка затрачивается время, несопоставимое со временем их разбора. Было создано достаточно большое количество таких языков, перечислим лишь основные и наиболее часто используемые.

Язык JavaScript был создан в компании Netscape Communications в качестве языка для описания сложного поведения веб-страниц. Первоначально язык назывался LiveScript, причиной смены названия послужили маркетинговые соображения. Он интерпретируется браузером во время отображения веб-страницы, по синтаксису похож на Java и (отдаленно) на C/C++. Язык имеет возможность использовать встроенную в браузер объектную функциональность, однако подлинно объектно-ориентированным языком не является.

Другой скриптовый язык VBScript был создан в корпорации Microsoft во многом в качестве альтернативы JavaScript. Имеет подобную область применения, синтаксически похож на язык Visual Basic (является усеченной версией последнего); так же, как и JacaScript, исполняется браузером при отображении веб-страниц и имеет ту же степень объектной ориентированности.

Язык Perl, нашедший применение для динамической генерации веб-страниц на веб-серверах, создавался в помощь системному администратору операционной системы Unix для обработки различного рода текстов и выделения нужной информации. Развился до мощного средства работы с текстами. Является интерпретируемым языком и реализован практически на всех существующих платформах. Интерпретируемый объектно-ориентированный язык программирования Python по структуре и области применения близок к Perl, однако менее распространен и более строг и логичен. Имеются реализации для большинства существующих платформ.

Интересно рассмотрение группы ранних объектно-ориентированных языков. Объектно-ориентированный подход, пришедший на смену структурному, впервые появился отнюдь не в C++, как полагают некоторые. Существует целая череда чистых объектно-ориентированных языков, без сведений о которых наш обзор был бы неполным. Первым объектно-ориентрованным языком был язык Simula (1967). Этот язык был предназначен для моделирования различных объектов и процессов, и объектно-ориентированные черты появились в нем именно для описания свойств модельных объектов.

Популярность объектно-ориентированному программированию принес язык Smalltalk, созданный в 1972 году. Язык предназначался для проектирования сложных графических интерфейсов и был первым понастоящему объектно-ориентированным языком. В нем классы и объекты – это единственные конструкции программирования. Недостатком Smalltalk являются большие требования к памяти и низкая производительность полученных программ. Причина – в не очень удачной реализацией объектно-ориентированных особенностей. Популярность языков C++ и Ada 95 связана именно с тем, что объектная ориентированность реализована без существенного снижения производительности.

Существует еще язык с очень хорошей реализацией объектной ориентированности, не являющийся надстройкой ни над каким другим языком. Это язык Eiffel (1986 г.). Являясь чистым языком объектно-ориентированного программирования, он, кроме того, повышает надежность программы путем использования "контрольных утверждений".

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

Язык Оccam был создан в 1982 году и предназначен для программирования транспьютеров – многопроцессорных систем распределенной обработки данных. Он описывает взаимодействие параллельных процессов в виде каналов – способов передачи информации от одного процесса к другому. Отметим особенность синтаксиса языка Occam – в нем последовательный и параллельный порядки выполнение операторов равноправны, и их необходимо явно указывать ключевыми словами PAR и SEQ.

В 1985 году была предложена модель параллельных вычислений Linda. Основной ее задачей является организация взаимодействия между параллельно выполняющимися процессами. Это достигается за счет использования глобальной кортежной области (tuple space). Процесс может поместить туда кортеж с данными (то есть совокупность нескольких, возможно, разнородных данных), а другой процесс может ожидать появления в кортежной области некоторого кортежа и, после его появления, прочитать кортеж с возможным последующим его удалением.

Заметим, что процесс может, например, поместить кортеж в область и завершиться, а другой процесс может через некоторое время воспользоваться этим кортежем. Таким образом обеспечивается возможность асинхронного взаимодействия. Очевидно, что при помощи такой модели можно эмулировать и синхронное взаимодействие. Linda – это модель параллельных вычислений, она может быть добавлена в любой язык программирования. Существуют достаточно эффективные реализации Linda, обходящие проблему существования глобальной кортежной области с потенциально неограниченным объемом памяти.

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

Основная идея, лежащая в основе функционального программирования, – это представление программы в виде математических функций (т.е. функций, значение которых определяется лишь их аргументами, а не контекстом выполнения). Оператор присваивания в таких языках не используется (или, как минимум, его использование не поощряется). Императивные возможности, как правило, имеются, но их применение обставлено серьезными ограничениями. Существуют языки с ленивой и с энергичной семантикой. Различие заключается, грубо говоря, в том, что в языках с энергичной семантикой вычисления производятся в том же месте, где они описаны, а в случае ленивой семантики вычисление производится только тогда, когда оно действительно необходимо. Первые языки имеют более эффективную реализацию, в то время как вторые – лучшую семантику.

Из языков с энергичной семантикой упомянем ML и два его современных диалекта – Standard ML (SML) и CaML. Последний имеет объектно-ориентированного потомка – Objective CaML (O'CaML). Среди языков с ленивой семантикой наиболее распространены два: Haskell и его более простой диалект Clean. Интересен язык функционального программирования F#. Он является языком мультипарадигменного программирования. На нем можно писать функциональный, императивный и объектно-ориентированный код. Это позволяет быть более прагматичным, вместо того чтобы пытаться загнать любую задачу, стоящую перед разработчиком, в прокрустово ложе классов и интерфейсов. Язык F# включен в стандартный набор Visual Studio 2010, хотя присутствует и сейчас, в виде плагина для VS2008.

F# использует вывод типов, что приводит к более лаконичным программам. Программист тратит массу времени, добавляя сигнатуры типов, точки с запятыми, фигурные скобки в своем любимом языке программирования. Вся эта информация предназначена большей частью для упрощения создания компилятора. Почему бы не писать тот код, который хочет программист, и предоставить компилятору вычислить остальное? Лаконичность языка F# его главная сильная сторона. F# – это .NET-язык программирования.

Он компилируется в IL в том же рабочем цикле, что и C# с VB, и будет работать с уже существующим .NET-кодом. У него есть интерактивная среда программирования, называемая F# Interactive Window. Программировать на нем увлекательно. Этот язык рушит многие барьеры, связанные с программированием, и позволяет сконцентрироваться на написании кода, который нужен разработчику.

Важно отметить, что F# поддерживает почти все возможности, которые есть у C#. Поэтому его можно использовать, не опасаясь принципа "все или ничего". Не нужно выбрасывать существующий код и переводить все на F#. Вообще, предполагается, что код на F# будет главным образом применяться как библиотеки классов, интегрированные в большой программный продукт.

Программы на языках логического программирования выражены как формулы математической логики, а компилятор пытается получить следствия из них. Родоначальником большинства языков логического программирования является язык Prolog (1971). У него есть ряд потомков – Parlog (1983, ориентирован на параллельные вычисления), Delta Prolog и др.

Технология программирования во многом определяется языком программирования, на котором пишутся программы. В языке могут быть заложены средства, влияющие на технологичность и архитектуру разрабатываемой системы (например, объектная ориентированность, модульность и т.п.). О распространенности языков можно судить по рейтингу, ежемесячно составляемому фирмой TIOBE [26].

В таблице приводится первая десятка языков с наибольшими рейтингами на март 2009 года и указанием тенденций в их местах по сравнению с тем же месяцем прошлого года. Рейтинг составляется по определенной методике, основанной в основном на упоминаниях в Интернете. Как видно, ведущие места занимают C-подобные языки. Язык Java прочно удерживает первую позицию в течение последних лет. Интересно, что эта десятка практически постоянна (см. рейтинги 2005 года), но доля первых трех языков снижается (с 54 до 45 % за 4 года). Это, по-видимому, связано с развитием интернет-технологий с их скриптовыми языками Python, Perl, JavaScript и др.

ПозицияИзменения по сравнению с прошлым годомЯзык программирования Рейтинг Март 2009 Рейтинг октябрь 2005
1 0 Java 19.9% 21.9%
20 C 15.9% 18.8%
3 +2 C++ 10.4% 11.8%
4 0 PHP 9.5% 9.7%
5 –2 (Visual) Basic 8.3% 6.9%
6 +1 Python 5.2% 2.9%
7 +1 C# 4.3% 3.5%
8 +2 JavaScript 3.6% 2.0%
9 –3 Perl 3.4% 7.4%
10 –1 Delphi 2.7% 1.5%

В заключение раздела можно выделить некоторую общую тенденцию в развитии языков программирования. Языки развиваются в сторону все большей и большей абстракции. И это сопровождается падением эффективности. Вопрос: а стоит ли этого абстракция? Ответ: стоит, так как повышение уровня абстракции влечет за собой повышение уровня надежности программирования. С низкой эффективностью можно бороться путем создания более быстрых компьютеров. Если требования к памяти слишком высоки, можно увеличить ее объем. Это требует времени и средств, но это решаемо. А вот с ошибками в программах можно бороться только одним способом: их надо исправлять. Еще лучше – не совершать. А еще лучше – максимально затруднить их совершение. И именно на это направлены все исследования в области языков программирования.

4.2. Основы компиляции

Программы, написанные на языках программирования высокого уровня, перед выполнением на ЭВМ должны транслироваться в эквивалентные программы, написанные на машинном коде. Транслятор – это программа, которая переводит программу на исходном (входном) языке в эквивалентную ей программу на результирующем (выходном) языке. Если исходный язык является языком высокого уровня, например, таким как Паскаль, С++, и если объектный язык – автокод, то такой транслятор называется компилятором.

Достоинство компилятора заключается в том, что программа компилируется один раз, и при каждом выполнении не требуется дополнительных преобразований. Соответственно, не требуется наличие компилятора на целевой машине, для которой компилируется программа. Недостаток: отдельный этап компиляции замедляет написание и отладку и затрудняет исполнение небольших, несложных или разовых программ. В том случае, если исходный язык является языком ассемблера (низкоуровневым языком, близким к машинному языку), компилятор такого языка называется ассемблером.

Другой метод реализации программ, написанных на языке высокого уровня, – интерпретация [21]. Интерпретатор программно моделирует машину, цикл выборки-исполнения которой работает с командами на языках высокого уровня, а не с машинными командами. Такое программное моделирование создает виртуальную машину, реализующую язык. Этот подход называется чистой интерпретацией. Чистая интерпретация применяется, как правило, для языков с простой структурой (например, АПЛ или Лисп). Интерпретаторы командной строки обрабатывают команды в скриптах в UNIX или в пакетных файлах (.bat) в MS-DOS, как правило, также в режиме чистой интерпретации.

Достоинство чистого интерпретатора: отсутствие промежуточных действий для трансляции упрощает реализацию интерпретатора и делает его удобнее в использовании, в том числе в диалоговом режиме. Недостаток – интерпретатор должен быть в наличии на целевой машине, где должна исполняться программа. А свойство чистого интерпретатора, что ошибки в интерпретируемой программе обнаруживаются только при попытке выполнения команды (или строки) с ошибкой, можно признать как недостатком, так и достоинством [20].

Существуют компромиссные между компиляцией и чистой интерпретацией варианты реализации языков программирования, когда интерпретатор перед исполнением программы транслирует ее на промежуточный язык (например, в байт-код или p-код), более удобный для интерпретации (т.е. речь идет об интерпретаторе со встроенным транслятором). Такой метод называется смешанной реализацией. Примером смешанной реализации языка может служить Perl. Этот подход сочетает как достоинства компилятора и интерпретатора (бомльшая скорость исполнения и удобство использования), так и недостатки (для трансляции и хранения программы на промежуточном языке требуются дополнительные ресурсы; для исполнения программы на целевой машине должен быть представлен интерпретатор). Так же, как и в случае компилятора, смешанная реализация требует, чтобы перед исполнением исходный код не содержал ошибок (лексических, синтаксических и семантических).

Для компиляции компилятор должен выполнить анализ исходной программы, а затем синтез объектной программы. Сначала исходная программа разлагается на ее составные части; затем из них строятся части эквивалентной объектной программы. Для этого на этапе анализа компилятор строит несколько таблиц (рис.4.2), которые используются затем как при анализе, так и при синтезе [12].

При анализе программы из описаний, заголовков процедур, заголовков циклов и т.д. извлекается информация и сохраняется для последующего применения. Эта информация обнаруживается в отдельных точках программы и организуется так, чтобы к ней можно было обратиться из любой части компилятора. Например, при каждом использовании идентификатора необходимо знать, как был описан этот идентификатор и как он работал в других местах программы. Что конкретно следует хранить, зависит, конечно, от исходного языка, объектного языка и сложности компилятора. Но в каждом компиляторе в той или иной форме используется таблица символов (иногда ее называют списком идентификаторов или таблицей имен). Это таблица идентификаторов, встречающихся в исходной программе, вместе с их атрибутами. К атрибутам относятся тип идентификатора, его адрес в объектной программе и любая другая информация о нем, которая может понадобиться при генерации объектной программы.

Лексический анализатор (сканер) – самая простая часть компилятора. Сканер просматривает литеры исходной программы слева направо и строит символы программы – целые числа, идентификаторы, служебные слова и т. д. (символы передаются затем на обработку фактическому анализатору). На этой стадии может быть исключен комментарий. Сканер также может заносить идентификаторы в таблицу символов и выполнять другую простую работу, которая фактически не требует анализа исходной программы. Он может выполнить большую часть работы по макрогенерации в тех случаях, когда требуется только текстовая подстановка.

(рис 4.2) Структура процесса компиляции

Обычно сканер передает символы анализатору во внутренней форме. Каждый разделитель (служебное слово, знак операции или знак пунктуации) будет представлен целым числом. Идентификаторы или константы можно представить парой чисел. Первое число, отличное от любого целого числа, использующегося для представления разделителя, характеризует сам "идентификатор" или "константу"; второе число является адресом или индексом идентификатора или константы в некоторой таблице. Это позволяет в остальных частях компилятора работать эффективно, оперируя с символами фиксированной длины, а не с цепочками литер переменной длины.

Синтаксический и семантический анализаторы выполняют сложную работу по расчленению исходной программы на составные части, формированию ее внутреннего представления и занесению информации в таблицу символов и другие таблицы. При этом также выполняется полный синтаксический и семантический контроль программы. Синтаксис – способ соединения слов (и их форм) в словосочетания и предложения. Семантика – это значения единиц языка. Обычный анализатор представляет собой синтаксически управляемую программу.

В действительности стремятся отделить синтаксис от семантики настолько, насколько это возможно. Когда синтаксический анализатор (распознаватель) узнает конструкцию исходного языка, он вызывает соответствующую семантическую процедуру, или семантическую программу, которая контролирует данную конструкцию с точки зрения семантики и затем запоминает информацию о ней в таблице символов или во внутреннем представлении программы. Например, когда распознается описание переменных, семантическая программа проверяет идентификаторы, указанные в этом описании, чтобы убедиться в том, что они не были описаны дважды, и заносит их вместе с атрибутами в таблицу символов.

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

Перед генерацией команд обычно необходимо некоторым образом обработать и изменить внутреннюю программу. Кроме того, должна быть распределена память под переменные готовой программы. Одним из важных моментов на этом этапе является оптимизация программы с целью уменьшения времени ее работы. По существу, на этом этапе происходит перевод внутреннего представления исходной программы на автокод или на машинный язык. Это наиболее хлопотная и кропотливая часть компилятора, хотя и наиболее понятная. В интерпретаторе эта часть компилятора заменяется программой, которая фактически выполняет (или интерпретирует) внутреннее представление исходной программы. Само внутреннее представление в этом случае мало чем отличается от того, которое получается при компиляции.

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

Более детальное представление о процессе компиляции можно получить в специальной литературе [12, 20, 21].

4.3. Понятие системы программирования

Всякий компилятор является составной частью системного программного обеспечения. Основное назначение компиляторов – служить для разработки новых прикладных и системных программ с помощью языков высокого уровня. Любая программа, как системная, так и прикладная, проходит этапы жизненного цикла, начиная от проектирования и вплоть до внедрения и сопровождения. А компиляторы – это средства, служащие для создания программного обеспечения на этапах кодирования, тестирования и отладки. Однако сам по себе компилятор не решает полностью всех задач, связанных с разработкой новой программы. Средств только лишь компилятора недостаточно для того, чтобы обеспечить прохождение программой указанных этапов жизненного цикла. Поэтому компиляторы – это программное обеспечение, которое функционирует в тесном взаимодействии с другими техническими средствами, применяемыми на данных этапах.

Основные технические средства, используемые в комплексе с компиляторами, включают в себя следующие программные модули [20]:

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

    Системы программирования в современном мире доминируют на рынке средств разработки. Практически все фирмы-разработчики компиляторов поставляют свои продукты в составе соответствующей системы программирования в комплексе всех прочих технических средств. Отдельные компиляторы являются редкостью и, как правило, служат только узкоспециализированным целям.

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

    В качестве основных тенденций в развитии современных систем программирования следует указать внедрение в них средств разработки на основе так называемых языков четвертого поколения 4GL (four generation languages), а также поддержку систем быстрой разработки программного обеспечения RAD (rapid application development).

    Языки четвертого поколения 4GL представляют собой широкий набор средств, ориентированных на проектирование и разработку программного обеспечения. Они строятся на основе оперирования не синтаксическими структурами языка и описаниями элементов, а представляющими их графическими образами. На таком уровне проектировать и разрабатывать прикладное программное обеспечение может пользователь, не являющийся квалифицированным программистом, зато имеющий представление о предметной области, на работу в которой ориентирована прикладная программа.

    Описание программы, построенное на основе языков 4GL, транслируется затем в исходный текст и файл описания ресурсов интерфейса, представляющие собой обычные тексты на соответствующем входном языке высокого уровня. С этим текстом уже может работать профессиональный программист-разработчик, он может корректировать и дополнять его необходимыми функциями. Такой подход позволяет разделить работу проектировщика, ответственного за общую концепцию всего проекта создаваемой системы, дизайнера, отвечающего за внешний вид интерфейса пользователя, и профессионального программиста, отвечающего непосредственно за создание исходного кода создаваемого программного обеспечения.

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

    4.4. Возникновение систем программирования

    Первоначально компиляторы представляли собой обособленные программные модули, решающие исключительно задачу перевода исходного текста программы на входном языке в язык машинных кодов. Компиляторы создавались вне связи с другими техническими средствами, с которыми им приходилось взаимодействовать. В задачу разработчика программы входило обеспечить взаимосвязь всех используемых технических средств:

  • подготовить тексты исходной программы на входном языке компилятора;
  • подать входные данные в виде текста исходной программы на вход компилятора;
  • получить от компилятора результаты его работы в виде набора объектных файлов;
  • подать весь набор полученных объектных файлов вместе с необходимыми библиотеками подпрограмм на вход компоновщику;
  • получить от компоновщика единый файл программы (исполняемый файл) и подготовить его к выполнению с помощью загрузчика;
  • поставить программу на выполнение, при необходимости использовать отладчик для проверки правильности выполнения программы.
  • Все эти действия выполнялись с помощью последовательности команд, инициировавших запуск соответствующих программных модулей с передачей им всех необходимых параметров. Параметры передавались каждому модулю в командной строке и представляли собой набор имен файлов и настроек, реализованных в виде специальных ключей. Пользователи могли выполнять эти команды последовательно вручную, а с развитием средств командных процессоров ОС они стали объединять их в командные файлы.

    Со временем разработчики компиляторов постарались облегчить труд пользователей, предоставив им все необходимое множество программных модулей в составе одной поставки компилятора. Теперь компиляторы поставлялись уже вкупе со всеми необходимыми сопровождающими техническими средствами. Кроме того, были унифицированы форматы объектных файлов и файлов библиотек подпрограмм. Теперь разработчики, имея компилятор от одного производителя, могли, в принципе, пользоваться библиотеками и объектными файлами, полученными от другого производителя компиляторов или от другой команды разработчиков.

    Поскольку процессу компиляции всегда соответствует типичная последовательность команд, разрабатывать для этой цели командный файл в операционной системе неэффективно и неудобно. Для написания подобных командных файлов пользователям компиляторов был предложен специальный командный язык, который обрабатывался интерпретатором команд компиляции – программой make (от английского глагола – строить, делать). Командный язык Makefile позволял в достаточно гибкой и удобной форме описать весь процесс создания программы от порождения исходных текстов до подготовки ее к выполнению [12].

    Появление Makefile можно считать первым шагом по созданию систем программирования. Язык Makefile стал стандартным средством, единым для компиляторов всех разработчиков. Это было удобное, но достаточно сложное техническое средство, требующее от разработчика высокой степени подготовки и профессиональных знаний, поскольку сам командный язык Makefile был по сложности сравним с простым языком программирования.

    Такая структура средств разработки существовала достаточно долгое время, а в некоторых случаях она используется и по сей день (особенно при создании системных программ). Ее широкое распространение было связано с тем, что сама по себе вся эта структура средств разработки была очень удобной при пакетном выполнении программ на компьютере, что способствовало ее повсеместному применению в эпоху mainframe с операционными системами типа Unix.

    4.5. Интегрированные среды разработки

    Командная строка – эффективное, но не всегда удобное средство управления компиляцией, хотя с этим могут и поспорить программисты, работающие под операционной системой Unix. Дело в том, что фактически для каждого сложного проекта разработчикам приходится еще одну дополнительную программу, описывающую на языке Makefile, как следует собирать (компилировать) этот проект. А программирование всегда есть потенциальный источник ошибок. Поэтому развитие систем программирования на этом не завершилось.

    Следующим шагом в развитии средств разработки стало появление так называемой интегрированной среды разработки. Интегрированная среда объединила в себе возможности текстовых редакторов исходных текстов программ и командный язык компиляции. Пользователь (разработчик исходной программы) теперь не должен был выполнять всю последовательность действий от порождения исходного кода до его выполнения, от него также не требовалось описывать этот процесс с помощью системы команд в Makefile. Теперь ему было достаточно только указать в удобной интерфейсной форме состав необходимых для создания программы исходных модулей и библиотек. Ключи, необходимые компилятору и другим техническим средствам, также задавались в виде интерфейсных форм настройки.

    После этого интегрированная среда разработки сама автоматически готовила всю необходимую последовательность команд Makefile, выполняла их, получала результат и сообщала о возникших ошибках при их наличии. Причем сам текст исходных модулей пользователь мог изменить здесь же, не прерывая работу с интегрированной средой, чтобы потом при необходимости просто повторить весь процесс компиляции. Кроме удобства работы, объединение текстовых редакторов, компиляторов и компоновщиков в единую среду дало системам программирования целый ряд достоинств.

    Создание интегрированных сред разработки стало возможным благодаря бурному развитию персональных компьютеров и появлению развитых средств интерфейса пользователя (сначала текстовых, а потом и графических). Их появление на рынке определило дальнейшие развитие такого рода технических средств. Пожалуй, первой удачной средой такого рода можно признать интегрированную среду программирования Turbo Pascal на основе языка Pascal производства фирмы Borland [19]. Ее широкая популярность определила тот факт, что со временем все разработчики компиляторов обратились к созданию интегрированных средств разработки для своих продуктов.

    Развитие интегрированных сред несколько снизило требования к профессиональным навыкам разработчиков исходных программ. Теперь в простейшем случае от разработчика требовалось только знание исходного языка (его синтаксиса и семантики). При создании прикладной программы ее разработчик мог в простейшем случае даже не разбираться в архитектуре целевой вычислительной системы.

    Дальнейшее развитие средств разработки также тесно связано с повсеместным распространением развитых средств графического интерфейса пользователя. Такой интерфейс стал неотъемлемой составной частью многих современных ОС и так называемых графических оболочек. Со временем он стал стандартом де-факто практически во всех современных прикладных программах. Это не могло не сказаться на требованиях, предъявляемых к средствам разработки программного обеспечения. В их состав были сначала включены соответствующие библиотеки, обеспечивающие поддержку развитого графического интерфейса пользователя и взаимодействие с функциями API (Application Program Interface, прикладной программный интерфейс) операционных систем [22]. А затем для работы с ними потребовались дополнительные средства, обеспечивающие разработку внешнего вида интерфейсных модулей. Такая работа была уже более характерна для дизайнера, чем для программиста.

    Для описания графических элементов программ потребовались соответствующие языки. На их основе сложилось понятие ресурсов (resources) прикладных программ. Ресурсами прикладной программы будем называть множество данных, обеспечивающих внешний вид интерфейса пользователя этой программы, и не связанных напрямую с логикой выполнения программы. Характерными примерами ресурсов являются тексты сообщений, выдаваемых программой; цветовая гамма элементов интерфейса; надписи на таких элементах, как кнопки и заголовки окон и т.п.

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

    Простая среда разработки включает в себя редактор текста, компилятор и/или интерпретатор, средства автоматизации сборки и отладчик. Когда эти компоненты собраны в единый программный комплекс, говорят об интегрированной среде разработки (Integrated development environment – IDE). Такая среда представлена одной программой, не выходя из которой можно производить весь цикл разработки. В состав комплекса, кроме перечисленных выше компонент, могут входить средства управления проектами, система управления версиями, разнообразные инструменты для упрощения разработки интерфейса пользователя, стандартные заготовки ("мастера"), упрощающие разработку стандартных задач, и др.

    Обычно среда разработки включает в себя текстовый редактор, компилятор и/или интерпретатор, средства автоматизации сборки и отладчик. Иногда она также содержит средства для интеграции с системами управления версиями и разнообразные инструменты для упрощения конструирования графического интерфейса пользователя. Многие современные среды разработки также включают браузер классов, инспектор объектов и диаграмму иерархии классов для использования при объектно-ориентированной разработке ПО. Хотя и существуют среды разработки, предназначенные для нескольких языков программирования, такие как Eclipse, NetBeans, Embarcadero RAD Studio или Microsoft Visual Studio, обычно среды разработки предназначается для одного определенного языка программирования – как, например, Visual Basic, Delphi, Dev-C++.

    Иногда достаточно использовать только одну интегрированную среду разработки, но для больших проектов в среду разработки включаются разнородные продукты разных фирм, разных версий. Пример такого набора: файловый менеджер, набор вспомогательных утилит и пакетных файлов, С++Builder – как IDE, PLSQL Developer – для работы с СУБД Oracle, Cristal Reports – для создания отчетов, StarTeam – для ведения версий и поддержки коллективной работы.

    Операционная среда разработки MS Visual Studio на сегодняшний день является предпочтительным выбором многих разработчиков, работающих на платформе Windows. В процессе своего развития MS Visual Studio имела несколько версий [27].

  • Visual Studio 97 – первая выпущенная версия Visual Studio. В ней впервые были собраны вместе различные средства разработки ПО. Система была выпущена в двух версиях: Professional и Enterprise. Она включала в себя Visual Basic 5.0, Visual C++ 5.0, Visual J++ 1.1, Visual FoxPro 5.0, впервые появилась среда разработки ASP – Visual InterDev. Visual Studio 97 была первой попыткой Microsoft создать единую среду для разработки на разных языках программирования: Visual C++, Visual J++, Visual InterDev и MSDN использовали одну среду, называемую Developer Studio. Visual Basic и Visual FoxPro применяли отдельные среды для разработки.
  • Visual Studio 6.0 вышла в июне 1998 г.. Это последняя версия Visual Studio, работающая на платформе Win9x. По-прежнему популярна среди программистов, использующих Visual Basic. Данная версия являлась основной средой разработки приложений под Windows от Microsoft, до появления платформы .NET.
  • Visual Studio .NET (кодовое имя Rainier; внутренняя версия 7.0) выпущена в феврале 2002 года (включает .NET Framework 1.0). Service Pack 1 для Visual Studio .NET (2002) выпущен в марте 2005 г.
  • Visual Studio .NET 2003 (кодовое имя Everett; внутренняя версия 7.1) появилась в апреле 2003 года (включает .NET Framework 1.1). Service Pack 1 для Visual Studio .NET 2003 выпущен 13 сентября 2006 г.
  • Visual Studio 2005 (кодовое имя Whidbey; внутренняя версия 8.0) выпущена в конце октября 2005 года, последняя официально работающая на Windows 2000 (включает .NET Framework 2.0). В начале ноября 2005 года также вышла серия продуктов в редакции Express: Visual C++ 2005 Express, Visual Basic 2005 Express, Visual C# 2005 Express и др.[ 29] 19 апреля 2006 г. редакция Express стала бесплатной. Service Pack 1 для VS2005 [30] и всех Express-редакций [31] выпущен 14 декабря 2006 года. Дополнительный патч для SP1, решающий проблему совместимости с Windows Vista выпущен 6 марта 2007 г.
  • Visual Studio 2008 (кодовое имя Orcas) выпущена 19 ноября 2007 г., одновременно с .NET Framework 3.5. Нацелена на создание приложений для ОС Windows Vista (но поддерживает и XP), Office 2007 и веб-приложений. Включает в себя LINQ, новые версии языков C# и Visual Basic. В студию не вошел Visual J#. С 28 октября 2008 года впервые доступна версия на русском языке.
  • Visual Studio 2010 (кодовое имя Hawaii, для Ultimate – Rosario) выпущена 12 апреля 2010 года вместе с .NET Framework 4.0. Visual Studio включает поддержку языков C# 4.0 и Visual Basic .NET 10.0, а также языка F#, отсутствовавшего в предыдущих версиях.
  • Среда Visual Studio 2010 позволяет эффективно создавать сложные приложения в течение короткого периода времени. Модель данной среды существенно богаче ранних версий и использует такие понятия, как решение (solution), проект, пространство имен (namespace) и сборка (assembly). Понятие проекта присутствует во многих средах, например, в среде Delphi. Файл проекта содержит перечисление исходных файлов и прочих ресурсов, из которых система будет строить приложение. В решение среды Visual Studio входят несколько проектов, которые могут быть зависимыми или независимыми друг от друга. Выделяется стартовый проект. Понятие сборки исходит из общеязыковой исполнительной среды CLR (Common Language Runtime). Среда CLR является наиболее революционным изобретением, с появлением которого процесс написания и выполнения приложений становиться принципиально другим.

    Компилятор преобразует файлы с исходными кодами в коды на промежуточном языке MSIL (Microsoft Intermediate Language). Вместе с метаданными эти коды записывают PE-файлы (Portal Executable), имеющие расширение exe или dll в зависимости от типа проекта. Также может быть получен модуль с расширением netmodule, который не содержит метаданных.

    Всего имеется 12 типов проектов. При загрузке PE-файлы "на лету" транслируются в команды реального процессора. Каркас Framework.NET, обеспечивающий выполнение программ, не входит в Visual Studio, а является настройкой над операционной системой. Это аналог виртуальной Java-машины.

    Сборка является минимальной единицей для развертывания приложений. Каждый тип сборки характеризуется уникальным идентификатором, идентифицируется цифровой подписью автора и уникальным номером версии. Между сборками и пространствами имен существует следующее соотношение. Сборка может содержать несколько пространств имен. В то же время пространство имен может занимать несколько сборок. Сборка может иметь в своем составе как один, так и несколько файлов, которые объединяются в так называемом манифесте или описании сборки.

    На уровне языка C# пространства имен, аналогично пакетам в Java, служат для структурирования проекта. Пространство имен включает один или несколько классов. В одном исходном файле может определяться несколько пространств имен и в тоже время одно пространство имен может определяться в нескольких файлах. И даже класс может располагаться в нескольких файлах (partial classes).

    Для начинающих программистов такое обилие возможностей может вызвать немалые затруднения. О масштабности и сложности среды можно судить по следующей сравнительной таблице трех сред.

    Операционная среда Число каталогов Число типов файлов
    Блэкбокс 85 9
    C++Builder 367 27
    Visual Studio 3450 188

    Интересной и перспективной представляется операционная среда Eclipse, разработанная в фирме IBM [34]. Первоначальной целью проекта было создание корпоративного стандарта IDE для разработки программ на разных языках под различные платформы. Потом проект был переименован в Eclipse и выделен в открытый доступ. Лицензия позволяет бесплатно использовать код и среду разработки и при этом создавать закрытые коммерческие продукты. Благодаря этому система получила широкое распространение и для многих организаций стала корпоративным стандартом для разработки приложений.

    Экосистема Eclipse относится к консолидированным технологиям, годом широкого распространения которой является 2007-й. Система реализована на языке Java и изначально представляла собой полноценную интегрированную среду для языка Java. В дальнейшем стали поддерживаться и другие языки. Первые версии были неудобны, поскольку целевой продукт вынуждено включал лишнюю функциональность. Начиная с третьей версии была переработана архитектура всей системы с целью максимального разделения модулей и взаимосвязи между ними. При этом модули Eclipse, образованные из согласованных наборов классов, давали функциональность целых подсистем, таких как подсистемы помощи, обновления продукта, обучения, презентации, многоязыковой поддержки и множество других. Разрабатывая приложение, теперь можно постепенно наращивать функциональность, подключая уже готовые бесплатные компоненты. В терминологии Eclipse эти компоненты называются "подключаемыми модулями", или "плагинами" (Plugins). Такая технология становится типичной для развитых операционных сред. Платформа на основе этой технологии получила название RCP (Reach Client Platform), а приложения, соответственно, названы RCP-приложениями.

    Графический интерфейс Eclipse построен с применением графической библиотеки SWT, которая опирается на графику используемой операционной системы. Предусмотрена возможность создания настраиваемых стилей, которые позволяют произвольно менять как внешний вид приложения, так и поведение составляющих его компонентов. Многооконный интерфейс MDI, реализованный в ОС Windows еще в версии 3.1, заменен на альтернативный интерфейс, основанный на закладках. Этот интерфейс похож на интерфейс MS Visual Studio, но имеет и отличия. Режимы работы могут объединяться в одну панель либо размещаться каждый в отдельной панели. Имеется встроенный механизм чередования панелей или механизм "быстрых" панелей, когда они не занимают место на экране, а вызываются кнопками по необходимости.

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

    Данные, которые используются при разработке приложения, размещаются в одном каталоге – рабочей области. Графическая среда разработки (или просто рабочая среда) представляет собой инфраструктуру для управления ресурсами рабочей области и навигации по ресурсам. Рабочая среда включает одно или несколько окон, которые, в свою очередь, могут включать страницы. Каждая страница может иметь так называемые проекции, которые управляют взаиморасположением редакторов и панелей для решения определенных задач.

    Такая, сложная на первый взгляд, организация интерфейса оказывается удобной именно благодаря использованию проекций. Проекцию можно рассматривать как набор визуальных компонент для выполнения конкретно поставленных задач. Например, проекция "Java" содержит необходимый набор для разработки java-приложений, а проекция "CVS" предназначена для оперирования удаленным репозиторием проектов при коллективной разработке. Каждая проекция имеет свой набор меню и панелей инструментов, состав которых можно настраивать и сохранять. Начальный макет проекции определяется разработчиком, но его можно изменять, открывая и закрывая панели и встраивая их в различные места окна рабочей среды.

    Основные визуальные компоненты рабочей среды – панели и редакторы.

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

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

    Процессы разработки приложений, которые включают модули расширений, также имеют отличия от традиционных подходов. При запуске среды разработки создается статический экземпляр рабочей среды, в котором пишется программный код, производится отладка и выполняются другие задачи производственного процесса. Когда же приложение запускается на тестирование, то создается динамический экземпляр рабочей среды, в который включаются выбранные в конфигурации запуска разрабатываемые модули, а также модули целевой платформы. Целевая платформа – это сборка продукта Eclipse, предназначенная для развертывания разрабатываемых приложений.

    За последнее время произошли существенные шаги по упрощению разработки собственных приложений. Кроме мастеров по созданию RCPприложений появился мастер конфигурирования и экспорта продукта. Это существенно упрощает подготовку продукта для развертывания клиентом. Доступен экспорт как в целевой каталог, так и в архив, который можно передать клиенту. Дополнительных инсталляторов не требуется, достаточно просто распаковать архив и создать ярлык на запускаемый файл. Есть возможность создания сборки сразу для нескольких операционных платформ. При желании можно произвести экспорт продукта в каталог и, используя содержимое каталога, создать автоматический инсталлятор для упрощения жизни неподготовленным пользователям.

    Рассматривая перспективы программных технологий, можно было выделить следующие технологические концепции и методологии, которые наверняка повлекут собой изменения в операционных средах: программные шаблоны (паттерны), компонентная разработка, программы как сервис, сервисно-ориентированные архитектуры.

    Вернуться к учебному плану