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

Анти-паттерн 1: «Потом допилим» — откладывать безопасность на потом

Первая история — про админку для небольшого интернет-магазина одежды. Клиент пришёл с запросом: «У нас на сайте полсотни заказов в день, нам нужна админка, чтобы менеджер видел заказы, менял статусы и выгружал в excel. К запуску через три недели, бюджет — столько-то, давайте без излишеств».

Я знала, как должна выглядеть правильная админка: bcrypt для паролей, JWT с коротким сроком жизни и обновляемые токены, защита от CSRF, rate limiting на API, secure cookies с флагами HttpOnly и SameSite, логирование подозрительной активности, регрессионные тесты на авторизацию. Это две с половиной — три недели работы. У меня было три недели. Но на эти три недели приходился еще один мой проект, налоговая отчётность и больничный ребёнка, и я была уверена, что уж как-нибудь выкручусь.

На второй неделе я согласилась на компромисс с собой: «Сделаю MVP с базовой авторизацией — логин-пароль через сессии, без JWT, без обновляемых токенов, без rate limiting. CSRF пока пропущу, потом допилим». Я записала себе в задачник «Добавить CSRF, rate limit, secure cookies» и выкатила MVP. Клиент был доволен, я получила оплату. Проект закрыли.

Через два месяца клиент вернулся. Оказалось, бот начал перебирать пароли — а у меня не было rate limiting. Сессии не истекали — я не настроила короткий TTL для cookie. Бот за ночь подобрал пароль менеджера (qwe12345 — это была их корпоративная норма), получил доступ к заказам, экспортировал базу с телефонами и адресами клиентов и попытался продать её в даркнете. Клиент узнал обо всём, когда ему позвонил один из покупателей с вопросом «а почему вы мне пишете с нового номера, хотя я у вас ничего не заказывал».

Я потратила четыре дня на авральный патч: добавила rate limiting, заставила сменить пароли, переписала сессии на JWT с refresh, добавила CSRF. Сделала я это за свой счёт, потому что формально была виновата. По деньгам вышло в ноль, по репутации — в минус. Анти-паттерн «потом допилим» — это не про «я ленюсь». Это про «у меня сейчас нет времени, но я обещаю себе, что вернусь». Не возвращаются. Через месяц у тебя другой проект, и технический долг этого MVP лежит, пока не взорвётся.

Анти-паттерн 2: «Это маленький проект, зачем перестраховываться»

Вторая история — про лендинг для услуги репетитора по математике. Задача простая: одна страница, форма заявки, оплата через ЮMoney, страница спасибо. Бюджет маленький, срок — десять дней. Я подумала: «Это же лендинг, тут нет смысла городить серверную валидацию, защиту от инъекций в sql-запросах, нормальную обработку ошибок. Сделаю простую форму, отправлю на почту, и всё».

Я не учла одного: на лендинге репетитора указывается вполне реальный email преподавателя и форма обратной связи. Если в форме нет серверной валидации и капчи, бот её заполнит. Если бот её заполнит — он подставит в поле «сообщение» ссылку на фишинговый сайт. Если у репетитора стоит автоответчик на почту, который пересылает письмо в WhatsApp — бот получит доступ к WhatsApp репетитора. Так и случилось. Бот пробился через форму, загнал в сообщение ссылку на «скачать пробный урок бесплатно», автоответчик переслал это репетитору, репетитор кликнул — а это был фишинг, который собрал данные его почты.

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

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

Анти-паттерн 3: «Скажу, когда будет видно» — молчать о рисках, пока не поздно

Третья история — про корпоративный сайт для средней региональной компании. Клиент хотел красивый сайт с интеграцией с 1С, личным кабинетом для дилеров и блогом для SEO. Срок — полтора месяца, бюджет средний. Я знала, что интеграция с 1С у региональной компании — это минимум 2 недели на переговоры с их айтишником, разбор форматов обмена, тестирование на их стороне. Но не сказала об этом на старте — подумала, разберёмся по ходу.

Через месяц работы, когда дизайн был готов, контент написан, личный кабинет наполовину сделан, я узнала, что у клиента нет API для интеграции с 1С — только выгрузка в excel раз в сутки. Айтишник клиента сказал: «Сделайте, чтобы кнопка тянула эту выгрузку и парсила». Это технически возможно, но это костыль, который сломается при любом изменении формата у 1С. Я сказала об этом клиенту. Клиент сказал: «Нам нужна автоматизация, сделайте». Я сделала. Через два месяца 1С обновилась, формат выгрузки поменялся, скрипт сломался, кабинет дилеров показывал пустые остатки. Клиент в панике, дилеры звонят, я разгребаю аврально за свой счёт.

Анти-паттерн «скажу, когда будет видно» — это про то, что я боялась поднять сложную тему на старте, чтобы не напугать клиента. Сейчас я понимаю: поднять тему на старте — это не напугать. Это показать экспертизу. Если бы я сразу на этапе оценки сказала «у вас нет API для 1С, давайте выберем один из трёх вариантов: либо вы договариваетесь с айтишником, либо мы делаем выгрузку ручную, либо мы делаем интеграцию через их облако за дополнительные деньги», клиент бы выбрал один из вариантов. И никакой авральной ситуации через три месяца бы не было.

Три правила, которые я держу в голове до старта каждого проекта

Из этих трёх историй у меня вырисовались три правила. Не теоретические — практические, написанные на стикерах и приклеенные к монитору. Они звучат просто, но я до сих пор ловлю себя на том, что хочу их нарушить.

Первое — «Безопасность в MVP, а не после». Если в проекте есть пользовательский ввод, авторизация, оплата, любая работа с чужими данными — базовая защита (валидация, санитизация, rate limiting, защита от типовых атак) идёт в первую очередь, до фич. Не после, не параллельно, не «потом». Это занимает 10-15 процентов от общей оценки, но без этого всё остальное — карточный домик. Я закладываю эти 10-15 процентов в смету отдельной строкой и в комментарии к заказу пишу, что это значит. Клиент видит и принимает, либо отказывается от проекта — оба варианта лучше, чем авральный патч через два месяца.

Второе — «Размер не отменяет базовых шагов». Лендинг на одну страницу, сайт-визитка, корпоративный блог — везде, где есть форма, есть почта, есть хоть какое-то взаимодействие с пользователем, есть риск. Стоимость базовой защиты для маленького проекта — 3-5 тысяч рублей и 4-6 часов работы. Это не те деньги, которые стоит экономить, и не то время, которое стоит сокращать. Я убрала из своего каталога услугу «сделаю лендинг за 2 дня» — теперь минимальный срок — 5 дней, и в них входит базовая защита и тестирование.

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

Чек-лист: что НЕ делать, когда срок — вчера

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

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

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