comments suggest edit

I knew this question would come up, so I figure I would address it in its own blog post. Mike asks a great question about my MVP implementation (actually he asks two).

One observation…don’t you seem to be tying the presenter to the ASP.NET event model? If not, can you use the same presenter for a WinForms app?

The answer is that I am absolutely tying my presenter to ASP.NET.

Why?

Well when I first working on the article, I planned on creating an abstracted IView and presenter that would work for both ASP.NET and Windows Forms, but ran into a few problems. The biggest problem is that I rarely have to write a Windows Forms applications. In fact, I almost never do. So why spend all this time on something I won’t need? I had to call YAGNI on my efforts.

Premature Generalization

Besides, I didn’t want to run afoul of Eric Gunnerson’s #1 deadly sin of programming, premature generalization. There is no point in writing an IView and Presenter to work with both winforms and ASP.NET unless I am also implementing concrete instances of both at the same time. Otherwise I will write it for one platform and hope it will work for the other. If I ever do implement it for the other, I will probably have to rewrite it anyways.

Parity is a rarity

Secondly, even if I did need it, there are some other issues to deal with. First, trying to write a single presenter for both ASP.NET and a WinForms app assumes the user interaction with the application and the view is going to be roughly the same. That is rarely the case. If I have to go to the trouble to write a Winforms app, I will certainly take advantage of its UI benefits.

Leaky Abstractions Rear Their Head

Thirdly, despite all the hoops that ASP.NET jumps through to abstract the fact that it is a web application and present an API that feels like a desktop platform, it is still a web application platform. The abstraction is leaky and trying to abstract it even more causes problems.

For example, in a Winforms view, you only need to call the Initialize method once because the data is persistent in memory. With an ASP.NET view by default, you have to essentially repopulate every data field every time a user clicks a button. Can you imagine a Winforms app written like that?

Of course you could more closely simulate the Winforms view in ASP.NET view by storing these fields in ViewState or, shudder, Session, but this then becomes a constraint on your ASP.NET view in order to support this pattern, forcing you to take a Winforms approach to a web based app. Ideally a presenter for an ASP.NET application should not have to assume that the ASP.NET view is going to store fields in a persistent manner.

Conclusion

So that is a long-winded answer to a short question. I believe if I had to, I could get the same Presenter to work for both a Winforms App and an ASP.NET app. These problems I mention are not insurmountable. However, I would need to be properly motivated to do so, i.e., have a real hard requirement to do so.

comments suggest edit

A while ago I wrote that you should never lock a value type and never lock this. I presented a code snippet to illustrate the point but I violated the cardinal rule for code examples: compile and test it in context. Mea Culpa! Today in my comments, someone named Jack rightly pointed out that my example doesn’t demonstrate a deadlock due to locking this. As he points out, if the code were in a Finalizer, then my example would be believable.

To my defense, I was just testing to see if you were paying attention. ;) Nice find Jack!

My example was loosely based on Richter’s example in his article on Safe Thread Synchronization. Instead of rewriting his example, I will just link to it.

His example properly demonstrates the problem with a Finalizer thread attempting to lock on the object. However Jack goes on to say that locking on this in an ordinary method is fine. I still beg to differ, and have a better code example to prove it.

Again, suppose you carefully craft a class to handle threading internally. You have certain methods that carefully protect against reentrancy by locking on the this keyword. Sounds great in theory, no? However now you pass an instance of that class to some method of another class. That class should not have a way to use the same SyncBlock for thread synchronization that your methods do internally, right?

But it does!

In .NET, an object’s SyncBlock is not private. Because of the way locking is implemented in the .NET framework, an object’s SyncBlock is not private. Thus if you lock this, you are using to the current object’s SyncBlock for thread synchronization, which is also available to external classes.

Richter’s article explains this well. But enough theory you say, show me the code! I will demonstrate this with a simple console app that has a somewhat realistic scenario. Here is the application code. It simply creates a WorkDispatcher that dispatches a Worker to do some work. Simple, eh?

class Program
{
    static void Main()
    {
        WorkDispatcher dispatcher = new WorkDispatcher();
        dispatcher.Dispatch(new Worker());
    }
}

Next we have the carefully crafted WorkDispatcher. It has a single method Dispatch that takes a lock on this (for some very good reason, I am sure) and then dispatches an instance of IWorker to do something by calling its DoWork method.

public class WorkDispatcher
{
    int dispatchCount = 0;
    
