PITADEV
Curiosity killed the developer's project.

Bloated Entities and Projections–Where Does it End?

Thursday, 21 October 2010 14:08 by aj

I ran into a curious situation today.  The database I’m working with primarily has lots of big, horizontal entities, which is fairly common for any schema that’s been around for several years.  It’s main consumer is a series of WinForms applications that rely heavily on grids for displaying data.  Since most of the grids don’t need to show every column of every entity they are displaying, there are several versions of entity projection classes in different namespaces of the existing framework.  I’ve found these frustrating, since they often don’t have everything that I need for the behavior I’m attempting to produce.  Yet these classes exist in the data access layer, along with the actual entity objects.

I was working on a set of forms for searching and displaying information on various entities, and when I started a new form, I realized that the initial search display was exactly the same as a form I had just created.  Obviously (much to my chagrin, more on that another time), it was time for a user control.  I grafted the controls into my new user control, started working on refactoring the code, and then sat back, stumped. 

In my opinion, a user control should really only be created if it is going to be re-used by different containers that require the same behavior for part of their purpose.  This particular control had a DataGridView in it that worked with an entity projection class.  The entity projection itself was in a separate namespace in the same project, since, at the time I created it, I believed that it’s sole purpose was going to be for use on the original form.  Now that I was looking at a user control, the projection became theoretically necessary on a larger scope than the original assembly, along with the control itself. 

Hence my stumpage.  Where do I put the projection and the corresponding query?  Hell if I want to be the guy violating DRY.

I considered the data access layer, but only for a few minutes.  The query for the entity along with the projection itself, though they might be re-used at some point, were behavior driven elements; part of the business logic. 

Then, I thought about creating a business logic assembly that would house both the user control and the logic.  This was more appealing, at first, because it seemed to keep things that should be separate separated.  But then I remembered the existing framework, and how these entity projection classes and the stored procedures used to load them kept getting changed, massaged, and bloated to represent 42 different things.  Not at all what I wanted. 

The truth of the matter is that the user control has a single responsibility: to search for an entity in a certain way and present the results in a certain way.  Might other applications down the road need to do this same thing?  I don’t know right now, and right now it doesn’t matter.  What matters is that the code that is required for this control doesn’t belong anywhere else.

So, I’m moving the projected entity class, the compiled query that projects it, and all of the calling code into the user control itself, which will then simply need a data context to work with.  Did I do the right thing in the long run?  Maybe not.  But even if this control needs to be used by another application in the future, it will be a simple, wholesale move to a separate project, rather than another application architecture decision. 

Projections are business logic.  Attempting to maintain several sets of projections for use by different projects is a no-win proposition.  The entities themselves change over time, hence the use of projections in the first place.  Maybe two applications will need very similar entity projections, but attempting to predict this leads to over-abstraction and accidental complexity. 

Be the first to rate this post

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

How I Came to Hate My iPhone

Monday, 11 October 2010 13:11 by aj

 wp7_signature_banner_sm 

No, it’s not because I’m trying to win a Windows Phone 7.  Well, maybe it’s partly because I’m trying to win a WP7.  Most everyone knows that I tend to drink the Microsoft Kool-Aid, but today, along with word of the WP7 lineup from AT&T, I have had an experience that made up my mind.  When I can afford it, I’m getting away from Apple all-together.

Waaaay back in the day, I had a POS Motorola phone with Windows Mobile 5.1.  I didn’t really mind the phone all that much, but there were some basic things about it, and the operating system, that made me mad.  I switched to BlackBerry, and as much as I loved my Curve, the sexiness of the iPhone finally won me over.  This past January, the family all got iPhones, and aside from some basic compatibility problems with Google that ironed themselves out (except for the Voice app, which I wouldn’t use anyway), we’ve all been pretty happy with it.

Until today.

I play guitar.  My instructor gave me a great drill for learning different scale positions for different notes.  It involved a bunch of flash cards in two or three different “hats,” and based on which cards are drawn, you do different things on the guitar.  I love this kind of stuff.  After fumbling around with pieces of paper and beat-up golf hats for a while, I realized that this drill would be a simple program to write.  So I wrote it in WPF, which took me all of about half an hour (not counting image creation), and it works great.  But lugging my laptop around with me whenever I want to practice guitar is, well, a PITA, so the obvious thing to do would be to write a phone app. 

