C. Keith Ray

C. Keith Ray writes about and develops software in multiple platforms and languages, including iOS® and Macintosh®.
Keith's Résumé (pdf)

Monday, December 29, 2008

William Wake described the essence of an automated test as Arrange, Act, Assert. I've added "Erase", to account for the clean-up that some tests have to do. You might ask why "Erase" added to "Arrange, Act, Assert" and not some word starting with "A". I think starting with "eh?" is close enough. :-)

"The thing about elves is they've got no ... begins with m," Granny snapped her fingers irritably."

"Manners?"

"Hah! Right, but no."

"Muscle? Mucus? Mystery?"

"No. No. No. Means like ... seein' the other person's point of view."

Verence tried to see the world from a Granny Weatherwax perspective, and suspicion dawned.

"Empathy?"

"Right. None at all. Even a hunter, a good hunter, can feel for the quarry. That's what makes 'em a good hunter. Elves aren't like that. They're cruel for fun [...]"

—Terry Pratchett, Lords and Ladies


In C++, with certain test frameworks, a test might be specified in a manner something like the following in C++.



TEST(TestBlurImageFilter)
{
// Arrange
string outfileName = NewTempFileName("TestImageFilter");
Image* sourceImage = new Image("lena.png");

// Act
ImageFilter* filter = new BlurImageFilter();
filter->ProcessToFile(sourceImage, outfileName);

// Assert
AssertImagesEqual("expected_lena_blurred.png", outfileName);

// Erase
DeleteTempFile(outfileName);
delete filter;
delete sourceImage;
}


Note: generally you don't want to deal with files in unit tests; working in-memory would be much faster. Also, if this is one of those frameworks that throws an exception, or otherwise aborts the test if an assertion fails, then the "Erase" portion of the test won't get executed if AssertImagesEqual failed. Let's assume that's not a problem for the moment.

Let's imagine that you then write a another test like so:



TEST(TestUnblurImageFilter)
{
// Arrange
string outfileName = NewTempFileName("TestImageFilter");
Image* sourceImage = new Image("lena.png");

// Act
ImageFilter* filter = new UnblurImageFilter();
filter->ProcessToFile(sourceImage, outfileName);

// Assert
AssertImagesEqual("expected_lena_unblurred.png", outfileName);

// Erase
DeleteTempFile(outfileName);
delete filter;
delete sourceImage;
}


Now you've got duplicated "Arrange" and "Erase" sections. And duplicated logic in tests can be just as bad it would be in production code. Fortunately, most test frameworks already have support for extracting "Arrange" and "Erase" to methods in a "test fixture". The above code could be refactored to something like the following:


class ImageFilterTests : public TestFixture
{
public:
ImageFilterTests()
: sourceImage(NULL), filter(NULL)
{
}

string outfileName;
Image* sourceImage;
ImageFilter* filter;

virtual void SetUp()
{
// Arrange
outfileName = NewTempFileName("TestImageFilter");
sourceImage = new Image("lena.png");
}
virtual void TearDown()
{
// Erase
DeleteTempFile(outfileName);
delete filter;
delete sourceImage;
}
};

TEST_F(ImageFilterTests, TestBlurImageFilter)
{
// Act
filter = new BlurImageFilter();
filter->ProcessToFile(sourceImage, outfileName);

// Assert
AssertImagesEqual("expected_lena_blurred.png", outfileName);
}

TEST_F(ImageFilterTests, TestUnblurImageFilter)
{
// Act
filter = new UnblurImageFilter();
filter->ProcessToFile(sourceImage, outfileName);

// Assert
AssertImagesEqual("expected_lena_unblurred.png", outfileName);
}


Not only has this eliminated the duplicated logic, most unit test frameworks will also guarantee running the TearDown method even if the test fails, so you don't have to write your own try/catch blocks or other contortions for exception-safe "erase".

