LINUX.ORG.RU
ФорумTalks

Стоимость строки кода в разных регионах и на удалёнке

 


0

1

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

Как думаете, сколько стоит качественный отлаженный DRY код в предметной области DevOps, соответствующий всем паттернам, best practices и т.п.?

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

Преимущества учета стоимости кода по количеству написанных строк в Agile-проекте

Учет стоимости кода по количеству написанных строк – подход, который периодически обсуждается в IT-среде, в том числе и в вашем прикреплённом обсуждении. Хотя в современной разработке этот метод считается спорным и не всегда применимым, у него есть определённые преимущества, особенно если речь идёт о специфических задачах (например, DevOps-скрипты, IaC, CLI-утилиты) и при правильной постановке процесса.

1. Прозрачность и простота расчётов

  • Лёгкость измерения: Количество строк кода – объективный, легко измеряемый показатель, который можно быстро получить с помощью инструментов анализа кода.
  • Понятная метрика для заказчика: Заказчик может видеть «осязаемый» результат работы, что важно для непогружённых в детали разработки людей.

2. Мотивация к эффективности

  • Фокус на результат: Такой подход мотивирует разработчика не растягивать задачи, а выдавать конкретный, измеримый результат.
  • Возможность сравнения: Можно сравнивать производительность между разными исполнителями или командами, если задачи типовые и стандартизированы.

3. Гибкость при изменении требований (Agile)

  • Простота пересчёта стоимости: При изменении требований (что часто бывает в Agile), можно быстро пересчитать стоимость, исходя из нового объёма кода.
  • Удобство для коротких итераций: В спринтах, где задачи дробятся на небольшие части, оплата по строкам может быть удобна для микрозадач (например, написание шаблонов, конфигов, скриптов).

4. Контроль качества (при правильной постановке)

  • Возможность учёта сложности: Если в стоимость строки закладывается качество (DRY, тесты, best practices), появляется стимул писать лаконичный и качественный код.
  • Быстрая оценка вклада: В проектах с большим количеством рутинных изменений (например, поддержка DevOps-инфраструктуры), этот подход позволяет быстро оценить вклад каждого разработчика.

5. Применимость к DevOps и инфраструктурным задачам

  • Стандартизированные задачи: В DevOps часто встречаются задачи, где результат – это скрипт или конфиг, и их объём хорошо коррелирует с трудозатратами.
  • Меньше риска «раздувания» кода: Если стоимость строки высокая и есть контроль качества (ревью, автоматические проверки), разработчики заинтересованы писать компактно и эффективно.

Важно!

  • Подход не универсален: Для сложных R&D-задач, архитектурных решений, оптимизаций, где ценность кода не в количестве, а в качестве и уникальности, этот метод не подходит.
  • Риски злоупотреблений: Без контроля качества возможен «честинг» – искусственное раздувание кода, копипаст, бессмысленные строки.
  • Лучше использовать в сочетании с другими метриками: Например, с оплатой за закрытие задач, code review, покрытие тестами и т.п.

Вывод

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



Последнее исправление: sanyo1234 (всего исправлений: 5)
Ответ на: комментарий от kaldeon

Чет я пропустил это решение. Скинь, пожалуйста, ссылку.

Стоимость строки кода в разных регионах и на удалёнке (комментарий)

Но я приведу пример того, почему я называю наследование негибким. Есть Event и Day — несколько типов объектов, на которые можно подписаться. Допустим, в нашей системе они настолько родственны, что есть основание создать родительский класс Subscribable и включить в него значительную часть общей реализации.

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

Какой именно принцип инкапсуляции был нарушен с твоей точки зрения?

Ты не можешь легко заменить Subscribable на, допустим, IntenseSubscribable — то же самое поведение, но с другой механикой.

Если пришлось бы менять родительский класс, то это неправильная попыткая использования наследования?

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

Множественное наследование не приветствуется ни в Java, ни в C#.

Эти две особенности—нарушение инкапсуляции и необходимость выбора иерархии—я и называю негибкими.

Твой пример просто не подходит для наследования, только и всего.

Понять других людей важнее, чем опровергнуть.

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

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

Композиция может использоваться одновременно с наследованием. Ненужно пытаться впихнуть в невпихуемое.

Сокращает ли наследование реализации код? Возможно.

Не возможно, а точно.

Как и процедуры.

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

Позволяет ли оно более просто воспринимать программу? С этим сложнее. Я не уверен.

Как раз позволяет при правильном использовании.

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

Главное для чего?

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

Можно накидать кривых примеров и для композиции.

Опять же, здесь существенная характеристика — абстракции. Выберешь нужные абстракции, будешь их правильно использовать — количество кода сократится.

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

sanyo1234
() автор топика
Последнее исправление: sanyo1234 (всего исправлений: 2)
Ответ на: комментарий от sanyo1234

Давай приземлим понятия к земле.

Что это значит? Упрощение?

В целом, да, но в особенности это обозначает хорошо подобранные примеры.

