Организованное программирование | Кирилл Мокевнин
9.97K subscribers
53 photos
199 links
Как из джуниора дойти до мидла, а потом и до синьора
Ютуб https://youtube.com/@mokevnin
Связь для предложений: @kirillpublic
Download Telegram
Синхронные VS Асинхронные дейли

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

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

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

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

В итоге перешли и остались довольны. Пример того как это работает можно посмотреть тут https://geekbot.com/

p.s. Какой дейли у вас в компании? Это эффективно иль нет?
В ближайшие месяцы хотим провести экскурсии в it компании для студентов нашего колледжа https://hexly.ru/ Это Москва, Питер и Новосиб. Ребят если вы можете это организовать или есть кому/кого посоветовать, то напишите плс. Лайк шер алишер.
Ревью кода, которые не тормозят

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

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

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

По каким критериям можно разбивать задачу?

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

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

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

p.s. Вы страдаете от процесса проверки пулреквестов у вас в компании?
Парный кодинг для всех

Про парное программирование слышали наверное все, но все ли его практикуют?

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

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

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

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

Научные исследования https://tuple.app/pair-programming-guide/scientific-research-into-pair-programming
Отличный доклад на тему https://www.youtube.com/watch?v=Vu5ujdZDS6E

p.s. Практикуете ли вы парное программирование у себя в компании?
simple git hook для всех
Вы знаете что можно удобно управлять хуками в git с помощью либы simple-git-hook?

Два действия:

1. Ставится эта либа через npm
2. Прописывается нужная команда на нужный хук в package.json
3. Запускается команда npx simple-git-hooks, которая все сама апдейтит



{
"simple-git-hooks": {
"pre-commit": "npx lint-staged",
"pre-push": "cd ../../ && npm run format",

// All unused hooks will be removed automatically by default
// but you can use the `preserveUnused` option like following to prevent this behavior

// if you'd prefer preserve all unused hooks
"preserveUnused": true,

// if you'd prefer preserve specific unused hooks
"preserveUnused": ["commit-msg"]
}
}


Шикарная вещь, ставим во все наши опенсорсы и внутренние проекты.

p.s. Какие подобные улучшалки вы еще знаете?
Делать ли livecoding на собесе

Тут в твиттере разгорелось после того как Козуля написал о лайвкодинге, который не проходят люди подделавшие резюме. Твит раз https://twitter.com/vladkozulya/status/1754986992570450283 твит два https://twitter.com/vladkozulya/status/1755209744057299174

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

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

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

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

p.s. Вы делаете лайвкодинг? Проходите его сами и завалили?
p.s.s. Задачка на разминку: Какой угол между часовой и минутной стрелкой когда на часах 15:15? 🙂
Переписывание редактора Хекслета на TS

Давно я не махал шашками серьезно, а тут полез поправить одну штуку в редактор, ну и как-то затянуло и в итоге уже третью неделю я переписываю его с JS на TS. Заодно так сказать вливаюсь в современные тренды. Я еще не закончил, но история уже получается прикольная, что я даже пытаюсь податься с докладом на holyjs, чтобы там про это рассказать.

Здесь я поделюсь немного разными мыслями, которые возникли в процессе. Понимаю что для многих это банальщина так как TS щас используют все, но вдруг кому будет интересно и даже полезно. Посвящу этот пост бекенду на Next.js

Первое что я сделал это заменил бек fastify на nextjs. Я люблю fastify, но мне хотелось снизить уровень конфигурирования до минимума. Это получилось, что-что, а вот тут next работает из коробки очень хорошо. Иногда все же приходится рестартовать, когда почему-то стейт не обновляется на беке, но в целом оно как-то само там магически работает и достаточно легко поддается легкой кастомизации если надо.

Что удивило, это поддержка бека. Правда вебсокеты подрубаются как костыль и команда разработки не очень спешит заниматься этим вопросом, так как для их платформы Vercel это не вещь, которая принесет деньги. Из-за этого получилось что я одновременно для части апи использую старый роутинг pages, а для части новый в app. Это рекомендация во всех issues.

