Categories
Uncategorized

Joel Spolsky: Learning from StackOverflow.com

This article also appears in Canadian Developer Connection.

Just in case there’s nothing good on TV and you’re having a “lazy Sunday”, here’s a video of Joel Spolsky’s recent presentation at Google, Learning from StackOverflow.com, in which he talks about the design decisions that went into and the lessons learned from the Stack Overflow site. It runs for about 52 minutes, so you might want to get yourself a nice beverage before you watch it:

Categories
Uncategorized

Career-Limiting Move

When using your company-assigned laptop to make presentations, remember to disable your pornographically-themed screensaver (and yes, the video below is not safe for work):

Categories
Uncategorized

The Empire’s Coming to WordCamp Toronto 2009!

Darth Vader in the lineup for Wordcamp 2009

WordCamp Toronto 2009, the Accordion City-based conference dedicated to the WordPress blogging platform (which this blog runs on), takes place next weekend, May 8th through 10th. It’s a three-day, three-track conference with offerings for WordPress users of all types, from those just getting started with blogging to hardcore developers and designers plumbing deep into WordPress’ internals.

This year, a couple of guys from The Empire – whom you might know as Microsoft — will be presenting at WordCamp Toronto. We’ll be giving away all sorts of prizes, too!

Paul Laberge

On Day 1 at 11:00 a.m. – that’s Friday, May 8th – my coworker Paul Laberge will make his presentation, titled Customizing Your Blog on Your Local Windows Box, in which he talks about using Microsoft tools like the Web Platform Installer and Expression Web on your home computer to make the most of your WordPress blog. Here’s his abstract:

Your blog represents your online personality and as such you spend a lot of time making sure the look and feel reflects who you are. While the blog platforms available (such as WordPress) provide you with much of the plumbing for your blog, you still need to tweak it until it looks just right for you. In this session, we’ll show you how you can customize your blog on Windows using the Web Platform Installer and Microsoft’s web design tool called Expression Web, all from your local machine. Oh, and we have giveaways, too.

Day 2 – that’s Saturday, May 9th – Yours Truly will be on at 2:00 p.m. giving my presentation, Better Living Through Blogging, where I suggest that blogging is more than just personal publishing or self-expression; it’s a means to a better life. Here’s my abstract:

I took up blogging at the suggestion of my friend Cory Doctorow when my job responsibilities had been whittled down to five minutes of actual work per day. What started as a way to break out of boredom turned out to be a life-changer: I made many new friends, got a couple of TV appearances, landed a couple of jobs, met my wife and even dodged a bullet. In this presentation, I’ll regale you with stories about how I made my life better through blogging, share what I’ve learned over the past seven years and give you some tips and tricks that I’ve found useful. And yes, there will be prizes and a rock and roll accordion performance, too!

WordCamp Toronto 2009 will be held at The Oasi Restaurant, which bills itself as “Toronto’s new centre of creative gravity.” It’s located at 99 Sudbury Street, a hop skip and a jump away from the Queen/Beaconsfield neighbourhood of the Gladstone and Drake Hotels. Registration is pretty cheap: just CDN$50 for the whole conference; it’s CDN$35 if you’re a student. For more details about WordCamp Toronto 2009, visit their site. I hope to see you there!

Categories
Uncategorized

Upwardly Mobile, Part 3: Exploring Windows Mobile 6’s Built-In UI Controls

 Mad Mobile: More Windows Mobile 6 example code from the guy who blogs at Global Nerdy

In my previous article in Upwardly Mobile, the ongoing article series in which I look as various aspects of Windows Mobile 6 development, I showed you a simple application that made use of a couple of user interface controls. In this article, we’ll take a closer look at some of the user interface controls by way of the steak-and-cocktails lifestyle of the characters on the TV series Mad Men.

(In case you’re not familiar with Mad Men, it’s a dramatic TV series set in the early 1960s whos emain characters are advertising executives working at an agency in New York. It was the age of three-martini steak lunches, which serves as the inspiration for the example application in this article.)

Introducing Beef ‘N’ Booze

