Как стать автором
Обновить

Комментарии 37

А вас не смущает, что класс Customer ($user) инкапсулирует в себе логику, далекую от его природы? Почему сущность «Клиент» должна знать как получать из базы его «Заказы»?
Ни капли. Пользователь является доменом (хозяином) для своих заказов и получить их от него самого- вполне логично. Так или иначе- всё зависит от цели приложения.
Покупатель так же является хозяином своих скидочных карт, а так же хозяином своих жалоб/предложений. В результате класс покупателя будет представлять службу для доступа к данным, связанным с покупателями. Я не вижу в этом ничего логичного.
Абсолютно верно. Он и будет являться службой в тех случаях, когда мы проводим какие-то операции над доменным объектом, в данном случае пользователем, например: показать все заказы пользователя, показать скидочные карты пользователя и т.д.
Все методы такого рода не содержат хитрой логики а проксируют запросы к целевым доменам лишь декорируя их.

public function getOrders()
{
    return Orm::find('Order', [ ['user_id', $this->getId()] ]);
}


Цель манипуляций- простота и ясность бизнес-логики.
В классах на 100 строк кода с подобного рода проксимирующими, однострочными методами нет никакой ясности и простоты. Куда проще определять для этих целей соответствующие службы. Мне по душе использовать в таких ситуациях аналоги реальных объектов (в случае продажи это может быть ЖурналПокупок или что то типа того). Бизнес-логика куда яснее.
Не люблю Бритву Оккама. Ловушка для новичков! Именно боязнь создать два новых класса приводит к появлению «Божественных, золото-молоточных» классов.
Хорошо, если класса два. В противном случае может появиться

а)объект-свалка
б)сотня мелких объектов за которыми сложно уследить

Мне по душе не распылять функциональность относящуюся к конкретным доменам, ведь, зачастую, мы достаточно редко работаем с сушьностями вне контекста их доменов
Согласен. Это как две крайности, здесь хороша золотая середина.
Что бы этого не было придумали GRASP.
Честно говоря, не знаю, зачем вы работаете с БД напрямую. ORM используется всегда, когда речь идет о чем-то, что в принципе имеет смысл решать с помощью DDD-подхода. И честно говоря, я бы вам посоветовал почитать книжки по этой тематике, да и в принципе о паттернах проектирования и прочем.
Пищи для размышления я у в этом посте как-то, к сожалению, не нашел :(
А можно поподробней… Для чего нужно использовать ORM? и какие преимущества по сравнению с тем же PDO
Все что относится к работе с базой данных выносится в отдельный компонент, о котором ваши модели предметной области могут даже не догадываться. Как следствие можно проектировать приложения начиная именно с моделей предметной области, а решить как это будет храниться в базе можно уже потом.

Хороший пример того как это организовано — Doctrine2.
И главное — через какую СУБД я буду с сущностью работать. Завтра мне в голову взбредет хранить сущность в Mongo и в той же доктрине это 5-10 строчек кода в одном месте.
… и объекты умирают.
so sad ;(
PHP он как игра престолов) старые умирают, новые появляются :)
А почему бы не установить Doctrine2 и не работать напрямую с объектами? Если не касаться сложных запросов с кучей связей, то запросы к БД мы даже и не увидим. Даже создание таблицы в базе будет делать сама доктрина.

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

