С лупой на слона

в 14:34, , рубрики: Анализ и проектирование систем, былое и думы, всякое, Программирование, Разработка веб-сайтов, теория, метки:

Я довольно давно участвую в разработке web-приложений. Это не высоконагруженные приложения (типа Facebook или Gmail) — там, разумеется, своя специфика. Мои приложения были небольшими (можно было уместить на одном физическом сервере), но функционально насыщенными — финансовые, e-commerce. Я не работал в больших командах, зато пощупал весь спектр технологий, начиная от сборки аппаратуры в стойке и заканчивая редактированием CSS.

В какой-то момент поймал себя на мысли, что моя деятельность в области разработки web-приложений чем-то начала напоминать мне охоту моих далеких предков на мамонта (если под мамонтом подразумевать задачу, которую нужно решить). Только предки полагались на свою физическую силу, а мы вместо этого используем силу своего интеллекта. Но и как и прежде большую добычу не завалить в одиночку — нужны совместные усилия всех охотников.

image

Под катом я попытался собрать своё видение относительно наиболее важных с моей точки зрения аспектах в разработке web-приложений.

Адаптивность

image

Самый важный аспект, IMHO. Современные web-приложения должны эволюционировать в течение всей своей жизни, все время подстраиваясь под постоянно изменяющуюся окружающую среду. И не только внешний по отношению к web-приложению мир изменяется все время, но иногда web-приложения сами своим появлением изменяют окружающий мир. В web-разработке модель водопада уступила место спиральной модели не потому, что модель водопада плоха — она просто не поспевала за изменениями. “Водопад” и сейчас хорош для разработки приложений в некоторых других, не столь динамичных средах — например, ПО для марсианских зондов. В web-разработке же гораздо важнее сделать приложение, которое легко изменять, чем приложение, которое работает в соответствии с требованиями заказчика. Почему так?

Неопределенность

image

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

Practice makes perfect

image

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

Другими словами, стратегия “тяп-ляп — и в продакшн” может быть вполне оправдана, если в результате ее использования некоторый набор полезного функционала растет, а набор бесполезного, а то и откровенно вредного функционала наоборот — исчезает. Разумеется, "тяп-ляп стратегия" работает только для спиральной модели разработки и только для высоко адаптивных приложений. Поэтому web-приложение должно попадать в альфа-бета-гамма-… эксплуатацию как можно раньше, а цикл внесения изменений должен быть как можно короче.

Там на неведомых дорожках…

image

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

Как натоптать дорожки в продукте, в котором нет миллионов пользователей? Самим становиться такими пользователями. Это только хороший драгдилер не должен сам использовать то, что он продает. Хорошие разработчики просто “обязаны употреблять” свой продукт. И не только сами разработчики — члены их семей, друзья, знакомые, знакомые друзей и друзья знакомых. В общем, все, до кого можно дотянуться и у кого есть интернет, все должны принять участие в использовании создаваемого web-приложения с как можно более ранней стадии.

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

Обработка ошибок

Когда-то одним из признаков хорошего ПО являлось наличие “защиты от дурака”. Бытовало мнение, что любая последовательность нажатия клавиш на клавиатуре или одновременной нажатие любой их комбинации не должны приводить к аварийному завершению программы. В силу чего разработчику приходилось думать не только о том, как обрабатывать ожидаемые данные, но и о том, к чему приведет обработка неожиданных данных.

Сейчас web-приложения стали настолько многоуровневые, что можно уже не сильно заботиться о подобном аспекте. Я не имею в виду, что можно забить на SQL injection или на CSRF-атаки, я всего лишь имею в виду, что если при сохранении в базе данных о новом пользователе по каким-то причинам не поступила информация об обязательном email’е клиента, нет необходимости формировать user-friendly сообщение об ошибке — достаточно того исключения, которое выбросит среда исполнения (типа “Integrity constraint violation”).

