category archive

Category: Articles

Why Most Corporate Training Sucks

And how to make yours suck less

Good morning, and welcome to Acme Widgets Sales Training. I’m Becca, your trainer; over the next 8 hours, you will learn all about Acme Widgets and how to sell them.

[Slide 1 (of 147): About me] First of all, let me tell you a bit about myself. I joined Acme 5 years ago as a customer service representative…

[Slide 2: Agenda] Here’s today’s agenda: First, “What are widgets?” We’ll spend some time on the history of widgets. Next, we’ll talk about the story of Acme and how we got into the widgets business…

Raise your hand if you’ve been there: several hours of “training”, consisting largely of the instructor reading his or her slides to you (or an e-learning course in which the narrator reads the text on the screen), followed by a quiz to make sure you got it. The course objectives promise that after attending the training, you will “know” or “understand” or “be able to explain” something.

Why is so much corporate training so bad? And if you are responsible for developing or delivering such training, how can you improve the lives of your victims (and, let’s be honest, your own life: nobody enjoys delivering ineffective, mind-numbing training)?

The History of Training

Haha, jk. Seriously, how did corporate training get so bad? I can think of three reasons:

  1. We (trainers and instructional designers) are afraid to push back against bad ideas from stakeholders. All too often, someone decides training is the solution to a performance problem; they request a course, and we dutifully create one. That’s our job, isn’t it?

    Even when training is a valid approach, stakeholders and subject-matter experts frequently demand that we include far too much content. They want us to teach students everything they know (never mind that it took them years to attain their expertise). If we object that there’s not enough time to effectively cover so much content, stakeholders reply that “at least the students will be exposed to the material”, as if they can somehow learn by osmosis.

    You can’t teach people everything they need to know. The best you can do is position them where they can find what they need to know when they need to know it. — Seymour Papert

    To be truly valuable to our organizations, we must be more than simply course designers or instructors; we must become performance consultants. Don’t create a course just because someone requests one; don’t allow stakeholders to dictate content or instructional approach. Instead, ask why stakeholders think they need a course; what do they want the training to accomplish? If you agree that training is warranted, you recommend the best ways to achieve the stakeholders’ objectives.

    Of course, you may not feel confident standing up to stakeholders due to…

  2. Lack of formal training. How many of you have received formal education as a trainer or an instructional designer? Yeah, me either. Many of us fell into this role because we were subject-matter experts in some other field. (I was a software developer with social skills.) Some training manager saw our potential and asked, “Hey, do you want to be a trainer?”

    If you do get formal training, many degree programs cover instructional-design models from 40 or 50 years ago (I’m looking at you, ADDIE and Bloom) without teaching you how to adapt them to today’s learners and rapidly-changing subject matter.

  3. This is all we know. We know our training could be better, but “tell-then-test” is how it’s always been done. (It kills me that university instructors are called “lecturers”.) What else is there?

Here are three ways to create training that learners and stakeholders love, and that effects real change within your organization:

Start with a goal

If you’re going to spend time developing a course (and ask people to spend time taking it), the training should have a specific, measurable goal. I like Cathy Moore’s Action Mapping process: 

Cathy Moore's Action Map

Start with a measurable business goal, then figure out what learners need to do in order to reach it. Identify the minimum information learners need in order to perform the desired behavior and include only that information in the course. If you must provide additional reference material, link to it as an external resource; don’t force-feed it to learners as part of the course. 

Perfection is attained, not when there is nothing more to add, but when there is nothing left to take away. — Antoine de Saint Exupéry

Lean, focused training saves your time during development, and ensures that you don’t waste learners’ time: Every moment they spend with your training moves them closer to your goal.

Here’s another great post on this subject that I wish I had written. If you don’t already read Ethan Edwards’ blog, you should start now.

Make it emotional

Quick: Think of your favorite scene from a movie or TV show. Why do you remember that scene? I’ll bet it provoked an emotional reaction – excitement, surprise, laughter, romance – the first time you saw it. People remember (and are moved to action by) experiences that engage their emotions. How can you apply this principle in your training?