    public void Dispatch(IWorker worker)
    {
        Console.WriteLine("Locking this");
        lock(this)
        {
            Thread thread = new Thread(worker.DoWork);
            Console.WriteLine("Starting a thread to do work.");
            dispatchCount++;
            Console.WriteLine("Dispatched " + dispatchCount);
            thread.Start(this);
            
            Console.WriteLine("Wait for the thread to join.");
            thread.Join();
        }
        Console.WriteLine("Never get here.");
    }
}

From the look of it, there should be no reason for this class to deadlock in and of itself. But now let us suppose this is part of a plugin architecture in which the user can plug in various implementations of the IWorker interface. The user downloads a really swell plugin from the internet and plugs it in there. Unfortunately, this worker was written by a malicious eeeeevil developer.

public class Worker : IWorker
{        
    public void DoWork(object dispatcher)
    {
        Console.WriteLine("Cause Deadlock.");
        lock (dispatcher)
        {
            Console.WriteLine("Simulating some work");
        }
    }
}

The evil worker disrupts the carefully constructed synchronization plans of the WorkDispatcher class. This is a somewhat contrived example, but in real world multi-threaded application, this type of scenario can quite easly surface.

If the WorkDispatcher was really concerned about thread safety and protecting its synchronization code, it would lock on something private that no external class could lock on. Here is a corrected example of the WorkDispatcher.

public class WorkDispatcher
{
    object syncBlock = new object();
    int dispatchCount = 0;
    
    public void Dispatch(IWorker worker)
    {
        Console.WriteLine("Locking this");
        lock (this.syncBlock)
        {
            Thread thread = new Thread(worker.DoWork);
            Console.WriteLine("Starting a thread to do work.");
            dispatchCount++;
            Console.WriteLine("Dispatched " + dispatchCount);
            thread.Start(this);
            
            Console.WriteLine("Wait for the thread to join.");
            thread.Join();
        }
        Console.WriteLine("Now we DO get here.");
    }
}

So Jack, if you are reading this, I hope it convinces you (and everyone else) that locking on this, even in a normal method, is a pretty bad idea. It won’t always lead to problems, but why risk it?

comments suggest edit

Recently I wrote that I could not seem to get Log4Net to work with an external configuration file while running ASP.NET 2.0 in Medium Trust. It turns out that I should have been more explicit. I could not get Subtext to work with Log4Net in Medium Trust, but it had nothing to do with Medium Trust. Mea culpa!

My best guess is that there was a small breaking code change in Log4Net that led to this issue since we hadn’t changed the logging code. Here is a breakdown of what happened just in case you run into this problem.

In Subtext, we wrap the Log4Net classes in our own Log class which is in the Subtext.Framework assembly. This is how we declare a logger within a class.

private readonly static ILog log 
    = new Subtext.Framework.Logging.Log();

In the Subtext.Web project, we have the following attribute in AssemblyInfo.cs which specifies the location of the log4net configuration file.

[assembly: log4net.Config.XmlConfigurator(ConfigFile 
    = "Log4Net.config", Watch = true)]

This worked fine and dandy up until ASP.NET 2.0. When you use the attribute approach, you have to make a log4net call early to jump start the engine so to speak. An attribute just sits there until somebody is told to look at it and do something about it. In our case, the line of code I showed above does the trick within Global.asax.cs.

I started digging into the Log4Net code to figure out how it uses the attribute to find the configuration file. I finally ended up at this code.

public static ILog GetLogger(Type type) 
{
    return GetLogger(Assembly.GetCallingAssembly(), 
        type.FullName);
}

GetLogger searches the attributes on the calling assembly to find out which configuration file to use. Since the calling assembly in our case is always Subtext.Framework (since we wrap all calls to Log4Net), Log4Net searches the Subtext.Framework assembly for the XmlConfiguratorAttribute. Well that won’t work because we have the attribute declared on the Subtext.Web assembly.

My initial fix was to move the attribute declaration to AssemblyInfo.cs within Subtext.Framework. That worked, but I felt like the proper place was to have it within the web project, since that is the natural place to look when you are trying to figure out where the config file is specified. So I updated the code to call log4net directly within Global.asax.cs like so.

//This call is to kickstart log4net.
//log4net Configuration Attribute is in AssemblyInfo
private readonly static ILog log 
    = LogManager.GetLogger(typeof(Global));

static Global()
{
    //Wrap the logger with our own.
    log = new Subtext.Framework.Logging.Log(log);
}

