30 июня 2013

Почему чистые Java Servlet'ы и JSP полный отстой в промышленных приложениях.

Всем привет!

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

Данный пост - это  мой перевод одной из глав книг "Tapestry in Action". Мне пришлись по нраву предложенные аргументы и я хотел бы их как-то зафиксировать хотя бы для себя. Некоторые подходы, которые используются при создании сервлетных приложений, часто используются и в других областях программирования и о вреде их использования стоит помнить.

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


"Понимание ограничений сервлетов".


Существует качественное различие между демонстрационными и учебными сервлетными приложениями и настоящими промышленными приложениями. Демонстрационные приложения небольшие, сфокусированы и ограничены областью применения. Они обычно создаются в короткие сроки людьми, которые одновременно являются и архитекторами и верстальщиками и Java программистами, в то время как разработка масштабируемых приложений влечёт за собой многочисленные проблемы из реального мира:
  • Большое количество разработчиков (верстальщики и Java программисты) могут работать параллельно.
  • Каждый разработчик будет иметь различный уровень навыков.
  • Внешний вид приложения может быть разработан группой участников с весьма скромным или полным отсутствием знаний о Java или JSP (или даже они могут быть вообще отделены от общей группы разработки).
  • Большие приложения (с сотнями различных страниц) могут быть настолько сложными, что отдельные разработчики будут понимать только небольшую часть приложения.
  • Удачные приложения должны, почти по определению, расти и их сложность будет увеличиваться чтобы удовлетворять новые требования пользователей.
Эти проблемы проявят себя в большом количестве общих антипаттернов, которые будут описаны далее.

Слабое связывание


Большинство фундаментальных проблем с построением, поддержанием и расширением web приложений, которые используют сервлеты, окружают две связанные проблемы: слабое связывание и нежелательные зависимости. В сервлетном приложении связи между страницами слабые, т.к. их соединения выражены в URL'ах, а не в вызовах методов или свойствах объектов. В тот момент когда JSP рендерит ссылку (или форму) соединение с другой страницей в приложении - это всего-навсего  вывод строки, как атрибута href тега <a> тэга гиперссылки (или атрибута action тэга <form>). Это ещё одно отличие между десктопными и серверными приложениями . Изменение сигнатуры метода объекта в десктопных приложениях создадут ошибки в коде где-то ещё в приложении, где используется старая сигнатура метода. IDE чётко покажет эти ошибки, и вы сможете найти и пофиксить их все до запуска и тестрования приложения.

В сервлетном приложении связь между двумя сервлетами упрощена до строки внутри JSP. JSP должна содержать URL до нужного сервлета, которая будет отправлена клиентскому web  браузеру. Откуда эта строка там появилась? Разработчик вручную вставил её в JSP после анализа дескриптора деплоя (файл web.xml) в попытках найти подходящее отображение действия на ссылку. Полагая, что разработчик не опечатался и линк должен работать, нет способа быть абсолютно уверенным в этом без реально запущенного приложения. Эта линковка сервлета к сервлету является слабым связыванием. Java компилятор или другие тулзы не могут провалидировать (во время компиляции) что URL'ы корректные и рабочие. Эта проверка может быть проведена только в рантайме.

Слабое связывание через URL'ы не огрызнется, пока приложение изменяется в одном установленном направлении. Но стоит измениться сигнатуре операции в приложении, например, URL поменяется (например, c /addCustomer на /addRetailCustomer)или атрибуты запроса поменяются, и данное изменение потребует пройтись по всему приложению для поиска ссылок на старую сигнатуру метода чтобы её обновить. Другими словами, существуют нежелательные зависимости между страницами, связанными с операциями, и реализациями самих операций.

Конфликты команд разработчиков


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

Другой формой командных конфликтов могут быть "узкие места" в приложении - общие файлы или Java классы, которые нужно периодически обновлять Java разработчикам. Ключевой пример - это дескриптор деплоя (web.xml), который служит для описания маппингов сервлетов и URL'ов. Как только один разработчик добавит новый сервлет, файл должен быть изменён. Когда много разработчиков делают похожую работу, конфликты практически неизбежны.
Struts уменьшил уровень конкуренции для дескриптора деплоя, разрешив множественные конфигурационные файлы для хранения некоторой информации, но конфликтов и там полностью не избежать.

Плохие упрощения кода


Создание сервлетных приложений может порождать очень много кода, это может привести разработчиков к плохим упрощениям. Обычным примером является перенос кода для работы с БД прямо в JSP. Сперва это казалось хорошей идеей, т.к. при этом код работы с БД размещается в JSP, которая собственно выдаёт результат запроса от пользователя.
К сожалению, данный подход ведёт к страшным проблемам в работающих приложениях. Это делает JSP очень хрупкой перед лицом любого изменения модели данных. Запрос может просто выкинуть исключение в рантайме если таблица или колонка изменили имена. Маловероятно, что упрощения кода воспользуются преимуществом пулом соединений с БД, скорее напротив будут создавать, использовать и сами закрывать соединения. Это может быть нормальным во время тестирования, но это всё упадёт при высоких нагрузках от большого количества одновременных пользователей. Наконец, упрощённый подход, скорее всего, не будет использовать try ... finally блок для обеспечения закрытия всех соединений. Это может привести к утечкам соединений с БД.
Обычные упрощения кода следующие:
  • Нарушение надлежащего локализированного вывода в интернационализированных приложениях (включая отказ от использования локализированных форматов даты и чисел).
  • Не использование HttpServletRequest.encodeURL() для кодирования ID сессии в URL'е приложения, что ломает приложение для пользователей у которых не включены Cookie.
  • Ненадлежащая фильтрация вывода для конвертирования зарезервированных HTML символов (таких, как < и >) в HTML элементы (типа &lt; и &gt;) что приводит к странным визуальным эффектам в браузере клиента.
  • Использование коротких, неадекватных имён для атрибутов HttpServletRequest и HttpSession, ведущих к конфликту нотаций и перезаписыванию данных.
Есть ещё больше примеров, но они требуют гораздо больше контекста чтобы их полностью описать. Целью данной главы не было настроить вас против сервлетов - они мощный инструмент для создания web приложений. Напротив, мы хотим сфокусироваться на областях, в которых сервлеты требуют куда больших усилий или экспертизы для разработчика чтобы быть использованы эффективно, особенно в больших и сложных приложениях.

PS:
Хоть автор книги в итоге и смягчает критику в сторону сервлетов, но то количество проблем, которые нам приносит использование стандартных средств Java для создания web приложений, весьма настораживает. Да, многие фреймворки используют сервлеты и даже подобие JSP, но их использование сводится к минимуму. JSF или Tapestry предприняли весьма удачные попытки увести разработчиков от проблем, но уровень вхождения в данные фреймворки существенно выше, хоть в итоге мы и получаем больше профита, что даёт основания полагать, что для промышленных приложений они приспособлены куда лучше. Ну и проблемы, затронутые в статье, не являются полностью уникальными для веб разработки. Можно привести много аналогичных примеров слабого связывания и т.п., которые актуальны и для других классов приложений. В общем, Java Servlet'ы представляют собой куда более хорошее ядро для нормальных фреймворков нежели сами пригодны для серьёзного энтерпрайз девелопмента.





Комментариев нет:

Отправить комментарий