Написать пост

Как разработать хорошее веб-приложение и избежать ошибок — отвечают эксперты

Аватар Никита Прияцелюк

Как писать веб-приложения, которые будут эффективны? Как выбрать подходящий фреймворк, ORM и т. д.? Что ещё нужно веб-приложению? Узнаем у экспертов.

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

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

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

В своей работе мы используем платформу собственной разработки BuroData Platform и следующий технологический стек:

  1. PHP позволяет нам в кратчайшие сроки разворачивать RESTful API и интегрироваться с API клиентов и других сервисов. Для написания сложных вычислений и выполнения высоконагруженных участков проекта используем компилируемый язык Go. Это позволяет гарантировать высокую устойчивость разрабатываемых систем.
  2. В качестве JS-библиотеки для разработки пользовательских интерфейсов используем React. Использование React позволяет в кратчайшие сроки вносить изменения, которые появляются в дизайн-системе проекта.
  3. Как основную базу данных используем PostgreSQL. Помимо высоких нагрузок, для которых данная БД используется, она позволяет хранить как структурированные объекты (стандартная реляционная БД), так и неструктурированные объекты в форматах JSON и JSONB, а также искать по ним, что позволяет более гибко подходить к выстраиванию архитектуры проектов.
  4. Для высоконагруженных систем используем Redis: это позволяет избежать сбоев от высоких нагрузок и вычислений при синхронизации между компонентами разрабатываемой нами системы и при интеграции со сторонними сервисами.
  5. В работе над проектами придерживаемся философии DevOps и принципа «инфраструктура как код» (IaC), что позволяет быть уверенным в стабильности поставляемого нами ПО.

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

Чтобы написать хорошее приложение, его надо написать. Буквально — в блокноте, в формате основных идей о том, как оно должно работать и из каких логических частей состоять. Это не про «контроллер берёт данные из модели и отправляет на отрисовку». Это про то, какие логические части есть в приложении и как они друг с другом общаются.

Не советую бездумно гнаться за всем «модным и молодёжным»: не можете объяснить, зачем вам GraphQL и какие у него преимущества перед простым REST API из трёх запросов, — не используйте. Кажется, это очевидно, но я сам не раз попадал в эту ловушку. Подход «открыть awesome-лист и поставить всё» тоже не лучшее решение: наличие огромного количества сторонних зависимостей не делает проект круче.

Вопрос «какой фреймворк/ОРМ/админку использовать» решается просто: выбирайте тот инструмент, который лучше всего знаете. Ничего не знаете и не умеете — берите то, с чем быстрее и проще разобраться, где меньше всего «уличной магии». Например, из списка Yii/Laravel/Symfony я выберу Laravel. Из админок выберу AdminLTE, потому что она «ну вроде норм и работает». Ни один из авторов этих проектов до сих пор не заплатил мне за рекламу.

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

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

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

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

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

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

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

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

Однако самой, наверное, неожиданной рекомендацией будет избегать любых сторонних библиотек и фреймворков всегда, когда это возможно. Это относится как к клиентской части приложения, так и к серверной. Приложение должно быть максимально компактным и потреблять минимальное количество ресурсов. Например, использование очень популярной библиотеки jQuery (или ей подобных) значительно замедляет работу клиентской части и требует немало ресурсов, что совершенно не обязательно. Абсолютно всё, что нужно, можно написать просто на JavaScript, а более быстрая загрузка и работа клиентской части будет высоко оценена заказчиком.

То же относится и к серверной части, а особенно к построению API для взаимодействия между ними. Для этой цели вполне достаточно использования устоявшихся протоколов CGI или WebSocket там, где это нужно. Различные фреймворки типа ORM несколько облегчают работу программиста ценой снижения эффективности приложения, да ещё и добавляют зависимость от этих библиотек и привносят в систему все их недоработки.

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

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

Существует множество способов разработки веб-приложения. Одним из самых современных считается реализация фронтенда как SPA (single page application), где взаимодействие с бэкендом происходит через REST API. Рассмотрим каждый из компонентов этой схемы детально.

Бэкенд

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

На каком языке реализовывать

Тут всё не так однозначно. Если не так важна производительность, то можно реализовывать на NodeJS (фреймворки ExpressJS, KoaJS, GatsbyJS), Python (фреймворки Django, Flask), Ruby (фреймворки Ruby on Rails, Grape). Если важна скорость — используйте Golang (фреймворки Gingonic, Beego, Revel). Думаю, самое верное решение — писать на том языке, который знаете. Мне, например, очень нравится Ruby и фреймворк Ruby on Rails.

