Home >

Decoupled design with events

21. December 2008

UPDATE:
Rob was kind enough to discuss on that issue. What I understand is that he thinks this increases complexity for now, since he doesn’t want to have multiple handlers, but spam service is quite enough.
Thanks Rob!

I know, I know. I am talking about Events a lot, but the reason for that is: I love them. They provide hell of a great way to decouple your design, and improve flexibility.

After reading Rob Conery’s Twitter about implementing subkismet for oxite, I decided to take a look at since I did it once, too. I take a look at it, unfortunately it wasn’t like what I expected from Rob but definitely he is a great guy!

My way of handling this issue will be based on events and the code is in BlogSharp codebase

As an illustration, I will work on comment adding process, where a user comes and write comments.

There is a problem with Rob’s implementation, IMHO. Spam control should not be part of comment adding process. Putting it right into Create method of CommentController will viloate the SRP and OCP as there may be some other controls on the comment as well, such as check for duplication, or flood, etc. You may also want to notify the author of the post whenever a comment is added.

All these issues can be easily addressed by using events.

public class PostService : IPostService
{
    #region IPostService Members

    public void AddPost(IPost post);
    public void AddComment(IPostComment comment)
    {
        var commentAdding = new CommentAddingEventArgs(comment);
        this.CommentAdding.Raise(this,commentAdding);
        if (commentAdding.Cancel)
            return;
        Repository<IPostComment>.Instance.Add(comment);
        var commentAdded = new CommentAddedEventArgs(comment);
        this.CommentAdded.Raise(this,commentAdded);
    }

    public void RemoveComment(IPostComment comment);
    public void RemovePost(IPost post);
    public IPost GetPostById(int id);
    public IPost GetPostByFriendlyTitle(string friendlyTitle);
    #endregion

    #region IPostService Members
    public event EventHandler<IPostService, PostAddingEventArgs> PostAdding = delegate { };
    public event EventHandler<IPostService, PostAddedEventArgs> PostAdded = delegate { };
    public event EventHandler<IPostService, PostRemovingEventArgs> PostRemoving = delegate { };
    public event EventHandler<IPostService, PostRemovedEventArgs> PostRemoved = delegate { };
    public event EventHandler<IPostService, CommentAddingEventArgs> CommentAdding = delegate { };
    public event EventHandler<IPostService, CommentAddedEventArgs> CommentAdded = delegate { };
    #endregion
}


Then, you let your plugins add themselves as event handler for particular action, and act accordingly.

PS: Raise is an extension method (thanks Sidar Ok for warning me about the ugliness of previous implementation)

public static class EventHandlerHelpers
{
    public static void Raise<TSource,TEventArgs>(this EventHandler<TSource,TEventArgs> @event,TSource source,TEventArgs eventArgs)
    {
        if(@event!=null)
            @event(source, eventArgs);
    }
}

kick it on DotNetKicks.com

,

Comments

12/21/2008 4:46:01 AM #
Trackback from DotNetKicks.com

Decoupled design with events
sirrocco
sirrocco
12/21/2008 7:00:19 PM #
Can you please show (maybe in a different blog post) what you mean by : "you let your plugins add themselves as event handler for particular action".  I'm not exactly sure where I would catch CommentAdding.

12/21/2008 7:41:56 PM #
Sure I can, but not in 4 week period. It needs some concentration to implement it for the blogsharp.
But I can tell what I mean simply.
I used to have plugins for the blog, and I discover them using reflection, and register them to the container. Then Resolve it from the container, and invoke method Start. In start method, the plugin may invoke

PostService.CommentAdding+=this.CommentAddingHandler;

for akismet plugin, for example, you can check the message if it is spam and if it is, you can set .Cancel=true so that it won't be added to the database.

Is that cleara?
12/21/2008 7:42:39 PM #
You can also use IoC containers to wire up your events.
12/22/2008 1:43:29 AM #
I like your way, but in fairness, I looked at Rob Conery's implementation and it is not bad. I think both ways are acceptable and I don't see any issue with either implementation. Your implementation reminds me a lot of Web Client Software Factory's implementation of services.

Events are an excellent resource and I agree with you that sometimes they are ignored by a lot of developers.

@Tuna your right about using an IOC to resolve events and handlers. Unity has a great example of that, you should check it out.
12/22/2008 1:49:10 AM #
@Khalid

Rob's implementation has no problem in seperating concerns, he is putting business logic into business, but i believe he is adding more responsibilities to a single method. This is the reason that I am saying it is not like the one I expected from him.

Of course, there is no silver bullet and I am not offering this as "a must", but just trying to show my point.

BTW, please also read the discussion I had with Rob Conery on his blog. It made me think, and see his points.
12/22/2008 1:56:54 AM #
So I have to admit that the title "decoupled" is a mistake, but SRP is not. The possibility of not wanting to use a spamservice, for example, is an indicator of an SRP violation. The only solution is to use NullSpamService which I refuse to do.
12/22/2008 4:50:39 AM #
Why do you need *both* Raise and delegate{} assignment?
12/22/2008 4:54:56 AM #
No particular reason. Raise method is safe, if someone forgets to assign delegate{}.
redsy
redsy
12/22/2008 9:00:01 PM #
I really like this approach. Am I right in assuming this is basically a workflow approach where you define the workflow without any assumptions over behaviour and expect any pipes/filters to attach themselves.
12/23/2008 8:05:10 AM #
I wouldn't say a workflow approach, but yes, I am making no assumption on the presence of anysubscriber. Subscribers can do whatever they want, without no special treatment in publisher code.
12/29/2008 8:44:11 AM #
I think you should take a look at <a href="http://blogsvc.net">BlogService</a> as I think if you joined the team you'd find that you have a better code base to work with your design idea's.  BTW, nice blog!
5/19/2009 5:13:28 AM #
Trackback from Tuna Toksoz

Id Generation for db4o
7/23/2010 10:23:46 PM #
Id Generation for db4o

Id Generation for db4o
3/22/2011 8:01:49 PM #
I actually love the actual data this specific site consistently provides you with. First class!
Comments are closed