Абстракция — это способ ментально отделить и использовать в свою пользу какой-то аспект реальности,

Почему обязательно в свою пользу? Абстракции бывают и вредными?

Бывают. Ещё они бывают лишены реальности. Я назвал определение, которое считаю важным в данном конкретном контексте.

аспект реальности, который не может существовать отдельно.

Отдельно от чего?

Отдельно от того, от чего он отделён. Например, «длина» сама по себе не существует отдельно от спички или палки. Или «файл» отдельно от того, куда в конечном счёте попадают данные.

Наследование реализации, в свою очередь, расширяет понятие возможностью переиспользования реализации (разница между private и protected не столь важна).

Причём тут это? И почему разница неважна?

При том, что реализация — это private или protected. Не важна потому что если сделать свойство или метод protected, то он не перестанет от этого быть реализацией.

Понятия должны быть основаны на существенной (или фундаментальной) характеристике.

Понятия, которые ты «приземляешь» (c)?

Человек — это живой организм с двумя глазами. Вот пример понятия без существенной характеристики. Именно так выглядит твоя одержимость на наследовании как способе сократить число кода.

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

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

Расшифруй своё сообщение. Какое отношение имеет абстрактность к возможности наследования того или иного свойства или метода?

Отношение наследования к абстракности таково, что наследование — это отношение между двумя абстракциями.

И код становится проще (и короче) именно благодаря абстракциям. Наследование — это частный случай, причём весьма несущественный в сравнении с абстрактностью.

По твоему для выявления общего свойства нужна абстрактность такого свойства, а не его наследуемость?

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

Это особенно удобно, если в будущем потребуется изменить общую логику: достаточно внести изменения только в одном месте - в базовом классе.

Когда у вас в коде будет N потомков которые все ещё ориентируются на старое поведение и M потомков которые ориентируются на новое

Разве нельзя для нового поведения сделать дополнительный уровень наследования вместо внесения изменений в оригинальный родительский класс ?

Противоречивые параграфы выделил полужирным.

Какой именно принцип инкапсуляции был нарушен с твоей точки зрения?

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

Инкапсуляция не то чтобы нарушена, её скорее нет на данном уровне.

Ты не можешь легко заменить Subscribable на, допустим, IntenseSubscribable — то же самое поведение, но с другой механикой.

Если пришлось бы менять родительский класс, то это неправильная попыткая использования наследования?

Изменение кода — это волшебная палочка, которая позволяет решить любую проблему)

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

Множественное наследование не приветствуется ни в Java, ни в C#.

А в C++ так можно делать.

Твой пример просто не подходит для наследования, только и всего.

Конечно не подходит, иначе всё было бы прекрасно и все были бы счастливы.

Но в более глубоком смысле он подходит. Вот что должно было меня остановить от наследования Event и Day от Subscribable? Наследование — это отношение между двумя абстракциями в контексте, ограниченном is-a. Event is subscribable, day is subscribable. Потом потребовалось—допустим, проект развивается—добавить IntenseSubscribable. Мы в ловушке.

ООП с наследованием намного сильнее сокращает код … я уже устал объяснять.

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

Я говорил о том, что [количества кода] не самое главное.

Главное для чего?

Для разума человека. Но об этом мне не хочется дискутировать.

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

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

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 5)
Ответ на: комментарий от kaldeon

При том, что реализация — это private или protected. Не важна потому что если сделать свойство или метод protected, то он не перестанет от этого быть реализацией.

Почему по твоему важно является ли метод реализацией, а не то, какой доступ ему назначен? И для чего важно?

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

Инкапсуляция не то чтобы нарушена, её скорее нет на данном уровне.

private - скрыто от всех, включая наследников - полная инкапсуляция

protected - скрыто от внешнего мира, но доступно наследникам - частичная инкапсуляция

public - доступно всем - не инкапсулировано

Ты искусственно пытаешься создать проблему на ровном месте, где её нет и не было никогда.

Если пришлось бы менять родительский класс, то это неправильная попыткая использования наследования?

Изменение кода — это волшебная палочка, которая позволяет решить любую проблему)

Нужно сразу продумывать: Правильную иерархию, принцип подстановки Лисков (каждый потомок должен корректно заменять родителя во всех контекстах), будущие изменения

Конечно не подходит, иначе всё было бы прекрасно и все были бы счастливы.

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

А в C++ так можно делать.

Не считается хорошей практикой в отличие от немножественного наследования.

Но в более глубоком смысле он подходит. Вот что должно было меня остановить от наследования Event и Day от Subscribable? Наследование — это отношение между двумя абстракциями в контексте, ограниченном is-a. Event is subscribable, day is subscribable. Потом потребовалось—допустим, проект развивается—добавить IntenseSubscribable.

Разве нельзя было унаследовать Event и Day от IntenseSubscribable, а IntenseSubscribable от Subscribable ?

Кроме того различные *able типа Subscribable обычно описываются интерфейсами, а не наследованием.

Мы в ловушке.

