Monday, September 26, 2016

SonarLint for Eclipse Does Not Analyze Test Files by Default

I say unit tests are code like any other code. As such, they deserve to be refactored and kept clean.

I learned today that, by default, SonarLint for Eclipse disagrees. If you select Window->Preferences->Sonar Lint, you will see that "Test file regular expressions" contains "**/*Test.*,**/test/**/*":

For SonarLint to behave the way I want, which is to treat any file whose name ends in ".java" as code, I have to clear the regex.

Wednesday, September 21, 2016

Legacy Code: Characterize or Test Protect?

In the context of working with legacy code, I often hear the terms "Characterization Tests" and "Test Protecting". Here is how I think about each term:

Characterization Tests: a suite of tests that I build against legacy code that uses sufficient representative inputs to convince myself that I have characterized the behavior of the object I am testing. This suite also documents the behavior.

Test Protecting: building a suite of tests against legacy code that covers the object under test sufficiently that I am confident that the suite protects me from inadvertently changing the object's behavior during refactoring or when I add features.

One thing that is interesting to me is that the exact same suite of tests can both characterize and protect an object's behavior.

I was running a workshop today and introducing the concept of test protecting. Here are the steps I introduced today. If you are new to test protecting, they should be a good starting point. If you've done some test protecting, I hope you'll find some new nuance to your understanding. If you're already awesome at test protecting, maybe you'll want to teach from my steps, or comment with your insights about test protecting.

Steps I Teach to Test Protect Legacy Code:

Select a class to protect. 

Usually this is the class that I need to fix a bug in or add a feature to. Or maybe I have a few spare cycles and I want to add coverage to a frequently edited class. I do not select a rarely-modified class to test protect - that would be a waste of time (and thereby money, mine or my employer or client's)

Create a test class.

Legacy code, by one definition is code that doesn't have tests, so it follows that a legacy class won't have a test corresponding class. Create a test file with a name and location that follows your unit testing framework's conventions.
(Commit to your version control.)

Choose a public method to start with.

Often legacy classes are large and complex enough that it is difficult to test protect them well through only the public methods. I see several options (of varying risk) in that case:

  1. Change private methods to public
  2. Change private methods to package protected
  3. Don't protect private methods that are difficult to test through public methods.
  4. Refactor the class so that it is easier to test.
  5. Use a testing tool that allows you to test non-public methods.
  6. Protect as much as you can in a reasonable amount of time, assess risks posed by unprotected code, then decide on your next action.
The only answer that I am comfortable with is number 6.

Write a test that exercises the method you selected.

If you are at least somewhat familiar with the behavior of the method you selected, think about edge case inputs and happy and sad path inputs. Choose one to start with. Some devs like to start with edge cases, some like to start happy or sad path. I'm not sure it matters.

Give your test an absurd assertion against the result.

This step is as much like characterization as it is like test protecting. I want to be sure my test fails before it passes, so I choose a value that is unlikely to be correct. For instance, if the method I am exercising is:
int lookupDogAverageWeightLbs(string breed);
then I will choose a number like 5000:

assertEquals(5000, lookupDogAverageWeightLbs("Goldendoodle"));

Run the test so it fails.

In the previous example, your test should fail with a message something like:
Expected [5000] got [40].
If it doesn't, check your assumptions and look for mistakes in your exercising of the method or in how you wrote your assertion.

Fix the test so it passes.

When we test drive, we assert what the expected value should be, run it to see it fail, and then write the least amount of code needed to make the test pass. In test protection, the existing implementation is the standard behavior, so we fix our expectation to make the test pass. From absurd fail message above, you can easily see the actual result delivered by the implementation and fix the expectation with it so that the test passes:
assertEquals(40, lookupDogAverageWeightLbs("Goldendoodle"));
(Commit to your version control.)

Examine the test coverage of the method you are exercising.

If your coverage tool doesn't automatically run when you run tests (why doesn't it?), then run your coverage tool. Find which lines of your exercised method are not executed by your first test. If there are none, your method is test protected.

Write another test that hopefully increases coverage. 

Write a new test and give your exercised method new input data. Use inputs that, based on whatever understanding you have of the method so far, will exercise a non-covered line. Sometimes the name of the method will give you an idea, sometimes you will have gleaned some tentative understanding by scanning the implementation code while looking at coverage, and sometimes you still won't have a clue. Pick new inputs however you can and run your test.

Get the new test passing.

You might have needed to write a green test in order to increase the method's coverage. That's ok. In test driving, a test that doesn't go red before going green is worthless and time-wasting at best and possibly dangerous at worst. But in test protecting, such a test is only worthless if it does not add to the method's coverage. If your new test didn't increase the method's coverage, change your inputs until it does. This is another difference from when we test drive. When we test drive, we choose a set of inputs that fail and implement code to make it pass. We change the inputs only if the ones we chose did not make the test fail.
(Commit to your version control.)

Check the coverage of your method again.

If you have not covered all the lines in the method, jump back to "Write another test that hopefully increases coverage." If you have covered all the lines in the method, start over again with"Choose a public method to start with." If you've covered all the lines in the class, you have test protected the class. Congratulations!

Make sure new tests are run in CI.
If there are already other test classes in your project, your continuous integration server may already be configured to run tests in all test classes. If not, adjust your CI server's configuration to be sure that it runs your new tests. Kick off a build and inspect the build output to be sure your new tests ran.

Monday, May 9, 2016

Jokes and Fun and Safety at Work

Something happened at a conference I recently attended:

Between sessions, there was a long line at the men’s room. There was little or no line at the women’s room. Behind me in line, out of my vision, I heard a man say:

“Maybe we're all starting to feel transgender right now.”

