The first thing I noticed was that all of these callbacks are actually
interacting with the conversation, not the message. A message shouldn’t be
responsible for updating a handful of attributes on another model! The second
thing I noticed was that Message#update_messages_count could actually be
handled by a counter_cache.

My gut reaction was to move all of this onto Conversation and call that one
method in a callback on Message. Why? I want to call one method that handles
all the data caching from a conversation’s standpoint.

Based on the conditionals, it looked like I could get away with passing the
author and be done with it. After pondering how to test that (it would’ve
been pretty nasty), I decided to extract it into a separate class. With a
seperate class, I can then stub methods on conversation (because stubbing the
system under test is evil) as well as the message.

One-line methods, small contexts in our tests, and an easy understanding of
what’s happening after a message is created. I’d call this a successful
refactor. The Message now doesn’t care whatsoever about what data is cached,
since that logic is on ConversationCacher. If more data needs to be cached
on the conversation when a message is created, it’s immediately obvious where
that logic is handled.

In my experience, after_* callbacks on Rails models seem to have some of the
most tightly-coupled code, especially when it comes to models with
associations. Do yourself a favor and decouple some code!