The application that we’ll build is called Beef ‘N’ Booze. It has no real function other than to demonstrate the use of some of the controls that come with Windows Mobile 6, and do so in a more entertaining way that you’d normally find in a book.

Here’s what the app will look like on startup:

beef_screen_1

The app has a single form and that form is filled completely with a tab control with two tab pages: Beef and Booze. The Beef page lets you choose the “doneness” of your steak as well as a selection of side dishes. Once you’ve made your choices, you click the Place Order button to see a message box containing a summary of your order:

beef_screen_2

Clicking on the Booze tab takes you to the Booze page, where you can place an order from a selection of cocoktails. You can also specify the number of cocktails you want to order and how strong you want the bartender to make them:

booze_screen_1

When you’ve made your drink choices, you click on the Place Order button to see a message box summarizing your drink order:

booze_screen_2

That’s the app in a nutshell. Remember that the idea behind Beef ‘N’ Booze isn’t to make something useful; it’s to demonstrate Windows Mobile’s built-in user controls and give you a chance to explore them. With that knowledge and a little practice, you can eventually build apps that actually do something.

TabControl and TabPages

One of the tricks to compensate for the limited screen “real estate” on a mobile device is to break up an application into pages. The simplest “out of the box” way to do this with Windows Mobile is to use a TabControl, which is a container that holds one or more TabPage controls. Each TabPage is itself a container that can hold other controls.

In Beef ‘N’ Booze, I created a TabControl named tabMain, which holds two TabPages:

  • tpgBeef, whose Text property is set to Beef. It will contain the controls for placing and order for a steak and side dishes.
  • tpgBooze, whose Text property is set to Booze. It will contain the controls for ordering cocktails.

tabcontrol_tabpages

One convenient thing about using TabControls is that the tabbed pages work inside Visual Studio’s form editor. To view and edit a given TabPage, you click on its tab; it becomes the topmost page and you can add, move and remove controls from it.

Buttons

The Beef page has a single button, btnBeef, that when clicked, causes a message box to display the user’s order for steak and side dishes. The Booze page has a similar button, btnBooze, except that it causes a message box to display the user’s cocktail order.

buttons

We’ll draw btnBeef on the tpgBeef page and btnBooze on the tpgBooze page. The next step is to create event handlers for both buttons. The easiest way to do this is to select each button and then use the Events view in the Properties window, and double-clicking on the Click event for each button. Here’s a screenshot of me doing that for btnBeef – Visual Studio responds by auto-magically creating a handler named btnBeef_Click:

btnBeef

Creating event handlers for btnBeef and btnBooze creates these empty methods in the code for the form:

private void btnBeef_Click(object sender, EventArgs e)
{
}

private void btnBooze_Click(object sender, EventArgs e)
{
}

While I do like the “magic” provided by Visual Studio, I also feel that you should know what’s going on behind the scenes. How are the btnBeef_Click() and btnBoozeClick() methods attached to the btnBeef and btnBooze controls? It’s taken care of in the Designer code for the form, in which the layout and events for controls on the form is defined. Here’s the chunk of code that concerns with btnBeef’s properties and events:

this.btnBeef.Font = new System.Drawing.Font("Tahoma", 8F, System.Drawing.FontStyle.Regular);
this.btnBeef.Location = new System.Drawing.Point(165, 181);
this.btnBeef.Name = "btnBeef";
this.btnBeef.Size = new System.Drawing.Size(111, 28);
this.btnBeef.TabIndex = 8;
this.btnBeef.Text = "Place Order";
this.btnBeef.Click += new System.EventHandler(this.btnBeef_Click);

When I added a Click event to btnBeef through the Properties window, Visual Studio generated the name btnBeef_Click for the event handler, added a blank btnBeef_Click() method to the form’s code and connected the event to the handler in the form’s Designer code with this line:

this.btnBeef.Click += new System.EventHandler(this.btnBeef_Click);

When the user clicks btnBeef, we want to call a method named OrderBeef(), which will collect the data from the controls on tpgBeef, format it into something human-readable and then display the results in a message box. When the user clicks btnBooze, we want to call a method name OrderBooze(), which will do something similar, but for the user’s cocktail order. Here’s what the resulting event handler code should look like:

private void btnBeef_Click(object sender, EventArgs e)
{
    OrderBeef();
}

private void btnBooze_Click(object sender, EventArgs e)
{
    OrderBooze();
}

We’ll define OrderBeef() and OrderBooze() over the next couple of sections, as we explore the controls.

Radio Buttons

Radio buttons are controls you use when:

  • You want the user to choose one (and only one) item from a selection of items
  • You want the user to be able to see the complete selection of items immediately

The name “radio buttons” comes from the radio buttons from older radios, such as those in older cars, which let you choose from a number of pre-set radio stations. Selecting one button would change the tuning to the corresponding radio station and de-select the currently selected button:

car_radio_buttons

Radio buttons are grouped together by putting them inside the same container control, such as a panel, or in the case of this particular application, a TabPage. Selecting a radio button de-selects all the other radio buttons occupying the same container control.

The diagram below shows the radio buttons on tpgBeef and the names I assigned to them:

radio_buttons

Here’s my first iteration of OrderBeef(), which shows you how to determine which radio button is selected by checking each one’s Checked property. Once that’s done, it displays the resulting choice in a message box:

private void OrderBeef()
{
    StringBuilder order = new StringBuilder("Steak: ");

    if (rdoRare.Checked)
    {
        order.AppendLine("Rare");
    }
    else if (rdoMediumRare.Checked)
    {
        order.AppendLine("Medium Rare");
    }
    else if (rdoMedium.Checked)
    {
        order.AppendLine("Medium");
    }
    else if (rdoMediumWell.Checked)
    {
        order.AppendLine("Medium Well");
    }
    else if (rdoWellDone.Checked)
    {
        order.AppendLine("Well Done");
    }
    else
    {
        order.AppendLine("Chef's choice");
    }

    MessageBox.Show(order.ToString());
}

Checkboxes

Checkboxes are useful when:

  • You want the user to select zero, one or more items
  • You want the user to be able to see the complete selection of items immediately

The diagram below shows the checkboxes on tpgBeef and the names I assigned to them:

checkboxes

Here’s my second iteration of OrderBeef(), which adds some code to check to see which side dishes the user ordered. As with radio buttons, we’re using the Checked properties, but for the checkboxes:

private void OrderBeef()
{
    StringBuilder order = new StringBuilder("Steak: ");
    int numSides = 0;

    if (rdoRare.Checked)
    {
        order.AppendLine("Rare");
    }
    else if (rdoMediumRare.Checked)
    {
        order.AppendLine("Medium Rare");
    }
    else if (rdoMedium.Checked)
    {
        order.AppendLine("Medium");
    }
    else if (rdoMediumWell.Checked)
    {
        order.AppendLine("Medium Well");
    }
    else if (rdoWellDone.Checked)
    {
        order.AppendLine("Well Done");
    }
    else
    {
        order.AppendLine("Chef's choice");
    }

    order.AppendLine("Sides:");

    if (chkCreamedSpinach.Checked)
    {
        order.AppendLine("Creamed Spinach");
        ++numSides;
    }

    if (chkFrites.Checked)
    {
        order.AppendLine("Frites");
        ++numSides;
    }

    if (chkMushrooms.Checked)
    {
        order.AppendLine("Mushrooms");
        ++numSides;
    }

    if (numSides == 0)
    {
        order.AppendLine("None");
    }

    MessageBox.Show(order.ToString());
}

Comboboxes

comboboxes

For the Booze page, I thought I’d use a different way to let the user select one item from a selection of many: a Combobox with its DropDownStyle property set to DropDownList and containing a number of cocktail names. The method below does the following:

  • Sets the Combobox’s DropDownStyle property to DropDownList, which means that the user cannot just type in any value into the list’s text portion, but can only select from items in the list.
  • Adds a number of cocktail names to the list.
  • Sets the list so that the first item is selected.

public void InitializeCocktailControls()
{
    cboCocktail.DropDownStyle = ComboBoxStyle.DropDownList;
    cboCocktail.Items.Add("Bloody Caesar");
    cboCocktail.Items.Add("Bloody Mary");
    cboCocktail.Items.Add("Martini");
    cboCocktail.Items.Add("Rye and Ginger");
    cboCocktail.Items.Add("Vodka Tonic");
    cboCocktail.SelectedIndex = 0;
}

If I wanted to, I could’ve set the DropDownStyle and the collection of items in the ComboBox in the Properties window.

I placed a call to InitializeCocktailControls() inside the form’s constructor:

public frmMain()
{
    InitializeComponent();
    InitializeCocktailControls();
}

And here’s my first iteration of OrderBooze(), which displays a message box showing which cocktail the user ordered. It makes use of the ComboBox’s SelectedItem property:

private void OrderBooze()
{
    StringBuilder order = new StringBuilder("Cocktail: " +
                            cboCocktail.SelectedItem.ToString() + 
                            "\n");

    MessageBox.Show(order.ToString());
}

Numeric Up/Downs

Numeric Up/Downs are useful when:

  • You want to restrict user input to numeric values only
  • You want to restrict those numeric values to a specific range

numeric_updowns

Here’s the second iteration of InitializeCocktailControls(), which adds code to initialize the numeric up/down nudCocktail in the following ways:

  • Restricting the possible values to the range of 1 through 10
  • Setting the up/down increment to 1 – if the user clicks the “up” button, the value contained within goes up by 1, if the user clicks the “down” button, the value contained within goes down by 1.
  • Setting the initial value to 1

public void InitializeCocktailControls()
{
    cboCocktail.DropDownStyle = ComboBoxStyle.DropDownList;
    cboCocktail.Items.Add("Bloody Caesar");
    cboCocktail.Items.Add("Bloody Mary");
    cboCocktail.Items.Add("Martini");
    cboCocktail.Items.Add("Rye and Ginger");
    cboCocktail.Items.Add("Vodka Tonic");
    cboCocktail.SelectedIndex = 0;

    nudCocktail.Minimum = 1;
    nudCocktail.Maximum = 10;
    nudCocktail.Increment = 1;
    nudCocktail.Value = 1;
}

Here’s the OrderBooze() method, featuring an additional line of code to display the number of drinks the user ordered. The value contained within nudCocktail is taken from its Value property:

private void OrderBooze()
{
    StringBuilder order = new StringBuilder("Cocktail: " +
                            cboCocktail.SelectedItem.ToString() + 
                            "\n");
    order.AppendLine("Quantity: " + nudCocktail.Value.ToString());

    MessageBox.Show(order.ToString());
}

Trackbars

Another way to get numeric value input from the user is to use a Trackbar control. While Trackbars don’t display their corresponding numeric values like Numeric Up/Downs, they have a couple of advantages:

  • They’re larger and more “finger-friendly” than Numeric Up/Downs
  • They give the user a visual cue of where the current value is in relation to the minimum and maximum values

trackbars

In the screenshot above, you can see that I’ve augmented the Trackbar with by putting a couple of label controls just below it: Lame, Decent, and Hardcore.

Here’s another iteration of InitializeCocktailControls(), with code to initialize the Trackbar with the following properties:

  • The leftmost position on the Trackbar corresponds to the value 0
  • The rightmost position on the Trackbar corresponds to the value 10
  • The smallest step you can make in either direction, up or down, is 1
  • Large steps, which you get by clicking to the right or left of the current slider position, change the value in steps of 5
  • The initial value of the Trackbar is 5

public void InitializeCocktailControls()
{
    cboCocktail.DropDownStyle = ComboBoxStyle.d;
    cboCocktail.Items.Add("Bloody Caesar");
    cboCocktail.Items.Add("Bloody Mary");
    cboCocktail.Items.Add("Martini");
    cboCocktail.Items.Add("Rye and Ginger");
    cboCocktail.Items.Add("Vodka Tonic");
    cboCocktail.SelectedIndex = 0;

    nudCocktail.Minimum = 1;
    nudCocktail.Maximum = 10;
    nudCocktail.Increment = 1;
    nudCocktail.Value = 1;

    tbrCocktail.Minimum = 0;
    tbrCocktail.Maximum = 10;
    tbrCocktail.SmallChange = 1;
    tbrCocktail.LargeChange = 5;
    tbrCocktail.Value = 5;
}

Here’s OrderBooze(), with an additional line to display the user’s preferred drink strength, which is derived from the Trackbar’s Value property:

private void OrderBooze()
{
    StringBuilder order = new StringBuilder("Cocktail: " +
                            cboCocktail.SelectedItem.ToString() + 
                            "\n");
    order.AppendLine("Quantity: " + nudCocktail.Value.ToString());
    order.AppendLine("Strength: " + tbrCocktail.Value.ToString());

    MessageBox.Show(order.ToString());
}

Putting It All Together

Here’s the complete code behind the single form in Beef ‘N’ Booze:

using System;
using System.ComponentModel;
using System.Text;
using System.Windows.Forms;

namespace BeefNBooze
{
    public partial class frmMain : Form
    {
        public frmMain()
        {
            InitializeComponent();
            InitializeCocktailControls();
        }

        public void InitializeCocktailControls()
        {
            cboCocktail.DropDownStyle = ComboBoxStyle.DropDownList;
            cboCocktail.Items.Add("Bloody Caesar");
            cboCocktail.Items.Add("Bloody Mary");
            cboCocktail.Items.Add("Martini");
            cboCocktail.Items.Add("Rye and Ginger");
            cboCocktail.Items.Add("Vodka Tonic");
            cboCocktail.SelectedIndex = 0;

            nudCocktail.Minimum = 1;
            nudCocktail.Maximum = 10;
            nudCocktail.Increment = 1;
            nudCocktail.Value = 1;

            tbrCocktail.Minimum = 0;
            tbrCocktail.Maximum = 10;
            tbrCocktail.SmallChange = 1;
            tbrCocktail.LargeChange = 5;
            tbrCocktail.Value = 5;
        }

        private void btnBeef_Click(object sender, EventArgs e)
        {
            OrderBeef();
        }

        private void btnBooze_Click(object sender, EventArgs e)
        {
            OrderBooze();
        }

        private void OrderBeef()
        {
            StringBuilder order = new StringBuilder("Steak: ");
            int numSides = 0;

            if (rdoRare.Checked)
            {
                order.AppendLine("Rare");
            }
            else if (rdoMediumRare.Checked)
            {
                order.AppendLine("Medium Rare");
            }
            else if (rdoMedium.Checked)
            {
                order.AppendLine("Medium");
            }
            else if (rdoMediumWell.Checked)
            {
                order.AppendLine("Medium Well");
            }
            else if (rdoWellDone.Checked)
            {
                order.AppendLine("Well Done");
            }
            else
            {
                order.AppendLine("Chef's choice");
            }

            order.AppendLine("Sides:");

            if (chkCreamedSpinach.Checked)
            {
                order.AppendLine("Creamed Spinach");
                ++numSides;
            }

            if (chkFrites.Checked)
            {
                order.AppendLine("Frites");
                ++numSides;
            }

            if (chkMushrooms.Checked)
            {
                order.AppendLine("Mushrooms");
                ++numSides;
            }

            if (numSides == 0)
            {
                order.AppendLine("None");
            }

            MessageBox.Show(order.ToString());
        }

        private void OrderBooze()
        {
            StringBuilder order = new StringBuilder("Cocktail: " +
                                    cboCocktail.SelectedItem.ToString() + 
                                    "\n");
            order.AppendLine("Quantity: " + nudCocktail.Value.ToString());
            order.AppendLine("Strength: " + tbrCocktail.Value.ToString());

            MessageBox.Show(order.ToString());
        }

    }
}

Download, Go Forth and Noodle!

It’s one thing to read about Windows Mobile 6’s built-in user interface controls, but something else entirely to make use of them. If you’re feeling ambitious, start a new project and rebuild Beef ‘N’ Booze (or a similar app that lets you explore the controls) yourself. Or, if you’d like, download my project files by clicking the link below, play with the app, make changes and learn. No matter which route you take, the best way to learn to is fire up Visual Studio and get coding!