Если приложение работает в ожидаемом окружении с ожидаемыми данными, то подобных ошибок не бывает. Ошибки возникают тогда, когда используются неожиданные данные или сложилось неожиданное окружение. В такой ситуации гораздо важнее как можно раньше отреагировать на неожиданные данные или неожиданное окружение и либо добавить валидацию входных данных (валидация — это бизнес-логика, а не обработка ошибок), либо ввести обработку неожиданного состояния, переведя его в разряд ожидаемых.

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

image

Максимальной задачей человека-пользователя является создание issue о “какой-то фигне, произошедшей при сохранении данных” с приложением скриншота и сообщения об ошибке. А лучше даже этого ему не доверять — web-приложение и само может рапортовать о неожиданной ситуации и создавать issues для человеков-разработчиков. Человек-пользователь будет даже благодарен, если увидит сообщение типа “произошла какая-то фигня, разработчикам сообщили, они уже работают, как поправят — стукнут по email’у, приносим свои извинения за неудобства”.

Для него гораздо важнее получить сообщение об исправлении мешающей ему ошибки через разумное время (минуты, часы, дни), чем подробное описание того, что именно произошло в приложении, и дружелюбное объяснение, почему именно его запрос не может быть обработан именно в данный момент. Разумеется, issues не должны стоять в очереди неделями или месяцами — если по каким-то причинам разработчикам не удалось подойти к проблеме в течение, допустим, полугода, то можно смело выбрасывать такую проблему — либо она уже неактуальна, либо повторится позднее (уже повторилась), создав новый issue на ту же тему (и не один).

Ориентированность на разработчика

image

Как я уже отметил, web-приложения должны быть адаптивными. Кто не успел измениться — вылетел из обоймы. Поэтому web-приложения должны быть ориентированы не на конечного пользователя, не на владельца бизнеса, web-приложения прежде всего должны быть ориентированы на разработчика (кто в этом не уверен — просто нажмите Ctrl+Shift+I).

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

Понятным код должен быть не только во время его написания, чтения, но и во время отладки, и во время тестирования. Это не только за минификацию/обфускацию/транспиляцию я сейчас говорю, но в том числе и за множество точек возврата в методе, и за текучий интерфейс, и за отсутствие ID у значимых элементов DOM’а. Все эти штучки весьма оживляют и без того занятный процесс отладки и тестирования кода.

Я разделяю понятия “программист” и “разработчик” — хороший программист не должен заниматься настройкой окружения для приложения, хороший программист не должен читать логи приложения и понимать, "почему в них написано именно то, что в них написано и откуда это могло взяться, если этого взяться ниоткуда не должно было", и хороший программист не обязан копаться отладчиком в дебрях написанного не им кода. Это все работа разработчика. Именно на него должно быть ориентировано web-приложение. Более того, оно должно быть ориентировано на

Посредственного разработчика

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

image

Web-приложение должно позволять модифицировать себя не только выпавшим из контекста разработчикам, но и тем, кто вообще не видит общего контекста задачи. Поэтому в помощь посредственному разработчику должно идти все — описание бизнес-функций в комментах кода, “говорящие” наименования для переменных/функций/классов, структурирование файлов проекта и структурирование кода в отдельном файле, использование возможностей IDE (inline documentation, autocomplete, hierarchy browsing), кросс-ссылки на связанные по контексту файлы (в том числе и для @deprecated аннотаций).

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

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

Модульность

image

Разбиение приложения на модули — это принцип, древний как мир. Декомпозиция позволяет ограничить контекст применения отдельного модуля (группы модулей), облегчая жизнь посредственному разработчику, и позволяя гениям строить более сложные программные комплексы. Каждое web-приложение, претендующее на звание сложного приложения, так или иначе состоит из модулей. Модуль — это и отдельная функция или замыкание (JS scope), и отдельный класс, и отдельный файл, и группа файлов с определенной структурой, и эта же группа файлов, закатанная в архив, и группа архивов.