Это ты в ловушке, потому что не умеешь или делаешь вид, что не умеешь в ООП с наследованием. Ловушка существует лишь в твоей голове, и ловит она только тебя самого, мешая понимать и правильно использовать ООП :(

Главное для чего?

Для разума человека. Но об этом мне не хочется дискутировать.

IMHO главное определяется не разумом определённого человека, а целями проекта и эффективностью программирования.

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

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

GUI, 3D графика, математика и т.п. В такого рода проектах implementation inheritance может сокращать количество кода в разы! А значит и отлаживаемость проекта, его поддерживаемость, time to market, etc.

Ты апеллируешь к субъективным предпочтениям, а я - к объективным метрикам.

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

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

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

Многие твои якобы «проблемы наследования» - это проблемы неумелого использования, а не самого механизма.

Мне кажется, что ты просто пытаешься рационализировать свою неопытность в ООП-дизайне.

sanyo1234
() автор топика
Последнее исправление: sanyo1234 (всего исправлений: 3)
Ответ на: комментарий от sanyo1234

GUI, 3D графика, математика и т.п. В такого рода проектах implementation inheritance может сокращать количество кода в разы! А значит и отлаживаемость проекта, его поддерживаемость, time to market, etc.

Подразумевается, что отлаживаемость проекта, его поддерживаемость, time to market, etc. пропорционально улучшаются.

sanyo1234
() автор топика
Ответ на: комментарий от sanyo1234

Наследование реализации, в свою очередь, расширяет понятие возможностью переиспользования реализации (разница между private и protected не столь важна).

Почему по твоему важно является ли метод реализацией, а не то, какой доступ ему назначен? И для чего важно?

Наследование реализации позволяет переиспользовать реализацию. Инкапсуляция обозначает сокрытие реализации. Следовательно при использовании наследования реализации инкапсуляция отсутствует.

protected - скрыто от внешнего мира, но доступно наследникам - частичная инкапсуляция

Есть несколько сторон в каждой проблеме: одна верная, другая нет, но посередине — всегда зло. Частичная инкапсуляция — это просто состояние неопределённости.

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

«Database может отправлять запросы, но ещё ты можешь унаследоваться и вмешаться в пул задач» — это не частичная инкапсуляция.

Ты искусственно пытаешься создать проблему на ровном месте, где её нет и не было никогда.

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

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

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

Наследование — это отношение между двумя абстракциями, иерархия. Это не застывшая во времени классификация, которую ты при желании всегда можешь достать из кармана. Её структура определяется ограничениями реальности, требованиями проекта. Нередко одна абстракция может быть полезна в разных контекстах, отсюда и необходимость множественного наследования. Пример из жизни: есть Вася, о котором ты что-то знаешь по литературным предпочтениям, а что-то знаешь из его медицинской книжки. Но это один Вася, не ReadingVasilii и MedicalVasilii.

Поэтому у опытного программиста особых перимуществ перед начинающим нет в выборе иерархии нового проекта, если только это не throwaway прототип.

[Множественное наследование не] считается хорошей практикой в отличие от немножественного наследования.

Ну а в C++ это считается хорошей практикой, поэтому и добавили в язык. Если бы были уверены, что это плохая практика, то не стали бы добавлять.

Я хотя против наследования реализации, но могу понять, что если уж хочется, то множественное наследование имеет свою область применения.

Разве нельзя было унаследовать Event и Day от IntenseSubscribable, а IntenseSubscribable от Subscribable ?

Иногда можно, иногда нет. Что если Subscribable — это уведомление на почту/календарь, а IntenseSubscribable — в какой-нибудь модный мессенджер?

Надо было сразу назвать этот пример, но упустил, сорри. Примерно такой пример я имел ввиду здесь:

Ты не можешь легко заменить Subscribable на, допустим, IntenseSubscribable — то же самое поведение, но с другой механикой.

В Event и Day уже происходят механики, жёстко привязанные к особенностям Subscribable. Например, подтверждение сделано через прослушивание сообщений. А в IntenseSubscribable пользователь нажимает кнопку, при этом никакое сообщение не отправляется.

Кроме того различные *able типа Subscribable обычно описываются интерфейсами, а не наследованием.

Не мог придумать название лучше, сорри.

Это ты в ловушке, потому что не умеешь или делаешь вид, что не умеешь в ООП с наследованием.

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

IMHO главное [до сих пор идёт речь о количестве кода] определяется не разумом определённого человека, а целями проекта и эффективностью программирования.

Не определённого, но я и не говорил про определённого.

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

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

GUI, 3D графика, математика и т.п. В такого рода проектах implementation inheritance может сокращать количество кода в разы!

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

Ты апеллируешь к субъективным предпочтениям, а я - к объективным метрикам.

Я привёл достаточно примеров, чтобы это не казалось субъективными предпочтениями. И метрики обозначают измерение, а измерить успешность наследования в «GUI, 3D графике и математике» — это непосильная задача. Сущестует огромное множество библиотек, порой сравнить хотя бы две тяжело, не говоря уже о выводах обо всех возможных библиотеках.

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

Нужны кому? Наследование — один подход, не единственный и не всегда верный.

игнорируешь очевидные решения проблем

Где?

подменяешь технические аргументы своими философскими

Они не полностью мои. И разница между техникой и философией в нашем контексте несущественна. Эпистемология — наука, посвящённая поиску правильных методов получения и подтверждения знаний. Строительный блок ООП в современном понимании — понятие об абстракции, дошедшее до нас со времён Древней Греции. Да и большинство моих аргументов вполне соответствуют современным представлениям об ООП: is-a, has-a, отношения между абстракциями — это всё я взял не из философии.

не учитываешь специфику разных доменов

А что там учитывать? Мы обсуждаем наследование само по себе.

ты догматически против наследования

Догма — набор убеждений, принятых на веру: без рационального обоснования ли доказательства. А я привёл достаточно много аргументов в поддержку своих убеждений.

Многие твои якобы «проблемы наследования» - это проблемы неумелого использования, а не самого механизма.

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

Мне кажется, что ты просто пытаешься рационализировать свою неопытность в ООП-дизайне.

Так субъективные предпочтения или рационализация?

Рационализация обозначает ложное логическое объяснение поведению или подходу. То есть ложь. Такие вещи нужно доказывать.

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 7)
Ответ на: комментарий от kaldeon

