Как из джуниора дойти до мидла, а потом и до синьора. Я – Кирилл Мокевнин, разработчик и сооснователь школы программирования Хекслет. В IT с 2007, работал в Skype и undev, управлял командами из 50+ разработчиков.
Знаю практически все о найме, обучении и карьерном росте программистов. Расскажу, как пробить карьерный потолок и взять максимум от работы в IT. Амбассадор организованного программирования, учу эффективно создавать системы и эксплуатировать их
Организованное программирование | Кирилл Мокевнин
Переключение контекста в программировании. Работать только над фичами утомляет и в течение дня иногда хочется переключиться или просто голова не особо варит, а делать полезное хочется. Куда и как можно переключиться? Вот что работает в моем случае. Для начала, какие типы задач я выделяю (в моей практике):
- UX/UI. Дизайн, удобство, отзывчивость и любые фронтовые правки
- Обновление зависимостей (люблю я это дело)
- Типизация. Добавление типов (нам в ruby актуально), оптимизация типов и т.п.
- DX. Тут и скорость работы инструментов (сборка, тесты и т.п.) и CI и разворачивание проекта
- Kubernetes. Сам по себе отдельно, как инфраструктурная единица
- Инфраструктура. Сюда относятся облака, хостинги и terraform для этого добра
- Покрытие и тесты. Тесты всегда можно дописать
- Массовые тупые рефакторинги. Когда надо бы поправить весь код, но обычно не доходили руки, а тут ИИ, который может сам если его попросить
- Посидеть над беклогом и поотвечать в тикетах :)
Я четко делю эти задачи не только потому что они живут в своем скоупе, а именно потому что переключение с одного типа на другой позволяет мне переключиться и расслабиться. Например я регулярно занимаюсь DX и делаю это когда нет сил. Сейчас к этому еще подключилось регулярное добавление типов. Ну и фронтенд из такого, что прямо доставляет удовольствие. Остальное в меньшей степени, хотя было время, когда я часто переключался на devops задачи. Думаю современная автоматизация привела к тому, что интерес к этому поугас, но если надо, то без проблем.
А у вас какие фишки для переключения в разработке?
2 days ago | [YT] | 38
View 4 replies
Организованное программирование | Кирилл Мокевнин
Иификация. Чем дальше, тем больше ии интегрируется в мой процесс разработки и уже появился какой-то набор паттернов, которыми я бы хотел поделиться. В этом посте поделюсь сетапом, а в будущих уже расскажу подробнее про эффективное использование
1. chatgpt всегда остается когда надо просто поговорить. Причем сейчас он может работать в агентском режиме, к нему можно подключить репозитории и всякое другое
2. Для работы над кодом codex и copilot в терминале отдельно от редактора.
3. В редакторе автокомплит + nes (next edit suggestion). Тут есть небольшое ограничение самого nvim, которое не позволяет делать многострочные nes, но это поправят буквально в следующей версии, которую я очень жду
4. Немного экспериментирую с автоматическими пулреквестами copilot и даже парочку принял. Но чего-то серьезного там не сделать без постоянного контроля и направления, поэтому пока отложил до лучших времен
Почему именно так? Несмотря на наличие чата в редакторе или консоли, chatgpt нужен для разного рода мелких отвлечений чтобы не сбивать контекст. По ходу решения задачи бывает нужно куда-то отвлечься, что-то вспомнил и хочу посмотреть. Если это делать в рамках кодинговой сессии, то можно легко запутать машину и уйти не туда. Поэтому я четко делю, чат во время разработки это фокус на задаче, все сайд истории в chatgpt.
Я пробовал пользоваться чатом в стиле курсора прямо внутри редактора, но отказался от этой идеи. В моем флоу есть две ветки. Я что-то делаю сам в редакторе и на фоне один или два (но не больше) процесса работают над кодом. Если использовать чат в редакторе в режиме работы над кодом, то он программировать одновременно с ним не получится, он банально и место занимает и изменения прямо тут делает.
Что касается автокомплита, то к нему конечно надо привыкать и не жать его сразу, потому что часто не та логика. Но правильной логики достаточно много, чтобы не хотеть вырубать этот механизм. Особенно когда речь идет про использование каких-то библиотечных механизмов, которые надо изучать, чтобы правильно использовать. А тут тебе уже сразу дают варианты использования. Ну и собственный код тоже неплохо помогает дописывать, особенно если он типизирован. То есть чем ближе к строгости и простоте, тем лучше подсказки. Вангую что для go это вообще работает все идеально. Очень круто в джаве и ts. В Ruby хуже, но после того как мы начали активно внедрять типизацию с Sorbet, то качество подсказок резко выросло, да и работать стало сильно приятнее.
Ну и NES. Что-то подобное еще до ИИ делали IDE от JetBrains, они пытались угадать следующие изменения и предлагали их, даже если по коду прямой связи не было, например могли подсказать что надо поменять название теста. Сейчас же, все эти штуки, причем универсально, а не под конкретные кейсы, делает NES (что кстати значительно приближает редакторы к платным фичам jetbrains). Меняешь что-то, что не делается стандартным рефакторингом, а оно уже говорит тебе что может поменять все остальные варианты. Эта фича, конечно, прорыв в области работы с кодом. Есть тут свои конечно особенности с тем как она возникает и иногда мешает, но думаю доведут до ума и руки перестроятся. Без нее уже не могу работать.
Ну и непосредственно кодинг в консоли. Кодекс развивается семимильными шагами, как консольная утилита, его интерфейс и возможности на голову выше чем у стандартного copilot. Например сейчас появилась возможность запускать что-то в бекграунде, а это позволяет стартовать сервисы прямо внутри, чтобы иметь прямой доступ к логам (если они идут в stdout) и ошибкам старта. Значительный буст в качестве дало подключение devtools mcp, фронтенд просто стал щелкаться как орехи там где мне не хватало знаний верстки. Если прямо сейчас идет какая-то работа, то codex не блокирует ввод, ему можно накидать каких-то дополнений и уточнений. И такого разного ux удобного там много.
p.s. А какой у вас сетап?
Ссылки: Телеграм: t.me/orgprog | Youtube: youtube.com/@mokevnin | VK: vk.com/orgprog
2 days ago | [YT] | 28
View 6 replies
Организованное программирование | Кирилл Мокевнин
Традиционные результаты года
Нас стало больше, мы больше комментировали, больше делились и реагировали. При том что постов было меньше, так как я весь этот год провел в безудержном программинге. Время на посты было меньше чем обычно.
Я бесконечно рад огромным обсуждениям на сотню другую комментариев под многими постами. Спасибо вам за это и давайте продолжать в том же духе :)
Кстати, если вы хотите поообщаться про рост каналов и выстраивание личного бренда, в клубе есть спец чат для этого, где я с удовольствием делюсь и рассказываю разные фишки. Так что заходите если еще нет!
Всем чмоки, увидимся в следующем году (а завтра я уже записываю новый выпуск для подкаста)
p.s. Если у вас есть истории про то, как канал повлиял на ваши убеждения/код который вы пишите/подходы которые вы используете, то было бы классно -) Поделитесь плс
1 week ago | [YT] | 34
View 2 replies
Организованное программирование | Кирилл Мокевнин
Что означает "порт занят"?
Я как-то совсем стороной обходил все что касается операционок, администрирования и девопса, хотя сказать есть что. Особенно в свете последних собеседований 🙂 Открою эту рубрику постом про занятые порты.
На моих собесах мы разворачиваем приложение и делаем что-то полезное в нем. Во время старта приложения поднимается база, веб-сервер, фронт и что-то еще по мелочи, вполне типовой набор для веб проекта. И вот тут, с вероятностью 50 на 50, падает с ошибкой:
Error: bind() to port 5432 failed: Address already in use
Что я заметил. Даже если эта строчка есть в выводе, многие ее как будто не замечают. Возможно это потому что нет понимания проблематики и человек автоматически ее игнорирует. Даже если так, то имеет смысл приучить себя после падения брать весь трейс и кидать его ии с вопросом "почему упало?". А упало потому что порт уже занят. Давайте немного теории, для понимания происходящего.
Такие штуки как базы данных, веб-серверы и любые другие серверные приложения должны уметь принимать внешние соединения. Для этого в операционных системах существует базовая концепция - сетевые сокетыю Сокет — это точка входа, через которую процесс может принимать и отправлять сетевые данные.
Когда серверное приложение стартует, оно создаёт сокет и привязывает его к конкретному порту (и ip). Этим оно сообщает операционной системе: «все соединения, пришедшие на этот порт, передавай мне». Если в этот момент порт уже занят другим процессом, операционная система не может создать второй сокет на тот же порт и возвращает ошибку Address already in use.
С этим разобрались. Что теперь делать?
Если мы точно знаем что там запущено и нам надо чтобы работали обе программы, то нужно разносить их по разным портам. Смотрим как поменять порт и стартуем на другом. Главное потом не забыть поправить клиентов, которые будут стучаться не туда если поменять порт.
Если для нас это сюрприз, то для начала надо посмотреть, а что там вообще запущено? Есть много способов, самый простой и универсальный:
lsof -i :5432 # может понадобиться sudo
com.docke 1682 user 241u IPv6 0x6373ba4a2a38037e 0t0 TCP *:postgresql (LISTEN)
Видим, что порт держит процесс с PID 1682. Возникает логичный вопрос: просто убить его через kill? Это почти всегда неправильный ответ. В реальных системах серверные приложения обычно запущены не вручную, а как сервисы. Это означает, что процесс был стартован менеджером сервисов, может автоматически перезапускаться, и его нужно останавливать тем же способом, каким он был запущен.
Для начала имеет смысл посмотреть, как именно был запущен процесс. Это можно сделать через ps -fp 1682. Если в команде запуска видно что-то вроде postgres, redis, nginx и так далее, то с большой вероятностью это сервис, а не разовый процесс.
На Linux такие вещи чаще всего управляются через systemd. В этом случае имеет смысл проверить статус сервиса, например systemctl status postgresql, и остановить его корректно командой sudo systemctl stop postgresql.
На маке серверные приложения часто ставят через Homebrew. Там можно посмотреть список сервисов командой brew services list, а затем остановить нужный сервис через brew services stop postgresql.
Смысл в том, что kill это аварийная мера. Она не отключает автозапуск и не меняет состояние сервиса, поэтому процесс может тут же подняться снова. Если порт занят и вы не запускали процесс вручную, почти всегда правильный путь это найти сервис и остановить его через менеджер сервисов.
У меня был собес, на котором кандидат килял процесс, пытался запустить приложение и порт снова был занят. Он довольно долго пытался повторить это пока я ему не подсказал что происходит.
p.s. Ребят нужен такой контент (лайкните если да)? Я знаю что для многих это довольно базовый уровень, но с другой стороны, немало и тех, кто с операционками на вы.
Ссылки: Телеграм: t.me/orgprog | Youtube: youtube.com/@mokevnin | VK: vk.com/orgprog
1 week ago | [YT] | 106
View 11 replies
Организованное программирование | Кирилл Мокевнин
Если вы еще не подрубили chrome mcp (github.com/ChromeDevTools/chrome-devtools-mcp) к своему проекту, то самое время это сделать. С его помощью я тут же смог решить несколько задач по верстке, которые раньше мне не поддавались из-за того, что я местами плаваю в ней + требовался глубокий дебаг включающий в себя и верстку и react и конкретно компоненты Mantine. Теперь эта штука имея полный доступ ко всему творит просто чудеса. Я в шоке.
Выглядит так, оно прямо запускает браузер и на глазах анализирует страницу. Главное чтобы был запущен веб-сервер
Ссылки: Телеграм: t.me/orgprog | Youtube: youtube.com/@mokevnin | VK: vk.com/orgprog
2 weeks ago | [YT] | 101
View 6 replies
Организованное программирование | Кирилл Мокевнин
Как я потерял 5000$ на авиабилетах
У нас были большие планы на это лето. Мы собирались полететь в европу, чтобы по полной программе оторваться. Снять машину и пару месяцев кататься по разным странам. В целом, выбраться у нас туда получалось каждый год, но мест где мы еще не были все равно много.
Короче закатали рукава и начали процесс оформления визы в испанию. В майами это самый ходовой путь получать туристическую визу в европу. Тем более это был не первый раз. Подняли все доки, вооружились ии, назначили дату и стали все готовить. Я забронировал отели, спланировал маршрут и приступил к поиску билетов. Стоимость на семью из пяти человек туда сюда выходила какая-то космическая. С пересадками можно было найти дешевле, но с тремя детьми включая годовалого, это еще та задница. Поэтому искал только прямой. Нашел какие-то итальянские авиалинии, которые довозили до рима, а дальше мы планировали уже на машине до испании. Стоимость билетов выходила в 5000$. Я помню как сейчас когда нажимал кнопку подтверждения спросил жену "мы точно готовы?", похихикали и купили. Там еще удачно была рассрочка с платежами в тысячу ежемесячно.
Непосредственно в день подачи документов, выяснилось, что мы налажали с фотками, не сделали каких-то копий и чо то там еще. В итоге с нас прямо там взяли допом 1000$ за оформление. Причем я прямо почувствовал как меня обувают, потому что там не было криминала, но альтернативой была перезапись на прием через месяцы, а у нас до вылета всего оставалось пару месяцев. В общем мы все подали и довольные уехали.
Буквально через две недели пришли паспорта для меня и жены. Нам дали визу на 73 дня, что было точно по плану. А вот на детей не пришли. Примерно в те же дни я получил письмо (и может звонок, не помню уже), где мне сказали, что детей надо сфоткать и для их свидетельств о рождении нужны апостили (каждый стоит 120$). Я тогда слегка офигел, потому что мы заплатили деньги за помощь в оформлении, а они в итоге поставили нас в такую ситуацию. Фотки еще ладно, мы просто теряем время на поездках (туда ехать час), а вот апостиль это уже не так просто. Его надо заказывать и ждать.
Я тут же позвонил юристу и уже через несколько дней с детьми и апостилями гнал к ним. Детей сфоткали, но когда забирали апостили, мне сказали что апостиль на свидетельствах не тот, нужен из москвы. Не знаю почему, но в тот момент я был уверен что это какая-то ошибка, во-первых почему Москва? Почему такая специфика? (как оказалось они когда это говорят имеют ввиду Россию) Во-вторых это выглядело как дичь, что мне надо было сначала лететь туда все это делать и потом возвращаться. А мы столько путешествовали, что уже привыкли к определенным процедурам. В общем я убедил девушку что это скорее всего какая-то ошибка и все прокатит. Она забрала документы и сказала ждать.
Прошло еще какое-то время и нам доставили паспорта детей. Я радостно их открыл и увидел отказ, причем без объяснения причины. Тогда меня охватила паника и я вспомнил про апостили, стало понятно что дело скорее всего в этом. Я решил идти до конца и поехал в посольство. Вообще по таким причинам никого во внутрь не пускают, но они мне не вернули кое какие доки (обычно их вместе с паспортами возвращают) и я на каждом шагу говорил что мне нужны доки которые мне не вернули. В итоге меня все пропускали удивляясь что такая ситуация случилась. Как потом оказалось, это были копии и они все делали по протоколу, но это мне помогло прорваться во внутрь.
Продолжение в комментах, потому что пост получился длиннее чем разрешено в телеге =>
Ссылки: Телеграм: t.me/orgprog | Youtube: youtube.com/@mokevnin | VK: vk.com/orgprog
2 weeks ago | [YT] | 15
View 7 replies
Организованное программирование | Кирилл Мокевнин
Async Jobs (Background Jobs)
Если для вас эти слова ничего не говорят, то возможно после этого поста вы сможете нехило улучшить и упростить ваше приложение. Зайдем через проблематику.
Буквально в каждом не тривиальном приложении, уже на старте, появляется задача выполнять какие-то задачи асинхронно. Самое простое - отправка писем после регистрации. Почему этого нельзя делать там же где делается регистрация? Отправка письма это почти наверняка взаимодействие с внешним сервисом по api или smtp. А это сеть со всеми вытекающими от задержек до ошибок. Ваши пользователи будут регулярно получать тайматы и ошибку 500. Сразу встает вопрос транзакционности и гарантий. Что в таких ситуациях делать?
Первое, что приходит на ум, это выполнять отправку в памяти, но отдельно. Такие механизмы иногда предоставляются самим фреймворком (async в spring boot), либо это можно организовать самому (nodejs, go). Для не критичных вещей, когда нет нагрузок и особых рисков, можно и так, но этот подход быстро упирается в потолок. Что не так?
• Нет гарантий выполнения. Процесс упал - задача исчезла. Получаем потерянные письма, вебхуки, уведомления. Такое будет происходит и при деплоях и автоматических рестартах и ошибках.
• Нет контроля нагрузки. Если растет потребление ресурсов, то такой подход не маштабируется и начинает мешать основному приложению.
• Нет прозрачности. Вы не видите: что сейчас выполняется, что упало, что зависло, что выполняется слишком долго.
Обычно после этого варианта, сразу переходят к очередям и стримам. А давайте воткнем redis/kafka/rabbitmq и на каком-нибудь задорном языке понапишем отдельных приложений, которые будут хватать эти сообщения и делать всякие задачи от отправки емейлов, до каких-то тяжелых вычислений. Сразу можем добавлять в резюме строчку про построение микросервисной архитектуры.
Да такой подход и разделение в какой-то момент может происходить. В первую очередь при росте числа разработчиков и необходимости разделять их в разные команды со своими приложениями и релизными циклами. Но это происходит далеко не всегда (на хекслете как было несколько разработчиков 12 лет назад, так и сейчас несколько разработчиков) либо происходит тогда, когда у компании уже много ресурсов и со старта проекта прошел не один год.
Короче, по середине между двумя этими подходами и затесались background jobs. Это механизм, позволяющий выполнять любые задачи асинхронно в отдельном процессе с персистентностью (а значит гарантиями) и возможностью масштабировать. То есть их можно запускать хоть на другом сервере и в любом количестве экземпляров. Чем это отличается от работы через очереди спросите вы? Отличается и вот в чем. Для начала пример в python (celery). Определение джобы:
# tasks.py
from celery import shared_task
@shared_task
def send_welcome_email(user_id, email):
send_email(email)
Использование:
# registration.py
from tasks import send_welcome_email
def register_user(email):
user = create_user(email)
send_welcome_email.delay(user.id, user.email)
return user
Джобы это код нашего приложения, а не отдельное приложение. На практике мы просто стартуем наше приложение в режиме джоб, когда оно не обрабатывает http запросы, а просто крутится в фоне. Планирование джобы, это отправка сообщений в космос для каких-то консьюмеров, о которых мы ничего не знаем. Джоба это запуск конкретного кода под конкретную задачу, что очень сильно отличает их от очередей. Джобу можно воспринимать просто как функцию, которая, кстати, в тестах часто вызывается вообще синхронно, значительно упрощая инфраструктуру и работу монолита. Данные при этом часто хранятся в redis, а сейчас вообще идет тенденция, чтобы по дефолту хранить джобы в той же базе что и само приложение (что значительно упрощает старт и есть адаптеры). Ну и все это добро поддерживает ретраи, приоритеты и другие механизмы типичные для очередей.
Реализации джоб есть в каждом языке. Какой либой пользуетесь вы?
Ссылки: Телеграм: t.me/orgprog | Youtube: youtube.com/@mokevnin | VK: vk.com/orgprog
3 weeks ago | [YT] | 37
View 14 replies
Организованное программирование | Кирилл Мокевнин
Сегодня я хочу поделиться соообщением Ростислава (подписчика), которое он вчера написал. Именно ради такого эффекта я делаю то что делаю. Безумно рад таким кейсам:
Хотел сказать спасибо за ваши подкасты: они немного поменяли мою картинку мира в лучшую сторону
Особенно спасибо за выпуски про VictoriaMetrics и Злых Марсиан. Спустя десяток подкастов именно они до меня достучались и я осознал, что можно прийти в open source
Я лет 5 пытаюсь построить свои SaaS'ы. В мае решил попробовать свои навыки для open source'а и в июне я выпустил postgresus.com/ (GitHub) для резервного копирования PostgreSQL
За полгода проект вырос до ~3к звёзд, ~45к Docker pull'ов и оказался востребованным (очень много фидбека). Теперь хочу сделать Postgresus лучшей бекапилкой PostgreSQL в мире 🦦
Несколько дней назад как раз выложил статью на Хабр про версию 2.0 - habr.com/ru/articles/974492/
За полгода оказалось, что open source даёт большой фидбек и немного помогает в карьере. А главное - позволяет закрыть чувство перфекционизма: не нужно бежать вперед за деньгами, можно играться в своей профессиональной песочнице
Тем более у меня немного маркетинговое искажение: я стараюсь делать удобно с точки зрения UX и DevEx - а это непаханное поле в open source'e
В общем, спасибо вам большое, что стараетесь для таких, как я! Если бы не вы, этого проекта бы не было
p.s. Если у вас происходят подобные сдвиги, обязательно пишите! Можно прямо тут в комментах
Ссылки: Телеграм: t.me/orgprog | Youtube: youtube.com/@mokevnin | VK: vk.com/orgprog
3 weeks ago (edited) | [YT] | 49
View 2 replies
Организованное программирование | Кирилл Мокевнин
Микросервисы это скам. DHH тут написал твит, которым я не могу не поделиться. Микросервисы — это самый успешный обман доверия в индустрии разработки. Они убеждают небольшие команды, что те «мыслят масштабно», одновременно систематически разрушая их способность двигаться вообще хоть как-то. Они тешат амбиции, превращая неуверенность в оружие: если вы не запускаете созвездие сервисов, вы вообще настоящая компания? И неважно, что эта архитектура была придумана для борьбы с организационной дисфункцией планетарного масштаба. Теперь её прописывают командам, которые всё ещё сидят в одном Slack-канале и за одним столом на ланче.
Небольшие команды держатся на общем контексте. Это их сверхсила. Все могут рассуждать от начала до конца. Все могут менять всё. Микросервисы испаряют это преимущество при первом же контакте. Они заменяют общее понимание распределённым невежеством. Никто больше не владеет системой целиком. Каждый владеет лишь осколком. Система перестаёт быть тем, что команда понимает и контролирует, и превращается в нечто, что просто происходит с командой. Это не усложнение. Это отказ от ответственности.
А потом начинается операционный фарс. Каждый сервис требует собственный pipeline, секреты, алерты, метрики, дашборды, права доступа, бэкапы и целый набор ритуалов умиротворения. Вы больше не «деплоите» — вы синхронизируете флот. Один баг теперь требует вскрытия нескольких сервисов. Выпуск фичи превращается в упражнение по координации через искусственные границы, которые вы сами же и придумали без всякой причины. Вы не упростили систему. Вы разнесли её и назвали обломки «архитектурой».
Микросервисы также консервируют некомпетентность. Вас заставляют определять API ещё до того, как вы понимаете собственный бизнес. Догадки становятся контрактами. Плохие идеи — постоянными зависимостями. Каждая ранняя ошибка метастазирует по сети. В монолите ошибочное мышление исправляется рефакторингом. В микросервисах ошибочное мышление становится инфраструктурой. Вы не просто сожалеете — вы хостите это, версионируете и мониторите.
Утверждение, что монолиты не масштабируются, — одна из самых глупых сказок современной инженерной мифологии. Не масштабируется хаос. Не масштабируется процессная показуха. Не масштабируется игра в Netflix, когда вы на самом деле делаете обычный CRUD. Монолиты масштабируются прекрасно, когда у команды есть дисциплина, тесты и умеренность. Но умеренность не в моде, а скучные вещи не делают хорошие доклады на конференциях.
Микросервисы для маленьких команд — это не техническая ошибка, а философская. Это громкое заявление о том, что команда не доверяет себе понять собственную систему. Это замена ответственности протоколами, а инерции — прослойками. Вы не получаете «защиту на будущее». Вы получаете перманентный тормоз. И к тому моменту, когда вы наконец доростёте до масштаба, который хоть как-то оправдывает этот цирк, ваша скорость, ясность и продуктовая интуиция уже будут потеряны.
p.s. Ссылка на твит x.com/dhh/status/1998785569468399819
3 weeks ago | [YT] | 118
View 45 replies
Организованное программирование | Кирилл Мокевнин
Слои валидации. Когда говорят "валидация", обычно подразумевают любое правило, которое должно защитить систему от неправильных данных. Но внутри этого большого слова скрываются разные типы и цели проверок, которые еще и выполняются на разных уровнях приложения. Разберем:
Валидация на клиенте (если он есть)
Сюда входит формат данных, обязательность полей и так далее. Чуть сложнее, когда надо проверять, например, уникальность имени пользователя или емейла, в этом случае придется ждать отправки или делать запросы на бекенд во время заполнения. Главное что надо знать про эту валидацию, то что она вспомогательная. Клиент всегда можно обойти и сделать запрос напрямую. Дублирование как ни крути, хотя и важно для UX.
Структурная валидация
Это валидация, которая, обычно, происходит на уровне самого фреймворка или в самом начале цикла обработки запроса. Для этого данные прогоняются через валидаторы json схемы, которая в идеале генерируется из openapi спеки. В самых деревянных случаях ручками (так делать не надо). Что важно понимать, это не доменная валидация (бизнес правила). Да тут можно проверить формат, наличие/отсутствие, но нельзя и не правильно пытаться проверять уникальность, выполнение каких-то условий, например количества денег на счету и тому подобное.
Кстати с точки зрения кодов ответа, на этом уровне несовпадение со схемой воспринимается не как ошибка валидации, а как неверный запрос с неверной структурой, а это код ответа 400.
Доменная валидация
Это уже уровень бизнес правил. Такая валидация включает в себя любые правила, которым должны соответствовать данные с точки зрения бизнес-логики приложения. Уникальность email, баланс на счету, ограничения переходов - все это относится к доменному слою, и проверяется глубже, после прохождения проверки структуры. Во фреймворках это слой, который часто реализуется внутри моделей (если они есть). В любом случае такие валидации должны быть вынесены в какой-то свой слой, который можно переиспользовать для разных точек входа, асинхронной обработки и т.п.
Доменные проверки, как и клиентские могут дублироваться, если завязаны на консистентность базы данных. Например во многих фреймворках (с orm) есть валидация на уникальность, которая делает sql-запрос, но в документации у этого валидатора всегда написано, что это не надежно (из-за конкурентности) и в таких ситуациях обязательно делать индексы в базе данных.
В случае провала такой валидации, в api принято возвращать код 422
Валидация на уровне базы данных
Все предыдущие уровни не могут дать 100% гарантий, особенно учитывая, что данные в базе обновляются далеко не только по запросам снаружи. Поэтому есть вещи, которые обязательно делать на уровне базы данных. Сюда относятся уникальные индексы, внешние ключи (если делаете их), nullable, ограничение по длине и т.д. Технически многие базы данных позволяют писать кастомные валидации, которые соблазнительно использовать как доменную валидацию. Не надо этого делать :)
Проверка корректности данных
Это тип валидации "ни туда ни сюда", потому что он может выполняться в разных слоях, в зависимости от используемого стека. К таким проверкам относится подтверждение пароля или, например, емейла. С точки зрения бизнес-логики, этой части вообще не существует, она есть только на уровне форм, потому что все давно привыкли так писать (хотя необходимость под вопросом). При этом ни в базе, ни в дальнейшей работе оно никак не используется и вообще это не данные, которые куда-то сохраняются.
Подобные проверки делают в первую очередь на клиенте (и на этом можно было бы остановиться). Внутри бека их располагают в слое форм (есть далеко не во всех фреймворках), либо некоторые фреймворки типа rails для простоты пихают такой валидатор в модели, хотя семантически это неверно.
p.s. Какие инструменты для валидации вы используете?
Ссылки: Телеграм: t.me/orgprog | Youtube: youtube.com/@mokevnin | VK: vk.com/orgprog
4 weeks ago | [YT] | 33
View 12 replies
Load more