I only point this out to show there are two ways to solve it, both with their plusses and minuses. If you run into this problem, hopefully this guide will help you.

comments suggest edit

In response to my blog post on ViewState backed properties and the Null Coalescing operator, Scott Watermasysk expresses a worry that the null coalescing operator opens one up to a race condition in the comments of his blog post.

He provides a code example of a thread safe means of reading the ViewState that copies the value from the ViewState into a local variable before performing the null check.

That got me worried as well. Not so much about the ViewState but about applying the null coalescing operator against the Cache or Session. These are classes where you are more likely to run into thread contention. Take a look at this method.

public void Demo(ref object obj){    Console.WriteLine((int)(obj ?? "null"));}

The worry is that it might be possible for another thread to set value of the reference to obj to null in between the null coalescing operator’s check for null and returning it to the cast operation, potentially causing a NullReferenceException.

However, looking at the generated IL (with my comments interspersed), it seems to me (and I am no IL expert so correct me if I am wrong) that everything is just fine. It seems to copy the value before it performs the null check. So it looks like the null coalescing operator is roughly equivalent to the code Scott uses.

.method public hidebysig instance void Demo(object& obj)     cil managed{  .maxstack 8  L_0000: nop   L_0001: ldarg.1   L_0002: ldind.ref   L_0003: dup //copy value to stack     L_0004: brtrue.s L_000c //jump to L_000c if value isn’t null     L_0006: pop      L_0007: ldstr "null"     L_000c: unbox.any int32     L_0011: call void [mscorlib]System.Console::WriteLine(int32)  L_0016: nop   L_0017: ret }

So it looks like this is a thread safe operation to me. I look forward to any IL experts informing me if I happen to be missing something.

aspnet comments suggest edit

This might be almost too obvious for many of you, but I thought I’d share it anyways. Back in the day, this was the typical code I would write for a value type property of an ASP.NET Control that was backed by the ViewState.

public bool WillSucceed
{
    get
    {
        if (ViewState["WillSucceed"] == null)
            return false;
        return (bool)ViewState["WillSucceed"];
    }
    set
    {
        ViewState["WillSucceed"] = value;
    }
}

I have seen code that tried to avoid the null check in the getter by initializing the property in the constructor. But since the getters and setters for the ViewState are virtual, this violates the warning against calling virtual methods in the constructor. You also can’t initialize it in the OnInit method because the property might be set declaratively which happens before Init.

With C# 2.0 out, I figured I could use the null coalescing operator to produce cleaner code. Here is what I naively tried.

public bool WillSucceed
{
    get
    {
        return (bool)ViewState["WillSucceed"] ?? false;
    }
    set
    {
        ViewState["WillSucceed"] = value;
    }
}

Well of course that won’t compile. It doesn’t make sense to apply the null coalescing operator on a value type that is not nullable. Now if I had stopped to think about it for a second, I would have realized how simple the fix would be, but I was in a hurry and quickly moved on and dropped the issue. What an eeediot! All I had to do was move the cast outside of the expression.

public bool WillSucceed
{
    get
    {
        return (bool)(ViewState["WillSucceed"] ?? false);
    }
    set
    {
        ViewState["WillSucceed"] = value;
    }
}

I am probably the last one to realize this improvement and everyone reading this is thinking, “well duh!”. But in case there is someone out there even slower than me, here you go!

And if I spend this much time trying to write a property, you gotta wonder how I get anything done. ;)

comments suggest edit

Tonight I attended our local Los Angeles .NET Developers Group meeting for the first time in years. I pretty much never go to these meetings because I just haven’t found them worth dealing with the congestion of rush hour traffic in the UCLA area, which is really bad. Of course I should probably view user group meetings in the same way Jeff Atwood views conferences - I am not there for the talks, I am there to meet you.

However the local group does bring in some great speakers via INETA. Tonight’s meeting featured Rob Howard, the CEO of Telligent. I first met Rob at Mix06 and it was good to see him again at this meeting. He gave a great talk on ASP.NET tips and tricks. The one trick that stood out to me had nothing to do with his talk. I noticed at one point he had SQL code with expandable regions much like code regions via the #region directive. Instead of the pound sign, they used --region. I just tried that with a .sql file and it didn’t work for me. Probably requires a database project. I’ll have to ask him about that.

I recognized one guy in attendance who happened to be Michael Washington, a member of the DotNetNuke core team. He patiently listened to my constructive criticism and we discussed ideas for improvements to module development. One thing I hope to help him with is incorporating more unit tests into DNN code he is working on. Andrew Stopford will be pleased that I am trying to steer Michael towards MbUnit.

