Организованное программирование | Кирилл Мокевнин
12.6K subscribers
73 photos
305 links
Как из джуниора дойти до мидла, а потом и до синьора
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
Download Telegram
Почему нужно использовать DTO

Data Transfer Object, термин, который для разработчиков на статических языках является чем-то самим разумеющимся, но вот остальные его могут не знать (даже если пользуются). Хотя в эпоху интеграций, фронтенд-бекенд, сервис-сервис, очереди, это крайне важная конструкция.

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

⁃ Модель => DTO => json/protobuf/sql/...
⁃ json/protobuf/sql/... => DTO => Модель

Нафига? Почему не сразу преобразовывать из, допустим, json в нашу модель или наоборот? Тем более во всех экосистемах есть механизмы, которые позволяют упаковывать любые объекты, задавая правила преобразования через метаданные, аннотации или еще как-то. Пример из Java:


@Entity
public class User {
@Id
private Long id;
@JsonIgnore // приходится скрывать
private String passwordHash;
@JsonProperty("created_at")
private LocalDateTime createdAt;

// getters/setters ...
}

var json = new ObjectMapper().writeValueAsString(dto);


Существует масса причин, почему это плохая идея. Для начала, это банальное нарушение MVC архитектуры. Модель начинает знать как о представлении, о том какие поля надо выдавать наружу, какие нет, как их переименовывать и так далее. Если это кажется натянутым, то вот вам реальные последствия.

Одна и та же сущность для внешнего мира редко представляется одним способом. В зависимости от задачи, это может быть один набор полей или другой. Как это разрулить? Дальше, здесь плохо контролируется процесс, легко может быть такое, что новое поле автоматически попало наружу, хотя вы этого не планировали, но забыли его исключить. А если нужны вычисляемые поля или другое представление (всегда в датах)? В такой ситуации модель будет наполняться доп свойствами и методами, которые готовят доп данные для преобразования, что ведет к сильному загрязнению кода. Что из этого относится к бизнес-части, а что к представлению? Проблема.

DTO позволяют отделить представление от модели в коде, создавая по сути промежуточный слой. Имея его, вы можете независимо развивать свою модель и API для взаимодействия с ним. И да, это один из аспектов MVC, конкретно Model-View.

Готовые DTO гораздо легче чем модели конвертировать в типы на TS если у вас есть такая потребность. Например мы наши DTO (используем Alba), превращаем в типы TS с помощью готового инструмента (Typelizer). С моделями так легко не получится.

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

Но это только базовая история. Если мы еще подключаем инструменты генерации из sql (как в go) или openapi как везде, то те самые DTO создаются вообще автоматически на основе описаний.

Пример для sqlc.Библиотека на базе этого запроса и схемы базы генерирует DTO. Запрос:


INSERT INTO links (original_url, short_name)
VALUES (sqlc.arg(original_url), sqlc.arg(short_name))
RETURNING *;


DTO:


type CreateLinkParams struct {
OriginalUrl string `json:"original_url"`
ShortName string `json:"short_name"`
}


Причем для update будет создана своя структура:


type UpdateLinkParams struct {
OriginalUrl string `json:"original_url"`
ShortName string `json:"short_name"`
ID int64 `json:"id"`
}


Здесь отличается только id, но в реальных кейсах, отличий в создании или обновлении одной сущности обычно значительно больше, поэтому количество DTO тут становится еще больше.

DTO, кстати, должны быть имутабельны, иначе туда потечет логика

p.s. Вы сами пишите DTO или генерируете?

Ссылки: Телеграм | Youtube | VK
51👍6821🔥8🤔8👎211🤝1
Как личность связана с кодингом. С годами опыта начинаешь замечать в себе, что есть определенные типы задач, которые тебе нравятся и ты их всегда делаешь с удовольствием, а какие-то, даже если они важные, делаешь всегда через силу или стараешься их избегать. Иногда это связано с недостатком знаний, но, как мне кажется, чаще это все же отражение каких-то особенностей личности.

Например я обожаю удалять код, обновлять зависимости, использовать готовые решения вместо самопальных и прокачиваться в vim. Мне нравится проектировать предметную область. я с удовольствием пишу тесты (там где хороший сетап) и занимаюсь инфраструктурой. Одновременно с этим я не люблю задачи на оптимизации, у меня никогда не возникает желания залезть куда-то в кишки и попробовать переписать на go/rust/c/асемблер. Да если надо я буду оптимизировать, но для этого должна быть причина и отсутствие тех кому бы я мог это делегировать :) Отдельно, много лет назад я обнаружил в себе любовь к фронтенду. Причем как верстальщик я скорее копипастер, но при этом обожаю собирать интерфейсы из готовых элементов типа bootstrap или, сейчас, mantine.

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

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

