harriyott.com

Thursday, July 20, 2006

Stewart left a comment on my post about enabling the "Leave this file?" button in SourceSafe, requesting the source code. It's quite simple, and here it is:

namespace Harriyott.SourceSafeLeaveEnable

{

    public partial class MainForm : Form

    {

        [DllImport("User32.dll")]

        public static extern Int32 FindWindow(String lpClassName, String lpWindowName);

        [DllImport("user32.dll", EntryPoint = "SendMessage")]

        public static extern int SendMessage(IntPtr hWnd, int Msg, int wParam, int lParam);

        [DllImport("User32.dll")]

        public static extern int FindWindowEx(int hwndParent, int hwndChildAfter, string strClassName, string strWindowName);

        [DllImport("user32.dll")]

        static extern bool EnableWindow(IntPtr hWnd, bool bEnable);

 

        public MainForm()

        {

            InitializeComponent();

        }

 

        private void btnEnable_Click(object sender, EventArgs e)

        {

            // Find the prompt window

            int windowHandle = FindWindow(null, "WindowsForms10.Window.8.app.0.11ecf05");

            if (windowHandle > 0)

            {

                // Find the radio button

                int leaveHandle = FindWindowEx(windowHandle, 0, "Button", "&Leave this file?");

                if (leaveHandle > 0)

                {

                    EnableWindow((IntPtr)leaveHandle, true);

                    lblStatus.Text = "Enabled";

                }

                else

                {

                    lblStatus.Text = "Cannot find the 'Leave this file?' control";

                }

            }

            else

            {

                lblStatus.Text = "Cannot find the prompt window";

            }

        }

    }

}



[Tags: ]

Monday, July 17, 2006

The three half-generations of computer users

I'm having an interesting reminisce with Helen on IM, part of which I'll quote. She said:

You're from the "I learnt to program on a computer who you fed program in using an audio tape" generation. I'm from the "I discovered the internet and suddenly the computer was really, really interesting" generation. My workmate is from the "yeah.. the internet.. haven't they always had that?" generation


Quite.

Saturday, July 08, 2006

I've met Robert Scoble...

I've met Robert Scoble cartoon

SourceSafe can't leave well alone

So the RTM version of SourceSafe has a irritating "feature". When getting the latest version of a directory, if you have a writeable version of a file, SourceSafe offers two options: overwrite it with the checked in version, or check out the file.

Before screen shot

I want to do neither. I would like to just leave it as it is, and move on. The dialog has even has the option there to leave it, but it is tantalisingly disabled. If only I could enable it. If only..

Well, it turns out that I could. I had to write a little app to do it, but it does it. This app has a single button: "Enable Leave Button". It locates the radio button on the dialog, and enables it. I can then click the radio button, and click and OK, and it does actually leave the file alone. It doesn't overwrite the file; it doesn't check it out.

So here's what the dialog looks like after clicking the "Enable Leave Button" button:

Before screen shot

Fantastic. I love being a geek. I've made this little app available for you to download from here, if you have this problem too. I've got some plans for it, but it works at the moment. You'll need the .NET framework version 2.0, which I assume you'll have, as you probably installed it with the offending version of SourceSafe.

