# Monday, April 23, 2007

Visual Studio 2005 - Source Control Warnings (or lack thereof)

I've just had to apologise to my peers for breaking the build (thankfully not something that happens often).  I encountered an interesting situation where writeable files don't show as such (a build script had 'got latest' but left files writeable).  I then made some changes and performed an incomplete checkin as half of the changed items weren't checked out.  Visual Studio interestingly showed all of the files as 'locked' even though they were writeable.  VS2003 used to detect that and give you a different type of 'tick' to show the file was writeable but not checked out (I think :-) ).

'Silly boy' - I hear you cry - yes I should have done a get latest before checking in (but didn't - my bad).  This does highlight however the Source Control settings available in the Tools-->Options dialog.  We enforce Checkin comments (through a VSS Addin) and so for safety (knowing what VS2005 is doing with VSS) it's always worth ensuring the following are enforced:

  • Prompt before checkout
  • Prompt before checkin (to allow comments)
  • Don't allow editing of checked-in items
  • Checked-in item behaviour
    • On Save - prompt for checkout
    • On Edit  - prompt for checkout

I'd changed some of these items in the past week but some had reverted to previous settings (a little concerning!!).

Anyway - it's all good - the build passed and I'm a little wiser about what options to tick in future.

posted on Monday, April 23, 2007 9:50:13 AM (AUS Eastern Standard Time, UTC+10:00)  #    Comments [0]
# Tuesday, March 20, 2007

PrevX - DeleteOld (eh?)

I just found that the top entry in google for 'codebureau' is actually some listing on prevx.com (which I'd never heard of) that's seeming to suggest that DeleteOld (a console app I posted on CodeProject some time ago) is possibly spyware/malware - bloody cheek!  I'd be interested to know how this pops up on that tool, and also whether the .NET code has some flaws that means it can be used in a malicious way.  At least then I could defend myself.

posted on Tuesday, March 20, 2007 1:02:11 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]

Visual Studio 2003 Colours - Registry Entries

Visual Studio 2003 doesn't give you any way of exporting your customised colours (I've gone for a 'black' theme) - well, black is the new black you know!

The theme's shown below (not that it's that great - but illustrates the effect the registry entries (further below) have...  In Visual Studio 2005 of course you can simply export your entire settings.  Oh yeah - also ignore the code as that's simply a work in progress for something I'm going to post on CodeProject in the next couple of months.

To create this look - simply copy the text below and save in a .reg file.  Take a backup of your current colours first of course by exporting the key: [HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1\FontAndColors] to a file.  I've got some ReSharper v2 settings in there too so you can remove those if you don't use ReSharper (shame on you!)

Windows Registry Editor Version 5.00

[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1\FontAndColors]
"Color Palette"=hex:ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,\
  00,ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,00,\
  ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,00,ff,ff,ff,00