Из странного, некст не показывает access логи к апи. Если что-то не так, ты вообще не понимаешь что не так. Опций никаких нет, в ишьюсе тихо. Понятно что api не приоритет.

Их хорошего, за счет того что у неста все же есть бек и мне он подходит, то получилось что не надо стартовать два отдельных приложения и менеджерить их. А это всегда требует доп усилий, в таких случаях, надо поставить что-то типа foreman (pm2) или docker compose.

В целом у редактора бекенд очень небольшой, буквально вебсокеты с rpc на 15 действий поверх него и пара rest эндпоинтов. Некст такое обрабатывает легко. Но если бы у меня был по настоящему большой и развесистый бекенд, то я бы брал fastify.
Кладбище забытых проектов

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

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

Кое что все таки оставил, одна часть это опенсорс, который может и не стал невероятно популярным, но все же я понаделал разного добра: отправил кучу пулреквестов (недавно у меня приняли пулреквест из php либы, который я года три-четыре назад сделал), создал немного относительно популярных библиотек, собрал большой список тестовых заданий, который наверное стал самым популярным из того что я начинал (но это не код хаха) https://github.com/Hexlet/ru-test-assignments.

Вторая это Хекслет, которым я занимаюсь уже 11 лет. Есть чем городиться, это довольно крутая техническая штука, которая даже легла в основу книги https://painlessrails.com/book/ Несмотря на размер (а Хекслет довольно большой) и возраст, он в отличном состоянии и поддерживается очень небольшой профессиональной командой. Но так как он свой, почему-то нет ощущения, что я сделал что-то как программист, с чужими это как-то по другому работает)

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

p.s. Что самого крутого сделали вы?
Шаблоны проектирования

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

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

Большая часть шаблонов, которые описаны в известных книгах, посвящены конкретным кускам кода, а не архитектуре в целом. Честно говоря их влияние на систему не такое большое, как об этом принято думать или написано в этих же книгах, в отличии от архитектурных шаблонов типа MVC.

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

• Убирает ифы из кода. Да вот так вот просто.
• Позволяет управлять кодом через конфигурацию, когда мы не очередной иф вставляем или правим сам код где используется объект, а мы в конфигурации приложения меняем реализацию. В основном это делается в библиотеках, которые мы можем конфигурировать. На уровне приложений такое применяется там где есть контейнеры зависимостей, например, активно в php и java фреймворках. Редко в js, go, python, ruby.

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

p.s. Часто ли вы используете паттерны?
p.s.s. Домашнее задание: Какой паттерн используется в ситуации, когда вы хотите иметь возможность подменить базу данных, в течении жизни приложения (например переехать с одной на другую) без изменения кода (в теории)
План на ближайшие посты по шаблонам проектирования
Тема с шаблонами зашла, она как обычно вызывает разные чувства, но комментариев много и интерес есть. Я хочу сделать цикл прямо обучающих постов, в которых мы кое что разберем. Однако, сразу хочу обозначить. Это ни в коем случае не стандартное вот шаблон вот поехали. Мы попробуем разобраться со смысловой частью программирования, в которой появляются шаблоны с рассмотрением проблемы, альтернатив, плюсов минусов и так далее. И что важно, даже когда мы будем говорить про паттерны, мы не будем говорить про набор классов как это описано в большинстве мест, мы будем говорить про организацию кода, которая решает реальную проблему, не зависимо от того, на каком языке мы пишем. На выходе у вас должно появиться более четкое понимание проблем, которые вызывает сложный код и как это код можно упростить (или усложнить) разными решениями. Первый пост будет завтра, а тут немного комментариев на те комментарии, которые вы оставляли к посту:

> С тех пор как ушел на го, то сразу исчез этот мешок барахла в голове. Максимум на практике встречаются декораторы. Но у меня в конторе не фанатики писать код по книгам. Используем там где уместно, а уместно прям мало где. Но это в го.

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

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

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

