четверг, 22 января 2015 г.

Принцип "Прямой совместимости" и Web-интерфейсы

Принципом "Прямой совместимости" я называю антипод всем известного принципа "обратной совместимости" (отсюда и название). Заключается он в том, что бы, когда ты вводишь какую-то технологическую инновацию на рынок в новой версии своего продукта, делать предыдущие решения так же с ней совместимыми. В качестве примера можно рассмотреть Microsoft - когда они в 2007-м Office вводили новый формат файлов "Open XML" с приставкой "x" на конце ("*.docx", "*.xslx" и т.д.), они (удивительное дело!) позаботились о том, что бы пользователи 2003-й версии MS Office`а могли работать с этим форматом, выпустив для этой версии соответствующий patch. Так же я ещё помню, как тогда ещё Sun Microsystems, вводя в язык Java Generic`и лишь в 5-й версии, ещё до её final-релиза выпустила update-pack на Java SE 1.4 SDK, который по сути добавлял поддержку Generic`ов в 4-ю версию. Это, что называется, "на слуху", но, думаю, если читатели поразмыслят, то вспомнят и другие примеры такого рода решений прямой совместимости в IT-индустрии.

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

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

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

Давайте представим, например, транслятор, который преобразовывал бы код на Java SE 8 в код на Java SE 7. Лямбды бы, очевидно, превращались в анонимные классы. Отсутствующие классы стандартных библиотек подтягивались бы в качестве библиотек внешних, для этого заюзали бы Jigsaw (на какой она там альфа-фазе, правда, не знаю) - упаковать их в jar`ники, вставить в проект при сборке - и вся недолга! Stream`ы преобразуются в Fork/Join пулы (поверх которых и реализованы). Time API вообще в-лёгкую переписывается на генетически родственную библиотеку Joda Time. Всякие дефолтные и статические методы интерфейсов как-то разруливались бы через абстрактные классы, которые бы генерились и вставлялись в цепочки наследования. Nashorn преобразовывался бы в так же подтягивающийся Rhino - и т.д. Если бы мы грамотно разрулили все такого рода нюансы, то, в идеале, получали бы на выходе вполне выполняющийся код под JRE 1.7. Может быть даже комментарии бы умудрились правильно сохранять, что бы JavaDoc`и, например, генерились корректно. Может быть (а чего бы не помечтать?), даже смогли бы написать не один, а два транслятора - и туда и обратно, протащив не только логику Java 8 в 7`ку, но и обратно, тогда получили бы возможность дать разработчикам самим выбирать - на Java 7 или на Java 8 им писать и часть большого проекта могли бы писать на Java 7, а часть - на Java 8. И дебажить могли бы спокойно, потому что дебаговая инфа бы сохранялась (через какие-нибудь хитрые аннотации, например).

Теперь давайте подумаем - если бы мы добросовестно такой проект реализовали и начали бы на нём работать - имело бы смысл заказчику переходить на новую версию Java? Менять 7`ку на 8`ку?

Мы, ведь, знаем, что лямбды, к примеру, отличаются от анонимных классов не только по форме - на уровне синтаксиса, но и на уровне байт-кода! И, очевидно, эти отличия значимы в первую очередь для производительности. Т.е. реально это - не синтаксический сахар, в то время, как такое вот наше решение могло бы остаться лишь исключительно на уровне синтаксического сахара. Да и Joda Time, боюсь, не так быстра, как Time API из Java 8 - всё-таки тюнить свой код (по крайней мере под стандартную JVM) Oracle`исты умеют лучше OpenSource`ников. Не говоря уже о сравнительных тестах производительности Nashorn`а и Rhino...

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

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