А от чего прет (или не прет) вас?

Ссылки: Телеграм | Youtube | VK
🔥91👍5928❤‍🔥6👎3🤔2💩1
В сегодняшнем выпуске разбираю главу "Модульные тесты" книги "Чистый Код" Мартина.
https://youtube.com/watch?v=DqgAqCpYsbs

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

Альтернативные ссылки: Аудио | vk
51🔥24👍185🤔1
В интернете кто-то не прав

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

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

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

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

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

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

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

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

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

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

Не имеет значение, насколько аргументированная критика от других людей, если она сопровождается прямой или пассивной-агрессией, оскорблениями кого-бы то ни было, попыткой указывать как поступать другому человеку (удали пост, не позорься). Часто подобные сообщения сопровождаются в конце очень сильно смеющимся смайликом, как бы показывая что человек на другой стороне больной дибил. Во всех таких случаях полный игнор.

Поэтому вы можете заметить, что я далеко не всегда отвечаю на то что мне пишут 🙂 Не потому что нечего сказать, а потому что ментальное здоровье дороже.

p.s. А вы попадали в такие перепалки? Какое было послевкусие?

Ссылки: Телеграм | Youtube | VK
256👍52🔥8💯5🌚4🤡3👎1🤔1🥱1🤝1
Почему провалился BDD?

Программирование управляемое поведением когда-то захватило умы разработчиков и об этом говорили буквально на каждом углу. Для поддержания этой идеи появился целый пласт инструментов, использовать которые было просто обязательно для любого прогрессивного разработчика. Активно пошли в мир тестовые подходы и фреймворки типа cucumber и rspec, отовсюду звучало Given-When-Then. А потом раз и все это исчезло как и появилось. Что случилось?

Идея BDD не нова, кейсы, примеры, сценарии существовали десятилетиями: Use Cases (1990-е), User Stories (начало 2000-х), Acceptance Criteria, примерно весь классический системный анализ.

BDD, по сути, внес такую формулировку:

⁃ Пример и есть требование.
⁃ Примеры и есть документация.
⁃ Примеры и есть тесты.

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


Feature: User login

Scenario: Login fails with invalid password
Given a registered user exists
And I am on the login page
When I enter "user@example.com" into the "Email" field
And I enter "wrong-password" into the "Password" field
And I click the "Login" button
Then I should see "Invalid email or password"
And I should remain on the login page


Читается? Да. Понимает ли это бизнес? Возможно, в первый день.
Но это только верхушка айсберга. Реальная работа происходит в другом месте - в описаниях шагов, так называемых step definitions, которые нужно писать отдельно:


Given("a registered user exists") do
@user = User.create!(
email: "user@example.com",
password: "correct-password"
)
end

Given("I am on the login page") do
visit "/login"
end

When('I enter "{string}" into the "{string}" field') do |value, field|
fill_in field, with: value
end

When('I click the "{string}" button') do |button|
click_button(button)
end

Then('I should see "{string}"') do |text|
expect(page).to have_content(text)
end

Then("I should remain on the login page") do
expect(page).to have_current_path("/login")
end


И вот тут начинается жопа. Этот слой быстро разрастается до сотен методов (даже для простых кейсов), которые должны быть одновременно “универсальными”, “переиспользуемыми” и “человеко-читаемыми”. На практике это приводит к бесконечному количеству абстракций вида “When I click the ‘Login’ button” и “Then I should see ‘Success’”, которые не помогают ни бизнесу, ни разработчикам, ни тестировщикам. Стейкхолдеры даже не открывали эти сценарии.

Разработчикам приходилось тратить значительно больше времени, для того чтобы эти тесты писать и поддерживать. Мантра была - такие тесты проще понять, но, в реальности, мы получили еще один слой абстракции и много жарких разговоров на тему того, а как правильно все это писать. А они еще сильно завязаны на визуальную часть, что ближе к e2e тестам с точки зрения кода. Это сильно добавляет хрупкости и усложняет отладку. В какой-то момент bdd и e2e стали чуть ли не синонимами у многих команд.

BDD провалился, потому что его реальная ценность была в коммуникации, а его реальная практика стала про автоматизированные UI-тесты. Несмотря на это, в те годы родилось много инструментов, элементы которых до сих пор живут в разных экосистемах. Например те же матчеры отлично прижились в vitest/jest, в ruby мире по прежнему популярен rspec.

