Sexy New Version: TimeSnapper 2.1, we finally grow up

TimeSnapper 2.1

In the last few days we've slipped out the new version of TimeSnapper, number 2.1, and it's a big jump.

First a wrap up of the new features, then a quick chat about the philosophy of being a Micro-ISV, and so on.

New Features In A Nutshell

New Look n Feel. Here's the new main form:

so attractive you are not afraid to show your friends

I'm sure you'll agree, it's lightyears ahead of the old front screen:

version 2.0

Now Includes a Breakdown of your time

Crucially, you can now view (and export) a breakdown of how your time was spent, thanks to a very versatile grid:

version 2.1 Activity Grid

(We've planned to have a form like this since the very start, and we've rewritten it three times to come up with something good enough to satisfy)

Now, in the 'Day Browser' you can select, and update a "range" of snapshots (rather than just selecting one at a time)

version 2.1 Activity Grid

This is a pretty powerful feature in itself, and we'll be doing more with this in future versions.

Oh, download it, by all means.

There's also a number of little features added specifically to tie in with specific needs of specific customers. We like nothing more than a specific customer and will always do what we can to help.

Okay -- that's it for the professional summary (did you register your copy yet?) now for the discussion.

In fact -- executive decision -- i'll post the next bit as a blog entry all of its own.

 

How To Be A Couple Of Micro-ISV People On Opposite Sides of the World

maybe the ui could do with some review...

This is a follow up to the previous article about the new version of TimeSnapper... this is more the inside Micro-ISV story...

My co-TimeSnapper-er, Atli Björgvin Oddsson, has put in many long hours getting this one to the place we were aiming for. We're now fulfilling a good number of the aims we wanted with the TimeSnapper product. There's still a lot of room to move but this one is taking us a long way further down our path.

The inside story behind 'Atli re-wrote the main form' -- okay okay, the main form was a bit too reminiscent of this famous and well regarded cartoon about UI. So, I rewrote the main form. And boy did it suck. Much worse than the original. But, i think history will show that it was a good form of suckiness, as it was so bad that Atli immediately had to delete it and come up with something much better. There's a lesson there, yes? Something like this:

Inspire action amongst your comrades by being a model to avoid

But on to other things...

One of the grooviest changes is that Atli moved us onto the dazzling nullsoft installer, instead of the woeful microsoft installer.

