My struggles in understanding and learning about Object Oriented design, and the tools and knowledge I've taken from them.

Thursday, March 17, 2011

The Vendor, The Consumer, and Loose Coupling

I recently had an epiphany that has made me a better programmer. Seeing as the intent of this blog is to share my experiences in my journey with object oriented programming, and considering this discovery relates to object oriented programming, I thought I would share.

We all know that code should be loosely coupled. That is, objects should avoid knowing too much about unrelated objects. If an object shouldn't need another object to exist and function, then why should that object know about it at all?

There's a lot of nuance in this concept, but part of it goes back to programming in layers.

So what happens when this nuance comes into play?

For a few years now, I've had a solution that worked well enough, but violated loose coupling principles.

I've dealt with this lack of eloquence for a time, partly because I didn't really have a better solution, and partly because it worked well enough.

But I've got a solution now, and it was something that I knew about all along: Event Handlers.

An Event Handler is the perfect solution for loosening up the coupling of your objects, because it puts the flow in the proper perspective. In code, there are vendors, consumers, and states. The Vendor in code is the code that has methods, attributes, etc. The Consumer is the code that uses another object's methods, attributes, etc. A state is sort of an abstract concept that describes when something happens - for example, when an object is out of work to do, or when a button gets clicked, or when an item is added to a collection.

A Vendor should generally have to know as little as possible about the consumer. This is a principle that my code has often failed to follow religiously. And the effect is tightly coupled code.

Consider a System.Windows.Forms.Button object. The Button object knows very little about other controls on a form, and it certainly doesn't know anything about your custom controls that do all sorts of funky stuff. And yet, you can make it so that a click of a button has an impact on all the other controls on the form.

How can this be?

Well, the short answer is by hooking an event handler up to the Clicked event of the button.

This is something a programmer learns within about 10 hours of programming in WinForms or WPF or whatever UI tool he (or she) has. But there's a bigger principle at play that a 10 hour old programmer probably doesn't know, and that is this loose coupling principle.

The Button has a Clicked event that some consumer (in this case, the Form that the Button is on) can subscribe to, and pass a delegate function to. So when the event fires (the button gets clicked), the consumer delegate that is hooked up to the vendor's (Button's) event gets called, and any behavior defined in the consumer's custom delegate gets executed.

This model is a beautiful one, and the underlying principle opens up a whole world of more eloquent solutions.

Consider (some version) of my real life example.

In an application I built about 8 months ago, I have an object called ActivityMonitor. The ActivityMonitor object keeps track of what's going on in the application, and exposes that information when a TCP/IP client requests it.

So, the ActivityMonitor looks something like this:

class ActivityMonitor
{
ActivityCollection _activities;

public void AddActivity(string activity)
{
Activity a = new Activity(activity);
_activities.Add(a);
}

public string GetActivityString()
{
return _activities.ToString();
}
}

So, before considering Event Handlers as a solution for this problem, when non-related objects did something, and I wanted the ActivityMonitor to know about it, I would send the ActivityMonitor to the consumer object as a parameter. This is a tightly coupled pattern, and as I see it now, something I'll avoid in the future.

For example:

public class BigSpecialObject
{
ActivityMonitor _monitor;

public BigSpecialObject(ActivityMonitor monitor)
{
_monitor = monitor;
}

public void DoStuff()
{
_monitor.AddActivity("About to do a bunch of stuff");
///Do a bunch of stuff
_monitor.AddActivity("Done doing a bunch of stuff");
}
}

When I look at BigSpecialObject, I can infer a few things:

1. The consumer of BigSpecialObject knows about ActivityMonitor
2. BigSpecialObject is tightly coupled with ActivityMonitor
3. It didn't have to be this way

The issue of state comes into play. Presumably, at instantiation time, BigSpecialObject is not done doing stuff. After BigSpecialObject.DoStuff() is called, at some point, BigSpecialObject is done doing stuff. This is a great example of where an EventHandler is not only appropriate, but it is the optimal solution.

So, with a couple extra lines of code, I can really "bust some heads" (to use a Ghostbusters reference):


public class BigSpecialObject
{
public event EventHandler WorkRequested;
public event EventHandler WorkCompleted;


public BigSpecialObject()
{
/// Notice that BigSpecialObject
/// knows jack-squat about ActivityMonitor
}

public void DoStuff()
{
this.alertWorkRequest();
///Do a bunch of stuff
this.alertWorkDone();
}

private void alertWorkRequest()
{
if (this.WorkRequested == null)
return;

this.WorkRequested(this, new EventArgs());
}

private void alertWorkDone()
{
if (this.WorkCompleted == null)
return;

this.WorkCompleted(this, new EventArgs());
}
}

So, the consumer of BigSpecialObject would take advantage of this loose coupling by doing the following:

public class Consumer
{
ActivityMonitor _monitor;

BigSpecialObject _bso;

public Consumer()
{
this.initialize();
}

private void initialize()
{
_monitor = new ActivityMonitor();
_bso = new BigSpecialObject();

_bso.WorkRequested += new EventHandler(onBSOWorkRequested);
_bso.WorkCompleted += new EventHandler(onBSOWorkCompleted);
}

private void onBSOWorkRequested(object sender, EventArgs e)
{
_monitor.AddActivity("About to do a bunch of stuff");
}

private void onBSOWorkCompleted(object sender, EventArgs e)
{
_monitor.AddActivity("Done doing a bunch of stuff");
}

public void DoSomeConsumption()
{
_bso.DoStuff();
}
}

So, there you have it. Pattern versus Antipattern. Having the Consumer class alert the ActivityMonitor when the work is done is better, because that means that BigSpecialObject is more reusable. And even though we added more lines of code (believe it or not, I try to find solutions to problems that minimize lines of code), this is a better solution, because of the looser coupling.

In looking at code I've written in the past, it's completely littered with examples of tight coupling. Well, I guess it's time to get to work!

Tuesday, March 1, 2011

Stock Predictor C# Utility

This blog references an application and source code.

To download this application, Click Here

To download the source, Click Here

Evidently, some people buy and sell securities on markets in the attempt to make money. These folks are called traders, and everyone is looking for the next big strategy to estimate what a particular security (also called Stock) is going to do in the future.

I'm not particularly interested in this, but a friend of mine brought up a method many traders use to predict when it is time to buy or sell a stock. The strategy involves looking at the current stock price, and comparing it to its 200-day moving average. When the stock price is below the 200 day moving average, has a history of being above its 200 day moving average, and is on an upward trend, that is a good indication that it might be time to buy.

When some version of the converse is true (stock is above the 200 day average, has a history of being below the 200 day moving average, and is on a downward trend), then it's time to sell.

Below is a screenshot of the utility I built



I'm not an active trader, and I know very little about how this whole capitalism thing works, but I know how to build an application that can represent this paradigm. I built this in C# Winforms. So, that's what I did.

I used the ZedGraph library to build a graph for me, and I built some logic around some of the concepts.

A few warnings:
1. I use Yahoo's stock history to grab prices. Usage of this tool may or may not violate Yahoo's terms of use agreement.
2. I make no guarantees about the correctness of the data derived from this tool, and this tool in no way constitutes a recommendation of a security transaction.
3. The code quality of this tool is not as high as it could be. It was sort of a rush job, because I didn't have much time to work on it before I had to start working on my next project.

I hope someone can use this little tool and get some value out of it. Or, if you decide to improve on it, let me know, and I'll post any fixes you make.

Followers

Search This Blog

Powered by Blogger.