Showing posts with label misc. Show all posts
Showing posts with label misc. Show all posts

Friday, June 25, 2010

In space, no one can hear you scream

Lately, most of my time is being spent refactoring legacy code. Everywhere I look I find try/catch blocks wrapped around a few lines of code. It appears the developer was using this as a way to "fix" bugs - by catching and eating the exception instead of tracking down the root cause. Enabling exception breakpoints and attempting to run the code is enough to make a developer scream. Unfortunately, if the exception isn't rethrown...

   catch (Exception)
   {
       // No one can hear you scream!
   }

I may have to put that on a t-shirt...

Thursday, December 11, 2008

New Year's Resolutions

I was looking through my "to blog" list recently and I was reminded of something: I have a LOT of items on my list. Two or three times the number of posts I've written thus far. What's worse is some of these items would actually make an entire series of posts. At my current rate of posting (once or twice a month) I'm never going to finish.

Then there are the computer books sitting on my shelf, several of which I've not read much passed the intro. Some may not be worth digging into right now, but a few of them are "must reads." Code Complete for example. Or Head First Design Patterns. I've not finished either of them, and have yet to fully grok what I have read.

The question then is how to tackle these lists? It seems the only way to stay motivated is to come up with a schedule and then stick to it. Read one chapter a week. Write a blog post a week. Or if I work it just right, I could write a blog post on the chapter I just read. But what if I get bored with one subject? Do I switch between books each week, or should I stick to one until I finish? If I want to post on what I'm reading, how much original content is necessary and how much can I quote or link to?

I'm off to ponder these questions (or read web comics, I've not decided which.) What are your thoughts on the subject? Do you have any professional goals to tackle next year? (Or even non-professional goals?) And if so, how do you plan to keep on track?

Friday, May 9, 2008

Add scroll wheel support to VB6

Yes, you read that right. The client I'm currently assigned to has a significant amount of legacy code in VB6. Not an ideal situation, but at least it isn't COBOL.

Anyway, one of the first things I noticed after loading a project was that I couldn't scroll through the code using the mouse wheel. It turns out the VB6 IDE didn't include wheel support. Fortunately, there's an add-in from Microsoft that fixes this. See KB article 837910 for the download and install instructions.

And yes, I'm aware that this probably doesn't pertain to you (if it does, I feel your pain.) The post is mainly a bookmark for my own reference. Any sympathy it generates is just a bonus :)

Thursday, May 8, 2008

Adding entries to a file's right-click menu

When setting up a new developer computer, there are a number of tools and shortcuts I typically want. One of these is the ability to register COM dlls through Explorer's right-click menu. The easiest way to add this is through the registry.

Standard warning: I'm sure you're aware that messing with the registry may cause all sorts of problems. Proceed with caution. Unless of course it's not your computer you're messing with. In which case, hack away.

Start regedit from the Run dialog (keyboard shortcut: Win+R.) Under HKCR (HKEY_CLASSES_ROOT) locate the extension of the file to modify - .dll in this case. In the list of properties, you should see a "(Default)" string with the internal name of the file type. For dll it will be "dllfile."


Further down, still under HKCR, will be an entry for dllfile. This is where the changes will be made.


Under dllfile, expand the "shell" key. Add a new key and set the name as you want it to appear on the right-click menu (mine is "register".) Within that, add another key with the value "command." The "(Default)" string needs be set to the command that you want to run. For this exercise it will be:

regsvr32.exe "%1"

Regsvr32 is the command-line utility to register the COM component. The %1 in quotes tells Windows to pass in the filename and path as the first parameter.


Once this is done, you should be able to right-click on any dll and see the new entry.


This takes care of one machine. Now that you have the shortcut defined, it would be useful to copy this to other machines. To do so, right-click on the "register" key and choose Export. Saving the selected branch will give you a .reg file with the changes. Copy the file to another computer and double-click to import it into the registry of that computer.

Tuesday, February 26, 2008

I can read the file myself, thank you

I've been downloading a number of PDFs lately, and the one thing that has been bugging me is the slow performance of Adobe Reader. Fortunately, I've found at least one of the major causes - the accessibility features. When opening a PDF, I was occasionally presented with a dialog stating "Please wait while the document is being prepared for reading." A quick search on the web located others with the same problem. This post, along with one of the comments, led me to the solution:

Locate the install folder (C:\Program Files\Adobe\Reader 8.0\Reader\plug_ins) and delete the following files

  • Accessibility.api

  • MakeAccessible.api

  • ReadOutLoud.api


Though I didn't break out the stopwatch, the performance improvement was significant. Before, there would be a pause after scrolling more than a page or two. Now, I can hold the PageDown key and see dozens of pages fly by before any pause (probably to allocate more memory.)

Friday, October 5, 2007

Lessons learned

My current project is nearing completion of Phase 1. Along the way, I've compiled a list of observations, lessons learned, etc, some of which I've already blogged. Here are a few more:

1) When possible, use project references instead of file references. It may seem convenient to break up the code into smaller solutions and use file references across solutions. Problems arise when you have one master solution that builds all of the projects - you must explicitly set the build order. With project references, VisualStudio determines the proper order for you, meaning less maintenance. Also, when you right-click on a method/class/whatever and choose "Go To Definition," file references will take you to a page of metadata instead of the actual code.