p.s. Хорошее видео по теме https://www.youtube.com/watch?v=Bq_oz7nCNUA

Ссылки: Телеграм | Youtube | VK
👍4718🔥4😢2🤡1
Неправильно называть рефакторингом переход с синхрона на асинхрон, это уже как минимум другой контракт, скорее всего и Use Case поменяется, добавятся очереди и бог его знает что.. Это уже другая по сути фича. А рефакторинг это же когда поведение программы (класса) не меняется и даже интерфейсы не меняются. Как у метода sort на вход был массив, так и остаётся, только вместо пузырька стали merge-sort использовать

Такой коммент оставили к видео про тесты youtube.com/watch?v=DqgAqCpYsbs Тут у меня приподнялась бровь, потому что у человека (судя по другим комментариям и лайкам) восприятие рефакторинга прочно ассоциируется с внутренними модулями. А раз есть такое восприятие, то не грех это проговорить.

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

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

А что обычно вы имеете ввиду когда говорите что делаете рефакторинг или тут нужен рефакторинг?

Ссылки: Телеграм | Youtube | VK
👍477🔥6🤷‍♂1👎1🤔1👌1
Слои валидации. Когда говорят "валидация", обычно подразумевают любое правило, которое должно защитить систему от неправильных данных. Но внутри этого большого слова скрываются разные типы и цели проверок, которые еще и выполняются на разных уровнях приложения. Разберем:

Валидация на клиенте (если он есть)

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

Структурная валидация

Это валидация, которая, обычно, происходит на уровне самого фреймворка или в самом начале цикла обработки запроса. Для этого данные прогоняются через валидаторы json схемы, которая в идеале генерируется из openapi спеки. В самых деревянных случаях ручками (так делать не надо). Что важно понимать, это не доменная валидация (бизнес правила). Да тут можно проверить формат, наличие/отсутствие, но нельзя и не правильно пытаться проверять уникальность, выполнение каких-то условий, например количества денег на счету и тому подобное.

Кстати с точки зрения кодов ответа, на этом уровне несовпадение со схемой воспринимается не как ошибка валидации, а как неверный запрос с неверной структурой, а это код ответа 400.

Доменная валидация

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

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

В случае провала такой валидации, в api принято возвращать код 422

Валидация на уровне базы данных

Все предыдущие уровни не могут дать 100% гарантий, особенно учитывая, что данные в базе обновляются далеко не только по запросам снаружи. Поэтому есть вещи, которые обязательно делать на уровне базы данных. Сюда относятся уникальные индексы, внешние ключи (если делаете их), nullable, ограничение по длине и т.д. Технически многие базы данных позволяют писать кастомные валидации, которые соблазнительно использовать как доменную валидацию. Не надо этого делать :)

Проверка корректности данных

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

Подобные проверки делают в первую очередь на клиенте (и на этом можно было бы остановиться). Внутри бека их располагают в слое форм (есть далеко не во всех фреймворках), либо некоторые фреймворки типа rails для простоты пихают такой валидатор в модели, хотя семантически это неверно.

p.s. Какие инструменты для валидации вы используете?

Ссылки: Телеграм | Youtube | VK
👍4119🔥5🤔3
Микросервисы это скам. DHH тут написал твит, которым я не могу не поделиться. Микросервисы — это самый успешный обман доверия в индустрии разработки. Они убеждают небольшие команды, что те «мыслят масштабно», одновременно систематически разрушая их способность двигаться вообще хоть как-то. Они тешат амбиции, превращая неуверенность в оружие: если вы не запускаете созвездие сервисов, вы вообще настоящая компания? И неважно, что эта архитектура была придумана для борьбы с организационной дисфункцией планетарного масштаба. Теперь её прописывают командам, которые всё ещё сидят в одном Slack-канале и за одним столом на ланче.

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

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

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

Утверждение, что монолиты не масштабируются, — одна из самых глупых сказок современной инженерной мифологии. Не масштабируется хаос. Не масштабируется процессная показуха. Не масштабируется игра в Netflix, когда вы на самом деле делаете обычный CRUD. Монолиты масштабируются прекрасно, когда у команды есть дисциплина, тесты и умеренность. Но умеренность не в моде, а скучные вещи не делают хорошие доклады на конференциях.

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

p.s. Ссылка на твит https://x.com/dhh/status/1998785569468399819

Ссылки: Телеграм | Youtube | VK
5👍20255🔥39🥱10🤔8👎5💊31💯1😴1😭1
Выпуск про Хаскель (с лайвкодингом) выйдет завтра, а сегодня я хочу поделиться соообщением Ростислава (подписчика), которое он вчера написал. Именно ради такого эффекта я делаю то что делаю. Безумно рад таким кейсам:

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

