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)

Wednesday, June 8, 2011

TDD, BDD, and XXDD

(repost from 2006.Aug.12 Sat)

Check out Dave Astel's paper (pdf) on TDD/BDD. Quotes:

[...] There are a score of books available on TDD, mine even won a Jolt award. So it seems that everything is rosy? Everyone who's doing TDD is fully understanding it and getting the full benefit, right?

Fat Chance!

Too few people I talk to really understand what it's really about. That means that many people who practice TDD are not getting the full benefit from it. What's wrong?

The focus on testing

Well... one thing is that people think it's about testing. That's just not the case.

Sure, there are similarities, and you end up with a nice low level regression suite... but those are coincidental or happy side effects. So why have things come to this unhappy state of affairs? Why do so many not get it?[...]

So with people thinking about testing, it's easy to come up with all sorts of negative reactions and reasons not to do it... especially when time gets short and the pressure's on.

By the way, I HATE saying TDD is "not about the testing". I have to say it now and then because of people not realizing it's about designing, rather than testing. The fact that the word "test" is in the name just helps confuse the issue. My preference for naming this design technique, is to call it "Behavior Driven Design". Or "Behavior-Spec Driven Design". With BSDD, I could say BSDD is about the behavior-specs, but mostly aboutdriving design.

Alistair Cockburn's "Executable Example Driven Design" (XXDD) is OK, but a bit long-winded. And I don't want to have say "Dos-equis Driven Design is not about beer." :-)

The problem is mental frameworks. People reject ideas that don't fit into their mental framework. You say "test" and the listener's mental framework comes up with these and other assumptions:

  • Testing can be done manually.
  • I can do implementing, someone else can do testing.
  • Testing looks for bugs.
  • Tests need something to test.
  • Testing is hard.
  • We can skip testing if we are good enough programmers, or time is short.

None of those assumptions directly applies to TDD. TDD can't be separated into tests written by one person and code written by another because the TDD cycle of test-code-refactor is a design process that one person (or a pair) goes through in cycles, where each cycle takes only minutes. TDD/BDD helps me find bugs, but that's not the purpose of TDD. TDD isn't TDD is you do the "test" part manually.

If you say "Test-Driven Development is not about the tests," that usually doesn't provide the zen-like kick in the brain-pan that the speaker intends. Instead, the phrase gets rejected because it doesn't fit into the listener's mental framework for "tests". The listener probably thinks you're nuts. He or she might just flip the "bozo bit" and stop listening to you.

If instead you say "Behavior Spec", the listener's mental framework will have fewer contradictory assumptions. For example:

  • Specs are written before coding.
  • Specs can provide examples.
  • Specs tell you what you need to implement.
  • Someone else can write specs and I can write the code.

Not all of those assumptions are true for BDD, but there are fewer contradictions to this idea of BBD that you're trying to introduce into someone's mental framework. Behavior Specs are written before the code exists (though only minutes before). Behavior Specs are executable examples. Behavior Specs tell you, more or less, what you need to implement next. There is still the contradictory idea that someone can write the Spec and someone else can write the code, but that isn't as difficult to overcome as all the other assumptions that come up with the word "test".


Thursday, June 2, 2011

What part of the brain calculates how a whip works?

Imagine a whip, in which each centimeter of the whip contains a data processor node, that calculates the position of the node in 3d space, the acceleration and velocity of the node in 3d space, the relative angle between this node and the next node, and the strength and angle of the pull on this node from the previous node, and so on.

Imagine each of these nodes gathering gigabytes of data, as a talented master of the whip, whose only control of this leather string of nodes comes from the handle in his hand, waves and curls the whip in the air, to snap it with precision, the tip exceeding the speed of sound, to clip a playing card or other some other target.

How much could we learn from examining and processing that data? What equations could we derive?

No doubt simulating this activity would take bank of CPUs some time to crank through the numbers. Far more time than the real-time action that took place.

