Larry Price

And The Endless Cup Of Coffee

Tags in C++ Cucumber Tests

| Comments

The project I’m working on is slowly adding Cucumber acceptance tests to our massive code base in order to replace aging Robot tests. One would think that getting developers on our team to use Cucumber would be east, since it uses googletest and googlemock which we use for our unit tests. Unfortunately, very few people on the team have been motivated to write integration tests using the new framework, so I have very few people to go to when I have problems writing my own integration tests.

The area of the code I deal with uses embedded mono to communicate with some C# libraries that we share with other applications. This means we have unmanaged memory which talks with managed memory. This has caused us more headaches than I care to remember. One such problem is that we have a static object that we only want to create and destroy once. So I write my first Cucumber test:

DoStuff.feature
1
2
3
4
5
6
Feature: Do that thing that we have to do

Scenario: Do it my way
  Given I have done step 1
  When I do step 2
  Then I should see results
DoStuff_StepDefinitions.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <cucumber-cpp/defs.hpp>
#include <gtest/gtest.h>
#include <mono/jit/jit.h>

const QString DOMAIN_NAME = "bridge";

class Context
{
  // The static Mono object
  static MonoDomain *Domain;
}

BEFORE() { Context::Domain = mono_jit_init(DOMAIN_NAME); }

AFTER() { mono_jit_cleanup(Context::Domain); }

GIVEN("^I have done step 1$") { /* ... */ }

WHEN("^I do step 2$") { /* ... */ }

THEN("^I should see results$") { /* ... */ }

Before my scenario starts, the BEFORE() function is called and my MonoDomain object is created. When the scenario ends, my AFTER() statement is called and the objects in my MonoDomain are cleaned up. Now, I add a second scenario.

DoStuff.feature
1
2
3
4
5
6
7
Feature: Do that thing that we have to do

Scenario: Do it my way
  ...

Scenario: Do it your way
  ...

Now I run my Cucumber test, and Mono explodes. Why? Because the BEFORE() and AFTER() functions are not before all and after all, but before each and after each.

So what should we do? Move the function calls in the BEFORE() and AFTER() statements into the constructor and destructor of the Context class?

Same problem. Are there BEFORE_ALL() and AFTER_ALL() macros? No.

I began to panic. I asked the person who taught me how to write Cucumber tests in C++. Our idea was to create the MonoDomain during what I knew would be the first step, and delete it after what I knew would be the last step. Oh, the horror! That would mean not being able to reuse those steps, not to mention moving the creation/destruction code around anytime I wanted to add new steps or change the order of my previous steps. We also thought about making specific steps and sticking them at the front of the first scenario and at the end of the last scenario. This still meant that the lay developer would have to recognize these first and last steps from the others. I asked my local senior engineer, and his advice was to create separate Cucumber tests for each scenario I intended to create. My plan was to write 6 scenarios in the long-term for this feature, and I really didn’t want to turn these very similar tests with beautifully reusable steps into 6 features.

Then it hit me: Cucumber is open source. I found the source on Github and started looking through the example code. It was there that I discovered tags. Tags were the solution to my problem.

DoStuff.feature
1
2
3
4
5
6
7
8
9
Feature: Do that thing that we have to do

@first
Scenario: Do it my way
  ...

@last
Scenario: Do it your way
  ...

Using tags, I could label my scenarios with meaningful @first and @last tags to signify the beginning and end of my tests. The trick is to then add the required tags to my BEFORE() and AFTER() macro as such:

DoStuff_StepDefinitions.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <cucumber-cpp/defs.hpp>
#include <gtest/gtest.h>
#include <mono/jit/jit.h>

const QString DOMAIN_NAME = "bridge";

class Context
{
  // The static Mono object
  static MonoDomain *Domain;
}

BEFORE("@first") { Context::Domain = mono_jit_init(DOMAIN_NAME); }

AFTER("@last") { mono_jit_cleanup(Context::Domain); }

// ...

Now my MonoDomain is only created before the scenario labeled @first and after the scenario labeled @last. Obviously, this isn’t the cleanest fix imaginable, but it was the cleanest fix available. Whenever someone wants to add a new step to this test, they need to remember to move the @last tag to their scenario. However, I have the hope that it will be pretty obvious that the second scenario is no longer “last” when there is a third scenario following the “last” scenario. Anyway, it leaves me happy enough, since now my tests don’t explode and I’m able to reuse ~50% of the steps I had already written for the first scenario. I added a third scenario later on and 9 out of the 10 steps in the scenario were reused from the first and second scenario.

There are lots of other cool things you can do with Cucumber tags, like having multiple tags on objects. All tags that match @first will do one thing, but tags that match @first and @second can have multiple BEFORE() or AFTER() clauses.

Changing Plans

| Comments

Your code is being sent to the dump.

Don’t take it personally. Your code isn’t bad. It’s just garbage.

Maybe your code wasn’t written the way they wanted you to write it. Or maybe they realized that they had already written this code three months ago. Or maybe the customer suddenly decided that they don’t need their smartphone to emit fragrances based on the text message they just received.

The “why” doesn’t matter. Plans changed. Your unused code isn’t aging well and it’s starting to stink up the place, so just do us all a favor and get it outta here!

As developers, we always take this kind of thing personally. Our code is an extension of ourselves. When we feel good, we write code that’s clean and concise. When we feel meh, our code is unimaginative and takes longer to write. When we feel bad, we litter the code with variables that don’t do anything and then name them after our managers.

But it’s not personal, is it? Management doesn’t sit in their mansion each evening, sipping a gin martini while adjusting their toupee, thinking about how worthless you are and how to properly punish you while continuing to pay you. Management has better things to think about, like ditching the toupee in favor of hair plugs or Rogaine or whatever hair fad is popular that day.

Plans change. You can lament your loss of three days of “ingenious” code that will never see the light of day, but management will be equally depressed about the hundreds (thousands?) of dollars lost paying you to work on something that’s not production-worthy. You may feel cheated in the short-term, but hopefully you can get something positive out of this change of plan. Maybe your second attempt at the code will jive better with the base architecture, or maybe you’ll be able to extract the functionality you need out of another component and limit code duplication, or maybe you’ll be able to deliver a different feature that the customer can actually use.

Sure, there may be an occasional senior engineer who thinks that the program should be implemented his or her way, and will make you throw out anything you write that has any deviation from The Plan (which never quite made it out of their heads and into any documentation). Usually you can satiate that senior engineer by listening to them and nodding your head for a few minutes. There’s a reason that engineer carries so much weight on the project, so they’ll probably be making a valid point while you nod your head and they’ll respect you for agreeing with them, even though you secretly wish you could just keep doing it the way you originally planned.

Don’t cry over spilled milk. No one’s actually questioning your coding competency when they change the plan. The odds are in your favor that the plan changed in the best interest of the project, and whatever code is being thrown out is likely a necessary casualty to benefit the system as a whole. Remember that most of the code you write is used, at least for a little while, so try not to dwell on the code that isn’t.

What's Still Possible

| Comments

If every Miss America candidate had her way, there would be peace on Earth and all the hungry mouths would be fed. While Earthlings enjoy violence and controlling others too much to achieve world peace, I have a proposal to help feed those around the world who don’t have enough to eat.

It’s not an ad campaign. I’m not going to send random people a nickle in the mail and then tell them that they could use that nickle to feed a starving child. I’m certainly not going to change any of my eating habits. I happen to know a huge source of food that we underutilize. My plan is to kill two birds with one stone. Well, preferably something like 3 million birds with however many stones it takes.

I’m talking, of course, about the terrible tyranny of the Canadian Goose. A little history:

Our ancestors domesticated Canadian Geese in ancient times and used these waterfowl for various acts of labor, including pulling tugboats down the Mississippi, plowing the great Canadian rice paddies, and keeping our elderly company during their final days of life. The young goslings flapped gingerly in the meadows pollinating the wildflowers, apple trees, and various other meadow-related objects. Much to our delight, some of our beloved geese bretheren became sentient, and started selling us medical insurance while performing a spot-on Gilbert Gottfried impression.

False. I must apologize for fooling you in this way sweet, sweet reader, but everything you read in the last paragraph was neither true nor fact. In reality, Canadian Geese serve no purpose. Canadian Geese were created accidentally during the Manhatten Project while one of the lab techs from the local university was trying to combine nuclear fission and the bubonic plague to get back at his ex-girlfriend for cheating on him. He quickly became bored of this task when she stopped responding to his texts, and thusly tossed the waste from his experiments in the river. The rest, of course, is history.

Now here we are. There are well over 3 million Canadian Geese nationwide, which is decidedly more than anyone finds pleasant. These geese are no longer afraid of humans, so they tend not to run away from us. In fact, we have spoiled the birds so much that some geese will actually approach humans demanding a bite of stale bread. If no bread gift is offered, the foul fowl will emit a frightening hissing noise, raise its wings, and chase off the poor human. Any sidewalk near a pond quickly becomes covered in goose byproducts during the breeding season, which might as well be year-round. I, for one, think that the geese have gone too far. They ruin our picnics, our walks in the park, our egg-stealing competitions, and our feather-collecting scavenger hunts. It’s time for the final showdown: Man versus Goose.

Time to tie in the beginning and the parts where I raved like a lunatic: We hunt the geese, and we feed them to people. ‘Nuff said.

People already hunt geese, of course, but it’s clearly not enough. Not to mention that these hunters currently just leave the gooseflesh in the woods where lower animals reap the rewards. I propose we extend goose season year-round, and provide free boxes to encourage hunters to package the gooseflesh and send it to the needy in other countries. We’ll poison our waterways to take out as many geese as possible, and we will make a wondrous soup for whomever needs it.

It’s still possible to feed the hungry. But we need to focus in order to do it. Man versus Goose is not the solution. It’s a demonstration of getting distracted from the original cause. The next time someone tries to get you riled up about feeding the hungry through some crazy scheme, remember that there’s no better way than addressing the problem directly. It’s still possible to do good in this world if you can avoid the crazy.

Blog Battle: Pvreryvre of Fyne Coddes

| Comments

Ice pellets bounced off my head as I walked myself home late one night. The air was dreadfully cold, so I swooped into one of Carmel’s seedy side alleys to take a shotcut. Out of the shadows crept a man wearing a long trenchcoat and thick-rimmed glasses. Hunched over, he brushed his unkempt hair out of his eyes. His coffee-stained breath rushed from beneath his pencil moustache as he asked, “Can I interest you in any of these fine iPhone apps?” I tried to cautiously back away. “How would you like a real BaZynga game, only ninety-nine cents, it’s called Perturbed Birds with Pals?” I was briefly distracted by sirens in the distance; by the time I returned my glance to the man’s last position he had disappeared, my virtual wallet was empty, and my phone was filled with bloatware and repetitive ‘Ville-style games.

There are more KLOCs in this world than there have been McDonald’s hamburgers sold. How do the good programmers differentiate themselves from the common street peddlers? How do companies convince you to pay $2.99 for their app when a clone is released less than a week later for free?

The answer? Maybe they don’t. Maybe a comparison can be made between software companies and pharamceutical companies.

Big Pharmaceutical companies spend many years researching, developing, and testing drugs to treat the common cold, arthritis, bad cholesterol, or even to sedate your energetic children. These drugs spend several years on the market where patents on the drug are valid, meaning that only the company that invented the drug can legally sell it. After the patent protections expire (approx 7-12 years), any big, small, or mom & pop drug manufacturer is legally allowed to “clone” this drug and make what’s called a “generic.” Generics are sold at a fraction of the cost of the original drug. At this point, no one wants to give Big Pharma $20 for 6 tablets to cure their heartburn when they could pay $5 for a year’s supply of generics.