[HKEY_CURRENT_USER\Software\Microsoft\VisualStudio\7.1\FontAndColors\{A27B4E24-A735-4D1D-B8E7-9716E1E3D8E0}]
"Colorable item format version"=dword:00000008
"FontName"="Monaco"
"FontPointSize"=dword:00000008
"FontCharSet"=dword:00000000
"Plain Text Foreground"=dword:00ffffff
"Plain Text Background"=dword:00000000
"Plain Text FontFlags"=dword:00000000
"Line Numbers Foreground"=dword:00c0c0c0
"Line Numbers Background"=dword:00000000
"Line Numbers FontFlags"=dword:80000000
"Collapsible Text Foreground"=dword:0000aaaa
"Collapsible Text Background"=dword:00000000
"Collapsible Text FontFlags"=dword:00000000
"Comment Foreground"=dword:002cef10
"Comment Background"=dword:02000000
"Comment FontFlags"=dword:00000000
"Current Statement Foreground"=dword:00000000
"Current Statement Background"=dword:0000ffff
"Current Statement FontFlags"=dword:00000000
"HTML Element Name Foreground"=dword:008080ff
"HTML Element Name Background"=dword:02000000
"HTML Element Name FontFlags"=dword:00000000
"HTML Operator Foreground"=dword:004080ff
"HTML Operator Background"=dword:02000000
"HTML Operator FontFlags"=dword:00000000
"HTML String Foreground"=dword:0000ff00
"HTML String Background"=dword:02000000
"HTML String FontFlags"=dword:00000000
"HTML Tag Delimiter Foreground"=dword:0000ffff
"HTML Tag Delimiter Background"=dword:02000000
"HTML Tag Delimiter FontFlags"=dword:00000000
"Identifier Foreground"=dword:00dfdfdf
"Identifier Background"=dword:02000000
"Identifier FontFlags"=dword:00000000
"Keyword Foreground"=dword:00538bff
"Keyword Background"=dword:02000000
"Keyword FontFlags"=dword:00000000
"Other Error Foreground"=dword:0000ff00
"Other Error Background"=dword:02000000
"Other Error FontFlags"=dword:00000000
"Preprocessor Keyword Foreground"=dword:00c0b4f3
"Preprocessor Keyword Background"=dword:02000000
"Preprocessor Keyword FontFlags"=dword:00000000
"ReSharper Completion Replacement Range Foreground"=dword:00e1e4ff
"ReSharper Completion Replacement Range Background"=dword:00000000
"ReSharper Completion Replacement Range FontFlags"=dword:00000000
"ReSharper Current Line Foreground"=dword:00ffffff
"ReSharper Current Line Background"=dword:00313131
"ReSharper Current Line FontFlags"=dword:00000000
"ReSharper Matched Brace Foreground"=dword:01000000
"ReSharper Matched Brace Background"=dword:00ffff00
"ReSharper Matched Brace FontFlags"=dword:00000000
"ReSharper Method Identifier Foreground"=dword:008b8b00
"ReSharper Method Identifier Background"=dword:01000001
"ReSharper Method Identifier FontFlags"=dword:00000000
"ReSharper Operator Identifier Foreground"=dword:008b8b00
"ReSharper Operator Identifier Background"=dword:01000001
"ReSharper Operator Identifier FontFlags"=dword:00000000
"ReSharper Read Usage Foreground"=dword:01000000
"ReSharper Read Usage Background"=dword:00face87
"ReSharper Read Usage FontFlags"=dword:00000000
"ReSharper Usage Foreground"=dword:01000000
"ReSharper Usage Background"=dword:00face87
"ReSharper Usage FontFlags"=dword:00000000
"ReSharper Write Usage Foreground"=dword:01000000
"ReSharper Write Usage Background"=dword:00c1b6ff
"ReSharper Write Usage FontFlags"=dword:00000000
"String Foreground"=dword:0034cb65
"String Background"=dword:02000000
"String FontFlags"=dword:00000000
"XML Doc Comment Foreground"=dword:002cef10
"XML Doc Comment Background"=dword:02000000
"XML Doc Comment FontFlags"=dword:00000000

 

posted on Tuesday, March 20, 2007 12:39:43 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Tuesday, February 20, 2007

Unit Tests - They've got to be worth it

This is a re-hash of a post I wrote and 'lost' a while ago after I was reading Charlie Poole's first blog entry (from September 05) 'What's a test worth?', and found a hard-copy this morning.

It occurred to me (originally) that we tend to never remove unit tests as we have some strange and irrational fear that we should only ever move forwards with tests and the 'rainy day' tests should be retained as a 'just in case' safety net.  All this does of course is water down your test library for a number of reasons:

  1. The test library takes longer than is desired AND required to run
  2. Tests exist with a purpose that no-one's quite sure about and thus are more difficult to maintain and fix when something causes them to fail
  3. The test library cannot possibly be well defined and categorised due to point 2, leading to more developer and tester confusion

I therefore tried to give myself a small number of practical rules to follow when adding or maintaining unit tests.  Refactoring is something that applies equally to unit tests (and I don't just mean changes that stop your build from breaking when you change your functionality).

The question is 'What characteristics should a test display in order to avoid being deleted'

  1. If the test covers unique specific functionality (not covered in any other test) in a contained and specific way, sets up its own data and tears it down whilst making a number of useful assertions, and tests logic 'not' data - it should stay
  2. If the test duplicates other coverage, but also covers something else at a higher level - i.e. more of a system test - it may also still be of some use.  If the new functionality is at the same logical level as that already covered, then it's probably an indicator that some refactoring should be undertaken to allow that to be specifically unit-tested (that's not very clear but hopefully you get what I mean)
  3. We're clutching at straws now, but if the test does 'anything' useful at all (that's not been done in another test), then it may still be a good 'catcher' for some other high-level scenarios - you'd probably want to re-categorise the test at least in this case.