The challenge will be how to integrate unit tests into the ASP.NET Web Site model, since VS.NET Web Developer Express does not support class library projects. This may be a no brainer, but I have never tried it. The tests will probably just be dropped in the App_Code folder, but will TD.NET run all tests by right clicking on App_Code and selecting Run Tests. I assume so, but we’ll see.

comments suggest edit

I am a little late in reporting this, but I hadn’t realized the problem until I had to maintain an older project that used Log4Net 1.2.8. I upgraded it to log4net 1.2.10 and noticed it stopped working. I then found this comment in the log4net mailing list archives.

There were a number of breaking changes in 1.2.9

http://logging.apache.org/log4net/release/release-notes.html#1.2.9

In your config file “log4net.spi.LevelEvaluator” needs to be updated to “log4net.Core.LevelEvaluator”.

I hope changes that would break existing config files are far and few between.

comments suggest edit

The Evil Monkey In Chris's
Closet This story from Boing Boing just cracks me up. Apparently monkeys have been harassing passengers of India’s Delhi Metro. This has become such a problem that they have had to hire some langurs (a fierce looking primate) along with a langur wrangler to scare away the monkeys. Here is a description of one such incident.

In that incident, a monkey boarded a train at the underground Chawri Bazaar station and reportedly scared passengers by scowling at them for three stops. It then disembarked at Civil Lines station. Passengers had to be moved to another car while staff chased the dexterous creature, causing delays.

Bad monkey! Bad monkey!

As the Simpsons showed us, the monkeys are trying to take over the world. The image above is from Family Guy.

comments suggest edit

If you read this blog outside of an aggregator, you might notice a few minor new tweaks. I am dogfooding Subtext 1.9 which runs on ASP.NET 2.0. We are very close to preparing a release, so I figured I would beta test this one on my own blog and see if everything works well.

A couple of new things you might notice is that there is now a simple search field on the left hand sidebar that displays its results in an overlaying div. Also, when you view an individual post, there are links to the next and previous post. I have also added gravatar support to the comments.

It took me a while to warm up to the idea, but I really like the gravatars. I have participated in many various message boards and sites (such as flickr) in which users choose an avatar to represent themselves. It is a small thing, but adds to the fun and identity for the visually focused. However in most cases, you have to set up a separate avatar for each site.

With gravatars, you register an avatar with their site and in any system that supports it, your avatar is displayed when you supply your email address to the software. Subtext takes your email address, creates a one-way MD5 hash of it, and then requests your gravatar from gravatar.com. If none is found, then a default placeholder is displayed. I will post a comment to this post as a demonstration.

code, open source comments suggest edit

Orchid Jeff “The CodingHorror” Atwood takes issue with the idea that software developers have any moral obligation to contribute to Open Source projects. And you know what? I agree. However I do take issue with his conclusion as well as some of the points that he makes in an attempt to bolster his argument.

The whole point of open source– the reason any open source project exists– is to save us time. To keep us from rewriting the same software over and over.

snip…

It’s exactly what open source is about: maximum benefit, minimum effort.

Well no. Not really. Back in the day, software was just an afterthought provided by hardware companies to complement and run their hardware. This software was widely shared freely, until companies began to impose restrictions with licensing agreements and started protecting their code by hiding the source.

Many developers grew frustrated as they lost control over their working environment and were unable to modify the programs to fit their needs. Hence Richard Stallman started the Free Software movement, hoping to give users the right to:

  1. run the program, for any purpose.
  2. modify the program to suit their needs. (To make this freedom effective in practice, they must have access to the source code, since making changes in a program without having the source code is exceedingly difficult.) They must have the freedom to redistribute copies, either gratis or for a fee.
  3. redistribute copies, either gratis or free.
  4. distribute modified versions of the program, so that the community can benefit from your improvements.

Thus originally, the whole point of open source was to provide users the freedom to regain control over software in order to get their jobs done.

Of course later, the movement split into the Free Software movement which was absolutist about the freedom issue, and the Open Source movement which sought to be more pragmatic and provide a business case for open source software. Open Source focuses on the intrinsic benefit of having communities of developers improving a software codebase.

Enough with the history lesson and please, I do know that I glossed over that with a big hand wave. That is called a rough history.

The highest compliment you can pay any piece of open source software is to simply use it, because it’s worth using. The more you use it, the more that open source project becomes a part of the fabric of your life, your organization, and ultimately the world.