Особенно спасибо за выпуски про VictoriaMetrics и Злых Марсиан. Спустя десяток подкастов именно они до меня достучались и я осознал, что можно прийти в open source

Я лет 5 пытаюсь построить свои SaaS'ы. В мае решил попробовать свои навыки для open source'а и в июне я выпустил https://postgresus.com (GitHub) для резервного копирования PostgreSQL

За полгода проект вырос до ~3к звёзд, ~45к Docker pull'ов и оказался востребованным (очень много фидбека). Теперь хочу сделать Postgresus лучшей бекапилкой PostgreSQL в мире 🦦

Несколько дней назад как раз выложил статью на Хабр про версию 2.0 - https://habr.com/ru/articles/974492/

За полгода оказалось, что open source даёт большой фидбек и немного помогает в карьере. А главное - позволяет закрыть чувство перфекционизма: не нужно бежать вперед за деньгами, можно играться в своей профессиональной песочнице

Тем более у меня немного маркетинговое искажение: я стараюсь делать удобно с точки зрения UX и DevEx - а это непаханное поле в open source'e

В общем, спасибо вам большое, что стараетесь для таких, как я! Если бы не вы, этого проекта бы не было

p.s. Если у вас происходят подобные сдвиги, обязательно пишите! Можно прямо тут в комментах

Ссылки: Телеграм | Youtube | VK
5🔥142👍4326🤡2🤔1
Хаскель! Ура, долгожданный выпуск 🙂

В гостях у меня снова Александр Вершилов. Мы час говорили про хаскель, фп и влияние на разработку, а потом, решили попробовать лайвкодинг, чтобы наглядно показать, в чем его прелесть и почему им стоит заняться хотя бы для общего развития. https://www.youtube.com/watch?v=AHpmdGVYSZo&lc=Ugw1wWGR7A6q3tyUc9t4AaABAg Максимально рекомендуется всем, кто хочет стать более крутым инженером

Альтернативные ссылки: Аудио | vk
👏40🔥29👍7🥰75👎1🤔1🤡1
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, а сейчас вообще идет тенденция, чтобы по дефолту хранить джобы в той же базе что и само приложение (что значительно упрощает старт и есть адаптеры). Ну и все это добро поддерживает ретраи, приоритеты и другие механизмы типичные для очередей.

Реализации джоб есть в каждом языке. Какой либой пользуетесь вы?

Ссылки: Телеграм | Youtube | VK
1👍6519🔥10🥱3👎1🤔1
Как я потерял 5000$ на авиабилетах

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

Короче закатали рукава и начали процесс оформления визы в испанию. В майами это самый ходовой путь получать туристическую визу в европу. Тем более это был не первый раз. Подняли все доки, вооружились ии, назначили дату и стали все готовить. Я забронировал отели, спланировал маршрут и приступил к поиску билетов. Стоимость на семью из пяти человек туда сюда выходила какая-то космическая. С пересадками можно было найти дешевле, но с тремя детьми включая годовалого, это еще та задница. Поэтому искал только прямой. Нашел какие-то итальянские авиалинии, которые довозили до рима, а дальше мы планировали уже на машине до испании. Стоимость билетов выходила в 5000$. Я помню как сейчас когда нажимал кнопку подтверждения спросил жену "мы точно готовы?", похихикали и купили. Там еще удачно была рассрочка с платежами в тысячу ежемесячно.

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

Буквально через две недели пришли паспорта для меня и жены. Нам дали визу на 73 дня, что было точно по плану. А вот на детей не пришли. Примерно в те же дни я получил письмо (и может звонок, не помню уже), где мне сказали, что детей надо сфоткать и для их свидетельств о рождении нужны апостили (каждый стоит 120$). Я тогда слегка офигел, потому что мы заплатили деньги за помощь в оформлении, а они в итоге поставили нас в такую ситуацию. Фотки еще ладно, мы просто теряем время на поездках (туда ехать час), а вот апостиль это уже не так просто. Его надо заказывать и ждать.

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

Прошло еще какое-то время и нам доставили паспорта детей. Я радостно их открыл и увидел отказ, причем без объяснения причины. Тогда меня охватила паника и я вспомнил про апостили, стало понятно что дело скорее всего в этом. Я решил идти до конца и поехал в посольство. Вообще по таким причинам никого во внутрь не пускают, но они мне не вернули кое какие доки (обычно их вместе с паспортами возвращают) и я на каждом шагу говорил что мне нужны доки которые мне не вернули. В итоге меня все пропускали удивляясь что такая ситуация случилась. Как потом оказалось, это были копии и они все делали по протоколу, но это мне помогло прорваться во внутрь.