If you can't place the test in any of the 3 above then you need to do one or more of the following

    1. Remove the test
    2. Refactor the functionality you're testing
    3. Improve the test so that there is a specific and unique purpose

I'll try and add to and refine this over time, but for now there's my starting point.

posted on Tuesday, February 20, 2007 9:26:39 AM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Sunday, February 18, 2007

Ant Problems (Nothing to do with builds)

I've got ant problems - lots of 'em - coming from every orifice (in my house).  Googling for some 'intelligence' on how the little blighters' minds work so I might better exterminate them I stopped for a moment when I read this heartening tale about the guts and determination of the average ant...

http://www.adventurejournalist.com/notebook/archives/001005.html

I then promptly moved on and started looking for more and ingenious ways to get rid of them for good so I wouldn't have to continually feel (slight) guilt whenever I squash one.

posted on Sunday, February 18, 2007 7:59:26 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Wednesday, January 31, 2007

Dynamic FTP Scripts

I seem to be getting back to basics at the moment with some of the things I'm doing - and didn't imagine myself having to get an automated FTP update working this week...

My objective was to 'get' files from a remote machine using a folder pattern consisting of the date in an 'yymmdd' format.  I'd forgotten that script files used with ftp (ftp -s:myscript.txt) are dumb text files, and if you want to 'get' from a dynamic location - or dynamic filenames you need to magic something up.

My interest was sparked here, and although I found a C# FTP library on CodeProject that would clearly do the job, and would be cool to use in itself, I was more interested in using 'old skool' lo-tech methods to solve the problem.

I read one article that suggested using batch files to spit out the ftp script.  Excellent idea I thought - so this is what I ended up with.... (I've changed a few details to protect the innocent so if it doesn't quite work it's only due to my own typo :-) )

I won't explain each bit as that would spoil the fun - but the general gist is that FTPReportsForDate is normally run without parameters and it finds files in a specific folder and renames them on the local host.  The process also does other stuff I didn't have time to go into....

FTPReportsForDate.cmd (which accepts a parameter or gets current date if not supplied)

@echo off

echo Creating Log Folder
IF NOT EXIST C:\logs\FTP\ md c:\logs\FTP

echo Removing previous processing date
IF EXIST processingdate.txt del processingdate.txt /F

IF "%1" == "" (
 echo Getting current processing date
 cscript //NoLogo GetCurrentDate.vbs >> processingdate.txt
 echo Transferring File
 FOR /F %%f in (processingdate.txt) do CALL FTPCommand.cmd %%f
)

IF "%1" NEQ == "" (
 echo Transferring File
 CALL FTPCommand.cmd %1
)

FTPCommand.cmd  This constructs the FTP script file and does the FTP itself...

IF EXIST FTPLatestFile.txt del FTPLatestFile.txt /F

Type FTPHeader.txt >> FTPLatestFile.txt
echo cd RP%1.IN >> FTPLatestFile.txt
echo get staticfilename.fil dyn%1.fil >> FTPLatestFile.txt
echo close >> FTPLatestFile.txt
echo bye >> FTPLatestFile.txt

ftp -s:FTPLatestFile.txt >> c:\logs\ftp\transfer_%1.log

FTPHeader.txt This contains the static information used in the FTP script

open 192.168.0.1
myftpuser
myftppwd
prompt
lcd c:\incoming


GetCurrentDate.vbs
gets current date in a yymmdd format in the event we don't pass in a date to FTPReportsForDate.cmd

'Simple script to output todays date in yymmdd format for FTP processing

Function pd(n, totalDigits)
 if totalDigits > len(n) then
  pd = String(totalDigits-len(n),"0") & n
 else
  pd = n
 end if
End Function

Wscript.echo pd(RIGHT(YEAR(date()),2),2) & pd(MONTH(date()),2) & pd(DAY(date()),2)
Wscript.echo
        

posted on Wednesday, January 31, 2007 4:51:13 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Monday, January 29, 2007

SQL Server Tips - Optional Parameters and Find Closest Match

It's funny how you can survive for years not knowing some really simple stuff.  I learned two useful things last week.  For instance...

Optional SQL Parameters

To have an 'optional' parameter in a SQL 'search' Stored Proc you'd often declare a parameter thus...

@MyParam VARCHAR(20) = NULL --to denote that we want to ignore this param

and you'd probably

  1. have some convaluted logic to possibly build dynamic SQL around whether to factor the parameter into your query
  2. build some nasty 'like' clause that defaults to '%'
  3. derive MIN and MAX values from the input parameter and use a BETWEEN
  4. use a 'magic value' in place of your NULL to denote 'ignore'
  5. something else equally ugly I've not considered

...or (assuming this parameter is expecting to do a direct match) you could just simply do

WHERE @MyParam = ISNULL(@MyParam, MyFieldIWantToMatch)

This will ensure if your field is nulled out it just does a simple (IF 1 = 1) type thing.

 

Find Closest Match

I had a need to find the closest match to a particular value within a 10% tolerance +-.  The following does that fairly simply (I did nick the idea from thescripts.com) but these sorts of things do avoid the need for nasty tempdb use with temp tables...

The following is an example - so don't think I design tables with one column!

DECLARE @Amount INT

SET @Amount = 50

DECLARE @MinAmount INT
DECLARE @MaxAmount INT

SET @MinAmount = @Amount * 0.9
SET @MaxAmount = @Amount * 1.1

SELECT  AT.Amount
FROM AT.AmountTable AT
WHERE Amount BETWEEN @MinAmount AND @MaxAmount --within range
ORDER BY ABS(@Amount - AT.Amount) ASC --Nifty 'closest' match

You can then take the first row in your result set to be the closest match.

 

posted on Monday, January 29, 2007 3:52:05 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Thursday, January 25, 2007

Using Batch Build in Visual Studio

This is a really simple one, but if you want to build a solution in a specific 'Configuration' and you have a big solution open, it can sometimes be an awfully long time to switch configurations - e.g. Debug -> Release.  You may find yourself needing to do this when you're needing to build and rebuild setup projects whilst testing.

You could of course run a command line compile, but a simple way to stay in the IDE and Debug configuration whilst running a Release build is the Batch Build facility. 

Just go to Build --> Batch Build, then select all the Release versions of the projects you want to build (or whatever you want to build), and then click Build.  The settings will be remembered for the next time you go in too...

I said it was simple. 

posted on Thursday, January 25, 2007 9:52:30 AM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]
# Thursday, January 18, 2007