Как реализовывать

Придерживайтесь паттерна MVC, и в какой-то момент вы заметите, что усложняется бизнес-логика. И дальше возникнет вопрос: где её реализовывать? В контроллерах или моделях? Один из наиболее простых и удобных способов — использовать интеракторы и презентеры.

Тестирование бэкенда

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

Сваггер

Представьте, что вы начали разрабатывать фронтенд. Как понять, какие параметры и запросы отправлять на сервер? Смотреть в код бэкенда? Согласитесь, не лучшее решение. Лучше добавить поддержку сваггера — в идеале, если сваггер поддерживает генерацию через тесты, он поможет документировать API.

Фронтенд

Тут всё не так просто, так как фреймворков очень много. Сейчас в основном используют AngularJS, ReactJS, VueJS. У каждого есть свои достоинства и недостатки. Я бы выбрал ReactJS: он достаточно простой и гибкий.

Тестирование фронтенда

Для фронтенда есть два основных типа тестов — тесты на логику и тесты на отображение. Первые проверяют логическую реализацию функций и классов. Тесты на отображение отвечают за то, чтобы контент демонстрировался пользователю в задуманном виде. Можно использовать следующие фреймворки: Mocha, Chai, Jest, Ava, Enzyme, Jest.

Отслеживание качества контента

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

Про контекст разработки

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

Соответственно, разработчик (и руководитель проекта, и владелец продукта, и конечный потребитель) должен с самого начала осознать — что и зачем.

Без ответов на эти вопросы приступать к разработке глупо.

Быстрые прототипы и мгновенная обратная связь с заказчиком

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

Тут хорошо показывают себя Ruby on Rails/Laravel/Nest.js/Django. Подобные вещи помогают сохранять высокий темп разработки. Иначе бизнес может поменять концепцию, сократить бюджет или даже закрыть проект. А участники разработки без очевидных результатов рискуют просто перегореть.

Про окружение

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

Сейчас верстка под разные экраны — самая незначительная забота. Мы живём в то время, когда уже нет той боли в эпоху IE6-7-8-9. Сегодня гораздо проще работать с интерфейсами, особенно с повсеместным переходом браузеров на WebKit.

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

Говоря о логике построения интерфейсов, стоит помнить, что несмотря на обилие различных фреймворков (Angular, React, Vue), предлагающих упростить разработку фронтенда, по неопытности строят монструозные системы, не думая, нужен ли этот код на странице. Страница оказывается перегружена, долго отрисовывается, плохо работает на мобильных устройствах. Как следствие, пользователи отказываются от приложения, бизнес теряет клиентов и деньги.

Помним про безопасность

Сегодня много спорят, как обмениваться данными — REST / SOAP / GraphQL — и при этом передают важную информацию в незашифрованном виде. Буквально недавно мы столкнулись с проектом, который получили на доработку, и обнаружили, что если в момент аутентификации отключить интернет, то приложение выдаёт ошибку «ERROR» и показывает пару логин/пароль.

Про декомпозицию

Если говорить об организации процессов, то всегда нужно иметь в виду, что должно быть продакшн-окружение и тестовое окружение, где можно все протестировать, проверить. И да, бэкапы нужны всего и всегда. Создание софта всегда следует декомпозировать на отдельные участки, на каждом выполняется своя работа — бэкенд, фронтенд, тестирование, не говоря про аналитиков, UX & UI designer, devops инженера.

Full-stack — это круто, но рискованно, использовать можно и нужно, но дозированно.  Фронт и бэк всё-таки стоит разделять, иначе люди быстро сгорают или темп проекта замедляется, особенно когда идёт работа над большим приложением.

Про важное

Не так важно, MVC или MVP.

Важно как можно быстрее добиться единого контекста всем участникам проекта: разработчикам, аналитикам, заказчикам.

Важно говорить на одном внятном языке.

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

Важно знать свои инструменты.

Изолируйте, что можете. Поверьте, будет меньше боли.

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

Помните про 12 факторов

Всё, что я рассказал, и даже больше содержатся в принципах 12-факторного приложения — открытой методике создания веб-сервисов, которая содержит общие декларации разработки софта, вне зависимости от платформы, языка разработки, назначения и т.п. Эти 12 факторов и есть 12 правил правильного написания приложений.

К сожалению, вот эти 12 факторов чаще всего открывают для себя на позиции middle/senior, когда уже обжигаются на ошибках, которых можно было бы избежать. Используйте это как направляющую в любых проектах!