Isn’t that the greatest contribution of all?

If I read a book you wrote because I found it worth reading, have I made a contribution? Hardly! Apart from the contribution I paid at Amazon.com for the pleasure of reading the book, I am merely using something worth using. That is not a contribution, it is just good sense.

Now if I post a positive review on my blog, that would be a contribution.

The way I see it, Jeff’s right, there is no moral obligation to contribute to an Open Source project. However I am not quite sure the puppy analogy he mentions suggests that. At the risk of yet another bad analogy, allow me to propose one that works for me. I think of Open Source software as being like a nice set of flowers in a common space such as a courtyard. Nobody that lives around the common space owns the flowers, yet they all enjoy the presense of the flowers.

Fortunately, one or two volunteers tend to the flowers and the flowers thrive. Some flowers seem to do fine with very little care, others require lots of care. But everybody benefits and there is no cost, nor moral obligation to others to contribute to the upkeep of the flowers.

However, should the caretakers decide to stop tending to the flowers, the others certainly have no right to complain to the caretakers. And while it is true that in some cases, others may take up the slack and tend to the flowers, or other flowers might grow as replacements, if nobody takes up the cause, or if the new flowers are simply weeds, then everybody loses out. Including those who had the time, means, and even desire to help with the flowers, but just never thought to because someone else was taking care of it.

So while I do not think contributing to Open Source software is a moral obligation, I do think it is a worthy practical consideration. No offense to my homie, but I think it is Jeff who misunderstands the economics of open source. Minimum effort does not equate to free in cost.

For example, should you begin to rely more and more on some piece of Open Source software, consider the effort to replace the software (which might tack on a monetary cost for a proprietary replacement) and learn a new toolkit if development of the software dies out. Hardly a minimal effort.

True, a contribution in this situation is no guarantee that a project will succeed. But doesn’t the same risk apply to purchasing proprietary software? It certainly applied to contributing to a political party (if you were a Democrat in the last couple of elections).

And while it may be infeasible for a large portion of the audience (Jeff pulls the figure 99% out of his rear, which is probably close to the truth) to contribute the extravagance of a bug fix, for the remainder for whom it is feasible, it is certainly worth considering. Every contribution not only helps in a small way to keep the project viable, but it improves the software for your own purposes. It is an entirely selfish benefit.

So again, please do not confuse exhortations to contribute to Open Source as a claim for moral obligation. I honestly believe that those who contribute will benefit from the contribution as much as the recipients of the contribution, which is why I am such a big proponent for contributing.

If you have the means, why not water the flowers for a bit? There are many forms of contributing to an open source project. I list several on the Subtext contribution web page.

comments suggest edit

Soccer BallOne thing I love about my soccer league is that they have a kick butt website. The design isn’t much to look at, but the site is chock full of useful information both current and historical.

For example, you can see how my team (Westside Rovers) did last season. Tied for fourth isn’t such a bad showing for our first season in the league, but check out the GF and GA column.

Ouch! That is 24 goals we scored while there were 54 goals scored against us in fourteen games. That means we scored an average of 1.7 goals per game, while being scored on an average of 3.9 goals a game. When we got beat, we really got beat. Notice that LA Blues, the lead leaders scored 19 goals on us. We played them twice. Double ouch!

There’s no lesson here other than sometimes, you really are better off not knowing the detailed stats. At least we have an easy target to beat for the upcoming season.

The reason for the disparity becomes apparent when you read the following blurb on the front page.

FORMER PROFESSIONAL PLAYERS ARE PLAYING ON SOME OF OUR TEAMS: Some of the teams in our league have former professional players from the Major League Soccer (MLS) in the United States and from Professional Teams from around the world. One team even has a former World Cup Champion from France 1998 on its squad. Thus the level of play can be very high at times. Come, watch and enjoy the competitive level of play.

None of those players are on our team.

In really bad news, we had a pre-season friendly this past Saturday against another team in the league. They had a new player who was trying out for the team who made a vicious sliding tackle (no slide tackles allowed in our league due to the fields policies) on my teammate, breaking his tibia and fibia. The sound of the contact made a sickeningly loud crack! and bent his leg in an unsightly manner. It may take a while, but I hope he has a speedy recovery. Meanwhile, I am looking into better health insurance.

comments suggest edit

In a triumphant return after about three months of not blogging, Barry “idunno.org” Dorrans has published an HttpModule for modifying custom HTTP headers in response to a throw away comment by Scott Hanselman in his post on P3P requests.

