PITADEV
Curiosity killed the developer's project.

Stifling the Oral Tradition; Documenting Self-Documenting Code

Friday, 7 August 2009 12:54 by aj

I have a hard time interviewing people.  No, it’s not because I don’t enjoy being a complete asshole or because I don’t know about the perfect interview question.  It has everything to do with the fact that I’m a fatally honest son-of-a-bitch.  So, when someone comes into an interview for a developer position at my company and asks what methodology we use, I always answer, “We don’t.”  It’s not that we’re completely disorganized (although sometimes we’re close), it’s that we are extremely production-oriented, and since we’re not a software company, our executives could care less about Kanbans, Scrums, and Waterfalls.  I’m not excusing this.  I think it’s a crime that we aren’t following something.  But it’s the reality of the situation and it’s going to take a long time to change.

One of the biggest problems any haphazard development department like mine encounters is a total lack of documentation.  It’s a cliché that developers hate documentation.  Especially project documentation.  I’m not even sure developers should be responsible for project documentation.  However, following these simple steps, I have found that I almost enjoy documenting my large libraries and frameworks, making life easier on my peers as well as satisfying auditors, PMs, and other business riff-raff.

Note: The following has a “tutorial” feel to it.  Both Sandcastle and GhostDoc are so easy to use that if you don’t want to follow these steps as guidelines for best-practices, then just go get them and start using them.

  1. If you’re not already, get familiar with Visual Studio’s built-in XML documentation capabilities.  In C#, type “///” (‘’’ in VB) above a class, method, property, namespace, whatever.  You’ll see a nice set of comments fill in for you:
    			/// <summary>
    	
    			/// A method that does stuff.
    	
    			/// </summary>
    	
    			/// <param name="stuff">A <see cref="IDictionary{TKey,TValue}" /> that has stuff in it.</param>
    	
    			private static void DoStuff(IDictionary<string, int> stuff)
    	
    This is a well-known feature of VS, so I’m not going to spend a great deal of time on it.
  2. Use very descriptive names for everything!  I could give a crap if you name a property “ContainerForAccountInformationThatHasAReallyLongName.”  At least I have some idea what the property is.
  3. Download and install SubMain’s GhostDoc.  Let it integrate with Visual Studio as it installs.  Don’t be afraid, it’s probably smarter than you are, and it’s free.  Once you have it installed, open up your favorite project and find a class or member with a really nice signature.  Something with a lot of parameters, generic type parameters, etc., and make sure everything is following item 2.  Put your DocumentThis cursor on the member signature, right-click (or use the built-in hotkey) and select “Document This.”

    GhostDoc extends the built-in XML documentation and interprets not only your member and parameter names, but what the description text should possibly be.  And if you are naming things well, it’s usually pretty damn close to right.  It is quite configurable and even attempts to interpret situations where you should add remarks along with summary documentation.  Using GhostDoc has greatly decreased the amount of typing I do for inline XML documentation.  Here’s an example of a method documented by GhostDoc with no changes made:
    		/// <summary>
    	
    		/// Locks the process item.
    	
    		/// </summary>
    	
    		/// <typeparam name="TProcessItem">The type of the process item.</typeparam>
    	
    		/// <param name="processItem">The process item.</param>
    	
    		/// <returns></returns>
    	
    		protected override TProcessItem LockProcessItem<TProcessItem>(TProcessItem processItem)
    	
    Notice it doesn’t fill in the value for “returns,” but if you think about it, there’s really no way for it to know that.  Besides, this is the sort of typing that we should do, because it eventually provides a synopsis of what the method does.
  4. Document your code and build your project.
  5. Download and install Sandcastle.  Fire it up.  The default empty environment will set you up with a new project.SCAddSource  After saving/naming the project, in Sandcastle’s Project Explorer, right-click  “Documentation Sources” and browse to the build .exe or .dll for your project.  Alternatively, you can use the .Net solution or project file.



  6. In the Project Properties, find “HelpFileFormat.”  This is how you can configure what sort of help files you want Sandcastle to build.  There are currently three options:

    HtmlHelp1x – Standard CHM help file that we’ve all come to know and love, built with HHC.exe, which you should already have installed.
    HtmlHelp2x – HxS help file.  Note that you need to have HXCOMP.exe, which is part of the Visual Studio SDK.
    Website – A rather robust HTML website that looks a bit like an older version of MSDN.  I haven’t experimented with this, but the Sandcastle site has a lot of tips on how to use third-party plug-ins for Ajax and other cool stuff.

  7. Configure all of the other Project Properties in Sandcastle as you see fit.  You’re going to miss some stuff.  Don’t worry, Sandcastle makes it easy to see what you’ve missed.  Leave the log-related properties as their defaults.
  8. Under the “Documentation” menu, select “Build Project.”  After a short time, your build will complete.  Navigate to your “OutputPath” folder and look at your awesome new help documentation!  Then, package it up with your project so that everyone can use it, send it to your boss, and go get some ice cream.

 