It's bewildering that nullsoft provide a free installer so far in front of the microsoft installer. I haven't personally grappled with how the nullsoft installer works: i just know that it was originally built as an installer for WinAmp, and grew from there. The Microsoft Installer (if you're using the standard off-the-shelf visual studio installer project) is woefully inadequate. As a show-stopping example of a sad installer product, you can't configure it to run the product immediately after install. WTF!? I know that, as a user, when I download some new tool off the internet I must run it straight away. If i don't run it straight away, i'll forget to run it ever

...anyway.

The philosophy behind this release, as a Micro-ISV, was that we'd add "Just One New Feature", a simple feature, and get the release out quickly. You know: we wanna be agile, we wanna be slick, we wanna be Web 2.0 and all that. The feature was going to be the 'Activity Grid' -- so that you could view (and export) a breakdown of how your day was spent.

The 'Just One New Feature' philosophy is a clever one... okay the reason I like it is because I invented it... but it didn't turn out to be so simple. The philosophy immediately expanded into 'Just One New Feature! Plus any bug fixes that arise' which seemed like a necessary improvement. But in no time the true philosophy became 'Just One New Feature! Plus any bug fixes that arise, and can't i just slip in one other feature, pretty please because it's way cool and i think it's going to improve things no end and anyway I'm on holidays at the moment and I am too, and both Atli and Leon have babies on the way due early next year, how cool is that, and actually, we ought to obfuscate the code too, cause some hacker dude wrote to us and told us we were idiots.' So that's our official, final philosophy. Just to repeat it, in big letters:

Just One New Feature*

* plus any bug fixes that arise, and can't i just slip in one other feature, pretty please because it's way cool and i think it's going to improve things no end and anyway I'm on holidays at the moment and I am too, and both Atli and Leon have babies on the way due early next year, how cool is that, and actually, we ought to obfuscate the code too, cause some hacker dude wrote to us and told us we were idiots.

So the Just One New Feature plan blew out a little bit... and I confess there was a little bit of 'oops, Leon made a mistake in the source code repository...' that I can only attribute to a bad week, but you get that anytime you make the fool hardy mistake of letting me near a source code respository... so we recovered. But the 2.1 product itself is quite nice, so i hope it pleases. Go on, buy the sucker, or at least download it.

Anyway, I plan to do more writing about the whole 'Micro-ISV' topic, since it's a big part of my life now -- unless you object. Maybe a 3-minute guide to being a micro isv, eh?

Well, thank you, good people. Good night.

Leon and Atli.

 

Passwords in Sql Server 2000 are Case Insensitive by default -- WTF?

Whereas, in SQL server 2005, Passwords are always case sensitive -- a seemingly more sensible default. But, infact, in SQL Server 2005, you can't even force it to allow case-insensitive passwords.

Good, you may think. SQL Server 2005 has done The Right Thing. Passwords should always be case-sensitive, this is dictate of law etc. But no -- if you want to be able to smoothly upgrade from SQL Server 2000 to SQL Server 2005, you need them to be capable of behaving the same.

It's great that SQL Server 2005 is 'secure by design' and 'secure by default' -- but we live in the 'real world' where we don't control every aspect of the systems we work with.

For example, the following scenario has just trapped a client of mine:

They have legacy applications with hard-coded passwords embedded in them. The hardcoded passwords are unfortunately in a differing case in differing legacy applications.

So now the upgrade path from SQL Server 2000 to SQL Server 2005 involves rewriting these legacy applications, even though, from the businesses point of view the legacy applications are working perfectly.

At first I swore and blamed the idiot developers who emdedded hard-coded passwords, in the old applications. Then I swore and blamed them for setting the wrong case. Then I swore and blamed SQL Server 2000 for ever allowing case-insensitivity in passwords in the first place.

(aside: WTF were earlier database devs doing allowing case-insensitive passwords by default?? I, for one, never realised that case doesn't matter in sql server 2K passwords. This depends on the case-sensitivity of your collation by the way (but since it's case-insensitive by default i expect most servers will have case-insensitive passwords). I think that sybase -- the mother product -- is case-Sensitive by default, so in order to assign blame we don't have to go back to sybase, the blame lies with microsoft.)

But all those things are in the past: they are not new suprises:

The legacy of idiot programmers and insecure databases is part of the landscape that a modern system must cater for.

The real shortcoming here is SQL server 2005. It's supposed to provide true 'SQL Server 2000' compatibity. Yet there was a case where that compatability is broken.

The solution in this case was to rewrite some of legacy apps, this time with an improved configuration model, and in other cases to hunt down the source code, fix the passwords and redeploy. It was an unexpected cost of the upgrade process, discovered very late in the game.

Things are back on track now, and overall the upgrade process was super-smooth. And shiny, very shiny. SQL Server 2005 is pretty much a thing of joy and a treasure to behold. But I'm still thinking about idiot programmers:

It's an idiot's world, we just live here.

 

Never Pay For Application Development Services Again

Design: Free
Implementation: $5
Working System: Priceless

Part A:

  1. Find an IT company willing to write a detailed quote for free.
  2. Bully them until they either drop their price to $5, or they quit revising the quote.
  3. If the IT company quits, then find another IT company, get them to write a 'more detailed' quote, based on the previous quote.
  4. If the result is good enough to begin implementation, move on to part B.
  5. Otherwise, back to step 2.

Part B:

  1. Rename the quote document to 'detailed design'
  2. Find an IT company willing to mock up a prototype based on the detailed design.
  3. They should be willing to do this for free based on loose promises about a highly-paid implementation and deployment scenario. Other fantasies can be used to deceive.
  4. If, despite all your best fairy tale stories, the IT company is not willing to do the prototype for free -- go to step 2.
  5. If the prototype is good enough, put it into production. End.
  6. Otherwise, find an IT company willing to 'take a look at a few bugs' in a prototype you've got.
  7. They should be willing to do this for free based on loose promises about a highly-paid implementation and deployment scenario. Other fantasies can be used to deceive.
  8. If, despite all your best fairy tale stories, the IT company is not willing to 'take a look at' (ie. resolve) the bugs for free -- go to step 6.

Part C:

  1. Burn any invoices that show up.
  2. Remove finger prints.
  3. Delete emails.

Sometimes I feel that every engagement I've ever done is a variation on this theme.

Sometimes I think that I'm just looking at the same buggy code that passed my desk years ago.

It's been refactored, upgraded, downsized, deployed, reverse-engineered, obfuscated and reflected so many times that i barely recognise it, but no... it's the very same code...

i recognise the way the loops inside the loops call the loops outside the loops...

i recognise the way the validation code is duplicated in every form...

i recognise the way the embedded sql gets the buffer overrun to generate the javascript...

it's changed in so many ways, but the flavor is the same...

i've seen this thing before i just know it...

maybe i'll fix just one bug, then pass it on...


(back from holiday ;-) )

 

