По ощущениям мне кажется (ссылок на пабмед не будет), что книги Мартина сформировали наибольшее количество фанатиков. Они написаны в таком безапелляционном стиле и на словах пропагандируют за всё хорошее и против всего плохого. На мой вкус, виноваты не только фанатики.
Хотя, возможно, это я просто так рационализирую то, что когда-то сам был фанатиком...
Роберт Мартин — отличный пропагандист и так себе программист. Одно то, что он называет себя "дядюшкой Бобом", уже прекрасный прием, чтобы втереться в доверие. Но какой он мне, блин, дядюшка?
Если внимательно почитать примеры кода из "Чистого кода" , можно охренеть от того, как этот "дядюшка" на ровном месте усложняет нормальное решение. Я бы такого "улучшенного" кода в своих рабочих сорсах видеть не хотел. А если код из книги его сложный для восприятия, то зачем следовать принципам, которые он в этой книге продвигает?
Кажется, в 2025 году уже точно стоит прекратить не только молиться на "Чистый код", но и перестать его советовать в принципе. А на собсесах начать проверять не знание принципов SOLID, а наоборот — спрашивать, почему эти принципы не стоит использовать.
ООП — это про обмен сообщениями, внутренний стейт объектов и позднее связывание. Почитайте или посмотрите про Алана Кея — человека, который придумал ООП.
Самый ООПшный язык — это вообще Erlang, но в нем нет ни классов, ни наследования, даже нет переменных в привычном понимании.
Не путаю. Если грубо, то каждый for, while и if добавляют по единице к цикломатической сложности. У вас программа может зайти в for, а может и не зайти, если не по чему итерироваться. Получается, что for — это тоже своего рода ветвление, которое добавляет дополнительный уникальный путь исполнения в программе.
Цикломатическая сложность не лучше. Вы же делаете map по children внутри flatMap'ы. В итоге получается тот же цикл внутри цикла. Потом, когда нужно пройти фильтром по всем-всем child'ам, вы точно такое же количество раз вызываете проверку на вхождение Child.id в childIds.
Магии не бывает. Как бы не было записано решение, для него в любом случае потребуется вложенный цикл и одно ветвление внутри цикла (на самом деле два ветвления, потому что для пустой группы нужно установить значение 'NoGroup')
Мужики, ну хорош! Проблема же банальная, и код должен быть таким же банальным:
const getChildrenByGroup = (childIds, parents) => {
const result = {};
for (const parent of parents) {
for (const child of parent.Children) {
if (!childIds.includes(child.Id)) continue;
const groupName = parent.GroupName || 'NoGroup';
if (!result[groupName]) result[groupName] = [];
result[groupName].push({ ...child, ParentName: parent.Name });
}
}
return result;
};
Если вложенные циклы почему-то пугают и хочется "функциональшины", то можно так. Читать и изменять такое сложнее, но хотя бы используются только стандартные методы, о которых знают все разработчики на js:
Если как и вы упороться в редактирование, то можно получить даже не 7 строчек на всю функцию, а всего лишь 5. И это без ненужных импортов и кастомных функций типа pipe и innerJoin:
В статье произошло то, что постоянно наблюдаю практически в каждой компании — фронтендеры сами создают себе проблемы, а потом героически и очень муторно их решают. Видимо, так сложно принять, что фронтенд — это не рокетсайнс.
window.SENTRY.captureEvent -> import('/sentry').then({captureEvent} => ...), если быть точным, я думал это и так понятно.
Тогда можно использовать абсолютно любой подход, ленивая загрузка будет из коробки :)
Вы зачем-то чистый доменный код разбавляете системной логикой (аналитикой) или другим доменом (подсказки, например)
Что такое этот ваш доменный код в разрезе фронтенд-приложений? Если что, синюю книжку Эванса читал, DDD в реальных проектах видел (не понравилось).
Как по мне, во фронтеде очень мало того, что вы называете доменной логикой. Основная и самая большая часть фронтенд-приложения -- это application-код, который в себе соединяет все "домены" и "системную логику". Можно, конечно, прятать эту основную работу за сложными абстракциями, но тогда спрятанными оказываются ещё и самые интересные баги, а реализация "сложных" сценариев занимает недели и месяцы вместо дней.
Нам же во фронте нужно сфетчить данные, трансформировать их в удобные для отображения структуры данных, сгенерить из структур html, мутировать эти структуры в зависимости от действий пользователя, трансформировать в формат, понятный бэку, и отправить по сети. Попытки с умным лицом засовывать в эту цепочку какие-то "сложные" вещи обычно оборачиваются проблемами для проекта. Лучше смириться с тем, что с точки зрения классического программирования мы -- как фронтендеры -- реализуем в основном довольно простые алгоритмы, но у нас есть свои интересные сложности в работе, просто они немного в другой плоскости: реализация удобных кастомных селектов, которые будут работать во всех браузерах; вёрстка страниц, которая на всех разрешениях выглядит хорошо; минимизация потребления ресурсов, чтобы пользователи на обычных компьютерах не страдали.
Что-то я растёкся мыслею, поэтому повторю вопрос: что такое этот ваш доменный код в разрезе фронтенд-приложений?
EE - достаточно общий и часто применяемый паттерн, глупо говорить что он вообще не нужен.
Может и нужен, но точно не в таком простом виде. В эвентах должна быть какая-то практическая изюминка. В событийной модели DOM'а есть всплытия событий, в очередях -- возможность подписываться на события по паттерну типа on('form-*-changed', doSomething). Но когда события добавляются только для создания decoupling'а, потому что это "правильно" и Боб Мартин с Мартином Фаулером про это писали, то от такого паттерна только вред
По ссылке вы частично описали тоже самое, что и в этом комменте, но я всё равно не понимаю.
Ну вот есть у вас такой код. Вы пишите, что хотите подгружать аналитику лениво, поэтому нужен декаплинг на эвентах
Но у вас же загрузка тяжёлой библиотеки в бандл будет происходить не в файле ~/features/some/analytics.ts, а где-то, где вы пропихиваете SENTRY внутрь window. Получается, в ленивом импорте здесь не будет никакого смысла.
Вы в телеграме ещё пишите, что моделей, которые нужно обмазать аналитикой, много. Но это тоже никак не мешает линейному коду. Если писать совсем просто и линейно, то эвенты проиграют в количестве кода, который нужно написать для подключения аналитики. Вот так будет выглядеть мой код:
// ~/analytics.ts
export function sendMsg(msg: string) {
window.SENTRY.captureEvent({ message: msg });
}
// ~/some/model-1.ts
import * as analytics from '~/analytics.ts';
export function submit() {
// Какой-то код сабмита
analytics.sendMsg('model-1 form submit');
}
// ~/some/model-2.ts
import * as analytics from '~/analytics.ts';
export function submit() {
// Какой-то код сабмита
analytics.sendMsg('model-2 form submit');
}
// ~/some/model-n.ts
import * as analytics from '~/analytics.ts';
export function submit() {
// Какой-то код сабмита
analytics.sendMsg('model-n form submit');
}
Зачем тут эвенты? Чем вызов функции из модуля отличается от эвента конкретно в этой ситуации? Эвент здесь просто добавит indirection на ровном месте, который при отладке, фиксе багов или добавлении фичей будет только создавать головную боль.
Вот ещё ваш аргумент из телеграма: Есть процесс оформления заказа. Отдельно пилится менее важный, но полезный модуль подсказок, который никак с критичным процессом оформления не должен быть связан.
Что значит "никак с критичным процессом не должен быть связан"? Подсказки же всё равно будут связаны с процессом, просто неявно. Типа, если явной связи не видно, то связи вообще нет? Но оно так не работает :) Если под отсутствием связи вы понимаете, что код подсказок может падать, и это никак не должно влиять на процесс оформления, то для таких случаев есть try/catch или catch у промисов. Можно писать как-то так
const noop = () => null;
async function createOrder() {
// Какой-то важный код
await tips.showSomeTip().catch(noop);
// Продолжение важного кода
await tips.showOtherTip().catch(noop);
}
Такой подход простой как палка, поэтому любое изменение фичи, фикс бага, добавление функциональности делается явно. Весь код, который нужен для понимания происходящего в рантайме, можно посмотреть в IDE с помощью Go To Definition. Такой код использует возможности языка и не обязывает читателя знать какие-то специфические библиотеки.
Чем дольше живу, тем меньше понимаю, зачем усложнять код событийной моделью, если всё можно написать сверху-вниз и слева-направо внутри самой вызываемой функции
В посте для аргументов стратегии используется any, в вашем случае тоже придётся пожертвовать типизацией аргументов. Можно пойти немного дальше и сохранить типы:
Зашёл, чтобы оставить похожий комментарий. С самого начала текста создалось впечатление "Я где-то на YouTube смотрел точно такой же ролик". Спасибо за ссылку!
А ещё мне кажется, что этот текст писал не человек, а какой-то алгоритм, как это недавно было с новостями на Hacker News
Я не разбираюсь в законах РБ, по-этому ваше утверждение "[Во время обыска в компании] Личные вещи – это все что находится в ваших карманах или ваших руках." для меня немного контринтуитивно.
Можете, пожалуйста, привести конкретные законы и статьи, на которые может ссылаться сотрудник, если в его компанию пришли с обыском?
Потому что JSON — это модно. Шутка. Может потому что я описал процесс скраббинга данных и его можно повторить. Товарищи могут в них не верить, я не настаиваю.
Мне не очень нравится риторика и визуализация Шпилькина, вот я и стянул данные сам. В свободное время буду их ковырять. Данных мне не жалко, поэтому я и скинул ссылку сюда
По ощущениям мне кажется (ссылок на пабмед не будет), что книги Мартина сформировали наибольшее количество фанатиков. Они написаны в таком безапелляционном стиле и на словах пропагандируют за всё хорошее и против всего плохого. На мой вкус, виноваты не только фанатики.
Хотя, возможно, это я просто так рационализирую то, что когда-то сам был фанатиком...
Спасибо за рекомендацию! Уже не первый раз встречаю положительный отзыв на эту книгу. Надо бы почитать
Учусь маркетингу у лучших представителей айти!
Роберт Мартин — отличный пропагандист и так себе программист. Одно то, что он называет себя "дядюшкой Бобом", уже прекрасный прием, чтобы втереться в доверие. Но какой он мне, блин, дядюшка?
Если внимательно почитать примеры кода из "Чистого кода" , можно охренеть от того, как этот "дядюшка" на ровном месте усложняет нормальное решение. Я бы такого "улучшенного" кода в своих рабочих сорсах видеть не хотел. А если код из книги его сложный для восприятия, то зачем следовать принципам, которые он в этой книге продвигает?
Кажется, в 2025 году уже точно стоит прекратить не только молиться на "Чистый код", но и перестать его советовать в принципе. А на собсесах начать проверять не знание принципов SOLID, а наоборот — спрашивать, почему эти принципы не стоит использовать.
ООП — это про обмен сообщениями, внутренний стейт объектов и позднее связывание. Почитайте или посмотрите про Алана Кея — человека, который придумал ООП.
Самый ООПшный язык — это вообще Erlang, но в нем нет ни классов, ни наследования, даже нет переменных в привычном понимании.
У вас есть положительный опыт использования такого обоснования?
Огонь! Ждал подобной статьи с самого первого дня, как познакомился с Эффектором.
Теперь жду чего-то подобного про FSD. Как раз недавно была статья от ВК о начале использования FSD в каком-то проекте :)
Не путаю. Если грубо, то каждый for, while и if добавляют по единице к цикломатической сложности. У вас программа может зайти в for, а может и не зайти, если не по чему итерироваться. Получается, что for — это тоже своего рода ветвление, которое добавляет дополнительный уникальный путь исполнения в программе.
Цикломатическая сложность не лучше. Вы же делаете map по children внутри flatMap'ы. В итоге получается тот же цикл внутри цикла. Потом, когда нужно пройти фильтром по всем-всем child'ам, вы точно такое же количество раз вызываете проверку на вхождение Child.id в childIds.
Магии не бывает. Как бы не было записано решение, для него в любом случае потребуется вложенный цикл и одно ветвление внутри цикла (на самом деле два ветвления, потому что для пустой группы нужно установить значение 'NoGroup')
Мужики, ну хорош! Проблема же банальная, и код должен быть таким же банальным:
Если вложенные циклы почему-то пугают и хочется "функциональшины", то можно так. Читать и изменять такое сложнее, но хотя бы используются только стандартные методы, о которых знают все разработчики на js:
Если как и вы упороться в редактирование, то можно получить даже не 7 строчек на всю функцию, а всего лишь 5. И это без ненужных импортов и кастомных функций типа pipe и innerJoin:
В статье произошло то, что постоянно наблюдаю практически в каждой компании — фронтендеры сами создают себе проблемы, а потом героически и очень муторно их решают. Видимо, так сложно принять, что фронтенд — это не рокетсайнс.
Что не так с идеей брака?
Тогда можно использовать абсолютно любой подход, ленивая загрузка будет из коробки :)
Что такое этот ваш доменный код в разрезе фронтенд-приложений? Если что, синюю книжку Эванса читал, DDD в реальных проектах видел (не понравилось).
Как по мне, во фронтеде очень мало того, что вы называете доменной логикой. Основная и самая большая часть фронтенд-приложения -- это application-код, который в себе соединяет все "домены" и "системную логику". Можно, конечно, прятать эту основную работу за сложными абстракциями, но тогда спрятанными оказываются ещё и самые интересные баги, а реализация "сложных" сценариев занимает недели и месяцы вместо дней.
Нам же во фронте нужно сфетчить данные, трансформировать их в удобные для отображения структуры данных, сгенерить из структур html, мутировать эти структуры в зависимости от действий пользователя, трансформировать в формат, понятный бэку, и отправить по сети. Попытки с умным лицом засовывать в эту цепочку какие-то "сложные" вещи обычно оборачиваются проблемами для проекта. Лучше смириться с тем, что с точки зрения классического программирования мы -- как фронтендеры -- реализуем в основном довольно простые алгоритмы, но у нас есть свои интересные сложности в работе, просто они немного в другой плоскости: реализация удобных кастомных селектов, которые будут работать во всех браузерах; вёрстка страниц, которая на всех разрешениях выглядит хорошо; минимизация потребления ресурсов, чтобы пользователи на обычных компьютерах не страдали.
Что-то я растёкся мыслею, поэтому повторю вопрос: что такое этот ваш доменный код в разрезе фронтенд-приложений?
Может и нужен, но точно не в таком простом виде. В эвентах должна быть какая-то практическая изюминка. В событийной модели DOM'а есть всплытия событий, в очередях -- возможность подписываться на события по паттерну типа
on('form-*-changed', doSomething)
. Но когда события добавляются только для создания decoupling'а, потому что это "правильно" и Боб Мартин с Мартином Фаулером про это писали, то от такого паттерна только вредПо ссылке вы частично описали тоже самое, что и в этом комменте, но я всё равно не понимаю.
Ну вот есть у вас такой код. Вы пишите, что хотите подгружать аналитику лениво, поэтому нужен декаплинг на эвентах
Но у вас же загрузка тяжёлой библиотеки в бандл будет происходить не в файле
~/features/some/analytics.ts
, а где-то, где вы пропихиваетеSENTRY
внутрьwindow
. Получается, в ленивом импорте здесь не будет никакого смысла.Вы в телеграме ещё пишите, что моделей, которые нужно обмазать аналитикой, много. Но это тоже никак не мешает линейному коду. Если писать совсем просто и линейно, то эвенты проиграют в количестве кода, который нужно написать для подключения аналитики. Вот так будет выглядеть мой код:
Зачем тут эвенты? Чем вызов функции из модуля отличается от эвента конкретно в этой ситуации? Эвент здесь просто добавит indirection на ровном месте, который при отладке, фиксе багов или добавлении фичей будет только создавать головную боль.
Вот ещё ваш аргумент из телеграма: Есть процесс оформления заказа. Отдельно пилится менее важный, но полезный модуль подсказок, который никак с критичным процессом оформления не должен быть связан.
Что значит "никак с критичным процессом не должен быть связан"? Подсказки же всё равно будут связаны с процессом, просто неявно. Типа, если явной связи не видно, то связи вообще нет? Но оно так не работает :) Если под отсутствием связи вы понимаете, что код подсказок может падать, и это никак не должно влиять на процесс оформления, то для таких случаев есть try/catch или catch у промисов. Можно писать как-то так
Такой подход простой как палка, поэтому любое изменение фичи, фикс бага, добавление функциональности делается явно. Весь код, который нужен для понимания происходящего в рантайме, можно посмотреть в IDE с помощью Go To Definition. Такой код использует возможности языка и не обязывает читателя знать какие-то специфические библиотеки.
Чем конкретно этот подход хуже эвентов?
Чем дольше живу, тем меньше понимаю, зачем усложнять код событийной моделью, если всё можно написать сверху-вниз и слева-направо внутри самой вызываемой функции
Чем эта более читаемая запись принципиально хуже decoupled-решения на эвентах?
В посте для аргументов стратегии используется
any
, в вашем случае тоже придётся пожертвовать типизацией аргументов. Можно пойти немного дальше и сохранить типы:Зашёл, чтобы оставить похожий комментарий. С самого начала текста создалось впечатление "Я где-то на YouTube смотрел точно такой же ролик". Спасибо за ссылку!
А ещё мне кажется, что этот текст писал не человек, а какой-то алгоритм, как это недавно было с новостями на Hacker News
Вы "отваливаете 100500 денег" на пенсию текущих пенсионеров, а не на свою пенсию в будущем. В России солидарная пенсионная система, а не накопительная
Я не разбираюсь в законах РБ, по-этому ваше утверждение "[Во время обыска в компании] Личные вещи – это все что находится в ваших карманах или ваших руках." для меня немного контринтуитивно.
Можете, пожалуйста, привести конкретные законы и статьи, на которые может ссылаться сотрудник, если в его компанию пришли с обыском?
Все же кажется, что к ним пришли из-за этого:
Ссылка на результаты кампании тоже есть в посте: https://www.facebook.com/photo/?fbid=10158723155694592&set=a.10151034658869592
Потому что JSON — это модно. Шутка. Может потому что я описал процесс скраббинга данных и его можно повторить. Товарищи могут в них не верить, я не настаиваю.
Мне не очень нравится риторика и визуализация Шпилькина, вот я и стянул данные сам. В свободное время буду их ковырять. Данных мне не жалко, поэтому я и скинул ссылку сюда