While browsing through your documentation and feeling really good about yourself, you may notice some points where Sandcastle will have marked in bold-red font, [Missing <something> documentation for “a particular thing”.]  You can easily repair this by going back to your project and adding the missing XML documentation, or, if it’s a namespace, you can add namespace documentation to the Sandcastle project by using the Namespace Summaries editor found in the Project Properties for “NamespaceSummaries.”  Also, if you would rather not dig through every single page generated by Sandcastle, you can easily find missing documentation by looking at the build log, which can be accessed through “Window—>Build Log Content.”  Sandcastle highlights any warnings for missing documentation in the build log, making it very easy to scroll through and see what you might have missed.

BuildLogWarn

 

So, with a little extra work (as opposed to a ton of extra work), you can feel a bit better about your documentation habits.  I’ve found that using these simple steps has made me a better programmer as well as a better teammate.  Looking at the output from Sandcastle and adding meaningful information to my code with GhostDoc makes me pay more attention to its structure and design.  That, in itself, makes it worth the effort.

Currently rated 4.5 by 2 people

  • Currently 4.5/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5

Setting an EventLogAppender’s Event Source at Runtime

Friday, 17 July 2009 09:37 by aj

I’m switching one of my big frameworks over from a homegrown logging solution to the beautifully simple and powerful log4net.  One of the many conveniences offered with log4net is the ability to log messages to many different message repositories with one call.  Our application requires three logging repositories: a table in our DB2 database, SMTP email, and the event log.  Using the built-in thresholds, the DB2 table receives all messages, while email and the event log only receive Error and Fatal messages.

This particular framework runs under a Windows Service, which uses a Factory to load multiple implementation assemblies that all execute on their own child thread.  Each implementation is responsible for its own set of activities, of course, and the service itself knows only to check the child threads every now and then to make sure they aren’t dead.  Using the default setup for the EventLogAppender, you can set the event source in the configuration by setting the EventLogAppender’s ApplicationName property.  In this case, all of the configuration for log4net is set in the service’s app.config file, which means that the settings for each appender are global to the service.  That’s fine, for most applications, but in this case it would be very convenient to change the event source to something that’s indicative of the specific implementation thread making the logging call, making it much easier to find messages related to a particular implementation.