You'll see that I also added a constructor to insure that the pointer variables have valid NULL values so we don't delete garbage pointers if the Image or Filter objects were not allocated successfully. (You should consider using boost::shared_ptr and/or boost::scoped_ptr if you're dealing with object pointers in C++ code and tests, by the way.)

In those C++ test frameworks where the test-fixture creation and deletion is done just before and after executing the test, the SetUp and TearDown methods can (almost always) be replaced with a constructor and destructor instead. Using that and boost::scoped_ptr to insure exception-safe object deletion would allow us to write the following code:



class ImageFilterTests : public TestFixture
{
public:
ImageFilterTests()
: outfileName(NewTempFileName("TestImageFilter")),
sourceImage(new Image("lena.png"))
{
// Arrange
}

virtual ~ImageFilterTests()
{
// Erase
DeleteTempFile(outfileName);
}

string outfileName;
boost::scoped_ptr sourceImage;
boost::scoped_ptr filter;
};

TEST_F(ImageFilterTests, TestBlurImageFilter)
{
// Act
filter.reset(new BlurImageFilter());
filter->ProcessToFile(sourceImage.get(), outfileName);

// Assert
AssertImagesEqual("expected_lena_blurred.png", outfileName);
}

TEST_F(ImageFilterTests, TestUnblurImageFilter)
{
// Act
filter.reset(new UnblurImageFilter());
filter->ProcessToFile(sourceImage.get(), outfileName);

// Assert
AssertImagesEqual("expected_lena_unblurred.png", outfileName);
}

Monday, December 15, 2008

C++ Mocking Framework

Google released Google Test for C++ earlier this year, and just recently released Google C++ Mocking Framework.

These are extensively documented... check them out!

Tuesday, December 9, 2008

What a Tangled Web We Weave, When Don't Have Effective Tracking

This is a re-post of a blog entry I wrote in 2003...

Steve Norrie points to a recent online article by Jerry Weinberg published on CrossTalk, the Journal of Defense Software Engineering here: Destroying Communication and Control in Software Development.

I'd like to mention a few of the Extreme Programming (XP) solutions to some of the problems mentioned in this article. Be aware that XP is a light-weight process, relying on people rather than technology to do the right thing. (A savvy person can undermine technology anyway.)

Requirements. One of the first areas that communication can be destroyed is by not doing requirements well... not involving the customer, thinking that requirements are a waste of time, and so on. Extreme Programming recommends involving the customer, or a qualified representative of the customer, throughout the entire project. And in addition to talking about the requirements often and in detail, XP requires writing the requirements down in an executable form - automated acceptance tests.

The configuration management system (CMS). The CMS tracks requirements, design, code, test data, test results, user documentation, etc. Jerry notes that information in the CMS can be undermined by failing to keep it up to date, restricting read-access from people who should have access, removing data or failing to put data into it. Extreme Programming doesn't require any specific CMS system (software or otherwise) for this tracking, but does suggest using the simplest thing that actually works. For code, tests, and test data, I recommend using CVS or some other source-code-management system. For acceptance test results, many XP teams record those on a white board or poster board, updated them weekly or daily, charting them over the course of the project. XP does strongly recommend using index cards (story cards) for tracking requirements during initial and weekly planning, and also strongly recommends documenting the relationship between the automatic acceptance tests and the story cards. The person playing the Customer role, as well as the whole team, is responsible for keeping track of the stories. Many XP teams also record the stories in web-accessible ways, such as a wiki.

In regards to a bug-tracking database, some XP teams track bugs the same way as stories - index cards and acceptance tests. You might think that this won't work, but consider that several XP teams have reported that their bug rate after implementing XP dropped from hundreds per six months to around one bug per month. It helps that bugs are not usually recorded until after a story is finished, and in XP, a story is not finished until it is passing its acceptance tests - this requires conversation between the tester and coder as soon as problems are noticed during the implementation and testing of the story. When a bug is recorded, it probably indicates that an acceptance test that was passing has started failing.

Weinberg recommends that you "set and enforce a policy of complete and open information at all times." Agile processes like XP need accurate information daily. Many projects keep tracking information on poster boards and white boards, visible not only to all team members, but anyone in management who walks by. This is the "Project Progress Poster" concept that Weinberg recommends in Quality Software Management: Anticipating Change. Since in my company, few people in management walk by, we keep tracking information in our wiki web pages.

Quality Assurance. Weinberg recommends "Prevent these abuses by having quality assurance report to the highest levels of management, and not to project management." In XP, QA testers are delegates of the person playing the Customer role -- the same person who defines the requirements. QA testers should not only be implementing and running the automated acceptance tests, but also running stress tests and manual testing of the product's user interface.

Weinberg reports that testing often comes too late in the project to be useful in effective risk management. (There's a phrase in XP circles: "Doctor, it hurts when I do this..."). Don't wait until it is too late. XP requires testing to start in the first iteration of the project -- the first week. This and other XP practices enables effective risk management.

The XP solutions noted here require that project management be willing to face reality at all times. One of the quickest routes to failing with XP is to not do XP. If project management destroys information, hides it, degrades it, or inserts misleading inforation, intentionally or not, it is going to be very difficult to have a successful project, no matter what the methodology used.

Tuesday, November 25, 2008

Science Daily Snips

Hopes for cleaner, safer energy:

Quicker, Easier Way To Make Coal Cleaner "Construction of new coal-fired power plants in the United States is in danger of coming to a standstill, partly due to the high cost of the requirement — whether existing or anticipated — to capture all emissions of carbon dioxide [...] Instead of capturing all of its CO2 emissions, plants could capture a significant fraction of those emissions with less costly changes in plant design and operation [...]"

Making Gases More Transportable "Chemists at the University of Liverpool have developed a way of converting methane gas into a powder form [...] made out of a mixture of silica and water which can soak up large quantities of methane molecules [...] might be easily transported or used as a vehicle fuel."

Tuesday, November 18, 2008

Agile Methods Help Programmers Shine

Now and then someone says something like "Agile methods won't turn a mediocre programming into a star. That irritates me, because bad non-agile methods can make a very good programmer produce mediocre results. Without taking into account their environment, no one will know how good that "mediocre" programmer can actually be.

A star NASCAR driver probably won't win the race, if his car has a flat tire and his support team can't or won't replace it. It doesn't matter how good the driver is, if the car is bad.

One simple idea - that the "traditional" way of developing an application is by implementing one complete layer at a time (whether bottom-up or top-down) - dooms a project to deliver no working features until late in the development cycle. When feedback finally arrives about the features (wrong requirements and/or wrong implementations), there is often not enough time to fix all the problems, and so the developers look bad. The testers also look bad if they don't have enough time to test, or enough time for fixes to be tested.

Turn that idea around - develop one vertical slice of an application at a time, so each feature can be tested as soon as possible - allows the customers and testers to provide feedback early in the development cycle. That can make a difference in how good the final product can be. Instead of projects running late or shipping with bugs, the project has known good features, can ship when enough features have been done, and the developers look so much better. People might say the project has star programmers.

Many programmers and testers have been trained in that "traditional" style. It's assumed in many books, schools, and corporate cultures. I call it "Unconscious Waterfall" when the style is just assumed. It takes a very remarkable developer to do good work in this environment.

In some shops where they do something they call "Waterfall" and they make it work, it turns out that they verify that many features are working correctly early in the project - there are many places where requirements, tests, and code are examined, verified, validated. Those kinds of waterfall projects are pretty rare, from what I see.

Wednesday, November 5, 2008

Adopt pets from the Humane Society

I adopted two cats last weekend. A five-month old female and a 3-year old female. Beautiful, curious, energetic, affectionate. I'll post pictures later.

Check the web pages of your local humane society. They probably have cats, dogs, rabbits and birds. If you can, give some of them a loving home.

Sunday, October 26, 2008

When a student is ready...

When a student is ready, a teacher will appear. On an agile team, everyone can be a student and teacher. One team member may be more knowledgeable about the unit testing framework, but another may know more about object-oriented design. One team member may be more skilled with the IDE, and another knows the in-and-outs of the mocking framework.

Pair programming is an excellent time for these kinds of knowledge transfer. Code-reviews (particularly those conducted asynchronously over email) are a low-bandwidth medium for teaching and learning. It can happen, but teaching and learning has a lot more room to occur with in-person interactions.

The converse: "When a student is not ready, a teacher will not appear." also happens. People who reject pair programming without giving it a serious try are sometimes afraid to expose their fallibility. I didn't expect to enjoy pair programming, and when I first gave it a try, I was making typos and exposing my fallibility right from the start. And then the person I was pairing with was just as clumsy and fallible. As we continued to pair, we learned not only how fallible we are, but also how smart we are. We get to know we each as human beings. We find out that instead of being a waste of time, we make progress faster than we could if we were programming alone.

It takes courage to pair program. Do it for a while, and you'll find it also provides more safety than programming alone does.

Wednesday, September 17, 2008

Refactoring for Testable C++ at OOPSLA

I will be co-presenting a workshop on Refactoring Legacy C++ Code to Testable C++ with Joshua Kerievsky at OOPSLA 2008. If you deal with C++ code and want to make it testable, this tutorial is for you.

This tutorial for intermediate-level C++ programmers is based on my own pragmatic experience working with legacy C++, as well as the experience of other Industrial Logic coaches. It is part lecture with slides and video, and part practice on C++ code that we provide.

I gave this workshop with Gil Broza at the Agile 2008 conference, and the class members really appreciated digging into the labs -- to the point that many of them choose to work on the code and tests in one of the labs instead of taking a break.

If you are working with hard-to-test legacy C++ code, and want to get it under test so you can safely refactor it, this tutorial will present several hard-to-test examples of C++ code and show how it can be refactored into testable code. The legacy code problems that may experience have several possible refactorings to get them under test, and we will cover the pros and cons of the most common refactorings and problems.

Friday, September 5, 2008

Looking at Good Object Oriented Design

Looking at good Object Oriented design is like watching an effective manager (or CEO) who knows how to delegate the proper responsibilities to his or her team(s).

Wednesday, September 3, 2008

jBehave's Golden Rules

I like these "Golden Rules" for contributers to jBehave:

Here are some rules that we follow when developing JBehave:

  • Example Driven: Only create code to solve a realistic (and preferably real) problem.
  • Behaviour Driven: Only create classes once you can describe and automate examples of their behaviour.
  • No Misbehaving: Automated examples must work before being checked into the repository, and existing tests must not be broken.


They have a new release, by the way. With "plain text" scenarios. Check it out.

Thursday, August 21, 2008

SF Reading material for you and your iPhone

Jeffrey Carver has made the book Neptune Crossing, available for download. The HTML version appears to be quite readable on my iPhone when rotated for a horizontal aspect ratio.

Cory Doctorow has made several of his books available for download, the best being Little Brother. He is finding that free online releases of his books are enhancing the sales of his paper editions, rather than reducing sales.

Other authors are finding the same thing. Old out-of-print books made available for download can revive an author's readership, while new books simultaneously released on the web and in paper can generate more buzz than just the paper edition will.

A little bit more about Little Brother:  one of the blurbs sums it up well: 
Little Brother is a scarily realistic adventure about how homeland security technology could be abused to wrongfully imprison innocent Americans. A teenage hacker-turned-hero pits himself against the government to fight for his basic freedoms. This book is action-packed with tales of courage, technology, and demonstrations of digital disobedience as the technophile's civil protest.
Andrew "bunnie" Huang, author of Hacking the Xbox
Check it out.

Tuesday, August 19, 2008

Can someone do a meta-study on agile adoption

Get conference proceedings from Agile2008 and earlier. Check out all the experience reports and other papers about agile adoption. What do the success reports have in common? What do the failure reports have in common? What is a typical timeline for success for transforming a project team, a division, a company?

Friday, August 15, 2008

Clean Code

Clean Code (also known as "Simple Code" as defined by Kent Beck) is (paraphrased):
  • Correct: it passes all its tests and its tests are thorough (but not redundant) and correct.

  • Does not contain duplication: Duplicate logic is eliminated and localized in a few places – this may require using functional or object oriented concepts and design patterns. Duplicate data is minimized. Duplicate syntax is also minimized. No redundency.

  • Expresses its concepts: by using good class names, methods names, and other identifiers. Dependencies are expressed in interfaces. Methods and classes are short, readable, and have a single responsibility.

  • Contains no superfluous parts: it does not have dead code, unnecessary parameters, etc. No code left over from features that have been removed. No code for features that haven't been scheduled for implementation.
I find that more explanation is often needed, since some programmers will, for example, point at "expresses its concepts" by saying: this huge function in this huge class perfectly expresses the two dozen actions it performs.

Saturday, August 9, 2008

How I Learned...

richard durnall
 points to an article "How I Learned to Let My Workers Lead" by Ralph Stayer. Richard notes 
There is a deeper, less tangible philosophy embeded within Lean that focuses on people, the systems we place them in and the behaviours these systems encourage. [...]
The Stayer article explains the leap of faith we have to take as leaders to create new systems where the people can determine the process.
In Lean Ops we missed this deeper philosophy. We focussed on the tools and when they didn’t work we just tried harder to enforce the application of the tools. The irony! [...]"
This correlates with several lessons that I am still learning to embody within myself and organizations I interact with. 

An observation: The most well-known success story of "Lean", Toyota, shows that the corporate culture is more important than the practices. Attempts to imitate the practices without the culture of true empowerment have failed. And from what I've heard, many of their specific practices change over the course of time.

A few choice quotes from Ralph Stayer's article: 
If I was going to fix what I had made, I would have to start by fixing myself.
Of course, fixing himself and his company (which, since he was the founder, was a reflection of himself) was a long and circuitous course... The "end state" he envisioned for his company was:
[...] a flock of geese on the wing. I didn't want an organizational chart with traditional lines and boxes, but a "V" of individuals who knew the common goal, took turns leading, and adjusted their structure to the task at hand. [...] Most important, each individual bird is responsible for its own performance.
Note the difference from his "end state" and how he attempted to get there:
I spent those two years pursuing another mirage as well -- detailed strategic and tactical plans [...] We tried-to plan organizational structure two to three years before it would be needed -- who would be responsible for what and who would report to whom, all care fully diagramed in boxes and lines on charts. Later I realized that these structural changes had to grow from day-to-day working realities; no one could dictate them from above, and certainly not in advance.
Now that is one of the lessons I learned when I attended Jerry Weinberg's PSL and participated in the experiential simulations he designed. Everyone who attends tends to learn different lessons -- often, the lessons they most need to learn. Jerry creates an environment that enables us to observe problems, without him having to didactically explain what's going on. He was teaching this before "Agile" or "Lean" became buzzwords in the software development community.

Trying to assign decision-making (or not) responsibilities and define a team structure before beginning a project is a something like buying equipment and organizing a team for to play softball, without knowing that the sport you're actually going to be playing is basketball.

[...] The early 1980s taught me that I couldn't give responsibility. People had to expect it, want it, even demand it. So my end state needed redefining. The goal was not so much a state of shared responsibility as an environment where people insist on being responsible.

To bring people to that new Point B, I had to learn to be a better coach. It took me additional years to learn the art of coaching, by which, in a nutshell, I mean communicating a vision and then getting people to see their own behavior, harness their own frustrations, and own their own problems.
Coaching is an art I'm still working on. As an Agile coach, I can model the behavior I'd like to see in others, observe, communicate, offer feedback, ask for feedback, and sometimes give advice. It turns out that managers (even CEOs) have little more power than a coach does:
The debacle of ordering change and watching it fail to occur showed me my limitations. I had come to realize that I didn't directly control the performance of the people at Johnsonville, that as a manager I didn't really manage people. They managed themselves.[...]
Stayer describes how top management had the responsibility of checking the quality of the product (tasting the sausage) and he made the change that the workers who are responsible for creating the product would become responsible for checking quality, with the expectation that quality would remain high. 

The employees self-organized taking ownership for quality and defects, and to remedy the defects. This led to better quality and employees asked for more information and more responsibility including changing training, HR, and salary structures: paying for people taking on more responsibilities rather than simply job tenure. 
Check it out.

Friday, August 8, 2008

Friday, August 1, 2008

Industrial Logic at Agile 2008

My Industrial Logic colleagues will be out in force at the Agile 2008 conference.

In order of appearance...

Tuesday
  • Brian Foote: "Agility, Evolution, Emergence, And The Primordial Ooze"
  • Mike Hill: "Throwing the Agile Transition Party"
  • Brian Foote: "Big Ball of Mud"
  • Joshua Kerievsky : "Ten Terrific Transition Tips"
  • John Tangney: "Mastering Selenium"
Wednesday
  • Mike Hill: "Clean Code Clinic: Dealing with CRRAP - Microtesting Legacy Code"
  • Joshua Kerievsky, Gil Broza: "Crafting User Stories – Four Experts And The Audience Weigh In"
  • Joshua Kerievsky: "Refactoring Strategies & Tactics"
  • Gil Broza: "Agile Clinic - Bring Your Toughest Challenges"
Thursday
  • Gil Broza: "The Secrets of High-Performance Agile Implementations"
  • Keith Ray, Gil Broza: "Refactoring for Testable C++"
  • Brian Foote: "Patterns Poster Children"
  • Joshua Kerievsky: "Estimating Considered Wasteful: Introducing Micro-Releases"

Tuesday - Friday
  • Joshua Kerievsky, Mike Hill: "Programming with the Stars"

Tuesday, July 29, 2008

next week - Agile 2008

Next week I'll be at the Agile 2008 Conference, where I'll be co-presenting a workshop with Gil Broza on refactoring legacy c++ code for testability. I might even blog from the conference. Hope to see you there.

Three rules of TDD?

A recent object mentor blog entry said:
We had an interesting result during that class. One group was practicing Bob’s three rules of TDD (paraphrased);
  • Write no production code without failing tests
  • Write only enough test code so that it fails (not compiling is failing)
  • Write only enough production code to get your tests to pass.
But they ended up with a bit of a mess. Following the three rules wasn’t enough. These rules are guiding principles, but those three rules mean nothing if you forget about clean code, refactoring and basic design principles [...]
Maybe the cause of the mess were the rules they used. I remember the rules more like this:
  1. Write enough test code so that to get a single test failure.
  2. Write enough production code to get all your tests to pass.
  3. Refactor until the code is Simple/Clean. (See elsewhere for the Rules of Simplicity/Clean)
As Brett Schuchert points out in that blog post, leaving out the refactoring step puts you onto the road to certain doom.

Monday, July 28, 2008