Tuesday, October 23, 2007

The Abstract Tar Pit

How often have you found yourself arguing with another person, and they just don't seem to understand you? Chances are they feel that you just don't understand them. You've fallen into the abstract tar pit.

Abstract discussions are like abstract art--they can be very appealing, in part because you can interpret the abstract art however you want to. People love to see what they want to see. But when it comes to technical discussions, abstract discussions are dangerous. There is a good chance someone listening to your abstract arguments will understand completely--but it won't be what you're trying to convey. To understand the abstract, they're likely creating concrete examples in their head and then arguing against your ideas based on these "private" concrete examples. The problem is, if these concrete examples aren't shared, you'll get an argument about completely different examples and understandings.

I recently worked on a 5-week project where this was really clear. There was a small group who had an idea they were trying to sell internally to get funding. Everyone else was feeling confused. Just when they thought they understood these ideas, another concept came along that contradicted what they thought they understood.

So we started a project using Expression Blend to create a "movie" of the idea. The first week we brainstormed a lot, and then drew sketches by hand of what the different screens would look like. We then presented these hand-drawn screens to a customer advisory board so we could get their feedback and help us decide what we should focus on during the next week. We intentionally used hand-drawn sketches in our discussions with customers so they wouldn't get bogged down in the small details and would just focus on the big picture.

About half way through the project we started to create actual screen mockups and animate them with Microsoft Expression Blend so it would look like a screen capture movie of an actual program--but it was all smoke and mirrors.

During the project, the team that had come up with the ideas were constantly arguing with us and saying we were asking the wrong questions. But when we had the final "movie" and showed it to them, an interesting thing happened. The conversations changed from being abstract to concrete. The idea team started to explain the details that we got wrong. And in the process, we discovered that we had gotten most of their vision correct--we just differed in some of the details.

What's more, other people who had been confused completely got the idea after seeing the movie. And again, the discussions were at a concrete level, so the discussions that came after seeing the movie were far more productive.

Friday, August 10, 2007

The Stages of Collaboration

Recently I've been working on an effort to create a new standard for a network protocol in the Model Railroad industry. There are several groups who began work on this effort independently without knowledge of the other groups. As it turns out, there are two groups with similar approaches and we've been trying to work together to create a unified proposal.

During this process, I realized that there are four stages that you must work through before you can come together with a unified approach that is truly a group effort:

Respect: First, you have to respect other people's knowledge and abilities. If you don't respect them, you're not going to listen to what they have to say. They also need to respect you, so there needs to be some work up front so each member learns to respect the other team members.

Understanding: This is a two way street. You need to make sure you understand what other people are proposing so you can see similarities and differences before you suggest changes. If you see what you believe are holes in another approach, you should ask questions about how they would handle that situation to help you understand. Either you'll help them see the hole, or you'll discover you didn't fully understand their approach. In either case, your questions must be sincere questions designed to help you understand both the advantages and disadvantages of other approaches.

Trust: You have to believe that each person is trying to work together to a common goal without hidden agendas. If you suspect they have a hidden agenda, you haven't achieved mutual trust yet.

Compromise: For any group effort to succeed, you must have compromise. But the compromises must come after the understanding and trust have developed or you're just giving in to reach an agreement.

Thursday, July 19, 2007

Programming is Continuous Brainstorming

I was talking about pair programming recently with Mike at a company in Everett, WA, and he asked the usual question: "Doesn't having two people working on the same computer mean we lose productivity?" In response, I blurted out a reply: "Imagine that you need to do some brainstorming and you go into a room by yourself." He got the point.

Mike is a business person, not a developer, so I came up with this analogy because I was looking for something that would resonate with a business person. However, while driving home I realized it's actually much more than a simple analogy. Programming is, in fact, continuous brainstorming, which is why two heads are better (and more productive) than one. Or even the same two people working apart.

Friday, January 05, 2007

Users are Idiomatic

I recently had a discussion with J.D. Meier about user interfaces. During that discussion, I was talking about how users aren't consistent in a way that programs would define consistency. I've been having this discussion for years because of lessons I learned while writing the Norton Commander. Back then I discovered that in order to make an application "feel" consistent, the code need to include many special cases. But I've never had a succinct way to describe this.