Продолжение в комментах, потому что пост получился длиннее чем разрешено в телеге =>

Ссылки: Телеграм | Youtube | VK
😱54👍1514😢5🤮5👎4👏1🤣1🤪1
Если вы еще не подрубили chrome mcp (https://github.com/ChromeDevTools/chrome-devtools-mcp) к своему проекту, то самое время это сделать. С его помощью я тут же смог решить несколько задач по верстке, которые раньше мне не поддавались из-за того, что я местами плаваю в ней + требовался глубокий дебаг включающий в себя и верстку и react и конкретно компоненты Mantine. Теперь эта штука имея полный доступ ко всему творит просто чудеса. Я в шоке.

Выглядит так, оно прямо запускает браузер и на глазах анализирует страницу. Главное чтобы был запущен веб-сервер

Ссылки: Телеграм | Youtube | VK
👍67🔥1910🤔5💩1
Что означает "порт занят"?

Я как-то совсем стороной обходил все что касается операционок, администрирования и девопса, хотя сказать есть что. Особенно в свете последних собеседований 🙂 Открою эту рубрику постом про занятые порты.

На моих собесах мы разворачиваем приложение и делаем что-то полезное в нем. Во время старта приложения поднимается база, веб-сервер, фронт и что-то еще по мелочи, вполне типовой набор для веб проекта. И вот тут, с вероятностью 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. Ребят нужен такой контент (лайкните если да)? Я знаю что для многих это довольно базовый уровень, но с другой стороны, немало и тех, кто с операционками на вы.

Ссылки: Телеграм | Youtube | VK
👍50182🔥28👎6😨4🤯3🥱2🤔1👌1
Традиционные результаты года

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

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

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

Всем чмоки, увидимся в следующем году (а завтра я уже записываю новый выпуск для подкаста)

p.s. Если у вас есть истории про то, как канал повлиял на ваши убеждения/код который вы пишите/подходы которые вы используете, то было бы классно -) Поделитесь плс
👍4224🔥18🎄7🤔1
Иификация. Чем дальше, тем больше ии интегрируется в мой процесс разработки и уже появился какой-то набор паттернов, которыми я бы хотел поделиться. В этом посте поделюсь сетапом, а в будущих уже расскажу подробнее про эффективное использование

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. А какой у вас сетап?

Ссылки: Телеграм | Youtube | VK
1👍6117💩17🔥9🤯2🤔1
Переключение контекста в программировании. Работать только над фичами утомляет и в течение дня иногда хочется переключиться или просто голова не особо варит, а делать полезное хочется. Куда и как можно переключиться? Вот что работает в моем случае. Для начала, какие типы задач я выделяю (в моей практике):

- UX/UI. Дизайн, удобство, отзывчивость и любые фронтовые правки
- Обновление зависимостей (люблю я это дело)
- Типизация. Добавление типов (нам в ruby актуально), оптимизация типов и т.п.
- DX. Тут и скорость работы инструментов (сборка, тесты и т.п.) и CI и разворачивание проекта
- Kubernetes. Сам по себе отдельно, как инфраструктурная единица
- Инфраструктура. Сюда относятся облака, хостинги и terraform для этого добра
- Покрытие и тесты. Тесты всегда можно дописать
- Массовые тупые рефакторинги. Когда надо бы поправить весь код, но обычно не доходили руки, а тут ИИ, который может сам если его попросить
- Посидеть над беклогом и поотвечать в тикетах :)

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

А у вас какие фишки для переключения в разработке?

Ссылки: Телеграм | Youtube | VK
50👍38🔥8💩5🤔1
Популярность Tailwindcss убила бизнес ее создателя

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

На днях ему пришлось уволить 3 из 4 разработчиков работающих над проектом. Денег осталось на 6 месяцев (с учетом падающего входящего потока) и дальше он пока не придумал что делать.

Основная бизнес модель у Tailwind это продажа дополнительных компонентов, о которых люди узнают через документацию. Так вот трафик на нее упал на 40% и продолжает падать. При этом популярность Tailwind сейчас находится в максимуме, 70 миллионов скачиваний каждый месяц, гигантское количество продуктов вокруг.

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

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

Ссылки: Телеграм | Youtube | VK
2😭46👍40😱17136😁2🤔1🥴1😍1