How does a man do it? Practice, of course. And the more esoteric calculations are done in parts of our brain that are not subject to conscious reasoning. The parts that can predict the not-entirely parabolic path of ball thrown in baseball or football.


Would it not be interesting if the simulation of a whip could be repurposed to predict movements in currency-trading, stocks and bonds, real-estate prices, national economies?

In some limited situations the number of variables might not be that different. The forces and effects, velocity and acceration and position, could have analogs in this financial world.

How would a whip-weilder of finance practice? How would he get feedback? Could it be visible enough and fast enough to allow the esoteric calculating parts of his brain reliably direct his (financially metaphoric) hand?

Monday, April 18, 2011

Objects Dependancies Are Their Own Tax

This list of ways one class can depend on another is ordered from worst to best (for C++):

1. A depends on B because B is Singleton.

Avoid this. The dependency is 'invisible' and Singleton makes it worse than a global variable. Destruction is usually not possible unless a counting mechanism is used.

2. A depends on B because B is global variable.

Avoid this. The dependency is 'invisible'.

3. A depends on B because B is a file-local variable.

Avoid this. Not accessible to test.

4. A depends on B because B is a function-static variable.

Avoid this. Initialization is not multiple-thread safe. Not accessible to test. Destruction is difficult.

5. A depends on B because B is a class-static variable.

Avoid this. A class with static members and non-static members is doing two things. Separate the two responsibilities into separate classes, one of which can be a longer-lived than the other.

6. A depends on B because B is a member variable of A "by value".

Great for "value" objects, not so good for other kinds of objects. ("By Value" means by not by pointer nor by reference,)

7. A depends on B because B is a local variable of one of A's function.

Inaccessible to test. The dependency is 'invisible'.

8. A depends on B because B is a "by value" parameter in A's functions.

Not subject to faking or mocking, any data or behavior that are defined in a subclass of 'B' is "sliced-off" to be just a "B" inside the function.

9. A depends on B because B is a pointer/reference member of A, created in constructor.

Creation in the constructor is too soon for us to insert a fake.

10. A depends on B because B is a pointer/reference member of A, created in non-virtual function.

We can't override the creation inside the function.

11. A depends on B because B is a pointer/reference member of A, created in virtual function.

This allows us to override the function that creates B, using a fake, stub, or mock.

12. A depends on B because B is a pointer/reference member set by parameter in A's constructor.

We can create A with a fake, sub, or mock in testing. Dependency is visible.

13. A depends on B because B is a pointer/reference parameter in A's functions.

This makes the dependency visible in the interface. We can supply fake, stub, or mock in testing.

Coupling. Or... what you don't want your objects doing too much of.

Dependencies by one class on another class can cause problems when refactoring and writing microtests. In microtests, you want awkward collaborators to be faked, mocked, or stubbed out, and some kinds of dependencies make that more difficult than others.

Here are some dependencies from best (least-coupled) to worst (most tightly-coupled).

1. Class A depends on Class B, where class B is an interface ("pure" abstract base class).

We can test instances of A by creating our own test-specific subclasses of B to pass into A.

2. Class A depends on Class B, where class B is a concrete class but the functions are declared virtual.

We can test instances of A by creating our own test-specific subclases of B, but at a price: we have to deal with B's constructors and destructor, possibly doing stuff we don't want.

3. Class A depend on Class B, where class B is concrete class with no virtual functions.

We're going to need to refactor B and/or A for testability. Either making B's functions virtual, or putting an testable Adapter between A and B.

4. Class A depends on Class B, and class B grants class A "friend" access.

Class A not only depends on the public interface of B, but also the private parts of B as well. Not recommended. Don't do this unless you are Bjarne Stroustrup. If a test needs to access private parts of B, make those parts 'protected' and use a test-specific subclass to change selected parts of B to have 'public' access.

5. Class A depends on Class B, and class B is a class declared INSIDE class A.