The obvious way to do this would be to set the ApplicationName property at runtime before each logging call.  However, after much Googling, I wasn’t able to find an example of how to do this.  So I mused and ruminated and muddled about for a while, and eventually started fiddling in the Immediate Window while debugging my test application, attempting to figure out how to access specific appender properties at runtime.  Turns out the solution is simpler than I could have imagined.  Using the excellent tutorials provided by Sir Beefy, I set up my log object like this:

   1: //Console app, global
   2: private static log4net.ILog log;
   3:  
   4: //In void Main()
   5: log4net.Config.XmlConfigurator.Configure();
   6: log = log4net.LogManager.GetLogger(
   7:     System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

Then I provided a Log() method in the abstract class that is required for each implementation that looks something like this:

   1: protected void Log(string appName, 
   2:                    string message, 
   3:                    Exception ex, 
   4:                    log4net.Core.Level entryLevel)
   5: {
   6:     //Set the application name of the EventLogAppender
   7:     ((log4net.Appender.EventLogAppender)
   8:         log.Logger.Repository.GetAppenders().Single(
   9:         a => a.Name == "EventLogAppender")
  10:         ).ApplicationName = appName;
  11:     //do whatever else to log the entry
  12: }

That’s it.  It might be a better idea to use a GetType() call to find the Appender of type EventLogAppender and set the ApplicationName property that way, but I don’t think that’s necessary here.  So if you’re looking to change the Event Source at runtime using log4net to an event log, this is one way to do it without having to change the configuration file on the fly.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   .Net | Tools
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

ReSharper C# FTW (again), VB not so much

Wednesday, 3 June 2009 13:24 by aj

resharper I write both VB and C#.  Anyone who’s read this blog knows that I prefer C#, but VB is my company’s standard, so anything I write that will be deployed is written in VB.  To keep my skills from decaying and in something of a silent protest, I do all of my prototyping and test code in C#.  I have ReSharper 4.5 Full Edition installed, and although JetBrains states that 4.5 has enhanced VB9 support, I’m still amazed at how much more it does for me when I switch over to a C# project.  It’s possible I don’t have it configured correctly, and I haven’t customized it at all yet (too busy coding, I guess).  Either way, here’s an example of what ReSharper does with the exact same method, first in C#, then in VB.

The method is a simple string parsing method.  I have a DB2 table full of strings.  Somewhere in each string is an eight digit number that I need.  However, this data was populated using a regular expression (^\D?\d{8}\D?$) that searched for all strings that have one non-digit wildcard before or after an eight digit string, which made room for situations where an octathorpe (#), parenthesis, colon, or anything else may have been directly in front of or following the desired string.  Since the eight-digit string is all I really care about, here’s what might be a typical (albeit poorly written to accentuate ReSharper’s capabilities) little method to chop off the leading and/or trailing wildcard, if it exists, and return the meaningful eight digit string:

   1: private String GetRealFieldData(string regexMatchData)
   2: {
   3:     if (regexMatchData.Length == 10)
   4:         return regexMatchData.Substring(1, 8);
   5:     else if (regexMatchData.Length == 9)
   6:     {
   7:         if (System.Text.RegularExpressions.Regex.IsMatch(regexMatchData, @"^\D"))
   8:             return regexMatchData.Substring(1);
   9:         else
  10:             return regexMatchData.Substring(0, 8);
  11:     }
  12:     else
  13:     {
  14:         return regexMatchData;
  15:     }
  16: }

Ugly, ain’t it?  ReSharper thought so, too.  Here’s what the snippet looks like in my IDE with ReSharper’s default options enabled:

ResharperCs1

Look at all of the possibilities that ReSharper found!

ResharperCs2First is the method signature, which (since for this blog I put this code in a console application) can be made static. That’s pretty boring by ReSharper standards, but I went ahead and let it do it anyway, since it doesn’t really hurt anything and I am generally of the mind that members should have explicit and accurate modifiers.

ResharperCs3 Let’s get to the meat, which surrounds all of the if-else conditions.  Notice that they are all grayed out, and that ReSharper put a green underline under the if’s.  Anything that gets grayed out is unnecessary code, and I love brevity, so I told ReSharper (by hitting the default ALT+Enter keyboard combination to expand the little light bulb) to go ahead and fix the bad else’s, which resulted in this snippet:

   1: private static String GetRealFieldData(string regexMatchData)
   2: {
   3:     if (regexMatchData.Length == 10)
   4:         return regexMatchData.Substring(1, 8);
   5:     if (regexMatchData.Length == 9)
   6:     {
   7:         if (System.Text.RegularExpressions.Regex.IsMatch(regexMatchData, @"^\D"))
   8:             return regexMatchData.Substring(1);
   9:         return regexMatchData.Substring(0, 8);
  10:     }
  11:     return regexMatchData;
  12: }

OK, that’s a little better.

ResharperCs4   But the real fun lies in the green underline under the embedded if statement, where Regex.IsMatch() is called.  I was curious to see what the light bulb said, and even more curious after the light bulb offered a “Replace with ‘return’” option.  So I let it rip, and was delighted to see the results, which will ultimately make me a better C# programmer since I learned a little more C# syntax.

   1: private static String GetRealFieldData(string regexMatchData)
   2: {
   3:     if (regexMatchData.Length == 10)
   4:         return regexMatchData.Substring(1, 8);
   5:     if (regexMatchData.Length == 9)
   6:     {
   7:         return System.Text.RegularExpressions.Regex.IsMatch(regexMatchData, @"^\D") 
   8:             ? regexMatchData.Substring(1) 
   9:             : regexMatchData.Substring(0, 8);
  10:     }
  11:     return regexMatchData;
  12: }

Then, I took the same method in its original (crappy) form, and translated it to VB to see what ReSharper would do.  Here’s the method again, VB this time:

   1: Private Function GetRealFieldData(ByVal regexMatchData As String) As String
   2:     If regexMatchData.Length = 10 Then
   3:         Return regexMatchData.Substring(1, 8)
   4:     ElseIf regexMatchData.Length = 9 Then
   5:         If System.Text.RegularExpressions.Regex.IsMatch(regexMatchData, "^\D") Then
   6:             Return regexMatchData.Substring(1)
   7:         Else
   8:             Return regexMatchData.Substring(0, 8)
   9:         End If
  10:     Else
  11:         Return regexMatchData
  12:     End If
  13: End Function

Even uglier than it was in C#, but I guess that depends on who’s looking.  Here’s the view in my IDE:

ResharperVb1

Wow, that’s quite a difference!  Aside from the method signature (VB console apps default you to Module1.vb rather than program.cs, so static/shared isn’t an issue here), none of the stuff that was marked by ReSharper in the C# version of this method is marked in the IDE for a VB application.  However, the light bulbs still do show up, I just had to move through line by line to see them.  ResharperVb2 Going to the ElseIf statement brings up a bulb offering to change the if statement to a select case statement, but nothing is said about converting unnecessary else’s to returns.  Also missing is the option to convert the Regex.IsMatch() condition to an If/Iif statement, my favorite part of the C# example.

So I guess the added support for VB in ReSharper 4.5 still lags well behind the power this plug-in provides for C# programmers.  And you know what?  I don’t blame JetBrains at all.  I believe that ReSharper is as much a best practices tool as it is a productivity tool.  When it comes to .Net best practices in books and online, a huge percentage of the examples you see are in C# rather than VB.  I applaud Microsoft for supporting both languages as .Net moves forward, even though VB has been behind in several language features, but why would JetBrains spend a great deal of time and money integrating VB support into ReSharper when the majority of the developers that use their product are coding in C#?  I have many more theories on this, which I’m sure I will expand on in days to come, and I’m hoping that I find ways to make ReSharper a better tool for VB coding.  But for elegance, productivity, and best practices, the true value of this tool is still found in C#.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   C# | Tools | VB | Visual Studio
Actions:   E-mail | del.icio.us | Permalink | Comments (4) | Comment RSSRSS comment feed

Raw Power

Wednesday, 27 May 2009 12:56 by aj

One of the problems that comes along with writing my own blog on software development is that I often expose my own ignorance.  I don’t pretend to know everything, by any stretch of the imagination, but writing stuff that anyone can read comes with a modicum of “assumed authority,” which I clearly don’t have.  However, I sometimes stumble across things that are so cool that I just have to write about them, no matter how behind-the-times they may make me look.  So, I’ll just come out and say it now: Powershell rocks my world.

Yesterday I was dinking around with a web-forms app that required some mildly tricky string manipulation.  When coding in Visual Studio, I’ve often found myself wishing that there were some way to use the Immediate Window to evaluate runtime behavior at design time.  For example, I can never remember string formats.  The .ToString(“format”) method is extremely common, but I’ve already got too much crap crammed in my skull to remember all of the possible values for “format.”  What I’ve always done in the past is fire up my project in Debug mode, put a breakpoint somewhere, and then use the Immediate Window to figure out which argument I need to pass to ToString().  There’s probably a better way to do this in general, but somehow my string of searches yesterday led to Powershell, and goodness am I happy about it.  It’s not that I didn’t know that Powershell existed.  Brad’s been singing its praises forever.  I just never took the time to understand how powerful it is. 

A known bug with the Immediate Window that I don’t believe has been solved yet is the “'RegularExpressions' is not a member of 'Text'” exception.  If you’ve ever tried to execute RegularExpressions in the Immediate Window, you’ve probably seen this.  After downloading and installing Powershell, I started out working on how to test the evaluation of a Regex.Replace() statement.  First, I had to figure out how to get the System.Text.RegularExpressions namespace loaded.  I found a nice blog post that taught me how to do that, and I’m pretty sure that you can have a Powershell script execute on launch as part of your profile.  This little guy will definitely be a part of it when I have time to figure it out.

   1: PS > $GacRootDir = Join-Path -Path $Env:SystemRoot -ChildPath "Assembly/Gac"
   2: PS > Get-Childitem -path $GacRootDir -recurse -include *.dll| Foreach-Object {$_.FullName} | Foreach-Object {([Reflection.Assembly]::LoadFrom($_))}

 

After that, most of what you can do is a matter of learning the syntax, and for a guy who spent the first six-odd years of his programming career using VIM in command prompts, I must admit that it’s strangely comforting to get back to a little command-line scripting.  Once my GAC assemblies were loaded, I set about solving my string manipulation problem.  Specifically, I needed to set a NavigateUrl property to a UNC path, which then got sent to a JavaScript method.  The code-behind is VB, but JavaScript, of course, likes it’s back-slashes to be escaped like C#.  For some reason my brain thought that I should use Regex.Replace() for this (maybe scripting reminded me enough of Perl that I wanted to do a little $foo =~ s/\\/\\\\/g; or something).  Testing this in Powershell was simple:

RegexReplacePS Lovely.  Really, it was.  I didn’t have to fire up a debugging session to find out that Regex.Replace() is going to be funny about back-slashes too, which, if I’d actually taken two seconds to think, I would have already known.  Then, I remembered String.Replace():

PSStringReplace I know, I know, this is elementary stuff.  But the beautiful thing to me here is that Powershell let me do this in a matter of seconds at design-time rather than having to write a separate application or fire up the debugger

Even more fun, I learned how to load unsigned .Net assemblies (and COM!) into Powershell so I can run methods for testing and support issues without having to write a test app.  Simply using System.Reflection.Assembly, same as I would to load an unreferenced assembly in code, I can initialize a new object and then view its members and execute its methods. 

So, maybe I just made myself look ignorant, but I needed to say something because I’m so excited to be finally learning to work with this powerful tool.  If you’re a .Net developer and you’re not already using Powershell, I highly recommend that you go and check it out.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   .Net | Tools
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed

Some Things Are Worth Paying For

Friday, 15 May 2009 06:42 by aj

DualMonitorsWork

I am a huge proponent of multiple monitor setups for developing.  The more real estate I have, the more productive I am, and the happier I feel.  Sure, it’s hard to come up with metrics for this sort of thing, which is exactly why many companies (that aren’t software companies, most of whom understand that hardware is cheap and brains are not) won’t spring for extra monitors for their programmers.  My current company is that kind of company.  I even went so far as attempting to find ways to convince them to invest in things like multiple monitors and ReSharper, but have been so busy that I haven’t been able to put Mr. MacIntyre’s plan into action.

My boss, however, is quite reasonable about things like this, so much so that he went to an auction site and used his personal money to buy us each (there are only three of us right now, so he didn’t have to shell out too much) an extra monitor as long as we were willing to chip in for the hardware needed to run it.  We have the standard Dell low-profile desktop workstations with on-board video that only support one VGA monitor, and I didn’t want to crack the case on something that my company owned, so I was presented with a bit of a conundrum.

Then I learned about one of the coolest little products I’ve seen in a while, the EVGA UV 12+.  After a quick driver install, plug this little box (it measures about 3” x 3” x 1”) into a USB 2.0 port, then plug your extra monitor in (DVI is the default, but they provide a VGA adapter), and voilà, dual monitors!  You can even stack more than one UV 12 to run even more monitors.  Our little Dells only push 1440x900, which is the max widescreen resolution on the UV 12 (and is adequate on the twin 19" widescreens I have at work), but if you want higher resolutions you can upgrade to the more powerful UV 16.

So, with a generous boss and about 46 bucks with shipping, I now have dual monitors at work, and this pleases me.

Be the first to rate this post

  • Currently 0/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Tags:  
Categories:   Hardware | Tools
Actions:   E-mail | del.icio.us | Permalink | Comments (0) | Comment RSSRSS comment feed