After contacting my Mac-Whore (we all have one), I figured out that the SDK is not only not free ($99), but it won’t run on anything except a Mac.  My MacBook bought the farm last year and I never really liked it enough to buy another one, so I am Mac-less.  So now if I want to build an app, I would have to “Hackintosh” my laptop with another partition for OS-X, which I would use only to write a single iPhone app that I really don’t care if anyone else uses except myself.  And there’s another problem: if/when I actually develop the app, I wouldn’t be able to put it on my own goddamn phone.  It would have to go through the craptacular App Store approval process.  In summary, I would have to:

  1. Pay $100 bucks for an SDK I’d probably only use once.
  2. Buy a Mac –or- possibly break the law hacking my computer so it could run OS-X.
  3. Buy OS-X.
  4. Spend the time getting the Hackintosh set up.
  5. Learn Objective-C.
  6. Write the app and submit it to the App Store Approval Process.
  7. Wait for them to tell me it’s OK to install it on my phone.

 

Now, to be fair, I don’t know Java either, but I’ve messed with Eclipse before, and from all accounts I’ve heard, Android is quite easy to work with.  Easier still, WP7.  I remember coding a Windows Mobile app and throwing it on my crappy Motorola in about 15 minutes once.  No big deal, because it’s my phone, and if I want to write a program for it, I should be able to. 

So I’m throwing in with Windows Phone 7, and I hope I win one with the little image above.  If not, and if it lasts longer than Kin, I’ll be deciding between WP7 and Droid for my next phone.  Apple the evil empire has lost what little support I still gave it.

