Не отрицаю того что вы говорите. Но. Я не утверждал что мы изолированная нейронная сеть. Так же как и нейронки подвержены ошибкам из-за технических збоев и в принципе технического ограничения вычислений, мы подвержены не только гормонам но и болезням, паразитам, пролетающим сквозь нас космическим излучениям. Все это бессмысленно отбрасывать. Но даже все это 'не случайно' и не дарует нам ни какой свободы воли.
Мы сложнее собак. Естественно обучать нас сложнее. Это первое о чем я говорю. Тряпия это не быстро.
Категорически не согласен. Терапия работает. На это есть исследования. И в общем с этим глупо спорить. Просто нужно понимать что это никогда не быстрое решение. Невозможно прожить 30 лет с проблемами и решить их за 5 сеансов. Это постоянная работа.
Нужно осознать для начала что свободы воли не существует. Все мы по сути своей сложные нейронные сети. Чтобы нейронные сети работали так как ожидается их обучают очень Длительное время. Если сеть работает с ошибками то её переобучают. То же самое и терапия. Это переобучение. Это инструмент позволяющий клиенту по новому воспринимаю происходящее и перестроить свою нейронную сеть а посредством этого и свое мышление, отношение к событиям вызывающим неадекватную реакцию.
Начать нужно с того что профессиональные психологи обязаны ходить на 'супервизии' где они обсуждают всякое и в том числе определённые проблемы неопределённых клиентов. В ит разработчики тоже обсуждают всякие проблемы своих проектов. Это называется 'делиться опытом'. Во вторых какая вам разница что какой то Петя Васечкин над вами подшучивает за спиной? Это действительно настолько большая проблема что вы сознательно отказываетесь от практики которая пойдёт вам на пользу? А что вы скажете своему ребёнку который отказывается идти в школу потому что кто то посмеятся над ним? Мне кажется это первое что нужно обсуждать с психологом и прорабатывать - зависимость от чужого времени. Прямо с порога можно и начинать : я беспокоюсь что вы будете обсуждать меня со своими коллегами и смеяться. Уверяю вас это очень глубокая кроличья нора. Далее. Психотерапевт никогда вас не оценивает. Ни вас. Ни ваши поступки. Ни ваши эмоции/ощущения. Его задача в другом. А вот по поводу найти качественного специалиста - это уже действительно серьёзная проблема. И дело тут даже не обязательно в профессионализме последнего. Просто нужно найти человека 'под себя'.
К сожалению даже в вашем примере вся боль бойлерплейтных конструкторов осталась на месте. Просто вместо пачки зависимостей они превратились в одну и вынесены в другой файл. Когда в FinalA и FinalB реализации интерфейсов используются различные то и объеденить все в один BaseDeps уже не получится. Это как раз мой случай.
Required фича, судя по описанию, позволит избавиться от этих конструкторов с пробросами. То есть вообще не придется их прописывать. И мой вопрос был в том : будет ли дефолтный .net core контейнер поддерживать required свойства\поля и автоматически собирать зависимости без конструктора с аргументами уже в net7 на старте ?
Видимо я чего то не знаю. Есть какой то конкретный шаблон проектирования? Было бы достаточно названия. Дальше я бы нашел где почитать.
Есть вероятность что я не совсем корректно сформулировал свою боль.
abstract class Base
{
public Base(IFirstInterface first, ISecondInterface second,..){}
//all methods with bl here
}
abstract class Middle: Base
{
//painful
public Middle (IFirstInterface first,ISecondInterface second,...):base(first,second,...){}
//some overrided methods
}
sealed class FinalA : Middle
{
//painful
public FinalA(...) : base(...){}
}
sealed class FinalB : Middle
{
//painful
public FinalB(...):base(...){}
}
судя по описанию фичи required больне не будет необходимости пробрасывать аргументы конструктора. дотаточно будет поменить нужные свойства. вопрос в том будет ли это поддержано со стороны контейнеров инверсии зависимостей.
Required properties with dependency injection? Все ещё придется пробрасывать аргументы через всю иерархию наследования или наконец то можно будет забыть про это?
Представляю как вы будете пересаживать киберкотлет с 144герцовых мониторов обрано на 60герцовые. Ведь какая разница сколько раз в секунду меняется кадр если все равно больше 30 не видим)
Свободы воли нет. Любое решение принято до того как осознано. Восприятие влияет на сознание и наоборот. Быть или не быть нпс - не выбор, а данность зависящая от окружающей вас действительности вплоть до мелочей и генетической базы. Ровно как быть единственным наследником мультимиллиардера вложившего в ваше образование значительные средства.
Студия Артемия Лебедева использовала нейронку для создания материалов. Насколько я понял успешно это комерциализировала. Так что нейросети уже де-факто комерческо применимые средства. Конкретно dalle очередной шаг эволюции. Думаю уже нет смысла пытаться делить это на технология/эксперимент. Мы живём в мире где все программное обеспечение одновременно находится и в состоянии эксперимента и в состоянии продукта. Инста, твич изначально задумывались и работали не сколько по другим направлениям и в процессе сменили его. Любые масштабные сервисы имеют множество фич на а/б тестировании. Ничто не имеет конечного, финального, 'технологичного' состояния. Все подверженно изменениям. Dalle - технология не доступная широким массам.
Не понимаю претензии многих комментаторов по поводу однотипности и отсутствия 'художественного' видения при реализации запросов. Это особое видение никому не нужно. Если у конечно пользователя запрос на red robot то и изображение должно строго соответствовать этому. Лишние элементы будут только мешать и приводить к дополнительным циклам перерисовки по запросу. Пользователь знает что ему нужно и при необходимости будет дополнять описания для получения требуемой детализации. Но только тогда когда это действительно востребованно, а не наоборот. Это то как должен работать дизайн в современном мире. Кмк.
Пхп тоже всего лишь язык. Я привел конкретный пример когда подобный подход менее безопасен чем использование интерфейса. Это, как по мне, достаточный ответ на изначальный вопрос
Каким образом моки классов более небезопасны, чем интерфейсы?
Если хотя бы в части случаем метод менее безопасный это значит что он менее безопасный в целом.
Потому что требования поменялись.
Происходит повсеместно. Вы не обернули все вызовы внешней библиотеки декоратором и теперь вам нужно поменять n точек вызова у вашем коде на нужный вызов. Изменение контракта проблема сложная, но она не зависит от того пользуете ли вы интерфейс или конечную реализацию. Но с декоратором вы как раз могли бы легко изменить вызов одного метода на другой или целочку вызовов в одном единственном месте.
Потому что в новой версии lib (или тем более внешней системы) появились новые возможности, или поменялись существующие (например исправили баг, что повлекло добавление нового параметра в метод).
Да. Все так. Что изменилось от наличия интерфейса? В худшем случае вы добавите метод в интерфейс руками. Остальное за вас сделает ide. Это не проблема.
Мы говорим про добавление нового метода в этот простой публичный интерфейс. Например, раньше подключение к какому-то ресурсу закрывалось автоматически, а потом решили, что надо добавить метод Close().
Тот самый случай когда вы добавите метод в интерфейс. Это займет больше 5 минут? Как часто вы обновляете библиотеки в своих проектах?
А пока разрабатываем и тестируем, туда могут добавляться дополительные аргументы, меняться их типы или типы возвращаемых значений. И для всего этого надо делать аналогичные изменения в интерфейсе. Это уже не "потратить 5 минут на создание интерфейса".
Ознакомьтесь с возможностями современных ide
При чем тут точки вызова? Я говорю про ситуацю, что при изменениях в реализации надо параллелельно менять интерфейс. Менять реализацию чего-то таким образом, что затрагивается публичный контракт, приходится довольно часто,
Если изменился контракт вы меняете входные данные в точках вызова. Изменения внутри интерфейса происходят автоматически при использовании ide. Единственным случаем ручного изменения могу придумать только добавление нового публичного метода.
ситуация, когда реализация существует в единственном экземпляре, тоже встречается довольно часто. Причем при следовании подходу "делаем много мелких классов с атомарной ответственностью и соединяем их через композицию" это проблема еще более выражена, так как композиция подразумевает наличие публичных методов у композируемых компонентов.
Все верно. Более того, осмелился бы даже сказать не "довольно часто" а 95% интерфейсов имеет одну реализацию. Иногда есть специальные реализации для дебага и тестов.
Смысл атомарного подхода в том что мы дорожим сложный алгоритм на цепочку простых и независимых. Что бы в каждый момент времени у нас был максимально узкий контекст работы и анализ этого кода был для нас тривиален. Вы будете писать, тестировать, отлаживать один раз, а читать его тысячи. И там где вам не нужно знать конкретно каким методом считается условное 'среднее' вы не будете этот код видеть.
Лично я никогда не рассматривал это как проблему, но создавать дополнительные сложности в разработке ради того, чтобы подсказки в IDE были другие, мне кажется неправильным подходом.
Вы правильно написали. Это ваше личное мнение. У других людей оно может быть другим. Я не вижу сложности в явном выделении сегрегированного интерфейса для класса. Для меня большая проблема видеть конечные реализации на пару экранов которые по какой то причине не были закрыты интерфейсом.
Когда я ищу баг, мне неинтересно, какая функциональность тут востребована, мне интересно, какая реализация тут вызывается.
Представим простую цепочку вызовов:
Controller -> Facade -> BLService -> Repository
Допустим у вас баг в бизнес логике. Вам важно какая у вас реализация чего то кроме BLService? Мне думается что нет. Я проигнорирую абсолютно всю цепочку кроме конкретного вызова. Попасть в этот вызов можно разными путями. Найти реализации через поиск или через дебаг или через логи. Это не проблема. Главное тут что вы так или иначе игнорируете реализацию 80% классов и исследует только ту что вам действительно фажна.
Зачем нам исследовать конкретную реализацию, если мы смотрим вызывающий код?
Зачем в коде оставлять конкретную реализан если она не важна? Высокоуровневый компонент не должен зависеть от деталей реализации конкретного инкапсулированного объекта. Это создаёт сложности для тестирования и расширения.
В рантайме под интерфейсом всегда есть какая-то конкретная реализация, которая каким-то образом мутирует какие-то данные.
Именно по этому проектировать нужно с интерфейса взаимодействия задавая контракт и ограничения на изменения данных. Реализация не должна знать деталей вызова как собственно и наоборот. Когда вы используете конкретную реализацию (даже если один раз в одном конкретном месте) вы потенциально создаёте опасность того что кто будет манипулировать данными (компонента данными овнера или овнер данными компоненты) тем самым нарушая публичный контракт взаимодействия. Например обновлять какие то параметры компоненты напрямую после вызова методов. Просто потому что: ну а чё бы и нет. Я же так сэкономил 5 минут на работе.
Видится мне это все так что все описанные вами "сложности" сводятся к тому что в процессе работы вы не знаете что будете делать дальше, не планируете на будущее и не хотите тратить чуть больше времени на написание тривиального, шаблонного кода.
С одной стороны я понимаю что многое действительно невозможно предугадать, но это не причина не придерживаться стандартных подходов.
Каким образом моки классов более небезопасны, чем интерфейсы?
Кажется вы плохо читаете мои комментарии.
Дублирую
Warning: Substituting for classes can have some nasty side-effects!
For starters, NSubstitute can only work with virtual members of the class that are overridable in the test assembly, so any non-virtual code in the class will actually execute! If you try to substitute for a class that formats your hard drive in the constructor or in a non-virtual property setter then you’re asking for trouble. (By overridable we mean public virtual, protected virtual, protected internal virtual, or internal virtual with InternalsVisibleTo attribute applied. See How NSubstitute works for more information.)
Понадобилось добавить method_4 в реализацию, которая единственная, и надо лезть еще и в интерфейс.
Для начала стоит хорошенечко подумать: а с какой такой стати вы меняете интерфейс взаимодействия с подсистемой (интерфейс может скрывать не просто класс из вашего проекта но и вызов к внешней системе)? Вероятно вы выбрали неверную абстракцию изначально. Во вторых это вновь нарушение принципа закрытости и открытости. Если этот метод плотно связан с предыдущей функциональностью то его вызов должен быть скрыт за простым, публичным интерфейсом. Если это независимый от предыдущейфункциональности метод то он должен быть выделен в отдельный интерфейс (interface segregation principle).
Теперь задайте себе вопрос : как часто вы будете добавлять по новому методу который нужно будет обязательно дополнительно вызывать в части или во всех точках вызова? Мое личное имхо на основе моего личного опыта - умозрительно редко. Чаще будет происходить сокрытое добавление вызова внутри публичных мелодов (валидации, блокировки).
Понадобилось поменять тип аргумента в method_3, и надо снова лезть в интерфейс.
За вас это прекрасно сделает ide. Только не говорите что вы пишете код в блокноте.
Я вот вообще не вижу никакой разницы в контекстной информации между вызовами
Ниже вам уже ответили о том что внутри класса может быть сколь угодно много других методов и полей не относящихся к текущему контексту. Более того интерфейсом вы подчеркивает какая именно функциональность востребована конкретно тут в отрыве от реализации (которая может быть любой). Это даёт нам право игнорировать эту самую реализацию и фокусировать внимание на текущем уровне абстракции вместо того чтобы исследовать конкретную реализацию. Тк если она фиксирована то она имеет значение, может повлиять на поток выполнения или каким то образом явно мутировать данные (этим в целях экономии памяти могут заниматься приватные методы класса). Конечно, в общем случае, достигнуть подобного возможно и при работе с интерфейсом, но чуть большими усилиями в сравнении с тем чтобы создать конкретную реализацию класса на месте и передать в него по ссылке данные используемые в последствии. Интерфейс не гарантирует безопасности вызова сам по себе, но подталкивает по другому относиться к проектированию компонент. Ещё раз invention of control.
Делать так имеет смысл всегда, если интерфейс в остальном коде нигде не будет использоваться.
То есть все таки далеко не всегда. И как я показал своим примером далеко не везде. Это и есть моя основная идея.
Даже если разброс 50/50 использование небезопасного подхода приведет к кому что 100% нужно задумываться лишний раз о том а как лучше реализовать в этом конкретном месте вместо того чтобы придерживаться безопасной реализации всегда.
Да. В каком то смысле это вкусовщина. Но на мой вкус это попахивает больше ленью инженера. Потратить 5 минут на создание интерфейса в процессе работы не вносит значительного импакта на время разработки. Интерфейс с парой методов не создаст никому проблем. Убережёт вас от ненужной контекстной информации. Позволяет делать простые и безопасные тесты (пусть на с# и вероятно где то ещё(скорее всего во всех строго типизированных языках)). И вообще это инверсия контроля и не мне рассказывать зачем это нужно.
Подразумевается не конкретная библиотека-заглушка, а библиотека, позволяющая делать заглушки.
По всей видимости вы правы.
Только вот совет все равно выглядит вредным. Стабать конкретный клас осмысленно только в случае когда вы не имеете доступа к самому классу (не являетесь владельцем кода) и он действительно не имеет интерфейса. Кроме того этот способ имеет серьезные ограничения.
Warning: Substituting for classes can have some nasty side-effects!
For starters, NSubstitute can only work with virtual members of the class that are overridable in the test assembly, so any non-virtual code in the class will actually execute! If you try to substitute for a class that formats your hard drive in the constructor or in a non-virtual property setter then you’re asking for trouble. (By overridable we mean public virtual, protected virtual, protected internal virtual, or internal virtual with InternalsVisibleTo attribute applied. See How NSubstitute works for more information.)
Зачем снимать сиденье с велосипеда мне не понятно. Вы на нем может быть и не сидите, но люди привыкли к другу.
Если меняется любая коммуникация между элементами, то это часто имеет каскадный эффект и требует изменений во многих элементах. Поэтому пусть они и имеют только одну причину для изменений, это не приносит пользы, если единственное изменение часто требует внесения изменений во множество элементов, превращая модификацию кода в мучения.
Какое то очень своеобразное понимание и реализация принципа solid. Если вы столкнулись с подобной ситуацией, то вы явно что то сделали не так.
Solid существует для того чтобы придерживаться реализации при которой код внутри класса имеет high cohesion и low coupling с внешним миром.
Кроме того, наличие классов, меняющихся только по одной причине, часто не даёт реальных практичных преимуществ. На самом деле, внесение изменений в классы, выполняющие несколько действий, часто даёт разработчику гораздо больше контекста, упрощающего понимание изменения и его влияние на окружающий код.
Отсутствие причин для изменений - преимущество само по себе. Когда на ревью вы смотрите изменения в большом файле на несколько строк тут и там это становится головной болью и причиной по которой ревью проходит на авось.
Больший контекст при реальной работе не добавляет абсолютно ни каких преимуществ. Откройте любой код на 4т строк и я уверен вы поймёте о чем я говорю. Человеческий мозг очень таки ограничен в своих возможностях.
Понимание Изменения влияния на окружение будет происходить только при учёте анализа точек вызова и ни как иначе. Вне зависимости от размера файла.
Тем не менее, почти все шаблоны имеют недостаток: они повышают структурную сложность и снижают согласованность кода.
Программное обеспечение всегда сложно. Со временем его сложность только растет. Сложность нельзя просто взять и убрать. Ей можно только пытаться манипулировать.
Любой шаблон - это агрегированный опыт многих поколений людей по стандартному решению стандартных ситуаций через которых сложность реализации переносится на уровень сложности архитектуры.
Множество сервисов реализованных в рамках одной архитектуры УВЕЛИЧИВАЮТ согласованность и консистентность кодовой базы. Упрощают понимание кода соседнего сервиса и таким образом значительно облегчают работу по их поддержке и модификации. Облегчают найм людей способных понимать стандартные решения. Я надеюсь что в индустрии таких людей большинство.
Сюрприз но то что вы сделали со своей кодовой базой тоже будет шаблоном пусть и комплексным. Любой новый разработчик будет понимать что происходит на проекте изучив один ендпоинт при условии что все остальные выполнены в рамках той же архитектуры.
Не жертвуйте читаемостью кода в пользу необязательной эффективности, и помните, что затраты времени разработчика часто сильно превосходят потенциальный выигрыш от экономии вычислительных ресурсов микрооптимизацией кода.
Полностью поддерживаю.
Отдельной фиче не требуются слабое связывание и интерфейсы для элементов, которые находятся внутри неё, потому что такое слабое связывание имеет свою цену.
Казалось бы верное утверждение, но на самом деле фичи бывают разных 'объемов'. Можно легко написать фичу на ещё 4т строк. Слабое связывание помогает при тестировании фич в отсутствии изначальной системы. Позволяет разобрать фичу на части и тестировать их отдельно. Позволяет разрабатывать ее разными командами людей. Достаточно согласовать интерфейсы. Если вы будете часть фич делать 'побыстрому', а часть как полагается исходя из вашей стандартной архитектуры, то очень быстро придёте к ситуации полного бардака. Потому что, сюрприз, программисты решили что можно и так. А если спросят то всегда сослаться на сраки и дедлайны. И вообще они не виноваты. У вас везде так фичи написаны. Это ваша новая архитектура.
Слабое связывание, и в особенности интерфейсы, снижают согласованность кода и усложняют ориентирование в нём, потому что ты не знаешь непосредственно, какой конкретно код будет исполняться. Тебе сначала нужно проверить, какие реализации существуют в интерфейсе, а затем разобраться, какая конкретно применяется во время исполнения.
Мне кажется что я не так понимаю вашу 'согласованность кода'.
Если у интерфейса есть множество реализаций то как минимум нужно понимать для каких случаев они нужны. Опять же мы понятия не имеем что за интерфейсом скрывается. Да и вся суть собственно в том чтобы и не задумываться об этом. Чтобы инженер фокусировался на важной для него задаче, а не копался в потрохах какой то конкретной реализации какого то конкретного интерфейса. Зачем? Альтернатива этому (шаблон стратегия) будет полная реализация всех альтернатив на месте ( внутри текущего файла) и свитч для выбора нужной на месте вызова. По вашему это действительно упростит чтение и понимание?
Кроме того, если вы используете интерфейсы только для того, чтобы можно было применять заглушки в тестах, то серьёзно рассмотрите возможность перехода на библиотеку-заглушку, позволяющую имитировать конкретные классы, чтобы избежать лишней траты ресурсов.
Мне нужно подготовить по заглушке на каждый вызов метода имеющего внутренний вызов библиотеки? А если я хочу проверить метод с разными данными, значительно влияющими на поток выполнения?
Method(input)
a = lib.method_1(input);
if a
then b = lib.method_2(input);
else b = lib.method_3(input);
Сколько заглушке для библиотеки мне нужно подготовить чтобы протестировать все пути исполнения? Это действительно экономия? Тащить в проект фейковые либы в проект. Между прочим их тоже кому то придется поддерживать. И как раз в этом случае сделать это будет сильно сложнее. Потому что их будет много и для каждой конкретной нужно чётко понимать где и как она используется. И это без учёта возможных кодов ошибок или же исключительных ситуаций которые тоже нужно тестировать.
Вы действительно думаете что не стоит закрывать это интерфейсами?
По этой причине мы полностью отказались от подобного юнит-тестирования и выбрали совершенно иной подход к автоматизированному тестированию.
Прозвучало так : мы создали себе проблему, а потом героически ее решили. Решили что это не проблема и просто удалили тесты.
Ранее вы описывали особенность solid - закрытость к изменениям и открытость к расширению. Если бы вы действительно этого придерживались то подобные проблемы с тестами происходили бы у вас крайне редко.
Возможно я вам удивлю но не все наркоманы выглядят как 'наркоманы'. Зачастую они живут по соседству и ни кто об этом не знает. Кроме того наркоманы чаще менее буйные чем например алкоголики. Хотя и с этим можно поспорить. В любом случае нет. Ложка дегдя здесь не применима. Можно ещё долго спорить об абстракциях и ассоциациях. А вот про отсутствие государства пожалуй выскажусь. Хотя пожалуй тоже нет. Уже слишком скользкая дорога. Обмолвлюсь только что государство вмешается только если упорно об это просить. И то не факт что сразу.
Я не говорил что нужно отменять правовое регулирование со стороны государства.
Нацисты и прочие это как раз доведенные до абсурда идеи. Это грань до которой люди могут докатиться если кто будет держать всю власть в своих единственных руках. То что не нравится лично ему одному будет худшим злом и предметом гонений.
Нужно чуточку больше осознанности людям. Чтобы они были в контексте происходящего и могли принимать решения. Тогда будет ответственность и может быть жить станет чуточку лучше.
Мы не знаем исходных данных кроме тех что представляет нам человек с которым мы говорим. Утверждение было о том что вы и ваша семья живут рядом с наркоманами. Мое дальшейшее предположение было что и остальные вокруг наркоманы. Я сделал некие необоснованные выводи пытаясь подчеркнуть свою мысль. Точно так же поступили и вы предположив что все остальные не наркоманы. Правда где то рядом. Любая ситуация особенная. Многое останется за гранью нашего понимания в угоду личных галюцинанаций каждого.
Даже коллективное желание сделать что то с наркоманами может превратиться в самосуд. Я в очередной раз пытаюсь сказать что мы не должны нарушать чужие границы. Мы можем только пытаться взаимодействовать. В рамках закона и морали. В том числе пытаться решать подобного рода проблемы через государственные рычаги. Но даже тут очень легко оступиться. Можно попросить знакомых в органах, структурах которые могут несколько переусердствовать а вы со своей стороны мало того что закроете на это глаза так ещё и поощерите их. Что непосредственно ведёт к поощрению насилия по отношению к гражданам. Какими бы они ни были. Единственный способ перебороть - это впитать толерантность. Конечно и в этом должна быть определенная граница указать которую я не способен в связи с непрофильным образованием. Считаю что такие вопросы обязаны решаться медицинскими и психологическими консенсусами.
Не отрицаю того что вы говорите. Но. Я не утверждал что мы изолированная нейронная сеть. Так же как и нейронки подвержены ошибкам из-за технических збоев и в принципе технического ограничения вычислений, мы подвержены не только гормонам но и болезням, паразитам, пролетающим сквозь нас космическим излучениям. Все это бессмысленно отбрасывать. Но даже все это 'не случайно' и не дарует нам ни какой свободы воли.
Мы сложнее собак. Естественно обучать нас сложнее. Это первое о чем я говорю. Тряпия это не быстро.
Категорически не согласен. Терапия работает. На это есть исследования. И в общем с этим глупо спорить. Просто нужно понимать что это никогда не быстрое решение. Невозможно прожить 30 лет с проблемами и решить их за 5 сеансов. Это постоянная работа.
Нужно осознать для начала что свободы воли не существует. Все мы по сути своей сложные нейронные сети. Чтобы нейронные сети работали так как ожидается их обучают очень Длительное время. Если сеть работает с ошибками то её переобучают. То же самое и терапия. Это переобучение. Это инструмент позволяющий клиенту по новому воспринимаю происходящее и перестроить свою нейронную сеть а посредством этого и свое мышление, отношение к событиям вызывающим неадекватную реакцию.
Начать нужно с того что профессиональные психологи обязаны ходить на 'супервизии' где они обсуждают всякое и в том числе определённые проблемы неопределённых клиентов. В ит разработчики тоже обсуждают всякие проблемы своих проектов. Это называется 'делиться опытом'. Во вторых какая вам разница что какой то Петя Васечкин над вами подшучивает за спиной? Это действительно настолько большая проблема что вы сознательно отказываетесь от практики которая пойдёт вам на пользу? А что вы скажете своему ребёнку который отказывается идти в школу потому что кто то посмеятся над ним? Мне кажется это первое что нужно обсуждать с психологом и прорабатывать - зависимость от чужого времени. Прямо с порога можно и начинать : я беспокоюсь что вы будете обсуждать меня со своими коллегами и смеяться. Уверяю вас это очень глубокая кроличья нора. Далее. Психотерапевт никогда вас не оценивает. Ни вас. Ни ваши поступки. Ни ваши эмоции/ощущения. Его задача в другом. А вот по поводу найти качественного специалиста - это уже действительно серьёзная проблема. И дело тут даже не обязательно в профессионализме последнего. Просто нужно найти человека 'под себя'.
Я конечно дилетант, но советую вам посмотреть : Мозг с Дэвидом Игелменом. Думаю что вы должны поменять свое мнение на этот счет.
Вопрос не в том как я могу это автоматизировать. Вопрос в том смогу ли я от этого избавиться. Ответ на этот вопрос я пытаюсь получить весь этот тред.
Личная боль связана не с тем что мне приходиться набирать на 5 строчек больше. Боль связана с эстетическим неудовлетворением.
классов типа FinalClass сотни. Прописывать везде эти конструткоры порядком утомительно. Надежда на то что required поможет удалить конструкторы.
К сожалению даже в вашем примере вся боль бойлерплейтных конструкторов осталась на месте. Просто вместо пачки зависимостей они превратились в одну и вынесены в другой файл. Когда в FinalA и FinalB реализации интерфейсов используются различные то и объеденить все в один BaseDeps уже не получится. Это как раз мой случай.
Required фича, судя по описанию, позволит избавиться от этих конструкторов с пробросами. То есть вообще не придется их прописывать. И мой вопрос был в том : будет ли дефолтный .net core контейнер поддерживать required свойства\поля и автоматически собирать зависимости без конструктора с аргументами уже в net7 на старте ?
Видимо я чего то не знаю. Есть какой то конкретный шаблон проектирования? Было бы достаточно названия. Дальше я бы нашел где почитать.
Есть вероятность что я не совсем корректно сформулировал свою боль.
Required properties with dependency injection? Все ещё придется пробрасывать аргументы через всю иерархию наследования или наконец то можно будет забыть про это?
Свободы воли нет. Любое решение принято до того как осознано. Восприятие влияет на сознание и наоборот. Быть или не быть нпс - не выбор, а данность зависящая от окружающей вас действительности вплоть до мелочей и генетической базы. Ровно как быть единственным наследником мультимиллиардера вложившего в ваше образование значительные средства.
Если бы вы действительно интересовались вопросом который задали то очень быстро бы нашли ответ в Гугле: https://ironov.artlebedev.com/ru/#
С ней все в порядке.
Студия Артемия Лебедева использовала нейронку для создания материалов. Насколько я понял успешно это комерциализировала. Так что нейросети уже де-факто комерческо применимые средства. Конкретно dalle очередной шаг эволюции. Думаю уже нет смысла пытаться делить это на технология/эксперимент. Мы живём в мире где все программное обеспечение одновременно находится и в состоянии эксперимента и в состоянии продукта. Инста, твич изначально задумывались и работали не сколько по другим направлениям и в процессе сменили его. Любые масштабные сервисы имеют множество фич на а/б тестировании. Ничто не имеет конечного, финального, 'технологичного' состояния. Все подверженно изменениям. Dalle - технология не доступная широким массам.
Не понимаю претензии многих комментаторов по поводу однотипности и отсутствия 'художественного' видения при реализации запросов. Это особое видение никому не нужно. Если у конечно пользователя запрос на red robot то и изображение должно строго соответствовать этому. Лишние элементы будут только мешать и приводить к дополнительным циклам перерисовки по запросу. Пользователь знает что ему нужно и при необходимости будет дополнять описания для получения требуемой детализации. Но только тогда когда это действительно востребованно, а не наоборот. Это то как должен работать дизайн в современном мире. Кмк.
Пхп тоже всего лишь язык. Я привел конкретный пример когда подобный подход менее безопасен чем использование интерфейса. Это, как по мне, достаточный ответ на изначальный вопрос
Если хотя бы в части случаем метод менее безопасный это значит что он менее безопасный в целом.
Происходит повсеместно. Вы не обернули все вызовы внешней библиотеки декоратором и теперь вам нужно поменять n точек вызова у вашем коде на нужный вызов. Изменение контракта проблема сложная, но она не зависит от того пользуете ли вы интерфейс или конечную реализацию. Но с декоратором вы как раз могли бы легко изменить вызов одного метода на другой или целочку вызовов в одном единственном месте.
Да. Все так. Что изменилось от наличия интерфейса? В худшем случае вы добавите метод в интерфейс руками. Остальное за вас сделает ide. Это не проблема.
Тот самый случай когда вы добавите метод в интерфейс. Это займет больше 5 минут? Как часто вы обновляете библиотеки в своих проектах?
Ознакомьтесь с возможностями современных ide
Если изменился контракт вы меняете входные данные в точках вызова. Изменения внутри интерфейса происходят автоматически при использовании ide. Единственным случаем ручного изменения могу придумать только добавление нового публичного метода.
Все верно. Более того, осмелился бы даже сказать не "довольно часто" а 95% интерфейсов имеет одну реализацию. Иногда есть специальные реализации для дебага и тестов.
Смысл атомарного подхода в том что мы дорожим сложный алгоритм на цепочку простых и независимых. Что бы в каждый момент времени у нас был максимально узкий контекст работы и анализ этого кода был для нас тривиален. Вы будете писать, тестировать, отлаживать один раз, а читать его тысячи. И там где вам не нужно знать конкретно каким методом считается условное 'среднее' вы не будете этот код видеть.
Вы правильно написали. Это ваше личное мнение. У других людей оно может быть другим. Я не вижу сложности в явном выделении сегрегированного интерфейса для класса. Для меня большая проблема видеть конечные реализации на пару экранов которые по какой то причине не были закрыты интерфейсом.
Представим простую цепочку вызовов:
Controller -> Facade -> BLService -> Repository
Допустим у вас баг в бизнес логике. Вам важно какая у вас реализация чего то кроме BLService? Мне думается что нет. Я проигнорирую абсолютно всю цепочку кроме конкретного вызова. Попасть в этот вызов можно разными путями. Найти реализации через поиск или через дебаг или через логи. Это не проблема. Главное тут что вы так или иначе игнорируете реализацию 80% классов и исследует только ту что вам действительно фажна.
Зачем в коде оставлять конкретную реализан если она не важна? Высокоуровневый компонент не должен зависеть от деталей реализации конкретного инкапсулированного объекта. Это создаёт сложности для тестирования и расширения.
Именно по этому проектировать нужно с интерфейса взаимодействия задавая контракт и ограничения на изменения данных. Реализация не должна знать деталей вызова как собственно и наоборот. Когда вы используете конкретную реализацию (даже если один раз в одном конкретном месте) вы потенциально создаёте опасность того что кто будет манипулировать данными (компонента данными овнера или овнер данными компоненты) тем самым нарушая публичный контракт взаимодействия. Например обновлять какие то параметры компоненты напрямую после вызова методов. Просто потому что: ну а чё бы и нет. Я же так сэкономил 5 минут на работе.
Видится мне это все так что все описанные вами "сложности" сводятся к тому что в процессе работы вы не знаете что будете делать дальше, не планируете на будущее и не хотите тратить чуть больше времени на написание тривиального, шаблонного кода.
С одной стороны я понимаю что многое действительно невозможно предугадать, но это не причина не придерживаться стандартных подходов.
Кажется вы плохо читаете мои комментарии.
Дублирую
Для начала стоит хорошенечко подумать: а с какой такой стати вы меняете интерфейс взаимодействия с подсистемой (интерфейс может скрывать не просто класс из вашего проекта но и вызов к внешней системе)? Вероятно вы выбрали неверную абстракцию изначально. Во вторых это вновь нарушение принципа закрытости и открытости. Если этот метод плотно связан с предыдущей функциональностью то его вызов должен быть скрыт за простым, публичным интерфейсом. Если это независимый от предыдущейфункциональности метод то он должен быть выделен в отдельный интерфейс (interface segregation principle).
Теперь задайте себе вопрос : как часто вы будете добавлять по новому методу который нужно будет обязательно дополнительно вызывать в части или во всех точках вызова? Мое личное имхо на основе моего личного опыта - умозрительно редко. Чаще будет происходить сокрытое добавление вызова внутри публичных мелодов (валидации, блокировки).
За вас это прекрасно сделает ide. Только не говорите что вы пишете код в блокноте.
Ниже вам уже ответили о том что внутри класса может быть сколь угодно много других методов и полей не относящихся к текущему контексту. Более того интерфейсом вы подчеркивает какая именно функциональность востребована конкретно тут в отрыве от реализации (которая может быть любой). Это даёт нам право игнорировать эту самую реализацию и фокусировать внимание на текущем уровне абстракции вместо того чтобы исследовать конкретную реализацию. Тк если она фиксирована то она имеет значение, может повлиять на поток выполнения или каким то образом явно мутировать данные (этим в целях экономии памяти могут заниматься приватные методы класса). Конечно, в общем случае, достигнуть подобного возможно и при работе с интерфейсом, но чуть большими усилиями в сравнении с тем чтобы создать конкретную реализацию класса на месте и передать в него по ссылке данные используемые в последствии. Интерфейс не гарантирует безопасности вызова сам по себе, но подталкивает по другому относиться к проектированию компонент. Ещё раз invention of control.
То есть все таки далеко не всегда. И как я показал своим примером далеко не везде. Это и есть моя основная идея.
Даже если разброс 50/50 использование небезопасного подхода приведет к кому что 100% нужно задумываться лишний раз о том а как лучше реализовать в этом конкретном месте вместо того чтобы придерживаться безопасной реализации всегда.
Да. В каком то смысле это вкусовщина. Но на мой вкус это попахивает больше ленью инженера. Потратить 5 минут на создание интерфейса в процессе работы не вносит значительного импакта на время разработки. Интерфейс с парой методов не создаст никому проблем. Убережёт вас от ненужной контекстной информации. Позволяет делать простые и безопасные тесты (пусть на с# и вероятно где то ещё(скорее всего во всех строго типизированных языках)). И вообще это инверсия контроля и не мне рассказывать зачем это нужно.
По всей видимости вы правы.
Только вот совет все равно выглядит вредным. Стабать конкретный клас осмысленно только в случае когда вы не имеете доступа к самому классу (не являетесь владельцем кода) и он действительно не имеет интерфейса. Кроме того этот способ имеет серьезные ограничения.
Зачем снимать сиденье с велосипеда мне не понятно. Вы на нем может быть и не сидите, но люди привыкли к другу.
Какое то очень своеобразное понимание и реализация принципа solid. Если вы столкнулись с подобной ситуацией, то вы явно что то сделали не так.
Solid существует для того чтобы придерживаться реализации при которой код внутри класса имеет high cohesion и low coupling с внешним миром.
Отсутствие причин для изменений - преимущество само по себе. Когда на ревью вы смотрите изменения в большом файле на несколько строк тут и там это становится головной болью и причиной по которой ревью проходит на авось.
Больший контекст при реальной работе не добавляет абсолютно ни каких преимуществ. Откройте любой код на 4т строк и я уверен вы поймёте о чем я говорю. Человеческий мозг очень таки ограничен в своих возможностях.
Понимание Изменения влияния на окружение будет происходить только при учёте анализа точек вызова и ни как иначе. Вне зависимости от размера файла.
Программное обеспечение всегда сложно. Со временем его сложность только растет. Сложность нельзя просто взять и убрать. Ей можно только пытаться манипулировать.
Любой шаблон - это агрегированный опыт многих поколений людей по стандартному решению стандартных ситуаций через которых сложность реализации переносится на уровень сложности архитектуры.
Множество сервисов реализованных в рамках одной архитектуры УВЕЛИЧИВАЮТ согласованность и консистентность кодовой базы. Упрощают понимание кода соседнего сервиса и таким образом значительно облегчают работу по их поддержке и модификации. Облегчают найм людей способных понимать стандартные решения. Я надеюсь что в индустрии таких людей большинство.
Сюрприз но то что вы сделали со своей кодовой базой тоже будет шаблоном пусть и комплексным. Любой новый разработчик будет понимать что происходит на проекте изучив один ендпоинт при условии что все остальные выполнены в рамках той же архитектуры.
Полностью поддерживаю.
Казалось бы верное утверждение, но на самом деле фичи бывают разных 'объемов'. Можно легко написать фичу на ещё 4т строк. Слабое связывание помогает при тестировании фич в отсутствии изначальной системы. Позволяет разобрать фичу на части и тестировать их отдельно. Позволяет разрабатывать ее разными командами людей. Достаточно согласовать интерфейсы. Если вы будете часть фич делать 'побыстрому', а часть как полагается исходя из вашей стандартной архитектуры, то очень быстро придёте к ситуации полного бардака. Потому что, сюрприз, программисты решили что можно и так. А если спросят то всегда сослаться на сраки и дедлайны. И вообще они не виноваты. У вас везде так фичи написаны. Это ваша новая архитектура.
Мне кажется что я не так понимаю вашу 'согласованность кода'.
Если у интерфейса есть множество реализаций то как минимум нужно понимать для каких случаев они нужны. Опять же мы понятия не имеем что за интерфейсом скрывается. Да и вся суть собственно в том чтобы и не задумываться об этом. Чтобы инженер фокусировался на важной для него задаче, а не копался в потрохах какой то конкретной реализации какого то конкретного интерфейса. Зачем? Альтернатива этому (шаблон стратегия) будет полная реализация всех альтернатив на месте ( внутри текущего файла) и свитч для выбора нужной на месте вызова. По вашему это действительно упростит чтение и понимание?
Мне нужно подготовить по заглушке на каждый вызов метода имеющего внутренний вызов библиотеки? А если я хочу проверить метод с разными данными, значительно влияющими на поток выполнения?
Method(input)
a = lib.method_1(input);
if a
then b = lib.method_2(input);
else b = lib.method_3(input);
Сколько заглушке для библиотеки мне нужно подготовить чтобы протестировать все пути исполнения? Это действительно экономия? Тащить в проект фейковые либы в проект. Между прочим их тоже кому то придется поддерживать. И как раз в этом случае сделать это будет сильно сложнее. Потому что их будет много и для каждой конкретной нужно чётко понимать где и как она используется. И это без учёта возможных кодов ошибок или же исключительных ситуаций которые тоже нужно тестировать.
Вы действительно думаете что не стоит закрывать это интерфейсами?
Прозвучало так : мы создали себе проблему, а потом героически ее решили. Решили что это не проблема и просто удалили тесты.
Ранее вы описывали особенность solid - закрытость к изменениям и открытость к расширению. Если бы вы действительно этого придерживались то подобные проблемы с тестами происходили бы у вас крайне редко.
Возможно я вам удивлю но не все наркоманы выглядят как 'наркоманы'. Зачастую они живут по соседству и ни кто об этом не знает. Кроме того наркоманы чаще менее буйные чем например алкоголики. Хотя и с этим можно поспорить. В любом случае нет. Ложка дегдя здесь не применима. Можно ещё долго спорить об абстракциях и ассоциациях. А вот про отсутствие государства пожалуй выскажусь. Хотя пожалуй тоже нет. Уже слишком скользкая дорога. Обмолвлюсь только что государство вмешается только если упорно об это просить. И то не факт что сразу.
Я не говорил что нужно отменять правовое регулирование со стороны государства.
Нацисты и прочие это как раз доведенные до абсурда идеи. Это грань до которой люди могут докатиться если кто будет держать всю власть в своих единственных руках. То что не нравится лично ему одному будет худшим злом и предметом гонений.
Нужно чуточку больше осознанности людям. Чтобы они были в контексте происходящего и могли принимать решения. Тогда будет ответственность и может быть жить станет чуточку лучше.
Любая идея доведённая до абсурда - пагубна.
Мы не знаем исходных данных кроме тех что представляет нам человек с которым мы говорим. Утверждение было о том что вы и ваша семья живут рядом с наркоманами. Мое дальшейшее предположение было что и остальные вокруг наркоманы. Я сделал некие необоснованные выводи пытаясь подчеркнуть свою мысль. Точно так же поступили и вы предположив что все остальные не наркоманы. Правда где то рядом. Любая ситуация особенная. Многое останется за гранью нашего понимания в угоду личных галюцинанаций каждого.
Даже коллективное желание сделать что то с наркоманами может превратиться в самосуд. Я в очередной раз пытаюсь сказать что мы не должны нарушать чужие границы. Мы можем только пытаться взаимодействовать. В рамках закона и морали. В том числе пытаться решать подобного рода проблемы через государственные рычаги. Но даже тут очень легко оступиться. Можно попросить знакомых в органах, структурах которые могут несколько переусердствовать а вы со своей стороны мало того что закроете на это глаза так ещё и поощерите их. Что непосредственно ведёт к поощрению насилия по отношению к гражданам. Какими бы они ни были. Единственный способ перебороть - это впитать толерантность. Конечно и в этом должна быть определенная граница указать которую я не способен в связи с непрофильным образованием. Считаю что такие вопросы обязаны решаться медицинскими и психологическими консенсусами.