Структурные и Именованные типы. Поведение или Представление?

Вурдалак

Продвинутый новичок
Это достаточно частая ошибка пытаться внедрить бессмысленные и вредные абстракции в domain. Модель создана решать конкретные задачи. Во ВКонтакте одна модель, а Фейсбук — другая. Попытка сделать абстрактную модель «Социальная Сеть» — путь в никуда.
 
  • Like
Реакции: AmdY

Lionishy

Новичок
Что мешает сделать DistanceCalculator класс?
Так, несомненно, делать нельзя.

Архитектурная ошибка с точками и расстояниями в том, что расстояние, видимо, является объектом операционной семантики.
Скорее всего, у расстояния кроме конструктора из пары точек есть ещё конструктор, например, от действительного числа.

Расстояние, в этом смысле, активные данные:
PHP:
interface Distance {
    /**
     * @return PositiveReal
     */   
    public function get();
}
Для типа Distance определим два конструктора:
PHP:
class DistanceFactory implements Distance {
    public function get()
    {
        return $this->distance;
    }

    public function __construct(PositiveReal $distance_)
    {
        $this->distance = distance_;
    }

    private $distance;
}
и
PHP:
class GeoDistance implements Distance {
    public function get()
    {
         //здесь вычисляется расстояние между двумя точками на Земле
    }

   public function __construct(GeoPoint a, GeoPoint b)
   {
       $this->point_a = a;
       $this->point_b = b;
   }

   private $point_a;
   private $point_b;
}
Если мне затем потребуется ещё из каких-нибудь данных создавать расстояние -- это легко можно будет осуществить. Можно добавлять любые функции: сумму расстояний, выбор по расстоянию, что угодно, не задевая самого Distance.
 

Вурдалак

Продвинутый новичок
Нет. Реализовал бы operator + :)
Если уж сахар, так побольше.

Но повторю, расчет расстояния между двумя абстрактными точками, в котором вдруг появляется радиус планеты и коэфициент между милями и км, это совсем не то, что комплексные числа, в которых операция add строго замкнута вокруг ComplexNumber.
OK, а Money::add() (Money+)? :)
 

fixxxer

К.О.
Партнер клуба
И нахрена это в domain model, в которой совершенно четко по постановке задачи тут абстракция никогда не потребуется?

Правду говорят, что нефиг математиков пускать в бизнес-разработку. Я видел такой пример, люди для внутренней(!) CRM 3 года пилили универсальную абстрактную модель для декларативного описания сущностей и связей, через 3 года было условно готово (толком не работало) что-то напоминающее первую версию redmine. На этом все закончилось.
 

fixxxer

К.О.
Партнер клуба
Что мешает сделать DistanceCalculator класс? Лень?
А внутри calculateDistance() что будет? $point->latitude? Получаем геттерно-сеттерный интерфейс.

Конечно, DistanceCalculator может попросить Point заполнить координаты в себе, а Point научить это делать. Но тут мы получим ничем не оправданное усложнение и два класса, которые друг без друга бессмысленны - и логично все упростить, поместив код в один класс.
 

Вурдалак

Продвинутый новичок
Возможно это покажется странным, но для Point иметь публичные getLat и getLng совершенно необязательно.
 

Lionishy

Новичок
@fixxxer,
Вот, я даже не сомневаюсь, что в проекте обязательно возникнет необходимость посчитать расстояние по маршруту, когда на входе будет набор точек, а на выходе расстояние строго по точкам. И будет создан какой-нибудь класс Helper, который будет в статическом методе эти вычисления проводить.
 

Lionishy

Новичок
@fixxxer,
Теперь вместо одного печального класса, мы имеем два печальных класса...
Если завтра нужно будет узнать расстояние между начальной и конечной точкой маршрута?

Через месяц подкатят ещё: сравнение маршрутов (по пройденному пути вдоль маршрута и полному перемещению), проверки маршрута на замкнутость и пересечение маршрутов, создание маршрута заранее и отклонения... Не говоря уже о пересечении маршрута с полигоном, что потребует изменения точки.
Проект в обработке этих данных увязнет.

Учитывая, что Route предоставляет свои точки: в чём разница между методом в классе Route и функцией, которая вне класса по точкам подсчитала бы расстояние? Зачем этот метод именно в Route?

Хоспадипрости...

P.S.
Проект, конечно, может быть и не Ваш, но хоть гипотетически предположить, почему нужен метод именно в классе? В чём смысл самого класса?
 

