Эволюция Java

17 сентябрь, 2009 - 12:06Андрей Зубинский

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

Эволюция Java

Приметы нашего времени – сверхвысокая скорость доставки информации, клип-культура и массовое признание социальных сетей, основанных на кратких сообщениях. Кроме них, есть еще много спорных латентных явлений, из перечня которых, пожалуй, на одно стоит обратить внимание. Условно его можно назвать «лягушачьим взглядом». Заключается оно в следующем – тренированный ежедневным информационным калейдоскопом обитатель «цифровой деревни» со временем утрачивает способность замечать медленно изменяющиеся объекты. В результате прогресса этого эффекта сколь угодно большие малоподвижные объекты начинают как бы отсекаться привыкшим к высоким скоростям сознанием. И вот тут-то к засмотревшемуся на мечущиеся в калейдоскопе узоры и подкрадывается большой рычащий и очень шумный каток таких фатальных понятий, как «потребность в стабильности», «унаследованные разработки высокой стоимости», «сопровождение сложных систем на протяжении жизненного цикла»...

Шутки шутками, но если посмотреть внимательно на публикации технологически-популярного характера, эффект «лягушачьего взгляда» заметить очень легко. Новые языки меняются от версии к версии, новые инфраструктуры (frameworks) анонсируются чуть ли не раз в неделю, эклектика модных парадигм и технологий пугает яркой красотой квартиры Эллочки Щукиной. Чуть ли не каждое изменение второй цифры в номере версии какой-либо разработки ее приверженцами объявляется в блогах эпохальным, и эти объявления ретранслируются безразличными к технологиям, но заинтересованными в скорости доставки контента. Мир расширяется, динамика – это модно, все слышат о Ruby, Haskell, F# в том числе и просто потому, что все о них говорят. Множество маленьких проектов, благие вести о реализации каждого из которых мгновенно разносятся «вебдванольной» машиной регенерации новостей, затмевает проекты действительно крупные настолько, что кажется – их и вовсе не существует. Кризисное стремление привлечь внимание потребителя контента волшебными способами сделать «все, быстро и за копейки» только усугубляет ситуацию. Завороженные неофиты, отличающиеся многочисленностью, а также завидной информационной всеядностью и прожорливостью, начинают думать, что все не только просто, а и вовсе уж совсем просто.

У эффекта «лягушачьего взгляда», кроме перечисленных проявлений, есть еще одно, также отчетливо наблюдаемое. Из-за неизбежных столкновений «калейдоскопической» реальности с прочими ее формами с регулярностью часового механизма возникают шаблонные вопросы «Is ... dying?», где вместо многоточия можно подставить любое название из мира унаследованных (legacy), корпоративных и вообще больше «больших», чем «высоких» технологий. Это касается любых масштабных разработок в период эволюционного их развития. Например, закавыченную (т. е. в точности совпадающую в каждом символе) фразу «Is Java dying?» поисковая машина Google находит на 30 тыс. страниц, эту же фразу, но без кавычек – на 237 тыс. С одной стороны, понятно, что подобным вопросом задаются не совсем те же самые люди, которые формируют топ запросов к Google типа «кто такой ктулху». С другой – действительно квалифицированные Java-программисты, если судить по вакансиям кризисного времени, остаются высокооплачиваемыми и востребованными. Одним из объяснений этого парадокса можно как раз считать проявление эффекта «лягушачьего взгляда». С которым мы и попробуем побороться этой статьей. Естественно, по мере скромных возможностей публикации в еженедельнике. Материал этот не предназначен для профессионалов Java, наоборот, он ориентирован скорее на тех, кто разве что и слышал, что есть такая штука – Java.

Элементы инфраструктуры Java
Эволюция Java Эволюция Java Эволюция Java Эволюция Java
Ориентированный на эволюционное развитие расширяемый мультипарадигменный язык программирования Клон Lisp, язык функционального программирования Clojure Интерированные среды разработки NetBeans и Eclipse

