Friday, May 18, 2012
Agile Does Not Mean Being Micromanaged
Today I joined some friends (ex-coworkers) in a goodbye party for an ex-coworker who is moving on to greener pastures. I haven't seen several of these people in a few years, so naturally they asked "What are you doing now?" And I told them that I am an agile coach. And I got asked "And you haven't killed yourself yet?"
Clearly, something is wrong here.
A little background: the company I used to work for was acquired and 'Agile' was imposed upon my old friends. This is an 'Agile' which may be far too familiar to some of you, but I've only heard stories of it before. At the party, two separate people told me they thought 'Agile' was intended to turn programmers into replaceable sprockets who need not think. For example, if they come across a bug in the system, they are supposed to create a defect in the tracking system and move on. Someone will add it to a sprint sometime. Or not. All decisions are made by project managers, and handed down.
The Agile Manifesto and the Agile Principles are a good place to start to validate whether an organization is acting in an agile way. "Individuals and interactions over processes and tools" from the manifesto, and "Build projects around motivated individuals" from the principles both give us an indication of the role of management in these environments: contribute, don't control.
Sunday, May 6, 2012
Why We Refactor
I have always enjoyed Mike Taylor's Reinvigorated Programmer, probably because he so obviously enjoys several things I also enjoy (Doctor Who, programming, Buffy The Vampire Slayer, sushi). I was perusing some of his posts from the last year and came across the following comment regarding the process of refactoring code:
"the purpose of all that shuffling is really only to get the deck clear so we can concentrate properly on the hard bits without getting distracted by crud".
"the purpose of all that shuffling is really only to get the deck clear so we can concentrate properly on the hard bits without getting distracted by crud".
I think this is missing the point. Refactoring give us tools for rigorously transforming code. There are several reasons why this might be useful. One reason is that the programmer before us was an incompetent buffoon Another reason is that we work in and with teams, and collaborative work tends to get messy with time. We need to perform housecleaning so the technical debt doesn't cause us to go bankrupt.
These reasons are largely in line with what Mike is suggesting, I think. However, there's another reason to perform refactorings on a regular basis, and it is crucial to how we work as programmers.
The code you wrote six months ago (or six weeks ago) solved one particular problem pretty well. This is probably not the exactly problem you're trying to solve anymore. The requirements may have changed (accounting suddenly really _does_ want to run reports against itemized receipts), or maybe you just saw a better way to code the whole thing. Now you've got to pull all the affected abstractions up to the new world order. Classes start to fit together differently. Design patterns get replaced by different patterns, or disappear altogether. Engines suddenly find themselves servicing wholly new systems.
The way forward is with the refactoring tools. Instead of rewriting the system to conform to our new way of thinking, we can transform it. We can mold it so it continues to fit our needs. And we prefer this to a rewrite because it is less costly, we can deliver with only half of the transformation done (usually) without unduly impacting features, and the new designs practically write themselves.
I think "the hard bits" Mike references are exactly where refactoring shines. Making sure the performance profile is acceptable is a refactoring task. Ensuring the application is extensible through plugins is an exercise in refactoring. Extracting out the timer behaviors from the license module to be reusable is refactoring; so is reconciling the 3 different timers you just found in the system, because they were disguised as something else. Refactoring touches nearly everything we do, so we really need to make sure we do it well.
Tuesday, May 1, 2012
How Do You Name Your Tests?
How do you name your classes? You probably think of the noun or verb which best describes the behavior you want; perhaps there are some technical details which slip through like the name of a design pattern. But generally, a class' name should tell you what that class is responsible for. (Edit: Jeff Langr and Tim Ottinger have written an excellent article on the mechanics of how to name your tests.)
Methods are easier to name, perhaps because we do it so much more often. Usually, you'll decide that the method is important because of the return value or the side effects on the enclosing class. Then try to communicate that in as few characters as possible.
Test fixtures and methods are different. A test name doesn't communicate what the test does, it communicates what SOMETHING ELSE does.
Let's look at some common naming conventions used in tests. Our System Under Test will be a Video Store billing system.
TEST_F(BillingTest, WhenRentingARegularMovie_GoodCustomerGetsOneFrequentRenterPoint)
TEST_F(BillingTest, CustomerWithNoLateFeesGetsOneFrequentRenterPointWhenRentingOneRegularMovie)
These two examples are pretty standard fixture names. Specifically, they just tell you the system being tested at the macro level. This may be common at the early stage of TDD because you haven't extracted subsystems yet. This is expected to change as development continues.
TEST_F(CustomerTest, WhenRentingARegularMovieGoodCustomerGetsOneFrequentRenterPoint)
This example names the fixture after the subsystem being tested. There's duplication between the test method name and the fixture name because there's a subset of Customers which we're concerned with. This will happen eventually to every test named this way.
TEST_F(GoodCustomerTest, WhenRentingARwegularMovieGetsOneFrequentRenterPoint)
This example learned a small lesson, and named the fixture after the general condition of the subsystem, thus eliminating the duplication.
TEST_F(CustomerFrequentRenterPointTest, WhenRentingARegularMovieGoodCustomerGetsOne)
This example tries to describe the effect as if it were the system under test. It is common to confuse the two, but it confuses the writer of the tests as much as the reader.
TEST_F(CustomerInGoodStandingRentingOneRegularMovie, GetsOneFrequentRenterPoint)
The last example demonstrates two features of good naming. The first derives from the fact that the fixture is used to share setup between tests, and so can be explicit about what is being shared.
The second feature is that the test method tells you what behavior to expect before the condition under which to expect it. This puts the emphasis of the test on the property of the system which the test is exercising. You would expect to see tests in the same fixture to be easy to compare against eachother. For example:
TEST_F(CustomerInGoodStandingRentingOneRegularMovie, GetsOneFrequentRenterPoint)
TEST_F(CustomerInGoodStandingRentingOneRegularMovie, Pays1_95ForOneDay)
TEST_F(CustomerInGoodStandingRentingOneRegularMovie, Pays2_95ForTwoDays)
Tests document our systems' expected behavior, and names play an important part of that. You want names which help navigate through that documentation. Put the most important information about your system at the first place the next coder will look: the beginning of the test method name. And if you've got underscores in your name to separate the parts, you're probably doing it wrong.
Monday, March 12, 2012
6 Tips For Writing (Code)
I came across a list of 6 tips for writing by John Steinbeck: http://www.brainpickings.org/index.php/2012/03/12/john-steinbeck-six-tips-on-writing/ . This struck me as being somewhat applicable to programmers, so I tweeted such. And now, I want to expound on that idea.
Abandon the idea that you are ever going to finish. Lose track of the 400 pages and just write one page for each day. ...
This is all about having a maintainable pace. A maintainable pace is valuable to the writer and the programmer in part because it relieves burnout. But it is also valuable to the editor and Product Owner because it provides an unmatched ability to forecast delivery.
... Never correct or rewrite until the whole thing is down. Rewrite in process is usually found to be an excuse for not going on. ...
This is a partial quote, which indicates that the association between writing an programming is a bit loose. However, it does remind me of Kent Beck's "Make it work, make it right, make it fast." Don't refactor or redesign until you've got enough written to know what you're talking about. You may think you need a set of metric unit types, but unless you've got some code which tells you that you're getting ahead of yourself. Solve only the problems you can prove that you have.
Forget your generalized audience. In the first place, the nameless, faceless audience will scare you to death and in the second place, unlike the theater, it doesn’t exist. ...
I've seen plenty of in-house code which was designed to withstand the application of a malicious or incompetent programmer. It's a waste of everyone's time. You cannot design around a malicious coworker, and you cannot protect yourself against an incompetent programmer. Instead, determine what kind of programmer your organization hires (you, for example), and write code for that person. Your real audience is you two weeks or six months after you wrote the code.
If a scene or a section gets the better of you and you still think you want it—bypass it and go on. When you have finished the whole you can come back to it and then you may find that the reason it gave trouble is because it didn’t belong there.
If you can't think of a good class/method/function/field name, maybe you don't really understand what you're trying to accomplish with it. If you're having problems making your code generic, stop. Come back later when you understand the problem better.
Beware of a scene that becomes too dear to you, dearer than the rest.
This is applicable in nearly every corner of life. Code or architecture which you are attached to becomes difficult to change. Change is the lifeblood of a programmers process. The code changes as your understanding of the problem changes. The code changes as the customer's demands change. The code changes as you learn new techniques. Anchors will drown you in your seas of change.
If you are using dialogue—say it aloud as you write it.
This relates to naming things, especially systems of things, and especially test methods. When you say the name of a method, it should be easy to turn into a sentence. The receiver is usually the object, the method is usually the verb and adverb. The parameters are usually the grammatical objects. When you follow this advice, you get a rich vocabulary for the domain. And you almost never succumb to Primitive Obsession.
So, there you have it: six tips for writing code. It's an imperfect but useful mapping from creative writing to programming. Programmers can learn much from authors, and maybe we can teach them a thing or two in return. But keep in mind that they've been at it for a few millennia. Us, not so much.
Abandon the idea that you are ever going to finish. Lose track of the 400 pages and just write one page for each day. ...
This is all about having a maintainable pace. A maintainable pace is valuable to the writer and the programmer in part because it relieves burnout. But it is also valuable to the editor and Product Owner because it provides an unmatched ability to forecast delivery.
... Never correct or rewrite until the whole thing is down. Rewrite in process is usually found to be an excuse for not going on. ...
This is a partial quote, which indicates that the association between writing an programming is a bit loose. However, it does remind me of Kent Beck's "Make it work, make it right, make it fast." Don't refactor or redesign until you've got enough written to know what you're talking about. You may think you need a set of metric unit types, but unless you've got some code which tells you that you're getting ahead of yourself. Solve only the problems you can prove that you have.
Forget your generalized audience. In the first place, the nameless, faceless audience will scare you to death and in the second place, unlike the theater, it doesn’t exist. ...
I've seen plenty of in-house code which was designed to withstand the application of a malicious or incompetent programmer. It's a waste of everyone's time. You cannot design around a malicious coworker, and you cannot protect yourself against an incompetent programmer. Instead, determine what kind of programmer your organization hires (you, for example), and write code for that person. Your real audience is you two weeks or six months after you wrote the code.
If a scene or a section gets the better of you and you still think you want it—bypass it and go on. When you have finished the whole you can come back to it and then you may find that the reason it gave trouble is because it didn’t belong there.
If you can't think of a good class/method/function/field name, maybe you don't really understand what you're trying to accomplish with it. If you're having problems making your code generic, stop. Come back later when you understand the problem better.
Beware of a scene that becomes too dear to you, dearer than the rest.
This is applicable in nearly every corner of life. Code or architecture which you are attached to becomes difficult to change. Change is the lifeblood of a programmers process. The code changes as your understanding of the problem changes. The code changes as the customer's demands change. The code changes as you learn new techniques. Anchors will drown you in your seas of change.
If you are using dialogue—say it aloud as you write it.
This relates to naming things, especially systems of things, and especially test methods. When you say the name of a method, it should be easy to turn into a sentence. The receiver is usually the object, the method is usually the verb and adverb. The parameters are usually the grammatical objects. When you follow this advice, you get a rich vocabulary for the domain. And you almost never succumb to Primitive Obsession.
So, there you have it: six tips for writing code. It's an imperfect but useful mapping from creative writing to programming. Programmers can learn much from authors, and maybe we can teach them a thing or two in return. But keep in mind that they've been at it for a few millennia. Us, not so much.
Monday, December 5, 2011
Reducing Extract Method on a Reduce Loop
Let's say you have code like this, wherein totalYs is being used for multiple purposes, including accumulate the Y values within the collection of Xs.
You can start isolating the Y accumulation (to extract to a method) by introducing a temporary variable.
Then, replace all instances of totalYs within the loop:
int totalYs = ...;
Collection<X> xs = ...;
... something that uses totalYs ...
for (X x : xs ) {
totalYs += x.getY();
}
...
process(totalYs);
You can start isolating the Y accumulation (to extract to a method) by introducing a temporary variable.
int totalYs = ...;
Collection<X> xs = ...;
...
int tmpTotalYs = 0;
for (X x : xs ) {
totalYs += x.getY();
}
totalYs += tmpTotalYs;
...
process(totalYs);
Then, replace all instances of totalYs within the loop:
int totalYs = ...;
Collection<X> xs = ...;
...
int tmpTotalYs = 0;
for (X x : xs ) {
tmpTotalYs += x.getY();
}
totalYs += tmpTotalYs;
...
process(totalYs);
Finally, you can extract your method easily, and inline the temporary variable:
int totalYs = ...;
Collection<X> xs = ...;
...
totalYs += collectYs(xs);
...
process(totalYs);
Now, totalYs is much easier to manipulate. The lure of this transformation is that tests will pass at every step.
BTW, this will work for any associative operation with an identity value in place of addition.
Chris
Wednesday, August 10, 2011
Feedback Loops
Remember when you were in school, and your teacher was handing back your homework? You probably got a number or letter near the top of the paper indicating whether were going to have trouble passing the semester. That was feedback.
And as it happens, one of the worst sort of feedback.
Homework grades suffer from several serious problems: they are fed back to you far too late in the learning process, and they are discouraging when they should be informational.
However, homework grades are a perfect example of one good trait of feedback: they are highly visible.
Feedback is an integral part of a feedback loop, which is any iterative process wherein feedback from one part of the process to alter another part of the process. We use feedback loops to learn in school, such as with homework or test grades. We use feedback loops to learn to play games and music. We use feedback loops to improve at everything we do.
Well, almost everything. When was the last time you evaluated your job performance? That happens once or twice per year, right? And did your job performance improve as a result? Probably not measurably. Oddly, the place we spend most of our waking time is the place we use the fewest feedback loops.
I'm guessing that you or your boss or someone fairly high in your organization's hierarchy wants to increase the ratio of your output value to your output costs. And probably not just once. Improving performance consistently is only possible by learning from the past. And feedback loops are integral to learning.
Agile and lean methodologies evangelize short iterations of production interspersed with customer demos and team retrospection. Notice that this is a simple feedback loop. What's more, this process exhibits some of the best properties of feedback loops: there are natural consequences and the customer responses are simple (if not always pleasant) to consume.
Let's characterize feedback according to whether it is a (non-trivial) metric. A non-metric feedback might be a customer's comments after a demo, or the blinking lights telling everyone that you just broke the build. A metric-based feedback might be a graph of the count of broken builds each day in the last month or a diagram of your bottlenecks in your value stream. Some generalizations may be made about these two classes. A non-metric feedback is generally more useful the closer it is to the behavior it is meant to adjust. A metric-based feedback is often used to detect trends, and thus is more useful for longer-term behavior adjustments.
Other generalizations may be made about feedback in general. It should be relatively simple. It should be highly visible. Feedback is most potent when it takes the form of natural consequences. However, feedback which triggers negative emotions will almost always have several undesired effects. You can create (intentionally or accidentally) a virtuous cycle or a vicious cycle depending on the representation of your feedback. A broken build light will motivate a fix. A broken build stick will motivate not checking in, which is worse than a broken build.
Feedback loops are much easier to maintain whenthe feedback is collected or generated automatically. For metric-based feedback, this usually means having an automated process which regularly processes the relevant data. For non-metric feedback, this means that the process must explicitly capture the data. In the case of gathering customer comments, this may require setting the expectation early in the relationship that every iteration the customer must look at the product and tell you what they think.
The reason we use feedback loops is to measure performance of our systems over time. Metrics-based feedback are used primarily for this purpose. But, why do we care to measure the performance of our systems? To combat overconfidence. Unwarranted confidence damages the ability for people to make decisions, which in turn destroys their ability to deliver. And delivery is what Agile and Lean are all about.
And as it happens, one of the worst sort of feedback.
Homework grades suffer from several serious problems: they are fed back to you far too late in the learning process, and they are discouraging when they should be informational.
However, homework grades are a perfect example of one good trait of feedback: they are highly visible.
Feedback is an integral part of a feedback loop, which is any iterative process wherein feedback from one part of the process to alter another part of the process. We use feedback loops to learn in school, such as with homework or test grades. We use feedback loops to learn to play games and music. We use feedback loops to improve at everything we do.
Well, almost everything. When was the last time you evaluated your job performance? That happens once or twice per year, right? And did your job performance improve as a result? Probably not measurably. Oddly, the place we spend most of our waking time is the place we use the fewest feedback loops.
I'm guessing that you or your boss or someone fairly high in your organization's hierarchy wants to increase the ratio of your output value to your output costs. And probably not just once. Improving performance consistently is only possible by learning from the past. And feedback loops are integral to learning.
Agile and lean methodologies evangelize short iterations of production interspersed with customer demos and team retrospection. Notice that this is a simple feedback loop. What's more, this process exhibits some of the best properties of feedback loops: there are natural consequences and the customer responses are simple (if not always pleasant) to consume.
Let's characterize feedback according to whether it is a (non-trivial) metric. A non-metric feedback might be a customer's comments after a demo, or the blinking lights telling everyone that you just broke the build. A metric-based feedback might be a graph of the count of broken builds each day in the last month or a diagram of your bottlenecks in your value stream. Some generalizations may be made about these two classes. A non-metric feedback is generally more useful the closer it is to the behavior it is meant to adjust. A metric-based feedback is often used to detect trends, and thus is more useful for longer-term behavior adjustments.
Other generalizations may be made about feedback in general. It should be relatively simple. It should be highly visible. Feedback is most potent when it takes the form of natural consequences. However, feedback which triggers negative emotions will almost always have several undesired effects. You can create (intentionally or accidentally) a virtuous cycle or a vicious cycle depending on the representation of your feedback. A broken build light will motivate a fix. A broken build stick will motivate not checking in, which is worse than a broken build.
Feedback loops are much easier to maintain whenthe feedback is collected or generated automatically. For metric-based feedback, this usually means having an automated process which regularly processes the relevant data. For non-metric feedback, this means that the process must explicitly capture the data. In the case of gathering customer comments, this may require setting the expectation early in the relationship that every iteration the customer must look at the product and tell you what they think.
The reason we use feedback loops is to measure performance of our systems over time. Metrics-based feedback are used primarily for this purpose. But, why do we care to measure the performance of our systems? To combat overconfidence. Unwarranted confidence damages the ability for people to make decisions, which in turn destroys their ability to deliver. And delivery is what Agile and Lean are all about.
Tuesday, December 28, 2010
Toy Robots and Linux
My lovely wife purchased a LEGO®* Mindstorms NXT 2.0 kit for Christmas for me!! Yay!!
I've got a Mac Mini driving my TV, so I _could_ plug my new toy into there... But, I don't like to stand uncomfortably for long periods of time, so I'd rather plug the brick into one of my Linux machines (laptop, desktop, or netbook). Ah, but the software that comes with the toy does not support Linux. Happily, there is an active community online which likes to play with these two systems together.
My first stop was Da' Goog, where I came across http://www.krizka.net/2009/12/27/starting-mindstorm-nxt-2-0-development-on-linux/. I started following the directions.
However, I was unable to get the udev rule to create the /dev/ device for me. After much gnashing of teeth, I found that the following worked:
The only other problem that I ran into was that 'nbc' (the compiler/uploader for the NXC and NBC languages) had to be run as root due to permissions issues. I hope to get those figured out. For whatever reason, the script /etc/udev/legonxt.sh, which changes the permissions of the device file, still does not allow my user to access the brick. However, root can do it just fine. 'sudo' is your best friend and worst enemy.
When I get my system set up better, I will post my step-by-step guide. I've got some robot-making to do right now, though...
*LEGO® is a trademark of the LEGO Group of companies which does not sponsor, authorize or endorse this site. Please see: http://aboutus.lego.com/en-us/corporate/fairplay.aspx
I've got a Mac Mini driving my TV, so I _could_ plug my new toy into there... But, I don't like to stand uncomfortably for long periods of time, so I'd rather plug the brick into one of my Linux machines (laptop, desktop, or netbook). Ah, but the software that comes with the toy does not support Linux. Happily, there is an active community online which likes to play with these two systems together.
My first stop was Da' Goog, where I came across http://www.krizka.net/2009/12/27/starting-mindstorm-nxt-2-0-development-on-linux/. I started following the directions.
However, I was unable to get the udev rule to create the /dev/ device for me. After much gnashing of teeth, I found that the following worked:
SUBSYSTEM=="usb", SYSFS{idVendor}=="0694", SYSFS{idProduct}=="0002", ACTION=="add" SYMLINK+="legonxt-%k", RUN+="/etc/udev/legonxt.sh"It differs from the original by the omission of 'group.' prepended to 'SUBSYSTEM', and by the used of 'usb' instead of 'usb_device' as the SUBSYSTEM value.
The only other problem that I ran into was that 'nbc' (the compiler/uploader for the NXC and NBC languages) had to be run as root due to permissions issues. I hope to get those figured out. For whatever reason, the script /etc/udev/legonxt.sh, which changes the permissions of the device file, still does not allow my user to access the brick. However, root can do it just fine. 'sudo' is your best friend and worst enemy.
When I get my system set up better, I will post my step-by-step guide. I've got some robot-making to do right now, though...
*LEGO® is a trademark of the LEGO Group of companies which does not sponsor, authorize or endorse this site. Please see: http://aboutus.lego.com/en-us/corporate/fairplay.aspx
Subscribe to:
Posts (Atom)
Followers
Blog Archive
About Me

- Chris
- Ingredients: Husband, Father, Software developer, Linux user, Juggler, Musician, ...