Общий облик современного веб-приложения, как правило, определяется полным разделением между клиентом и сервером. Каждая из сторон для другой является «черным ящиком». Сервер ничего не знает про внутреннее устройство клиентов, а клиенты — про устройство сервера. Кроме того, веб-приложение может быть не единственным клиентом. API стоит проектировать так, чтобы его можно было использовать без изменений на любой платформе — веб, мобильные и десктопные приложения.

В качестве слоя API используется REST с рассылкой уведомлений через WebSocket. REST применяется почти повсеместно, мало в каких проектах найдутся причины для использования других подходов. WebSocket важны, потому что без них не удастся сделать «живой» интерфейс с мгновенным обновлением информации. Несмотря на высокий интерес сообщества к GraphQL, для большинства проектов плюсы этой технологии не перевесят минусов.

Хорошей практикой является делать API версионируемым и использовать автоматически сгенерированную документацию для его описания.

Дизайн бекенда чаще всего продиктован сложностью разрабатываемых веб-приложений и объемом необходимых API.

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

Такой подход повышает гибкость в разработке:

  • Нет нужды привязываться к одному языку программирования или к одному технологическому стеку. Например, одни сервисы могут быть разработаны на Java с использованием реляционных баз данных и ORM, другие на NodeJS с различными NoSQL базами («ключ-значение», «документная», «графовая»), третьи на Golang.
  • Большие приложения cмогут продолжать работать даже при отказе одного из сервисов.
  • При возрастании нагрузки можно масштабировать только те сервисы, на которые данная нагрузка ложится в большей степени. Это позволяет экономнее расходовать ресурсы оборудования.

При всех плюсах у микросервисного подхода есть и минусы:

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

На стороне фронтенда стандартом де-факто является Single Page Application. Если работа на мобильных устройствах является приоритетной, стоит подумать и о реализации подхода Progressive Web App.

Пользовательский интерфейс эффективнее всего писать в декларативном стиле. Лучше всего с этой задачей справляется React. Vue и Angular используют тот же подход, но их популярность несколько ниже.

В приложениях, где востребован Sever Side Rendering, имеет смысл закладывать его поддержку как можно раньше. Добавлять её потом будет сложнее и болезненнее, чем сразу сделать правильно.

Если ваша компания работает с большим количеством веб-приложений, то имеет смысл создать собственный UI kit и обеспечить повторное использование компонентов. По нашему опыту, в достижении этой цели помогает использование Storybook, который служит «витриной компонентов» и предоставляет окружение для их разработки и тестирования.

Итак, как подойти к разработке веб-приложений?

  • Не спешите писать код. Сначала обдумайте архитектуру приложения, подумайте, что будет с продуктом через год-два после создания, заложите масштабируемость, гибкость и т. д.;
  • Не стремитесь использовать новые технологии, о которых все говорят. Вы всю жизнь писали на REST и вдруг решили, что вам нужен GraphQL? Сначала ответьте себе, какие у него преимущества перед привычным вам подходом и не перевешивают ли они недостатки. То же касается и других технологий;
  • Не забывайте про безопасность. Можно долго выбирать, как передавать данные — с помощью REST или GraphQL — но какая разница, если они будут передаваться по HTTP?
  • Создавайте прототипы, чтобы быстро видеть результат своих действий и как можно скорее получать обратную связь от заказчика/пользователя;
  • Стоите перед выбором фреймворка? Выбирайте то, на чём лучше умеете писать и что лучше подходит под вашу задачу. Ни на чём не умеете? Тогда выберите что-то, в чём проще и быстрее разобраться;
  • Пишите тесты, чтобы быть уверенным в том, что у вас всё работает как надо и очередная фича не стала багом;
  • Логируйте работу системы, чтобы потом было проще разобраться в причине неполадок;
  • Подумайте об уменьшении количества сторонних зависимостей и попробуйте реализовать нужную функциональность сами. Да, это, скорее всего, займёт больше времени, зато вам не будет мешать никакая сторонняя «магия», и вы будете лучше ориентироваться в коде;
  • Прочитайте о 12-факторном приложении. Это что-то вроде набора методологий по созданию веб-приложений.

Напоминаем, что вы можете задать свой вопрос экспертам, а мы соберём на него ответы, если он окажется интересным. Вопросы, которые уже задавались, можно найти в списке выпусков рубрики. Если вы хотите присоединиться к числу экспертов и прислать ответ от вашей компании или лично от вас, то пишите на experts@tproger.ru, мы расскажем, как это сделать.

Следите за новыми постами
Следите за новыми постами по любимым темам
18К открытий18К показов