Здравствуйте, AndrewVK, Вы писали:
AVK>"direct component objects" это составная часть объекта, где экземпляр создается инициализатором поля и в конструкторе. Если ты создаешь объект в вызове метода, то это не direct component objects нифига.
Это уже некоторая политика владения объектом. В википедийном определении речь только о том, где и какие методы можно звать.
ARK>>Что такое "created within"? AVK>Метод является владельцем экземпляра объекта.
А метод другого объекта не может передать владение (абстрактная фабрика)?
AVK>2 + 3 вообще не является элементом ОО дизайна в подавляющем большинстве языков, не надо доводит до абсурда.
Ну, меня интересует формальное определение закона (что указано в первом посте), если конечно оно в принципе возможно. Формальное определение должно учитывать все случаи, в том числе и арифметические операторы. Абсурд тут ни при чем. Кроме того, есть ведь языки и не принадлежащие "большинству".
ARK>>А если мы просто перенесем операцию в другое место в нашем же объекте — это хрень какая-то получается. AVK>Не просто в другое место, в другой метод. А что тебя удивляет? Многие принципы ООД по сути говорят о том, как распределить код по методам и/или классам.
А что, перенос вызова в другой метод нашего объекта уменьшает число связей? Если мы используем напрямую Order.Customer (неважно, в каком методе), то по-прежнему, если кто-то изменит реализацию Customer, нам придется переделывать свой код. Нет?
Здравствуйте, samius, Вы писали:
S>Можно, но формулировка закона касается того, каким образом был получен объект, а не того, как его хранить в локальных переменных. S>А что может запретить записывать в глобальную переменную? Она ведь вроде по умолчанию именно "переменная" и не указано что она readonly/const.
Вроде как тут должна быть полная аналогия. Если закон о том, "как получен объект" (т.е. некая политика владения), то глобальные переменные не должны давать индульгенцию на косвенный вызов методов. Если же мы принимаем, что все же закон в этой части дает послабление, то мы по идее должны признать такую же возможность и для локальных переменных.
ARK>>Так что формальное определение не то что сводит к абсурду, оно просто неполное и допускает разные трактовки. S>А есть ли трактовка, которая объясняет чем вызов через точку вреднее явной передачи параметра?
Если явная передача идет в метод нашего же объекта, то мне такая трактовка неизвестна — разницы в этих двух случаях не вижу, по-прежнему мы завязаны на структуру другого объекта (потенциально подверженного изменениям).
S>Но все-таки закон не о том, какие объекты писать, а о том, какие методы не вызывать.
Не вызывать методы "внутреннего" объекта.
Но в таком случае получаем отсутствие абстрактных фабрик (как минимум).
Наверное нужно формальное определение политик владения. Если функция нам отдает объект "целиком", отказываясь от всех прав на него, то мы можем делать с этим объектом чего захотим. Если не отдает... то фиг знает, чего мы можем делать.
S>К сожалению раздел о LoD у того же Боба цитирует определение буквально и не раскрывает сути его работы.
Да, там все основывается на чутье и опыте. А хотелось бы больше формализма.
S>Да, Боб добавляет неразбирихи. Оказывается, что надо делать различие между объектами и структурами данных. Знать лишнее об объектах плохо, а о структурах данных — нет.
Да, есть там такое. Это не очень понятно, ведь изменение в структуре данных точно так же потребует изменений в клиентском коде.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, AlexRK, Вы писали:
ARK>>Мало того, в таком случае получается, что мы можем вызывать любые цепочки методов — мы ведь просто вызываем статические методы класса в засахаренном виде. Определение становится бессмысленным. Значит в нем явно чего-то не хватает.
S>>>В итоге смысл закона сводится к тому что в контексте метода m FooBar(foo) лучше чем Foo::Bar(foo). И не совсем очевидно, чем это лучше с позиций знания внутреннего устройства класса Foo.
ARK>>С этих позиций ничем не лучше. Просто странный способ укорачивания метода.
S>Это способ сделать неявные зависимости явными. Раньше весь ваш код зависел от метода Bar, а теперь только код метода FooBar. S>В ещё более реальном случае (типа того, который был процитирован где-то выше), мы перестаём полагаться на то, что у Customer есть Name, из которого можно сделать Substring с далеко идущими выводами, а начинаем полагаться на наличие у Customer метода GetFirstName — на этот раз, с чётко определённой семантикой.
Ну да, я про это и говорю.
Комментируя фразу "в контексте метода m FooBar(foo) лучше чем Foo::Bar(foo)", я подумал, что речь идет исключительно о разнице между статическим методом и методом экземпляра (возможно, я не так понял ее смысл).
Здравствуйте, Кодт, Вы писали:
К>Здравствуйте, samius, Вы писали:
К>>>Заметили вы оба или нет, но это каламбур. Per rectum и есть "напрямую". S>>Это напрямую для тех, кто термин придумал. Для медиков, полагаю. А для программистов "напрямую" и "через ..опу" — это два различных направления
К>rectum = прямая (кишка). А программисты могли бы и не использовать в речи двусмысленные термины
Скажите лучше, что вы думаете о законе Деметры.
После чтения ваших постов у меня сложилось впечатление, что вы интересуетесь всякими теоретическими изысканиями.
Здравствуйте, Sinclair, Вы писали:
S>Вот так нельзя. Мало ли, как устроен кастомер с точки зрения ордера. Завтра мы захотим иметь возможность работать с юридическими лицами, и весь код, завязанный на личное имя покупателя, сломается. S>Закон Деметры заставляет вас задуматься над тем, зачем вообще нужна эта строчка. S>Чтобы написать в емейле "Уважаемый <firstName>, ваш заказ номер <orderNumber> уже отправлен, и в самое ближайшее время заслышится жизнерадостный стук в вашу дверь или весёлая трель домофона"? S>Тогда надо делать order.GetCustomerGreetingLine(), который для юридических лиц сможет вернуть "представитель ООО Мефодий Мунтян и Сыновья, действующий на основании доверенности №2013/156Ф, выданной 5 июня 2013 года". Независимо от того, каким боком Order привязан к Customer. S>Примерно так.
Полностью согласен.
Но в формальном определении этого нет. Как сюда втиснуть фабрики объектов и операторы? Никак, только "полагаясь на здравый смысл"?
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>Вообще, формально что такое "direct component objects"? S>Объекты, включённые в O. В нарочито-ссылочных языках типа Delphi, Java, или C#, отличить объекты "принадлежащие" О от внешних ссылок формально невозможно, но в данном контексте это не очень важно.
В данном — да, не очень важно. Но вообще в контексте LoD — очень важно. Ведь нам надо точно знать, у каких объектов (даже экземпляров) какие методы можно звать.
S>>Точнее, о том, что запрет вызывать некоторые методы у нелегально полученных объектов освобождает от зависимости лишь в том случае, когда нет вызовов методов у легально полученных объектов. Как в этом случае влияет закон на зависимости — непонятно. S>Как раз понятно. Мы имеем зависимости двух типов: S>1. Я завишу от foo; я завишу от baz S>2. Я завишу от того, что foo зависит от baz.
Отлично. Обратите внимание, что ваши типы зависимостей не зависят от способа получения объекта, как в LoD.
S>Закон борется с зависимостями второго типа. Его выполнение гарантирует то, что если я изменил зависимость между foo и baz, то список потенциальных повреждений ограничивается прямыми зависимостями от foo. Так мы локализуем возможные проблемы.
Прежде мы вынуждены разобраться с тем, чем зависимость от метода foo.Bar() хуже зависимости от метода FooBar(foo). И чем потенциальные повреждения в одном случае хуже потенциальных повреждений в другом.
Из формулировки закона можно сделать весьма сомнительное следствие, говорящее о том что вызов через точку — зло. Ведь если писать только методы с явной передачей параметра (я не рассматриваю сейчас виртуальные методы), то применять LoD будет просто не к чему.
S>>Пусть будет order.Customer.GetFirstName(). S>Вот так нельзя. Мало ли, как устроен кастомер с точки зрения ордера. Завтра мы захотим иметь возможность работать с юридическими лицами, и весь код, завязанный на личное имя покупателя, сломается. S>Закон Деметры заставляет вас задуматься над тем, зачем вообще нужна эта строчка. S>Чтобы написать в емейле "Уважаемый <firstName>, ваш заказ номер <orderNumber> уже отправлен, и в самое ближайшее время заслышится жизнерадостный стук в вашу дверь или весёлая трель домофона"? S>Тогда надо делать order.GetCustomerGreetingLine(), который для юридических лиц сможет вернуть "представитель ООО Мефодий Мунтян и Сыновья, действующий на основании доверенности №2013/156Ф, выданной 5 июня 2013 года". Независимо от того, каким боком Order привязан к Customer. S>Примерно так.
Все как бы верно. Только причиной создания метода GetCustomerGreetingLine стал не LoD, а уточнение требований (или оверинженеринг). Вчера было достаточно GetFirstName-а без учета представителей и доверенностей. И опять таки, по тому же LoD метод order.GetCustomerGreetingLine() дает меньшую гибкость чем Order::GetCustomerGreetingLine(order).
Здравствуйте, AlexRK, Вы писали:
ARK>Это уже некоторая политика владения объектом.
Это смысл фразы direct component objects.
ARK>>>Что такое "created within"? AVK>>Метод является владельцем экземпляра объекта. ARK>А метод другого объекта не может передать владение (абстрактная фабрика)?
Фабрика этот тот же конструктор, вид сбоку.
ARK>Ну, меня интересует формальное определение закона
Пока что я вижу что тебя интересует доведение до абсурда, имхо. В дизайне нет и не может быть законов, которые формализуются до уровня математических теорем, потому что почти все они это эмпирика, а не выведенные математически правила. А эмпирика потому что он направлен на восприятие кода человеком, а не на достижение абсолютно формализуемых критериев. Так что, если захотеть, можно довести до абсурда абсолютно любой закон и принцип, потому что даже фундаментальные понятия — coupling, cohesion, readability — не формализуемы, а все остальное в основном от них и пляшет.
AVK>>Не просто в другое место, в другой метод. А что тебя удивляет? Многие принципы ООД по сути говорят о том, как распределить код по методам и/или классам. ARK>А что, перенос вызова в другой метод нашего объекта уменьшает число связей?
Да, уменьшает число связей этого метода. Кроме того, уменьшение связности это не только уменьшение числа связей, но еще и упорядочивание этих связей, чтобы сильные связи были как можно компактнее и внутри границ вероятного изменения контрактов. Возьми, для примера, IoC — число связей там не меняется, а связность уменьшается. Сабж направлен ровно на то же самое — на инкапсуляцию сильных связей в семантически плотном коде метода, а не раскидывание их через границы разных методов и классов.
ARK> Если мы используем напрямую Order.Customer (неважно, в каком методе), то по-прежнему, если кто-то изменит реализацию Customer, нам придется переделывать свой код. Нет?
Нет. Потому что если я что то поменяю в Customer, будет лучше если перед глазами не будет маячить код, в котором, помимо Customer, еще и Customer.Address.Country какой нибудь присутствует.
... << RSDN@Home 1.2.0 alpha 5 rev. 100 on Windows 8 6.2.9200.0>>
Здравствуйте, samius, Вы писали:
S>В данном — да, не очень важно. Но вообще в контексте LoD — очень важно. Ведь нам надо точно знать, у каких объектов (даже экземпляров) какие методы можно звать.
Имхо, формулировка закона плоха.
S>Отлично. Обратите внимание, что ваши типы зависимостей не зависят от способа получения объекта, как в LoD.
Это согласуется с интуитивным пониманием целей закона.
S>Прежде мы вынуждены разобраться с тем, чем зависимость от метода foo.Bar() хуже зависимости от метода FooBar(foo). И чем потенциальные повреждения в одном случае хуже потенциальных повреждений в другом.
Вопрос не в зависимости от foo.Bar(), а о зависимости от того, что вернёт foo.Bar().
S>Из формулировки закона можно сделать весьма сомнительное следствие, говорящее о том что вызов через точку — зло.
В доисторические времена закон звучал примерно так: "вызов через две точки — зло".
А современная формулировка — попытки прижать хитрецов, которые заменяют foo.bar().baz() на t = foo.bar(); t.baz().
S>>Примерно так. S>Все как бы верно. Только причиной создания метода GetCustomerGreetingLine стал не LoD, а уточнение требований (или оверинженеринг).
Не совсем. LoD потребовал бы от нас засунуть в order метод GetCustomerFirstName(), потому что через две точки — нельзя.
А greeting — это уже результат анализа всех мест использования GetcustomeFirstName(), проведённого при code review.
Вчера было достаточно GetFirstName-а без учета представителей и доверенностей. И опять таки, по тому же LoD метод order.GetCustomerGreetingLine() дает меньшую гибкость чем Order::GetCustomerGreetingLine(order).
Не вижу, где. Вы имеете в виду, что у результата Order::GetCustomerGreetingLine(order) я буду иметь право вызывать методы? Не понимаю.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.
Здравствуйте, AlexRK, Вы писали:
ARK>Здравствуйте, samius, Вы писали:
ARK>Вроде как тут должна быть полная аналогия. Если закон о том, "как получен объект" (т.е. некая политика владения), то глобальные переменные не должны давать индульгенцию на косвенный вызов методов. Если же мы принимаем, что все же закон в этой части дает послабление, то мы по идее должны признать такую же возможность и для локальных переменных.
нельзя сказать однозначно без знания о том, имеют ли пункты формулировки приоритеты.
S>>Но все-таки закон не о том, какие объекты писать, а о том, какие методы не вызывать.
ARK>Не вызывать методы "внутреннего" объекта. ARK>Но в таком случае получаем отсутствие абстрактных фабрик (как минимум).
Все-таки не отсутствие, а нежелательность вызовов методов объектов, полученных у фабрик. Опять-таки, что в точности понимать под инстанциированием? Инстанциирует фабрика, но по заказу из текущего метода, т.е. косвенно инстанциирует и текущий метод тоже. Хотя глядя на фабрику мы не можем с уверенностью сказать, инстанциирует ли она или берет объект у третьих лиц. ARK>Наверное нужно формальное определение политик владения. Если функция нам отдает объект "целиком", отказываясь от всех прав на него, то мы можем делать с этим объектом чего захотим. Если не отдает... то фиг знает, чего мы можем делать.
Не нужно. И без этого все неоднозначно.
S>>Да, Боб добавляет неразбирихи. Оказывается, что надо делать различие между объектами и структурами данных. Знать лишнее об объектах плохо, а о структурах данных — нет.
ARK>Да, есть там такое. Это не очень понятно, ведь изменение в структуре данных точно так же потребует изменений в клиентском коде.
вот-вот.
Здравствуйте, Sinclair, Вы писали:
S>Здравствуйте, samius, Вы писали:
S>>В данном — да, не очень важно. Но вообще в контексте LoD — очень важно. Ведь нам надо точно знать, у каких объектов (даже экземпляров) какие методы можно звать. S>Имхо, формулировка закона плоха.
Согласен.
S>>Отлично. Обратите внимание, что ваши типы зависимостей не зависят от способа получения объекта, как в LoD. S>Это согласуется с интуитивным пониманием целей закона.
Получается что интуитивное понимание целей закона расходится с формальным описанием способа его применения.
S>>Прежде мы вынуждены разобраться с тем, чем зависимость от метода foo.Bar() хуже зависимости от метода FooBar(foo). И чем потенциальные повреждения в одном случае хуже потенциальных повреждений в другом. S>Вопрос не в зависимости от foo.Bar(), а о зависимости от того, что вернёт foo.Bar().
FooBar(foo) вернет то же самое и имеет точно такие же риски изменений, как и foo.Bar().
S>>Из формулировки закона можно сделать весьма сомнительное следствие, говорящее о том что вызов через точку — зло. S>В доисторические времена закон звучал примерно так: "вызов через две точки — зло". S>А современная формулировка — попытки прижать хитрецов, которые заменяют foo.bar().baz() на t = foo.bar(); t.baz().
Да, помню такие времена. Однако, на хитрецов, которые решат не делать у объекта экземплярных методов, у закона ничего нет. И не было.
S>>>Примерно так. S>>Все как бы верно. Только причиной создания метода GetCustomerGreetingLine стал не LoD, а уточнение требований (или оверинженеринг). S>Не совсем. LoD потребовал бы от нас засунуть в order метод GetCustomerFirstName(), потому что через две точки — нельзя.
Нет, он этого буквально не требует. Он ведь разрешает так же метод Order.GetCustomerFirstName(order). S>А greeting — это уже результат анализа всех мест использования GetcustomeFirstName(), проведённого при code review.
Вот и я об этом. Но раз мы предположили наличие результата такого анализа, точно так же можем предположить и отсутствие такого результата, либо анализа.
S>Вчера было достаточно GetFirstName-а без учета представителей и доверенностей. И опять таки, по тому же LoD метод order.GetCustomerGreetingLine() дает меньшую гибкость чем Order::GetCustomerGreetingLine(order). S>Не вижу, где. Вы имеете в виду, что у результата Order::GetCustomerGreetingLine(order) я буду иметь право вызывать методы? Не понимаю.
Нет, я имею в виду что Order::GetCustomerGreetingLine(order) можно будет вызывать откуда угодно, не оглядываясь на LoD. А oder.GetSustomerGreetingLine() лишь в тех местах, где order получен легально по LoD.
Здравствуйте, AndrewVK, Вы писали:
AVK>Пока что я вижу что тебя интересует доведение до абсурда, имхо. В дизайне нет и не может быть законов, которые формализуются до уровня математических теорем, потому что почти все они это эмпирика, а не выведенные математически правила. А эмпирика потому что он направлен на восприятие кода человеком, а не на достижение абсолютно формализуемых критериев. Так что, если захотеть, можно довести до абсурда абсолютно любой закон и принцип, потому что даже фундаментальные понятия — coupling, cohesion, readability — не формализуемы, а все остальное в основном от них и пляшет.
Я понимаю вашу позицию. Тем не менее, не исключаю, что формализация некоторых — сейчас неформализованных, но формализуемых в принципе — вещей вполне может привести к общему улучшению этих самых "неформализуемых в принципе" фундаментальных понятий. Собственно, тема как раз об этом.
ARK>> Если мы используем напрямую Order.Customer (неважно, в каком методе), то по-прежнему, если кто-то изменит реализацию Customer, нам придется переделывать свой код. Нет? AVK>Нет. Потому что если я что то поменяю в Customer, будет лучше если перед глазами не будет маячить код, в котором, помимо Customer, еще и Customer.Address.Country какой нибудь присутствует.
Вот это не понял. Я понимаю так:
// клиентский кодvar country = order.Customer.Address.Country; // BAD. знаем слишком много об объекте Order
DoSomething(country);
...
order.DoSomethingWithCountry(); // OK. ничего не знаем, можно менять Order как угодно
...
this.DoSomething(order); // а тут чего хорошего? опять надо будет переделывать _наш_ класс, если изменится Customer
Здравствуйте, AlexRK, Вы писали:
ARK>Скажите лучше, что вы думаете о законе Деметры. ARK>После чтения ваших постов у меня сложилось впечатление, что вы интересуетесь всякими теоретическими изысканиями.
Ненавижу закон Деметры! Ё)
Существует несколько крайностей в практике создания крупных объектов.
Одна ось крайностей — степень открытости-закрытости. Слева — кишки наружу, справа — всё закрыто интерфейсами и водопроводными методами.
Другая — алгебраичность-неповторимость. Слева — композиции композиций безымянных структур, справа — каждый тип сделан по-своему, так что любые полиморфные операции над ними нужно специализировать, т.е. вводить прослойку адаптеров.
Самый ураган в том, что алгебраичность прекрасно уживается с закрытостью. Кортеж интерфейсов к объектам, управляющим кортежами интерфейсов.
Прямо сейчас ковыряюсь в OpenFST — так там алгебраичность плюс закрытость, это адъ для отладки.
Но больше всего достаёт то, что контексты для вычисления передаются не (только) как параметры методов, но и как члены-данные объектов. Вот где зло. И пофиг, делается ли это через кишки наружу или через водопроводные методы.
Водопровод позволяет расставить прерывания и отследить, кто что где меняет. А кишки — добавить интересующие поля в watch window.
Хороший, абстрагирующий водопровод — мешает добавить вотчи. Алгебраический шаблонный водопровод — мешает расставлять прерывания. Алгебраические кишки — снимают всякую уверенность, что кто-то где-то не имеет внезапный доступ к данным.
Извините, наболело. Не могу быть беспристрастен. Поэтому см. первую строку ответа.
Здравствуйте, Кодт, Вы писали:
К>Ненавижу закон Деметры! Ё)
Понятно.
К>Самый ураган в том, что алгебраичность прекрасно уживается с закрытостью. Кортеж интерфейсов к объектам, управляющим кортежами интерфейсов.
Не можете привести простенький пример? А то я что-то медитировал-медитировал, да не вымедитировал. Речь о функциях, возвращающих вместо примитивных типов указатели на сложные структуры?
К>Но больше всего достаёт то, что контексты для вычисления передаются не (только) как параметры методов, но и как члены-данные объектов. Вот где зло.
Дык — в точном соответствии с принципами, изложенными в Clean Code.
К>Алгебраический шаблонный водопровод — мешает расставлять прерывания. Алгебраические кишки — снимают всякую уверенность, что кто-то где-то не имеет внезапный доступ к данным.
Вот это тоже не понял. А кто у нас поимеет доступ к данным мимо водопроводных методов? Или "алгебраические кишки" выдаются наружу через указатель с возможностью модификации?
Здравствуйте, AlexRK, Вы писали:
К>>Самый ураган в том, что алгебраичность прекрасно уживается с закрытостью. Кортеж интерфейсов к объектам, управляющим кортежами интерфейсов.
ARK>Не можете привести простенький пример? А то я что-то медитировал-медитировал, да не вымедитировал. Речь о функциях, возвращающих вместо примитивных типов указатели на сложные структуры?
Я издеваюсь и утрирую, но при этом очень сильно преуменьшаю.
OpenFST изобилует такими схемами.
К>>Но больше всего достаёт то, что контексты для вычисления передаются не (только) как параметры методов, но и как члены-данные объектов. Вот где зло.
ARK>Дык — в точном соответствии с принципами, изложенными в Clean Code.
Дык и что в этом хорошего, если мутабельность на мутабельности мутабельностью погоняет.
Если любой скрытый параметр может поменяться в недрах любого метода.
Это не God Object, а Devil Staff.
К>>Алгебраический шаблонный водопровод — мешает расставлять прерывания. Алгебраические кишки — снимают всякую уверенность, что кто-то где-то не имеет внезапный доступ к данным.
ARK>Вот это тоже не понял. А кто у нас поимеет доступ к данным мимо водопроводных методов? Или "алгебраические кишки" выдаются наружу через указатель с возможностью модификации?
Алгебраические кишки делаются так, что те, кому нужен прямой доступ, — просто наследуются от разнообразных хелперов и встраиваются в цепочку алгебраически сконструированных шаблонов. А кому не нужен, те используют готовые базовые хелперы.
С самого верхнего уровня доступа к потрохам нет... если предварительно не встроился.