Наследование реализации позволяет переиспользовать реализацию. Инкапсуляция обозначает сокрытие реализации. Следовательно при использовании наследования реализации инкапсуляция отсутствует.

Разве инкапсуляция protected отсутствует для внешних пользователей класса?

protected - скрыто от внешнего мира, но доступно наследникам - частичная инкапсуляция

А если реализация выполнена в private методах, то полная инкапсуляция отсуствует?

Есть несколько сторон в каждой проблеме: одна верная, другая нет, но посередине — всегда зло.

Это твои фантазии. При правильном использовании посредине - обоюдовыгодный компромис, а не зло.

Частичная инкапсуляция — это просто состояние неопределённости.

Откуда неопределённость? Protected доступ подробно определён в документации. Опять твои фантазии.

«Database может отправлять запросы, но ещё ты можешь унаследоваться и вмешаться в пул задач» — это не частичная инкапсуляция.

Скорее принимать запросы? И не database, а DBMS?

Унаследовать Database ?

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

Ну как же не сочетаются при использовании protected и private?

Ну а без инкапсуляции тоже можно работать, если аккуратно.

А зачем, когда есть private?

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

Опытному ООП разработчику легче создать корректную иерархию сразу на старте проекта?

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

Наследование - это один из инструментов. Требования проекта разве регламентируют его использование?

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

IMHO очень неудачный пример. Вася больше подходит в качестве экземпляра класса Human, у которого могут быть свойства, описывающие его Reading и Medical особенности и предпочтения.

Поэтому у опытного программиста особых перимуществ перед начинающим нет в выборе иерархии нового проекта, если только это не throwaway прототип.

Очень спорно, не согласен с тобой.

Ну а в C++ это считается хорошей практикой, поэтому и добавили в язык.

С чего ты взял, что то, что добавляется в C++, считается хорошей практикой всеми пользователями C++?

https://stackoverflow.com/questions/406081/why-should-i-avoid-multiple-inheritance

Если бы были уверены, что это плохая практика, то не стали бы добавлять.

Поэтому и не стали добавлять ни в Java, ни в C#. Думаешь, С++ чем то лучше подходит для multiple inheritance по сравнению с шарпом?

Я хотя против наследования реализации, но могу понять, что если уж хочется, то множественное наследование имеет свою область применения.

Есть реальные популярные проекты, которые его используют?

В Event и Day уже происходят механики, жёстко привязанные к особенностям Subscribable.

Это твоя очередная архитектурная ошибка ?

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

И многие из них публично опровергнуты в различных паблик обсуждениях.

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

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

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

Ты можешь разработать WinForms, WPF, Avalonia UI без наследования? Вспомни хотя бы посмешище GObject, что из этого получилось?

Я привёл достаточно примеров, чтобы это не казалось субъективными предпочтениями.

Твои примеры являются примерами архитектурных ошибок при ООП.

И метрики обозначают измерение, а измерить успешность наследования в «GUI, 3D графике и математике» — это непосильная задача. Сущестует огромное множество библиотек, порой сравнить хотя бы две тяжело, не говоря уже о выводах обо всех возможных библиотеках.

По твоему нет инструментов, которые измеряют степень переиспользования кода, эффективность применения ООП наследования и т.п.?

Нужны кому? Наследование — один подход, не единственный и не всегда верный.

Тем, кто извлекает выгоду от снижения затрат времени на программирование с ООП наследованием.

игнорируешь очевидные решения проблем Где?

Почти во всех своих неудачных примерах для применения наследования, и мои контр примеры.

А что там учитывать? Мы обсуждаем наследование само по себе.