С другой стороны, как ни удивительно, часто это может оказаться даже легче, чем реализовывать новую технологическую версию. В качестве примера здесь приведу приём, который я описывал некоторое время назад, который стал возможен благодаря интересному явлению гомоиконности, присущему языку Lisp (соответственно, и Clojure`у), а так же различным XML-технологиям, например, XSLT. Там я показывал, как можно составить таблицу преобразований на XSLT 1.0, которая будет преобразовывать таблицу преобразований XSLT 2.0 в таблицу преобразований XSLT 1.0 - и тогда сложная библиотека, реализующая XSLT 2.0 вам может оказаться не нужна...

С третьей стороны, внесению инноваций может сопротивляться, как это ни удивительно, сам спрос, для удовлетворения которого эти технологии как бы и разрабатываются! Например, какую ситуацию мы видим в мире Web-разработки? Есть довольно удобный драфт стандарта ECMAScript 6. Там, где нет балласта в виде огромного кол-ва пользователей с устаревшими браузерами, например в сообществе программистов под Node.js, разработчики давно уже используют все фишки этого неутверждённого стандарта и в ус, что называется, не дуют. Но когда заходит речь о браузерах, то всем становится грустно. Яков Файн, у которого я недавно брал интервью для журнала "Хакер" (текст можно почитать тут), например, оценивает темп появления поддержки новой версии стандарта у значительного кол-ва пользователей (достаточного для того, что бы забить на всех остальных) минимум в 2 года после его официального утверждения (при том, что официально он ещё даже не утверждён).
Конечно, не все производители официальных браузеров сидят, сложа руки - многие уже реализуют этот стандарт, но частично. Мониторить ситуацию в real-time можно тут: ECMAScript 6 compatibility table (кстати, как ни удивительно, но "вечный тормоз" на наших глазах стремительно превращается в "вечный газ" - на состояние сейчас флагманом внесения изменений с 72-мя процентами поддержки фич ES6 является Tech Preview IE 12-го, обогнав даже ночные сборки FF, правда, что бы увидеть это чудо, придётся ставить 10-ю версию Windows, так что приходится верить ребятам на слово).

Так же можно мониторить и поддержку новых версий HTML и CSS, например, тут: HTML5 & CSS3 Web Design.

Тут проблему для внесения изменений представляют как раз-таки старые версии браузеров, которые не спешат обновляться. И вот для них такой транслятор был бы очень в тему. И такие попытки действительно есть - это проекты типа ES6-shim, EJS, Traceur`а (кстати, удобно интегрированного в IDEA`ю), но, как легко видеть всё в той же табличке, все они так же, как и браузеры, страдают лишь частичной реализацией ES6. Да и комментарии, представляющие исключительную ценность для сжатия Google Closure Compiler`ом, они так же не сохраняют. Да и парсеры, например, Esprima, почти не поддерживают ES6. И даже IDEA 14`я, хоть и подсвечивает синтаксис удобных конструкций ES6, но пока не работает с этим языком в-серьёз - например, как правило ничего не подставляет по нажатию Ctrl+Spase.

А что Вам делать, если Вы терпите издержки от того, что Вам приходится до сих пор поддерживать IE 8, к примеру? И ладно, когда Вы работаете с корпоративным заказчиком, который сам будет платить за неспособность пользователей перейти на новую версию браузера, а если у Вас - Internet-проект c хитрым Web-interface`ом и Вы понимаете, что разрабатывать намного быстрее и поддерживать дешевле его было бы на ES6?..

Как хорошо было бы, если бы разработчики стандарта сами написали бы такой вот транслятор, как Sun, когда-то написавшая патч с Generic`ами для Java SDK 1.4, и она стала бы своего рода "эталонной реализацией" такого транслятора? Тогда разработчики в дизайн-студиях смогли бы быстро и легко перейти на новую версию языка, а создатели браузеров бы, поддерживая новый синтаксис языка, конкурировали бы между собой по нефункциональным требованиям. Правда, тогда нужно было бы делать проверку на стороне сервера - с какого браузера к нам зашли? Есть ли там этого и этого поддержка? Нету? Тогда вставляем вот этот полифил и/или переформатируем JS-код. Есть? Тогда вот этот кусок JavaScript`а отдаём как есть. Сделать Плагин для Apache, к примеру - было бы вполне достаточно, благо его как прокси-кеш используют многие специализированные решения.

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

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