Tuesday, October 27, 2015

Tribute to Lyndon B.

Bor, I didn't get up to speak at your memorial service because I didn't think I could do you justice with an impromptu eulogy and so little time. This is my tribute to you.


On Sunday, October 25, 2015, I stepped out into the crisp, cool fall morning air as the cloudless Illinois night sky above slowly faded from black to a deep dark blue. The storm clouds that had set a fitting mood for the events of the previous days had all cleared out, as if the stories we had shared with each other into the early morning hours had also been a catharsis for the weather, ridding it of the vestiges of the gigantic hurricane that made its effects felt across an entire continent. Fitting indeed.

The breaking dawn was just starting to bleed vibrant hues of red and orange along the ragged horizon of the Chicago suburbs. As I looked up to the east, Venus, Jupiter, and Mars shone brightly as they converged in an area on the ecliptic that I could cover with my thumb held out at arm's length. To the south, Orion was still clearly visible, as if steadfastly standing guard to ensure that the three deities could complete their celestial rendezvous undisturbed. The ephemeral image that only heavenly hands could draw stirred up long-dormant memories of warmer daybreaks in the distant past. 

The Batang Gate 3 scavenger hunts, dubbed “Midnight Madness,” always culminated with the winners buying bags of hot pan de sal for the rest of the gang. Our Midnight Madness runs, inspired by a movie of the same title, were the brainchild of Tony Utzurrum and, I’m pretty sure, Berlyn, as Lyndon liked to call himself in those days. Those days were way back in 1981, when Gate #3 of Silliman University was our little enclave, where the "bad boys" of SUHS Batch '81 met to smoke, drink, ogle girls, intimidate passers-by, and just istambay, the Visayanized word for "stand by," or basically, hang out.

Lyndon Bernardez and Tony Utzurrum were neighbors, their houses straddling either side of Gate 3, one of the main points of entry into the SU campus west of Hibbard Avenue. Tony's house was on the inside of the gate and Lyndon's house was on the outside. Both houses were Silliman property and were used by faculty and staff of the university, which their parents were.

Tony's house was a smaller, more modern bungalow made of concrete. Lyndon's was a bigger, older, two-story house constructed mostly of wood. It was really a bungalow raised on stilts, with the lower level just a storage area with a dirt floor that was fenced off from the outside by bamboo lattice painted white. There was a big door facing the road that swung out so you could drive a car through it and park under the house, out of the elements. There was no car to park there though, so it was just a dimly-lit, dusty space where we would hide and do things we didn't necessarily want to be seen doing out in the open. (Note: The only image I was able to find of a house that was similar to the one that Lyndon lived in was one of the old Rowland house. Lyndon's house was very similar to it although the upper level was painted a dark brown, as I recall.)

Google Streetview shows that those houses are no more, with new buildings standing in their places. The old Gate 3 appears to be gone, a new iron gate erected and positioned closer to Hibbard Avenue. It even has mini portals that are the trademark of Silliman University entry ways. By contrast, the Gate 3 in our time was a rickety old wooden frame, about seven feet high, with either chain link or big four-inch wire mesh nailed over it. It remained open most of the time because it was old and hung poorly so you had to drag its heavy mass across the asphalt road to close it. I remember it had a rusty old chain and lock wrapped around one of posts, in case the security guards did decide to make the effort to shut down that access point.

It looks like there's a new guard house there, too. This one is about four times bigger than the old, ramshackle little plywood shed that the Gate 3 boys would often man. It's on the opposite side of the road leading into the campus from where the old one was. The former structures long demolished since I don't know when, they are now relegated to the memories of those who made that Acacia-shaded corner of our alma mater their stomping grounds so many years ago.

Lyndon was the youngest of four brothers. They had sisters, too, but back then I didn't know exactly how many there were. I just knew that he had at least two older sisters. His older brothers were Tani, Abra, and Evic, in that order. I only knew them by those names. The older brothers and their friends hung out at Lyndon's house so naturally, Lyndon and his friends hung out there, too. I don't remember exactly how I came to be part of their group but towards the end of my senior year in high school, in the summer of '81, I was hanging out with them regularly.

It was probably through my friendship with Tony U that I got sucked into this group of bugoys, or "bad boys". I remember them recruiting me into a "fraternity" that they started, giving me a few whacks with a paddle behind the soccer field near Daro as my initiation. I also remember them tricking me into eating dog meat for the very first time by telling me it was kalderetang kanding, or goat stew. It sure tasted a lot like goat meat so I didn't really mind it that much when they told me what I was really eating.

These were the same guys who introduced me to smoking when I was only thirteen years old. That was way back when we were just freshmen in high school. I think that was the same year they got me drunk for the first time, too. Or maybe that was our senior year, I forget. Come to think of it, by the time I was a senior, I was getting drunk a lot already, so yeah, it must have been my freshman year in high school, when we were just thirteen years old, that they got me drunk with my first taste of San Miguel Pale Pilsen beer.

Tony and I had been classmates in the fifth grade, under Miss Flores, and in freshman year of high school, in E.J. Cuevas' homeroom class. After our freshman year in high school, Tony got bumped out of the first section. It wasn't that Tony wasn't smart, because to me, he clearly was; I guess he just didn't care that much about grades. Not that I cared that much about grades either, which is why I always expected to be bumped down to the lower sections along with rest of the guys at the start of each school year. For whatever reason, I never was, despite losing my scholarship status from sophomore year onwards.

I don't think I was ever in the same section with Lyndon except for P.E., where two sections had to be combined because P.E. wasn't a co-ed thing. Even in that class, the boys from each section were seated on opposite sides of the room, maintaining a level of segregation that would be socially and politically incorrect these days. I always thought they had more fun on their side of the room though.

Those high school years were formative for the core Batang Gate 3 gang. Tony U, Lyndon B, Francis Nocete, Wawil Ferolin, Cisel Kiamco, Eric QuiƱanola, Alejo Necesito, Lloyd Tenaja, Edwin Mananquil, Carlos Roxas, Felipe Torres, and others whom I can't readily name now, were in the same sections throughout high school. We would always hear of them making teachers cry, arguing and debating with them, pulling pranks, skipping and boycotting class, and just being "wise" and "pilosopo" in general.

One story that I remember hearing about Lyndon was during Mrs. Cabanag's Spanish class. She had asked him to read "¿Por que?" and Lyndon pronounced it "Por KYU?" like the letter Q. When Mrs. Cabanag corrected him, saying "No, it's KEH, not KYU," he replied, "Sa ato pa, Ma'am, mo adto diay ko sa ilang Siega para mo palit og banana KEH?" (You mean to tell me, Ma'am, that I'm going to the Siega's to buy a banana KEH?), referring to the popular banana-que snack sold from under the Siega's house across the street from the high school. What a devilishly brilliant thing for a kid to say to a teacher. At least for us it was.

I went through most of high school just being on the fringe of the Batang Gate 3 gang. There was that one time when they brought me along to Carlos Roxas' house to watch Bo Derek in "10" on a BetaMax, which was still quite a novelty back then. That was kind of exciting and awkward at the same time, if you know what I mean. But it wasn't until that summer of '81, the time between our high school graduation and the start of our freshman year in college at Silliman that I really started hanging out with them a lot.

It was at Gate 3 that I learned how to solve the Rubik's cube and ride a unicycle. Tony, of course, was the best rider, since it was his unicycle. Lyndon was right there with Tony though, being one of the few who could ride backwards and do breakneck turns over the slabs of concrete that covered the canal on the side of the road. You had to be careful navigating around those slabs because the gaps between them were big enough for the tire to fall through. That would have been bad for both the rider and the unicycle.

It took me a good week of falling and scraping my knees and chafing my ankles and kigol before I could ride that darn unicycle a few meters at a time, but I eventually got good enough that one day, I rode it all the way back to Larena Hall on the opposite side of campus so I could show off my new skills there. I can still do it actually, although not as well as Lyndon apparently still could, even at our age now.

We even had a T-shirt printed for all Batang Gate 3 members. It was blue and the designs were printed in plain black ink. The front design was an intricate collage that was conceptualized and executed perfectly by Mark Cornelio, who was our class artist and kababata. I only remember that there was an image of a guy with a tirador or maybe it was an indian pana, some kind of street lamp, and various other typical scenes of Gate 3 life. On the back was a single large hand flipping the bird, our gang sign, I guess. I doubt that any of those T-shirts have survived through the years but I know that we all wore them proudly around the campus.