Как я уже упоминал, некоторые домены разрабатывать без наследования особенно тяжело и трудоёмко.

А я привёл достаточно много аргументов в поддержку своих убеждений.

IMHO это не доказательства, а попытки натянуть твои неудачные примеры использования на ООП в целом.

Многие твои якобы «проблемы наследования» - это проблемы неумелого использования, а не самого механизма.

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

Любые инструменты могут перестать правильно работать, если их неправильно применять.

Так субъективные предпочтения или рационализация? Рационализация обозначает ложное логическое объяснение поведению или подходу. То есть ложь. Такие вещи нужно доказывать.

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

sanyo1234
() автор топика
Последнее исправление: sanyo1234 (всего исправлений: 1)
Ответ на: комментарий от sanyo1234

Разве инкапсуляция protected отсутствует для внешних пользователей класса?

Она отсутствует для дочерних классов.

А если реализация выполнена в private методах, то полная инкапсуляция отсуствует?

private позволяет сделать обычную, полную инкапсуляцию.

Это твои фантазии. При правильном использовании посредине - обоюдовыгодный компромис, а не зло.

Компромисс возможен не в правильном использовании, а в ограниченном контексте, когда проблема сводится к деталям и специфике, а не базовым принципам. Я против protected ничего не имею, это как раз допустимый компромисс. Но это не инкапсуляция.

Откуда неопределённость? Protected доступ подробно определён в документации. Опять твои фантазии.

Неопределённость возникает из-за приблизительного использования понятий. «Частичная инкапсуляция», «приблизительная истина» и т.д. В области познания и программирования нет ничего вреднее, чем приблизительное.

И protected определён не в документации, а в спецификации языка. Я даже не намекал на то, что это не так.

«Database может отправлять запросы, но ещё ты можешь унаследоваться и вмешаться в пул задач» — это не частичная инкапсуляция.

Скорее принимать запросы? И не database, а DBMS?

Унаследовать Database ?

Я имел ввиду клиент к базе данных. Просто привык, что слово «клиент» зачастую опускается для краткости.

Ну как же не сочетаются [наследование и инкапсуляция] при использовании protected и private?

А зачем [работать без инкапсуляции], когда есть private?

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

Поэтому инкапсуляции между родительским и дочерним классом нет. protected — это просто возможность хоть как-то контролировать этот процесс, но это просто права доступа.

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

Опытному ООП разработчику легче создать корректную иерархию сразу на старте проекта?

Только если это прототип, который этот разработчик делал хотя бы несколько раз и знает заранее как в нём организовать типы, чтобы побыстрее сдать проект. Но разработка не ограничивается прототипами и скоростью.

Наследование - это один из инструментов. Требования проекта разве регламентируют его использование?

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

С чего ты взял, что то, что добавляется в C++, считается хорошей практикой всеми пользователями C++?

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

https://stackoverflow.com/questions/406081

Смотрим первый ответ:

Perhaps composition? This is true for inheritance, and so, it's even more true for multiple inheritance.

. . .

Do you really need Multiple Inheritance? Sometimes, yes.

Я не спорю ни с первым утверждением, ни со вторым.

Думаешь, С++ чем то лучше подходит для multiple inheritance по сравнению с шарпом?

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

Это просто компромисс, а не «множественное наследование придумали тупицы, используют идиоты, разработчики C++ дураки».

Есть реальные популярные проекты, которые его используют?

Не знаю, я не работал никогда с языками с множественным наследованием. Думаю, если поискать, то найдётся.

В Event и Day уже происходят механики, жёстко привязанные к особенностям Subscribable.

Это твоя очередная архитектурная ошибка ?

В такой формулировке это лаже не ошибка. Проблема в том, чтобы заменить родительский класс всех или некоторых дочерних классов. «Ошибка» подразумевает, что её можно было избежать. А как?

Допустим, у нас много сущностей, на которые можно подписаться — не просто Event и Day, а ещё десяток других сущностей. Например, это какая-то внутренняя система для журналистов — им нужно быть постоянно в курсе различных сущностей, внутренних и внешних. Мы вынесли подписку в общий родительский класс, а в дочерних классах неизбежно привязались к особенностям родительского класса.

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

И многие из [твоих аргументов] публично опровергнуты в различных паблик обсуждениях.

Они опровергнуты примерно также как мы общаемся в этом треде: люди продолжают спорить.

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

Ты можешь разработать WinForms, WPF, Avalonia UI без наследования? Вспомни хотя бы посмешище GObject, что из этого получилось?

Как я уже упоминал, некоторые домены разрабатывать без наследования особенно тяжело и трудоёмко.

Не смогу, потому что не пользовался ничем из перечисленного. Я бэкендер. GObject, скорее всего, в большей мере страдает из-за трудностей написания абстрактного кода в C.

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

Я привёл достаточно примеров, чтобы это не казалось субъективными предпочтениями.

Твои примеры являются примерами архитектурных ошибок при ООП.

А я привёл достаточно много аргументов в поддержку своих убеждений.

