Введение
Пару-тройку недель назад попалась ссылка на интересный подход к проектированию называющийся DCI, сформулированный создателем MVC.
В кратце его можно передать так: все, что сейчас разрабатывается не ООП, а Class Orientied Programming.
И на самом деле должно быть разделение не на объекты, которые умеют как-то менять свое состояние, а на данные + роли, т.е. то, как разные классы данных взаимодействуют.
Ведь в сущности объект человек это набор ролей: отец, брат, продавец, муж и т.д.
Описание
Во время выполнения программы или любого алгоритма 1 объект может выступать в разных ролях и попытка впихнуть весь этот функционал в класс приводит к жуткой мешанине кода, тесной связность и вообще страданиям, страху и ужасу).
Вместо этого классы доменной логики, сами по себе должны быть эдакими "тупыми" объектами.
Например, объект Банковский Счет должен знать, что у него есть баланс, и он может его повышать и понижать, но только в рамках определенной роли и определенного контекста, к нему добавляется логика, например
1)возможность или невозможность залезть в долг при выдаче наличных,
2)возможность перевода денег на другой счет, при наличии достаточного количества на счету
3)возможность оплатить деньги всем кредиторам.
Все 3 предыдущих пункта - роли, играемые данным счетом в определенном контексте, и например во 2м варианте , этот же счет может играть роль "принимающего" счета.
Фактически любая программная система это динамический набор объектов, которые принимают то одну то другую роль за время своей жизни в рантайме и концпеции типа MVC, позволяют через сеть слоев соединить ментальную модель пользователя с настоящей vjltkm. работы системы.
Но во время разработки программист работает, с ментальной моделью статичной программы, в которой есть классы А И Б, которые умеют действий В и Г, а не с динамической моделью, что вот в этом месте класс А впитывает в себя роль принимающего счета, или брата, или чего-либо еще.
Подход к разработке с использованием парадигм DCI, пытается смягчить "impedance mismatch" (как это по русски-то называется ?)) между моделью системы в работе(runtime), и моделью ее во время разработки(compiletime), что должно послужить повышению читаемости, понятности и предсказуемости поведения программ.
Итого
Чем-то этот подход и сама идея незримо напоминает AOP (который слишком сложен и неудобен и потому не получил особого распространения) и очень даже напоминает идеи mixin-нов, trait-ов и соответственно аспектов (которые мало-помалу вкрадываются во все новомодные языки и предают им синтаксической и концептуальной силы).
С одной стороны вроде получается боян, по причине "вот же оно - уже было".
С другой стороны если посмотреть, как обычно о них рассказывают, то нет именно этого акцента на участие роли в определенном контексте взаимодействия, и отсутствие четких стратегий смешивания этих самых миксинов и ролей.
В общем-то видно, что интуитивно идея постепенно просачивается в программерское сообщество с тенденциями типа DDD, mixin`ов и trait`ов, но возможно с другим именем, и пока только кусками.
Источники
Тексты/Статьи:
1)http://en.wikipedia.org/wiki/Data,_Context_and_Interaction - статья в википедии
2)http://heim.ifi.uio.no/~trygver/themes/babyide/baby-documents.html - набор ссылок от автора
Видео:
1) http://oredev.org/videos/dci-in-practice(качественная речь, на слух воспринимается до скорости 1.3-1.4х)
2) James Coplien - The DCI Architecture: Supporting the Agile Agenda (качественная речь, до 1.6х скорости воспринимается)
Пару-тройку недель назад попалась ссылка на интересный подход к проектированию называющийся DCI, сформулированный создателем MVC.
В кратце его можно передать так: все, что сейчас разрабатывается не ООП, а Class Orientied Programming.
И на самом деле должно быть разделение не на объекты, которые умеют как-то менять свое состояние, а на данные + роли, т.е. то, как разные классы данных взаимодействуют.
Ведь в сущности объект человек это набор ролей: отец, брат, продавец, муж и т.д.
Описание
Во время выполнения программы или любого алгоритма 1 объект может выступать в разных ролях и попытка впихнуть весь этот функционал в класс приводит к жуткой мешанине кода, тесной связность и вообще страданиям, страху и ужасу).
Вместо этого классы доменной логики, сами по себе должны быть эдакими "тупыми" объектами.
Например, объект Банковский Счет должен знать, что у него есть баланс, и он может его повышать и понижать, но только в рамках определенной роли и определенного контекста, к нему добавляется логика, например
1)возможность или невозможность залезть в долг при выдаче наличных,
2)возможность перевода денег на другой счет, при наличии достаточного количества на счету
3)возможность оплатить деньги всем кредиторам.
Все 3 предыдущих пункта - роли, играемые данным счетом в определенном контексте, и например во 2м варианте , этот же счет может играть роль "принимающего" счета.
Фактически любая программная система это динамический набор объектов, которые принимают то одну то другую роль за время своей жизни в рантайме и концпеции типа MVC, позволяют через сеть слоев соединить ментальную модель пользователя с настоящей vjltkm. работы системы.
Но во время разработки программист работает, с ментальной моделью статичной программы, в которой есть классы А И Б, которые умеют действий В и Г, а не с динамической моделью, что вот в этом месте класс А впитывает в себя роль принимающего счета, или брата, или чего-либо еще.
Подход к разработке с использованием парадигм DCI, пытается смягчить "impedance mismatch" (как это по русски-то называется ?)) между моделью системы в работе(runtime), и моделью ее во время разработки(compiletime), что должно послужить повышению читаемости, понятности и предсказуемости поведения программ.
Итого
Чем-то этот подход и сама идея незримо напоминает AOP (который слишком сложен и неудобен и потому не получил особого распространения) и очень даже напоминает идеи mixin-нов, trait-ов и соответственно аспектов (которые мало-помалу вкрадываются во все новомодные языки и предают им синтаксической и концептуальной силы).
С одной стороны вроде получается боян, по причине "вот же оно - уже было".
С другой стороны если посмотреть, как обычно о них рассказывают, то нет именно этого акцента на участие роли в определенном контексте взаимодействия, и отсутствие четких стратегий смешивания этих самых миксинов и ролей.
В общем-то видно, что интуитивно идея постепенно просачивается в программерское сообщество с тенденциями типа DDD, mixin`ов и trait`ов, но возможно с другим именем, и пока только кусками.
Источники
Тексты/Статьи:
1)http://en.wikipedia.org/wiki/Data,_Context_and_Interaction - статья в википедии
2)http://heim.ifi.uio.no/~trygver/themes/babyide/baby-documents.html - набор ссылок от автора
3)гугл =)
1) http://oredev.org/videos/dci-in-practice(качественная речь, на слух воспринимается до скорости 1.3-1.4х)
2) James Coplien - The DCI Architecture: Supporting the Agile Agenda (качественная речь, до 1.6х скорости воспринимается)
3) Trygve Reenskaug - DCI: Re-thinking the foundations of object orientation and of programming
(у него жуткий акцент, очень сложно воспринимаемое на слух видео)
(у него жуткий акцент, очень сложно воспринимаемое на слух видео)
Как я понимаю, Rails 3 насквозь пропитаны этой идеологией, и код при разработке на них модно писать именно так. Т.е. идея уже просочилась, и, вроде даже, стреляет :)
ОтветитьУдалитьНу в динамических языках такое полегче будет провернуть, в сях придеться через шаблоны что есть ужас)
ОтветитьУдалитьТ.е. уже щас пишут вот в таком стиле ?
class AddToCartContext
def initialize(user, shop, product_id, quantity)
//do smtng
end
def execute()
@shop.extend CatalogRole
@user.extend BuyerRole
product = shop.find_product(@product_id)
user.add_to_cart(product, @quantity)
end
end
+ Для первых-вторых рельс вроде было нормально, что логика валидации (и бизнес логика и логика корректности сущности/данных) вносилась в модель ?
скорей так https://gist.github.com/997823
ОтветитьУдалитьCart это типа и есть context.
На счет валидации: сам процесс валидации вынесен в модуль ActiveModel::Validations (т.е. это роль объекта -- быть валидируемым).
В том, что сама модель знает, как быть валидируемой -- тоже вроде бы нет ничего страшного: модель это данные в роли валидных данных. Хотя по идее, такая отговорка не особо нужна, вряд ли имеет смысл писать что-то, что соответствовало бы DCI на всех уровнях абстракции.
Большей частью все происходит мягко и неявно, потому что если явно биндить везде данные с их ролями, выйдет совсем петрушка.
Главный профит здесь -- это имхо разнос логики таким образом, что классы(модули) и методы знают и реализуют только то, что необходимо.
impedance mismatch - дословно "несогласованность по сопротивлению", термин из электротехники.
ОтветитьУдалитьВ software engineering это значит несогласованность моделей (например объектной модели и реляционной при рассмотрении ORM-ов)
А в целом по предлагаемой идее (судя по твоему посту, сейчас гляну первоисточник) я вижу ООП со строгой динамической типизацией.
ОтветитьУдалитьМы настолько привыкли к ООП со строгой статической типизацией (иногда встречаем нестрогую статическую), что считаем, что это и есть "настоящее" ООП :) А подстилей ООП много :)
Ага только получается, что User во все возможные места все равно таскает с собой методы от Buyer`а, даже там где методы должны быть от другой роли.
ОтветитьУдалитьВот такой пример надумал, корявый конечно, но показывает, что статический линкинг(include Smtng) этих методов может привести к не совсем хорошим последствиям:
https://gist.github.com/997931
Дочитал. Да, элегантная идея.
ОтветитьУдалитьНо только это не классический ООП, т.к. мы разделяем данные и поведение.
Надо будет попробовать :)
Кстати, предтечей можно считать DDD в варианте anemic domain model.
Суть коллизии понятна, но я привел пример наиболее употребительного способа применения идей, не претендуя на универсальность и чистоту.
ОтветитьУдалитькстати, применительно к руби, для чистоты все можно подсластить и сделать, чтобы было что-то вроде
ОтветитьУдалитьuser.as(Buyer).can_pay
но так никто не делает :)
@ekr, ага отдаленно похоже, и избавляется от недоcтатков, типа:
ОтветитьУдалитьневозможности коде-реюз,
невозможности проверить корректность домаин обьекта,
нарушения энкапсуляции и т.д.
Это получается DDD поделенное на две абстракции: модели(доменные состояния) + взаимодействия этих состояний и изменения(что собственно автор где-то в одной из статей там подметил).
И нет такой проблемы как в DDD:
к какой модели принадлежит use case "покупка товара" к магазину или пользователю ?.
2Илья:
ОтветитьУдалитьDDD в варианте с анемичной моделью как раз разделяет сервисы (процессы, поведение) и доменные объекты (данные). Т.е. формально это тоже не ООП в классическом виде :)
Если замеппить DCI на anemic DDD, то получается, что DDD-сервис это С+I, а DDD-domain model это D.