This can lead to mutual complete visibility between A and B, plus the scoping makes it hard to test A without B, or vice versa. Not recommended. Don't do this unless you are Alexander Stepanov.

Also affecting how class A depends on class B is the WAY the dependency is manifest. It turns out that "visible" dependencies are often better than "hidden" dependencies, which is opposite of the usual idea of "information hiding", the predecessor idea of "encapsulation".

Saturday, April 9, 2011

from one twitter-reading session

Stuff I found interesting in reading twitter today, mostly links to things I'd want to read later.


RT: @LeanVoices: The idea is the easy bit, execution is where excellence and hard work resides.

RT: @suziedwards: Resume blooper of the day? "Software Mythologies used include Waterfall and Scrum".

RT @markrneedham: How to type on an iPad http://bit.ly/ftr9Vl

RT @flowchainsensei: Facebook's data center play sidelines Google, Apple http://reg.cx/1NBh

Chad Fowler = "These have changed my developer life, how I perceive software
and that great technology is fun" http://bit.ly/hP2B6O

Cool, @gregturn has finished Python Testing Cookbook! #congrats http://www.packtpub.com/python-testing-cookbook/book

RT @hackernewsbot: New engine shakes up auto industry... http://www.msnbc.msn.com/id/42460541/ns/technology_and_science-innovation/

Divvy is pretty awesome. http://bit.ly/g11Hj5

RT @badbanana: If you enjoy being the 10,000th person to put your thumb into a hole, then bowling is for you.

RT @theCoachingblog: "The things we hate about ourselves aren't more real than things we like about ourselves."
(Ellen Goodman) #quote

"Managing" Velocity: The term velocity is very well-chosen. It means speed in a certain direction, w... http://bit.ly/gvikOP #agileotter

RT @capotribu: "My startup story: from big idea to thriving business in 8 short years" http://t.co/IXMCjfV < great story of real reality

Fun Fact http://dinosaurmusings.wordpress.com/2011/04/08/fun-fact/

Our schools failed many of us. Why don't people understand the role of analogy? http://bit.ly/gBRqji (see comments) #testing

Good read. RT @toddcharron: An Agile Pace http://t.co/Rn9Gzuf - reminds me of http://t.co/gwmGRX7 #agile #scrum #kanban #overtime

Best #Agile article this year: Agile’s Second Chasm (and how we fell in) http://bit.ly/hvQDpT by @williampietri #recommended

RT @tottinge @jamesshore Someone was selling us a product that allows you to "collaborate in isolation from each other."

James Shore = For the record: Rabu is not and never* will be a project management tool, a planning tool, or a replacement for a whiteboard.

See what you started, mike hill? RT @alancfrancis: I am now nekkid as a jaybird, in an apartment with 10 windows wide open, attempting to cool down. #sorrytoputthatimag ...

10 Acts of Resistance That Changed the World — YES! Magazine http://t.co/NFN2UVx

jasonlittle = we did a retrospective on why we stopped doing retrospectives. good insights, blog post coming.

I read this = http://blog.benjaminm.net/2011/02/16/argyriscasestudylearningmodelii/ = worth it

http://blog.benjaminm.net/2010/12/07/agile-argyris-double-loop-learning/

publishing co I never heard of: http://www.packtpub.com/python-testing-cookbook/book

This practical cookbook covers lots of test styles including unit-level, test discovery, doctest, BDD, acceptance, smoke, and load testing. It will guide you to use popular Python tools effectively and discover how to write custom extensions. You will learn how to use popular continuous integration systems like Jenkins (formerly known as Hudson) and TeamCity to automatically test your code upon check in. This book explores Python's built-in ability to run code found embedded in doc strings and also plugging in to popular web testing tools like Selenium. By the end of this book, you will be proficient in many test tactics and be ready to apply them to new applications as well as legacy ones.

http://www.ted.com/index.php/talks/jonathan_haidt_on_the_moral_mind.html

yourmorals.org ?

https://github.com/twitter/commons