IMHO это не доказательства, а попытки натянуть твои неудачные примеры использования на ООП в целом.

Я отвечал про то, что это не субъективные предпочтения. Субъективное предпочтение — это «я могу написать код так, а могу по-другому, но первый вариант мне больше нравится, удобнее мне лично».

Архитектурные ошибки — слишком широкое понятие. Что я должен был архитектурно сделать, чтобы избежать описанных проблем?

Важно то, что в моих примерах проблемы возникают из-за наследования.

Может быть, я не могу вас переубедить, но у меня и нет такой цели — я просто делюсь своими выводами, это форум, а не научная публикация.

[Где я игнорирую очевидные решения проблем?]

Почти во всех своих неудачных примерах для применения наследования, и мои контр примеры.

Я их не игнорирую, я их не вижу. Я только вижу «неправильно», «не подходит», «ошибочно», «неудачно», «опыт».

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

Всем было бы проще, если бы ты предложил решения проблем. «Нужно было использовать наследование вот так и проблем бы не было».

Не заметил.

По твоему нет инструментов, которые измеряют степень переиспользования кода, эффективность применения ООП наследования и т.п.?

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

kaldeon
()
Ответ на: комментарий от sanyo1234

[Иерархия] не застывшая во времени классификация, которую ты при желании всегда можешь достать из кармана. Её структура определяется ограничениями реальности, требованиями проекта… . есть Вася, о котором ты что-то знаешь по литературным предпочтениям, а что-то знаешь из его медицинской книжки. Но это один Вася, не ReadingVasilii и MedicalVasilii.

IMHO очень неудачный пример. Вася больше подходит в качестве экземпляра класса Human, у которого могут быть свойства, описывающие его Reading и Medical особенности и предпочтения.

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

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

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

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

Go, кстати, попытался решить часть проблем. Это немногословный язык, предпочитающий простые решения сложным (if err ≠ nil — граничащий случай: упрощает последовательность исполнения, но раздувает код). Но люди не спешат на него переходить, потому что для них количество строк не главное.

Разумеется, 2,000,000 строк на hello world — это слишком. Но программисты и не встречаются с такими крайностями, а ещё нужно учесть множество других аспектов, которые намного ощутимее влияют на проект, чем минус 10 строк кода здесь, минус 50 там.

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 7)
Ответ на: комментарий от kaldeon

Компромисс возможен не в правильном использовании, а в ограниченном контексте,

И чем это отличается одно от другого?

когда проблема сводится к деталям и специфике, а не базовым принципам.

А когда проблема сводится к базовым принципам вместо специфики частного случая?

Я против protected ничего не имею, это как раз допустимый компромисс. Но это не инкапсуляция.

Ну так C# гибкий. Можно опцианально выбирать только private и будет полная инкапсуляция.

Неопределённость возникает из-за приблизительного использования понятий. «Частичная инкапсуляция», «приблизительная истина» и т.д.

Да с чего ты взял, что при дизайне руководствовались стремлением к полной инкапсуляции, а не выгодам, получаемым от частичной инкапсуляции при её правильном использовании?

В области познания и программирования нет ничего вреднее, чем приблизительное.

Дооо, поэтому индустрия LLM показывает такой бурный рост.

«Database может отправлять запросы, но ещё ты можешь унаследоваться и вмешаться в пул задач» — это не частичная инкапсуляция.

От реализации не зависит?

Наследование - это один из инструментов. Требования проекта разве регламентируют его использование?

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

А если родительский класс - часть тиражируемой ООП библиотеки?

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

Если следовать твоей логике, то раз множественное наследование не добавили ни в Java, ни в C#, то значит оно очень многими считается бесполезным? Вообще разве можно натягивать частный случай крестов на все остальные?

so, it’s even more true for multiple inheritance.

Т.е. таки вредная?

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

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

придумали тупицы, используют идиоты, разработчики C++ дураки».

Я такое где-то упоминал? Я лишь думаю, что от него больше вреда, чем пользы в отличие от обычного наследования.

Ошибка подразумевает, что её можно было избежать. А как?

Разве я не показывал, как?

Допустим, у нас много сущностей, на которые можно подписаться — не просто Event и Day, а ещё десяток других сущностей. Например, это какая-то внутренняя система для журналистов — им нужно быть постоянно в курсе различных сущностей, внутренних и внешних. Мы вынесли подписку в общий родительский класс, а в дочерних классах неизбежно привязались к особенностям родительского класса.

Когда количество сущностей больше единицы, и тем более, если их неопределённо много, то используют динамические структуры данных, а не статическое наследование?

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

Множественная реализация почти одинакового кода ведёт к дополнительным затратам на разработку.

Архитектурные ошибки — слишком широкое понятие. Что я должен был архитектурно сделать, чтобы избежать описанных проблем?

Изучить ООП дизайн? Почитать соответствующие книги?

Важно то, что в моих примерах проблемы возникают из-за наследования.

