Современная веб-разработка: выбери себе приключение +40


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


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


upd — немного дополнил текст до ката.



От идеи до прототипа


Предположим, что я и мой друг Валерка решили сделать стартап. Uber for X, или там еще что-нибудь в таком духе. Собрались в баре, обсудили эту идею, клёвая тема. Надо сделать. Три месяца не спали, не ели, не выходили из дома. Разрабатывали. Запустили и поняли, что это никому не нужно.


Печаль. Попробуем еще раз. На этот раз мы изучили рынок, посмотрели, какие потребности у пользователей, какие проблемы. Мы сделали какой-то прототип совсем на коленке, быстро и бесплатно за два вечера. Прототип взлетел. Круто, идем дальше.


Выбираем технологии


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


Язык


По порядку. На каком языке писать? Можно взять модный функциональный: Haskell, Erlang, Lisp (очень модный среди дедушек старше 70). Либо очередного убийцу JS, который очень клевый, компилируется в JS, имеет все нужные фичи. Но скорее всего, нам некого будет нанимать через год, потому что очередной убийца JS не взлетит, и придется переучиваться заново или переписывать проект.


Попытка номер два. Можно взять что-нибудь проверенное временем. Например, PHP. Это неплохой язык, его модно иногда критиковать, у него есть свои минусы, но на нем легко делать бизнес-логику, он достаточно быстрый, неплохо масштабируется, можно нанять людей когда угодно и где угодно. Но он не очень производительный. Поэтому нам нужно либо много железа, либо писать свой компилятор, как сделали Facebook или ВК.


Еще варианты? Можно взять Perl, но тогда будет некого нанимать ещё вчера. Ещё?
Java. Java — норм. Как язык не очень, на мой субъективный взгляд, но JVM — отличная виртуальная машина, все ок, быстро работает, но железа все равно нужно много. А ещё пока мы на Java писали абстрактный билдер фабрики стратегий вместо того, чтобы делать фичи, пользователи ушли к конкурентам.


Ладно, у нас есть еще Python. В принципе, у него всё ок. Но мы запускаем приложение на Python, оно использует одно ядро из 56, в остальном… все ок. Либо можно взять что-то современное: Go, Rust, еще что-то. Но они слишком низкоуровневые, и мы просто долго делаем фичи… Какой-нибудь язык нам всё равно придется выбрать. Пусть в итоге это будет JS, сойдет.



База данных


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


Ок, давайте возьмем реляционную базу. MySQL, PostgreSQL, или Oracle, если денег хватит. С реляционными базами можно однажды прийти на работу и обнаружить себя в аду из транзакций и хранимок. Это не обязательно произойдёт с нашим проектом. Но если произойдет, то эти хитросплетения логики будет невозможно тестировать. А ещё если вдруг мы достигнем вертикального предела нашего большого золотого сервера, на котором мы хостим базу, потом будет довольно сложно их разделять. Долго делаем фичи.


Ладно. Базу взяли какую-нибудь, бахнули перед ней ORM, чтобы проще было с одного SQL на другой переезжать. Когда-нибудь (spoiler: никогда).



Архитектура


Какую взять архитектуру? Ребята на Хабре пишут, что микросервисы – это клёво. Олег Бунин говорит: «берите микросервисы».


Если начать с микросервисов, то с восьмидесятипроцентной вероятностью границы у них будут неправильные, потому что не до конца продумали доменную модель и плохо поняли, где надо резать, а где не надо. Плюс все берут микросервисы, деплоят их пачками по всему своему кластеру, и через месяц возникает вопрос: «а как это всё теперь тестировать?». Сервисы уже работают в продакшене, а мы их не тестируем. Используя привычные методологии (пирамида тестирования, ручные интеграционные тесты, end-to-end тесты), тестировать микросервисы сложно. Поэтому мы долго делаем фичи.


