vs, sublime comments edit

As developers, we’ve all argued over tabs vs. spaces, indentation size, how line endings should be, and so on.

And, of course, each project you work on has different standards for these things. Because why not.

What really kills me about these different settings, and what probably kills you, is remembering to reconfigure all your editors to match the project settings. Then when you switch, reconfigure again.

The open source project EditorConfig aims to rescue you from this nightmare. Simply place an .editorconfig file in your project and your editor can pick up the settings from there. Move to the next project (which also uses .editorconfig) and everything dynamically updates.

I don’t know why this isn’t the most popular Visual Studio add-in ever.

Here’s the deal:

Here’s the .editorconfig I use. I like tab indentation except in view markup. We’re a Windows shop, so lines end in CRLF. I hate trailing whitespace. I also like to keep the default settings for some project/VS files.

root = true

[*]
end_of_line = CRLF
indent_style = tab
trim_trailing_whitespace = true

[*.ascx]
indent_style = space
indent_size = 4

[*.aspx]
indent_style = space
indent_size = 4

[*.config]
indent_style = space
indent_size = 4

[*.cshtml]
indent_style = space
indent_size = 4

[*.csproj]
indent_style = space
indent_size = 2

[*.html]
indent_style = space
indent_size = 4

[*.resx]
indent_style = space
indent_size = 2

[*.wxi]
indent_style = space
indent_size = 4

[*.wxl]
indent_style = space
indent_size = 4

[*.wxs]
indent_style = space
indent_size = 4

Note there’s a recent update to the EditorConfig format that supports multiple matching, like:

[{*.wxl,*.wxs}]
indent_style = space
indent_size = 4

…but there’s a bug in the Sublime Text plugin around this so I’ve expanded those for now to maintain maximum compatibility.

I’ve added one of these to Autofac to help our contributors and us. It makes it really easy to switch from my (preferred) tab settings to use the spaces Autofac likes. No more debate, no more forgetting.

Now, get out there and standardize your editor settings!

testing, vs comments edit

I get a lot of questions from people both at work and online asking for help in troubleshooting issues during development. I’m more than happy to help folks out because I feel successful if I help others to be successful.

That said, there’s a limited amount of time in the day, and, you know, I have to get stuff done, too. Plus, I’d much rather teach a person to fish than just hand them the fish repeatedly and I don’t want to be the roadblock stopping folks from getting things done, so I figured it’d be good to write up the basic steps I go through when troubleshooting stuff as a .NET developer in the hope it will help others.

Plus - if you ever do ask for help, this is the sort of stuff I’d ask you for, sort of along the lines of calling tech support and them asking you to reboot your computer first. Is it plugged in? That’s this sort of thing.

Soooo… assuming you’re developing an app, not trying to do some crazy debug-in-production scenario…

Change Your Thinking and Recognize Patterns

This is more of a “preparation for debugging” thing. It is very easy to get intimidated when working with new technology or on something with which you’re not familiar. It’s also easy to think there’s no way the error you’re seeing is something you can handle or that it’s so unique there’s no way to figure it out.

  • Don’t get overwhelmed. Stop and take a breath. You will figure it out.
  • Don’t raise the red flag. Along with not getting overwhelmed… unless you’re five minutes from having to ship and your laptop just lit on fire, consider not sending out the all-hands ‘I NEED HELP ASAP’ email with screen shots and angry red arrows wondering what this issue means.
  • Realize you are not a special snowflake. That sounds mean, but think about it - even if you’re working on the newest, coolest thing ever built, you’re building that with components that other people have used. Other folks may not have received literally exactly the same error in literally exactly the same circumstances but there’s a pretty high probability you’re not the first to run into the issue you’re seeing.
  • Don’t blame the compiler. Sure, software is buggy, and as we use NuGet to pull in third-party dependencies it means there are a lot of bits out of your control that you didn’t write… and sure, they might be the cause of the issue. But most likely it’s your stuff, so look there first.
  • Use your experience. You may not have seen this exact error in this exact spot, but have you seen it elsewhere? Have you seen other errors in code similar to the code with the error? Do you recognize any patterns (or anti-patterns) in the code that might clue you in?