Любое современное приложение (не только web) зависит от множества различных внешних зависимостей для работы с которыми придумано множество инструментов — rpm, dpkg, ant, maven, PEAR, composer, npm, requirejs, browserify. Возможно, когда-нибудь появятся репозитории и для web-модулей — компонентов для сборки web-приложений (плагинов/расширений, а не то, что имеет в виду java или requirejs). Пока же создание очередного web-приложения зачастую начинается с проектирования собственной структуры данных для аутентификации пользователей.

Тем не менее, используем ли мы сторонние модули в своем web-приложении или пишем свои — но наше приложение целиком и полностью состоит из модулей. И чем лучше у нас продумана структура модулей, тем более сложные приложения можно строить на их основе. Зачастую, для создания очень сложных композиций нужны очень простые, даже примитивные, правила — понятные не только посредственным разработчикам, а всем, кто так или иначе может поучаствовать в создании этой композиции. Например, двоичная система.

Муравейник

image

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

Эти правила могут быть оформлены в виде стандартов (ISO, RFC) или оформлены менее формально, или даже совсем неформально. Тем не менее именно эти правила позволяют разработчикам взаимодействовать друг с другом, строить свои проекты на базе других проектов (библиотеки, фреймворки), связывать одни проекты с другими проектами. Общее понимание правил делает возможным поддержку одними (администраторами) приложений, созданных другими (разработчиками). Даже использование приложений требует общего понимания базовых правил (кто пробовал открыть файл по Ctrl+O в IBM Visual Age, а?).

Современное web-приложение — это композиция усилий множества “муравьев”, большая часть из которых в глаза не бросается (начиная с двоичной системы и вплоть до браузера). Мы, пользователи, замечаем только конечные усилия конкретных разработчиков, реализаторов наших желаний. Мы, пользователи, зачастую хотим “нечто этакое”, совершенно не задумываясь о всем том стеке технологий, на котором базируется приложение, о том, что из нами перечисленного делается в два клика, а что — с перетряхиванием структур данных. Мы хотим то, чего нет у других, пусть и не прямо сейчас, но как можно скорее.

И как пользователи мы совершенно правы в своем нежелании погружаться в детали реализации, но вот как разработчики мы должны понимать не только весь стек используемых технологий, но и обеспечить его адаптацию под постоянные изменения желаний конечных пользователей (или представления заказчика web-приложения о таковых желаниях). Т.е., разработчики на вершине иерархии “муравейника” (возле конечного пользователя), должны не только использовать плоды труда своих коллег на более нижних уровнях, но и должны иметь возможность донести потребности пользователей (feedback) и внести свои коррективы в более нижние уровни.

Специализация, унификация, обобществление — вот те киты, которые, я надеюсь, когда-нибудь позволят создать для web-приложений модуль аутентификации, аналогичный утилите grep в nix-операционках, а создание web-приложений станет больше похожим на компоновку linux-дистрибутивов.

Обратная совместимость

image

А эта главка добавлена специально для будущих разработчиков Magento 3, ежели таковые вдруг объявятся. Требованию обратной совместимости зачастую должны удовлетворять все принятые решения по проекту. Это если и не Священный Грааль, то вполне себе даже “королевское” требование. Но… обратная совместимость — враг адаптивности. Поэтому коротко.

Резюме

Современное web-приложение:

  • изменяется столько, сколько существует;
  • является совокупностью усилий множества людей, даже если конечным разработчиком является один человек;
  • собирается из множества модулей, изрядная часть которых используется в других web-приложениях;
  • взаимодействует с другими web-приложениями по определенным правилам;
  • должно быть весьма дружелюбно не только к конечному пользователю, но и к своим разработчикам;
  • не обязано быть совместимым со своими предыдущими версиями (dependency managers в помощь, как говорится);

Спасибо тем, кто дочитал. Текущее мнение автора может не совпадать с вышеизложенным.

P.S. Почему "С лупой на слона"? Когда погружаешься в дебри кода, рассматриваешь "под увеличительным стеклом" причудливые изгибы реализации очередного "слона", так сразу и не поймешь, где ты находишься — в основании хобота или в основаниии хвоста.

Автор: flancer

Источник


* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js