Skip to content

Instantly share code, notes, and snippets.

@andrzejkrzywda
Forked from justinko/Plea.markdown
Created June 22, 2012 21:19
Show Gist options
  • Save andrzejkrzywda/2975264 to your computer and use it in GitHub Desktop.
Save andrzejkrzywda/2975264 to your computer and use it in GitHub Desktop.
Am I doing it wrong?

Here is my solution, based on use-cases and AOP.

  1. you need to separate persistence from your domain
  2. you need to have a proper use-case, not a single request-class, like above.
  3. notifications are notifications (twitter, fb), they are implemented with AOP
  4. spam detection and language detection are separated (discussable) with an aspect.
  5. there is an "app" object that wraps it all together.

The first file is the original example. The second file is mine.

Flame :on

# app/use_cases/post_comment.rb
# Called from the "create" action in a controller
class PostComment
def initialize(user, entry, attributes)
@user = user
@entry = entry
@attributes = attributes
end
def post
@comment = @user.comments.new
@comment.assign_attributes(@attributes)
@comment.entry = @entry
@comment.save!
LanguageDetector.new(@comment).set_language
SpamChecker.new(@comment).check_spam
CommentMailer.new(@comment).send_mail
post_to_twitter if @comment.share_on_twitter?
post_to_facebook if @comment.share_on_facebook?
@comment
end
private
def post_to_twitter
PostToTwitter.new(@user, @comment).post
end
def post_to_facebook
PostToFacebook.new(@user, @comment).action(:comment)
end
end
# There is no explanation about the domain of this example, so I'm going to assume that
# it's a kind of a social network, where the goal is to post statuses and comment them.
# use-case is more than a single action, it's an interaction.
# use-case doesn't know about the db and notifications.
class ConnectWithOtherPeople
def initialize(..)
end
def post_a_status(..)
@user.post_a_status
end
def comment_a_status(..)
@user.comment(status, message)
end
def like_a_status(..)
end
end
# Persistence is separated, as an aspect. It's fine to use AR here.
class Persistence
def initialize(use_case, db)
after(use_case.comment_a_status(..), db.save_status_comment(..))
after(use_case.post_a_status(..), db.save_new_status(..))
end
# some more methods here
end
# LanguageDetection is separated, as an aspect.
# It's almost like a domain, so it's fine to keep it in the use_case
# All depends on the complexity and the need of reusability.
class LanguageDetection
def initialize(use_case, detector)
before(use_case.comment_a_status, detect_the_language(..))
end
end
# similar aspect for spam detection ( before use_case.comment_a_status, detect_spam)
# similar aspect for notifications (twitter and fb)
class TheAlmostFacebookApp
def initialize
end
def start
#initialize the use-case and all the features/aspects here.
#it's just a glue
ConnectWithOtherPeople.new(..)
Persistence.new(..)
end
end
@qertoip
Copy link

qertoip commented Jun 24, 2012

I like how Andrzej is taking AOP to the limits. It is valuable to stretch the idea and hit the wall - so we can back of to its rational applications more confidently.

@justinko
Copy link

I am not familiar with AOP, therefore have a hard time understanding this code :(

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment