Sunday, March 29, 2009

Flash ain't so flash

I thought Microsoft SilverLight was just a rip-off of Adobe Flash, and so I wanted Flash to remain dominant.

I finally started learning Flash, and have decided it sucks compared to SilverLight.

Flash is great for creating pre-defined animations, but for programming complex dynamic animations, it has issues.

Worse yet, it's code editor is EXTREMELY hard to use.

And the ActionScript compiler even produces incorrect error messages.

All up, whilst a week ago I had high hopes of adding my own bit of momentum to the Flash technology, I am now inclined to believe that SilverLight will annihilate it, due if nothing else to vastly better development tools for complex programmatically-controlled animations.

So, for example, I wanted to accomplish the simple task of creating a button in Flash that, when clicked, would respond visually so I knew I was correctly handling the mouse click event.

I decided to make my button turn semi-transparent when clicked - just an elementary visual confirmation that my event handler fired.

I drew my button (an arrow) with the crappy drawing tools in Flash. (I see now why the average Flash artist would start in Illustrator, and only go to Flash once all their artwork was finished.)

I converted it to a symbol, and in the library, chose the "Button" type (instead of MovieClip or Graphic).

All should be well, or so I thought. I then proceeded to use the stock-standard ActionScript 3.0 Flash CS4 button event handling code :

function myHandler()
{
myButton.alpha = 0.1;
}
myButton.addEventHandler(MouseEvent.CLICK, myHandler);

Right off the bat, the editor is TERRIBLE. Microsoft has this thing called "Intellisense", that I just took for granted. But seeing that one of their chief rivals, namely Adobe, can't create something even half as good, makes me realise that Microsoft is actually quite good at creating code editors.

Oh - for sure - Flash has an "Intellisense" equivalent, but only if you declare a strongly-typed variable. But why should I have to do that? Flash already knows that "myButton" is a reference to that button on-screen, so why should I have to declare yet another variable just to get strong typing?

Anyhow, I dutifully do so :

var myStronglyTypedButtonReference:? = myButton;
function myHandler()
{
myStronglyTypedButtonReference.alpha = 0.1;
}
myStronglyTypedButtonReference.addEventHandler(MouseEvent.CLICK, myHandler);

Snag. What type to use?

Again, the code editor is crappy to the max.

Fortunately, there is a very-slow-to-use (no search functionality) class list on the left-hand-side of the editor. It is categorised, which means that whilst my intuition tells me I probably need to find a class called "Button", I need to search through package after package after package. Oh - at the very end there is an "Index" option, which I use. On my powerful computer, it still takes too many seconds to prepare the index, but I am finally rewarded. In the index I find a Button class, and it is in the fl.controls package.

var myStronglyTypedButtonReference:fl.controls.Button = myButton;
function myHandler()
{
myStronglyTypedButtonReference.alpha = 0.1;
}
myStronglyTypedButtonReference.addEventHandler(MouseEvent.CLICK, myHandler);

You'd think that would work. But no.

Flash now complains that "Type was not found or was not a compile-time constant: Button". Fat lot of good that is!

I search and search. The answer almost everyone gives is "just add a button to your stage then delete it straight away, and this will add the necessary library code to your project".

Ummm - but don't I already have a button on my stage? I mean, this arrow I drew is very definitely a button.

I add another copy of the arrow button from the Library to the ActionScript layer, just in case that will help, but the problem persists.

Prompted by one web page, I look at my class path, but that has nothing to do with the problem.

Finally, I find a web page that gives me the clue I need. Check out WarpZone's contribution here. Turns out you need to open the "Components" window, and drag a "Button" control from that "Components" window onto your stage.

So I do it.

And now Flash complains that it can't convert a SimpleButton to a Button!!!

Can I just say that this is really really really stupid. In SilverLight, it is quick & easy to determine the data type of any control on the "stage". But in Flash, it seems you have to just guess, then look for compiler error messages or runtime error messages that would indicate if you guessed wrong!

So I need to use "SimpleButton", not "Button".

var myStronglyTypedButtonReference:fl.controls.SimpleButton = myButton;
function myHandler()
{
myStronglyTypedButtonReference.alpha = 0.1;
}
myStronglyTypedButtonReference.addEventHandler(MouseEvent.CLICK, myHandler);

Problem : SimpleButton is not in the fl.controls package. Groan. Back to the Index. Oh - guess what - it's so dumb it hasn't cached the results of the last time I opened the index. So it spends way too much time once more opening the index.

But at least I can find SimpleButton without too much more pain. It lives in flash.display.

var myStronglyTypedButtonReference:flash.display.SimpleButton = myButton;
function myHandler()
{
myStronglyTypedButtonReference.alpha = 0.1;
}
myStronglyTypedButtonReference.addEventHandler(MouseEvent.CLICK, myHandler);

Extremely unintuitive so far! But surely I have arrived, no?

But no.

When I run, Flash tells me :

ArgumentError: Error #1063: Argument count mismatch on Untitled_fla::MainTimeline/myHandler(). Expected 0, got 1.

Wait a moment - expected ZERO, got ONE?

Adobe, do you know how to write compiler error messages?

My function takes ZERO arguments. If ZERO are expected, then things should work fine!

But, suspecting sloppiness on Adobe's part, I figure that they probably intended to say "expected ONE, got ZERO". So more searching on the web, and I find a code example that uses a single argument of type Object for event handlers. I try it, and at last it works :

var myStronglyTypedButtonReference:flash.display.SimpleButton = myButton;
function myHandler(eventObj:Object)
{
myStronglyTypedButtonReference.alpha = 0.1;
}
myStronglyTypedButtonReference.addEventHandler(MouseEvent.CLICK, myHandler);

Once again, were it SilverLight, it would have been much quicker & easier for me to identify which argument(s) are required for the event handler, and what data type each argument needs to be.

Oh - and SilverLight does at least tend to give ACCURATE error messages.

And this is just a small sliver of my Flash woes. It is horribly unintuitive.

Flash, I wanted to support you, to cheer you on in the race against Microsloth, but I am deeply shocked, saddened, and surprised to find that from a programmability perspective, Microsoft has already won the race. You suck.

I hope it doesn't stay this way.

UPDATE : Despite its many faults and failings, Flash can do really powerful things when you finally figure out how to do things. (It's the "finally figure out" process that Adobe has made waaay too hard.) So for example, here are two pages with EXCELLENT introductory information that has helped me immensely in my quest for complex dynamically-generated Flash animations :

Core Display Classes in Adobe Flash

How to use the Adobe Flash Drawing API at runtime

Monday, March 16, 2009

Bazaar - managing local feature branches with lightweight checkouts

Bazaar is the BEST source code versioning system in the world, or at least, the best non-commercial one (I can't comment on commercial ones except Visual SourceSafe, which epitomises dog-ness).

Well, that's my opinion, after using SVN and Visual SourceSafe, and reading fairly extensively about other systems.

But it can be hard to get started, just because it is SO powerful and has SO many options and can be used in SO many different ways.

If you're a single developer who just uses it to track their own work, and never makes feature branches, life is very simple.

bzr init
bzr add
bzr commit -m "My project is now in Bazaar! Woot, woot!"
... edit your project ...
bzr add
bzr commit -m "I just made edits to my project, and Bazaar has been updated accordingly."

It's really sweet. Suppose you ship a new version, and you want to be able to access the exact source code that was used in that version :

bzr tag "Released version 1.2.3"

And to review previous tags? Simple :

bzr tags

If you mucked up?

bzr revert

(Throws away your changes since the last commit.)

That's all very sweet and simple. (Sure beats SVN and Visual SourceSafe!!!!!!!!!!!!!!!)

But I wanted to use feature branches.

There are various ways to do it, but here's a simplified version of how I'm doing it, with great success :

Create a root development folder. For sake of demonstration, let's call it "src".

src> bzr init-repo --no-trees
src> md trunk
src> cd trunk
src\trunk> bzr init

At this point, you have a trunk, with nothing in it. Not much use, but press on...

src\trunk> cd..
src> md wt

Here, "wt" is an acronym I've chosen somewhat arbitrarily. It stands for "working tree". It's the only place I'm going to have a copy of the (often extensive) set of files in the project.

Get it?

Bazaar lets you have as many branches as you want, without clogging your hard disk! THAT is AWESOME!

Now any time you embark on a change, you can afford to do it in a branch. That keeps your work well organised, and means you don't end up stuck with half-finished changes in your trunk. Very nice!

Did I mention that Bazaar is the best source code versioning system in the world? :o)

Ah - but we're not done yet. It's still useless at this point. Press on...

src> cd wt
src\wt> bzr checkout ..\trunk --lightweight

Woot, woot! At this point, copy any existing files for the project into src\wt, then proceed.

src\wt> bzr add
src\wt> bzr commit -m "Initial commit, directly into trunk. After this point, we will work on branches, not on the trunk."

Extra wootness! Now we have a trunk, and a working tree, and we are ready to start branching.

src\wt> cd..
src> bzr branch trunk "Branch001 - completely revolutionise colour scheme"
src> bzr branch trunk "Branch002 - add new powerful print-preview system"
src> bzr branch trunk "Small changes"

Yep - you guessed it. If you think there's a reasonable chance you'll get stuck halfway through a set of changes, and not have them finished before you have to work on some other aspect of the source code, then that's a good candidate for a branch. But if it's a REALLY small change (e.g. update the copyright notice in a single file), no need to create a new branch just for that. You could conceivably make that change directly in the trunk (although I advise against it, for reasons that are beyond the scope of this article). My solution? I have a permanent branch called "Small changes", and that's where I make small changes! :o)

So now, let's start work!

src> cd wt
src\wt> bzr switch "..\Branch001 - completely revolutionise colour scheme"
src\wt> bzr revert

At this point, the working tree matches the contents of Branch001.

Start work on that colour scheme.

Oh no! The boss has walked in and said the new print-preview system has to take priority.

Gotta change to a different branch.

Easy done :

src\wt> bzr commit -m "These are my changes so far."
src\wt> bzr switch "..\Branch002 - add new powerful print-preview system"
src\wt> bzr revert

Voila! Now the working tree matches Branch002. Code away merrily...

In comes the accounts lady. "The last digit on the bank account number should be seven, not three."

This change should be done immediately. No point waiting two weeks for the new uber-funky print-preview system, nor five months for the new colour scheme to finally be done.

src\wt> bzr commit -m "Well, working on Branch002 was fun and all, but necessity demands my (temporary) departure."
src\wt> bzr switch "..\Small changes"
src\wt> bzr revert

Now fix that account number. And then proceed...

src\wt> bzr commit -m "Maggie informed me that the account number was incorrect. Fixed now."

Now, chances are, we want that change to go into the trunk right now. Let's do that.

A clue : BAZAAR IS NOT INTUITIVE WHEN IT COMES TO COMBINING FEATURE BRANCHES INTO THE TRUNK.

Oh - don't flame me. The problem is that most documentation talks about the 'bzr push" and "bzr pull" options.

But these will destroy everything. You'll lose the farm, the house, the boat...

There is a very simple rule to keep in mind when working on feature branches on your own computer :

bzr merge!!!!!!!

Yes - Bazaar's merging features are second-to-none. They are truly impressive.

So despite the myriad examples out there telling you to "bzr push" your changes to the central server - ignore it! Those instructions apply in certain common situations, but do not apply for our current purposes.

So here's how we get the latest changes from a branch into the trunk :

src\wt> bzr merge ..\trunk

That's the first step. Remember - whilst we've been busily working away on a branch, there might have been other branches committed to trunk. So the trunk we once knew is not necessarily the current trunk. We need to ensure that what we're about to commit to the trunk is compatible with the current version of the trunk.

And the way we do that is to first merge the latest changes from the TRUNK back into the current branch.

Having done that, we run our unit tests. If everything compiles and runs fine, we're happy chaps. If not, fix it! :o)

When we're happy with the merge :

src\wt> bzr commit -m "Merged with trunk"

Cool. So now we know that our changes in this branch are compatible with the trunk. That means it's safe to merge this branch into the trunk.

src\wt> bzr switch ..\trunk
src\wt> bzr revert
src\wt> bzr merge "..\Small changes"

There shouldn't be any conflicts or other problems at this point, because we already merged the trunk into our branch, and any problems should have been encountered then not now.

src\wt> bzr commit -m "Merged with branch 'Small changes'"

Woot, woot!

Oh - there's the boss again. I'd forgotten about the print preview. Better get back onto it :

src\wt> bzr switch "..\Branch002 - add new powerful print-preview system"
src\wt> bzr revert

Code away.

Oh no! I just discovered that the print preview cannot possibly work unless the account number is correct - but the account number was fixed in a different branch!

Not a problem.

src\wt> bzr merge "..\Small changes"
src\wt> bzr commit -m "Merged with branch 'Small changes'"

Ah - wonderful. Now the changes in the "Small changes" branch are also in Branch002.

What's better yet is that Bazaar is so smart that you can merge those two branches together as many times as you want, and Bazaar will keep a record of what has been previously merged and what hasn't been, so that you'll never have trouble with the one change being included multiple times!

THAT is POWERFUL.

In fact, suppose we made Branch003 for some purpose or other :

src\wt> cd..
src> bzr branch trunk Branch003
src> cd wt
src\wt> bzr switch ..\Branch003
src\wt> bzr revert

Suppose it adds some cool new features to our library of helper functions.

Suppose we finish with the branch :

src\wt> bzr merge ..\trunk
... compile and run unit tests ...
src\wt> bzr commit -m "Merged with trunk"
src\wt> bzr switch ..\trunk
src\wt> bzr revert
src\wt> bzr merge ..\Branch003
src\wt> bzr commit -m "Merged with Branch003"

At this point, Branch003, trunk, and "Small changes" ALL contain the account number change, and Branch003 and trunk both contain the new helper functions.

We don't need Branch003 any more, so we're going to switch away from it and delete it. (We could switch to any branch, but hey, for the time being, I'll switch to the trunk, 'coz I don't know where I'm going next.)

src\wt> bzr switch ..\trunk
src\wt> bzr revert
src\wt> rd ..\Branch003 /s
... and type "y" and Enter to confirm that you want to mercilessly annihilate Branch003.

Now, in some other source code versioning systems, you have to manually track which changes have been merged where. (Not mentioning any names... <cough - SVN> )

But with Bazaar, things just work, and they work perfectly!

We return to the print preview branch :

src\wt> bzr switch "..\Branch002 - add new powerful print-preview system"
src\wt> bzr revert

Oh - turns out we need those new helper functions.

If Branch003 still existed, we could get those new helper functions by merging it in to Branch002.

Or we can merge the trunk into Branch002.

But Bazaar is so cool, that it doesn't matter which one we do, or even if do both, or even if we do both multiple times! It just works!

src\wt> bzr merge ..\trunk
src\wt> bzr commit -m "Merged with trunk, to get those wonderful new helper functions."

So, merge is your friend.

See, because I grew up with Visual SourceSafe and SVN, "merge" had a negative connotation. I assumed that the change history, including the detailed comments I leave with every commit, would be marred by merging.

But with Bazaar, the history is preserved!

It's easy to prove :

src\wt> cd ..\trunk
src\trunk> bzr log

And now you get a nice big listing of all the changes that have happened. It doesn't matter how many times you merged, all changes and all commit messages are preserved.

THAT'S what I call a good source code versioning system (aka "revision control system").

So many branches and can't remember which one the working tree is currently bound to?

src\trunk> cd ..\wt
src\wt> bzr info

Ah! It tells us which branch we're bound to. Very nice.

Now, my setup is actually considerably more elaborate than this. I have multiple development machines that I switch between - one laptop for the road, and a much more powerful desktop that I prefer using when I can.

I wanted a "central trunk" from which I could run automated unit tests, and which could be my controlled release point. Plus, I have other developers help out here and there. So I really wanted a system that works this simply and this well, but works across multiple computers.

And I needed each computer to have its own "local trunk" so that the respective developers could branch away happily even when they were not connected to the internet and the central trunk.

So, in effect (although I accomplished it slightly differently), I have a folder called "central-trunk", on my controlled-release computer.

I have found that the Bazaar logs look nicest when you only have one level of indirection with merges. Since I like nice, readable logs, this is what I do :

I merge finished branches into the CENTRAL trunk, and I never delete a branch until I have merged it with that CENTRAL trunk (unless I'm abandoning the branch).

The LOCAL trunk exists ONLY TO ENSURE I CAN CREATE NEW LOCAL BRANCHES EASILY.

And to keep the local trunk in-sync with the central trunk, I run the following when connected :

src\trunk> bzr pull Z:\central-trunk

I NEVER merge or commit into my LOCAL trunk. If I'm working on two branches that need features from each other, I merge them into each other.

So basically there are three levels - the central trunk, the local trunk, and each feature branch.

The changes are "bzr pull"ed from the central trunk into the local trunk.

"bzr branch" from the local trunk creates local feature branches.

"bzr merge", NOT "bzr push", takes my local feature branch into the central trunk.

And "bzr merge" also handles inter-branch updates along the way.

-

Bazaar changed my programming life. It is a source code versioning system that works, and works brilliantly well, and isn't cumbersome. It is a pleasure to use. I enjoy the feeling of committing a change, and I enjoy merging a feature branch into the trunk. It feels like hammering another peg into the cliff face, as I climb the metaphorical cliff of whichever crazy software development endeavour I've embarked on. (And I usually embark on difficult ones! :o) )

It changed my life, even long before I started using feature branches. For a long time, I just used (and loved) the ability to track each version of the trunk, and tag releases.

Now with feature branches, things are even better again.

If I'd been given this information when I first found Bazaar, I would have accomplished more. Feature branches are a produtivity tool.

But the documentation was more focussed on contributing to open-source projects where you always branch directly off the head revision from a read-only URL somewhere, and where only specially-privileged people can commit to trunk. That's fine - that's a very powerful and very common use of Bazaar.

But it can do so much more! I hope in this article that I've helped some of you get up-to-speed with Bazaar in ways that will transform your programming life for the better.

Sunday, March 1, 2009

Beating the performance bogeys in the Intel SSDs

Intel changed the world forever with its new X25M and X18M SSDs.

But reports are circulating of major performance problems.

Everyone's puzzled, and Intel denies any performance problems at all.

What's the low-down?

It's simple, as far as I can tell.

First, let's review the kinds of problems being reported :

* Intel SSD is BLISTERINGLY fast when first installed, but after a few months, random write performance plummets.

* Testing the Intel SSD by hammering it with tiny random writes for even less than a few hours brings a brand-new SSD to its knees - write speeds lower than 10MB per second.

* Imaging a hard disk partition onto a brand-new Intel SSD, results in that SSD's write speed dropping to just a fraction of the advertised speed. (Search the linked page for 'All we did here was write the OS files')

You're not going to like this, but if you partition the drive - e.g. in half - and only ever use one of the two partitions, you won't see these problems.

Or at least, that's my bet, not actually owning one quite yet (although I've placed an order).

Can you see why?

The Intel SSD is so mind-bogglingly brilliant because it combines random writes into sequential writes. Others have already blogged about that very well, so I won't detail it here.

The problem is that the SSD doesn't know when virtual sectors are "available" again - it only knows which virtual sectors the operating system has ever written to.

If the operating system has EVER written to a virtual sector, the SSD controller studiously preserves the content of that virtual sector ever after, EVEN IF THE OPERATING SYSTEM LATER THINKS IT HAS DELETED FILES AND THAT THEREFORE THE SECTOR IS UNUSED AND AVAILABLE FOR RE-USE.

Thus, if you use the wrong imaging tool, and write an 80GB partition to your brand-new Intel SSD, BAM - as far as the SSD is concerned, you have 0% free space. Yup - your partition might have contained 60% free space, but if the imaging tool does a sector-by-sector copy of the source disk to the SSD, then the imaging tool will write to every virtual sector in the SSD, and the poor SSD controller will be left diligently trying to preserve the contents of empty sectors.

SO, the trick to ensuring that the Intel SSD controller has some "breathing space" in which to perform its magic, is to ensure you NEVER COMPLETELY FILL the SSD.

Sad, but true.

Yup - that means that if you fill your 80GB SSD with 80GB of data (whether test data for random write tests, or 80GB worth of your data files), then read speed will stay great (it does slow down, but you're not likely to notice without a performance monitoring tool), but write speed will plummet. The poor SSD controller won't be able to turn random writes into sequential writes, 'coz there's no free space!

Actually, there is free space - a tiny bit. See, apparently, the Intel SSD comes with a few GBs spare storage space beyond the advertised capacity.

Without this spare storage space "up its sleeve", the Intel SSD could, in worst-case performance scenarios, have random write speeds as abysmally low as say the OCZ Core V2 (which I am suffering with).

So by having more storage space available than it lets the computer directly use, the SSD controller always has a little bit of room to move - and that's why even when things go horribly pear shaped, the Intel SSD can still maintain a random write speed of well over 1 megabyte per second (reports vary up to even still around 20 megabytes per second) - which is WAY more than the competitors do from the very outset!!! (For comparison, my OCZ Core V2 120GB has a random write speed for 4kb blocks somewhere under, well, I'm not entirely sure, but I think less than 100 kilobytes per second - i.e. less than 0.1 megabytes per second.)

So let's take the case of the hardcore random-write test. We write a special program that randomly chooses any sector across the entire 80GB of the SSD, and writes just to that sector, and then chooses another randomly, and writes to that, and does so as fast as the SSD can handle it, for hours on end.

For the first 80GB-worth of random writes, it zooms along at the mind-boggling speed of 70MB per second or more.

But it quickly hits a wall. The SSD controller was attaining these astounding speeds by combining the random writes into sequential writes, but shortly after 80GB worth of writes, it runs out of unused sequential storage locations. (Remember that it has a bit of breathing room, but that gets used up quickly too...)

In this condition, the effort required to combine even just two random writes into one sequential write is multiplied. On the virgin drive, it could cram 2MB of random writes into each 2MB write block (or whatever write block size it actually uses - I pick 2MB for demonstration purposes, but the principle remains true whatever the actual write block size). But on the drive in this random-write-crammed-full condition, if there was no "breathing space" (additional storage space beyond what the host computer is aware of), then each 4 kilobyte (0.004 megabyte) random write would require an entire 2 megabyte write block to be written. That's a slowdown factor of 2 / 0.004 = 500!!!!!!! No wonder people report speed problems!

Of course, Intel was smart to include the "breathing space" - it ensures that the worst-case random write speed never actually gets as bad as that.

SO - what's a man to do?

The reality is, this problem is not as bothersome as you might think - if you know what triggers it and how to avoid it.

The simplest thing to do - and what I plan to do as soon as mine arrives - is to give it even a bit more breathing space than comes built-in.

e.g. partition it into 70GB + 10GB, and never touch the 10GB. That gives the controller an extra 10GB of "breathing space". In a more extreme case, if you - for example - chopped the drive in half, and kept 40GB in an untouched partition, where the SSD controller can have a huge amount of "breathing space", then you should find that the worst-case random write performance never drops below roughly half of the best-case random-write performance.

So why is it that Intel claims they can't reproduce the reported problems? I bet they're not testing with a chokkers drive. Pack that drive full - every last sector - and you'll get random write speed issues double-quick time. But leave more "breathing space" than the default built-in, and things will improve.

Does it seem sad to lose a big chunk of an already-very-expensive-per-gigabyte SSD?

It sure does. But on the flipside, do you need all 80GB of super-speed goodness?

In my case, I reckon I can survive with say just 40GB or 60GB of primary partition, tools, and source code, and keep my photo libraries and downloads and other huge files on a traditional spinning platter.

But do I even care that much? Suppose random write speed dropped to 10MB/s? Given that it has practically zero seek time, and given that developing for the Microsoft .NET Framework results in HUGE numbers of small relatively random writes, 10MB/s sustained on an SSD will probably still out-pace my current hard disk by a good margin.

I think I'll set aside 20GB as unused additional "breathing room" initially, and then chip into that later if I can make more precise calculations about worst-case random write performance with different amounts of breathing room...

So talk to me - did it work for you?




UPDATE: If your Intel SSD has hit the doledrums (i.e. has lost its random write performance), check out the HDD Erase tool and accompanying notes.