Monday, October 23, 2006

Comments as version control

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/comments_as_version_control.htm]

At every company I've been, I see source code with old code commented out instead of deleted. In a sense, this is almost using commenting like a primitive form of version control. I see pros & cons to this approach:

Pro:

  • In environments where requirements constantly change, some developers are more comfortable seeing how the chuck was previously written so that they can easily revert.
  • You may be intending to switch back to the previous code, and it's easier to see it if the code is commented out, as opposed to digging through version control.

Con:

  • As Steve McConnell suggests in Code Complete, the purpose of comments is to show the intent of your code. Using comments as version control can be misguided.
  • It can imply a lack of confidence. If the code is really no longer used, why not just delete it and make your code leaner.
  • It can bloat the source code very quickly, requiring future developers to read through more.

I think ideally old and obsolete code should be removed instead of commented out (makes for leaner, easier-to-read code), but I can see the other approach in certain development cultures.

Sunday, October 22, 2006

How many ways to represent True and False

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/how_many_ways_to_represent_true_and_false.htm]

I was recently serializing data from both the database and user input, and it made me reflect on how many ways you can represent a boolean value as a literal string. For an English-language app (no globalization), here are several ways to represent a boolean:
  • TRUE / FALSE - converting from a literal string.
  • T / F - users who only want to enter the first character.
  • Yes / No - non-technical users who want "friendly" terms.
  • Y / N - again, users who want to only enter the first character.
  • 1/0 - A bit, such as how SQL Server stores booleans.

And of course, the first three options can be case insensitive and trimmed white space (i.e. "tRUe" becomes "TRUE").

I had talked about using Convert.ToString to convert different objects to string, so I'd initially look at it's related method: Convert.ToBoolean. But one quickly sees that that won't handle all the cases (and with good reason). The only literal string it takes from this group is "true"/"false". For example, it would handle converting the integer 1, but not the literal string "1". Having a single function that just converts these different inputs to a boolean is a nice convenience. Here's a sample:

public static bool ConvertToBoolean(string strVal)
{
  if (string.IsNullOrEmpty(strVal))
    return false;

  strVal = strVal.ToUpper().Trim();

  if (strVal == "TRUE" || strVal == "T" || strVal == "1"
    || strVal == "YES" || strVal == "Y")
    return true;
  else if (strVal == "FALSE" || strVal == "F" || strVal == "0"
    || strVal == "NO" || strVal == "N")
    return false;
  else
    throw new ArgumentException("Cannot convert '"
    + strVal + "' to Boolean.");
}

Wednesday, October 18, 2006

What to do before just asking someone?

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/what_to_do_before_just_asking_someone.htm]

Some projects have the local superstar. Any whenever anyone has a question, rather than figure it out for themselves (or even try to), they just ask their local star. There are two problems to this approach: (1) It eventually burdens that "star", and (2) It weakens the average guy's ability to find out info for himself.