Как часто случается с масштабными и «долгоиграющими» разработками, Java начиналась вовсе не с тех задач, которые ставятся сейчас перед результатом ее многолетней эволюции. И, естественно, без мысли о сегодняшних масштабах. Просто в первой половине 90-х годов для создания нового поколения небольших встраиваемых систем потребительского назначения понадобился удобный язык. Не такой сложный, как С++. И не такой небезопасный, как просто C. Речь ведь шла фактически о бытовых приборах, в процессе разработки которых что сверхдорогие высококлассные программисты С++, что ничуть не менее дешевые процедуры доведения до промышленного качества С-кода – настолько непозволительная роскошь, что уж лучше сделать новый язык и среду его исполнения (runtime). К слову, почти через 20 лет после начала начал Java (которые отыскиваются где-то в 1990 г.), задача создания подобного инструментария, подходящего для встраиваемых систем разных масштабов, остается не менее актуальной, потому что в арсенале разработчиков по сей день основными инструментами являются С и (в значительно меньшей мере) С++. Даже не первое, а нулевое поколение будущей Java (несколько позже несоответствие родов – женского для Java и мужского – для «языка», будет объяснено) уже в 1992 г. располагало и собственной аппаратной платформой, конструктивно выполненной в виде носимого персонального цифрового ассистента (PDA), и достаточно (для уровня поставленных задач) развитой программной инфраструктурой. Только за первые четыре года идеи области применимости новой разработки менялись несколько раз. Персонифицированные вычислители сменились интерактивными телевизионными бытовыми приставками, затем «бытовуха» ушла на второй план (но и эта ветвь эволюции не оказалась тупиковой и позже «аукнулась» исчисляемой миллиардами инсталляционной базой мобильных телефонов, оснащенных Java) и в 1994 г. наступил период WWW. В том же году проект получил и современное название (прежнее Oak оказалось уже зарегистрированным). Если подойти сугубо формально к описанию дальнейшей эволюции Java, можно ограничиться следующей «траекторией» в системе координат «версия – год»: 1996 г. – версия 1.0, через год – 1.1, 1998 г. – 1.2, ставшая тем, что называют Java 2, 2000 г. – Java 2 версии 1.3 (нумерация версий, несмотря на Java 2, осталась «сквозной»), 2002 г. – Java 2 1.4, 2004 г. – нарушение сквозной нумерации: Java 2 версии 5.0, 2006 г. – очередная версия 6, и теперь уже опять не Java 2. Этот перечень на самом деле не настолько бессмысленный (как может показаться из-за отсутствия описания изменений и особенностей каждой версии). Десять лет истории (на самом деле – больше) – заметный, но не всегда соблюдаемый двухлетний цикл выпуска версий. Открытые спецификации. Лавинообразный рост инсталляционной базы. Появление клоновых реализаций. Битвы за недопущение модификации спецификаций, которые приводят к появлению несовместимых продуктов. Судебные процессы. Победа над Microsoft, принуждение ее к признанию единственно верных спецификаций. За счет этого – почти миллиардная инсталляционная база в мире Wintel. И параллельно со всеми этими процессами, являющимися всего лишь составляющими сложного процесса эволюции большой разработки, – технологическое развитие, причем такое, которое гарантированно сохранит всех инвестировавших в технологию Java от таких последствий типичного волюнтаризма правообладателя, как несовместимость на уровне спецификаций. Иными словами, разработчики Java сражались сразу на всех фронтах, да еще и сами с собой. Можно, конечно, считать, что такой подход затормаживает прогресс, но логику никто не отменял – потребители заинтересованы в стабильности своих инвестиций в технологии, и кто хочет действительно массового признания своей hi-teck-продукции, тот или должен уберечь ее потребителей от революций, или так проводить революции, чтобы не просто не «до основанья», а и вовсе чтобы ни одна пылинка не упала.

В 2009 г., конечно, кому-то все эти разговоры покажутся излишеством. Но кому-то ведь и откровением – массовые технологии «въедаются» в повседневные предметы до полной незаметности, и потому с какого-то момента становятся... опять интересными. Так что теперь можно и нужно немного сказать и о самой Java. Начнем с того, что это давным-давно не язык программирования. Нет, естественно, и язык тоже. Но вовсе не только и даже не столько язык. Сегодня Java – параллельно развивающиеся совместимые «снизу вверх» четыре программные инфраструктуры разного назначения и масштабов. Нижняя граница диапазона вычислителей, обеспечивающих аппаратную поддержку этих инфраструктур, определяется микроконтроллерами смарткарт (обычно 16-битовыми, с единицами килобайтов ОЗУ и десятками – ПЗУ), верхняя – суперкомпьютерами. Инфраструктуры образованы комбинацией виртуальной машины Java, многослойных бесчисленных библиотек самого разного назначения и, наконец, многоуровневого инструментального набора, в который входит и язык программирования Java.

Как язык программирования Java – lingua franca современного компьютинга, в каком-то смысле и вовсе псевдокод. Это значит, что фрагменты Java-кода может прочесть фактически любой мало-мальски грамотный программист, даже не учивший Java. Достигается это во многом благодаря не только изначально хорошо продуманному синтаксису, но и принципу, которого придерживались и продолжают придерживаться разработчики языка – «читаемость важнее синтаксического подслащивания». Или, в кофейных терминах (которые неизбежны, раз уж речь идет о Java) – благодаря принципу «горького крепкого кофе». Иными словами, предлагаемые «украшения» синтаксиса Java, конечно же, могут быть приняты разработчиками, но добиться этого очень и очень непросто. Некоторые горячие головы берутся утверждать, что такая особенность языка приводит к его «неуклюжести», что языки новой волны позволяют в одну строку кода «утрамбовать» несоизмеримо большую функциональность. Впрочем, упреки, касающиеся эстетики, в мире языков программирования будут всегда, так что можно на них не обращать внимания. В конце концов, один из самых могучих языков Lisp имеет такой синтаксис, который вызывает вообще сомнение в наличии какого-либо синтаксиса. Что не помешало Lisp мало того что оказаться долгожителем, так еще и настоящим чемпионом по количеству «ответвлений» (к слову, одно из них предлагает и Java-платформа – язык Clojure, clojure.org).