> Интересно, кто-то на практике сталкивался с потребностью поменять базу во время жизни приложения?

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

> А в чем вообще разница между медиатором и адаптером?)

Поговорим) Однако тут надо идти от проблематики, в которых эти паттерны возникают.

p.s. Знаете ли вы что такое динамическая диспетчеризация и мультидиспетчеризация?
Шаблоны проектирования: Синглотон
Начнем с чего-то наиболее простого, но наиболее известного. Синглотон, это объект, который создается ровно в одном экземпляре и за этим не надо следить, он сам за этим следит за счет того как его реализуют.


public class Singleton {
// The volatile keyword ensures that multiple threads handle the uniqueInstance variable correctly when it is being initialized to the Singleton instance.
private static volatile Singleton uniqueInstance;

// private constructor so no one can instantiate the class from outside
private Singleton() {}

// Method to return an instance of the class
public static Singleton getInstance() {
// First check without locking to improve performance
if (uniqueInstance == null) {
// Locking the class object to only let one thread in to check and instantiate the singleton
synchronized (Singleton.class) {
// Double-check whether the instance is null or not to ensure that no two instances are created
if (uniqueInstance == null) {
uniqueInstance = new Singleton();
}
}
}
return uniqueInstance;
}

// other useful methods here
}


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

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

Но как это ни странно, все же есть разные экосистемы с разными порядками. Например эталонный пример где синглотоны никак не нужны и не используются почти никогда это spring (boot), так как там крутой контейнер зависимостей, который решает проблему доступа и управляет жизненным циклам объектов. В JavaScript, Python и Ruby подобные синглотоны встречаются, но в другой реализации. В JavaScript и Python иногда делают файлы, в которых формируются данные/объект, который может быть импортирован куда-то и этот объект инициализирован ровно один раз, так как сам файл интерпретируется только один раз. В Ruby такое принято и в самой Rails и в ее библиотеках, когда класс содержит статическое поле с объектом. Да это сильно упрощает написание кода (так как нет контейнера) и помогает новичкам, но иногда больно стреляет и если не следить за абстракциями, делает из кода кашу. Кстати поэтому в тестах на Ruby часто встречается такое когда синглотон меняют в начале теста и потом возвращают обратно в конце. Подобные хаки для синголотон встречаются и в других языках, я точно такое делал сам на php

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

Про альтернативу синголотоном можно прочитать тут: https://en.wikipedia.org/wiki/Dependency_injection

p.s. Вы сталкивались с проблемами в использовании синглотонов?
Шаблон проектирования: Команда

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

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

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

В случае Java это объект-команда.


var button = new Button();
// У команды есть один интерфейсный метод execute()
var command = new CopyCommand();
button.setCommand(copy);
// Кнопка добавляется в интерфейс


В случае JS это обычная анонимная функция, которая вешается на событие. Собственно сам механизм реакции на события это и есть реализация паттерна команда.


const button = document.getElementById('myButton');

// Adding a click event listener to the button
button.addEventListener('click',() => {
// Тут может быть напрямую зашитая логика
// Если логика повторяется, то она может быть вынесена куда-то,
// а здесь только вызов
});


Если посмотреть описание этого паттерна, то видно, что оно довольно сильно заточено под классовые языки. Там как преимущество говорится о том, что если сделать команду объектом, то ее можно использовать как данные, передавать куда-то, записывать и так далее. В языках где все нормально с функциями высшего порядка, такой проблемы нет. Поэтому и паттерн команда там реализуется настолько просто, что даже возникает вопрос “для этого нужен паттерн?”. Но по смыслу команда там есть, даже если код очень простой.

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

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

p.s. Вам приходилось реализовывать команду в своей практике?
Шаблон проектирования: Стратегия

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

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


// ChatGPT
async function fetchUserData(userRole, userId = null) {
let queryOptions = {};

if (userRole === 'admin') {
// Admin gets access to all users
queryOptions = {};
} else if (userRole === 'user') {
// Regular user gets only their data
queryOptions = {
where: {
id: userId
}
};
}

try {
const users = await User.findAll(queryOptions);
console.log(users);
} catch (error) {
console.error('Error fetching user data:', error);
}
}