But during my discussion with J.D. yesterday, he mentioned idioms and models and I realized that that's really the issues. Model-based design uses models to help create the design, and that's useful for many things. However, users, by nature, are not model driven--users are idiomatic.

One of the definitions of idiomatic, from the Merriam-Webster dictionary is this:

"peculiar to a particular group, individual, or style"

There are actually several aspects to viewing users as idiomatic.

First, different users will have different definitions of "intuitive." So when designing software, you need identify the different groups to understand what they're expected. But to make it even more interesting, individuals tend to jump from one group to another on a whim, so this process is by no means an easy process.

Second, and this isn't conveyed directly by the definition of idiomatic, users actually expect inconsistent behavior. Let me say that again. Users expect inconsistent behavior. What I mean by this is that code that "feels" correct to users typically has lots of special-case code to make the interface feel natural. As an example, going way back to the mid 1980s with the Norton Commander, I had scroll bars for a file viewer. In these days the thumb of the scroll bar moved by an entire line at a time and only had 23 possible positions. The usual approach for positioning the thumb is to calculate the percentage into the file and use this for the thumb position.

But imagine for a moment what happens when you have a long document. You page down several times and the thumb hasn't moved at all. Makes sense, right? You're probably thinking about the math when you answered that question. However users for the most part aren't familiar with the principles that lead to the code that controls the thumbs position. Instead, they're probably expecting the thumb to give them some indication of where they are in the file. One common reaction was that they must be at the top of the file because the thumb is at the very top.

So what I did was add some special case code that would move the thumb away from the top the minute you scrolled away from the top-most line of the file. Likewise, the thumb would not be at the very bottom until the last line in the file was visible. In between these two positions the thumb position was proportional.

This type of special-case code is what makes a program "feel" right to a user, but it often drives programmers nuts. My libraries were used by the people who wrote Norton Utilities 5.0. One of the first things they did when they started to change these libraries is to remove these special cases because they were "confusing" to users. The actual fact is that they were inconsistent by design. The inconsistency was in understanding that users views and "models" often do not map well into logical models because users are idiomatic. 

Tuesday, December 12, 2006

Customizing TFS Work Item States and Reporting

We're using Team Foundation Server to manage our projects. The MSF Agile template, which is what we started with, has just two states for Tasks: Active and Closed. We wanted to add more states to keep track of the flow through iteration planning and test, so we ended up with the following states:

Pending
In Process
Developed
In Test
Closed

The initial state of Pending means it hasn't been planned for an iteration, whereas In Process means it's been assigned to an iteration. You could certainly envision other states, but you probably get the idea.

I added new states and transitions to the template and uploaded it to the server (you can use witexport to get a copy of the template and witimport to save it back to the server). The first think I noticed is that all the items in the "Active" state were flagged as having an invalid state because I had replaced "Active" with "Pending." There wasn't any batch method for updating these work items, so I had to change them one at a time. Fortunately, this is a young project, so there weren't many items that I had to change.

The next thing I found out is that I had broken some of the reports. It turns out that the burn-down chart on the Project Portal page is from the Remaining Work report, and this report assumes that Tasks only have the Active and Closed states. That means all the Tasks in all the new states disappeared from this graph. Woops!

Updating the Warehouse

Since I needed do some more work and testing, I switched to a test TFS server so I wouldn't be working with the production server. However, this server didn't have Tasks in the other states, so I changed the state of a number of tasks. But since the warehouse isn't updated immediately, I needed to run the warehouse task. You can do this by running a web Service on the TFS reporting box:

http://localhost:8080/Warehouse/v1.0/warehousecontroller.asmx?op=Run

You'll need to run this web service method from the TFS machine if you're using a browser to run it.

Setting up Visual Studio to Customize Reports

The reports in TFS are built on top of SQL Server Reporting Services, and Visual Studio has a way to edit the reports. However, getting it all set up wasn't exactly obvious. Here is how to set things up so you can edit and test reports.

Download a Report