Note: I just realized that you have to pay $99/year to submit apps to the WP7 Marketplace (unless I'm wrong), so I guess it ain't so bad to pay $99 for iPhone App development.  Wait...except you can't even get the SDK from Apple unless you pay the $99, whereas I just got the WP7 SDK for free.  Either way, full disclosure, apparently we could create the awesomest thing ever, and in order for either Microsoft or Apple to distribute it, we'd have to pay them.

Currently rated 5.0 by 2 people

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

Get UNC Path Utility

Thursday, 25 March 2010 11:23 by aj

We pass files around a bunch here, especially documents, and it becomes incredibly annoying to constantly have to copy/paste/type full UNC paths into emails and messaging.  One of the guys on my team found a CopyFilePathContextMenuutility yesterday built by Dynamic Edge called Copy File Path.  This little VB6 app (it installs the VB6  runtime, ew!!!) adds a menu item to the Windows Explorer context menu that will copy the full UNC path of the selected file to the clipboard.  Even if you use mapped drives, it still pulls out the full network path.  Pretty sweet!  This is the kind of thing that I’d have fun writing myself, but why do that when this little thing works great, and is free?  Thanks Dynamic Edge!

Be the first to rate this post

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

Windows 7 "Repair Install" (AKA "Did I fall asleep?")

Saturday, 24 October 2009 14:51 by kevin

...a highly questionable method that works... or at least worked once for me. 

I'm going to give smaller disclaimers a few times, but let me start out with a comprehensive one: I am not an expert in Windows, nor do I really do PC system administration for a living, nor did I hear from anyone else that this idea was OK.  Also, I did it just last night, and if I set myself up the [time]bomb, I won't know for a while.  Also, for all I know, it could only work this way on certain combinations of hardware.  Absolutely do a disk image backup before trying this, and absolutely do not try this with a machine that you need to have working tomorrow or your kid won't get his life-saving medication. In fact, it is my recommendation that you don't do this at all.  That said, I'll tell you what I did to move a fully functional Windows 7 system hard drive from a 2-year-old Dell Latitude laptop to a 1-month-old Dell Studio XPS desktop.

If you find yourself reading this, you probably already know that Windows 7 has no straightforward "Repair Install" option of the type you could use on Windows XP to move a hard drive to a system with completely different hardware.  According to what I've read, people often would do this when replacing motherboards.  You've probably also been annoyed to find out that the Windows 7 install disk, and the Vista and Windows 7 resources you find via Google search, tend to be obtuse about the reasons people would want to do such things: they assume you can successfully log into Windows at all on the relevant machine, but you still need to "repair" your installation.  You boot up the Windows installation disk, tell it you want to "Upgrade" your existing installation (the method of "Repair Install" that everybody recommends), and it tells you to remove the disk, shut down, boot up Windows, and stick the disk into the drive again after you're in Windows.  Well, when you've moved your system disk to a system that has a completely different motherboard, that's not really an option.  Usually, you get a fatal error and an infinite reboot cycle.  But by all means, if you can get into Windows on your relevant system, and you still need to do a Repair Install, follow the instructions at the sevenforums.com link; don't do what I did.

To make this work, you need to have access to the old, working system (the "source" system).  So this may not work for a lot of motherboard replacements, especially if the old one is burnt out or you didn't find out the system didn't boot until the whole rebuild was done, and you don't want to undo everything and start over. But if you're just trying to clone an existing system so you don't have to go through the weeks-long process of reinstalling all your software and redoing all your miscellaneous config settings, or if you're trying to move a system from any old (working) hardware to any new hardware, this might work for you.

So without any further ado, here's what you do: 

1. Boot up your working (old) system, using the hard drive that belongs in the new system as your system drive.

2. Begin the "Repair Install" process as described in the sevenforums.com link.  Go about the beginning of the Upgrade process as if you were Repair Installing to your old system.

3. When the Windows installer tries to reboot for the first time -- a few minutes after it has said "That's all the information we need right now" -- forcibly TURN OFF your computer* in the few seconds after the installer OS has unloaded and before the installer OS loads up again.  I believe the first reboot attempt happens after it's done with the "Expanding files" step, but I'm not 100% sure (please tell me if I'm wrong).  Just make sure the system is at least in your peripheral vision while the installation is happening, so that you'll see when the monitor goes blank.

4. Move your hard drive to the new system.  I also put the installation disk into the DVD drive, but I doubt that was necessary.

5. Boot up the new system, making sure that it boots to your hard drive, not the installation disk.  If you have a choice on your bootloader screen, choose the entry that says something like "Windows 7 Setup", not the one that says something about "Rollback".

6. Let the installer do its thing.  In my case, it seemed like the installer took a while longer than it has usually taken for me, but then, I usually am not running an Upgrade, but a new installation, so this could be normal.

The process itself is a lot simpler than explaining why you would want to do it.  Basically, it's the Repair Install process, but with the hard drive moved to the new system partway through, after the installation files have been prepared on the system drive.  My guess is that all of the assigning of low-level hardware drivers -- the stuff that makes it impossible to move the system hard drive without any hassles -- simply happens later in the installation process.

If you're still reading, be sure that you have a good reason for wanting to do this.  I did it because I had spent many hours installing development tools onto my new SSD drive.  I decided I wanted that drive in my new desktop, and I didn't want to reinstall everything.  And because this machine wasn't one of my two "main" computers, I didn't feel like I was risking much.  Even so, I made sure to take a Windows Home Server backup before beginning the process, just in case I wanted to get that experimental system back.

I cannot stress these things enough: 

  1. Don't do this if you don't feel like you know what you're doing.  
  2. Don't ever do this with a system drive that you're relying on for anything important, unless you're 100% confident you can restore it quickly.  Even so, I probably wouldn't do it.
  3. I don't know whether this would work for other people's hardware.
  4. I'm not really recommending you do this at all, and even if I were, you shouldn't think of me as an authority, as I'm just a guy on the internet.

 

For anyone who heard me telling everybody a couple weeks ago about how Windows 7 was awesome because it lets you just move a hard drive from one machine to another, and just figures it out: consider this a revision to that.  I had seen two cases where Windows 7 installations seamlessly figured out new hardware: 1) a VHD-based Windows 7 system had zero difficulty moving from running in VirtualPC to having that VHD file running on native hardware as a bootable VHD.  It may seem counterintuitive to some, but as far as the OS is concerned, this is one case of moving seamlessly between "hardware" setups.  2) When I moved a hard drive from a Latitude 820 to a Latitude 830 and back, Windows 7 had no problem with it.  If this sounds like nothing: I had tried to do the same thing, between the same two specific laptops, with XP system drives in the past, and they crashed hard.

* usually works by holding down the power button, but if you didn't already know how to force your PC to turn off, as opposed to turning it off via "shutdown", you shouldn't be doing this.

Currently rated 5.0 by 1 people

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

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

Which.bat -- "whereis" for old Unix people who hack their Windows something fierce