// Example usage
fetchUserData('admin'); // Fetches all users for admins
fetchUserData('user', 1); // Fetches data for user with id 1


Эту задачу логично начинать решать обычным набором ифов, которые проверяют тип пользователя и дальше формируют правильный запрос. В большинстве случаев для подобной задачи нам хватит, но если сложность выборки вырастет до определенного уровня за счет доп. условий и/или количества новых ролей, то анализировать такой код станет крайне затруднительно. Это связано с тем, что сложно вычленить конкретную роль и то что будет выведено для нее с одной стороны, а с другой, любое изменение потребует постоянного анализа “а как это скажется на остальных”. Вероятность ошибки тут крайне высокая и через такие решения проходил не мало в своей жизни, когда делаешь изменение для одной ветки, а ломаются другие.

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

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

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

p.s. Расскажите про свои ситуации, где стратегия помогала снизить сложность?
PHP работы пост: Ищу Laravel-разработчика с фронтенд опытом на проектную работу для нашего колледжа https://mokevnin.notion.site/a62fc9b140df44609ee2b365d70f4e90?v=ecb6fa57cfe84022add265b6b574c2d1&p=a0195e34c32c4c6fb622662cdfe4b83a&pm=c стоимость проекта будет считаться исходя из 2000 руб/час, ориентировочно месяц на разработку, дедлайн 15 мая. Я соучаствую, помогаю с архитектурой, инфрой и ревью
Редактор Хекслета: JS => TS

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

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

За это всегда прилетает и нам тут же прилетело. Любые изменения людей напрягают если они ломают стандартные пути работы. Пользователям сложно, а порой невозможно объяснить, что движение вперед невозможно без ломания того, что было раньше. Если все время поддерживать статус кво (как было), то мы в какой-то момент не сможем вносить изменения и молодая шпана снесет нас с лица земли.

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

p.s. Все нужные фиксы мы внесли в течении дня, щас редактор уже лучше чем был и готов к расширению без боли
Что такое полимофризм?

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

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

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

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

Допустим мы работаем с беком по апи и для этого используется спец либа, а не просто fetch запросы. У гитхаба есть подобная либа: https://github.com/octokit/rest.js Дальше вы решили написать тесты к своему коду и столкнулись с проблемой, что в тестах улетают запросы на реальный github, что не правильно. В тестах во внешние системы не ходят (кстати вы знаете почему?). Как выйти из этой ситуации?

• Либа может сама содержать такую функциональность. Ставится какой-нибудь флаг и она не шлет запросы
• Подход, который довольно популярен в JavaScript (и Ruby) это манки патчинг. С помощью либы https://github.com/nock/nock которая патчит низкоуровневый код и подменяет его фейком, который не делает никаких запросов.
• С помощью ифов
• Как развитие предыдущего пункта, с помощью полиморфизма

Поговорим о последних двух. Мы легко могли бы расставить по коду проверки на окружение:


if (process.env.NODE_ENV === ‘testing’) {
// ничего не делаем
} else {
// реальный запрос
}


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

Выйти из этой ситуации можно с помощью применения полиморфизма. Для этого понадобится продублировать библиотеку octokit/rest.js но внутри, вместо реальных запросов, например, складывать данные в свойства объекта-библиотеки. Дальше, в отдельном файле пишем:


let octokit;
if (process.env.NODE_ENV === ‘testing’) {
octokit = new OctokitFake();
} else {
octokit = new Octokit();
}

export octokit;


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

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

p.s. Мастхев для чтения: https://guides.hexlet.io/ru/usefull-twitter-threads/#мифы-вокруг-ооп

p.s.s. Требуется ли для полиморфизма подтипов наличие ооп?)
Решил попробовать добавлять в вакансию вот такой блок, чтобы кандидаты могли оценить сами себя и понять стоит ли приходить или нет. Как думаете, поможет улучшить воронку?