«А можно поподробнее о вопросах собеседований? Что спрашивали и что слышали / хотели услышать?»
Я постараюсь чуть позже об этом написать, в двух словах наверно не выйдет.
Вопросы у вас хорошие :) Собственно, сам факт подобных дискуссий, а они встречаются почти везде, где пишут data vs domain, говорит о том, что тема спорная и нераскрытая и ее следует исследовать.
Попробую ответить.
«Какая разница в какой иерархии будет наследование в сущностях домена или в сервисах?»
В ООП объекты могут обладать не только данными, но и действиями / методами, это известно всем и на этом строится собственно весь ООП (инкапсуляция, наследования и тп)
Поэтому ООП хорошо подходит для моделирования чего-то, что обладает не только данными, но и действиями, а так же поведением.
Когда мы выносим весь функционал из моделей в сервисы, то мы разделяем данные и «действия», ведь в ваших сервисах обычно нет данных, это абстракция поведения. Сервисы не могут менять внутреннее состояние модели.
По сути, если идти дальше, то такие модели можно сделать immutable, да, и это нас приблизит к функциональным паттернам. Это не хорошо и не плохо (если говорить об абстрактном решении), это просто по-другому.
Более того, такая anemic модель может лежать в основе rich модели (т.е. rich модель может быть большой «оберткой» для anemic).
«При маппинге в DDD возникает слой с кучей DTO, которые являются дублированием сущностей домена.»
Да, именно поэтому полноценный ddd получается дорогим для небольших проектов, особенно, если у вас реляционная СУБД
Вообще, DTO тема тоже отдельная. Уровень DTO зависит от сложности модели.
ps кстати, добавлю масла в холивар :) anemic model добавляет в жизнь программиста как минимум две «сущности»: модель и сервис, а domain подход, больше стремится к упаковыванию всего этого в модель, поэтому вам не надо вспоминать какой сервис делает, то что вам нужно
Реализуется АОП в PHP ручками )
В самом PHP это пока не планируется, хотя для версии 4.0 были попытки, я даже где-то видел грамматику лексера PHP с учетом аспектов, но это уже в прошлом. Из нового — есть PECL-расширение PHP-AOP, которое разрабатывается, но там куча багов, сегфолтов, да и скорость в отдельных случаях меньше, чем у моей PHP-библиотеки. Моя же библиотека написана на чистом PHP и не требует никаких дополнительных экзотических расширений, за счет этого она стабильна и активно развивается.
Идея работы такая — отслеживаем момент загрузки любого PHP-кода (перехватываются incude/require), делаем статический анализ кода, вносим в него необходимые правки, создаем декоратор, подменяем им оригинальный класс и сохраняем в кэше, дальше отдаем этот код парсеру PHP. После таких манипуляций в памяти PHP будет находиться класс, уже имеющий расширенную функциональность, но с прежним именем класса.
Это краткий обзор предыдущих серий Санта-Барбары под названием «как сделать АОП»
Не, но игрался. Я сейчас использую сфинкс, а не его, только потому, что сфинкс мало памяти ест (эластиксëрч на старте от 100 мб, для маленького впс неприятно ;).
Но у эластика есть куча приятных фич, которых в сфинксе нет никак, можно вот посмотреть в их постах:
Определяется, что стоит слева от выражения вызова (грубо, от скобок — ( )). Главное, что интересует — это тип вычисленного промежуточного значения, который может быть либо Reference type, либо не Reference type.
Первый случай (Reference type) возможен, когда слева стоит либо идентификатор (identifier), либо выражение доступа к свойству (property accessor). Второй случай (не Reference type) — всё остальное.
Далее, у этого значения Reference type берется базовый объект (base), и именно он будет использован в качестве значения this (Если нужно пояснить про Reference type, скажите).
В случае же, когда значение — не Reference type, this получает значение null. Но, т.к. null особого смысла для this не несёт, автоматом подставляется глобальный объект.
Поэтому:
var foo = {bar: function () {}};
foo.bar(); // Reference type (accessor), база - foo
(foo.bar)(); // тоже, Reference type, база - foo, используется оператор группировки
function test() {}
test(); // тоже Reference type (identifier), база - global
this.test(); // равносильно предыдущему, база видна явно
А вот здесь, оператор присваивания (в отличие от оператора группировки в примере выше), вызовет GetValue, и в итоге будет уже не Reference type, а Function:
(foo.bar = foo.bar)(); // не Reference type, this = null => global
Аналогично другие выражения (всё тоже — не Reference type, поэтому this в итоге будет global):
По поводу with: будет Reference type с базой — объект with добавленный к scope chain; поэтому не global.
Есть одно исключение, когда будет получен Reference type (и даже база будет не global, как выше в случае с test), но всё же this будет global. Это в том случае, когда базой будет является объект активации (activation object). Если упрощенно, это объект контекста функции, в котором хранятся вложенные функции, переменные и параметры:
function foo() {
function bar() { alert(this); }
bar(); // global
}
При вызове bar будет определено значение Reference type (т.к. это идентификатор), но с базой — объект активации контекста функции foo. Т.е. эта запись образно равносильна:
AO.bar();
где АO — объект активации контекста foo.
Так вот для этого случае в стандарте тоже прописано — использовать в качестве this не объект активации (базу), а null, и, как следствие, global.
Не стоит вообще полагаться на точность после умножения float'ов. Ежели уж где-то совсем никак юзать sprinf для удаления шлака в неинтересующих порядках. Например если var_dump'ать round(sprintf('%f',$value)) то наверное всё одинаково выведется.
Я постараюсь чуть позже об этом написать, в двух словах наверно не выйдет.
Вопросы у вас хорошие :) Собственно, сам факт подобных дискуссий, а они встречаются почти везде, где пишут data vs domain, говорит о том, что тема спорная и нераскрытая и ее следует исследовать.
Попробую ответить.
«Какая разница в какой иерархии будет наследование в сущностях домена или в сервисах?»
В ООП объекты могут обладать не только данными, но и действиями / методами, это известно всем и на этом строится собственно весь ООП (инкапсуляция, наследования и тп)
Поэтому ООП хорошо подходит для моделирования чего-то, что обладает не только данными, но и действиями, а так же поведением.
Когда мы выносим весь функционал из моделей в сервисы, то мы разделяем данные и «действия», ведь в ваших сервисах обычно нет данных, это абстракция поведения. Сервисы не могут менять внутреннее состояние модели.
По сути, если идти дальше, то такие модели можно сделать immutable, да, и это нас приблизит к функциональным паттернам. Это не хорошо и не плохо (если говорить об абстрактном решении), это просто по-другому.
Более того, такая anemic модель может лежать в основе rich модели (т.е. rich модель может быть большой «оберткой» для anemic).
«При маппинге в DDD возникает слой с кучей DTO, которые являются дублированием сущностей домена.»
Да, именно поэтому полноценный ddd получается дорогим для небольших проектов, особенно, если у вас реляционная СУБД
Вообще, DTO тема тоже отдельная. Уровень DTO зависит от сложности модели.
ps кстати, добавлю масла в холивар :) anemic model добавляет в жизнь программиста как минимум две «сущности»: модель и сервис, а domain подход, больше стремится к упаковыванию всего этого в модель, поэтому вам не надо вспоминать какой сервис делает, то что вам нужно
В самом PHP это пока не планируется, хотя для версии 4.0 были попытки, я даже где-то видел грамматику лексера PHP с учетом аспектов, но это уже в прошлом. Из нового — есть PECL-расширение PHP-AOP, которое разрабатывается, но там куча багов, сегфолтов, да и скорость в отдельных случаях меньше, чем у моей PHP-библиотеки. Моя же библиотека написана на чистом PHP и не требует никаких дополнительных экзотических расширений, за счет этого она стабильна и активно развивается.
Идея работы такая — отслеживаем момент загрузки любого PHP-кода (перехватываются incude/require), делаем статический анализ кода, вносим в него необходимые правки, создаем декоратор, подменяем им оригинальный класс и сохраняем в кэше, дальше отдаем этот код парсеру PHP. После таких манипуляций в памяти PHP будет находиться класс, уже имеющий расширенную функциональность, но с прежним именем класса.
Это краткий обзор предыдущих серий Санта-Барбары под названием «как сделать АОП»
Про Resume можно почитать здесь(дальше поиском по странице)
Но у эластика есть куча приятных фич, которых в сфинксе нет никак, можно вот посмотреть в их постах:
www.elasticsearch.org/blog/2011/05/13/data-visualization-with-elasticsearch-and-protovis.html
www.elasticsearch.org/blog/2011/02/08/percolator.html
www.elasticsearch.org/blog/2011/02/08/versioning.html
www.elasticsearch.org/blog/2010/08/16/geo_location_and_search.html
На самом деле правило одно:
Определяется, что стоит слева от выражения вызова (грубо, от скобок — ( )). Главное, что интересует — это тип вычисленного промежуточного значения, который может быть либо Reference type, либо не Reference type.
Первый случай (Reference type) возможен, когда слева стоит либо идентификатор (identifier), либо выражение доступа к свойству (property accessor). Второй случай (не Reference type) — всё остальное.
Далее, у этого значения Reference type берется базовый объект (base), и именно он будет использован в качестве значения this (Если нужно пояснить про Reference type, скажите).
В случае же, когда значение — не Reference type, this получает значение null. Но, т.к. null особого смысла для this не несёт, автоматом подставляется глобальный объект.
Поэтому:
А вот здесь, оператор присваивания (в отличие от оператора группировки в примере выше), вызовет GetValue, и в итоге будет уже не Reference type, а Function:
Аналогично другие выражения (всё тоже — не Reference type, поэтому this в итоге будет global):
По поводу with: будет Reference type с базой — объект with добавленный к scope chain; поэтому не global.
Есть одно исключение, когда будет получен Reference type (и даже база будет не global, как выше в случае с test), но всё же this будет global. Это в том случае, когда базой будет является объект активации (activation object). Если упрощенно, это объект контекста функции, в котором хранятся вложенные функции, переменные и параметры:
При вызове bar будет определено значение Reference type (т.к. это идентификатор), но с базой — объект активации контекста функции foo. Т.е. эта запись образно равносильна:
где АO — объект активации контекста foo.
Так вот для этого случае в стандарте тоже прописано — использовать в качестве this не объект активации (базу), а null, и, как следствие, global.