engineering.twitter.com blog = Cross-site Scripting Protection is one hundred percent live on mobile.twitter.com

After a soft launch, we ran into some unexpected issues. Several common Firefox extensions insert Javascript on page load, thereby triggering a report. However, even more surprising were the number of ISPs who were inadvertently inserting Javascript or altering image tags to point to their caching servers. It was the first example of how CSP gave us visibility into what was happening on the user’s end. We addressed this problem by mandating SSL for Firefox 4 users, which prevents any alteration of our content.

http://c2.com/cgi/wiki?WikiDesignPrinciples

http://elabs.se/blog/15-you-re-cuking-it-wrong

http://dannorth.net/2011/01/31/whose-domain-is-it-anyway/

http://cuke4ninja.com/

http://www.infoq.com/articles/Accidental-Agilist = Johanna Rothman wrote:
I didn’t think if myself as an agilist, of course. I decided to experiment with some practices, such as pairing and TDD. I’d worked closely with a couple of people one-on-one, back when I was a developer, and I wasn’t sure if it was really pairing. So I tried pairing and TDD with a colleague, Keith Ray, at an AYE conference, and sure enough, it was just like what I had done at work. Except, Keith was much nicer than my work colleague back in the ‘80s.
:-)

Sunday, March 20, 2011

J. S. Bach 300+ years of beautiful music

In honor of Bach's birthday, March 21, 1685, and the #bachchat celebration on twitter. Here are some of my favorite performances of Bach's music.

My current favorite is The "Little" Fugue in G Minor, BWV 578. ("A fugue is a contrapuntal piece of music wherein a particular melody is played in a number of voices, each voice introduced in turn by playing the melody." wiktionary)

To get a feeling for how The Little Fugue introduces the melody over and over, in multiple voices, each continuing to play over the others and yet still sound "good", check out this "piano-roll" animated rendition of this piece on youtube.


The above piece is performed on a piano-like instrument with a pedals, so the pianist can play a bass melody with his feet, just like an organist. And I think you would need that with this piece. I'm not sure how someone would like all the parts with just two hands.

Now the more fun performances are these...

The Canadian Brass:


The Swingle Singers:


Leopold Stokowski's orchestral arrangement:



You can search for other renditions of this fugue on other instruments. Wendy Carlos did a recording using a Moog synthesizer in Switched-On-Bach Boxed Set. The original instrument was of course, organ.

Bach's most famous organ piece is The Toccata and Fugue in D Minor, BWV 565 which may not have been written by Bach (!) and may have originally been a violin piece (!!). See the wikipedia article here. And here's what the violin piece might have originally sounded like:


I rather like Don Dorsey's synthesized version of The Toccata and Fugue in Bach Busters.

No youtube version of Don Dorsey's version. But there is this guitar performance:



My other favorites include the Brandenburg concertos, The Passacaglia and Fugue in C Minor (which is another piece arranged by Leopold Stokowski for orchestra)...


...and several pieces from the Anna Magdalena notebook.

I'm not a fan of Bach's vocal music.

I own a "complete" collection of Bach's music (153 CDs, excluding his religious vocal music), including several recordings of my favorite pieces.

Wednesday, February 9, 2011

If you are struggling how to TDD something...

If you struggling to think how to test-drive something with simple input and complex output, a few heuristics might help:

1. Testing pathological code (e.g. bad argument values) isn't going to drive your implementation that much, so leave that for later. Try the simplest successful case first.

2. If you really can't think how to test it, sketch out the algorithm (e.g. code-first) and figure out how you could test that algorithm. If the algorithm is 50 lines long, pretend it is 50 method calls instead: how would you test each of those method-calls? What does each line/method take as input, what is its output? Then try to go back to test-first and re-implement the code. Don't worry about public / private methods. Once your are "done" or at good stopping point, figure out which classes should own which methods, then refactor them to cooperating classes where most of the work is in public methods of each class. Move the tests to be closer to the code they test.