Anyway, shortly after the "Midnight Madness" movie came out in Philippine theaters, somebody, presumably Tony and probably Lyndon, too, thought it would be a great way to break the monotony of the nights we spent mostly just sitting around, smoking, drinking, talking and joking around, and singing to the accompaniment of an old, beat up guitar. The movie was about some college kids going on a crazy, all-night scavenger hunt. We were incoming college freshmen and we were kind of crazy, so we fit the bill perfectly.

Anyone who wanted to participate in a BG3 Midnight Madness run had to put some money—I think it was five pesos or something like that—in the pot and the team that came in first would win it all. If any of us had the foresight, he could have beaten Jerry Bruckheimer at his own “Amazing Race” by many years. As it was, we were just a bunch of teenagers fresh out of high school, living in the moment and having the time of our lives in the idyllic coastal city of Dumaguete on Negros island in the Philippines, where most of us had grown up together.

There were no consolation prizes in the BG3 Midnight Madness runs but the winners would invariably buy pamainit for everyone who had spent the last six hours running around in the dark, throughout the more than twenty hectares of the main Silliman campus. Teams of two or three runners followed the trail that wound around the campus, with each leg of the trail punctuated with cryptic clues that the devious and wily Tony U had authored and hidden at various landmarks the night before.

Like I said, I’m pretty sure Lyndon was Tony’s co-organizer for the runs but he may have also been running around with the rest of us. All I remember, after thirty-five years, is that the clues were hard but we always had lots of fun solving them, like the one where Tony used invisible ink and only left each team two matchsticks. I seem to recall that there were some teams who burned their clues down to ashes instead of singeing them just enough to make the dried calamansi juice on the paper turn brown to reveal the secret message. We all had a good laugh teasing them about their cluelessness. Good thing I was up to speed with my Hardy Boys. Or maybe it was Encyclopedia Brown. Meh. I just know my team won that race. I also remember that there was never enough pan de sal afterwards.

We were able to hold our intrepid and often frantic Midnight Madness runs because we were “lakas” with the campus security guards. It might have helped that Lyndon and Tony lived on campus and that Tani Ray Torremocha, who liked to team up with me, was a nephew of one of the security guards. Tony Boy would always make sure that the captain of the guards knew when we were having a race so they knew what we were doing.

So, whenever a group of young men ran across the paths of sikyu making their rounds in the wee hours of the night, they were simply sent on their merry way with a wave of a flashlight and perhaps a bemused chuckle and shake of a head after confirming that these were Gate 3 scavenger hunters and not burglars trying to make a quick getaway. I imagine the sikyu would have said something like “Sapat gyud kaayo ning mga Batang Gate 3 boys…” Translation: "These Batang Gate 3 boys are really (something)" — I don’t know if there’s an English word for “sapat”, the closest I can come up with is “mischievous” and “rabble-rouser".

I would have preferred that all those memories of fun and carefree days gone by had been brought back under different circumstances. As it was though, Lyndon Bernardez, aka “Bor Lyndon”, aka “Pugak", aka “BerLyn", aka “Don”, a kid I had known since I was in the fourth grade, a classmate in elementary and high school at Silliman University in Dumaguete City, Philippines, had passed away, surrounded by family and friends. His relatively short but valiant fight against cancer ended in the early hours of Thursday, October 22, 2015. Lyndon was only 51.

The news spread quickly through social media and text messages. I was sleeping on a couch in my office at home when my wife woke me up at dawn to let me know that my sister, Eda, had texted her to tell me that Lyndon had just died. Within 48 hours, people from all over the country, from L.A, New Jersey, Minnesota, North Carolina, and elsewhere, arrived in Chicago to pay their last respects to a beloved friend and classmate and to offer condolences and support to his grieving family. I made the six-hour drive up from Columbus, Ohio with my son, who had already been planning to spend the weekend at the University of Chicago with a buddy from high school who was on a football scholarship there. After dropping my son off at his friend's dorm, I drove north another hour and arrived at Al's house at about mid-morning, while Al was still out fetching other classmates from O'Hare.

Arnold Olegario, or Aploy as we call him, was flying in from North Carolina. Arlene Larot was coming all the way from L.A.  Eric "Bongky" Dumalag had flown in earlier that morning from New Jersey. Wawil Ferolin, Lyndon's best friend, had also flown in from New Jersey with his wife Brenda and was staying with his brother, who lived in the Chicago area. Felipe "Eping" Torres and Tonit Paraiso, a friend from college, were driving in from Minneapolis-St. Paul, Minnesota and were still a few hours out. Egay Estimo was going to be there, too. He lived just south of Chicago, somewhere in Northern Indiana.

The viewing at the funeral home was scheduled to be from 2 to 4pm, followed by a memorial service. As we waited for Eping and Tonit to arrive, Al and Mayette filled us in on the events of the past few days and we laughed when Mayette told of how Lyndon was still joking and goofing around the day before he passed. Al, Aploy, and I decided that we would dress up in full suits because Lyndon would have liked it. We left Al's house with less than an hour to make it to the funeral home, which was about 40 minutes away. We got there at 3:50pm, with just a few minutes to spare before the service started.

There were many friends and family in attendance. There were people from his church, his pastor, and his boss from work. His wife and sons were there, of course, and all of Lyndon’s brothers and sisters, with the sole exception of older brother Abra, who joined through videoconference from Dumaguete.

Lyndon’s sister, Lulu, was first to give a eulogy. She told of how they considered naming him John, after the recently assassinated U.S. president, but ended up deciding that their new baby brother would be the namesake for JFK’s successor, Lyndon B. Johnson, instead. I wondered if Lulu knew of Lyndon’s other monikers, like Berlyn, which was a clever play on the first syllables of his name, as were the nicknames of others in our batch like Elmer "Elsid" Sidro, Edwin "Edmanz" Mananquil, and Joel Vito "Tovits" Villaluz. Lyndon was also often called “Pugak,” although I couldn’t tell you how he got stuck with that one.

Lulu told of growing up with siblings who all had a sense of humor, and of family and friends, especially friends, "many, many friends.” She also mentioned “secrets” that she and her sisters did not know about. “You’ll have to ask his friends to tell you those stories,” Lulu said.

In closing, Lulu speculated that Tatang and Nanang had probably called Lyndon home first because any of the other siblings would be boring in comparison. Lyndon may have been the runt of the family but he was also the clown who could make everybody laugh.

Al Gallogo, who with his wife and also high school classmate, Mayette, had been Lyndon’s surrogate family in Chicago for the last thirteen years, was called up to give his eulogy. He spoke of Lyndon’s devotion to his family, and his constant longing to be with them. He told of the times that Lyndon fell asleep in front of his computer while chatting with his wife and kids on Skype or FaceTime, wishing that he could somehow be transported through the screen and halfway around the world so he could embrace them, and how Lyndon worked hard, patiently and faithfully waiting for thirteen years to finally give those hugs in the flesh just two short years ago.

Al spoke of their backyard cooking sessions and outings with Lyndon. He spoke of Halloweens past when Lyndon would entertain the neighborhood kids on his unicycle and dress up Buddy, his beloved adopted pug, so he could help give out candy to the trick-or-treaters. Halloween will never be the same without Lyndon and Buddy, Al said.

Lyndon's boss, Elsie, spoke too. She told of how Lyndon adopted her pug, Buddy, and how she shared custody of her "son" with Lyndon. She told of how she had taught Lyndon how to ski and how the student quickly surpassed the master. She told of how, after just a day on the beginner's slopes, she had challenged Lyndon to go down the advanced slope. Always up for a challenge, Lyndon gamely started down the steep slope, only to end up going too fast, then tumbling down, head over heels in the snow. "I guess we forgot to teach him how to stop," said Elsie, smiling through her tears to a round of laughter. They hurried down to where Lyndon lay in the snow, afraid that he had hurt himself. They found him laying there, just laughing, of course.