The nice thing about Barry’s module is that it is much widely general and applicable than just for P3P headers.

This is a configurable HttpModule, allowing you to use web.config to specify what headers and values you wish added to requests.

So if you need tight control over your HTTP headers, this is the module for you.

comments suggest edit

UPDATE: I long ago stopped supporting Captain Hook. This is a dead project.

CaptainHook I recently introduced an internal tool for writing Subversion Hooks that we developed for internal use at VelocIT. We made the source code and binaries available to the general public and there was enough interest (hey, it only takes two or three and I’m sold!) that we decided to make an Open Source project out of it hosted on SourceForge. This is our company’s first Open Source project and we hope many will find it useful.

I thought about using CodePlex to try it out, but in this particular case I figured it would be less of a pain to host it in a Subversion repository since this is a tool for Subversion users after all.

At a Glance

Mailing List
captainhook-devs at lists dot sourceforge dot net Commits Mailing List
captainhook-commits at lists dot sourceforge dot net Subversion Repository
https://svn.sourceforge.net/svnroot/captainhook/trunk License
BSD

The mailing list might not be ready at the time you read this If you would like to have Subversion commit access, please join the mailing list and send an email to the list with your SourceForge username. Please only request access if you are planning to work on it in the next few months. I will probably cap it after some point just to keep the process sane (not that I am expecting a flood of requests, but you never know).

And of course CaptainHook is licensed as BSD. Any code contributions should have their copyright for the contribution assigned to VelocIT, the maintainer of the project (an informal email ackowledgement is sufficient). As I mentioned before, assigning copyright when contributing is a standard operating procedure and nothing insidious. You do not lose your own rights to use the code elsewhere since the code is licensed as BSD.

Enjoy!

comments suggest edit

Update Corrected my pop-culture iconography mix up.

Thomas Eyde brings up a great point in the comments section of Scott Hanselman’s post about SandCastle and the death of NDoc.

It’s sad to see good projects die, especially when programmer support is a main reason.

But on the other side, it’s not that easy to join these projects. How many of them advertise? How often do we see “Developers wanted on [your favorite project]”?

I think these projects must advertise what they need. Do they need C++ expertise? Java? C#? UI design? How do we know what to do? Where are the tasks listed? How do we assign to them?

Open Source project that are lacking in developer support probably need to tear off a page from the corporate playbook and be a bit more savvy about recruiting developers. I often hear developers wistfully day dreaming that if they just open source their pet project, legions of developers will take up the banner and join in.

Ha! Hardly! Recruitment is necessary and fundamental to an OS project. So much so that SourceForge has a tab dedicated to the topic in the admin section of a project.

Seeking skilled developers (and people who are interested in the goals of your project) is one of the most important activities performed by project administrators.

Sourceforge also provides a Help Wanted page to recruit volunteers for a project. There is also a discussion forum dedicated to recruitment.

But by no means limit yourself to SourceForge. Consider putting a free ad in CraigsList or in the forums of other developer communities.

The second comment on Scott’s post by Martin Bennedik questions the donation model.

But I don’t understand the donation model. Who is supposed to donate the $5? Say I am an employee working for my company, and I am using NDoc. Should I donate the $5 personally? Or should I ask my company to pay the 5$?

When I wrote my original challenge to donate to Open Source projects, I wanted to avoid a

Suzanne Summers Sally Struthers For just five dollars you can feed the kids of those poor Open Source Developers plea. As Scott points out, monetary contributions are far down on the totem pole of contributions. For the subtext project, I added a Contribution page that discusses several ways in which developers contribute should they feel the desire.

I think it is the project leader’s job to make the barrier to contribution as low as possible.

Technorati : Open Source, Software \ Del.icio.us : Open Source, Software

personal comments suggest edit

UPDATE: Sorry, but this site appears to be down now. I’ll try to find the tools and upload them elsewhere.

My colleague Jon Galloway has been on a spree of unleashing useful tools lately. I released a few of my own as well.

One thing in common with these little tools and utilities is that we are hosting them on our new company tools site, http://tools.veloc-it.com/.

These tools are little scripts and apps that we use internally to increase our efficiency. Many of them relieve us from the drudgery of boring repetitive tasks. Quite likely, these are the tools that many of you would write yourself if you only had the time (some of them you probably already have written. I swear we did not plagiarize you). We hope you find them useful. There aren’t that many now, but over time we will add to the catalog.