Впрочем, Вы правы, что от работы напрямую с БД давно пора уходить, и для этого выбирать или писать свою ORM \ ODM.
на случай сложных выборок с кучей связей (особенно если хочется воспользоваться всеми преимуществами выбранной СУБД) есть варианты использовать named queries со своими правилами мэппинга данных на модели или dto объекты.
Doctrine 2 и это позволяет, насколько я помню (Google «DQL»).
Читать книги — это хорошо, но тут ваша заметка напоминает теорию, далекую от практики. Посмотрите Symfony2\Laravel, Doctrine2\Propel\ActiveRecord и т.д…
Да база есть, фреймворки есть, грамотно писать можно.
Но, к сожалению, наоборот, на практике постоянно встречаются методы в объектах, которые слабо к ним относятся, и следовало бы вынести в функциональные классы/сервисы. А там, где нужно было бы применить логику объекта, сплошные обращения к ORM.
Возможно, мне просто не везло с проектами :)
Мне кажется последнее предположение верным ;)
Каждый считает свой код PHP самым классным и правильным. Люди пишите комменты в коде, тогда и вам и последующим поколениям не придется мучиться! А то ваш классный код настолько классный, что понятен только вам, и то не всегда. Это кстати не автору, а так, в общем, для всех…
Если код понятен только по комментариям, это не может быть «классный код». Комментировать стоит лишь сложные или неочевидные места, которых должно быть немного.
«Комментировать стоит лишь сложные или неочевидные места, которых должно быть немного.» мы ведь говорим о сложных системах, не так ли? И не всегда понятно что откуда берется и за чем следует. И у каждого свой подход к организации структуры кода. И каждый считает его лучшим. А как же все таки правильно, если не секрет?
Правильно выносить описание «что откуда берется и за чем следует» в отдельный документ, который может называться «Моделью проекта», а не записывать техническую документацию прямо в исходники.
Ну вот, некоторые моменты проясняются для меня. но все же приятно видеть что делает «вот эта вот» функция и за что отвечает «вот этот вот» класс прямо рядом с тем местом где он используется. А когда функций сотни, все ведь не запомнишь.
Это уже не совсем комментарии, а скорее документация интерфейса классов. Она описывает цели классов, методов и свойств, но не в контексте системы или бизнес-логики, а именно как документация интерфейса. Для другой информации есть «Пользовательская документация» (что умеет система и как этим пользоваться) и «Техническая документация» (из чего состоит система, как это взаимодействует, почему принята именна такая структура и так далее).

Комментарии это что то вроде:
str = currentStr[0 : len(currentStr) - 1] # Удаляем символ переноса строки

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

Вообще ИМХО, если ты хочешь написать комментарий, подумай как написать код так что бы комментарий был не нужен.
Чтобы не плодить методы с одной строчкой кода в теле и которые используются один раз за весь проект только для того, чтобы было написано:
str = delNR(currentStr)

вместо:
str = currentStr[0 : len(currentStr) - 1] # Удаляем символ переноса строки

Я тоже люблю идеи, изложенные Макконнеллом, но не стоит перебарщивать с ними. Может метод будет читаться проще, но проект в целом превратиться в клоаку.
Не соглашусь.
Дело в том что даже в этом примере, если будет метод, то его можно будет протестировать очень легко. И так же легко будет изменить в будущем, если например нужно будет использовать более сложный алгоритм, или ещё что нибудь.
По этому не нужно бояться методов в одну строку.
Таким подходом у вас класс будет состоять из методов в одну строку, поверьте мне. Хорошо, когда легко тестировать и меня код, но с этим можно и перегнуть палку. Прекрасный пример этого — частота использования метода в проекте. Если метод используется в проекте один раз, стоит задуматься, а не заменить ли его вызов на его тело?
Против замены вызова на его тело, говорит сложность тестирования. А с тестами переборщить очень сложно.
Если есть сложность тестирования, то да, выносить стоит, но это уже не вопрос документирования или понятности кода.
Комментарии — признак плохо пахнущего кода.
Если у вас возникло желание написать комментарий — производите декомпозицию, уменьшайте сложность.
Все красиво, да вот на практике будет не так радужно. Мое личное имхо: либо использовать нормальные ORM (Propel/Doctrine), где вариант 2 из коробки дается, либо писать лапшу из варианта 1. Если начать велосипедировать вариант 2, то высока вероятность вместо лапши в контроллере наделать высокосвязную лапшу моделей, а это в 100 раз хуже.
1. Если вас так смущает ORM::find (хотя я не понимаю, чем именно), есть EntityRepository (по крайней мере в Doctrine) для этого.
2. Опять же можно в Entity добавить поле «один ко многим» и получать заказы через user->orders (причем это «ленивое» свойство), ну это если вы не с MyISAM работаете.
Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.