3. A class where there is only one or two public methods and a dozen or more private methods is exhibiting the code smell "Iceberg Class".

4. If the complexity resides in a third-party library or framework, concentrate your tests on YOUR code, assuming the third-party library or framework is correct. Unless, of course, the third-party library or framework needs tests (because it is unreliable), in which case test how your code uses the library or framework to get expected results.

5. You might have the test create the output, you verify that the output is correct manually, and then you save that output as a "gold standard" to test against automatically. I've done that for image-processing... it broke rarely, when the jpg library I was using changed.

Tuesday, November 23, 2010

High technical debt = slum

Sometimes I think the "debt" analogy is too clean. Brian Foote and his coauthor used many analogies in his "Big Ball of Mud" paper, including "Shanty Town", but I think the best analogy for the products I've seen with large amounts of technical debt is "Slum".

Products with large technical debt are money-makers, in spite of their problems (until the problems cost too much).

Slums have slum-lords, who profit from lack of maintenance, who are ignoring the pain of the inhabitants (developers and tester), and who are also ignoring the benefits of a clean environment... (of course, you can only take an analogy so far).

Still, it takes an empowered group of inhabitants to transform a slum into a desirable place to live and work. That requires management support.

Some books I recommend to those new to Agile

The following are some books I recommend to developers new to Agile software development.

  • This book is new, pretty complete, and easy-to-read about adopting agile software development: The Agile Samurai

  • This book covers the same ground as the Agile Samurai book. It's a little more in-depth. Most of it is now free on-line, but you can buy the book from Amazon: The Art of Agile Development.

Industrial logic has eLearning and in-person workshops on TDD, Refactoring, Design Patterns, and other topics. This web-based eLearning contains videos, exercises, and quizzes that are, for most people, more effective than reading a book. I would recommend both.

Friday, November 19, 2010

Going meta sometimes helps.

One of the sessions I participated in at AYE 2010 was Steve Smith's session on "Power, Authority, and Teams". We did an exercise where we individually tried to solve a problem (on paper, a problem whose answer can be scored as to correctness) and then we were divided into four teams, with one observer each, to try to solve the same problem.

The team that I was on, started with some direct actions by individuals: deciding we would use a flip-chart on an easel, and moving the flip-chart away from another team (which, funnily enough, put us next to another flip-chart on an easel, so we could have avoided carrying that easel around). One partipant decided to act as scribe, and off we want, problem-solving. I'm sure it looked like pure chaos. And it was. (But not necessarily in a bad way.)

As we worked through the problem, sometimes we'd ask for a show of hands in favor of a particular part of the solution. We never actually formalized how voting would work, and certainly never had more than one third of the group raising their hands. I think a lot of us in the group were trying to gauge agreement by audio and visual cues, but we didn't go "meta" long enough to formalize how we would signal agreement. We didn't appoint roles, or vote on a leader.

You have to remember that a many of us were coaches. "Agile coaches," even. We know about dot-voting (I almost suggested it once during this chaos), consensus/thumb-voting. We know about team-formation, Satir change model, self-organizing teams. Some of us had been through Problem-Solving Leadership training. We didn't use any of those tools. I know I could have, but I didn't, and I expect some others were thinking the same thing.

After struggling with one problem solving technique for a while, one of the Europeans in the group complained that our usage of American-style measurements was making it hard for him to contribute. I wrote "1 meter ≈ 3 feet" on the flip-chart to help him out, but another member of the team proposed working in relative sizes instead of absolute sizes. We transitioned to that problem-solving style and, after a little confusion, the team seemed to jell.

We had come to an agreement on process, though never explicitly agreeing on process through any formal means.

Later, we could compare our individual scores on the answering the problem with our team scores. Our team scored higher than any of our individual scores, though we were in third-place compared to the other three teams. The team with the highest score had chosen to use computers to solve the problem. Imagine! A bunch of software people using computers to solve the problem! :-)