The first step to customizing a report is to get a copy of the report from the server. There is an article on MSDN with the steps to get a local copy of the report: How to: Locate and Edit a Report. However, this article is missing one important piece of information.

Setting up the Data Sources

The reports on the server that I downloaded uses two shared data sources with specific names. I needed to create these data sources in the Visual Studio project created in the previous step so they would have the same names, as defined in Data Sources for Team Foundation Server Reporting.

In order to set up data sources, you'll need to have access to the SQL Server machine with the TFSWarehouse database. I didn't have access to the production server, but I did have access to a test box with TFS on it, so I set the connection strings to point to the test box. Just right click on the Shared Data Sources folder and select Add New Data Source from the context menu to create a new datasource. Read Data Soruces for Team Foundation Server Reporting to setup the two data sources correctly (both point to the TFSWarehouse database, but they use different providers).

Here is what the project looked like after I setup the data sources:

Modifying and Testing the Report

At this point I could double-click on the Remaing_Work.rdl report file and open it in the visual report designer. The report was initially setup to show only three values that correspond to the three states Active, Resolved, and Closed. Since I added new states to the Task template, I decided to add a new value for each state.

You add new state values to this report by clicking on the Layout tab and then right-clicking on the graph and selecting Properties.

In the Chart Properties dialog box click on the Data tab and then click on the Add button to the right of the Values list box. This will allow you to add a new value. For the value I used a variation of the expression that was already used for existing values:

=Sum(IIF(Fields!State.Value="In Process",Fields!Cumulative_Count.Value,0))

All I had to do was change the name of the state in the State.Value= test. The resulting dialog looked like this:

Test the Report

Finally, if you have the connections setup properly, and have sufficient rights, you should be able to test your modified report on your computer using the Preview tab of the Report Designer. The report should behave exactly as it would if you double-clicked on the report in the Team Explorer Reports folder.

Upload Modified Report

Once you have your report working the way you want, you'll need to upload it back to the server. The process for this is almost identical to downloading the report, except that you'll click on the Update link instead of the Edit link at the bottom of the page:

Here is what the chart looked like when I was all done:

This graph actually shows the before and after. Most of the graph shows Tasks that were based on the three original states, using data saved in the data warehouse. The last two days of the graph show the "Active" state split into two of the new states: "Pending" and "In Process." As we move forward, we'll see even more states appear on this chart. 

Friday, November 03, 2006

Simplifying VSTS Test Projects

Every time I create a new test project, it always adds some files I delete without even thinking. Today a colleague, Alan Ridlehoover, told me how to turn off some options that add these files to new test project.

If you select Options... from the Tools menu, and then click on the Test Project node under the Test Tools node, as shown below, you'll get the settings that allow you to remove these files. I decided to uncheck all these boxes.

Thursday, October 05, 2006

"Brittle" Unit Tests

I have a friend who is new to unit tests and therefore has never done Test-Drive Development. His management has decided that developers should now write unit tests. But there has been some debate about what should be tested. Since his "application" is really a class library, a lot of the functionality is hidden inside the library (the public API is just a small part).

Some of the people he talked to suggested not writing unit tests for the implementation (just test the public APIs) because they were nervous about making the library "brittle". As my friend said, "they define brittle as in it's really easy for someone to make a change and break stuff."

The comment about brittle unit tests is actually very interesting. I’ve encountered that myself. It’s frustrating when I have to go back and update unit tests after doing a large refactoring. It certainly makes the unit tests “feel” brittle. But I think this feeling is a result of changing my approach to development rather than a real issue. I think it can be broken into two cases:

  1. Unit tests fail, showing bugs in my code. This is obviously the “good” case.
  2. Unit tests fail because assumptions have changed. This makes unit test feel brittle. But actually it’s a good thing. They fail because my assumptions or “specifications” have changed. That means I really do need to rewrite the tests to reflect the new specifications that resulted from design changes.

There is another way to look at item 2 above. Often the broken unit tests are a result of bugs in the specifications, so what you're really faced with is having to interrupt what you were working on to fix bugs. This can certainly be unsettling, because it's a brick wall you have to scale before you can continue with your thread of thought. However, since you're fixing bugs as you go, your code will be much more reliable.