Download icon Download the Beef ‘N’ Booze project (Visual Studio 2008 SP1, 15K .zip file)

Categories
Uncategorized

Old Apple Ad: “What Kind of Man Owns His Own Computer?”

Old Apple ][ ad featuring Ben Franklin: "What Kind of Man Owns His Own Computer?"Click the ad to see it at full size.

From roughly the same time as the Honeywell “What the Heck is Electronic Mail?” advertisement I showed you earlier, comes this Apple ad for the original Apple ][ computer. You have to remember that this was a time when most people didn’t have a computer at their desk; in fact, if an office had a computer, it had just one. And the desktop computers of that era had far less processor power (they typically has 1 MHz 8-bit chips like the Z80 or 6502) and RAM (maximum address space was 64K; machines typically maxed out at 48K RAM) than even the cheapest of today’s mobile phones. And yes, that’s a standard TV set being used as a monitor – its highest resolution was 280 by 192 pixels.

The tricky part about creating such an ad is trying to convince people of that era that they needed a computer. Remember, in those days computers were relegated to their own rooms, the fax machine was still new, mobile phones were toys for the rich and were carried in their own briefcases and when office and even legal documents were typed or written out in longhand. I’ve been trying to think of a present-day analogue for a late 1970s/early 1980s computer ad, but I’m drawing a blank.

Here’s the text of the ad:

What kind of man owns his own computer?

Rather revolutionary, the whole idea of owning your own computer? Not if you’re a diplomat, printer, scientist, inventor…or a kite designer, too. Today there’s Apple Computer. It’s designed to be a personal computer. To uncomplicate your life. And make you more effective.

It’s a wise man who owns an Apple.

If your time means money, Apple can help you make more of it. In an age of specialists, the most successful specialists stay away from uncreative drudgery. That’s where Apple comes in.

Apple is a real computer, right to the core. So just like big computers, it manages data, crunches numbers and prints reports. You concentrate on what you do best. And let Apple do the rest. Apple makes that easy with three programming languages – including Pascal – that let you be your own software expert.

Apple, the computer worth not waiting for

Time waiting for access to your company’s big mainframe is time wasted. What you need in your department – on yourdesk – is a computer that answers only to you…Apple Computer. It’s less expensive than timesharing. More dependable than distributed processing. Far more flexible than centralized EDP. And, at less than $2500 (as shown), downright affordable.

Visit your local computer store

You can join the personal computer revolution by visiting the Apple dealer in your neighborhood. We’ll give you his name when you call our toll-free number…

Categories
Uncategorized

If Everything was Made by Microsoft

Cracked asked its readers to show them what the world would look like if everything in it was made by The Empire. Of the images they submitted. the one below is my favourite – I’ve joked in front of audiences that we make too many versions of Windows and am anxiously awaiting the release of Windows 7 Tartar Control Edition:

Microsoft Can of Peas Home Edition and Microsoft Can of Peas Professional

What, no “Can of Peas Ultimate” and “Can of Peas Team System”?

Categories
Uncategorized

Quebec City Coffee and Code Tomorrow!

This article also appears in Canadian Developer Connection.

If you’re in Quebec City, we’ll be hosting a Coffee and Code tomorrow! IT Pro Advisor Pierre Roman provides the details below:

Salut tout le monde,

Rick Claus, Joël Quimper et moi-même serons au Cosmos sur Grande Allée à Québec demain matin de 9:00am a 11 :30am pour un « Coffee & Code ».

cosmos_cafe

Le concept du « Coffee & Code » est de promouvoir les connections avec la communauté des professionnels en Informatique. Ce, à l’aide d’un endroit public, d’une bonne tasse de café et d’un environnent agréable. Nous nous installerons dans l’entrée et nous serons disponible pour jaser de sujets quelconques.

Donc, si tu es intéressé, tu as le temps pour une pause, viens nous voir… Il me fera plaisir de te payer un café.

Les “Coffee & Code” étaient originalement réservés aux développeurs mais nous nous sommes rendus à l’évidence que le concept est bon et les résultats sont remarquables et c’est maintenant ouvert à tous.  Tu veras bien.

A demain!