Забиваю микроскопом гвозди, но они плохо забиваются и микроскоп почему-то потом плохо работает?

Я их не игнорирую, я их не вижу. Я только вижу «неправильно», «не подходит», «ошибочно», «неудачно», «опыт».

Поэтому сделал вывод, что микроскоп ущербен?

Всем было бы проще, если бы ты предложил решения проблем. «Нужно было использовать наследование вот так и проблем бы не было».

Вася, учи матчасть! Читай книжки про ООП.

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

SonarQube, Codacy, Code Climate, Codebeat, CKJM, CodeMR, NDepend, CppDepend

sanyo1234
() автор топика
Последнее исправление: sanyo1234 (всего исправлений: 1)
Ответ на: комментарий от BruteForce

Это что, сырой вывод чатГПТ?

Это summary для всей ветки, т.е. итого на основе получившегося обсуждения.

sanyo1234
() автор топика
Ответ на: комментарий от BruteForce

Ещё раз итоги по версии текстогенератора:

1. Преимущества подхода

  • Прозрачность и простота: легко посчитать, просто объяснить заказчику.
  • Мотивация к лаконичности: если учесть требования к качеству (DRY, тесты, best practices), появляется стимул писать компактно и эффективно.
  • Гибкость в Agile: удобно для микрозадач и быстрой переоценки при изменении требований.

2. Недостатки и риски

  • Риски злоупотреблений: без контроля качества возможен «честинг» — искусственное раздувание кода, копипаст.
  • Не универсально: для сложных, творческих, архитектурных задач ценность кода не определяется количеством строк.

3. Выводы

  • Оплата за строку кода может быть полезна для стандартизированных, повторяющихся задач в DevOps и инфраструктуре при жёстком контроле качества.
  • Для большинства проектов лучше использовать смешанные метрики: оплата за задачи, строки, качество (code review, тесты).
  • Модель оплаты за строку кода — не универсальна, но может применяться для отдельных типов задач при строгом контроле качества.
sanyo1234
() автор топика
Ответ на: комментарий от sanyo1234
private - скрыто от всех, включая наследников - полная инкапсуляция

protected - скрыто от внешнего мира, но доступно наследникам - частичная инкапсуляция

public - доступно всем - не инкапсулировано

ПРОГРАММИСТА! В ЗАЛЕ ЕСТЬ ПРОГРАММИСТ!?

thesis ★★★★★
()

До 1000 строчек - бесплатно на уровне AI, проект 5к+ строчек оплата за 8 часов работы с AI, то есть 10-20к рублей, свыше по договорённости.

One ★★★★★
()
Ответ на: комментарий от sanyo1234

Это на каком языке пишешь? Не понимаю.

One ★★★★★
()
Ответ на: комментарий от sanyo1234

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

Видишь? Видишь проблему, м?

thesis ★★★★★
()
Ответ на: комментарий от thesis

Как я мог придти на запах своего слабоумия?

Ещё с прошлого твоего визита не выветрился, очень стойкая вонища:

Стоимость строки кода в разных регионах и на удалёнке (комментарий)

sanyo1234
() автор топика
Последнее исправление: sanyo1234 (всего исправлений: 2)
Ответ на: комментарий от thesis

Подумал, что раз от тебя опять завоняло, значит тема насущная и аткуальная!

sanyo1234
() автор топика
Ответ на: комментарий от sanyo1234

Про наследование

«[DatabaseClient] может отправлять запросы, но ещё ты можешь унаследоваться и вмешаться в пул задач» — это не частичная инкапсуляция.

От реализации не зависит?

У DatabaseClient есть пул задач (или очередь запросов) — это реализация. Мы её сделали protected, чтобы дочерние классы могли в неё вмешаться и сделать по-своему. Любой доступ кем-то кроме тебя самого — не инкапсуляция.

Можно, конечно, сделать так, чтобы все protected члены не были реальной реализацией, а интерфейсом между родителем и дочерними классами. Скорее всего, так делают. Только тогда это не «частичная инкапсуляция», а полная. И тогда это буквально композиция в другой форме: вместо DatabaseClient implements IClient и MyClient(IClient) мы имеем MyClient extends DatabaseClient, при этом IClient никуда не делся, а растворился в тумане protected членов. Я люблю динамичные техники, но в данном случае это скорее неконтролируемый процесс.

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

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

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

А если родительский класс - часть тиражируемой ООП библиотеки?

Если оставить за скобками нужность самого класса, а только говорить о наследуемости, то у библиотечного класса множество клиентов, поэтому он стоит дороже, чем «гроши». Но библиотеки нужно по-другому оценивать, через их абстракции, а не наследуемость. Может оно повсюду наследуется, но всё равно неудобно в использовании.

Про инкапсуляцию

Ну так C# гибкий. Можно опцианально выбирать только private и будет полная инкапсуляция.

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

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

И ещё уже несколько раз было упомянуто, что private — это якобы полная инкапсуляция. Это неудобное определение. Мы можем сделать поле приватным, но открыть его наружу с помощью геттеров/сеттеров. Ни о какой инкапсуляции, в таком случае, речь не идёт. public/private/protected — модификаторы доступа.