A great way to get people emotionally involved is to tell a story, a realistic scenario that helps learners see how the training relates to them. 

For example, I began a course on service-oriented architecture (SOA) with a story about Linda, a software developer, and Bill, her manager. Linda wants to use SOA on her current project; she believes the long-term benefits are worth a bit of up-front investment. Bill thinks it’s a nice idea, but there’s not enough time in the schedule to try something new. 

Bill and Linda

The conflict between Linda and Bill invites learners to choose a side and helps get them emotionally involved. Try to think of a story with a plot and characters to which your learners can relate.

For more excellent ideas on creating a memorable message, read Made to Stick by Chip and Dan Heath.

Make it practical

If your goal is to teach people how to do something, your course should include interactions that allow them to practice the desired behavior. By “interactions”, I don’t mean a multiple-choice quiz or matching terms with their definitions. Learners must be able to practice what you expect them to do on the job, including the ability to make mistakes and see the consequences of those mistakes. Dr. Michael W. Allen recommends a model that he calls CCAF: Context, Challenge, Activity, Feedback.

Context is the setting in which the learning takes place. It includes the story you choose to set the scene as well as the visual design of the course, which should be immersive and reflect the learner’s day-to-day work environment as closely as possible.

Allen Interactions' Security Risks Course

Challenge refers to creating a desire in the learner to complete the course successfully, a sense that something personal is at stake. Ethan Edwards explains

When the learner makes forward progress equally, whether an answer is correct or incorrect, he or she learns that it does not really matter what one gives as an answer… If there is no real chance for the learner to fail, then failure or success is a matter of indifference. And if the performance required of the learner seems pointless or irrelevant, there will be little motivation to work toward that end.

The learner must know that success is possible, but that it’s not necessarily guaranteed without some mental effort.

Activity is the physical action the learner must perform to achieve success. Ideally, the activity should mirror as closely as possible what the learner will actually do on the job. The goal is to demonstrate mastery of a skill, not simply the recall of information.

Feedback is the information we communicate to the learner in response to his or her actions. Telling the learner whether he or she completed an activity correctly is just scratching the surface. Instead, you can show the learner the consequences of his or her actions (intrinsic feedback). Or you can give the learner a challenge at the beginning of a lesson, then use feedback after an activity to present the associated content. By tailoring the content to the learner’s needs (as demonstrated through the activity), the instruction takes less time and becomes more relevant, and the learner will be more receptive to it.

For more information on the CCAF model, download this free e-book from Allen Interactions.

Be the change you wish to find in your couch cushions

By starting with a specific, measurable goal, engaging the learner’s emotions, and making the training practical and relevant to the learner, you will greatly increase the appeal and effectiveness of your training.

Have you experienced a memorable training experience (good or bad)? Do you have questions about how to apply this article? Please leave a comment below.

UX Tip of the Week: Why Message Boxes Are Evil

I recently purchased a new hard disk. Eager to free up space on my crowded system drive, I dragged hundreds of files from their existing locations to the new drive. “67 Minutes Remaining,” Windows said. I went off to read a book (who am I kidding? I watched TV) while the computer did its thing.

An hour or so later, I went to check on the computer’s progress. I expected it to be almost finished, but instead I saw this:

 Windows confirmation dialog

Thanks, Windows!

What’s So Bad About Message Boxes?

Here’s why message boxes are evil and you should avoid them:

If message boxes are such a bad idea, why do we continue to use them?

  • They’re easy. Most programming languages allow you to create a message box with one line of code.

  • They’re placeholders. “I’ll replace it with something better before we ship.” Right.

  • Management insists. You want to do the right thing, but your manager tells you there’s no time in the schedule. “A message box is good enough!”

  • They’re all we know. The program needs to communicate with the user. How is it supposed to do that if we don’t use a message box?

Message Box Alternatives

To answer that last question, let’s consider four contexts in which programmers commonly use message boxes:

Confirmations. Those infamous “Are you sure?” prompts. Confirmation dialogs are generally ineffective because they quickly become routine: the user learns that to perform some action (say, to delete an item), she must click the Delete button and then click “Yes” on the confirmation dialog. The one time in 100 she doesn’t intend to delete the item, her fingers are faster than her brain.

A better solution is to provide an undo function. Simply perform the action the user requests, then make it easy to reverse the action if she changes her mind.

Status updates. “I have successfully completed a task! Click OK if you’re proud of me.” It’s fine to keep the user informed as to your program’s status, but is it really necessary to make her pat you on the head?

As its name suggests, the status bar was invented for precisely this purpose. If you’re concerned that your users won’t notice status bar messages, please use a non-modal way to display your status. Here’s how Outlook does it:

Outlook status message

Internet Explorer uses an animated Information Bar:


Google uses an ingenious method to display status and expose the undo option:

Gmail undo

Options. “Do you want to do X?” When thinking about how a program should behave, I like to imagine it as my administrative assistant. If I ask my assistant to make a travel reservation, do I want him to interrupt me with every option: “Excuse, me, sir. Do you prefer a window or aisle seat? In the front, middle or back of the plane? Would you rather leave in the morning or the afternoon? Do you want to fly through Chicago, Denver or Minneapolis?” Of course not! I’d like my assistant to make educated guesses about my reservation, then present it to me for approval. If I make any changes, I’d like him to note my preference for next time.

Similarly, rather than displaying a message box for each option, software should use intelligent defaults. Choose default options that will satisfy most users, and offer a straightforward way for more advanced users to change them.

Errors. This is the context most likely to warrant a message box, but only if it tells the user precisely how to correct the problem (“Please insert a blank disc into drive E:”) or if the error is so severe that the program cannot continue.

If the user can’t do anything about the error, there’s no need to bother her with it; simply log it, perhaps notify the development team, and move on. If the error is caused by something the user did, such as entering invalid data, there are non-modal ways to tell her about it. The best solution is to help the user avoid making the mistake in the first place.

In future columns, I’ll discuss each of these situations in more detail and provide sample code demonstrating my suggestions. My hope is that someday, it will be as quick and easy to do the right thing as it is to use a message box!

Easy RSS in VB.NET

I implemented an RSS feed for FTPOnline last night; .NET's XML serialization capabilities made it relatively painless.