Wawil Ferolin went up to share his memories about Lyndon. Earlier, when Lulu was giving her eulogy, I had glanced over to where Wawil and Eping Torres were sitting together nearby. I already had a lump in my throat and I saw Eping wiping away tears from his eyes. Wawil was clearly trying to keep it together.

Wawil was best buds with Lyndon and his account of some of the Batang Gate 3 shenanigans, while considerably sanitized, were gut-bustingly poignant, to say the least. I think Eping might have even started to blush as Wawil related how the BG3 boys would call out to unsuspecting girls walking past our tambayan and treat them to an impromptu “show.” I assure you that there’s a version of that story where viewer discretion would be strongly advised and the accompaniment of an adult highly recommended for those under 18. That was a time when we could get away with almost anything, including things that were highly inappropriate and could land you neck deep in hot water these days.

When Wawil finished, I considered going up to speak a few words as well but I was certain that I would break down and cry at the podium. Lyndon wouldn’t have wanted any drama from the boys, especially not from the bugoys of Gate 3, the tough guys and hoodlums who were so intimidating that many Silliman students who didn't know better avoided going by our "territory" for fear that they would be harassed and get pareglahan. So I just stood up, the lump in my throat even bigger now, and shook Wawil’s hand as he walked by, giving him a big hug of thanks for representing the BG3 boys.

There were others who shared their memories, too, but perhaps none more memorable than the eulogy that Lyndon’s three young sons shared. Luigi, the eldest, said that his Paping was a meticulous planner: he always had a plan A, plan B, plan C, etc.

That Lyndon was a planner is absolutely true. Only the most well-laid plans could pull off the framing of an unsuspecting classmate for cutting loose a humongous fart in class. Lyndon and his co-conspirators would sit in front, on either side, and behind their hapless victim (to protect the innocent, I will not mention any names) so that when a cohort did the dirty deed, everyone who would bear false witness simultaneously turned and shouted out, all pointing accusing fingers at their mark.

The victim was usually shocked into silence by the suddenness and vehemence of the charges directed at him or her (yes, it was an equal opportunity prank) and quickly realized that indignant protestation and denial was going to be an exercise in futility. All their victims—oh yes, there were quite a few of them—ended up just grudgingly resigning themselves to bearing the responsibility and concomitant shame for the malodorous offense. I witnessed them pull this prank one day in our P.E. class, while Mr. Romero was checking attendance and I'll never forget the look of shock, dismay, and embarrassment on their victim's face. A little cruel perhaps but hilarious nonetheless and absolutely classic Bor Lyndon.