fixxxer

К.О.
Партнер клуба
Раз ты уж с DDD не знаком, давай ты сначала ознакомишься с книгой, ссылку на которую я давал, а потом мы будем это предметно обсуждать. Поскольку для развернутого ответа на этот вопрос мне придется ее своими словами пересказать. :)
 
Последнее редактирование:

Adelf

Administrator
Команда форума
Я книгу читал. Мне интересно такое: Employee::calculateMonthSalary - тоже имеет право на жизнь? Salary зависит например от стажа, должности.. как-нибудь так.
 

fixxxer

К.О.
Партнер клуба
Если ты представляешь себе единственно возможные два варианта Employee::calculateMonthSalary и геттеры, то это не так =)

С геттерами-сеттерами мозг меньше напрягать, эт да. Я анемиками сам злоупотребляю, когда задача "раз-два и в продакшен", но хорошей практикой это не назову.
 

Adelf

Administrator
Команда форума
Просто мне гораздо проще выделить SalaryCalculator, это не потребует каких-то сверхзатрат. Но потом, если условия подсчета изменятся, я всегда смогу подцепить... например тот сервис, который посчитает сколько дней в этом месяце этот человек отработал. Интерфейс вызова SalaryCalculator::calc - не поменяется. Ему не нужно будет скормить дополнительные значения. Он сам их подцепит. Да. Это меньше напрягает мозг. Вот я и хотел, чтобы меня переубедили. Я в отличие от @Lionishy не догматик. Я готов слушать. Но не готов верить без аргументов.
 

Lionishy

Новичок
давай ты сначала ознакомишься с книгой
Отлично. Специально почитаю, что там такого Эрик Эванс мог написать, что обработка данных вдруг стала выражаться не отдельными объектами, а методами в классах данных. Чую носом, что там либо примеры неудачные, либо проблемы с Java.
 

fixxxer

К.О.
Партнер клуба
@Adelf,
Да, тут явно логично выделить domain service. Но это не значит, что нужны публичные геттеры.
 

Вурдалак

Продвинутый новичок
Отлично. Специально почитаю, что там такого Эрик Эванс мог написать, что обработка данных вдруг стала выражаться не отдельными объектами, а методами в классах данных. Чую носом, что там либо примеры неудачные, либо проблемы с Java.
Заодно не забудь почитать на досуге про инкапсуляцию :)
 

Adelf

Administrator
Команда форума
@Lionishy, Почитай. Книга хорошая. Но оставь свой скептицизм и постарайся просто понять чужие идеи.
 

Вурдалак

Продвинутый новичок
Просто мне гораздо проще выделить SalaryCalculator, это не потребует каких-то сверхзатрат. Но потом, если условия подсчета изменятся, я всегда смогу подцепить... например тот сервис, который посчитает сколько дней в этом месяце этот человек отработал. Интерфейс вызова SalaryCalculator::calc - не поменяется. Ему не нужно будет скормить дополнительные значения. Он сам их подцепит. Да. Это меньше напрягает мозг. Вот я и хотел, чтобы меня переубедили. Я в отличие от @Lionishy не догматик. Я готов слушать. Но не готов верить без аргументов.
Понимаешь ли, ответ на то, как это будет реализовано сильно зависит от реальных бизнес-требований и модель действительно может выглядеть по-разному, в том числе возможна какая-то SalaryCalculationStrategy.

У меня еще есть такое подозрение, что класс Employee у тебя один и ты не хочешь в него пихать разные вещи: email, password, стратегию расчета ЗП. Скорее всего у тебя просто смешано несколько разных bounded contexts. Если контекст небольшой, связан с расчетом ЗП сотрудников, то и метод расчета в сущности не будет казаться диким.
 

Lionishy

Новичок
оставь свой скептицизм и постарайся просто понять чужие идеи
Ладно, раз социальная революция -- не надо топить.
Провели анализ требований и вывели, что вся операционная семантика может быть выражена через вычисление расстояния между двумя точками.
Но почему, как только всё это началось, люди стали ходить в грязных колошах по мраморной лестнице?
Эрик Эванс предлагает для каждой новой функции над комплексным числом создавать новый метод в классе комплексного числа?
Где у Эрика Эванса написано, что один метод для обработки точек в классе Route нужно забить гвоздями, а для всех остальных идти в обход, через getLegs, через чёрный ход?
Вот это очень подозрительно. Специально надо выяснить, что же он там такого возмутительно-атеистического содержания написал...
 
Сверху