Python: Веб-разработка без фреймворков (ответ на критику)
Почти месяц назад в сети появился отзыв на эту серию статей, причем отзыв строго негативный. Я не придал этому значения, так как критика, на мой взгляд, оказалась направлена не на статьи, а на то, что автор в них увидел. Но, как выяснилось, мало кто расценил это так же. Дошло до того, что один мой знакомый, устраиваясь на работу, упомянул разработку напрямую для WSGI, на что ему незамедлительно подсунули тот отзыв как бесспорный аргумент против такого подхода. Так что, я думаю, нужно всё-таки ответить.
Комментарий Ивана Салагаева: Тут я хочу сказать, что от таких эффектов все равно нельзя защититься. Большинство людей любят не думать, что от чего зависит, а сразу ищут однозначных ответов. И уж тем более, если их пишет человек с авторитетом (который у меня, уж как получилось, есть). Моя статья, хоть и эмоционально написана, отвечает, как ты сам заметил, не конкретно на твой обзор WebOb, а использует его как повод для развития моей собственной точки зрения, которую я постарался обрисовать в начале. (WebOb важная часть, но статьи не только про него — примечание СЩ).
Недоразумения можно было бы избежать, если бы Иван прежде чем писать отзыв уточнил правильно ли он понял к чему я веду. Чтобы не повторить эту ошибку со своей стороны, я, как вы уже заметили, попросил его прокомментировать эту статью до её публикации.
Начать стоит, пожалуй, с того, что я не агитирую никого бросать их любимый фреймворк, не призываю писать свой собственный, я вообще ничего не предлагаю и не требую. Статьи описывают библиотеки, которыми пользуюсь я сам и приводят примеры как выглядит в результате код, не более того. Статьи не предназначены для новичков, для того чтобы эффективно писать код в том стиле, как делаю это я, необходимо хорошо понимать как работают все задействованные уровни включая HTTP протокол, сам стандарт WSGI, диспатчинг, шаблоны, используемый ORM и сама база данных, объяснить всё это я могу лишь отчасти. Пожалуй нелишним будет опыт разработки на нескольких существующих web-фреймворках. Я начал программировать для веб на Python шесть лет назад, и хотя были перерывы, имею солидный опыт использования самых разных фреймворков, поэтому не надо думать, что я пишу код таким способом из-за того что страшусь использовать существующие.
Велосипеды
Насколько я понимаю, основная претензия к описываемому подходу состоит в том, что якобы предлагается заново реализовывать тот самый код, который делает фреймворки раздутыми, либо же, что рано или поздно это придется сделать. На самом деле это не так.
Для того чтобы внести ясность попробую объяснить различие между фреймворком и библиотеками. Framework в переводе с английского это буквально каркас, т.е. ваш код является вторичным по отношению к библиотечному коду. Не вы выбираете где и что использовать, а расширяете и переопределяете уже имеющуюся функциональность. Более четким критерием отличия фреймворка будет повсеместное использования инверсии контроля, будь это декларативный код или callbacks[1].
Я исхожу из того, что этого нужно избегать насколько только возможно. Это вопрос личного предпочтения — если вам нравится писать код в колбеках, если это вам не мешает, то, вероятно, у нас совершенно разные стили программирования и мой опыт вам ни к чему. Если же вы улавливаете преимущества более свободного структурирования кода, то, возможно, программировать при помощи библиотек окажется удобней и продуктивней[2].
Таким образом, надеюсь, понятно, что я не считаю нужным переписывать уже реализованный функционал, но точно также я считаю неуместным раскорячивать свой код для того чтобы подстроиться под фреймворк. Цель этих статей — показать что в этом просто нет необходимости.
Если верить предположению Ивана, то у меня должен был бы образоваться собственный фреймворк, однако этого не произошло — помимо сторонних библиотек проекты повторно используют минимум кода, от силы наберется пару килобайт. Весь остальной код в проектах выполняет задачи специфичные для именно для них. Трудно поверить, но на самом деле меньше стало не только используемых библиотек, но и самого кода.
Также Иван предположил, что такой подход продиктован «чистотой» WSGI, но ничто не может быть дальше от правды. Как раз поиском решений для всего и сразу страдают фреймворки. Они часто исходят из какой-то идеологии (например MVC). Очень часто пытаются спрятать сложность веб-приложения за избранными абстракциями итд итп. Благодаря же WebOb получается укротить эту сложность, оставив притом всю доступную мощь на кончиках пальцев. Что приводит нас к следующему пункту.
«... в качестве клея компонентов... WSGI! Нет, серьезно — WSGI!!!»
Объясню, почему в статьях всё крутится вокруг WSGI. Поскольку я стараюсь максимально использовать существующие библиотеки, поскольку я стараюсь не терять возможностей на разных уровнях приложения, то я привязываюсь к WSGI. Если мы хотим использовать разные библиотеки совместно мы вынуждены использовать WSGI. Посмотрите на URLMap, посмотрите на различные middleware, без предоставления и использования WSGI они были бы невозможны. Из-за того что фреймворки идут другим путем и выбирают другую, предположительно лучшую, модель представления запросов и ответов именно для них так часто приходится изобретать велосипед, ведь нужно вписаться в идеологию фреймворка. В таких случаях обычно говорят о важности интеграции родных компонент и прочую лабуду, однако правда гораздо проще — просто приходится делать заново или что-то перекручивать[3].
Я знаю мнение PJE о том, что middleware злоупотребляют и я с ним полностью согласен. Ядро его недовольства он сформулировал так: «If your application requires that API to be present, then it’s not middleware any more!». Совершенно верно, однако есть ряд случаев когда middleware единственно верное решение, например paste.gzipper. Это те случаи когда оборачиваемые приложения не знают и не должны знать что они обернуты, к такому использованию прослоек претензий быть не может.
Не нужно думать что такие рассуждения идут вразрез с мейнстримом в веб-разработке. Дело лишь в том, что и распространенность поддержки WSGI и, скажем, выпуск WebOb произошли относительно недавно. Поэтому неизбежная инерция продолжает двигать разработку фреймворков — уже есть программисты с такими навыками, уже есть туча проектов требующих поддержки, кроме того всегда будет приток новичков для которых необходимо ограничивать сложность разработки (но ценой доступной мощности), также никуда не исчезнут желающие сделать лучше чем все предшественники. Также обратите внимание на возраст разных фреймворков, большинство уходит корнями в такую древность, что никаких WSGI, никаких вспомогательных библиотек просто не было. Более новые библиотеки зачастую были созданы с учетом ошибок и находок из фреймворков, с использованием современных средств языка и нет ничего странного что использовать их порой оказывается удобней.
Фреймворки были, есть и будут, это совершенно нормально. Более того, если вам они нравятся — пользуйтесь, если вы новичок — пользуйтесь итд. Моя задача лишь поделиться тем, что есть жизнь в веб-разработке и без них. На моем опыте выходит, что фреймворки неудобней на порядок. Пробовать применять мои рекомендации на опыте или нет в любом случае ваш выбор, но не надо спешить заочно утверждать что это ущербный подход.
Диспатчинг
Мне, без дураков, больше нравится писать серию if или, скажем return self.appmap.get(req.path_info_pop()). Если ваш пуризм (или менеджер проекта) требует чтобы это было сделано иначе — делайте, для этого, среди прочего, есть например Routes. Не нужно ни писать заново, ни платить цену использования фреймворка.
Вообще, многих программистов похоже пугает писать код, как только они пишут код приложения, они думают «О Боже! Почему этого не делает за меня фреймворк!?». Конечно, размышляя таким образом, получится, что диспатчинг вручную — зло, и срочно надо писать свою библиотеку или хвататься за готовую. Если же не спешить, и не побояться сделать самому решение именно имеющегося вопроса (подчеркиваю — не универсальное решение), то может оказаться, что паника была преждевременной, и кода вышло меньше, код вышел понятней, в будущем менять его проще. Так выходит у меня. Извините.
Остальное
«Что произойдет, если клиент пришлет невалидную utf-8 строку?» (см. третью статью в серии). Произойдет то что и должно произойти — клиент получит ошибку (нет, ничего не упадет, снова извините)[4]. Какие такие «ваши данные» выжмет Django из невалидной строки я не знаю, но мне такие и не надо. Может вам нравится иначе, но это, по крайней мере, соответствует PyZen и здравому смыслу.
Кстати, если посмотреть на The Zen of Python в целом (или его русский перевод), то почти по каждому пункту веб-фреймворки идут против него, такое моё мнение. Это не аргумент против, просто наблюдение[5].
- ^ ИС: Кстати... Джанго, как немногие знают, очень близко подходит к этой границе: в нем очень много просто библиотечного кода, который не является каркасом. Да, Джанго, несомненно фреймворк, потому что предоставляет архитектуру обработки запроса с разбором url’ов и вызовом пользовательской view. Но это, пожалуй, и все. Шаблоны, обработка форм, ORM — это фактически внешние библиотеки, которые пользователь зовет сам, и тогда, когда ему надо. Единственное, чем тут помогает Джанго — примерами в документации.
Тот же Pylons в этом смысле существенно глубже находится в зоне «фреймворк». - ^ Мне действительно нравятся те места, где Джанго строит «собственный путь» по той простой причине, что он совпадает с тем, что сделал бы я сам. А это значит, что он экономит мне время.
Но в целом, я полностью согласен с тем, что это вопрос личного стиля. - ^ А я тогда объясню, почему я так резко реагирую :-). Дело в том, что я удивительно часто встречаюсь с точкой зрения, что WSGI — это такая великая магия, и если на сайте фреймворка на первой странице написано это слово, то фреймворк автоматически считается дико гибким и мощным. Моя цель — объяснить, что WSGI — это простой протокол, который очень удобно использовать в качестве базы, но который сам по себе никакой архитектуры не строит. В WSGI нет, например, понятия каскада приложений. Его так использует тот же Paste, но это не само по себе происходит.
И снова, это я отвечаю не на то, что ты пишешь, а разъясняю, что имел в виду я сам. (С последним полностью согласен — СЩ) - ^ Тут под «упадет» я имел в виду не то, что приложение остановится на сервере. Я имел в виду как раз 500 ошибку. Это, я так понимаю, просто разница в жаргоне. (Насколько я понял, просто был выбран неудачный пример для критики — СЩ)
- ^ О, вот это точно флеймообразующий абзац :-).
9-й пункт в Дзен («Although practicality beats purity») дает возможность трактовать все что угодно как угодно :-). Поэтому я обычно на Дзен ссылаюсь только в шуточной манере. (А как же остальные пункты! — СЩ)
Все про українське ІТ в телеграмі — підписуйтеся на канал DOU
36 коментарів
Підписатись на коментаріВідписатись від коментарів Коментарі можуть залишати тільки користувачі з підтвердженими акаунтами.