Ок, тогда давайте бахнем монолит. Это самая правильная идея для стартапа. Очень долго можно жить с отличным монолитом и не иметь проблем. Но если мы решим сильно расширить команду, то надо быть осторожнее. Монолит нормально масштабируется, пока разработчиков 20, 30, 50. Дальше скорость доставки фич падает экспоненциально, а мы теряем пользователей.



Где запускать проект?


Это всё надо где-то запускать. 2018 год, самый логичный вариант сделать это в облаке. Запустишь не в облаке — пацаны засмеют. Но, во-первых, есть федеральный закон 152, значительно ограничивающий выбор облачных провайдеров, у которых можно хоститься. Во-вторых, очень легко приватный ключ от своего аккаунта на Amazon случайно закоммитить в Github, и кто-то обязательно придёт и потратит все ваши деньги. А если этого не произойдёт, то в какой-то момент вас разорят облачные тарифы.


Можно арендовать дата-центр. Может, это не так ресурсоэффективно изначально, но в долгосрочной перспективе, вероятно, обойдётся дешевле, чем хоститься в облаке. Но тут нужны люди, которые это будут поддерживать. По моему опыту, те, кто это любят и умеют делать, не очень любят общаться со всеми остальными, поэтому они организуются в отдел. А отдел – это сепаратизм. Я имею в виду то, что внутри команды админов будет легче обмениваться опытом, но в будущем это может работать не очень хорошо. Будут вопросы с приоритезацией задач от других коллег, с синхронизацией. Другие специалисты не будут знать, что происходит внутри отдела, который поддерживает наш дата-центр.
В общем, сепаратизм нам не подходит. Логично переходим к вопросу набора команды.


Команда


Разработка


Допустим, мы разобрались с языками, базами и тем, где хостить проект. Настало время набирать команду. Можно взять несколько очень крутых ребят, которые все проблемы решат: стократные разработчики, бэкенд-ниндзи, вы понимаете. Возможно, это прокатит. Но на деле вероятно, что приглашённые звёзды будут:


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

В итоге… да-да, долго делаем фичи. Еще вариант — взять обычных девчонок и ребят, которые просто будут писать код, делать фичи нормально. Но если взять много не очень опытных разработчиков с разным бэкграундом, они могут писать код в разном стиле, делать штуки по-разному, и при достаточном размере команды всем будет тесно, все будут у друг друга фигурные скобочки переставлять в пуллреквестах. Это не очень эффективно. Как это можно решить? Начальник может читать весь код. Я могу читать все пуллреквесты, а мой друг и ко-фаундер Валерка потом второй раз будет перечитывать (на всякий случай, мало ли). Понятно, это не масштабируется и все медленно делают фичи.


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



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


Quality Assurance


Можно сказать, что QA-специалисты нам не нужны. Многие так делают, это иногда работает. Но не все разработчики любят писать тесты. Их можно понять. И стоит их лучше мотивировать, чтобы тесты все-таки писали, но реальность жестока: unit-тесты ловят далеко не все баги. А если какой-то разработчик не любит писать тесты и все-таки начал их писать, то скорее всего это будут unit-тесты.


Плюс еще есть подходы, когда ты минимизируешь mean time between failures вместо mean time to recover. Mean time between failures — это когда QA специалист говорит: «не будем релизить, у меня чутье плохое, баги будут, давайте через две недели выкатим». А mean time to recover — это когда вы катите что-нибудь, сразу видите на метриках, что что-то сломалось, и через две минуты все откатили, пофиксили и все ок. Но чтобы можно было проект через две минуты откатить, надо всё покрыть нормальными метриками, а это не всегда тривиально. А если метрики в плачевном состоянии, и мы выкатим плохой релиз, мы можем узнать об этом после того, как все пользователи уйдут от нас к конкурентам.


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


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


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



Итоги


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


А ещё — всё это интересно. Интересно решать проблемы, которые уже кто-то решал, новые проблемы еще интереснее решать. Интересно делиться знаниями.




К сожалению, не доступен сервер mySQL