Pull to refresh

Comments 27

ну не ActiveModel, а ActiveRecord::Model — между ними большая разница =)
Основанный на этой же статье) надо попробовать где-нибудь.
Про декоратор:
И в контроллере:

class CommentsController < ApplicationController 
  def create
    @comment = FacebookCommentNotifier.new(Comment.new(params[:comment]))
    if @comment.save
      redirect_to blog_path, notice: "Your comment was posted."
    else
      render "new"
    end
  end
end


этот пример меня смущает, получается, мы должны помнить при написании контоллера, что модель должна отправлять нотификации в фейсбук и мы должны использовать декоратор, а не саму модель. По-моему, это наоборот, увеличивает сложность.
Также ожидал услышать про делегацию, на мой взгляд, самый правильный способ разбивать модель.
На самом деле тут даже не нужен декоратор. Есть же Observer, который позволят перехватывать стандартные after и before хуки.
Если поковыряться в документации Ruby/Rails, то можно найти кучу реализаций паттернов GoF и не только. Имхо это вообще тема для отдельной статьи.
По-моему довольно логичный ход. Когда я пишу код создания комментария, я знаю что мне нужно продублировать его в ФБ. В данном случае как раз Observer, использование которого многим показалось бы логичным, как раз и усложняет код. А вот декоратор как раз явно показывает намерения разработчика кода.
А если вам где-то в другом месте понадобится создать комментарий, вы уверены, что вспомните о том, что надо в фейсбук продублировать? Или у вас в одном месте будет дублироваться, а в другом — нет? Логику надо отделять от контроллеров, а тут она во всей красе. Обсервер предлагал не я, мне тоже не нравится, что он неявно обвешивает модель, но для некоторых вещей, непосредственно не связанных с функциональностью модели, наверное, имеет смысл.
Уверен. Мы же не пишем код с ИИ, чтобы он сам помнил о ТЗ. Это моя задача, как разработчика.
В данном конкретном месте, зная что необходимо дублировать в ФБ, я использую стратегию создания комментария, заодно дублирующую его в ФБ. В другом месте, если это необходимо — тоже буду. Там, где не нужно — не буду. Проблема то в чём?
В том, что проекты не пишутся раз и навсегда, а поддерживаются и изменяются. Также есть проекты, которые просто не влезут целиком в голову и которые пишутся не один месяц. Также есть проекты, которые пишутся не в одиночку, а командой, поэтому код должен быть понятным и предсказуемым, а не «угадай, куда я это засунул».
Если это всё не про вас, вопросов нет, можете писать всё одной портянкой, зачем вам вообще контроллеры и модели, если у вас есть ТЗ и вы всё знаете?
Вы сейчас пытаетесь сказать, что когда команда работает над проектом, каждому из них знать ТЗ и архитектуру проекта — не нужно? И новичка не нужно никак вводить в курс дела, чтобы он как раз и не был главным героем «угадай, куда я это засунул» и не найдя, не засовывал в новое место?

Но это всё вторично. Как, если не декоратором (CommentsService с методом create(text) — то же самое, только в профиль)?
Угу, только если код лежит в неожиданных местах, знаний архитектуры и ТЗ окажется недостаточно, в случае чего придётся лопатить весь связанный код, и не только новичку, но и старичку, особенно, если данный код писал его изобретательный коллега )
Первое место для поиска — модель и callback на create, конечно, откуда его и вытащили. Если вытаскивать, то вместе с другим кодом, например, в делегат. Можно оставить и в декораторе, только вызывать из модели, а не контроллера. То что тяжёлые коллбеки делают тесты медленнее и более хрупкими, конечно, понятно, но я очень далёк от мысли, что это причина для изменений в архитектуре.
Если у модели наличествует большой и тяжелый callback, я обычно завожу в модели виртуальный атрибут, истинность которого отменяет callback. В обычной работе он совершенно не мешает, а в тестах позволяет сэкономить время и сохранить чистоту.
Я дико извиняюсь. Можете в двух словах объяснить что такое виртуальный аттрибут?
Сразу оговорюсь: я тоже за, что вызов декоратора должен быть не в контроллере.

Декоратор красив только в данном сферическом примере в вакууме. Первый «неудобный» случай уже описан выше — это когда нужно создать комментарий где-то еще. Приходится заново прописывать конструкцию с декоратором, а это нарушение DRY.
Второй случай — это когда нужно сделать больше одного действия. Например, нужно отправить коммент в FB, Twitter, отправить оповещение автору статьи на почту, да еще и начислить какие-нибудь баллы. Будете запихивать это все в один декоратор? Или строить монструозную цепочку из декораторов при каждом создании комментария? За оба эти решения вы через месяц проклянете сами себя. Особенно, если вам таки нужно создавать комментарии где-то еще. Создание нескольких обсерверов, обслуживающих одну модель, но выполняющих разную работу, выглядит гораздо красивее.
Третий случай — это тестирование. В случае с обсервером вам нужно протестировать обсервер — и все. Обсервер будет отрабатывать всегда, когда создается комментарий. В случае с декоратором вам придется проверять каждый случай на предмет того, не забыли ли вы, ваш коллега или новичок в кофейном угаре использовать декоратор.
Ну вот вы обоснованно ругаете декоратор за «нужно создать комментарий где-то ещё». А что, если где-то ещё мне, создавая комментарий, не нужно посылать сообщение по электропочте? А тут этот Observer, о котором я, кстати, будучи новичком в проекте, ещё и не знаю. Связь то неявная.
Если новичок сел писать код, не изучив хотя-бы тесты, в которых обсервер явно упомянут, то его тимлидер просто обязан поставить его в угол на горох.
Если же в каких-то единичных случаях какой-то из обсерверов таки не должен отрабатывать, решение с виртуальным «выключателем» я написал выше.
ППКС. Автору респект. Правда, по-моему это не правила рефакторинга моделей, а правила их написания :) Какая разница, когда их применять!
Я бы почитал как автор это раскидывает по директориям. Я додумался только до /app/services, в котором хранятся корневые сервисы. А остальное куда? Всякие value object и стратегии. В lib что ли? Как-то далеко рыться.
У меня в /lib, как правило, Ruby-код, никаких рельсов. И мне это нравится)
Я думаю эти все вещи хранить в /app/lib.
Sign up to leave a comment.

Articles