The importance of patterns and guidelines in software development
I think I've figured it out. Finally!
I started writing a whole entry on it, but then I realized there is a whole prequel that needs to be written first. So...
We're talking about patterns and guidelines for software here, my friends. They exist to ensure consistent behavior and therefor consistent expectations. This is for direct users of your classes and also those who subclass your classes. The problem with patterns, though, is that they become customs. We do them without asking why we do them. Then we start questioning why we do them if we don't fully understand. We might even start tweaking them if they get cumbersome, which can cause unexpected consequences later on.
So it's always good to understand why (at least at some level) we implement a pattern.
My favorite example: events.
So you add a public event to your class:
public event EventHandler Updated;
And because you were told to, you implement:
protected virtual void OnUpdated(EventArgs args)
{
EventHandler handler = Updated;
if(handler != null)
{
handler(this, args);
}
}
Like a robot. Do yo know why? Really?
Q: Why protected?
A: So a subclass can raise your event. The C# compiler is doing work behind the scenes. You don't see that the event really has both public and private surface area. Only the class that defines the event can raise it directly.
Q: Why virtual?
A: Because a subclass might want to intercept the event and take some action on it. It's cumbersome for a subclass to register an event listener on itself.
Q: Why create the 'handler' field in the method? Seems like a waste of a variable.
A: Threading. To ensure that between the check for null and the call, the event hasn't been unregistered. (But I don't have multithreaded stuff in my library, you say. Right. But might you tomorrow? Might a subclass? Might a direct user of your library?)
Q: Why not simplify the method signature to take no parameters? EventArgs is empty, right?. I should just handle that in the method, right?
A: No. Some subclasses might want to pass a different EventArgs to the method. They might want to pass more information via FooEventArgs. If you lock down the method signature, you are locking them out of extensibility. (Working on WPF, we actually got a bug about this with OnCollectionChanged in ObservableCollection).
See! Such a simple pattern, yet so many nuances!
You might do this work even if you haven't imagined any subclasses. You are doing it just in case.
In fact, the only good reason not to do this work is if you seal your class. Even then, what if the class gets unsealed in the future? Will you remember re-implement the pattern the right way?
Better to do it correctly from the start.
I need to get some work done now. In the next day or two, I'll post my discoveries on IDisposable.
In the mean time, ask yourself: am I cutting corners with patterns? Am I implementing patters which I don't fully understand?
Hmm...
Happy hacking.