Представляется, что дело не в том, насколько трудно освоить профессию БА (срежем углы и примем гипотезу, что это действительно просто). Ассенизатором тоже, предположу, несложно стать. Проблема в соотношении спроса и квалифицированного предложения. Белые воротнички, имеющие достаточно софтов и абстрактного мышления - зачем они, собственно, пойдут на низкооплачиваемую должность? В мире есть миллион стезей для таких людей: мелкий бизнес, менеджмент, финансовый гешефт, значительная часть преподавания очевидных умений, в конце концов - мошенники той или иной степени легальности.
Ну и сколько остаётся достаточно способных людей на такую странную должность, как БА? Вот именно отношение их количества к количеству позиций и даёт в итоге и зарплаты для топовых специалистов, и средний уровень остальных. Из порога вхождения тут надо вычитать порог вхождения в другие отрасли деятельности.
А вот для программистов тут дело хуже - умение упаковывать килобайты, сочинять апи и проектировать микросервисы востребовано только здесь, его в театре, вузе или на площади не монетизируешь. Короче, прямое сравнение трудозатрат на обучение и востребованности тут не работает.
Ну если не продаётся, то это нельзя купить? Это ведь нормально? Откуда эта мысль, что всё можно купить или получить? Да, есть вещи, которые нельзя купить, это нормально. Это не значит, что их можно хватать самовольно. И убытки тут ни при чём. Отсутствие убытков ещё не признак того, что использование краденого не является использованием краденого.
Проезд зайцем тоже ничего не стоит метрополитену (с точностью да погрешности измерения), но является нарушением.
Для того, чтобы при тестировании связки не закладываться на функциональность каждого мелкого компонента, вроде бы тыщу лет назад и придумали интерфейсы и DI?
В результате функционал одного и того же компонента не покрывается многократно, потому что в тестах связки участвует не сам этот объект, а его мок.
Я не понимаю механику развала проекта, если пул-реквесты отвергаются без брани. Изменения не попали в код, пояснения даны, что произошло бы ужасного, если бы это просто сопровождалось словами "отвергаю по двум причинам: у этой функции такие-то пороки, а также нарушен срок подачи пр-ов"
Каким образом после этих слов развалится проект ядра линукса, не очень понятно
Нельзя прийти, к примеру, в гостиницу, и сказать: слушайте, у вас всё равно эти номера пустуют, я тут незаметно поживу бесплатно. Вы же ничего не потеряете!
Или подойти к гиду, который ведёт экскурсию, и сказать: ну мы тут рядом постоим послушаем, с вас не убудет, платить не будем, продолжайте, пожалуйста.
Да даже элементарный заяц в метро не может оправдаться тем, что он для поезда и инфраструктуры ничтожная нагрузка и фактически метро ничего не потеряет, провезя его бесплатно.
Разумеется, для нематериальных товаров физический переход от владельца к потребителю не происходит, и это очень легко эксплуатировать в свою пользу. Просто из этого не следует, что неоплаченное потребление нематериальных товаров чем-то отличается от неоплаченного потребления материальных товаров. А уж назвать это воровством или ровостмом, дело десятое.
Как только выяснится, что для вычисления рейтинга необходимо передать ещё один какой-нибудь параметр/зависимость, а выяснится это на этапе реализации алгоритма вычисления рейтинга, придётся бежать по всем тестам и править вызовы. А там уже и ещё какие-то новости в сигнатурах всплывут.
Чего принципиально не хватает в постановке задачи "написать программу, выигрывающую в шахматы"?
Принципиально то, что я не знаю хороших практик решения этой задачи, я никогда этим не занимался. Понятно, что надо как-то в глубину просчитывать ветви ходов и оценивать полученные позиции. Так ли это, может я что-то упускаю? Как отсекать? Как оценивать? Возможно, для оценки нужны ещё какие-то вспомогательные абстракции? Может быть, есть ещё какие-то стадии решения? Всего этого я не знаю. Нужна постановка задачи от эксперта.
И такая постановка позволит лучше декомпозировать решение. В том числе и в ООП-парадигме, почему нет.
А если предположить, что наш шахматный движок имеет какую-то степень абстракции и позволит дёшево реализовывать другие игры со схожим флоу, то ООП станет основной практикой. Реализовал, грубо говоря, интерфейс "правила игры" и "оценка позиции" для шашек - и ура, пользуйся, все эти доски и алгоритмы принятия решения будут автоматически переиспользованы.
Короче, ничего ужасного в уместном применении ООП нет. Если с ума не сходить.
Я ничего не знаю про программирование шахмат, так что дальше вольная фантазия. Очевидно, там существуют уже устоявшиеся методики, которые не сочинить в рамках сочинения случайного комментария на хабре
Но нет ничего невероятного, то в шахматах, написанных с использованием ООП, будут:
примитивный класс хранения состояния игры (доска), просто сохраняет инварианты, к примеру, не позволяет поставить две фигуры на одну клетку.
наверное, при реализации логики понадобится возможность итерироваться по дереву возможных вариантов ходов. Это удобно реализовать в виде класса, ведь это же просто контейнер, дерево положений доски со своими инвариантами. И, возможно, с какими-то дополнительными промежуточными данными, которые можно привязать к узлам.
Наверняка есть какие-то вспомогательные абстракции - например, оценка позиции. И наверняка их методики бывают разные, и у них есть состояние (например, кэш предыдущих рассуждений), поэтому они кандидаты на общий интерфейс и реализация в классах.
и, допустим, самый корневой класс, принимающий решение за игрока, строящий логику выбора следующего хода. Он через DI принимает предыдущие.
ну и так далее, нужна постановка задачи, это всё вольная фантазия, дело не в моих выдумках, а в том...
А в том, что вы сами выдумали себе какой-то свой ужасный ООП, в котором программисты моделируют не объекты предметной области, а объекты материального мира: класс для доски, потом класс для клетки, для белого и чёрного цвета, для пешек и ладей - и теперь с этим успешно боретесь.
Но так никто не делает, вы боретесь с демонами в своей голове. Классы для фигур не нужны. А для абстракций, участвующих в принятии решений - вполне могут оказаться полезны.
Как пример для статьи про ООП на хабре? Почему, собственно, нет? Речь не идёт про промышленную универсальную реализацию, вы даже не знаете, какие требования будут к такой очереди, но уже лезете в бутылку. Вполне можно навертеть ООП-абстракций для примера, начиная от иерархии самих типов сообщений и заканчивая какими-нибудь, я не знаю, подписчиками. Это иллюстративный материал для статьи, он не обязан летать на утюгах.
Ах да, я вспомнил, вы тот самый любитель общественного внимания, который обращается к собеседнику "тупой дегенерат", когда его самого макают в, назовём это так, чрезмерную широту обобщений на фоне ограниченнго кругозора. Тогда вопросов не имею.
Мы пишем класс (и прочими способами упрощаем поддержку кода), потому что писатель кода и читатель могут различаться, да (это может быть и один человек, но в разное время). Это действительно причина
Код, в котором никому никогда не надо будет разбираться и поддерживать, всё равно, в какой парадигме писать
Семантика владения и прочие детали важны при написании кода (и то в большинстве случаев компилятор не даст ошибиться).
Но код читается кратно больше, чем пишется. И когнитивная нагрузка - это про чтение, а не про написание. Здесь алиасы работают, как хорошее именование переменных и даже как конструирование типов - упрощает код.
Слушайте, если у вас всё надо заменить, чтобы вас правильно понять, может, вы уже признаете, что пример плохой? Задача организации очереди сообщений это другая задача и действительно служила бы лучше целям статьи.
Казалось бы, наоборот? Если я знаю, что FooPtr это некий уместный в данном контексте тип указателя, то я не думаю о нижележащем типе и когнитивная нагрузка падает?
Мне неважно, что он юник или шейред, мне важно, что он указывает на Foo и используется в заданной сигнатуре. Остаётся только нужная информация. Нагрузка падает.
Да господи, стандартная библиотека в 2025-м году от РХ у него хак. Как будто кто-то запрещает писать на плюсах в процедурном стиле. Ну возьмите раст, там enum из коробки - тот же вариант. Код ещё в три раза короче станет, кстати.
Вы по-прежнему не туда воюете, я уже сороковой комментарий подряд пытаюсь вам объяснить, что проблема не в ООП, а в вашей статье, в которой выбран неудачный подход демонстрации достоинств ООП. Ладно, это бесполезно.
зачем в коллекцию? В вашем примере коллекция никак не используется
но если есть какая-то ломовая необходимость в коллекции конкретно в этом микроскопическом примере, у вас есть стандартный std::vector<std::variant>
Понимаете, вы сейчас начнёте накручивать требования, которых нет в примере. Моё замечание было не про ООП (это мощный и полезный подход во множестве случаев), а про ваш пример. Он не иллюстрирует сильные стороны ООП. Поэтому идея соревнования в решении этой задачи в разных парадигмах не имеет смысла.
Это очень плохой пример, потому что для игрушечных задач ООП не нужен. Он нужен для сложных абстракций, для разделения когнитивной нагрузки между группами разработчиков. У вас никогда не будет отдельной группы разработчиков для кружочков, а отдельной - для треугольничков.
Давайте попробуем вернуться в реальность и представим, что эти квадратики - что-то более-менее сложное. Очевидно, функции draw() должны обращаться к каким-то связанным с рисованием зависимостям (как минимум, тянуть заголовочные файлы). Но сами прямоугольники могут использоваться в контекстах, которые не подразумевают никакой связи с рисованием. Например, я не знаю, библиотека, которая вычисляет пересечения прямоугольников. На кой ляд ей draw() и все её зависимости?
А значит, фигура у нас разбивается на две части: Rectangle и RectangleDrawer (если предположить, что у рисовальщика есть состояние, например, кэш, и просто функции недостаточно, то понадобится класс), а RectangleDrawer станет частью своей иерархии. Они будут связываться, к примеру, как визиторы, и тут...
И тут в помещение вбегают критики ООП и говорят, что вот наворотили дикий оверинжиниринг! И они правы, потому что для этой примера достаточно POD-структур, для их хранения - несколько векторов, а для рисования - перегруженных (и даже это необязательно) свободных функций. Плохой пример, негодный. Надо придумать пример реального размера, в котором ООП действительно нужно.
ООП, разумеется, не панацея, оно придумано, чтобы снимать когнитивную нагрузку. Её нужно снимать, если а) предметная область большая, не десятки, а сотни и тысячи разнородных сущностей со сложными связями. б) работает много программистов, которые увольняются и приходят на протяжении долглих лет
Ты смотришь на код первый и последний раз, тебе надо что-то сделать и не испортить. Использовать готовый объект, скрывающий состояние, а ещё лучше - реализующий известный интерфейс - идеальное для этого решение. Спасибо тому, кто его создал!
Если вы делаете магазин размером в два человеко-месяца, который никто не будет сопровождать, без ООП легко можно обойтись.
Методологическая проблема поста.
Типичная работа программиста в мало-мальски объёмном проекте это поиск компромиссов и оценка рисков. Сделал оптимально - плохо читается. Сделал читаемо - трудно расширять. Сделал расширяемо - бьют по голове за оверинжиниринг.
И так далее. Постоянный поиск компромиссов. Этой проблемы нет, только если ты пишешь в команде из трёх человек, в которой ты главный.
Отсюда следует, что если кто-то на голубом глазу пишет статью "Такой-то подход - скам" (не с кликбейтными целями, а от души), то он принципиально неспособен к этому поиску баланса, у него не развита ответственная за это часть профессионализма.
Вы немножко мерилом работы считаете усталость.
Представляется, что дело не в том, насколько трудно освоить профессию БА (срежем углы и примем гипотезу, что это действительно просто). Ассенизатором тоже, предположу, несложно стать. Проблема в соотношении спроса и квалифицированного предложения. Белые воротнички, имеющие достаточно софтов и абстрактного мышления - зачем они, собственно, пойдут на низкооплачиваемую должность? В мире есть миллион стезей для таких людей: мелкий бизнес, менеджмент, финансовый гешефт, значительная часть преподавания очевидных умений, в конце концов - мошенники той или иной степени легальности.
Ну и сколько остаётся достаточно способных людей на такую странную должность, как БА? Вот именно отношение их количества к количеству позиций и даёт в итоге и зарплаты для топовых специалистов, и средний уровень остальных. Из порога вхождения тут надо вычитать порог вхождения в другие отрасли деятельности.
А вот для программистов тут дело хуже - умение упаковывать килобайты, сочинять апи и проектировать микросервисы востребовано только здесь, его в театре, вузе или на площади не монетизируешь. Короче, прямое сравнение трудозатрат на обучение и востребованности тут не работает.
Ну если не продаётся, то это нельзя купить? Это ведь нормально? Откуда эта мысль, что всё можно купить или получить? Да, есть вещи, которые нельзя купить, это нормально. Это не значит, что их можно хватать самовольно. И убытки тут ни при чём. Отсутствие убытков ещё не признак того, что использование краденого не является использованием краденого.
Проезд зайцем тоже ничего не стоит метрополитену (с точностью да погрешности измерения), но является нарушением.
Для того, чтобы при тестировании связки не закладываться на функциональность каждого мелкого компонента, вроде бы тыщу лет назад и придумали интерфейсы и DI?
В результате функционал одного и того же компонента не покрывается многократно, потому что в тестах связки участвует не сам этот объект, а его мок.
Я не понимаю механику развала проекта, если пул-реквесты отвергаются без брани. Изменения не попали в код, пояснения даны, что произошло бы ужасного, если бы это просто сопровождалось словами "отвергаю по двум причинам: у этой функции такие-то пороки, а также нарушен срок подачи пр-ов"
Каким образом после этих слов развалится проект ядра линукса, не очень понятно
Да хоть горшком назови.
Нельзя прийти, к примеру, в гостиницу, и сказать: слушайте, у вас всё равно эти номера пустуют, я тут незаметно поживу бесплатно. Вы же ничего не потеряете!
Или подойти к гиду, который ведёт экскурсию, и сказать: ну мы тут рядом постоим послушаем, с вас не убудет, платить не будем, продолжайте, пожалуйста.
Да даже элементарный заяц в метро не может оправдаться тем, что он для поезда и инфраструктуры ничтожная нагрузка и фактически метро ничего не потеряет, провезя его бесплатно.
Разумеется, для нематериальных товаров физический переход от владельца к потребителю не происходит, и это очень легко эксплуатировать в свою пользу. Просто из этого не следует, что неоплаченное потребление нематериальных товаров чем-то отличается от неоплаченного потребления материальных товаров. А уж назвать это воровством или ровостмом, дело десятое.
Как только выяснится, что для вычисления рейтинга необходимо передать ещё один какой-нибудь параметр/зависимость, а выяснится это на этапе реализации алгоритма вычисления рейтинга, придётся бежать по всем тестам и править вызовы. А там уже и ещё какие-то новости в сигнатурах всплывут.
Принципиально то, что я не знаю хороших практик решения этой задачи, я никогда этим не занимался. Понятно, что надо как-то в глубину просчитывать ветви ходов и оценивать полученные позиции. Так ли это, может я что-то упускаю? Как отсекать? Как оценивать? Возможно, для оценки нужны ещё какие-то вспомогательные абстракции? Может быть, есть ещё какие-то стадии решения? Всего этого я не знаю. Нужна постановка задачи от эксперта.
И такая постановка позволит лучше декомпозировать решение. В том числе и в ООП-парадигме, почему нет.
А если предположить, что наш шахматный движок имеет какую-то степень абстракции и позволит дёшево реализовывать другие игры со схожим флоу, то ООП станет основной практикой. Реализовал, грубо говоря, интерфейс "правила игры" и "оценка позиции" для шашек - и ура, пользуйся, все эти доски и алгоритмы принятия решения будут автоматически переиспользованы.
Короче, ничего ужасного в уместном применении ООП нет. Если с ума не сходить.
Я ничего не знаю про программирование шахмат, так что дальше вольная фантазия. Очевидно, там существуют уже устоявшиеся методики, которые не сочинить в рамках сочинения случайного комментария на хабре
Но нет ничего невероятного, то в шахматах, написанных с использованием ООП, будут:
примитивный класс хранения состояния игры (доска), просто сохраняет инварианты, к примеру, не позволяет поставить две фигуры на одну клетку.
наверное, при реализации логики понадобится возможность итерироваться по дереву возможных вариантов ходов. Это удобно реализовать в виде класса, ведь это же просто контейнер, дерево положений доски со своими инвариантами. И, возможно, с какими-то дополнительными промежуточными данными, которые можно привязать к узлам.
Наверняка есть какие-то вспомогательные абстракции - например, оценка позиции. И наверняка их методики бывают разные, и у них есть состояние (например, кэш предыдущих рассуждений), поэтому они кандидаты на общий интерфейс и реализация в классах.
и, допустим, самый корневой класс, принимающий решение за игрока, строящий логику выбора следующего хода. Он через DI принимает предыдущие.
ну и так далее, нужна постановка задачи, это всё вольная фантазия, дело не в моих выдумках, а в том...
А в том, что вы сами выдумали себе какой-то свой ужасный ООП, в котором программисты моделируют не объекты предметной области, а объекты материального мира: класс для доски, потом класс для клетки, для белого и чёрного цвета, для пешек и ладей - и теперь с этим успешно боретесь.
Но так никто не делает, вы боретесь с демонами в своей голове. Классы для фигур не нужны. А для абстракций, участвующих в принятии решений - вполне могут оказаться полезны.
Как пример для статьи про ООП на хабре? Почему, собственно, нет? Речь не идёт про промышленную универсальную реализацию, вы даже не знаете, какие требования будут к такой очереди, но уже лезете в бутылку. Вполне можно навертеть ООП-абстракций для примера, начиная от иерархии самих типов сообщений и заканчивая какими-нибудь, я не знаю, подписчиками. Это иллюстративный материал для статьи, он не обязан летать на утюгах.
Ах да, я вспомнил, вы тот самый любитель общественного внимания, который обращается к собеседнику "тупой дегенерат", когда его самого макают в, назовём это так, чрезмерную широту обобщений на фоне ограниченнго кругозора.
Тогда вопросов не имею.
Мы пишем класс (и прочими способами упрощаем поддержку кода), потому что писатель кода и читатель могут различаться, да (это может быть и один человек, но в разное время). Это действительно причина
Код, в котором никому никогда не надо будет разбираться и поддерживать, всё равно, в какой парадигме писать
Эвона чо
Семантика владения и прочие детали важны при написании кода (и то в большинстве случаев компилятор не даст ошибиться).
Но код читается кратно больше, чем пишется. И когнитивная нагрузка - это про чтение, а не про написание. Здесь алиасы работают, как хорошее именование переменных и даже как конструирование типов - упрощает код.
Слушайте, если у вас всё надо заменить, чтобы вас правильно понять, может, вы уже признаете, что пример плохой? Задача организации очереди сообщений это другая задача и действительно служила бы лучше целям статьи.
Зачем я буду заменять слово "статья" на слово "код", если я имею а виду не код, а всю статью? Т.е. контекст использования этого кода.
Код, конечно, тоже плохой, но речь не об этом.
Казалось бы, наоборот? Если я знаю, что FooPtr это некий уместный в данном контексте тип указателя, то я не думаю о нижележащем типе и когнитивная нагрузка падает?
Мне неважно, что он юник или шейред, мне важно, что он указывает на Foo и используется в заданной сигнатуре. Остаётся только нужная информация. Нагрузка падает.
Да господи, стандартная библиотека в 2025-м году от РХ у него хак. Как будто кто-то запрещает писать на плюсах в процедурном стиле. Ну возьмите раст, там enum из коробки - тот же вариант. Код ещё в три раза короче станет, кстати.
Вы по-прежнему не туда воюете, я уже сороковой комментарий подряд пытаюсь вам объяснить, что проблема не в ООП, а в вашей статье, в которой выбран неудачный подход демонстрации достоинств ООП. Ладно, это бесполезно.
зачем в коллекцию? В вашем примере коллекция никак не используется
но если есть какая-то ломовая необходимость в коллекции конкретно в этом микроскопическом примере, у вас есть стандартный std::vector<std::variant>
Понимаете, вы сейчас начнёте накручивать требования, которых нет в примере. Моё замечание было не про ООП (это мощный и полезный подход во множестве случаев), а про ваш пример. Он не иллюстрирует сильные стороны ООП. Поэтому идея соревнования в решении этой задачи в разных парадигмах не имеет смысла.
Да тут даже мр не нужен, вот вам код, выполняющий совершенно ту же задачу, что и ваш пример.
По сравнению с вашим у него масса достоинств, начиная с того, что он компилируется.
Ваш пример не убеждает, а разубеждает пользоваться ООП.
Он не подчёркивает его сильные стороны (разделение кода на изолированные куски с хорошо описанной изолированной ответственностью)
Но зато он отлично иллюстрирует аргументы критиков ООП: вы усложнили примитивную задачу.
(ну и плюс задача решена некорректно, рисование не является частью прямоугольника, как я уже выше и написал)
Это очень плохой пример, потому что для игрушечных задач ООП не нужен. Он нужен для сложных абстракций, для разделения когнитивной нагрузки между группами разработчиков. У вас никогда не будет отдельной группы разработчиков для кружочков, а отдельной - для треугольничков.
Давайте попробуем вернуться в реальность и представим, что эти квадратики - что-то более-менее сложное. Очевидно, функции draw() должны обращаться к каким-то связанным с рисованием зависимостям (как минимум, тянуть заголовочные файлы). Но сами прямоугольники могут использоваться в контекстах, которые не подразумевают никакой связи с рисованием. Например, я не знаю, библиотека, которая вычисляет пересечения прямоугольников. На кой ляд ей draw() и все её зависимости?
А значит, фигура у нас разбивается на две части: Rectangle и RectangleDrawer (если предположить, что у рисовальщика есть состояние, например, кэш, и просто функции недостаточно, то понадобится класс), а RectangleDrawer станет частью своей иерархии. Они будут связываться, к примеру, как визиторы, и тут...
И тут в помещение вбегают критики ООП и говорят, что вот наворотили дикий оверинжиниринг! И они правы, потому что для этой примера достаточно POD-структур, для их хранения - несколько векторов, а для рисования - перегруженных (и даже это необязательно) свободных функций. Плохой пример, негодный. Надо придумать пример реального размера, в котором ООП действительно нужно.
Две проблемы.
ООП, разумеется, не панацея, оно придумано, чтобы снимать когнитивную нагрузку. Её нужно снимать, если
а) предметная область большая, не десятки, а сотни и тысячи разнородных сущностей со сложными связями.
б) работает много программистов, которые увольняются и приходят на протяжении долглих лет
Ты смотришь на код первый и последний раз, тебе надо что-то сделать и не испортить. Использовать готовый объект, скрывающий состояние, а ещё лучше - реализующий известный интерфейс - идеальное для этого решение. Спасибо тому, кто его создал!
Если вы делаете магазин размером в два человеко-месяца, который никто не будет сопровождать, без ООП легко можно обойтись.
Методологическая проблема поста.
Типичная работа программиста в мало-мальски объёмном проекте это поиск компромиссов и оценка рисков.
Сделал оптимально - плохо читается.
Сделал читаемо - трудно расширять.
Сделал расширяемо - бьют по голове за оверинжиниринг.
И так далее. Постоянный поиск компромиссов. Этой проблемы нет, только если ты пишешь в команде из трёх человек, в которой ты главный.
Отсюда следует, что если кто-то на голубом глазу пишет статью "Такой-то подход - скам" (не с кликбейтными целями, а от души), то он принципиально неспособен к этому поиску баланса, у него не развита ответственная за это часть профессионализма.
Т.е. он недееспосбоен как инженер