Quiz Show for John

my Sister-In-Law, Brother, and Sister, on the set of temptation

Hey groovers, particularly those in Australia, be sure to watch the television show 'Temptation' (aka 'The new sale of the century') this week, as my brother John will be a contestant on the show this Thursday. And of course if he wins he'll appear on subsequent shows until he is defeated, takes the money and runs, or is arrested for cheating.

John has always been a legendary quiz master within our family. When he was maybe eight years old, he was faster and more knowledgeable than all the adult contestants in the show. I thought then that if they allowed kids to compete against the adults, he'd be sure to become a champion. This week we'll find out if the intervening years have enhanced or depleted his childhood genius. ;-).

Long time readers may recall that, last year, John's wife Al went on the same quiz show. Al did well but was trumped in the fast money. The highlight (for an irony lover like me) was when Al won a 'Who Am I' question, with the answer 'Germaine Greer' (outspoken feminist) and received a cosmetics package as a prize. This was sort of the equivalent of winning a hand gun after answering 'Mahatma Ganhi'.

So Thursday and beyond -- watch for John on channel 9, 7pm.

(By the way, the photo is of my Sister in Law, Allison, my brother John, and my sister Jody. Allison and Jody are both due to have babies in the near future. Another generation of contestants in quiz shows, no doubt.)

 

On The Importance of Whitespace

 

Cheers Simon.

 

Reasons for a headache

  1. Eye Strain
  2. Sleep deprivation
  3. Physical Exhaustion
  4. Neck tension
  5. Jaw tension
  6. Neural Tension
  7. Stress
  8. Constipation
  9. Hunger/ Low bloog glucose
  10. Virus / Fever
  11. Toothache
  12. Sinus pressure
  13. Ear infection
  14. Caffeine withdrawal
  15. Hangover
  16. brain parasite
  17. brain tumour or absess
  18. ate too much ice-cream!

Okay, okay. It was the ice-cream.

 

Whose Month is it anyway?

Is November really Powershell month? Is it MOvember (the month when we all men grow a moustache to raise discussions on male cancer)? Or is it National Novel Writing Month (NaNoWriMo) ?

Novemeber is officially 'Month' Month, the month that is traditionally dedicated to something or other.

I know November has arrived when the traffic suddenly jumps up for a page I wrote at the dawn of this blog, titled 'How to write a novel'. Although that page is basically a list of all the mistakes i've made when trying to write in the past, I get a steady flow of emails telling me that my techniques are great and have worked well for other people. I wonder if Roedy Green gets fan mail thanking him for the great tips on programming?

 

Your Next Action is: Download NextAction!

Next Action

The Top Of Your Mind Is A Very Very Small Place.

And NextAction -- is a Very Very Small application to manage the top of your mind.

It boasts less features than any other self-management tool.

Hence it is more effective.

There is no configuration -- NONE! and not even a save button. Saving and loading happen automatically.

Next action is always on top, and always out of the way. It only has one purpose: to help you track what you are doing right now, and to keep this at the top of your mind.

It's from the team that brought you TimeSnapper and it is free.

Download NextAction Download NextAction!

Enjoy!

Bugs, help requests, ideas... send em in...

 

NextAction in Action

 

 

A Very Simple .net Model View Controller

MVC. Model View Controller. Ahhh. One of those pattern things that your java kids are fond of. And now getting a lot of love from the RoR crowd.