First, I created this class to model the feed. (I actually cheated and used .NET's xsd.exe utility, first to create a schema based on my own RSS feed, then to generate a VB.NET class from that schema. All I had to do then was tweak the code to use a collection instead of an array for the items.)

Now all it takes to update the feed is to populate the RSS object and serialize it to XML:

    Dim rssFeed As New rss()
    Const BaseURL As String = ""

        .title = "FTPOnline"
        .description = "Technical information for " & _
            "developers and IT professionals from " & _
            "the FTP family of publications and conferences."
        .link = BaseURL
    End With

    ' -- Query database for recent items

    ' Loop through DataReader, adding items to feed
    Do While drFeatures.Read
        Dim rssItem As New rssChannelItem()
        With rssItem
            .link = CStr(drFeatures!headerLink)
            ' Fully-qualify relative links
            If InStr(.link, "http://"= 0 Then
                .link = BaseURL & .link
            End If
            .title = CStr(drFeatures!headerText)
            .description = CStr(drFeatures!text)
            .pubDate = Format(drFeatures!dateCreated"R")
        End With

    ' Serialize RSS object to file
    Dim xml As New XmlSerializer(GetType(rss))
    Dim strFile As New FileStream("d:\path\rss.xml"FileMode.Create)

    ' Empty namespaces collection eliminates 
    ' default namespace attributes from XML root
    Dim xmlns As New XmlSerializerNamespaces()

    xml.Serialize(strFile, rssFeed, xmlns)

Is Inheritance Overrated?

Like many VB programmers, I'm only marginally familiar with implementation inheritance. Oh, sure, I understand it in theory -- I've read all the standard primers ("A dog and a cat are both animals, but they speak differently...") -- but I have yet to use it in a real application. So I was enthusiastic when it looked like my current application, a content management system written in ASP.NET, would provide an ideal opportunity to get my feet wet with implementation inheritance.

The app deals with content objects which are displayed within placeholders in page templates. When a page is requested, the system retrieves the relevant content from the database, binds the data to a user control, then inserts the user control into a placeholder on the page. There are several types of content: home page lead, home page non-lead, feature article, product review, etc. As I designed the various content objects, it occurred to me that they shared certain features in common: they all, for example, had a title, description and publication date; all home page items had a URL to which they linked; all article types had an author and one or more pages. They all needed to know how to load themselves from and save themselves to the database. So, I thought, why not create a base ContentItem class containing the shared properties and methods, and inherit the more specific types from this base class?

In my initial proof-of-concept, that's exactly what I did. Specific content types inherited from a base ContentItem class; when they were serialized to the database, they looked like this. Everything worked as expected; this inheritance stuff was a piece of cake!

As I started to flesh out the prototype, however, it became apparent that my design was pretty maintenance-intensive. Each new content type required me to create two user controls and associated code-behind classes: one of each to load/edit/save the content, and another to display it on a page. Although the new classes could inherit common functionality from my ContentItem and ContentDisplay base classes, I'd still have to create, test and debug them. In addition, the XML stored in the database was version-specific: If I later changed the design of a class, it wouldn't know how to deserialize data saved by an earlier version of the class.

One way to reduce the maintenance burden, I thought, would be to create a generic edit form: The form's code could read its layout from an XML file and dynamically create the necessary controls. That was simple enough (I'll write about it in a future article); the hard part was figuring out what to do when the user clicked the 'Save' button: I'd still have to create an instance of the correct content class and manually assign the form's field values to the associated class properties. Nor did this approach do anything to reduce my class development burden, or avoid the version-specific nature of the serialized XML.

Finally, I concluded that inheritance was not a good fit for this application; it was simply more trouble than it was worth. I refactored the design to use a generic content object, which consists of a simple collection of items. My generic edit form could save itself by simply looping through its controls and adding a name-value pair to the content object's Items collection. I'd no longer have to create new classes for each new content type, and the serialized XML would no longer be version-specific: the content object would neither know nor care what items it contained. To add a new content type, all I'd have to do is create a simple form definition file, and a user control to display the content.

Is it just me, or is this a well-known downside of implementation inheritance? Does inheritance work best in cases where the object model is relatively static? Or are there ways to efficiently handle situations like this one, and I just don't know them yet?

A Tale of Tabbed Pages

The Design: In my ASP.NET content management system, I wanted to use a tab control to allow an author to edit individual pages of an article. I also decided to use Active­Up's HtmlTextBox control to enable rich-text editing: it's a full-featured control at a very reasonable price.

The Problem: I quickly discovered, however, that changes to the text box weren't being saved when I switched to a different tab. After another marathon session of cursing and semi-random code-tweaking (I tried changing viewstate settings, attaching code to various page and control events, etc.), I finally concluded that the postback triggered by a change of tabs was circumventing the text box's onblur event, which is where it persists its contents. (I should mention that in my desperation, I took advantage of ActiveUp's live chat tech support feature. Pierre, the control's author, was extremely cordial and helpful. Since he's in Belgium and I tend to work in the middle of the night, the arrangement proved to be convenient for both of us!)

The Solution: Now that I understood the source of the problem, the question was: How do I force the text box to persist its data before a postback? I tried a few things, and eventually found a solution by Googling for "intercept __doPostBack": The trick was to create my own function that does whatever I need to do before a postback, and then create a function pointer that redirects the default __doPostBack function to my custom function (JavaScript is awesome, by the way). Problem solved!

Footnote: Another problem I had with the HtmlTextBox was that I couldn't get a second control on the page to work correctly. Pierre assured me that this is supported, so I took a closer look at my code. Turns out that the ID I was assigning to the second control contained a space (I create the controls dynamically based on an XML form definition -- that's a subject for another article -- and I was assigning an ID equal to the name of the data field). Replacing the space with an underscore solved that problem.