OK, our team had a moment of conversation, early on, where some of us agreed not to use computers for the problem-solving, as that seemed against the spirit of the simulation. Again, not a formally-ratified agreement, but no one in our team went against that decision during the simulation. We were supposed to be learning about power: how people interact with each other, so we didn't bring computers into the simulation.

The team in fourth place had a score that was lower than any of their individual scores. I really wish I could have observed what was going on in that team. Somehow their collective problem-solving skill went completely opposite of their individual skills.

I think that even if we had formalized how our team made its decisions, we probably would have come to the same solution that we did in our informal way. We might have done so faster. We might have included insights from some of the quieter members of the team, and might done a little bit better.

It's also possible that if we had been too formal, we could have done worse, perhaps much worse.

Two points I want to mention.

In a team-building exercise at AYE 2005, my team happened to be all PSL graduates and no one in the other team was a PSL graduate. My team quickly jelled. We decided to enjoy ourselves and not stress out. The other team, across the room, we could see going through "forming, storming, norming, performing" stages. We ended up coming in second-place (of two teams)... but each team was working on a different LEGO model, so the difference in performance could be the difference in complexity of the models, or differences in our LEGO-building skills. As much as we would like to have simple causes-and-effects, sometimes effectiveness in one area doesn't mean success in another.

The other point I want to mention, I just read in The Gift Of Time, in the chapter written by Willem van den Ende: "Solving the Groupthink Problem". He quotes a diagram-of-effects by Jerry Weinberg (Quality Software Management vol. 3) Rather than re-print the image, I'll try to describe it.

"Effectiveness of meta-planning" directly affects "Effectiveness of strategic planning".

"Effectiveness of strategic planning" directly affects "Effectiveness of action planning".

"Effectiveness of action planning" directly affects "Quality of Action".

"Other Factors" directly affects "Effectiveness of action planning" and also directly affects "Quality of Action".

"Change Artistry" directly affects "Quality of Action".

That may or may not speak for itself. (Probably not, but it's getting late.) Willem has a paper here that shows other diagrams of effects. Diagramming systems can be useful.

And one last thing... In a discussion with the "power" team, I listed a bunch of different ways we can have power (or influence): speaking louder, speaking more persuasively, deciding on a process for the team to follow, holding the marker and thus acting as scribe...

That last idea had some impact on the participant who had been acting as scribe. She had been thinking that by acting as scribe, she would be avoiding taking power in this simulation. But the scribe can influence what gets recorded, who gets listened to. It's a position of power. We coaches who sometimes facilitate meetings by acting as scribe, should keep that in mind.

There are all sorts of power.

Thursday, November 4, 2010

Beautiful tools

Go to this page and scroll down to Figure 4. Apple's IDE graphically shows you the results of static analysis by drawing arrows over the code.

Beautiful.

Wednesday, November 3, 2010

Virtual Functions in C++ make TDD easier, but at what cost?

Virtual functions in C++ make allow us to do mocking, stubbing, and faking, which helps us test code in isolation in TDD or just microtesting in general. A frequent objection to virtual functions is that it "costs more" than simple function calls.

The cost of a virtual function is hardly ever important, unless the function is being called in a very tight loop, or it is being called at interrupt-time, and even then compiler / linker optimization might overcome the "extra" table-lookup that makes a function virtual.

In C, calling a function through a function-pointer is equivalent to calling a virtual function in C++. Implementations of file-systems APIs in Linux and BSD Unix use function-pointers internally to do what C++ does with virtual functions.

The cost of cache-misses (on-chip cache and off-chip cache) is a LOT bigger than the cost of virtual function pointers. Incorrect branch-prediction is also a CPU-level cost that people fail to understand.

The best way to know if making a function virtual has any user-apparent cost, is to measure the application via some tool that does non-invasive timing. Often, there will be no visible effect if you make some functions virtual that were non-virtual before. (I'm talking about REAL applications, not benchmarks.)