You might be wondering, if these tools make us more efficient, potentially giving us a competitive advantage, why are we giving them away? Good question. I hadn’t thought of that. Jon! Take down the site!

Well the truth of the matter is that it is a way for us to show off how amazingly smart we are so we can get more clients, fame, and adulation.

Uhhh… Ok. Maybe not.

Let’s be realistic. Decision makers and CEOs are not dinking around the web looking for an Abstract Boilerplate HttpHandler.

Not only that, most of what we post here is not supremely innovative rocket science and going to make someone rich. If we had such a tool, you think I’d be blogging about software tools? No way man! I’d be regaling you with stories about the funny looking crab that walked up to the porch of my immense beach house in Hawaii. But I digress.

Part of the reason is certainly to increase exposure of our company, as I know we do some kick-butt work. Over time, we hope that our site will reflect the quality of the work we do for our clients. But our primary reason is the same reason we’ve been posting such tools even before there was a VelocIT. We enjoy helping other developers benefit from what we’ve learned. Likewise, we appreciate the tools and learning shared by other developers that have benefitted us. In the end, I think this sharing elevates the entire profession.

comments suggest edit

This is just too funny not to link to. Scott Adams, the author of Dilbert, had an epiphany recently which led him to solve the problems in the Middle East.

Recently we had a heat wave in California. My air conditioner broke because, I assume, it is not designed to operate in hot weather. That was the bad news. The good news is that I solved the problems in the Middle East. Allow me to explain.

Please, allow him.

comments suggest edit

UPDATE: CaptainHook is now an Open Source project on SourceForge.

Hook Logo One potent tool for team communications on a project, especially one with distributed developers, is the simple commit email. Setting up Subversion to send out an email when a developer commits changes to the repository is fairly easy. The Subversion distribution comes with a PERL script (commit-email.pl) that works quite well for this purpose.

At least it did for me until we changed mail servers to one that did not allow SMTP relay. Try as I might, I could not get the script to authenticate with our SMTP credentials. I downloaded various other PERL modules that were supposed to be able to authenticate with no luck. I read the RFC 2554 (seat of your pants reading) and authenticated manually via telnet and compared that to the SMTP logs for the components and realized that for some reasons, these scripts were doing the wrong thing.

That’s when it occurred to me that I could probably write a simple .NET app in a minute that could send out the commit email. As I got started though, I realized that it might be nice to write something that would allow others to easily handle other Subversion hooks. Hence CaptainHook was born.

Hooks in Subversion are scripts (or executables) that are triggered by an event in the subversion version control life cycle. The following are the five hooks supported by Subversion. For a short discussion on how to install the hooks, read this post by Pete Freitag.

Note that (except for post-commit and post-revprop-change) the return value of the script controls whether or not the commit should continue. If the script returns 0, the commit continues. If it returns anything other than 0, the commit is stopped.

Script Name Triggered By Arguments Notes
start-commit Before the commit transaction starts Repository Path and username Can be used for repository access control.
pre-commit After the commit transaction starts but before the transaction is commited Repository Path and transaction name Often used to validate a commit such as checking for a non-empty log message.
post-commit After the commit transaction completes Repository Path and the revision number of the commit Can be used to send emails or backup repository.
pre-revprop-change Before a revision property is changed Repository Path, Revision, Username, name of the property Revision Property’s new value is passed into standard input. Can be used to check permission.
post-revprop-change After a revision property is changed Repository Path, Revision, Username, name of the property Can be used to email or backup these changes.

My goal was to provide a nice strongly typed interface and a few useful service methods for accessing Subversion. Thus handling a Subversion hook is as easy as implementing an abstract base class and calling methods on a Subversion wrapper interface.

Setup

To setup CaptainHook, simply unzip the exe file and its related assemblies into the hooks folder on your Subversion server. The distribution includes a plugins directory with a single plugin already there. The plugins directory is where CaptainHook looks for other hook handlers. Be sure to update the config file with settings that match your environment.

The next step is to rename the .tmpl file for the hook events you wish CaptainHook to handle. CaptainHook comes with some sample batch files you can use instead, one for each hook. Just copy the ones you want to use from the SampleBatchFiles directory into the hooks directory.

Flow

Now when a commit occurs, Subversion will call the post-commit.bat file which in turn calls CaptainHook with the post-commit flag. This flag indicates to CaptainHook which plugins to load. CaptainHook then looks in the plugins directory for any assemblies with types that implement the PostCommitHook abstract class. It then instantiates instances of these types and calls the Initialize method and then the HandleHook method.