Раз язык Java принято изменять крайне неохотно, то основной объект эволюционного процесса – вся остальная часть инфраструктур. Главные события происходят именно там. Потому если кому чего-то не хватает даже в синтаксисе Java, следует искать недостающего в элементах инфраструктуры. Эта особенность во многом определяет сам стиль работы Java-программиста. Например, если ему нужна в языке реализация такой модной конструкции, как замыкание (closure, вложенная функция, имеющая доступ к переменным из «наружного» контекста), он сначала не пытается ни имитировать требуемое имеющимися языковыми средствами (хоть это и возможно), ни писать предложения разработчикам языка и ждать (хоть их и пишут, конечно же). Он поступает в точности так, как поступает любой инженер – ищет готовое решение. Благо, информационная поддержка этого процесса в Java-сообществе доведена до индустриальных масштабов. И естественно, требуемое находит (например, мощную библиотеку lambdaj, наделяющую Java весьма развитыми механизмами функционального программирования, code.google.com/p/lambdaj). «Естественно» употреблено не случайно – Java-инфраструктуры давно стали отдельным огромным миром, в котором можно найти чуть ли не все, что может потребоваться. Как ни странно, но эта особенность Java-программирования, которую можно смело называть «software engineering в прямом смысле», часто подвергается критике. Говорят, что такое «компонентное изобилие» развращает программистов. Вот только говорящие это молча пользуются всеми доступными благами инженерии, ничуть не возмущаясь тем вопиющим фактом, что, например, развращенные конструкторы и производители автомобилей упорно не хотят каждый подшипник, вал и микросхему делать самостоятельно и «с нуля».

Эволюция инфраструктур привела Java к весьма впечатляющим характеристикам. Например, к высокой производительности – характеристике, несвойственной системам, в фундаментальных основах которых заложен принцип виртуализации. Тем не менее сегодня Java безоговорочно принята и признана требовательным к производительности научным сообществом в качестве расчетного инструмента. Этот факт лучше любых синтетических тестов подтверждает одно из впечатляющих достижений эволюции. И эволюционный процесс продолжается, причем в весьма очевидных направлениях, о которых можно легко догадаться по контексту даже такого легковесно-обзорного материала. Итак, раз основной объект эволюции – Java-инфраструктура, и раз количество, например, библиотек становится не просто очень большим, а сверхбольшим, возникает проблема наведения порядка. Кроме того, инфраструктура «раздувается», что усложняет процессы распространения и сопровождения ПО. Ну и наконец, инженерный подход к разработке программ очевидно требует мощного механизма отслеживания зависимостей конечного продукта от многочисленных компонентов. Классический подход к решению подобных задач – развитая система модулей. Для ожидающегося нового седьмого релиза Java предложено несколько вариантов модульных систем, в том числе и позволяющих тотально реорганизовать и сформировать развитую модульную структуру самой Java-инфраструктуры (проект Jigsaw). Какие именно из предложений окажутся одновременно наиболее удобными и настолько «безопасно революционными», что будут удостоены внесения в спецификации Java, покажет седьмой релиз. Второй важнейший и наиболее ожидаемый эволюционный эффект – адаптация Java к реалиям аппаратных платформ сегодняшнего дня. Взрывной рост доступности многоядерных вычислителей – явление вовсе не десятилетий, и было бы, мягко говоря, наивным требовать от разработчиков такой махины, как нынешняя Java, мгновенной на него реакции. Но все же реакция будет – седьмая версия предложит обновленную поддержку разработки параллельных программ. Причем в полном соответствии с традициями Java это будет очередное изменение на уровне инфраструктуры, не затрагивающее языка программирования. Java в текущей версии располагает механизмами параллельного программирования, соответствующими реалиям сегодняшнего, но не завтрашнего дня. Утилизировать с их помощью возможности современных многоядерных процессоров можно, но ожидаемый рост числа ядер (32 и выше) заставляет искать новые подходы. Механизм ответвления/объединения (fork/join) предлагает весьма изящную и эффективную поддержку параллельного решения большого класса задач, которые в последовательном мире принято решать методом «разделяй и властвуй»:

задача {
if ( масштаб задачи мал)
решить задачу
else {
разбить задачу на
подзадачи
ответвить-запустить
решатели каждой
подзадачи
объединить решатели
найти композицию
результатов работы
решателей
}
}

Механизм fork/join интересен и тем, что предусматривает автоматический «перехват» незанятых вычислительных ресурсов, т. е. полную загрузку имеющихся аппаратных средств.

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