Sharpen Your Knives
You’ve heard the old adage about the lumberjack who—in order to cut a tree in an hour—will take 45 minutes to sharpen the saw? This old analogy really needs updating: Not many of us are all that familiar with the logging industry.
I like to instead use the metaphor of the chef who sharpens her knives before cooking.
By: Rob Myers
You’ve heard the old adage about the lumberjack who—in order to cut a tree in an hour—will take 45 minutes to sharpen the saw? This old analogy really needs updating: Not many of us are all that familiar with the logging industry.
I like to instead use the metaphor of the chef who sharpens her knives before cooking.
Saw it on TV
A few years back I went through a phase where I started watching, and even enjoying, reality cooking shows: Top Chef, Hell’s Kitchen, Beat Bobby Flay… And part of the appeal was that, on occasion, I could pick up some very good cooking tips. E.g., we learned from Bobby Flay, himself, that if you’re going to serve raw onion on anything, rinsing the sliced onion in cold water reduces…well, um…belching guests.
I recall, in particular, one brief scene of a chef sharpening her cooking knives.
Before the invention of good electric knife sharpeners, there was a discipline—even a matter of pride with some chefs—of sharpening their own knives. (Or have their sous-chef do it for them once the cameras were gone, I suppose…)
I immediately went to my favorite on-line cooking class site ( rouxbe.com ) and found their knife-sharpening class! Bought the classic Japanese whetstone, and got to work.
Let’s just say that the practice of manually sharpening your own knives was…meditative: Monotonous, laborious, and a bit messy; but rewarding. That feeling when the knife cut through a piece of paper with no sawing or pushing…exquisite!
Why do it?
Imagine you were a competing chef cutting carrots for a wondrous meal for your favorite sports team. In an hour. And you suddenly realize you have a fairly dull knife.
And Padma Lakshmi is watching you with that cold, calculating stare... You have two choices:
1. Just push through it. What could possibly go wrong? Well, with a dull knife, the carrots have more control over the trajectory of the blade than they should. So, you may end up with various odd shapes and sizes of carrots, and oh! What’s this? Your blood in the bowl. You’ve cut your finger.
Padma shakes her head sadly and says “This is not at all appetizing…pack your knives!”
2. You take 10-15 minutes to sharpen the knife. That’s 25% of your time! The audience is aghast! But it pays off because you can cut the carrots much faster, with more confidence that you won’t hurt yourself. The carrots all come out with uniform thickness, and thus all finish cooking evenly, at the same time.
Your favorite player on your favorite team announces that you’ve won the quick-fire challenge!
So, why do chefs sharpen their knives? Because they can get done faster, work more accurately, and create higher quality.
We wouldn’t tell a chef to “just keep cooking! Go, go, go! Never mind quality or technique or safety…” would we?
Skipping this essential practice is a false “short cut” that leads to wasted time, effort, and money.
Essential practices
An “essential practice” is one that the majority of your profession’s colleagues believe is a good one to know about. You know how to do it; and you know why, and when, to use it. You also keep up with the advancements regarding that practice. E.g., now there are good knives designed to be sharpened by electric sharpeners, and good electric sharpeners that won’t ruin those knives. (You may have to find some other form of meditative practice…)
In my “pre-Agile" days of software development, practices like up-front design (e.g., carefully considering numerous potential variations), line-by-line code reviews, and thorough scripted testing, were the disciplines we used to provide value. They were all we knew about. And, some of the newer techniques I’m about to list would have been impossible: How to do TDD on Ada 83 code when it took a half hour just to compile the project?
Essential “Agile" developer practices, or skills, are those that are specifically tuned to an iterative and incremental approach to software development. Since the late 90s, I, and teams that I have served as coach, would not in good conscience touch your product’s code without Test-Driven Development (TDD) or perhaps Behavior Driven Development (BDD), Continuous Integration, or at least two people actively collaborating on that code. We would not touch the code when exhausted (Sustainable Pace). And so on.
The selection of knives keeps changing. BDD has perhaps supplanted Acceptance-Test Driven Development (ATDD). Online collaboration tools such as Zoom.us may allow us to step back from some of our social practices (i.e., Sit Together aka co-location). That’s to be expected. As long as the real value of the practices is obtained in some way, we are able to select the right knife for the task, and complete the dish, professionally and safely.
Assuming, of course, that we’re given the time to use it, and we’ve learned how to use it correctly.
If not, well… "enjoy your lumpy, crunchy, bloody carrots.”
If you'd like to hear more- check out Rob's upcoming CSD class here.
Exceptional Circumstances by Rob Meyers
In our Business Driven Development (BDD) course, we use a real example of an online library patron portal. Course participants are provided with a number of (often vague) business rules regarding whether or not a book loan can be renewed. Some have to do with the state of the book (e.g., has another patron requested a “hold” on the book?) and others on the loan, itself (e.g., has this patron already renewed twice?).
In our Business Driven Development (BDD) course, we use a real example of an online library patron portal. Course participants are provided with a number of (often vague) business rules regarding whether or not a book loan can be renewed. Some have to do with the state of the book (e.g., has another patron requested a “hold” on the book?) and others on the loan, itself (e.g., has this patron already renewed twice?).
The business rules shape the Gherkin scenarios, to be sure, but that’s not what I want to talk about today. After the scenarios, step definitions, and glue code are all written, it came down to writing the implementation, and one course participant brought up an excellent question.
“If the book isn’t renewable, should I throw an exception?”
And, as any good consultant would answer, I said, “Well, it depends…”
What it depends on, is the customer. If we’re building a stand-alone app, a smartphone app, or a web application, then using exceptions to communicate business rules and user mistakes is strongly discouraged.
If we’re instead building a Web API, JAR file, or .DLL for another team, or an external client; then perhaps an exception is appropriate…but even then, perhaps not. It’s better, I would say, to encourage client software to avoid exceptions.
Let’s take a look at our choices in code, and see which one feels better. I’ll be using a programming language I like to call PseudoJavaDotNet. If you know Java, C#, C++, JavaScript, or Ruby, you can probably pick up the meaning of my PseudoJavaDotNet with no trouble. (And, if you harass me about the One True Brace Style, I will send you a reply about how life is far too short to argue over something that your IDE’s auto-formatting hotkey combo could fix in a nanosecond… :-P )
Okay, here’s what many developers typically want to write…
And, what would the caller of this code be expected to do? Yup, catch the exception and deal with it, somehow.
1. Just let it bubble up at least one level.
If it’s a Java “checked exception” this is done by declaring that the caller also throws the exception. Eventually checked exceptions have to be dealt with, though it’s never quite clear when, where, or what that’s supposed to be. Retry with the exact same data? Reboot the phone? Reboot the Internet?
You’ve likely seen methods (you know, other people’s methods) that throw exceptions from three or four different libraries: A strong code smell indicating lots of unintentional coupling within that method. Or, if the Java developer gets really lazy, the method will throw Throwable. :-(
If it’s a Java RuntimeException, or a .Net Exception (Microsoft decided not to implement checked exceptions in .Net.), you can still declare that your method throws it (and you probably should, if you really throw it) but your client is not obligated to know what to do with it.
2. Catch, wrap, and throw.
3. Log the exception, then act as though everything is fine.
What Exceptions Were Meant to Do
Exceptions were intended to provide an alternate return path out of a method (function, procedure) when something very out-of-the-ordinary happens.
Exceptions are meant to communicate to developers, not users. They can indicate a defect in the method’s code (due to insufficient unit testing), or (perhaps) in the caller’s code (also due to insufficient unit testing). They can also indicate when the expected flow of the system is thwarted by some other service (database, network, filesystem) that is not currently functioning. They should not be thrown due to business rules or problems with user-provided data.
And please never, ever, ever show the Exception’s error message and stack trace to the user. (I once sent a note to a website explaining to them that the connection pool they were using to connect to Oracle via JDBC was likely not threadsafe. I think they responded by deleting my login. Fine by me...)
An example of an inappropriate use for an exception: When the user’s credit card has expired.
An example of when an exception make more sense: When the credit card verification API is not responding.
In that case, I would suggest including pertinent in-scope data in the exception message, like the URL or other connection data used. That could include sensitive data: Yet another reason not to share it beyond your own team, and servers.
Generally, exceptions should halt the activity that was supposed to occur, rather than letting things continue blindly, as though nothing untoward had occurred. The code that does catch the exception generally does so in order to (a) clean up, rewind, roll-back, or otherwise undo any partial steps that were completed, and/or (b) tell the user the bad news that what they were trying to accomplish was unsuccessful, perhaps with some useful suggestions.
Try, Try Again?
People will often talk about the ability to retry when an exception is thrown. I’ve rarely seen that functionality automated successfully. Usually, it’s left to the user, and that’s been the better choice. Making the user wait, while your code uses a tight loop to repeatedly bang on their unresponsive GPS chip, while deep within the Ozarks, is just going to make them impatient. And run down their battery.
The best software products I worked on generally handled exceptions similarly. There was usually a database or filesystem involved: The activity was a purchase, the storing of a new collection of records, or the altering of a set of related records. So if something blew up in our faces, the database exception would typically be caught and wrapped at the source (e.g., a JDBC call), then our wrapper exception would bubble all the way up to a handler that would give the user some context and suggestions.
E.g., “Very sorry. We could not complete your purchase of ‘War and Peace’. It has been moved from your Shopping Cart to your Saved4Later list (seen whenever you view your cart). You may want to call the help desk at 800-555-5555. If so, please refer to your specific issue #XABCXYZ. Or, you may choose to try again another time and see if it occurs again. Meanwhile, we’ve created this Order with the other items from your cart.”
Typically, that means that all unrecoverable exceptions (which is most of them) need to bubble up to the level where they can be dealt with honestly: Log them, let the development team know that an exception has occurred, and let the user know that their activity was unsuccessful.
In Java, we once developed a self-logging application exception. Upon construction, it would write its message, unique issue number, and stack trace to the log; all before being thrown. It would also send e-mail containing the issue number to the development team’s support address. And, if another exception occurred while trying to do all that, well then that would pretty much crash the app.
And, isn’t that what you want to happen? No one wants to be using your software as it flails around in cascading layers of crashing, untested spaghetti code.
When I tell developers about the automatic exception e-mail (or, in one case, the logger would trigger the pager), they often complain: “We’d get thousands of messages daily!”
I respond with “I’m so sorry. So very, very sorry. How many unit tests did you say you have…?” I can be a real jerk when it comes to unit tests.But...
Exceptions should be…exceptional!
An Alternative to Exceptions
Okay, so what should happen when someone tries to renew a book that has a hold request? The general “pattern" I suggest is to encourage the caller to query, then act. In other words:
For some reason, this bothers a lot of developers. I think we are often looking for the perfect independent, object-oriented, single-method solution to every software activity. It’s a red herring.
Or, a better metaphor would be the Unicorn: One horn to rule them all, and in the rainbow, unite them; or some such. As much as we want to embrace Single Responsibility Principle, every computer I ever worked on had a testandset instruction of some kind. I consider “and” in a method name to be a code smell; and yet there it is, physically etched into each computer’s brain!
So, good for you, endeavoring to follow the S.O.L.I.D. principles. They provide great guidelines. But also recall that “perfection is the enemy of good.” (That’s particularly important to remember when you get to the O in S.O.L.I.D., the Open-Closed Principle, but that’s perhaps fodder for a future post…)
Good objects interact with each other. That’s because one of the real purposes of object-oriented development is to make it easy to understand and alter one small cluster of data and behavior (an object) without affecting other less-related clusters of data and behavior. Clear, maintainable, useful objects rely on each other, but aren’t all blended together into one big ball of spaghetti.
If we compare the code above to...
...well, which one better communicates the code’s intent to you and your teammates?
Lastly, if I’m the person writing both the called and the calling code, I won’t need to throw any exceptions in my renew() code, because I’m going to write a unit test that makes certain I always call loan.isRenewable() before calling loan.renew(). If I test that I didn’t make a mistake, do I need to check again in the code for the same stupid programming mistakes?
If You Can’t Scrum You Can’t Scale
Two years ago, we posted an article about the “fuss” around Scaling Agile or Scrum. The fascination hasn’t diminished at all;, in fact, there are more organizations than ever rushing to “scale” Scrum. The reality is most of these organizations are simply not ready to scale Agile or Scrum. How can these organizations scale something that they can’t even define?
Two years ago, we posted an article about the “fuss” around Scaling Agile or Scrum. The fascination hasn’t diminished at all, in fact, there are more organizations than ever rushing to “scale” Scrum. The reality is most of these organizations are simply not ready to scale Agile or Scrum. How can these organizations scale something that they can’t even define?
How can you scale something that you can’t execute?
Dictionary.com defines scaling as a verb:
· To remove the scales or scale from: to scale a fish
· To remove in scales or thin layers
· To shed scales
· To come off in scales
Yet many organizations think that “scaling” Agile and Scrum means preservation of scales. Preservation of top-down hierarchies with layers of management and oversight. Nothing could be further from the truth. Agility is about “turning on a dime for a dime” which means shedding layers. The Agile Manifesto is about empowering teams of people doing the work, not maintaining hierarchies. Scrum focuses on rapid value delivery by teams organized around features instead of silos.
How can you scale something that you can’t execute at its basic element?
In our original article, we posed even more questions for organizations to ponder regarding scaling Agile and Scrum:
· Do you mean Scaling Agile or Scrum across a large Product?
· Do you mean Scaling Agile or Scrum across an entire organization?
· Do you mean Scaling Agile or Scrum across distributed geographies?
· Do you mean all of the above? (Yikes!)
The reality of adopting any Agile framework, Scrum in particular, means change. Approaching the problem to be solved, the product being developed, or the work being done in a completely different way. A lot of Agile and Scrum vocabulary layered over your old way of working doesn’t make sense and won’t deliver value any faster. If a company delights customers and accomplishes their goals, why would they want to change their approach to doing work?
If an organization isn’t ready for Agile or Scrum at “small” scale, challenges await in the rush to take that adoption bigger.
Here are three questions to determine if the scaling conversation makes sense for the organization:
· Is the organization willing to dedicate teams (no time-slicing)?
· Is the organization willing to order the work? Everything can’t be #1 priority - you will have to say "No" at regular intervals.
· Is the organization willing to change the way teams of people are currently structured?
Answer no to any of these questions and the organization may need further education and discussion on what it hopes to accomplish with Agile or Scrum.
Questions? Ideas to improve this challenge? Please leave us a comment below.