Note that for the time being, CaptainHook is an executable so it has to incur the cost of searching the plugin assemblies every time which may seem like overkill (and it is). However my focus was on the model for CaptainHook. At some point it will evolve to use remoting as a Server Activated Singleton or it may become a Windows Service which fit the model better. Either way, there are ways in which we can incur this cost only once. But for now, this will do and performs well enough.

Assemblies and Classes

Captain hook contains serveral assemblies.

Assembly Purpose
CaptainHook This is the main console exe and is the starting point for the application.
CaptainHook.Interfaces Contains the interface definitions. This is the only assembly you need to reference when writing a plugin.
CaptainHook.SubversionWrapper This is potentially useful as a stand-alone library. It includes the SubversionRepository class which allows running commands against Subversion and receiving the output as a string. This is useful for running straight commands against Subversion. This assembly also includes the SubversionTranslator class. This class wraps the SubversionRepository class and provides an object oriented means to calling the Subversion commands.
Velocit.Hook.Plugins Contains the PostCommitEmailHook plugin that started this whole ordeal as well as the RequireLogMessageHook which is a pre-commit hook that demonstrates how to reject a commit if no log message is specified.

Let me know if you find this useful. It is definitely a work in progress as not every command is implemented in the SubversionTranslator class. If it turns out that several people find this useful and want to contribute to the code, I am willing to put the code on SourceForge.

Download CaptainHook from my company’s tools site.

The zip archive contains both the source code and the binaries. I also compiled an x64 version of the exe for you 64bit kids.

comments suggest edit

My company’s official 1 year birthday was yesterday, and we didn’t even notice. I guess it is a good thing that we are so busy that we fail to notice our own birthday passing us by.

We’ve had a rocky start which involves some interesting stories that I will tell someday when we are far enough removed from them. But things are starting to hum along much better now.

comments suggest edit

My goodness. Today is Open Source News Day for me.

I just read the sad news that Kevin Downs, the leader of the NDoc project, announced that NDoc 2 Is Officially Dead. NDoc is a wonderfully useful tool for generating nicely formatted CHM and HTML documentation from XML comments within your source code.

What is really troubling about the news is the attitude by some members of the community that was a contributing factor to Kevin calling it quits.

As some of you are aware, there are some in the community who believe that a .Net 2.0 compatible release was theirs by-right and that I should be moving faster – despite the fact that I am but one man working in his spare time…

This came to head in the last week; I have been subjected to an automated mail-bomb attack on both my public mail addresses and the ndoc2 mailing list address. These mails have been extremely offensive and resulted in my ISP temporarily suspending my account because of the traffic volume. This incident has been reported to the local authorities, although I am highly doubtful they will be able to do anything about it.

This has was the ‘last-straw’ and has convinced me that I should withdraw from the community; I’m not prepared to have myself and my family threatened by some lunatic!

Kevin

I cannot understand the mentality of someone who demands for developers to hurry up and release a new version of a free software product. If you are in such dire need of the new version, why not hurry up and contribute?

Having said that, I feel particularly bad that I never contributed to NDoc, yet enjoyed so much use out of it. As the manager of an open source project myself, I understand the inherent difficulty in generating interest and contributions from the community at large.

In general, I try to contribute to Open Source projects when I can. I have contributed a tiny bit of money and some documentation and code to RSS Bandit, I bought a domain name for MbUnit, and of course I contribute to Subtext. But I realized today that I am quite haphazard in how I contribute to useful open source projects. I contribute to some when the mood strikes, but not others.

Challenge

So I offer the following challenge. First, ask yourself these two questions:

  1. How much money do I save because of Open Source Software?
  2. Considering how many people spend three bucks for a useless ring tone, is a single dollar too much to contribute to a useful Open Source project?

So let’s ban together and declare today, July 26, 2006, Contribute To Open Source Day. Look at the open source software you use and consider making a tiny contribution to the project if you find it useful. The contribution could be a small monetary contribution such as a buck (or five). Even more valuable is contributing a single bug fix. If you want to contribute to Subtext, consider writing a Unit Test to cover a case that isn’t tested. What better way to learn about writing unit tests?

Gee, using GIMP alone saves me a few hundred that I would otherwise pay for Photoshop. My goal now is to at least contribute something everytime I download a new open source product, whether it be some useful bug reports or feedback, a bug fix, a buck…anything. Just as long as it is something.

I will check back with you next year on July 26 and remind you again to consider contributing. It is worth it.