Wednesday, 17 June 2009 16:20 by kevin

(file under: interesting info that's difficult to Google)"Vintage Plastic Witch with Bat" photo by Flickr user "riptheskull"

If you're like me*†, you download a huge amount of open-source and free utilities that don't have installers, write a bunch of batch files and scripts to automate common tasks, and use cmd.exe constantly‡.  So, you're setting up a new VirtualPC image, and you know you want to have the Sysinternals utilities on your new machine €, but you don't want to re-download them and you don't know where the heck you unzipped them to.  Where oh where could pslist.exe be?  Wait, you're an old Unix guy.  When you want to know where in your path an executable file is, you say "which".

Gladly, the great Raymond Chen solved your problem years ago, though you didn't know it till now:

@for %%e in (%PATHEXT%) do @for %%i in (%1%%e) do @if NOT "%%~$PATH:i"=="" echo %%~$PATH:i

Paste this line into a file in your Windows directory (or elsewhere in your path; c:\scripts or something like that), save as "which.bat" (or "whereis.bat" if you're not really an old Unix guy and you've just been pretending up till now).  Use like so: "which pslist".  To which it replies "c:\Program Files\Sysinternals\pslist.exe".  Simple as that.

Talk to you next season! 

 

*alive!  All recent appearances to the contrary.

and I realize you probably aren't, aside from being alive

 I tried getting into PowerShell a few times, and I'm sure I'll eventually end up there, but at some of the basic shell commands, it's just not fast enough for me. I sometimes do this cycle 20 times in a minute:

cd [beginning of dir] [tab-to-complete] [enter]
dir /od
cd [other dir beginning][tab-to-complete][enter]

I just cant wait 5 seconds (every single time.) for PowerShell to "Get-ChildItem" when it would have taken 1 second for cmd.exe to "dir".  

(yes, €) You may not have known that you know you want the Sysinternals Suite until now.  I'm glad I could be part of your self-discovery process.

Currently rated 4.0 by 1 people

  • Currently 4/5 Stars.
  • 1
  • 2
  • 3
  • 4
  • 5
Categories:   Dev Info
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

A Necessary Evil

Tuesday, 19 May 2009 08:50 by aj

Creative Commons user Paulus Veltman

One of the most well-known code smells in .Net development is explicitly messing with the Garbage Collector.  In my coding travels, I’ve had at least a couple of situations where a performance/memory consumption issue was traced back to a GC.Collect() call.  In my own applications, I’ve generally followed Rico Mariani’s Rule #1, “don’t use it.”  I figure the .Net Framework team has a much better idea of how to handle that sort of stuff than I do, and for the most part, their ideas work just fine.

I’ve been working on a project for the last month or so that requires the use of an OCR API to read type-written words from TIFF images and then run them up against a set of regular expression patterns looking for useful data.  There are several OCR libraries available for purchase, but after significant testing and analysis, we decided that the Microsoft Office Document Imaging (MODI) library that comes with Office 2003 works about as well as anything else, and has the added benefit of being free, since our workstations haven’t been upgraded to Office XP.  I spent some time figuring out how to use MODI for OCR, then found a nice tutorial on Code Project that would have saved me some time.

Our TIFF images are stored in a homegrown database/file system setup that, after years of working with FileNet, is a cool breeze on a hot day.  Through more prototyping, I found that MODI OCR’s performance was best if I copied each multipage TIFF file to the local system, split them into single page files, and then ran each file through the OCR process, cleaning everything up afterward.  Here’s a chopped down version:

   1: MODI.Document modiDoc = null;
   2: MODI.Image modiImage = null;
   3: MODI.Word modiWord = null;
   4: List<String> filesToProcess = null;
   5: try
   6: {
   7:     filesToProcess = SplitTif(inputFile, workingFolder);
   8:     foreach (var fileToProcess in filesToProcess)
   9:     {
  10:         try
  11:         {
  12:             modiDoc = new MODI.Document();
  13:             modiDoc.Create(fileToProcess);
  14:             modiDoc.OCR(MODI.MiLANGUAGES.miLANG_ENGLISH, true, true);
  15:             for (var i = 0; i < modiDoc.Images.Count; i++)
  16:             {
  17:                 modiImage = (MODI.Image)modiDoc.Images[i];
  18:                 for (var j = 0; j < modiImage.Layout.Words.Count; j++)
  19:                 {
  20:                     modiWord = (MODI.Word)modiImage.Layout.Words[j];
  21:                     if (System.Text.RegularExpressions.Regex.IsMatch(modiWord.Text, regexPattern))
  22:                     {
  23:                         //Do stuff that needs to be done when there's a hit
  24:                     }
  25:                 }
  26:             }
  27:         }
  28:         finally
  29:         {
  30:             if (modiWord != null)
  31:                 DisposeCom(modiWord);
  32:             if (modiImage != null)
  33:                 DisposeCom(modiImage);
  34:             if (modiDoc != null)
  35:                 DisposeCom(modiDoc);
  36:             modiWord = null;        //This may be redundant...?
  37:             modiImage = null;
  38:             modiDoc = null;
  39:         }
  40:     }
  41: }
  42: catch (Exception ex)
  43: {
  44:     //handle it
  45: }
  46: finally
  47: {
  48:     //Cleanup temp files
  49:     if(filesToProcess != null && rdoNIS.Checked)
  50:         filesToProcess.ForEach(System.IO.File.Delete);
  51: }

Notice all of the cleanup.  I’ve learned the hard way that it’s never a bad idea to be very explicit about cleaning up COM objects, especially since a lot of COM objects don’t implement anything close to IDisposable.  So, with this code, I thought I was good to go.

And for the most part, I was.  My company has two main data centers: one in the building where I work, in a city I’ll call St. Small, and one that’s roughly 1,300 miles away, in a city I’ll call Sunville.  The TIFF images and the database I’m persisting data to are in Sunville.  The workstations that I started out running my client application for the OCR process are all in St. Small.  They worked fine, albeit slowly due to network latency and crappy hardware. But I wanted the process to run faster, since we have a lot of images to sift through, so I nabbed up the only workstation I could find in Sunville, set up my client, and started to run a batch.

I was quite surprised when I repeatedly and inconsistently received OutOfMemory exceptions from the MODI OCR method.  I checked all of the system resources, running programs, and RAM, and everything looked fine.  It’s running a dual-core processor at 2.4 GHz with 2 GB of RAM, which should be totally adequate for the MODI process, right?  Wrong.  No matter how hard I tried, I could not get these exceptions to go away.  What was even more interesting is that I wasn’t getting the errors on the workstations in St. Small.

So what’s the difference?  Duh.  Since the Sunville workstation doesn’t have nearly as much network latency to deal with, it does run quite a bit faster.  Since it’s able to run faster, it’s creating and destroying MODI COM instances much more frequently than the copies running on the St. Small systems.  So I did some more web research, more testing, and with a cringe, I added this line of code (and the comment) to my finally block: 

   1: //THIS IS VERY VERY BAD YOU BAD BOY
   2: GC.Collect();

I tested it on my workstation and performance didn’t seem to suffer too much.  So I dropped the new version of my application on the Sunville workstation and fired it up, thinking I’d solved the problem.

Nope.  The Sunville system still threw random OutOfMemory exceptions.

Creative Commons User Photos o' Randomness

What gives?  I thought GC.Collect() was the magic baseball bat that beat the crap out of everything?  If it isn’t, why is it so terrible to use it?  Well, the answer is, it is terrible to use.  Read Rico’s post and the many other articles on Garbage Collection, if you don't believe me.  But in my situation it seems necessary, since we have so many images to process and I don’t want to babysit every instance of the application.  I still had the problem, though.  Why wasn’t GC.Collect() working?

Because I wasn’t using it correctly, that’s why.  The client application I wrote was a quick and dirty Windows Forms app, so all of the MODI OCR calls were synchronous.  GC.Collect(), on the other hand, is not.  However, you can force it to be synchronous by adding one line of code, which I did, and now my application runs wherever I want it to.

   1: //THIS IS STILL VERY BAD AND YOU ARE STILL A BAD BOY
   2: GC.Collect();
   3: GC.WaitForPendingFinalizers();

It’s funny—I can actually see the points when the code execution is sitting on that line.  It doesn’t happen often, but it clears up all of my errors.  If anyone knows a better way, I would love to hear it.  I don’t want to use it, but for this project, I’ve come to believe that forcing garbage collection is a necessary evil.

Currently rated 5.0 by 1 people

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