Да с чего ты взял, что при дизайне руководствовались стремлением к полной инкапсуляции, а не выгодам, получаемым от частичной инкапсуляции при её правильном использовании?

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

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

А так да, не одним абстрактным кодом едины.

Про множественное наследование

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

Если следовать твоей логике, то раз множественное наследование не добавили ни в Java, ни в C#, то значит оно очень многими считается бесполезным? Вообще разве можно натягивать частный случай крестов на все остальные?

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

Множественное наследование не «натягивается» на все остальные языки, оно подходит (может быть полезным, удобным) к любому языку, в котором есть обычное наследование.

Perhaps composition? This is true for inheritance, and so, it’s even more true for multiple inheritance.

Т.е. таки вредная? [multiple inheritance]

Вредная — неподходящее слово. Если проект уже сделал для себя решение использовать наследование, множественное наследование может быть необходимо. Если следовать принципу composition over inheritance, то следует избегать наследование само по себе.

придумали тупицы, используют идиоты, разработчики C++ дураки».

Я такое где-то упоминал? Я лишь думаю, что от него больше вреда, чем пользы в отличие от обычного наследования.

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

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

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

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

Про то, что я неправильно применяю наследование

Есть Event и Day — несколько типов объектов, на которые можно подписаться. Допустим, в нашей системе они настолько родственны, что есть основание создать родительский класс Subscribable и включить в него значительную часть общей реализации.

В этот момент происходит привязка к реализации, что нарушает принцип инкапсуляции. Ты не можешь легко заменить Subscribable на, допустим, IntenseSubscribable — то же самое поведение, но с другой механикой.

Разве нельзя было унаследовать Event и Day от IntenseSubscribable, а IntenseSubscribable от Subscribable ?

В Event и Day уже происходят механики, жёстко привязанные к особенностям Subscribable.

Это твоя очередная архитектурная ошибка ?

[Как её можно избежать?]

Разве я не показывал, как?

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

Понятно, что если бы нам заранее было известно, что множество классов (Event, Day, …) могут проявлять свойства разных частей системы (Subscribable, IntenseSubscribable, …), то тут нужно думать по-другому. Вся суть проблем с наследованием в том, что заранее мы не знаем куда будет развиваться проект, что оно заставляет выбрать иерархию перед тем, как на наш выбор может повлиять опыт.

Когда количество сущностей больше единицы, и тем более, если их неопределённо много, то используют динамические структуры данных, а не статическое наследование?

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

Структуры данных про другое, в них геометрические отношения между данными (жук является родителем человека в бинарном дереве), а не абстракциями.

Архитектурные ошибки — слишком широкое понятие. Что я должен был архитектурно сделать, чтобы избежать описанных проблем?

Изучить ООП дизайн? Почитать соответствующие книги?

Да. И не использовать наследование (после прочтения тоже).

Забиваю микроскопом гвозди, но они плохо забиваются и микроскоп почему-то потом плохо работает? … Поэтому сделал вывод, что микроскоп ущербен?

Метафора — не аргумент.

Вася, учи матчасть! Читай книжки про ООП.

Что хуже: убивать своё время, следуя непрошеным советам, или давать такие советы другим людям?

kaldeon
()
Последнее исправление: kaldeon (всего исправлений: 1)
Ответ на: комментарий от sanyo1234

Про всё остальное

Компромисс возможен не в правильном использовании, а в ограниченном контексте

И чем это отличается одно от другого?

«Правильный компромисс» ничего не говорит о природе компромиссов. Всё что угодно может быть правильным и неправильным, разделение на таком уровне бесполезно. Контекст обозначает область того, что сознаёт индивид в определённый момент. Ограниченный обозначает, что компромисс применяется не ко всем знаниям или принципам индивида, а чем-то меньше (лучше значительно меньше).

А когда проблема сводится к базовым принципам вместо специфики частного случая?

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

В области познания и программирования нет ничего вреднее, чем приблизительное.

Дооо, поэтому индустрия LLM показывает такой бурный рост.

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

измерить успешность наследования в «GUI, 3D графике и математике» — это непосильная задача.

По твоему нет [SonarQube, Codacy, Code Climate, Codebeat, CKJM, CodeMR, NDepend, CppDepend], которые измеряют степень переиспользования кода, эффективность применения ООП наследования и т.п.?

Впервые вижу эти программы, честно говоря. Это статический анализ, нечто вроде PVS Studio?

Но я всё равно сомневаюсь, что они могут измерить успешность наследования. Они могут в лучшем случае найти дублирующийся код. Есть множество способов организовать код, только человек сможет сказать какой именно подходит конкретному проекту в конкретном случае. И ты не можешь ему после этого сказать «смотри, PVS Studio сделал за тебя ту же самую работу».

kaldeon
()
Закрыто добавление комментариев для недавно зарегистрированных пользователей (со score < 50)