Sometimes you need the answer right away, so you'll just ask someone. (And it would take too long to figure out yourself). However, most of the time it's worth first taking a stab at it yourself. Here are some ideas:

  • Tell yourself that you're just going to try for the next 5 minutes (If you say "I don't have 5 minutes", consider does anyone else?)
  • Read the documentation (feature spec, help doc, inline code comments, etc...)
  • Google the buzzwords, especially if it's a unique error message (like '__pendingCallbacks[...].async' is null or not an object)
  • Step back and think of the higher level concepts (maybe there's a knowledge gap you need to fill)
  • Step through the code in the debugger (such as to see the context it's being used in)
  • Use SQL Profiler to find data sources (what SP does this call?
  • Start at the problem and try working backwards
  • Find the steps necessary to deterministically reproduce the problem, then take a divide and conquer approach, checking each part of the code in isolation to see if it is the cause.
  • Work on something else and come back to the problem later with a fresh mind.

While having other star coworkers is a nice safety net, it is a luxury that may not always be there. And during those times, it will be nice to have had the practice at figuring out answers for oneself. Besides, the more someone practices at solving problems, the more likely it is that they'll become that goto guy that everyone else asks questions too.

Tuesday, October 17, 2006

Sql Tools - Profiler and SqlCommand

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/sql_tools__profiler_and_sqlcommand.htm]

Everyone knows how to use SQL Management Studio, but there are two other useful tools that SQL Server 2005 has.

  • SQL Profiler - This lets you profile the SQL Server calls. It's very effective to determine what page is making which calls (and how long those calls take). It's much easier to just run profiler, as opposed to stepping through all the code to find what SP gets triggered when you click Button X.
  • SqlCmd - This is the command line for SQL Server (replaces osql for SQL 2000). It's useful when you need to Automate, or don't want the full SQL GUI installed (such as when you have limited space on a build server).

Monday, October 16, 2006

Converting to a string

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/converting_to_a_string.htm]

In web development, we constantly need to get string values (from objects of different data types) that we can display to the user. For example, ints, dates, bool, and even custom objects eventually need to be rendered as some string. There are different ways to handle this conversion, but I think one of them is best.

      //Fail if type is wrong, such as an integer
      //Compile error: Cannot convert type 'int' to 'string'
      string s1 = (string)i;

      //Fails if object is null
      string s2 = i.ToString();

      string s3 = Convert.ToString(i);

As the code snippet shows, there are at least three standard ways: (1) casting, (2) calling the ToString method - which every object has, and (3) using the System.Convert class. I think the third way is often the best because the first will throw a compile error if the the object is an incompatible type (like converting a value type int), and the second will fail at run time if the object is null (not possible with value types like integers, but very likely with other reference types). However, using System.Convert handles both of these cases - you can convert value types and handle null instances of reference types. This lets you use a consistent approach for your conversions.

Sunday, October 15, 2006

'__pendingCallbacks[...].async' is null or not an object

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/__pendingcallbacksasync_is_null_or_not_an_object.htm]

I was doing so ASP.Net 2.0 callbacks (see an overview here: http://dotnet.sys-con.com/read/192509.htm), and kept getting this error when I did a document.location redirect on the ReceiveCallback JavaScript function.

Microsoft JScript runtime error: '__pendingCallbacks[...].async' is null or not an object

Looks like a flagrant Microsoft bug: http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101974

People have different suggestions

What worked for me is the setTimeout. However, I needed to pass a parameter to the variable, so I used a technique like so:

var _gRValue;
function ReceiveCallback(rValue)
{
  _gRValue = rValue;
  window.setTimeout('__ReceiveCallback(_gRValue)',0);
}

function __ReceiveCallback(rValue)
{
  //Do stuff here
} //end of method
 

To handle the nature of setTimeout, I stored the returned data in a member variable.

Backwards: "I wanted to do Unit Tests, but my manager wouldn't let me"

[This was originally posted at http://timstall.dotnetdevelopersjournal.com/backwards_i_wanted_to_do_unit_tests_but_my_manager_wouldnt_l.htm]

I've heard this before when I give interviews or meet new developers at tradeshows.  The thinking seems to go that "While I'd personally love to do this best practice of 'Unit Tests', adding them takes a lot longer (like adding a new development phase), which costs extra money, therefore I need managerial approval." This is fundamentally backwards.

The whole point of Unit Tests is that:

  1. They save you time: Obviously with regression testing, but also by stubbing out the context so you can very quickly test things in isolation (without wasting tons of time constantly re-setting up that context). They also help you to see all the boundary test cases, and hence prevent future bugs.
  2. They are free to use - open source tools like NUnit can be downloaded for free and instantly used for your own personal development. It's not like you need to purchase a separate expensive tool, or hire out some auditor to review your code.
  3. You write tests as you develop, not afterwards.

Here's an analogy: Think of your schedule like a bucket, and your tasks are like rocks that fill up the bucket. You can't increase the size of your bucket, or decrease the number of rocks, therefore the bucket (i.e. your schedule) seems full. However, there are gaps between the rocks (just like there are gaps between tasks - like setting up the context and regression testing). You could pour sand into a full bucket, in the cracks in between the rocks. That's what unit tests are like. If you do them as you develop, you can squeeze them into your schedule without overflowing it.