Luigi also mentioned his father’s membership in the International Order of DeMolay and I had to hold back a chuckle when I remembered the pun on that name, “Di mo uli” (doesn't go home), and the time that Lyndon ran away from home to work in construction in Cagayan de Oro. Wawil later recounted to us how Lyndon had purposely gotten himself into trouble with Tatang so that he could have an excuse to layas.

I still laugh when I remember what Wawil said about their little misadventure back in the summer of 1981, right after we had graduated from high school. Apparently Lyndon was absent from Physics on the day that Mrs. Macias went over the principle of the lever. After having a good laugh at the spectacle of Lyndon straining his scrawny unassisted arms trying to bend iron rebar for a few minutes, Wawil mercifully showed him how to use a pipe and a couple of 4-inch nails to gain leverage and make the work of bending the bar into a square much easier.

After the service, we went back to Al and Mayette’s house and spent the rest of the evening and most of the early morning hours remembering Lyndon and all the good times we had with him. To the end, Lyndon played his part, the one that all the Bernardez brothers have played ever since we were kids. They were THAT family, THAT house, where all the neighborhood kids would gather and hang out. Tani’s friends, Abra’s friends, Evic’s friends, and Lyndon’s friends all congregated at that old house on the corner, next to Gate 3. Lyndon was THAT kid who brought together our bunch of misfits and miscreants.

As I recall, the older brothers and their friends always had dibs on the screened veranda that overlooked the street below. Lyndon, Wawil, Tony, Francis, and the rest of the core barkada would also hang out in that inner sanctum, but being somewhat of a latecomer to this elite group, I never really got comfortable enough to go any further than the wide wooden staircase that went up to the front door. Still, I was content to sit there, smoking Marlboro shorts and chatting with other friends of the youngest Bernardez brother. I can only imagine what Wawil, Tony, and the others in that inner circle must feel, knowing that it could be a while before we would see Pugak again. But for now, as we bid our farewells to Lyndon, I have no reservations in claiming my place in the circles that revolved around him, to be one of those he continues to bring together with his warmth, mischief, silliness, laughter, loyalty, bravery, compassion, and the ever-lasting memories we’ll share of him and with him.

Thank you, Bor Lyndon, for being there when the BG3 boys tricked me into eating “iro” for the first time, for showing me how to ride Tony’s unicycle and solve the Rubik’s cube, for letting me help you hand out class cards during enrollment time so we could check out the cute girls signing up for their classes, for hosting the Midnight Madness runs, for the inomtagay, and camaraderie and rabble-rousing that came with it, for letting me tambay on your front stairs and be a part of this band of brothers, and for counting me as one of your many, many friends.

To Lyndon's wife, Yum, and sons, Luigi, Bryan, and DJ, I hope this tribute will give you a better idea of the kind of boy, brother, man, friend, husband, and father he was. Please take these memories of him and the times we had with the Batang Gate 3 boys and make them part of yours as well.

To the Bernardez family, thank you for sharing Lyndon with us and welcoming us into your home and your lives. I hope you can take comfort and find some joy in knowing that many people loved and respected your baby brother and were touched by him in one way or another.

Finally, to Lulu, I think you were right about Tatang and Nanang wanting to have Lyndon first. I like to think that the three planets I saw converging in the eastern sky on that Sunday morning were not wandering deities of ancient lore but were actually Tatang, Nanang, and Bor Lyndon. And even though planets are not supposed to twinkle, I’m positive that one of them looked like the mischievous glint in Lyndon’s eye whenever he told a joke or was up to something and the three of them were up there, finally together again, laughing and looking down from on high while shining their light of peace, hope, and joy on all of us. 

Godspeed, Bor, and God Bless. 


Wednesday, October 14, 2015

TDD and Getting Lost in the Trees (Part 2)

"There is no such thing as complete when it comes to stories. Stories are infinite. They are as infinite as worlds." – Kelly Barnhill

This is the sixth of a series of posts about Test-Driven Development (TDD).  Here's a recap of what I've posted so far:


In the last post, I started describing the situation when, in doing TDD, it starts to feel a lot like you're getting lost in the woods. You get that sinking feeling of helplessness when you've lost your bearings and become confused. There's probably even some dismay, desperation, and fear mixed in that bag of doom and gloom. Invariably, people in this situation ask themselves "What in the world have I gotten myself into and how the heck do I get out of it?"

There are two aspects to addressing this problem: prevention and remediation.

Let's talk about prevention first.

Extending another olive branch


Before we get back to eavesdropping on the imaginary conversation between Phil, aka "Tandy", and Carol in their simple calculator TDD session, I'd like to extend another olive branch to the practical-minded folks who have stuck it out through the five philosophically-laden posts that came before. That's a long time to hold out hope that you'll see some sample code written through TDD.

I'm going to take a slight detour from the calculator program and demonstrate a few things from a very simple exercise in refactoring. It will illustrate three simple tools that I believe can help you vastly improve 80% of the code you write.

I was looking for an analogy for these and started out with the venerable Swiss Army Knife but after thinking about it, these techniques are really like your basic oral hygiene kit: a toothbrush, floss, and mouthwash. If you use these properly and consistently, not only can you go about your daily business with freshness and confidence, you can also avoid a host of bigger problems and pain in the long term.

The Code Hygiene Starter Kit


The code hygiene starter kit includes the following techniques:

  1. Rename
  2. Extract
  3. Compose Method

That's it.

You might be saying to yourself right now that it can't be that simple. Yes, in my experience it really is that simple. However, my observation is probably consistent with what dental hygienists see with their patients: there are a lot of people who do not use these tools diligently or consistently. Only about one out of ten programmers I talk to have even heard of the Compose Method refactoring or use it on a regular basis when they are refactoring code.

In my experience, diligently applying these techniques in every TDD cycle keeps you moving forward with clean, readable, and well-factored code 80% of the time. Oftentimes, these are all that's required for 100% of your refactoring needs.

Joshua Kerievsky's Compose Method example has become my go-to example for this trio of refactoring techniques. I like to use Joshua's example not only because there's a stark improvement in the code after just a few simple changes, but it also embodies the strategy that I use to avoid getting into the "lost in the woods" predicament we're talking about.

I won't rehash what Joshua discussed in his article so go ahead and read that before you continue here.

Notice that Joshua uses the three refactoring techniques in our basic code hygiene kit. Mixed in there are some bonus goodies: the Arrow Code antipattern and the Guard Clause, and the Single Level of Abstraction Principle or SLAP, which I mentioned in passing in the first post of this series. It also has the elements of the strategy I mentioned. More on that later.

It'd be great to be a fly on the wall


In the previous post, we heard Carol tell Phil that the way we get there is just as important as what we get in the end when we do TDD.  The problem with most examples on TDD is that, for the sake of brevity, they seldom let us in on the conversation that goes on while refactoring and TDD is happening. We only get to see the results. That's understandable but unfortunate.

I think that TDD remains a mystery to many because they miss out on certain nuances about TDD that can only be discerned when we have a better understanding of the thought processes involved in arriving at the refactored code. Conversations and experimentation are what weaves the threads of knowledge into the cloth of understanding.

So here's another chance at being a fly on the wall during a reconstruction of some of the conversations I have with participants in my TDD workshop when we go over the Compose Method refactoring.

Caveat: As you read through the dialog below, remember that these are still fragments of a much longer conversation. For the sake of relative brevity and coherence, I left out parts where we go from Red to Green to Refactor or where we discuss the merits of others choices we needed to make. This illustrates my point about the challenges in giving good, complete stories about TDD. You really have to be there to appreciate the whole thing.

Me: First up, let's address the Arrow Code problem. We know how to recognize it now, right? And to remediate the problem, we introduce a guard clause, right?

Participants: Right.

Me: Hmmm, since we're doing TDD, do we really want to do that right away or should we do something else first?

Participants: We should probably write a test first to make sure we don't break anything.

Me: Great idea! What test do we write first?

Invariably, somebody will want to address the null case first. I steer them away from that and any other test idea not related to introducing the guard clause. I'll skip that part of the conversation for now; there are other topics where that's relevant but we'll get into those later.

Me: So, say we write the test to check that the guard clause works. What would this test look like?

Participants: We should check the readOnly property.

Somebody will offer something like this:

public class MyListTest {
 
   @Test
   public void testReadOnly() {
       MyList list = new MyList();
       list.setReadOnly(true);

       assertTrue(list.isReadOnly());
   }
}


Me
: Ok, so we add a setter, that's fine. But how does this test help us make sure that the "introduce guard clause" refactoring won't mess anything up?

Participants: Well, if the list is read only, then the guard clause should work, right? The guard clause is checking the readOnly attribute and it will work if the readOnly attribute is true, right?

Me: But is that really what this test is telling us?  Here's what I'm getting from this: When you make a list readonly, then its readOnly property is true.

Participants: We don't get it. We're confused. What's your point?

Me: That's like saying that if you're a U.S. citizen, then your passport is blue.

Participants: Ok, that's true, a U.S. passport is blue. But we still don't get your point.

Me: If I'm a U.S. citizen, the fact that my passport is blue doesn't mean much. Being a U.S. citizen means I can vote. Otherwise, I can't. What does the readOnly attribute allow or prevent you from doing?

Participants: Ok... well, if readOnly is true, we can't add any new elements to the list.

Me: Right! So instead of checking the readOnly attribute, we need to check the elements, right?  If we try to add to a list that is read-only, then the code should ignore that request and the elements array shouldn't change, right? Would anybody care to modify the test?

Somebody will offer something like this:

public class MyListTest {
 
   @Test
   public void testReadOnly() {
       MyList list = new MyList("First");
       list.setReadOnly(true);
 
       list.add("new element");

       assertEquals(1, list.getElements().length);
   }
}


Me: Ok, so we add a constructor that takes an initial element. We can easily make that take a variable size argument list so it can be any number of elements. That makes sense. Then we get the elements and check its length. Is everybody ok with this?

There is usually a nod of agreement or an awkward pause here, sometimes both. Sometimes somebody will object but let's go with the usual case where they still feel a little lost. I won't even go down the thread of conversation that addresses the fact that the above code has a big bug in it. That can also be the motivation for getting away from this option.

Me: Ok, is there an object-oriented design concept that we're violating here? Are we breaking anything, like say by examining the length of the elements array that we get from the list?

Participants: Yeah, we're breaking encapsulation. But we do this all the time in our code...

Me: Doesn't mean it's right, does it? This is what talking about these things does: it puts your bad habits in a spotlight. It makes you rethink your approach.  What can we do so we don't break the encapsulation of the list?

After more prodding and discussion, someone will come up with this:

public class MyListTest {
 
   @Test
   public void testReadOnly() {
       MyList list = new MyList("First");
       list.setReadOnly(true);
 
       list.add("new element");

       assertEquals(1, list.size());
   }
}


Me: Ok, that looks better.  By adding the size() method, we pushed down the knowledge about the implementation of the elements array and its length, and replaced it with a higher level concept of size().  At this level of abstraction, it doesn't matter whether there's an array or whatever involved.

Me: That's a step forward. But there's some implied dependency in this test. Where does that 1 in the assertion come from?

Participants: There's only one initial element in the list.

Me: But what if somebody comes in later and decides they want more than one initial element? Are they going to remember to modify that assertion accordingly? What are the chances of them forgetting to do that? There's an implied connection between that first line where we initialize the list and the assertion.  Can we do something to make this more explicit and less brittle? Either bring it all out in the open or hide it behind a name that reveals our intent better?

After more prodding and discussion, someone might come up with this:

public class MyListTest {
 
   @Test
   public void testReadOnly() {
       MyList list = new MyList("First");
       int initialSize = 1;
       list.setReadOnly(true);
 
       list.add("new element");

       assertEquals(initialSize, list.size());
   }
}

Me: That's good. We definitely made the intent of the test a little clearer. But there's still a need to change that line that sets the value of initialSize if we add more initial list elements in the line above. We can make that better, right? How about if we did this?

public class MyListTest {
 
   @Test
   public void testReadOnly() {
       MyList list = new MyList("First");
       int initialSize = list.size();
       list.setReadOnly(true);
 
       list.add("new element");

       assertEquals(initialSize, list.size());
   }
}

Me: That's kind of obvious now, right? Why didn't we think of that before? Now we won't have to worry about having to keep these two lines synchronized. But there's still something not quite right with that name. There seems to be a disconnect between its intent and the test intent.

I want the test to read pretty much like this: When I try to add new elements to a read-only list, the list's size should not be changed after I call the add() method. Or something along those lines. How can we refactor this test so that it says that? Is there a better name we can use instead of initialSize?

After more discussion, we have these versions to choose from:

// Choice #1

@Test
public void testReadOnly() {
   MyList list = new MyList("First");
   int initialSize = list.size();
   list.setReadOnly(true);
 
   list.add("new element");

   int finalSize = list.size();

   assertEquals(initialSize, finalSize);
}

// Choice #2

@Test
public void testReadOnly() {
   MyList list = new MyList("First");
   int sizeBefore = list.size();
   list.setReadOnly(true);
 
   list.add("new element");

   assertEquals(sizeBefore, list.size());
}

// Choice #3
 
@Test
public void testReadOnly() {
   MyList list = new MyList("First");
   int sizeBefore = list.size();
   list.setReadOnly(true);
 
   list.add("new element");

   int sizeAfter = list.size();

   assertEquals(sizeBefore, sizeAfter);
}

// Choice #4

@Test
public void add_does_not_change_size_of_readOnly_list() {
   MyList list = new MyList("First");
   list.setReadOnly(true);
   int notChanged = list.size();
 
   list.add("new element");

   assertThat(list.size(), is(notChanged));
}

Style Note: The test name convention I use here is something I picked up from Neal Ford at a No Fluff Just Stuff Symposium many years ago. Neal's assertion was that test names are special and don't really need to follow the normal convention for regular method names. I find this convention more readable and it also helps me highlight regular program element names when I use them in the test name.

That last option above actually involves a lot more discussion than I let on here. There's discussion about the test name itself, the convention (see the Style note above), whether we really need that second explaining variable, whether we want to use a more fluent API for assertions, and even a discussion about whether to move the first explaining variable closer to the Act part of the test (see Arrange, Act, Assert).

After more discussion, we settle on this:

@Test
public void size_of_readOnly_list_does_not_change_after_add() {
   MyList list = new MyList("initial element");
   list.setReadOnly(true);
   int notChanged = list.size();
 
   list.add("new element");

   assertThat(list.size(), is(notChanged));
}

There are a lot of details in this particular arch of a story that I have left out. I will leave it to you as an exercise with your programming partners to explore and discover your own version of this story.

Again with the reflections


You might be getting tired of this by now but it's not going to end. These posts are going to be full of reflections.

Reflection #1: Refactoring is a lot harder in the field than it is on paper.

On paper, the Compose Method refactoring example seems simple and straightforward. You see the end result and the way to get there seems obvious. Reality is very different, however, especially when there are people who are not familiar with the thought processes involved.  The end result is not known and getting there requires experimentation, discussion, and sometimes, negotiation.

In my experience from giving interviews/auditions and from leading a TDD workshop, this exercise can easily take 30 minutes to go through when I do it with as few as three or four people. And if you're thinking otherwise, this seems to have very little to do with the intelligence or apparent lack thereof of the people involved.

Rather, I have found that the level of familiarity and understanding of the principles of design, the mechanics of the refactoring techniques, and the kind of questions we ask each other and the quality of the ensuing discussions determines how quickly we get to the desired end state of the code or at least a good enough approximate of it.

Reflection #2: Finding good names for program elements is challenging.

Programmers have a tendency to be very technical when choosing names in their programs. Names tend to leak implementation details. Names can mislead the reader. They can obfuscate the intent of the code. I'm not even talking about the names that are chosen out of lack of effort to find anything better than numElmnts.  Names like this are a pet peeve of mine. Read the relevant chapter in Uncle Bob's "Clean Code" book. Please.

There are a few things you can do to find good names. Keep the language of the conversation focused on high-level concepts. Constantly remind each other that you want to keep as much of the implementation details hidden and make the intent abundantly clear. Pay attention to grammar, spelling, and context. These will usually help you stumble upon a good name.

In the five TDD workshops that I have led in the last two years, there has been only one person who came up with the name atCapacity() right off the bat.  And no, this guy had never seen Joshua Kerievsky's example before. I was very excited when that happened and my reaction got a few strange looks. All the other times, we needed a few iterations to get something as succinct. Some usual suspects include: hasEnoughElements(), isMaximumSize(), isMaxSizeReached(), and other similar alternatives, each with their own problems and reasons for disqualification.

I will talk about names in more detail in another post.

Reflection #3: It is important to have these kinds of conversations and thought processes to spur action down a path that leads to better code.

The conversations usually revolve around revealing intent and improving clarity. Revealing intent includes the intent of tests as well as the intent of the program code. These two intents must be in agreement. The tests need to say what it expects of the program and the program must say what it does to meet those expectations.

Questions must be asked in a way that elicits ideas for saying what you want to say both with the tests and the code in as clear and succinct way as possible. Don't settle on the first idea that pops up either. There are usually more questions and ideas that can be brought to the surface after the first few rounds of refactoring.

Reflection #4: Prefer to verify behaviors and capabilities rather than attributes

Tests should focus on verifying behavior, not so much the value of an attribute. This meshes very nicely with the idea that object-oriented programming is mostly about properly assigning responsibilities. A good set of guidelines to use is GRASP, the general responsibility assignment software principles. There's also the Law of Demeter and code smells like feature envy and inappropriate intimacy.

In the example conversation, I used the analogy of being concerned with a person's ability to vote rather than the color of a person's passport.

Since tests also should tell what is expected of the program, you should make sure the test says what these expectations are in a clear and unambiguous way. Nothing implied, nothing assumed, and nothing that the reader must deduce from clues that are found anywhere other than the immediate test. Parts of the example conversation revolved around this.

I find that reading the code out loud really helps in discovering subtle problems related to unclear intent and mis-assigned responsibilities. Try to explain what the code is doing in non-technical terms to each other. I'll write more about making code more expressive and readable and how to "listen" to the code in a subsequent post.

Reflection #5: Diligently and consistently apply the Code Hygiene Starter Kit techniques in the refactoring step.

These three simple techniques will help you quickly fix problems you introduced in the Red and Green steps of TDD and avoids the buildup of plaque in your code that can cause bigger problems and pain in the long run.

Just as you should brush, floss, and gargle daily, you should also Rename, Extract, and Compose Method constantly throughout the TDD cycle. Refactor ruthlessly.

Reflection #6: The "strategy" that I alluded to earlier in this post is this: have an idea of the end in mind and use that to guide you along the way.

It's kind of like getting a bearing on the sun and having a general sense of north, south, east, and west. Or finding the North star if you're traveling at night in the northern hemisphere. This is your "big picture" view.

As you slowly make your way through the fog of uncertainty and the unknown, the brush and undergrowth of quickly written code, and the thick of trees that are your program requirements, don't lose sight of where that guiding light is and keep a bead on it so you know you're still heading in the right direction.

Don't sweat the small stuff or let yourself get distracted by them but don't forget to pay attention to the little details, too. Little details can often make a big difference in how your code ends up saying what it's doing.

You may not see any connection between what I discussed above and the last reflection but it's there. It's just very subtle and for me, it's one of those things that is elevated to the level of a general principle for TDD.

Again with the Martial Arts connections


You may also be getting tired of these martial arts analogies but these concepts have really helped me see things in my TDD practice in a different light.

Miyamoto Musashi wrote in the "Use of the Gaze in Strategy" section of his "Book of Five Rings":

Use the eyes in a broad manner. There are two aspects of sight—perception and seeing. Perception is strong and seeing is weak. It is vital to see things which are at a distance as if they were close, and things which are close as if they were far away. It is vital in strategy to know the opponent's sword, but not to look at it.

Aikido has a similar concept called Zanshin which also pertains to a broad focus and general awareness of your surroundings.  In western terms, the closest thing to zanshin is the concept of situational awareness.  It's an awareness of your own relative position and connection to everything else in any given setting.

In an often-told story about events that led to a spiritual awakening that inspired the development of Aikido, O'Sensei was said to have seen and perceived his connection to the entire universe, thus allowing him to easily and deftly evade an expert swordsman's strikes until the swordsman was so exhausted from exertion that he had to concede defeat to O'Sensei.

I like to explain it like this: In Aikido we are taught to not let our minds be captured by the swinging katana (sword). The blade moves faster than you can ever hope to follow. We are taught to not allow our mind be captured by the other person's eyes but rather to look at nothing in particular and perceive everything as a whole. Connect with uke's center this way and you can control him before he even moves. In Aikido, the conflict is over before it even begins.

If this makes no sense to you, that's fine. Hopefully you'll start getting a sense for what it means as you practice TDD more.  More on this later.

That's it for this "little" detour. Hopefully, it has helped set the tone for a better understanding and quicker recognition of ways around the challenges that Phil and Carol are going to encounter when we rejoin them in their TDD exercise next time.

Next: TDD and Getting Lost in the Trees (Part 3)

Sunday, October 11, 2015

TDD and Getting Lost in the Trees (Part 1)

"Experience enables you to recognize a mistake when you make it again." – Franklin P. Jones

This is the fifth of a series of posts about Test-Driven Development (TDD).  Here's a recap of what I've posted so far:


As promised in my last post, I'm going to show some code examples this time. But before we get to that, bear with me as I wax philosophical just a little bit more.

How do we get ourselves in trouble? Let me count the ways…


I've seen many ways that programmers, including myself, can paint themselves into a corner. You have to admit, we can be pretty good at getting ourselves wedged between a rock and a hard place and I wouldn't be surprised if you found a mess of other ways besides the ones that I'll put under a microscope here. (Quick, how many idiomatic expressions did I manage to squeeze into this paragraph?)

I started out writing this post thinking that I could cover several scenarios but it quickly became clear that this first one that I'm going to bring up has so many facets to it that it deserves to be picked apart in isolation. Buckle up because this is going to be a doozy!

Recognizing that we don't know what we don't know


If you're one of those who I predicted would struggle with TDD and the simple calculator problem, then you probably didn't do so well on your first few attempts, even if you think you did.

You might think it a bit presumptuous of me to say that or maybe even arrogant but if you think about it for a minute, it's really a natural consequence of just starting out with TDD. Without a frame of reference, how can you know if what you just did was really what TDD is supposed to be like? If you're relatively new to TDD, then you won't really know that you've done it poorly until you do it better. As Donald Rumsfeld famously put it, "There are things we don't know we don't know."

This is kind of what the phrase "Aikido works, your Aikido doesn't" is getting at. It's what we sometimes tell people who think Aikido is ineffective. Similarly, people who say the same about Agile are sometimes told that "Agile works, your Agile doesn't." Or with TDD, "TDD works, your TDD doesn't." I honestly don't say this often because it tends to rub people the wrong way and often the people you want to say it to the most aren't really worth the aggravation. Nevertheless, there is a ring of truth to it that can't be denied and maybe that's why they get mad, because now they know it's them.

When I was just starting to learn Aikido, I got better by pairing up with black belts because they would usually point out things that I could improve, things that I would have never recognized otherwise. Now that I'm a black belt myself, I try to pay it forward by helping new students recognize ways they can improve their practice.

Remember, practice only makes habit. Only perfect practice makes perfect. Unless we start recognizing aspects of our practice that are flawed or could be strengthened, we're not going to be able to make it better, much less perfect. So, here are some things that I first focused on recognizing and making better in my TDD practice. Hopefully, these will help you see how you can get better, too.

Getting Lost in the Trees


You've probably heard the expression "seeing the forest for the trees". This first scenario that we will examine is about losing sight of the forest and getting lost in the trees. There are many dimensions to this but it happens quite often and it mainly comes from not understanding the principles that Michael Feathers and Steve Freeman alluded to in their presentation "Test-Driven Development: Ten Years Later." It is rooted in at least two thought processes that I think most developers find difficult to avoid. These are boxes that most of us find hard to think out of.

(Grammar police wannabes be like, "Really, ending a sentence with a preposition?" and I'd be like, "Chill out, dude, don't get all Carol with me. It's fine." Carol is hilarious though. If you're not quite following me, I'm talking about the TV comedy show, "The Last Man on Earth")

First, let's take a look at some test code that's typical of when developers are getting themselves "lost in the trees."

// CalculatorTest.java

public class CalculatorTest {

   private static final double TOLERANCE = 0.0001;
 
   private Calculator calc;
 
   @Before
   public void setUp() {
      calc = new Calculator();
   }

   @Test
   public void testAddition() {
      assertEquals(3.0, calc.evaluate("1 + 2"), TOLERANCE);
   }

   @Ignore
   @Test
   public void testMultiplication() {
      assertEquals(6.0, calc.evaluate("2 * 3"), TOLERANCE);
   }

   @Ignore
   @Test
   public void testAdditionAndMultiplication() {
      assertEquals(7.0, calc.evaluate("1 + 2 * 3"), TOLERANCE);
   }
 
   @Ignore
   @Test
   public void testWithParentheses() {
      assertEquals(9.0, calc.evaluate("(1 + 2) * 3"), TOLERANCE);
   }
}

// Calculator.java

public class Calculator {
   
   public double evaluate(String expression) {
       return 0.0;
   }
}

If you're thinking that this code doesn't look all that bad, you should probably pay close attention to the rest of this post. You might learn a few things you don't know you don't know. And no, that's not a typo; see the Donald Rumsfeld quote above.

If you're thinking that this is way too much code to start with when you're doing TDD, it's great that you recognize that. You're right, if this is the code that you have after just one or two TDD cycles, then you're probably writing too much up front. But just humor me for a bit. Let's just say for now that this is code you might have after a few rounds of following the Red-Green-Refactor flow. Then we'll step through how we might get here.

They say that imitation is the greatest form of flattery so I'm going to fashion this after Uncle Bob's archetypical XP Episode. Since I already mentioned Carol, let's get Phil in on this and pretend that they are pairing up on the calculator TDD exercise. Suspend your disbelief as necessary.

(Phil, of course, is the title character in "The Last Man on Earth")

Phil: Hey, Carol, I started that calculator TDD exercise like you asked me to. Here's the code so far. I even have my first failing test. See?

Carol: Really, Phil? That looks like a lot of code. Did you really get that through proper TDD or did you just write it all at once because it's what you thought you'd need anyway?

Phil: (sheepishly) I wrote it all at once because it's what I thought I'd need anyway...

Carol: That's Ok, Phil, I understand. You just wanted to save some time and cut to the chase. But it's important to understand that the way we get there is just as important as what we get in the end when we do TDD. The means is just as important as the end, Phil. Remember that.

Phil: I don't know what we're getting out of doing all those little steps though, Carol. It seems like a waste of time and it feels silly to do the wrong things when the right things are so obvious.

Carol: Oh, like how you knew that NOT leaving Todd in the desert to die so you could have more booty for yourself was obviously the right thing to do?

Phil: Aw jeez, Carol, that was a low blow, even for you. I already said I was sorry! And I went back for him, didn't I?! Am I ever going to live that mistake down? That was one small lapse of judgement in a moment of weakness!

Carol: Relax, Tandy. That's all behind us now but you should remember the lessons from the past. Doing TDD reminds us that you often have to see the wrong thing before you realize what the right thing to do is. Tell you what, why don't we write that calculator again and this time, let's go through the TDD cycle and thought process, step by step.

Phil: (grudgingly) Ok. Lucky for us, I'm using Git and I just happened to make that default JUnit test my initial commit. Let me revert to that really quick.


// CalculatorTest.java

public class CalculatorTest {

   @Test
   public void test() {
      fail("Not yet implemented");
   }

}

(PAUSE)

Let's hit the pause button for just a minute and reflect on what just transpired. You might be thinking that this conversation is a bit contrived (Well, duh. Unlike Uncle Bob and Bob Koss, Phil and Carol are not real people) but it's based on observations and questions from my own experience with doing TDD and teaching it to other developers.

Reflection #1: Phil went ahead and just wrote all the test code that he thought he was going to need. His intention was to save time. He also felt that the small intermediate steps were a waste of time and that it was silly because he was writing code that was obviously wrong.

The thing to recognize here is that writing correct code and avoiding or eliminating incorrect code is part of the complex algorithm for writing a program that you've followed for years. Your brain has most likely also been trained to be averse to rework, based on the belief that rework is wasteful and costly and that you can avoid rework by doing things right the first time.

Does that strike a chord with you? Do you not hold these things in high regard, if not dearly, as a software developer?

These ideas form part of your understanding of what it takes to write good software. It's the same kind of understanding that you have about how to ride a bicycle. It is the kind of understanding that is so entrenched in your brain that it has become almost a second nature to you. It's that rigid idea that Destin said is stuck in your head and you're finding it hard to change it, even if you want to.

Destin said that "Knowledge is not understanding." In other words, understanding runs deeper than knowledge. Much deeper. That's why it's so hard to change. Even if you have the knowledge about how to write programs through TDD, it's going to take a lot of effort to supplant your brain's current understanding of how to write programs with a new understanding that comes from all that TDD knowledge.

Does that make sense?

Reflection #2: TDD is as much about the way you get there as it is about what you get in the end.

Very skilled programmers can probably produce software with the same level of quality and testing that you could get by doing TDD properly. The problem is, I don't think I've ever met one these mythical super rock stars of programming in real life, even after decades in this profession. I've worked with many companies and met many developers and from what I can tell, the average developer just doesn't write very good programs and they don't write very good tests, sometimes even when they claim to be doing TDD. Color me cynical but I'm just stating my opinion based on experience.

If you recall what Michael Feathers and Steve Freeman said in their presentation, TDD is much more than just testing. Each of the steps you take in the TDD cycle has a very distinct purpose and focus. And that's why the path to get to the end product is very important. More about this later.

Reflection #3: TDD reminds us that we often need to see what's wrong before we can recognize what's right. You've probably heard or said this before: "I'll know it when I see it." We say this because it's probably the case that

  1. You've never really seen "It" before
  2. "It" is just a vague notion or an immature or incomplete idea
  3. You can't completely describe or wrap your head around what "It" is
  4. There are a few things "It" could be; there are multiple possibilities for "It"
  5. You have to actually try some of the possibilities for "It" first before you can say what "It" is

Take a minute to reflect on the above again before we hit the play button to see what happens next with Phil and Carol.

(PLAY)

Phil: Ok, first step is to write some test code and see it fail. I'm going to need a Calculator class. Agreed?

Carol: Sure, Phil, I agree.

Phil: (sigh) This is going to be a long day. (makes changes to the code)

// CalculatorTest.java

public class CalculatorTest {

   @Test
   public void test() {
      Calculator calc = new Calculator();
   }
}

Phil: Ok, I'm instantiating Calculator but this doesn't compile because we don't have a Calculator class yet. That still qualifies as Red because according to Uncle Bob's Three Rules of TDD, code that doesn't compile is still a failure.

Carol: Yup, you got it. Go ahead and fix it then.

Phil: (uses keyboard shortcuts) There. Now the test compiles.

Carol: Oooh, now you're just showing off, Phil. But that's cool. There's nothing more annoying than mousing around for every little thing you need to do. The keyboard shortcuts are much faster. Ok, run the test then.

Phil: What do you mean? There's nothing in the test to run.

Carol: Oh, Ok. Well, I suppose we should write another line of test code then.

Phil: See, this is getting pretty silly now. Why do we have to do this when we can easily just write everything out and then fix the problems all at once? This is a really tedious way to write a program, isn't it?

Carol: Believe me, Phil, I've been there. It really does feel tedious and downright stupid at first but once we get a hang of the flow and a better idea of where we're going, we can start trying to write bigger chunks of code. Right now, we're writing tiny chunks of code to force ourselves to take things slow. Really slow.

Phil: Why do we need to go so slow?

Carol: Because we want to fail fast and fail small.

Phil: Wait, what? I thought we were going slow. Now we want to go fast? WTH, Carol! Make up your mind! Are we going slow or fast?

Carol: Silly Care Bear. I know that sounds contradictory but by "going slow," I mean that we write smaller increments of new code. Smaller increments means that it'll take us longer to get all the code that we eventually want to get. That's because we're failing fast and failing small, which means that we run our tests every time we add a small increment of code. This way, we'll know right away if we messed anything up. And if we do mess anything up, we know it's probably the last small increment of code that messed it up. Bottom line is that we go slow by adding only small bits of code, fail fast by always running the tests and getting feedback right away, and fail small because we can only mess up a little bit with each increment of code.

Carol: It's kind of like driving in the dark, right? If you go fifty miles before checking if you're still on the right road, then you can drive faster but there's a bigger chance that you can go miles out of your way and get really lost. But if you stop every five miles to check with someone at a store or gas station if you're still on track, then it might take you longer to get wherever you're going, but at least you won't get too far off track at any point. Does that make sense?

Phil: That driving thing makes sense because that's kind of what I did when I took scenic routes from Billings, Montana back home to Tucson. I think I follow your twisted logic though, Carol. You still might have to explain it to me again a few times. I'm not sure I really understanding it all.

Carol: That's Ok, Phil. At least now you know. Understanding will come with practice. You just gotta keep doing it for a while for it to really sink in and make sense. And when it does, it does. It's kind of like those 3D pictures that you have to stare at cross-eyed, you know? It's hard to see the 3D at first but once you get it, you get it and it's a lot easier to see the 3D in other pictures afterwards.

Phil: Huh, I guess I never really looked at it like that before. Yeah, it took me a while to get those 3D pictures. I always saw them as just random patterns until one day, I just suddenly saw the 3D in one of them. Ok, I'll try to see this through some more. Now I'm curious to see if this picture of TDD that you have is as great as you say it is.

(PAUSE)

I'm going to hit the pause button again here for some more reflection.

Reflection #4: Adding small increments of code may seem silly and tedious but it allows you to go slow and keep checking your progress more often. I think Carol explained it quite well.

Reflection #5: Fail Fast and Fail Small. Run your tests every time you add an increment of code so you get feedback quickly and often. The smaller your code increments, the smaller the problems are that they might introduce. The smaller code also makes it easier to revert to a previous state where all the tests were passing.

Reflection #6: Knowledge is NOT Understanding. Understanding will come later, when the knowledge you have is exercised in a context. The more contexts there are in which you apply that knowledge, the more it gets ingrained in your brain as Understanding.

Reflection #7: The tests provide different contexts in which you can exercise your knowledge of what your program is doing. The more you test your program, the more you understand what it's doing. See Reflection #6.

Reflection #8: The algorithm for writing a program with TDD is very complex and complicated and belies the simplicity of the Red-Green-Refactor mantra. As you can see from the number of things we can reflect upon from just this short "conversation," there are many things to think about when you're doing TDD.

You may be asking where those "trees" are that we supposedly can get lost in. If you don't see them, then remember what I said before about not having enough experience to recognize what you don't know? The trees are there but maybe you just didn't recognize them for what they are.

I know you're probably disappointed to not see more code than what I've shown but if you have a little bit more patience, it will be rewarded. (Remember what I said in the first post about needing some virtues?)

We'll continue our eavesdropping on Phil and Carol's TDD session next time. They are going to be writing a lot more now that they have a bit of a shared understanding of TDD.

In the meantime, I encourage you to reflect on all this some more. As you do that TDD exercise again, keep in mind whatever new knowledge you've managed to pick up here. This is how you develop recognition, which in turn opens up possibilities for improvement and getting closer to perfection in your practice of TDD.

Next: TDD and Getting Lost in the Trees (Part 2)

Saturday, October 10, 2015

TDD: First Time Crash and Burn

This is the fourth in a series of posts about Test-Driven Development (TDD). Previously, I posted these:



Eliminating the Self-Centered Ego 


One of the things that makes Aikido different from many other popular martial arts is that there are no competitions in Aikido, unlike say, in Tae Kwon Do or Karate or Wu Shu.

The following are excerpts from the book "Advanced Aikido" by Phong Thong Dang and Lynn Seiser:

O'Sensei Morihei Ueshiba... discouraged competition. He felt that competition... diminished Aikido's application as a legitimately applied martial art. He also believed that competition and the striving for championship status would only further encourage, develop, and inflate the self-centered ego. The learned identity ego, in Eastern thought, is one of the major barriers to sprituality... He felt... that competition would create ego blocks to spirituality.
"Aikido is for the development of the entire human being," states Doshu Moriteru Ueshiba... The mental discipline of Aikido is to overcome our own ego for spiritual development, as opposed to employing Aikido in the service of the learned ego identity, to overcome someone else, thus strengthening what Aikido is trying to minimize.

No Contest


You may be wondering what any of this has to do with TDD. Well, in my previous post, I posited that people who have never written a program with TDD would not be able to write a simple calculator program with TDD. I put out the challenge and gave some requirements for how the calculator should work.

And then came the beat down: "You can't do it! You might think you can, but you can't!"

This is what Destin, the engineer who learned how to ride the backwards bicycle, told viewers of his short and hugely popular video on YouTube. He even offers to pay $200 to anyone who can ride the bicycle for ten feet. I don't think anyone has cashed in on that offer yet. Quite frankly, I think it's a sucker bet and Destin knows it.

I'm not going to put any money on the table for this but I'm betting that at the very least, half the people who take up the challenge of writing a program through TDD for the first time will falter after a few minutes and quickly fall back to their old ways of writing programs, much like those who take up Destin's challenge on the backwards bicycle.

The Agony of Defeat 


As Destin said: You wouldn't think it, but the algorithm for riding a bicycle is just that complicated and any change to one thing throws the whole control system off balance. The algorithm for writing a simple program is pretty complicated, too, maybe even more complicated than that for riding a bike.

"But what does that stuff about Aikido have to do with any of this?" you might ask again.

It all goes back to what I said before about being afraid to screw up. It's the ego, man. It's about not wanting to look stupid. It's about wanting to be a winner.  It's about proving Destin and me wrong about you not being able to do it.

"Ok, whatever," you might say with a roll of your eyes.

But am I wrong? Were you really able to write a little bit of test code, then some production code, then refactor, then some more test code, yada, yada, yada?  Were you able to get through the whole exercise without, at some point, stopping and racking your brain as to what test you should write next? Did you not, at some point, stop and look at the mess you'd made and say, "What the (bleep)?!!! This is horrible! This is frustrating! How can I possibly not get this right?!"

I know this is starting to sound like a lawyer badgering the witness but admit it, it's not as easy as it seems, is it? Admit that you started all over at least one or two times, maybe even more. C'mon, if I can be man enough to say that it also happened to me, which it did, you can at least admit that it didn't go swimmingly well for you either.

I hate to say "I told you so," but I told you so. The truth hurts, doesn't it?

Keep Calm and TDD On


Ok, so if you can admit to crashing and burning on this first outing with TDD, then there's still a glimmer of hope for you. Here's why: I couldn't do it at first but after a while, I finally could. After about two years actually.

As self-deprecating, down-to-earth, and approachable as Kent Beck and most of his contemporaries in the field can be, we all know that the apparent ease and dexterity with which these tests and code can be wrangled is belied by the fact that they are the gurus, gods, and demigods of TDD. It's easy for them to talk about and demonstrate how powerful and effective TDD is as a technique because they practically and quite literally invented all this stuff.

It's kind of like how my fellow students of Aikido around the world and I will watch videos on the Internet (isn't technology wonderful?) of all the Aikido masters and even of the founder himself from way back in the 1960s, and wonder in awe at how easy and effortless they make all these techniques appear to be. And then we try to do them and find out that it's not easy at all.

I, on the other hand, hold about as much candle to any of those guys as a baby to her octogenarian grandmother. I'm one of you, just another Joe Schmoe programmer trying to learn how to get a little better at this job. If I can pick myself up, dust myself off, and power through the pain and frustration of failing at TDD, I think most of you can, too.

So relax, take a deep breath, and try it again. It gets better, I promise. You just gotta keep keepin' on.

Eliminating Competition


So now we know that most of us go into TDD with a good measure of knowledge about it but with little to no understanding that we have what Destin calls "a very rigid way of thinking" which we cannot easily change even if we wanted to.

Were you not at some level fighting with this new paradigm? Were you not struggling against the urge to just write production code first, even for just a little bit? Once you entered that ring with TDD, you quickly realize that despite having all the weapons you thought you needed, you were still ill-prepared for this battle with your mind.

Did you really think it would be that easy to find the magical switch that controls the flow of your thought processes, creating big up front designs and writing production code before the tests? The bias from your past experiences guards that switch very jealously, trying to keep you from flipping it. And when, on occasion, you are able to flip it and alter the flow of your thought processes, your bias continues to fight to flip it back to its "normal" position.

Even if you don't buy all that or want to dismiss it as just more hokey martial arts, Eastern philosophy baloney, that's fine. All I'm saying is that this is how I retrospected about the start of my journey in learning TDD. Retrospecting about it helped me re-align my outlook and attitude towards TDD so that I could be more open minded and accepting of what was happening and what TDD wanted me to do.

Call it mind games, or neurolinguistic programming, or whatever. The biggest obstacle to you being able to go with the flow of TDD is your own bias from past experience and you need to eliminate at least some of that bias to keep going, to get unstuck. That's the competition you have to deal with.

Where's the Code, Dude?


All right, I promised I'd give some demonstrations on how I do TDD and all I've given so far are a bunch of philosophical essays. I get it. You're a developer and you want to see some code.

In the next post, I promise I'll finally get to it. Sorry, but it's the weekend now and the Buckeyes are playing Maryland, with kickoff in less than twelve hours. My daughter is finally going to go for her road test and my wife is bugging me to finish putting up curtains on the new windows and a shower head in our newly-renovated master bathroom.

Next week, I promise, you'll see a lot more code.

Friday, October 9, 2015

TDD and that First Awkward Moment

This is the third in a series of posts about Test-Driven Development (TDD). These are what I posted before:

These posts were partly inspired by a question I answered at coderanch.com about how to develop a simple calculator program with TDD.  It turned out to be quite a long discussion and you can head over to the Ranch and read through all 200+ responses there, if you have that kind of time to kill. Or you can stick around here as I review and summarize some of the things I mentioned in that thread.

Ok, I created a new test... now what?


So you've decided to do TDD and you're all excited and eager to see and experience just what everyone has been talking about. You've created a new JUnit test class, which typically looks something like this:

public class MyNewTest {

    @Test
    public void test() {
        fail("Not yet implemented");
    }
}

Now comes that first of many awkward moments people new to TDD are most likely to have. It's just like being on a first date and not knowing exactly how to break the ice, so you sit there uncomfortably, hoping and praying for a flash of inspiration for a witty remark. 

You say to yourself or your programming partner(s), "Now what?"

Why do we hesitate? What are we afraid of?

Think about that for a minute.

Here's my best armchair psychologist's analysis: We get stuck because we're afraid of being wrong. We're afraid that we'll mess up, that we'll look stupid, or that we'll feel stupid. 

My wife would probably say it's a typical "guy thing," knowing that we're hopelessly lost but not wanting to ask directions for fear of being called "a dumb schmuck" or looking like one.

Ok, I'll admit that I think the invention of portable GPS navigation systems and mobile apps has probably saved more marriages than AAA TripTiks, Dr. Phil, and Couples Counseling combined ever will. 

I see the same thing with beginners in the dojo. They'll start the technique, then stop midstride and ask for validation. Then they'll want to start all over. We always tell them to just keep going and do what they think they saw sensei demonstrate just a few minutes ago.

The Challenge


As pointed out in my previous post, knowing is not understanding. You may be nodding your head in agreement to all of the above but to really understand, you need to get on that backwards bicycle and feel it for yourself! You need to step on the mat and practice!

Let's try to create a simple calculator through TDD. Now, if you've never written a program using TDD (or maybe even if you think you have), then I'm sorry to tell you this but "You can't do it! You may think you can, but you can't!

Destin's words, not mine. But yeah, he's probably right.

At this point, hopefully you're saying "Ok, homes, challenge accepted!" as you're firing up your favorite IDE and deftly clicking around various menus with your mouse, or better yet, quickly typing in the keyboard shortcuts, to create a new project.

What, are you still just reading? Go ahead and fire up your IDE, dude!

Enter the TDD dojo


I expect that by now, you have your brand spanking new project laid out in front of you. Hopefully, you've navigated to the /src/test/java folder or wherever you plan to keep your unit test classes. If you're a real go-git-'er-done type, then you probably have already created a new JUnit test called CalculatorTest.  I am, of course, assuming that you're programming in Java and using JUnit. If you're not, feel free to go ahead and make the necessary mental adjustments.

Now what?

What's that? You need requirements? Ok, here they are:

Write a simple calculator program that can handle the four basic arithmetic operations of addition, subtraction, multiplication, and division. The calculator should adhere to the order of precedence rules associated with the mnemonic "Please Excuse My Dear Aunt Sally," except this calculator need not support exponents for now. Your calculator should honor the order of precedence dictated by parentheses.
The calculator should be able to handle decimal calculations and a result that is a rational number supported by your platform, presumably a typical laptop or desktop computer. Any underflow or overflow should be reported as an error. (Note: if you're trying to do this on a mobile device or a mainframe, I salute you, but maybe ease up a little and find a PC or Mac for this, you weirdo)
For example, given the expression 1 + 2 * 3, the calculator should return 7 as the result rather than 9.  However, given the expression (1 + 2) * 3, the calculator should return 9 as the result.
Also, the calculator should be able to display intermediate results as they become available throughout the process of evaluating an expression. 
For example, while evaluating the expression 3 * 4 + 5, the calculator should be able to display the intermediate result of 12 when the "+" operator is reached.  And while evaluating the expression (1 + 2) * 5, the intermediate result of 3 (the sum of 1 and 2) should be available for display when the closed parenthesis is reached.
That's all I have for now.

I'm going to end this post here and give you a chance to go and prove Destin and me wrong. (And no, you grammar police wanna-be, the correct form is "Destin and me," not "Destin and I."  Look it up for yourself if you doubt it.)

In the next article, I will go over what typically happens with TDD neophytes and cargo culters when they try to do this.

Hajime!

Next: TDD: First Time Crash and Burn