До сих пор не создано такого языка программирования, который бы одинаково хорошо решал все задачи программных систем. Уже существует большое количество языков и новые продолжают появляться. Устаревшие языки не спешат уйти со сцены, на них написаны программы, и они продолжают работать, а значит, по ним нужны специалисты для сопровождения и развития существующих программ. Возможно, не стоит ориентироваться на устаревшие или не получившие достаточного распространения языки, но, например, если вы вдруг надумаете устроиться программистом в компанию Боинг, то вам придется изучить язык достаточно прогрессивный для своего времени и не очень распространенный в наше - язык Ада.
Текущее представление языков примерно выглядит так:
- Старые
- Fortran, Cobol, PL\I, Basic, Pascal, Ada, Lisp, …
- Мейнстримные
- C, C++, Java, C#, JavaScript, Python, Ruby, PHP, …
- Новые и будущие
- Go, Swift, Hack, Rust, Kotlin, Scala, …
- Нишевые
- D, Clojure, OCaml, Haskell, …
Есть множество причин, по которым создаются новые языки. Самая общая из них заключается в появлении новых задач, требованиям которых не удовлетворяют в полной мере существующие языки. Вот несколько причин возникновения новых языков:
- Необходимость избавиться от архаичного наследия «старых» языков
- Несоответствие существующих ЯП новым задачам и возросшим требованиям
- Недостаточность уровня абстракции в существующих языках для уровня сложности решаемых задач
- Желание сохранить контроль над эволюцией языка
- Для обучения или проверки положений теории языков на практике
- Маркетинг (например J#)
- Энтузиазм отдельных разработчиков
Следующая таблица демонстрирует, что несмотря на наличие существующих языков, решающих сходные задачи, известные ИТ компании создают собственные языки, а не переиспользуют готовые.
Таблица 1. Новые языки, появившиеся в последнем десятилетии от известных ИТ-компаний
Компания |
Год |
Язык |
Описание |
Apple |
2014 |
Swift |
язык общего назначения на замену Objective C |
|
2014 |
Hack |
замена PHP |
|
2009 |
Go |
язык реализации веб-приложений |
|
2011 |
Dart |
более надежная и производительная замена JavaScript |
JetBrains (СПб, Россия) |
2011 |
Kotlin |
простая и эффективная замена Java |
Microsoft |
2012 |
TypeScript |
«улучшенный» JavaScript (аннотация типов, классы) |
Mozilla |
2010 |
Rust |
язык реализации алгоритмов для многоядерных архитектур |
RedHat |
2011 |
Ceylon |
«упрощенный» Java |
Однако язык не может существовать сам по себе. Языку требуется активное сообщество, которое использует язык, популяризирует его, участвует в его развитии. В современных условиях язык без возможности интеграции с существующими библиотеками не имеет будущего. Действительно, никто не будет писать с нуля на новом языке, каков бы он не был хорош изначально, алгоритмы, которые уже написаны и проверены временем на других языках. Как минимум новый язык должен поддерживать вызов библиотечных функций, написанных в формате языка C.
С появлением таких языковых платформ как JVM и CLR задача интеграции библиотек кода на различных языках была решена на качественно новом уровне. Код, написанный на платформе, автоматически становится интегрированным в общую многоязычную среду. Платформа обеспечила не только интеграцию на этапе исполнения, но и переносимость как аппаратную, так и программную под различные операционные системы. Отладка и написание многоязычных проектов стала возможной в единой среде разработки. Последнее обстоятельство привело к новому видению использования различных языков в одном проекте - созданию многоязычных проектов.
Проекты с использованием нескольких языков открывают новые возможности проектирования программных систем. В таких системах под разные задачи для разных частей выбирается тот язык, средствами которого достигается лучший результат. Синергетический эффект такого подхода достигается за счет использования преимуществ языка в тех частях, для которых выбранный язык будет наиболее эффективным и компенсации недостатков в тех, где лучше всего использовать другой язык.
Системный архитектор и разработчик Ола Бини (Ola Bini) интересуется языками программирования. В своей статье «Фрактальное программирование» Ола Бини рассуждает о том, как, по его мнению, можно организовать проекты, основанные на использовании нескольких языков программирования. Для понимания того, какие языки и в каком сочетании можно использовать в многоязычных проектах Бини предложил рассматривать структуру приложения по слоям. В своем условном делении Бини выделяет три слоя и рассматривает их в виде перевернутой пирамиды.
В перевернутой вершине пирамиды находится стабильный слой. Приложения этого слоя отвечают самым высоким требованиям по производительности, стабильности, отсутствию ошибок. Написание программ на таких языках является самым трудоемким и дорогостоящим. Именно поэтому пирамида перевернута - ведь ПО этого уровня обречено пребывать в меньшинстве. Однако затраты на создание такого ПО вполне оправдывают себя благодаря существенно большему количеству переиспользования библиотек этого слоя из ПО верхних слоев.
В динамическом слое располагается ПО, с одной стороны, достаточно ответственное, чтобы создавать ПО высокого уровня качества, с другой стороны, достаточно гибкое, чтобы трудоемкость его создания была ниже, чем из стабильного слоя.
И, наконец, верхний слой, самый нестабильный, с низким уровнем ответственности. Языки этого слоя предъявляют невысокие требования к уровню знаний программиста и тем самым обеспечивают большую армию разработчиков. Основное назначение этого слоя - быстрая поставка ПО. К этому слою относится легкие языки без контроля типов для создания ПО типа front-end и, так называемые, DSL для создания прикладного ПО. Это языки переднего края, максимально приближенного к своим потребителям, настолько, что даже знаний непрограммиста может вполне хватать чтобы сделать свой веб-сайт или даже построить свою БД для личного учета. В этом слое разрабатывается самый значительный объем ПО и ему соответствует самая широкая часть пирамиды Бини.
Слой |
Описание |
Языки |
Предметный слой |
Быстрая прикладная разработка |
1С, SQL, XML, XAML, веб-шаблонизаторы |
Динамический слой |
Быстрая продуктивная, гибкая разработка |
JavaScript, Python, Clojure |
Стабильный слой |
Стабильный, высокопроизводительный, хорошо протестированный функционал |
Java, C#, Scala |
Рисунок 1. Пирамида Бини
Системный архитектор и идейный вдохновитель компании ThoughtWorks Нил Форд (Neal Ford) предложил разделить языки по признаку типизации: сильная-слабая, статическая-динамическая. Такое разделение позволяет понять, как можно соотнести языки по слоям приложения Бини.
При таком делении к стабильному слою относятся языки с сильной статической типизацией. Как уже отмечалось выше, ПО, создаваемое на таких языках может отвечать весьма жестким требованиям по качеству. К такому ПО относятся: компиляторы, драйверы устройств, встроенное ПО, билинговые системы, серверное ПО, высоконагруженные сервисы, компьютерные игры.
К динамическому слою относятся языки с динамической сильной типизацией. Отличительной чертой языков этого слоя является высокая скорость создания качественных программ. ПО этого слоя: скрипты автоматизации, администрирования и создания тестов, веб-разработка (бэк-енд), прототипирование.
На последнем верхнем слое располагаются предметно-ориентированные языки с динамической слабой типизацией. Это языки, на которых пишется ПО прикладного уровня: системы учета, скрипты с упрощенным синтаксисом для программирования формул или встроенной техники, DevOps, моделирование бизнес-правил и интеграции. Для них характерно отсутствие контроля типов, неявные приведения и динамическое определение типов.
Рисунок 2. Языки по типизации: сильная-слабая, статическая-динамическая с выделением слоев Бини
Функциональное деление (будущее языков)
В развитии своей теории многоязычного программирования Нил Форд выдвинул идею того, что в классификации слоев Бини стабильные языки будут развиваться в сторону увеличения поддержки функционального стиля. Уже сейчас в моду входит функциональный стиль программирования и, хотя программы бухгалтерского учета пока еще не пишут на Haskell, многие языки начинают поддерживать операции с функциями высшего порядка. Такие понятия, как «декларативный», «чистые функции», «каррирование» потихоньку начинают проникать в лексикон все большего количества программистов.
Распространению идей функционального программирования в немалой степени способствуют успехи в области создания многоядерных архитектур с одной стороны и проблемы создания программ, использующих параллельные вычисления на императивных языках с другой. Дело в том, что параллельные вычисления очень сложно поддаются программированию в императивном стиле и в тоже время очень органично и проще решаются в функциональных языках. Кроме того, функциональным языкам присущ высокий уровень абстракции, благодаря которому становится возможным решение сложных задач.
В будущем по Форду типизация уже не будет играть такую большую роль, а определяющим будет чистота реализации функциональной парадигмы. Типизация останется, однако будет прерогативой самого программиста.
Форд также обращает внимание на распространение поддержки создания DSL средствами самого языка. В таких языках как Scala и Clojure встроенная поддержка создания собственных DSL позволяют просто и компактно формализовать важные концепции предметной области. По Форду языки будущего помимо мультипарадигмальности будут также поддерживать DSL во всех слоях.
Современные языки идут по пути поддержки мультипарадигмальности. Языки, исторически поддерживающие парадигму процедурного и ОО программирования, начинают вводить элементы поддержки парадигмы функционального стиля. Функциональные языки наоборот расширяют свои возможности, вводя поддержку ОО парадигмы.
Такое развитие имеет как свои плюсы, так и минусы. Если поддержка функционального стиля - это, как правило, расширение возможностей языка, то добавление в функциональный язык ОО парадигмы - это улучшение интеграции с другими языками с ОО парадигмой. Сравните: язык Scala - продвинутый язык Java с элементами функционального стиля и Clojure - чисто функциональный язык с поддержкой ОО парадигмы для совместимости с Java.
Мультипарадигмальность увеличивает мощь языка, но может и привести к проблемам. Так, когда один проект разрабатывается разными командами с использованием различных парадигм, то существует риск разработки несовместимых библиотек. Разработка в ОО парадигме стимулирует использование структур, а в функциональной - композицию и функции высшего порядка. В результате смешения парадигм могут получиться существенно различающиеся алгоритмы, которые не смогут работать без взаимной адаптации, а значит, внесения дополнительного усложнения в проект. Подобные проблемы команды разработчиков уже испытывали при переходе с Java на Ruby или с C на C++.
Рисунок 3. Распределение языков по слоям приложения по функциональному признаку
В сложившейся ситуации программисту недостаточно знать только один язык программирования. Работая сегодня над проектом на одном языке, возможно, уже в следующем проекте или в этом же, придется писать код на другом языке, выбранном для решения соответствующих задач. Так какой же язык имеет смысл знать или изучать? Однозначного ответа на этот вопрос нет. Однако есть нечто общее во всех языках и есть различия. Знание общего позволят сэкономить время вхождения в новый язык, сконцентрировавшись лишь на различиях.
Общим для всех языков является синтаксис, а различие, в основном, кроется в семантике. Так, в любом языке могут быть структурные синтаксические конструкции, условия, вызовы, структуры данных, классы и т.д. Несмотря на кажущуюся одинаковость синтаксических конструкций наличие семантических различий может привести к неверной интерпретации работы алгоритмов и к ошибкам.
Одна и та же синтаксическая конструкция «ТКласс Класс» в языке C++ будет означать конструирование объекта, а в языках Java/C# - неинициализированный объект типа null. В 1-ом случае можно продолжать работать с объектом, а во 2-ом попытка работать с неинициализированным объектом приведет к краху программы.
В общем случае профессионально-ориентированному программисту необходимо владеть знаниями компьютерных наук, различных парадигм и быть в курсе последних тенденций развития языков. Можно рекомендовать знать несколько языков из различных слоев приложений (см. Слои Бини) или одного слоя - в количестве 3-4 языков. Ниже приведены варианты выбора языков исходя из целей.
Цель |
Язык |
Узнать, как устроен и работает компьютер |
C |
Научиться работать со сложными структурами данных |
C#, Java |
Научиться программировать эффективные алгоритмы работа с данными |
C++ |
Научиться строить большие и сложные сайты |
JavaScript |
Для цели определения какой язык стоит изучить можно использовать также исследование организации IEEE Spectrum «Первые 10 языков программирования»:
Рисунок 4. Интегральный рейтинг языков программирования 2018 IEEE Spectrum
Выбор для работы
Цель |
Язык |
Недостатки |
Нужна быстрая и эффективная программа? |
C, C++ |
трудно писать; трудно поддерживать |
Быстро написать и получить работающую программу или сайт? |
JavaScript, Python, Ruby |
работает медленно, часто ломается (зависает), пока происходит поиск ошибок |
Быстро небольшой веб-сайт? |
PHP |
для дальнейшего улучшения веб-сайта может потребоваться много усилий |
Выбор языка в проекте зависит от множества факторов, вот некоторые из вопросов, которые могут помочь определиться с языком:
- какова кривая освоения языка?
- насколько эффективны существующие фреймворки?
- насколько развито сообщество языка?
- насколько быстро можно найти нужных разработчиков?
- насколько легко язык интегрируется в многоязычную среду?
Несмотря на то, что в заголовке этого абзаца язык 1С обозначен как DSL, это утверждение не всеми разделяется. Действительно, на языке уже написана масса прикладных решений в самых разнообразных сценариях использования и это не только учетные задачи. В самом языке есть встроенные объекты для работы с файлами даже на уровне байтов. Все это может представляться как написанное на языке общего назначения. Сам Мартин Фаулер, который ввел понятие DSL, в своем труде отмечал, что порой очень сложно отнести возможности языка именно к DSL и существует тонкая грань, где язык выходит за рамки только одной предметной области и уже может рассматриваться как язык общего назначения. Но давайте рассмотрим, что же представляет собой встроенный язык платформы 1С.
Платформа 1С поддерживает встроенный язык программирования (именно "встроенный язык", а не "язык 1С", т.к. официального названия у этого языка нет). Предполагается, что основная функциональность прикладного решения реализуется средствами визуального конструирования в режиме конфигуратора. Платформа предоставляет множество событий, в обработчиках которых на встроенном языке можно изменить типовое поведение платформы.
Основное ограничение встроенного языка - алгоритмы могут быть запущены только в реализованных событиях платформы. Определение вызываемой функции по событию также предопределено платформой и не может быть произвольным. В платформе отсутствует также понятие "библиотеки" в смысле кода со своей областью видимости. Синтаксис и семантика встроенного языка максимально просты. Все основные возможности языка реализуются через встроенные объекты платформы.
Встроенный язык обладает множеством ограничений, которые не характерны для языков общего назначения. На этом языке нельзя построить эффективный веб-сервер или реализовать интерфейс, не поддерживаемый платформой (попробуйте изменить цвет выделения текущей строки табличного поля). С другой стороны, все необходимое для решения прикладных задач максимально реализовано в объектах платформы, которые доступны из языка. Семантика объектов определена на уровне платформы и благодаря этому обеспечивается их поддержка: целостность данных, расчет итогов, права доступа, представление в интерфейсе и т.д.
Из определения языка 1С как DSL следует вывод о возможном его развитии. Собственно, сам язык, начиная с версии 1С7, не сильно изменился. Все, что меняется для языка - это расширение встроенных объектов и появление дополнительных встроенных функций. И, скорее всего, так и будет продолжаться: в платформе продолжат появляться новые объекты, потребность в которых будет обозначена сложными реализациями на встроенном языке. Например, недавно появились объекты, с помощью которых можно работать с историей хранения, когда похожая функциональность была реализована ранее средствами встроенного языка и потребность в простом решении на уровне платформы назрела.
Практика показала безуспешность поиска единого универсального языка программирования. Новые языки продолжат появляться. Каждый новый язык будет по-своему находить компромисс между скоростью разработки, производительностью и надежностью. Кроме того, большое разнообразие предметных областей гарантирует неисчерпаемую потребность в предметно-ориентированных языках, как наиболее адекватно описывающих её задачи. Платформы JVM и CLR, изначально созданные для решения задачи переносимости, а в последствии и унификации моделей программирования, будут только способствовать появлению новых языков.
В сложных приложениях найдут применение многоязычные проекты. Такие проекты в рамках одной платформы JVM или CLR будут включать алгоритмы, написанные на разных языках, однако на уровне байт-кода это будут единые приложения с разделяемыми данными.
Универсальные языки продолжат развиваться в сторону мультипарадигмальности. Исторически такие языки начинали работать в процедурной парадигме, затем в ОО и теперь набирает популярность функциональная парадигма. Постепенно функциональный стиль будет становиться основным, а императивный вспомогательным. Ответственные приложения будут делаться на функциональных языках, сфера применения императивных языков останется для задач ввода/вывода, необратимых операций, разработки интерактивных интерфейсов пользователя.
Наряду с мультипарадигмальностью языки начнут поддерживать создание DSL. Останутся также и внешние DSL как самые приближенные к предметной области языки. Эти языки будут иметь самый низкий порог вхождения и будут доступны даже для непрограммистов.
Профессиональным программистам необходимо смириться с необходимостью знать несколько языков программирования. С одной стороны, знание нескольких языков может сильно увеличить умственную нагрузку на программиста, с другой - все языки обладают сходными синтаксическими конструкциями, а значительную трудность в освоении языков составляет семантика и стандартная библиотека языка.
Зачастую технологии, изначально созданные для решения одной задачи, являются ключом к качественно новым решениям в других. Так, среда JVM, CLR изначально создавались для решения задачи переносимости и унификации моделей программирования (последнее изначально закладывалось в CLR для двух языков: C# и VB). В последствии оказалось, что существование таких сред позволяет в принципе поменять отношение к разработке: если раньше преимущество в разработке отдавалось какому-то одному языку, а трудные аспекты языка решались на уровне поставки компонентов и библиотек среды или даже расширении языка, то теперь открылась возможность в принципе в одном проекте совмещать решения на разных языках программирования, используя преимущество каждого из них для конкретного рода задач. Подводя итог, можно утверждать, что идея создания одного универсального языка на данном этапе развития не оправдала надежд, и мир ИТ идет по пути многоязычного программирования.
PS
Материал этой статьи был представлен ранее в сокращенном варианте новостного формата. Там же есть опросник "Сколько языков программирования вы знаете?". Новость получила живой отклик. Тема мне показалась интересной, и я решил выложить полный вариант статьи, получившейся в результате моего исследования.