If you didn't cringe when you read that, I get it. In a way, it is a clever nod to all the happenings related to the recent North Carolina bathroom law.

But I cringed when I heard it, and I cringe each time I read it again. Unfortunately, that comment is hurtful. Would a transgender man feel welcome hearing that? I can't imagine one would.

I'm sure that the comment was not intended to be hurtful. But if a transgender man heard it, and I can't be certain that one did not, I expect it would have a hurtful impact. And if we want a better workplace and a better world, I believe we have to take responsibility for the impact of our actions, not just our intentions.

I believe everyone wants a fun work environment, and jokes can certainly be part of that. But I'm hoping that we can create cultures that push women and members of marginalized groups out of IT less. When someone is outnumbered in a setting, it can be hard to speak up about what feels OK and what doesn’t, especially if the rest of the group seems to (even if silently) condone something. I understand - rocking the boat about culture can be a risk to employment. As white, heterosexual men, we are probably not experienced with what can feel hurtful to people different from us. I try to honor and believe people’s life experiences. Even if I can’t see how something can be hurtful, I try to believe people when they say something is.

All of this means that I try to avoid humor that is sexually charged, comments on people’s bodies, or touches on race, religion, sexual orientation, gender presentation, and other characteristics of members of marginalized groups.

And if a joke like that slips out and I notice, I don't wait for someone else to point it out. I call myself out on it and acknowledge the possible impact, even though it wasn't my intention.

Saturday, May 7, 2016

Slides from my Diversity in IT talk at Agile and Beyond 2016 are Now Available

At Agile and Beyond 2016, I presented: "Why Should I Go See Another White Man Talk About Diversity in IT?" I spoke mainly about how women and members of marginalized groups are often made to feel unsafe or unwelcome at IT companies, usually without men realizing the impact of what we are doing.

I've put my slides up (link below). If you are interested in the topic, please take a look. I have included many links to information and resources.

slides - scroll down below my profile to find the .pptx

Wednesday, May 4, 2016

A New Adventure - Same Employer, Same Client!

For the last ten months, I have been a software developer on a high-functioning, reference team at a major enterprise client. The team is a great group of people, with solid processes, and has been delivering defect-free code and providing mission-critical business value since before I joined them. But my time as a member of that team has drawn to a close.

Starting Monday, I will be moving within that same client to join the coaches in their Agile Center of Excellence. This new role will allow me to use more of my personal, social, coaching, and training skills, and will no longer involve creating production code on a cadence.

I am really excited for my employer, my client, and myself. The change comes at a time when the development team is beginning a pre-planned size-down, so my employer has somewhere to place me immediately. My client can continue to benefit from my accumulated domain experience. Both will be getting their best value by paying for work that I excel at, and I'll be doing work that I have a deep passion for.

Thursday, March 31, 2016

On Privilege

What do I mean by “Privilege”? Privilege is a set of advantages that I receive, without earning them, merely because of my birth circumstance(s). Privilege is different than prejudice or “ism”s. As a person of privilege, I get the advantages even if don’t have prejudice and don’t engage in overt oppressive activities like sexism or racism.

Some examples of my privilege as a white man include:
• I can go to any workplace and expect to see people who look like me
• If I make a mistake, no one will say that it’s because white people are stupid
• The lead roles in movies and tv shows are usually of my color and gender
• If I have children and a career, I won’t be called selfish for not being home with the children
• I am more likely to get a job than an equally qualified applicant who is a woman and/or person of color

There are many types of privilege, including (specific examples and details can be found by following the links):
White Privilege
Male Privilege
Heterosexual Privilege
Able-bodied Privilege
Class Privilege
Religious Privilege
Cisgender Privilege (contrast with transgender)

You may say: “But I have struggled! I don’t have privilege!” Privilege isn’t about whether I am powerful, wealthy, have a good job, have worked hard all my life to get where I am, or struggle every day. Privilege is simply unearned advantages I get because I belong to a group.

Sometimes when people learn about the concept of privilege, people feel guilt?  If this happens to you, ask yourself where the feeling is coming from. Is it because:
• I never noticed it before?
• I act in ways that make this worse?
• I don’t do things that make it better for people without privilege?

Now that you know about privilege, what can you do about it? You can:
• Read about privilege
• Stay on the lookout for other privileges you might discover you have
• Belive the life experiences of people with less privilege
• Ask yourself if your actions or policies reinforce the advantages of certain privileged groups
• Don’t “help” less-privileged groups - it robs them of agency. Instead amplify their voices (retweet, etc)

Wednesday, March 2, 2016

Pair Programming "Out Loud"

One element of Pair Programming that I find key to success is "Programming Out Loud". When I have the keyboard and mouse (driving), I want to be explaining my train of thought to my pair partner, moment-by-moment. Conversely, if I am the non-keyboard partner (navigating), I want my partner to be explaining their thoughts moment-to-moment. If my partner is practicing "silent pair programming", I try to ask ask questions like: "What's next?" or "Where are we headed?" to try to get them talking about what they are thinking or doing. Or if that doesn't help, I can ask to drive for a while and try and draw out their ideas that way. Usually things don't go this far, unless my partner is new to pairing. When I start to go off silent and solo, my partner usually invites me back into collaborative mode.

But what if my partner is the navigator and they are disengaged? I can ask (slightly tongue-in-cheek): "Are you with me?" It can require courage to "call out" my partner in that way, but sometimes it takes courage to be on a successful agile team. And if I'm the disengaged navigator and I catch myself being distracted, I can ask to write the next test to try and focus myself back on what we are doing.

Do you have ways that you draw a distracted partner back into collaboration? Or do you have ways to get yourself back into collaboration?