Beware the unseen checkout in Visual Studio Setup Projects

I was inadvertently responsible for a broken build this morning as I checked out a Setup Project last night in Visual Studio 2003 that ended up checking out a merge module that was included in the Setup.  This merge module is built and subsequently stored in SourceSafe (I know - it shouldn't be! - this is a temporary measure) by the build script, and the build failed as the .msm output file was checked out to me.
 
Shouldn't Visual Studio prompt you when you check out?
The project was checked out in Visual Studio and it gave no warning that the .msm was also going to be checked out.
 
In other setup projects you'll often find that other files will appear in the Check Out dialog (i.e. you're about to check  out all the 'files' that have been explicitly included into your setup - from their source location).  As a matter of course it's wise to first untick everything (right at the top), and then select only the .vdproj file to actually check out.
 
Why didn't it prompt in this case?
The problem in this case appears to be that the offender is a merge module and was added to the setup project as such rather than as an included 'file'.  It seems that Visual Studio neglects to mention merge modules when you check out as it probably thinks they're static and not something it should worry you about! (which is probably true - yadayadayada)
 
How to prevent this happening to you
Well, while this file is still in VSS there's little option but to just be vigilant whenever you check out a setup project that includes it. Either check out in VSS Explorer or if in Visual Studio -go immediately to VSS and undo the offending checkout.  Another option is to add some more resilience into the build and somehow force an undo-checkout (as no one other than the build should be updating the file).  A variation of this is to disallow checkout for all but the user running the build process through SourceSafe Admin (but this is a pain to administer), and the final and best solution is to remove the need to store the merge module in Source Control by sorting out cross-dependencies in different components so that they all pick the file up from the same central location.
 
 
posted on Thursday, January 18, 2007 9:18:27 PM (AUS Eastern Daylight Time, UTC+11:00)  #    Comments [0]