Read the Exception Message

This is an extension of RTFM - RTFEM. I recognize that there are times when exception messages are somewhat unclear, but in most cases it actually does tell you what happened with enough detail to start fixing the issue.

And don’t forget to look at the stack trace. That can be just as helpful as the message itself.

Look at the Inner Exception

Exceptions don’t always just stop with a message and a stack trace. Sometimes one error happens, which then causes a sort of “secondary” error that can seem misleading. Why did you get that weird exception? You’re not calling anything in there! Look for an inner exception - particularly if you’re unclear on the main exception you’re seeing, the inner exception may help you make sense of it.

And don’t forget to follow the inner exception chain - each inner exception can have its own inner exception. Look at the whole chain and their inner messages/stack traces. This can really help you pinpoint where the problem is.

Boogle the Message

You know, “Bing/Google” == “Boogle” right? Seriously, though, put the exception message(s) into your favorite search engine of choice and see what comes up.

  • Remove application-specific values - stuff like variable names or literal string values. You’re probably more interested in places that type of exception happened rather than literally the exact same exception.
  • Add “hint words” - like if it happened in an MVC application, throw “MVC” in the query. It can help narrow down the scope of the search.
  • Don’t give up after the first search - just because the first hit isn’t exactly the answer doesn’t mean the answer isn’t out there. Modify the query to see if you can get some different results.

Ask a Rubber Duck

Rubber duck debugging is a pretty well-known strategy where you pretend to ask a rubber duck your question and, as you are forced to slow down and ask the duck… you end up answering your own question.

Seriously, though, step back from the keyboard for a second and think about the error you’re seeing. Run back through your mind and think about the error and what might be causing it. It’s easy to get mental blinders on; take ‘em off!

Break in a Debugger

Put a breakpoint on the line of code throwing the exception. Use the various debugging windows in Visual Studio to look at the values of the variables in the vicinity. Especially if you’re getting something like a NullReferenceException you can pretty quickly figure out what’s null and what might be causing trouble.

Step Into Third-Party Code

Many popular NuGet packages put symbol/source packages up on SymbolSource.org. If you configure Visual Studio to use these packages you can step into the source for these. You can also step into Microsoft .NET framework source (the SymbolSource setup enables both scenarios).

Do this!

If you don’t know what’s going on, try stepping into the code. Figure out why the error is happening, then follow it back to figure out the root cause.

Use a Decompiler

If you can’t step into the third-party source, try looking at the third-party stuff in a decompiler like Reflector, JustDecompile, dotPeek, or ILSpy.

You can use the stack trace to narrow down where the issue might be going on and try tracing back the root cause. You might not get an exact line, but it’ll narrow it down for you a lot.

Create a Reproduction

Usually crazy hard-to-debug stuff happens in a large, complex system and figuring out why that’s happening can feel overwhelming. Try creating a reproduction in a smaller, standalone project. Doing this is a lot like the rubber duck debugging, but it tells you a little more in the way of concrete information.

  • As you work through creating the reproduction, the number of moving pieces becomes easier to visualize.
  • If you can easily reproduce the issue in a smaller environment, you can troubleshoot with many fewer moving pieces and that’s easier than doing it in the complex environment. Then you can take that info to the larger system.
  • If you can’t easily reproduce the issue then at least you know where the problem isn’t. That can sometimes be just as helpful as knowing where the issue is.

Next Steps

Once you’ve gotten this far, you probably have a lot of really great information with which you can ask a very clear, very smart question. You’ve probably also learned a ton along the way that you can take with you on your next troubleshooting expedition, making you that much better at what you do. When you do ask your question (e.g., on StackOverflow) be sure to include all the information you’ve gathered so people can dive right into answering your question.

Good luck troubleshooting!

personal, home comments edit

My daughter and I are both big Doctor Who fans. She has a bathroom that she primarily uses, so we decided to make that into a ThinkGeek extravaganza of TARDIS awesomeness. Here’s what we got:

Doctor Who TARDIS Bath Mat

The bath mat is pretty decent. It is smaller than the throw rug and works well in the bathroom.

Doctor Who TARDIS Shower Curtain

The shower curtain is OK, but it is a thinner plastic than I’d like. I really wish it was fabric, like what you’d put in front of a plastic curtain; or maybe a nice thick plastic… but it’s not. The first one we received arrived damaged - the print on it had rubbed off and one of the metal grommets at the top was ripped out. ThinkGeek support was super awesome and sent us a new one immediately.

Of course, then my stupid cat decided to chew through a section on the bottom of the new one so I had to do my best to disguise that, but it still irritates me. Damn cat.

Doctor Who TARDIS Ceramic Toothbrush Holder

The toothbrush holder is really nice. Looks good and nice quality. My three-year-old daughter’s toothbrush is just a tad short for it and falls in, but that’s not a fault in the holder. She just needs a bigger toothbrush.

Doctor Who 3-Piece Bath Towel Set

We got two sets of these towels and they are awesome. Very thick, very plush. I wish all towels were nice like this.

Doctor Who TARDIS Shower Rack

We actually have the shower rack hanging on our wall because our shower is one of those fiberglass inserts rather than tile, so the shower head doesn’t sit flush with the wall. We have some hair supplies in there. One problem I ran into with this was that the little stickers didn’t adhere very well. I had to do a little super glue work to get the stickers stuck down permanently. It could have just been this one unit, but it was less than optimal.

The bathroom looks really good with all this stuff in it, and my daughter is super pleased with it.

vs, wcf comments edit

I’ve run into this issue a couple of times now and I always forget what the answer is, so… blog time.

We have some WCF service references in our projects and we were in the process of updating the generated code (right click on the reference, “Update Service Reference”) when we got an assembly reference error:

Could not load file or assembly AssemblyNameHere, Version=1.0.0.0, Culture=neutral, PublicKeyToken=1234567890123456 or one of its dependencies. The located assembly's manifest definition does not match the assembly reference.

Normally you can fix this sort of thing by adding a binding redirect to your app.config or web.config and calling it a day. But we had the binding redirect in place for the assembly already. What the… ?!

As it turns out, svcutil.exe and the service reference code generation process don’t use binding redirects from configuration. It didn’t matter where we put the redirect, we still got the error.

The fix is to reduce the set of assemblies with types that get reused. Right-click the service reference and select “Configure Service Reference.” Switch the setting to reuse types in referenced assemblies to be very specific. If you aren’t actually reusing types from a particular assembly (especially third-party assemblies you aren’t building), don’t include it in the list.

We were really only reusing types in one assembly, not the whole giant set of assemblies referenced. Cleaning that up removed the need for the binding redirect and everything started working again as normal.

Note: If you really want to use binding redirects, you can add them to devenv.exe.config so Visual Studio itself uses them. Not awesome, and I wouldn’t recommend it, but… technically possible.

testing comments edit

I’ve noticed that some of our unit tests are running a little long and I’m trying to figure out which ones are taking the longest. While TeamCity has some nice NUnit timing info, it’s a pain to build the whole thing on the build server when I can just try things out locally.

If you have NUnit writing XML output in your command line build (using the /xml: switch) then you can use Log Parser to query the XML file and write a little CSV report with the timings in it:

LogParser.exe "SELECT name, time FROM Results.xml#//test-case ORDER BY time DESC" -i:xml -fMode:Tree -o:csv

A little fancier: take all of the tests across several reports and write the output to a file rather than the console:

LogParser.exe "SELECT name, time INTO timings.csv FROM *.xml#//test-case ORDER BY time DESC" -i:xml -fMode:Tree -o:csv

And fancier still: Take all of the reports across multiple test runs and get the average times for the tests (by name) so you can see which tests over time run the longest:

LogParser.exe "SELECT name, AVG(time) as averagetime INTO timings.csv FROM *.xml#//test-case GROUP BY name ORDER BY averagetime DESC" -i:xml -fMode:Tree -o:csv