From what I can tell so far, one of the main historical uses of MVC is to give dull people something to argue about.

"No no -- that's not pure MVC! If you go back to page 97 of GoF..."

And yet... I'm intrigued. The promise is nice.

I haven't found any simple examples using MVC for a .net application. So I'll give it a go. And it will be bad and you will tell me how to improve it ;-)

It's the view/controller bit that I'm a little mixed up with.

First, here's my architecture (notice the small 'a' in architecture... )

View a windows form in this example /\ || \/ Controller class that co-ordinates between Model and View /\ || \/ Model Your business object, an 'AppUser' in this example

Have I gone off the track yet?

Principles

  • No 'business rules' in the view.
  • The view in fact knows nothing about the model.
  • The 'model' knows nothing about the view.
  • The less code in the view, the better.
  • The controller doesn't care whether the view is a web form or a windows form.

Before I show you this approach -- let me point out that i'm not advocating it -- i'm just throwing it out there, to see what problems you've got with it.

Okay so inside our Login form, we have this variable:

    Private WithEvents m_LoginController As New LoginController

So, the Login Form has a member variable of type LoginController and as it happens we've declared that we're interested in events that this object might raise (i.e. 'WithEvents') (we'll see the reasons for this soon enough).

(Question: Should we have one controller for each form, like i'm doing here? or one controller for the whole app? If we have one controller for each form, then our view platform is dictacting the structure of our control -- since the type of viewing platform will determine the optimal complexity of a single form. Never mind... Let's make it one controller per form and see if anyone complains.)

Okay when the Login button is clicked we tell the controller.

 

    Private Sub btnLogin_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnLogin.Click

        'The view doesn't know what a user is!

        'The view doesn't know how passwords are validated...

        'It just **looks pretty** and **does what it's told!**

        m_LoginController.Login(txtUserName.Text, txtPassword.Text)

    End Sub

The login controller is notified.

And that's all the code we have in any event handlers from our controls. Seem easy.

Now what happens inside this Login Controller?

Okay -- so this login controller is going to have to talk to "the model". I figure the model contains my business objects: in this case there's probably a "User" class of some sort. Let's say that there's a class called AppUser and it's in a namespace called Model.

    Public Class LoginController

 

        'The controller knows what's happening on the view... but doesn't know the

        'names of the controls... or anything about the way the thing looks.

        Public Sub Login(ByVal Username As String, ByVal Password As String)

            'The controller knows a bit about the back-end.. the 'model'

            Dim currentUser As New Model.AppUser

            Dim result As Boolean = currentUser.Login(Username, Password)

            '!! Somehow notify the View!!

        End Sub

 

    End Class

The Login controller also has to talk back to the view somehow: and for this rambling demo I've chosen to use "events". We can notify the view that something has happened...

    Public Class LoginController

 

        Public Event LoginFailure(ByVal Message As String)

        Public Event LoginSuccess(ByVal Name As String)

 

        Public Sub Login(ByVal Username As String, ByVal Password As String)

            Dim currentUser As New Model.AppUser

            Dim result As Boolean = currentUser.Login(Username, Password)

            If Not result Then

                '!! Use events to communicate with the view.

                RaiseEvent LoginFailure("Login failed")

            Else

                RaiseEvent LoginSuccess(currentUser.Name)

            End If

        End Sub

 

    End Class

Now back in the windows form, we have handlers for the events raised by the Controller.

    Private Sub ShowLoginFailure(ByVal Message As String) _

            Handles m_LoginController.LoginFailure

        'Clear the password field.       

        txtPassword.Text = ""

        'Display the failure message

        lblMessage.Text = Message

        'Set focus to the username control

        txtUserName.Focus()

    End Sub

 

    Private Sub ShowLoginSuccess(ByVal Name As String) _

            Handles m_LoginController.LoginSuccess

        'Notice that the view has decided not to do anything with the 'Name' parameter.

        'The view gets to make all the visual decisions

        Me.DialogResult = DialogResult.OK

        Me.Close()

    End Sub

Now I've got a bunch of problems with the above implementation. It seems over-engineered, adds extra code for little benefit.

Am i doing it wrong? Thinking about it wrong? Or both?

What do you see?