2) Refactor often, and sooner rather than later. Say you're working on set of classes that use a common interface. You then decide to build a base class from that interface, and derive the other classes from the base. Don't leave old classes as-is and use the base only for new classes. One issue is you potentially leave bugs that the base was specifically designed to address. Another is that when a new team member joins the project, he will likely use existing code as a template for adding new functionality. If he sees the non-base-derived class and builds his own directly from the interface, refactoring later becomes more difficult.

3) Remove dead code. When you replace one method with another, delete the old method. When functionality is no longer required, delete that functionality. Don't leave it in. Don't comment it out. If you need that code later, pull it from your source repository. As the source grows in size, you'll have enough to deal with without adding the extra hassle associated with dead code.

4) Obsolete code if you can't currently delete it. Say you replace a method with another, but you can't replace all of the method calls at the moment (this especially happens with public methods.) Mark the method as obsolete and note the proper method to use instead. In C# this looks like [Obsolete("Use method foo instead")].

5) When changing the database schema, change the data access code at the same time. Until these two are in sync, your code doesn't work. You should have failing unit tests to flag the issues, but that's not always the case. In that instance, your first indication that there is a mismatch is when a developer attempts to run code that he thought was working. Often, the developer attempts to track down the problem, which another dev already knew about. All of which leads to wasted time.

6) Reduce confusion within the code. Maybe there's a method being incorrectly called, or called when another should have been used instead. It's not enough to correct the developer. Look at why the error occurred. Perhaps better comments on the method would help (use xml comments to populate intellisense.) Or perhaps the method could be named better. The problem may also be due to poorly architected code in need of refactoring. Bottom line: fix the issue instead of addressing symptoms.

7) If you can't unit test the entire codebase, write tests for the error-prone code. Ideally you want 100% code coverage from your unit tests. In reality this isn't going to happen. Therefore, focus unit tests on problematic and/or complex areas of code. We have lots of code binding to dataset columns. These columns are taken directly from the database. If a column was dropped from the table, you won't receive a compiler error on row["DroppedColumn"] but you will receive a runtime exception. These issues need to be caught by the unit tests, not the QA team.

8) Code generation must be handled very carefully. Most see code generation as an easy way to save time on a project. This is especially true for database access code - basic CRUD operations don't change from one table to the next. Once you have the first generation complete, how you proceed becomes critical. Say you spend a few weeks writing code that uses the autogen code. Someone then decides to make changes to the templates and regen everything. While the intent may have been valid, this regen quite likely broke existing code. At a minimum, your unit tests fail and you can easily find and fix all of the problems. But even then, time must be spent on the fix. If you don't have a decent set of unit tests - be prepared for the increase in tickets from QA. Unless your autogen code is truly separate from the rest of the project, it's probably better in the long run to gen once and modify by hand after that.

Sunday, September 16, 2007

Silverlight preparation

A friend recently decided to start a monthly Hack Day for a small group of colleagues. Given that it's often difficult to motivate oneself to study new technology, the idea is to gather like-minded slackers and force each other to do a little research.

After some discussion, we decided on Silverlight as the first topic. Here's what I did in preparation:

1) Downloaded a VPC image of Orcas (aka VS2008.) You have to download a base image along with the Orcas image - nearly 14GB total.

2) Installed various 1.0 and 1.1 packages:

Silverlight 1.0 Runtime
Silverlight 1.0 SDK
Silverlight 1.1 Alpha Refresh
Silverlight Tools for VS2008
Expression Blend 2 August Preview

3) Watched the Getting Started video and a few Blend tutorials

Uncompressed images and file sizes

Scanning paper documents can be a useful way to transfer and store data. This of course assumes you are scanning bitonal, with some form of image compression. If you were to scan in 24-bit color with no compression, you'd find the output less than useful.

To see this, let's start with a 1 inch square, at 10 dots per inch (dpi.) The total number of dots (pixels) is 10x10, or 100. If we create a larger square, say 5 inches on each side, we now have 25 square inches. At 10dpi, that's 2500 pixels (100 dots per square x 25 squares.) If we scanned a normal sheet of paper (8.5x11) we have a total of 93500 pixels.

Going back to the 1 inch square, say we double the dpi to 20. What does that do to the pixel count? You might initially say it doubles. If you calculate it, however, you find that you quadrupled the number (20x20 = 400.)

The total number of pixels can be found using the formula:

(horizontal dpi * image width in inches) * (vertical dpi * image height in inches) = total pixels

A normal sheet of paper, scanned at 100dpi

(100 * 8.5) * (100 * 11) = 935,000 pixels

The other item to consider is the bit depth of the image. For a bitonal image, each pixel is represented by 1 bit (black or white.) Color images, such as photos, are saved with RGB values for each pixel. This typically requires one byte per color, or three bytes per pixel

To calculate the total number of bytes per image:

total pixels * bytes per pixel = total bytes

A normal sheet of paper, again at 100dpi, scanned in 1 bit-per-pixel (bpp)

935000 * 0.125 = 116,875 bytes

That same page, scanned in 24bpp

935000 * 3 = 2,805,000 bytes (~2.5MB)

As you can see, scanning in full color without compression creates much larger images. Again with 24bit color, here are some common scanner dpi's with their resulting image sizes (in bytes.)


200 dpi = (200 * 8.5) * (200 * 11) * 3 = 11,220,000

300 dpi = (300 * 8.5) * (300 * 11) * 3 = 25,245,000

600 dpi = (600 * 8.5) * (600 * 11) * 3 = 100,980,000