Software companies tend to spend somewhere between 12 weeks and 12 months developing apps that will be consumed by the general population. If the company just released an Android or iOS app, then the product will stay relevant somewhere between 2 weeks and 2 years. After that time, the app will either no longer have market value or will need to be revamped to please the modern consumer. Within a short number of days or weeks, there is a high probability that surly software pirates will begin to copy your app and put it on the market for free. At this point, no one wants to give your company $4.99 for an endless runner when they could just as easily find a copy for free. Of course, app developers can submit complaints and get the pirated app taken down, but more and more will crop up as time goes on, and eventually it won’t be worth the trouble to get the doppelgangers removed.

For both industries, a company comes up with a novel idea and presents it to the world. People who like that product can start associating the brand name with other products. After recognizing the brand, a person may start to trust that company and look for other products associated with the brand. That company will become known as a purveyor of fine wares.

So here we stand, reader. Make code that you can be proud of; not for getting tens of thousands of downloads, but for scrawling your good name on the white boards of the world in Sharpie. The customers will keep coming back as long as you’ve got the cure for what ails them.

Code Complete Second Edition

| Comments

Design is a process of carefully planning small mistakes in order to avoid making big ones. – Steve McConnell

The Gist

Code Complete Second Edition by Steve McConnell is the ultimate programmer’s handbook, though certainly not a pocket guide considering its massive 850+ page size. This book contains a seemingly endless amount of information regarding the state of programming circa 2004. Topics range from extremely technical, such as making code readable above making it clever, to office politics, such as dealing with non-technical managers.

My Opinion

McConnell has written an encyclopedia for software development. In doing so, the book sometimes suffers from the “wide as an ocean, shallow as a puddle” complex. Nonetheless, the book holds an incredible amount of information that I found refreshing to see in print.

The use of the term “construction” to refer to coding throughout the book is an apt analogy for McConnell’s views on the world of software development. Before beginning construction, a team should have a plan. Construction requires a solid base. While constructing a project, individuals should ensure that anyone else could look at their part of the project and figure out what’s happening. Working with a partner often improves quality. People doing construction should test their work to ensure the integrity of their product. Redoing lower levels causes a lot of pain. The team is unlikely to hit the original due date. Etc, etc.

Many things in this book go directly against what I was taught in at university. McConnell recites a quote several times in the book:

Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, you are, by definition, not smart enough to debug it. – Brian Kernighan

At university, we’re taught all the secrets of writing clever code: pointer manipulation, recursion, inappropriate variable reuse, and others. We were also never taught to plan ahead (…besides flowcharts, which were never required) or test, both of which McConnell highly recommends as necessary steps in software development. It’s no wonder my programs took so long to debug! Of course, I’ve learned to perform these tasks naturally while working as a Real Life Programmer. Reading this book is likely more helpful than taking the first few semesters of programming at university.

A small issue I had was a wishy-washy attitude towards comments. In one chapter, McConnell describes having minimal comments in a code and keeping it mostly self-documenting. He then goes on to show all kinds of different, horrifying comments and justifies why they are sometimes okay.

This is where I will note that Code Complete Second Edition is a book published by Microsoft Press. I was often surprised by McConnell’s adamance that Visual Basic is the most popular programming language at the time of publishing. Even circa 2004 (the year this book was published), the Tiobe index shows VB behind Java, C, and C++. The PyPl index also shows VB behind Java, PHP, C, and C++ in 2004. For the record, VB is a silly language.

Who Would Like This

This book would be nice required reading for students. Given the length and technical depth, it’s practically a textbook. Developers a few years out of university would still enjoy this text, but some topics are so obvious or overdone that many readers may start skipping chapters. If a developer knew of precisely the area he or she wanted to improve, then said developer could likely benefit from perusing a chapter of this book covering that topic.