Легаси != говнокод
Каждый раз когда обсуждается легаси, создается впечатление, как будто мы обсуждаем какой-то очень плохо написанный код в прошлом, который обязательно надо выкинуть и переписать, потому что он нам мешает жить.
Последнее может быть правдой, но легаси может быть хорошо написанным и отлично работающим кодом. Почему?
Код становится легаси как только мы его выпустили, просто потому что уже начиная с этого момента, мы можем решить писать по другому, с другим набором библиотек и в другую сторону с точки зрения решаемых задач. Но на момент своего написания, он использовал самые современные библиотеки и подходы, а так же решал нужную задачу в тех ограничениях (сроках, ресурсах) настолько хорошо, насколько это было возможно.
Такой взгляд на ситуацию полезен, чтобы меньше стресовать на тему того, что приходится копаться в чем-то устаревшем или бояться идти в какие-то проекты. Легаси это вообще хорошо, только поработав с легаси, человек понимает, чего стоят те или иные решения.
Тогда что такое говнокод? Несмотря на наличие каких-то общепризнанных признаков, все же восприятие кода у разных людей слишком разное. Один видит что у нас классы разбиты не правильно, другой что система не разбита на сервисы, третий, что нет нормальной работы с микросервисами, а я, например, плююсь от программирования на флагах.
Давайте об этом поговорим немного (или много). Как вы определяете говнокод? И допустимо ли так делать?
Ссылки: Телеграм | Youtube | VK
Каждый раз когда обсуждается легаси, создается впечатление, как будто мы обсуждаем какой-то очень плохо написанный код в прошлом, который обязательно надо выкинуть и переписать, потому что он нам мешает жить.
Последнее может быть правдой, но легаси может быть хорошо написанным и отлично работающим кодом. Почему?
Код становится легаси как только мы его выпустили, просто потому что уже начиная с этого момента, мы можем решить писать по другому, с другим набором библиотек и в другую сторону с точки зрения решаемых задач. Но на момент своего написания, он использовал самые современные библиотеки и подходы, а так же решал нужную задачу в тех ограничениях (сроках, ресурсах) настолько хорошо, насколько это было возможно.
Такой взгляд на ситуацию полезен, чтобы меньше стресовать на тему того, что приходится копаться в чем-то устаревшем или бояться идти в какие-то проекты. Легаси это вообще хорошо, только поработав с легаси, человек понимает, чего стоят те или иные решения.
Тогда что такое говнокод? Несмотря на наличие каких-то общепризнанных признаков, все же восприятие кода у разных людей слишком разное. Один видит что у нас классы разбиты не правильно, другой что система не разбита на сервисы, третий, что нет нормальной работы с микросервисами, а я, например, плююсь от программирования на флагах.
Давайте об этом поговорим немного (или много). Как вы определяете говнокод? И допустимо ли так делать?
Ссылки: Телеграм | Youtube | VK
Telegram
Организованное программирование | Кирилл Мокевнин
Как из джуниора дойти до мидла, а потом и до синьора
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
3👍69❤16🔥5🤮3👀1
Долгожданный выпуск про DDD. Местами даже получились дебаты :) Смотрим, слушаем, наслаждаемся!
https://www.youtube.com/watch?v=03FnrgYLkV8
Альтернативные ссылки: Аудио | vk
https://www.youtube.com/watch?v=03FnrgYLkV8
Альтернативные ссылки: Аудио | vk
YouTube
DDD: как подружить бизнес и код | Кирилл Ветчинкин | Организованное программирование #55
Когда архитектура перестаёт быть просто техническим решением и становится инструментом понимания бизнеса, в игру вступает DDD. В этом видео — как выстраивать границы контекстов, выявлять субдомены, находить общий язык между разработкой и бизнесом, использовать…
5❤35👍29🔥12🤮3
Наткнулся на твит, где человек пишет: "вам не нужен ORM, если вы знаете SQL" — и прикладывает вот такой пример:
И его версию в Laravel:
Я абсолютно согласен, что знать SQL для бекендера важно и нужно, но этим все не ограничивается, а еще:
- То что здесь описывается это не ORM, а Query Builder
- Конкретно тут показан Query Builder Laravel, который нельзя назвать эталоном среди QB
- Запросы с группировкой составляют доли процента от обычных запросах в типовых веб-проектах (Аналитические запросы не считаем их вообще делают во внешних системах)
- Сам запрос это еще полдела, в статически типизированных языках еще придется фигачить маппинг если не пользоваться никакими либами
- Чистый SQL это полное отсутствие типобезопасности
- В такой запрос невозможно нормально вставить условные конструкции, например если понадобится фильтрация. Мы сразу попадем либо в склеивание строк, либо в необходимость затаскивать Query Builder
А на картинке к посту пример на drizzle-orm, в котором обеспечивается 100% типобезопасность: проверка всех условий (включая возможность выполнить join), всех операций, всех имен (таблиц и полей). Естественно автокомплит и рефакторинг в наличии.
Естественно это отдельный язык (хотя и крайне близкий к sql), но в современном мире ИИ, подобные запросы могут генериться без проблем, особенно в drizzle-orm, с его описанием схемы.
Плюс хочется сказать, что active = 1 в исходном запросе я не могу рассматривать как не говнокод. Активность должна определяться не флагом, а нормальным статусом. Про флаговое программирование скоро пост в телеге, не пропустите
Ссылки: Телеграм | Youtube | VK
SELECT u.*, COUNT(c.id) as comment_count
FROM users u
LEFT JOIN comments c ON c.user_id = u.id
WHERE u.active = 1 AND c.created_at > NOW() - INTERVAL 30 DAY
GROUP BY u.id
HAVING comment_count > 5;
И его версию в Laravel:
User::select('users.*', DB::raw('COUNT(comments.id) as comment_count'))
->leftJoin('comments', 'comments.user_id', '=', 'users.id')
->where('users.active', 1)
->where('comments.created_at', '>', DB::raw('NOW() - INTERVAL 30 DAY'))
->groupBy('users.id')
->having('comment_count', '>', 5)
->get();
Я абсолютно согласен, что знать SQL для бекендера важно и нужно, но этим все не ограничивается, а еще:
- То что здесь описывается это не ORM, а Query Builder
- Конкретно тут показан Query Builder Laravel, который нельзя назвать эталоном среди QB
- Запросы с группировкой составляют доли процента от обычных запросах в типовых веб-проектах (Аналитические запросы не считаем их вообще делают во внешних системах)
- Сам запрос это еще полдела, в статически типизированных языках еще придется фигачить маппинг если не пользоваться никакими либами
- Чистый SQL это полное отсутствие типобезопасности
- В такой запрос невозможно нормально вставить условные конструкции, например если понадобится фильтрация. Мы сразу попадем либо в склеивание строк, либо в необходимость затаскивать Query Builder
А на картинке к посту пример на drizzle-orm, в котором обеспечивается 100% типобезопасность: проверка всех условий (включая возможность выполнить join), всех операций, всех имен (таблиц и полей). Естественно автокомплит и рефакторинг в наличии.
Естественно это отдельный язык (хотя и крайне близкий к sql), но в современном мире ИИ, подобные запросы могут генериться без проблем, особенно в drizzle-orm, с его описанием схемы.
Плюс хочется сказать, что active = 1 в исходном запросе я не могу рассматривать как не говнокод. Активность должна определяться не флагом, а нормальным статусом. Про флаговое программирование скоро пост в телеге, не пропустите
Ссылки: Телеграм | Youtube | VK
👍82❤26🔥7👎5😁4🤔1
Программирование на флагах
Недавно я упомянул этот термин в одном и постов и получил неожиданно большое количество комментариев "что это?". Тема заслуживает раскрытия, поэтому пост.
Возьмем пример с sql:
Почти наверняка это поле из двух состояний активен/не активен (1/0), где активность определяется подтверждением емейла. В Postgresql это было бы true/false.
В целом, этот код выглядит совершенно нормально и очень хорошо работает. До поры до времени. А потом выясняется, что «неактивный» бывает как «удалённый», так и «заблокированный». Или, например, мы (бизнес) захотим давать работать на сайте тем кто зарегистрировался, но не подтвердил емейл. Подтверждение емейла будет работать как способ получить больше функций. В сумме мы получаем:
⁃ зарегистрированный
⁃ активный (подтвержден емейл)
⁃ удаленный
⁃ забаненный
Поскольку в базе уже есть active, то разарботчик, вероятно, пойдет по наиболее легкому пути - начнет добавлять новые флаги. Это просто и не требует хитрых миграций, чтобы обеспечивать обратную совместимость (для zero downtime). В итоге в базе появятся флаги:
и с этого момента начинается то самое программирование на флагах.
Вместо одной колонки состояния появляется несколько несвязанных булевых полей, которые можно комбинировать как угодно:
⁃ Комбинаторный взрыв состояний - пользователь может быть
⁃ Неявные правила - чтобы понять, что такое «активный пользователь», нужно лезть в код и смотреть, как именно проверяются флаги (active && !deleted && !banned && email_confirmed)
⁃ Сложность изменений - добавление нового флага или изменение бизнес-логики требует правок во множестве мест, потому что условия размазаны по коду и SQL-запросам.
⁃ Повышенный риск багов - достаточно забыть один флаг в проверке и все, приплыли.
Самое главное, что состояния в рамках одного процесса будут требовать синхронного изменения. Если меняется один, то надо не забыть поменять другой. Например если мы человека вводим в бан, то надо не забыть снять активность.
Более универсальный и безопасный для расширения способ в таком случае, это не флаги, а одно свойство определяющее состояние нашей сущности.
Мы кстати с этого и начали, когда перечисляли возможные состояния пользователя.
Фактически такой подход гораздо лучше ложится на то, как мы думаем об этом, чем флаги. Более того, это и намного нагляднее с точки зрения кода. Таким образом мы сразу решаем проблему синхронизации, переход из одного состояния в другое это одно действие и отсутствие багов в стиле "флаги не согласованы"
Есть еще один немаловажный плюс. Допустим у нас изначально два состояния и мы решили, что не будем бежать впереди паровоза. Мы делаем в базе boolean и попадаем в ситуацию, что когда добавится третье состояние, придется менять тип колонки на строку и все значения внутри него. Опытные разработчики сразу будут этому сопротивляться, потому что ломать обратную совместимость в базе нельзя, поэтому правильным способом, будет создать новую колонку и выполнить миграцию туда. Оно нам надо? То есть использования состояния это безопасно и расширяемо в отличие от флагов.
Но даже этого может быть недостаточно. Следующим шагом будет использование конечных автоматов https://github.com/eram/typescript-fsm (в том случае если нужна реакция на переходы, а сама структура переходов не линейная)
Ссылки: Телеграм | Youtube | VK
Недавно я упомянул этот термин в одном и постов и получил неожиданно большое количество комментариев "что это?". Тема заслуживает раскрытия, поэтому пост.
Возьмем пример с sql:
SELECT *
FROM users
WHERE active = 1;
Почти наверняка это поле из двух состояний активен/не активен (1/0), где активность определяется подтверждением емейла. В Postgresql это было бы true/false.
В целом, этот код выглядит совершенно нормально и очень хорошо работает. До поры до времени. А потом выясняется, что «неактивный» бывает как «удалённый», так и «заблокированный». Или, например, мы (бизнес) захотим давать работать на сайте тем кто зарегистрировался, но не подтвердил емейл. Подтверждение емейла будет работать как способ получить больше функций. В сумме мы получаем:
⁃ зарегистрированный
⁃ активный (подтвержден емейл)
⁃ удаленный
⁃ забаненный
Поскольку в базе уже есть active, то разарботчик, вероятно, пойдет по наиболее легкому пути - начнет добавлять новые флаги. Это просто и не требует хитрых миграций, чтобы обеспечивать обратную совместимость (для zero downtime). В итоге в базе появятся флаги:
active
, email_convirmed
, banned
, deleted
и с этого момента начинается то самое программирование на флагах.
Вместо одной колонки состояния появляется несколько несвязанных булевых полей, которые можно комбинировать как угодно:
⁃ Комбинаторный взрыв состояний - пользователь может быть
active = true
, но при этом banned = true
и deleted = true
. Что это значит? Он активен или нет?⁃ Неявные правила - чтобы понять, что такое «активный пользователь», нужно лезть в код и смотреть, как именно проверяются флаги (active && !deleted && !banned && email_confirmed)
⁃ Сложность изменений - добавление нового флага или изменение бизнес-логики требует правок во множестве мест, потому что условия размазаны по коду и SQL-запросам.
⁃ Повышенный риск багов - достаточно забыть один флаг в проверке и все, приплыли.
Самое главное, что состояния в рамках одного процесса будут требовать синхронного изменения. Если меняется один, то надо не забыть поменять другой. Например если мы человека вводим в бан, то надо не забыть снять активность.
Более универсальный и безопасный для расширения способ в таком случае, это не флаги, а одно свойство определяющее состояние нашей сущности.
Мы кстати с этого и начали, когда перечисляли возможные состояния пользователя.
type UserState = 'active' | 'banned' | 'deleted' | 'waiting_email_confirmation'
Фактически такой подход гораздо лучше ложится на то, как мы думаем об этом, чем флаги. Более того, это и намного нагляднее с точки зрения кода. Таким образом мы сразу решаем проблему синхронизации, переход из одного состояния в другое это одно действие и отсутствие багов в стиле "флаги не согласованы"
Есть еще один немаловажный плюс. Допустим у нас изначально два состояния и мы решили, что не будем бежать впереди паровоза. Мы делаем в базе boolean и попадаем в ситуацию, что когда добавится третье состояние, придется менять тип колонки на строку и все значения внутри него. Опытные разработчики сразу будут этому сопротивляться, потому что ломать обратную совместимость в базе нельзя, поэтому правильным способом, будет создать новую колонку и выполнить миграцию туда. Оно нам надо? То есть использования состояния это безопасно и расширяемо в отличие от флагов.
Но даже этого может быть недостаточно. Следующим шагом будет использование конечных автоматов https://github.com/eram/typescript-fsm (в том случае если нужна реакция на переходы, а сама структура переходов не линейная)
Ссылки: Телеграм | Youtube | VK
👍131❤29🔥12🤔2👀1
Мы с Саматом раньше лично не были знакомы, но всегда крутились в одной технической тусовке. Я давно хотел записать с ним выпуск, потому что мне интересен путь, который он прошёл — как технарь превращается в предпринимателя. Я регулярно делаю подкасты на эту тему, и нам было важно разобрать его историю: он пришёл к бизнесу через запуск собственного аутсорса, а не через стартапы. В этом разговоре мы обсудили, как из разработчика вырастаешь в владельца сервиса, переход от аутсорса к продуктам, изменения на рынке и почему продажи часто важнее кода. Мы говорили о найме и проверке разработчиков, об испытательном сроке как фильтре, а также о скучных, но прибыльных нишах, автоматизации рутины и подводных камнях работы с клиентами.
https://youtube.com/watch?v=T7WsVGtKZJw
Альтернативные ссылки: Аудио | vk
https://youtube.com/watch?v=T7WsVGtKZJw
Альтернативные ссылки: Аудио | vk
YouTube
Самат Галимов: экс-CTO «Медузы» о найме, клиентах и деньгах в аутсорсе | #56
Мы с Саматом раньше лично не были знакомы, но всегда крутились в одной технической тусовке. Я давно хотел записать с ним выпуск, потому что мне интересен путь, который он прошёл — как технарь превращается в предпринимателя. Я регулярно делаю подкасты на эту…
103👍58🤮18❤11👎7🔥7⚡5🖕3💊1
ИИ для проверки качества уроков на Code Basics
Какое-то время назад на проекте https://code-basics.com/ru я внедрил ассистента на базе chatgpt, который помогает в каждом уроке. Причем он знает весь контекст включая задание, тесты к нему, код студента и вывод тестов после запуска. Им начали пользоваться так активно, что пришлось включить дневные лимиты, так как стали приходить нехилые счета на, по сути, бесплатном продукте.
Спустя какое-то время, стало понятно, что вопросы, которые задают пользователи, дают очень качественную обратную связь, по тому что в каждом конкретном уроке можно поправить и улучшить. Но вопросов много и далеко не все из них помогают, поэтому ручками их анализировать проблематично.
А что если написать код, который будет брать вопросы пользователей каждого конкретного урока и отправлять их туда же в chatgpt с инструкцией "суммируй и предложи улучшения по уроку"? Сказано сделано, вчера буквально за пол дня зафигачил эту фичу (ее можно глянуть в исходниках). И теперь по каждому я вижу примерно такой вывод:
Семантические и логические ошибки
⁃ Не понимают, что означает пустая строка — что именно считать пустым ("" или " ").
⁃ Отсутствует понимание, что возвращать: что значит "true", "false" (пытаются явно конвертировать int к bool, чего делать нельзя).
⁃ Не разобрались с проверкой условий: >=0, >0, != "" и т.д.
⁃ Запутались с тем, является ли 0 положительным числом (спрашивают об этом).
Ну не красота ли?
Ссылки: Телеграм | Youtube | VK
Какое-то время назад на проекте https://code-basics.com/ru я внедрил ассистента на базе chatgpt, который помогает в каждом уроке. Причем он знает весь контекст включая задание, тесты к нему, код студента и вывод тестов после запуска. Им начали пользоваться так активно, что пришлось включить дневные лимиты, так как стали приходить нехилые счета на, по сути, бесплатном продукте.
Спустя какое-то время, стало понятно, что вопросы, которые задают пользователи, дают очень качественную обратную связь, по тому что в каждом конкретном уроке можно поправить и улучшить. Но вопросов много и далеко не все из них помогают, поэтому ручками их анализировать проблематично.
А что если написать код, который будет брать вопросы пользователей каждого конкретного урока и отправлять их туда же в chatgpt с инструкцией "суммируй и предложи улучшения по уроку"? Сказано сделано, вчера буквально за пол дня зафигачил эту фичу (ее можно глянуть в исходниках). И теперь по каждому я вижу примерно такой вывод:
Семантические и логические ошибки
⁃ Не понимают, что означает пустая строка — что именно считать пустым ("" или " ").
⁃ Отсутствует понимание, что возвращать: что значит "true", "false" (пытаются явно конвертировать int к bool, чего делать нельзя).
⁃ Не разобрались с проверкой условий: >=0, >0, != "" и т.д.
⁃ Запутались с тем, является ли 0 положительным числом (спрашивают об этом).
Ну не красота ли?
Ссылки: Телеграм | Youtube | VK
🔥100👍36❤16🤣5🤮2👎1👀1
Сложность обучающих материалов
Продолжаем тему "я у мамы методист". Когда мы пишем что-то для других людей, то один из первых вопросов, который всплывает в голове, а на какую аудиторию мы рассчитываем с точки знания предмета? Допустим мы делаем курс по реакту. Надо ли нам делать его для тех кто не знает js (не знает программирование вообще или знаком с другим языком)? А если знает то насколько? Человек уже работал с браузером и понимает как устроен DOM или ему в целом надо рассказывать основы про браузер, про события и все остальное?
Существуют разные подходы к тому чтобы определить аудиторию, но здесь я бы хотел рассказать про восприятие контента студентами и негатив, который вы получите если сделаете неудачно. Ниже я привожу примеры на основе курсов, но это так же актуально и для статей и для видео и для репетиторов и групповых занятий.
Допустим для конкретного человека сложность вашего курса оказалась ниже чем он рассчитывал, то есть с его точки зрения этот курс для более новичкового уровня, чем его собственный. Как он будет воспринимать происходящее? В подавляющем большинстве случаев он будет проходить его дальше, если он верит в то, что дальше таки будет нужный ему материал. Если нет, то худшее что вы можете получить это реакция: "слишком поверхностно". Прямо негатив что курс полное говно в таких кейсах почти никогда не встречается.
Теперь обратная ситуация, ваш курс оказался сложнее, чем рассчитывал человек. Причем природу этой сложности он вряд ли поймет, так как не понимает саму тему. Из-за этого все сводится к двум возможным сценариям "я слишком тупой" и "курс говно". Оба сценария плохие. Здесь мы получаем по полной, начиная от возврата денег, заканчивая жесткими отзывами на соответствующих площадках и просто в соцсетях.
То есть при прочих равных, материалы лучше делать с расчетом на менее прокаченную аудиторию, потому что опытные ребята поймут, что происходит и почему так, а не опытные вставят вам пистонов по самое не балуй.
Это не значит что не бывает курсов для профи. Бывает, но все упирается в то, как вы собираете аудиторию и что пишите в описании к курсу. Крайне важно правильно проработать ожидания, например, говорить о том, какой входной уровень ожидается. Отлично если в этом месте будут возникать входные тесты.
Пример. Школы часто пишут "курс: go с нуля" имея ввиду что с нуля в Go, но не с нуля в программировании. И на выходе мы получаем немало людей, которые в шоке от сложности контента.
p.s. Нам кстати нужны авторы курсов по программированию, тестированию, аналитике и администрированию. Пишите в комментариях если вам интересно.
https://making.hexlet.io/
Ссылки: Телеграм | Youtube | VK
Продолжаем тему "я у мамы методист". Когда мы пишем что-то для других людей, то один из первых вопросов, который всплывает в голове, а на какую аудиторию мы рассчитываем с точки знания предмета? Допустим мы делаем курс по реакту. Надо ли нам делать его для тех кто не знает js (не знает программирование вообще или знаком с другим языком)? А если знает то насколько? Человек уже работал с браузером и понимает как устроен DOM или ему в целом надо рассказывать основы про браузер, про события и все остальное?
Существуют разные подходы к тому чтобы определить аудиторию, но здесь я бы хотел рассказать про восприятие контента студентами и негатив, который вы получите если сделаете неудачно. Ниже я привожу примеры на основе курсов, но это так же актуально и для статей и для видео и для репетиторов и групповых занятий.
Допустим для конкретного человека сложность вашего курса оказалась ниже чем он рассчитывал, то есть с его точки зрения этот курс для более новичкового уровня, чем его собственный. Как он будет воспринимать происходящее? В подавляющем большинстве случаев он будет проходить его дальше, если он верит в то, что дальше таки будет нужный ему материал. Если нет, то худшее что вы можете получить это реакция: "слишком поверхностно". Прямо негатив что курс полное говно в таких кейсах почти никогда не встречается.
Теперь обратная ситуация, ваш курс оказался сложнее, чем рассчитывал человек. Причем природу этой сложности он вряд ли поймет, так как не понимает саму тему. Из-за этого все сводится к двум возможным сценариям "я слишком тупой" и "курс говно". Оба сценария плохие. Здесь мы получаем по полной, начиная от возврата денег, заканчивая жесткими отзывами на соответствующих площадках и просто в соцсетях.
То есть при прочих равных, материалы лучше делать с расчетом на менее прокаченную аудиторию, потому что опытные ребята поймут, что происходит и почему так, а не опытные вставят вам пистонов по самое не балуй.
Это не значит что не бывает курсов для профи. Бывает, но все упирается в то, как вы собираете аудиторию и что пишите в описании к курсу. Крайне важно правильно проработать ожидания, например, говорить о том, какой входной уровень ожидается. Отлично если в этом месте будут возникать входные тесты.
Пример. Школы часто пишут "курс: go с нуля" имея ввиду что с нуля в Go, но не с нуля в программировании. И на выходе мы получаем немало людей, которые в шоке от сложности контента.
p.s. Нам кстати нужны авторы курсов по программированию, тестированию, аналитике и администрированию. Пишите в комментариях если вам интересно.
https://making.hexlet.io/
Ссылки: Телеграм | Youtube | VK
making.hexlet.io
Образовательные проекты Хекслета
Делитесь своим опытом в программировании, развивайте новые навыки и компетенции, растите в цене и получайте дополнительный доход!
👍35❤18🔥6🤔2😁1👀1
Тот случай, когда фичи ruby позволяют создать сложный для восприятия код (if после выражения и ||=). Здесь идет попытка добавить логику, которая избегает запроса в базу если id не передан
Как бы вы переписали его? Пулреквест вот: https://github.com/hexlet-basics/hexlet-basics/pull/605 он еще не принят
Как бы вы переписали его? Пулреквест вот: https://github.com/hexlet-basics/hexlet-basics/pull/605 он еще не принят
😱8👍2