[Update: I've posted the source code.]

[Tags: ]

Friday, July 07, 2006

Geek dinner - Chris Anderson

Another great London geek dinner, with special guest, Chris Anderson of Wired magazine, who created the long tail concept. There were about 90 guests in attendance, much more than expected, so the small room we were in got very hot, and we all went outside. Fortunately I sat near the front, so I could hear every word; those at the back weren't so lucky. I think everyone heard Ryan though!

The best quote of the night came right at the end: "Insurgency is the long tail of war".

Photo of Chris Anderson

Tom Morris and Ian Forrester suggested that the next Sussex geek dinner should be in Brighton - Ian had the great idea of holding it at the same time as d.Construct. Good idea; I'll follow that up.

Big thanks to Ian for organising it. He puts so much effort into it. He didn't eat anything the whole evening, until after 10pm when he found a small bowl of feta cheese.

I took my tablet PC with me, as I went on the train. I've never used a laptop on a train before, and it's great. I'm writing this on the way back to Tunbridge Wells. When I get home, I'll post it. In the past, I couldn't start typing until I got home.

[Tags: ]

Thursday, July 06, 2006

A new refactoring please

I use the built-in refactoring in Visual Studio for my C# code. I often use "Extract Method" to cut out a chunk of code from the middle of a growing method. This creates a new method under the original, moves the selected code into the new method, and replaces it with a call to the new method, working out what the parameters should be.

So, this contrived example:

        public void HaveAGoIfYouThinkYoureHardEnough(Person queueJumper)

        {

            bool hardEnough;

            int currentHardness = 0;

            if (queueJumper.Height >= 6)

            {

                currentHardness += 2;

            }

            if (queueJumper.Weight >= 14)

            {

                currentHardness += 3;

            }

            if (queueJumper.Weight >= 18)

            {

                currentHardness += 2;

            }

            if (queueJumper.Weight <= 8)

            {

                currentHardness -= 4;

            }

            if (queueJumper.ScarCount > 2)

            {

                currentHardness += 1;

            }

            if (currentHardness > 5)

            {

                hardEnough = true;

            }

            else

            {

                hardEnough = false;

            }

            if (hardEnough)

            {

                LetHimHaveAGo(queueJumper);

            }

        }



becomes

        public void HaveAGoIfYouThinkYoureHardEnough(Person queueJumper)

        {

            bool hardEnough;

            int currentHardness = 0;

            currentHardness = AddHeightHardness(queueJumper, currentHardness);

            currentHardness = AddWeightHardness(queueJumper, currentHardness);

            currentHardness = AddScarHardness(queueJumper, currentHardness);

            hardEnough = IsHardEnough(currentHardness);

            if (hardEnough)

            {

                LetHimHaveAGo(queueJumper);

            }

        }

 

        private static bool IsHardEnough(int currentHardness)

        {

            bool hardEnough;

            if (currentHardness > 5)

            {

                hardEnough = true;

            }

            else

            {

                hardEnough = false;

            }

            return hardEnough;

        }

 

        private static int AddScarHardness(Person queueJumper, int currentHardness)

        {

            if (queueJumper.ScarCount > 2)

            {

                currentHardness += 1;

            }

            return currentHardness;

        }

 

        private static int AddWeightHardness(Person queueJumper, int currentHardness)

        {

            if (queueJumper.Weight >= 14)

            {

                currentHardness += 3;

            }

            if (queueJumper.Weight >= 18)

            {

                currentHardness += 2;

            }

            if (queueJumper.Weight <= 8)

            {

                currentHardness -= 4;

            }

            return currentHardness;

        }

 

        private static int AddHeightHardness(Person queueJumper, int currentHardness)

        {

            if (queueJumper.Height >= 6)

            {

                currentHardness += 2;

            }

            return currentHardness;

        }



So I've added four more methods to make the first method smaller. Mostly, this type of new method will not be used by any other method, as I extract them for readability, not functionality.

If this main method (and it's four extracted methods) was called from an even mainer method, which did something else, then the two main methods (which originally were adjacent) become separated:

        public void GetIntoNightClub()

        {

            HaveAGoIfYouThinkYoureHardEnough(new Person("John Prescott"));

            WillTheBouncerLetMeIn();

        }



After refactoring, HaveAGoIfYouThinkYoureHardEnough and WillTheBouncerLetMeIn now have four methods between them.

I generally don't want to see these four methods again, and as I've made the method names self-commenting, I won't need to refer to them unless there's a bug. As there's only four static methods, and they're related to the existing method, creating a new class for them is probably not the right way to go.

Therefore, I propose two new refactorings. The first, and easiest, would be to add a region under the main method, which contains the extracted methods:

        #region Methods extracted from HaveAGoIfYouThinkYoureHardEnough

        // ...

        #endregion



Let's call this "Extract method to region". The region can be collapsed, and both main methods are visible at once.

The second refactoring would be to shuffle the methods off to another file, using the cunning partial class feature of C#. Let's call this "Extract method to new file". The file will be called <ClassName>_HaveAGoIfYouThinkYoureHardEnough.cs, so it's easy to see in the solution explorer what the file contains. Obviously the "Rename" refactoring would have some extra work to do here.

So, Visual Studio refactor team, please get to work...

How CodeSmith spreads

I first found out about CodeSmith from reading Mike Gunderloy's excellent Coder To Developer. I introduced it to my colleagues, and one of them showed it to their partner, a web designer.

The web designer, being into design, would rather not have to write SQL for the admin functionality, which goes into every website. CodeSmith to the rescue, saving 90% of the work.

I find this really pleasing, as I was the one who passed on the knowledge. Regular readers will know that I love making people's jobs easier by cutting out the monotonous tasks.

[Tags: ]

Tuesday, July 04, 2006

Spell checker for Flexwiki

FlexWiki has no spell checker included, but I've found an cunning way to add one: the Google toolbar.

Google toolbar

Next to the page rank, there's a spell checker button that spell checks form fields. Editing a flexwiki page is done in a really big form field, which the spell checker can check.

Obvious when you think about it.

[Tags: ]

Using using

Daniel Moth has been experimenting with using the "using" statement to perform common entry and exit code. The using statement calls the constructor of a class at the beginning, and Dispose() at the end. The before code (status bar and wait cursor in his example) goes in the constructor, and the after code goes in Dispose(). Clever trick.

I post this because Daniel finishes his post thinking the approach is "wrong" and asking for feedback, but doesn't seem to have comments enabled. I'll post my thoughts here instead.

I think it's quite neat, and as the original developer, there's one less thing to think about when doing something, which is always useful. The problem comes with maintainability. He mentions the problem that no memory management actually takes place, and the leap would have to be made to understand that. This would only come to light when looking at the class.

If the maintenance coder didn't look at the class, just the using statement, she would assume that there was some memory stuff going on, and wonder where the heck the status bar text was getting changed. Eventually she'd have to look at the class, and realise that the original coder was a blatant liar. "Hey punk, there's no memory management here!". From that point on, she trusts the original coder a whole lot less, and has to check more classes just to confirm that they do what they say they do.

In this (admittedly contrived) example, a better approach would be to explicitly state what the code was doing by using meaningful method names:

SetGuiWaiting();
DoTheThing();
SetGuiReady();

or

guiController.SetWaiting();
DoTheThing();
guiController.SetReady();

Now the maintainer can just read what's going on without having to visit the other code. Not quite as pleasing for the original developer, but a lot easier to maintain. Still, an interesting idea, and it's always worth experimenting with things like this.

As for a class with only a constructor and a Dispose(), I'm not bothered by that, if the abstraction requires nothing else.

[Tags: ]

Monday, July 03, 2006

Topic of conversation

It looks like there's going to be only one topic of conversation today - football. My team in the office sweepstake happens to be Portugal.

[Tags: ]