A Fool with a Tool

One of my quips that people seem to get a kick out of is:

“A fool with a tool is still a fool”

My point is simple: woodworking tools in the hands of craftsmen can produce fine furniture or musical instruments. But merely the availability of great tools “doth not a masterpiece make.” Not to take the woodworking analogy too far, but power tools can also make it easier for the amateur to get hurt.

The reason a quality piece can be turned out more efficiently with a tool is the ability for the craftsmen to more quickly realize the design and architecture. In addition, tools can help make patterns easier to replicate. From actual patterns (like certain cross-section shapes on molding), to templates (like violin bodies), to connectors (like Kreg pocket hole jigs). A woodworking shop will also make good use of building components to put into larger assemblies.

So, tools in the hands of experts can help realize the design. Tools that are able to help apprentices produce parts designed by the masters, can help produce more output and help train the apprentices.

But put me in a room with the most awesome woodworking tools, and I will not be producing Stradivarius-esque violins any time soon (or ever, most likely).

A Java Developer’s Switch to Rails

As I read this account of transitioning from Java EE to Ruby on Rails,”Java Web Apps to Rails, A Developer’s Experience,” I thought the following:

Regarding the lack of a good Ruby/Rails IDE:

When it was time to look at the code, I was a bit disappointed.  TextMate looked like a popular choice but it fell short in many ways.  I struggled to navigate the code, link the methods across files and follow the code. Grep was my only savior.

I am surprised he did not find RubyMine. JetBrains makes awesome IDEs (IntelliJ IDEA for Java, too). I have to admit at being very impressed that the underlying model of the ruby code within the RubyMine IDE is amazingly capable of giving you the same sort of features that it can for a “compiled,” or more type-centric language like Java.

Ruby

Next he mentioned about learning the language…

My approach to learning Ruby was to start looking at code and figuring out pieces of syntax that did not make sense.  That turned out to be a bad idea. Constructs like “do |x| x+1” threw me off. … I found it very important to understand the motivation behind creating the new language.

There are some good books out there, and other resources…

Another comment rang true with me:

I found it very important to understand the motivation behind creating the new language.

More about the motivation behind Ruby… or at least, how I interpret things.

Ruby treats you like an adult. It doesn’t baby you, or hold your hand, or make you type all sorts of (obfuscating, in my opinion) fluff that a compiled language needs. Your code is more compact and obvious and “dense with meaning,” leading to less need for things like method return types and method parameter data types. Or semicolons.

However, I miss parameters list, curly braces, return statements, camel case naming conventions…

Be patient… soon you will grow weary of having to read all that extra stuff when you go back to Java. If you write well-formed classes, and very small, compact, and obvious methods, you don’t need the extra frills. You will run across the concept of “duck typing” which really means that classic C++/Java/C# style interfaces are not needed. If you create a method that expects a passed-in object to respond to a method call (e.g., “torque”), any object of any class will do — as long as it has that method call! And if you pass in an object that does not have that method, Rails will kindly throw an exception.

The concept of ‘open classes’ that allow developers to go in and change a base class sounds scary.

Go back to my opening statement. “Ruby treats you like an adult.” If you are naive, you can blow your code up and break stuff. If you do everything the Ruby way, you’ll be fine — because you will catch it with tests (right?). There are good rules of thumb for how and why and when you should consider adding to an existing class — or worse, monkey-patching. In Ruby you can actually alter the behavior of an existing method of an existing class. Do it poorly, and you will pay the price. And maybe not for a year or two. Mwahahahaha.

Ruby’s metaprogramming is incredibly powerful (even if the syntax takes a bit of getting used to).

Rails

Rails is incredibly opinionated about how the MVC code should look. It is basically a model-driven architecture approach. The framework expects the MVC stack to have a model, a view, and a controller for each domain concept. (As a long-time domain modeler, and UML guy, this is a real treat.) You can use the default rails generators (interesting when first starting, or for banging out a quick prototype), or write your own twist on a generator. Instead of focusing on the boring framework bits with repetitive, template-like code for each domain object, you can focus on quickly creating features that people want to use and pay for 🙂

Supporting Cast

Ruby on Rails has a great ecosystem of wonderfully talented folks providing 1000s of gems to do all sorts of useful things. For example:

The ecosystem of supporting tools is incredible. Some of my favorites:

These all make it so easy to “do the right thing” and write code with BDD/TDD to provide quality from the start.

Personally, my switch from J2EE to Rails (not to mention SQL to NoSQL/MongoDB) has been one of pure pleasure. The kinds of rich functionality and the ability to build stuff faster is imprerssive. I only wish I were better at writing kick-ass Ruby, Rails, CSS, Javascript, MongoDB…

Is it perfect? Of course not. There are other cool things to look at as well… Meteor, Node.js, MEAN, etc. So much to explore, so little time.

Back to my continuous learning!

 


Measuring Effectiveness: The Software Industry’s Conundrum

On “Measuring Effectiveness”

I’ve been saying for seemingly decades, this is (one of?) our nascent software industry’s biggest conundrums (maybe even an enigma?).

Just how do you prove a team is “doing better?” Or that a new set of processes are “more effective?”

My usual reaction when asked for such proof:

“Ok, show me what you are tracking today for the team’s performance over the past few years, so we have a baseline.”

Crickets…

But seriously, wouldn’t it be awesome if we could measure something? Anything?

For my money:

Delivering useful features on top of a reasonably quality architecture, with good acceptance and unit test coverage, for a good price, is success.

Every real engineering discipline has metrics (I think, anyway, it sounds good — my kids would say I am “Insta-facting™”).

If we were painting office building interiors, or paving a highway, we could certainly develop a new process or a new tool and quantitatively estimate the expected ROI, and then prove the actual ROI after the fact. All day long.

In engineering a new piece of hardware, we could use costing analysis, and MTBF to get an idea on the relative merits of one design over another.

We would even get a weird side benefit — being relatively capable at providing estimates.

In software, I posit this dilemma (it’s a story of two teams/processes):

Garden A:

  • Produces 15 bushels (on average) per month over the growing season
  • Is full of weeds
  • Does not have good soil management
  • Will experience exponential (or maybe not quite that dramatic) production drop off in ensuing years, requiring greater effort to keep the production going. Predictability will wane.
  • Costs $X per month to tend

Garden B:

  • Produces 15 bushels (on average) per month over the growing season
  • Is weed free and looks like a postcard
  • Uses raised bed techniques, compost, and has good soil management
  • Will experience consistent, predictable, production in ensuing years
  • Costs $Y per month to tend

I could make some assertions that $Y is a bit more costly than $X… Or not. Let’s assume more costly is the case for now.

To make it easier to grok, I am holding the output of the gardens constant. This is reflected by the exorbitant rise in cost in the weedy Garden A to keep producing the same bushels per month… (I could have held the team or expense constant, and allowed production to vary. Or, I could have tried to make it even more convoluted and let everything vary. Meh. Deal with this simple analogy!)

 

Year 1 2 3 4 5 6 7 8 9 10
Garden A 100 102 105 110 130 170 250 410 730 1600
Garden B 120 120 120 120 120 120 120 120 120 120

If we look at $X and $Y in years 1 through 10, we might see some numbers that would make us choose B over A.

But if we looked at just the current burn rate (or even through year 4), we might think Garden A is the one we want. (And we can hold our tongue about the weeds.)

But most of the people asking these questions are at year 5-10 of Garden A, looking over at their neighbor’s Garden B and wanting a magic wand. The developers are in the same boat… Wishing they could be working on the cooler, younger, plot of Garden B.

What’s a business person/gold owner to do? After all, they can’t really even see the quality of the garden, they just see output. And cost. Over time. Unless they get their bonus and move on to the next project before anyone finds out the mess in Garden A. Of course, the new person coming into Garden A knows no different (unless they were fools and used to work in Garden B, and got snookered into changing jobs).

Scenario #2

Maybe we abandon Garden A, and start anew in a different plot of land every few years? Then it is cheaper over the long haul.

Year 1 2 3 4 5 6 7 8 9 10
Garden A 100 102 105 100 102 105 100 102 105 100
Garden B 120 120 120 120 120 120 120 120 120 120

I think the reason it is so challenging to get all scientific about TQM, is that what we do is more along the lines of knowledge work and craftwork, compared to assembly line.

The missing piece is to quantify what we produce in software. Just how many features are in a bushel?

I submit: ask the customer what to measure. And maybe the best you can do is periodic surveys that measure satisfaction (sometimes known as revenue).

Matt Snyder (@msnyder) tweeted me a nice video: Metrics, Metrics, Everywhere – Coda Hale


Regex to Exclude Multiple Words

For Google Analytics, I wanted to create some chainable filters to deal with a set of subdomains that can occur on alpha, beta, and production, etc. So I needed to find a way to say “Give me all of the production subdomains, and none of the alpha/beta variants, or preprod.”

Here are the sample URLs that I want to filter out the alpha/beta/preprod from:

acme.domain.com
acme.beta123.domain.com
acme.alpha123.domain.com
wyle.alpha.domain.com
wyle.showme.domain.comcool_stuff.html
acme-two.domain.com
acme-two.preprod.domain.com

Here is the resultant regex:

^w+-*w*.(?!(?:alpha(123)*.|beta(123)*.|preprod.)domain.com).*$

And here is what Rubular looks like:
Rubular Multi Word Exclude URL Regex

Big shout out to Rubular.com, an awesome place to test out regex!

Don’t be the Frog!

Ever hear the muse about the frog and the boiling water?

I use it to describe the behavior where we innocently allow otherwise really odd things to happen to software products over time. “Oh, it’s been like that for 10 years!” It is never a single, discreet moment in time; instead it kind of “sneaks up” on you if you are not paying attention.

For example:

  • Code that is hard to unit test without bringing in all sorts of dependencies (even mocking barely helps)
  • That javascript error that happens in (unsupported) Firefox, but not in (supported) IE or Chrome
    • Instead of being more compatible with all modern browsers via a simpler and more consistent UI framework.
  • Context menus (right-click) that have everything but the kitchen sink in them
    • Instead of more clearly articulating the commonly-used vs the rare menu choices
  • A UI that nearly defies Cucumber/Capybara testing
  • A “Save As” dialog that also offers up to the user the ability to control the next landing page, to deactivate the item, to create a new item under a new parent, and to generate the PDFs for the item All under Save As!
    • Instead of making the UX more clear and solving the real problem: undesirable workflow.
    • We have Save. We have Save As. But wait! There’s more! You can Save As, give a new name, and choose from 3 different pages to go to next!

I often think it stems from a few common shortfalls:

  • The real problem was not solved, but simply masked
  • Complexity begets more complexity
  • The domain is not understood, so incompatible fixes are tacked on in the wrong spots
  • We didn’t have time to do it right, so we just got something that would work shipped
  • The customer(s) wanted it built like this
  • There is no overriding vision for the type of user experience we want to convey
  • There is no hard-ass product owner putting their foot down

Don’t let this discourage you if you are still outside the pot looking in at friends and colleagues who are in the hot water. It’s an opportunity to improve, clean up, straighten things out, and start anew.

Don’t be the frog!

 


 

Best way to Learn Authentication?

This was a question posed on the Rails Studio mailing list…

My initial reply to a suggestion to check out Railscasts was…

And then, once you are happy with your learning, throw away all of your Auth code and get the Devise gem loaded and working 🙂

To which, the OP replied:

Hmm, I would think your own custom solution would always be smoother than using someone else’s code. Why use Devise?

Here is my reply:

One day, in a galaxy far away, I needed to have millisecond resolution timing on the PC to do some reaction time experiments with subjects as they were exposed to various shapes and colors (eventually used to improve HUD symbology for fighter aircraft display). Since the computer timer chip could only get down to 54ms, I was on the prowl for a better way. Lo and behold, I found some assembly code techniques I could use to over clock the timer chip. Problem solved. I hated writing assembly code… But I had to. Must. Not. Be. Blocked.

Product went into production, and was used by the researchers…

A month or two later, I found an awesome timer package for $50. It did what I needed and more, by a guy who specialized in this.

As fast as I could, I ripped out my code and dropped in the new library. I never looked back. You see, timing was not core to my research app, but rather contextual (like printing or graphing). (As an aside, the module grew and grew and kept up with hardcore CPU vagaries… it was able to tune itself in spite of processor logic becoming much less predictable as it went from 286 to 386 to 486 to 586. I was glad I didn’t have to keep up with the CPU technology! I used this same core functionality on apps that I wrote to control missiles in real-time.)

So, if your business is all about writing an authentication module, then that is what is “core” for your work, and you should craft your own and hone it to perfection.

Or, if you just want to do it as a learning exercise, that is great! Learn, and then pitch your code.

But for me, I am all too happy to drop in some other folks’ gem that gets a set of functionality up and running quickly, so I can get on with my core functionality and not be distracted.

YMMMV

uTest Interview

I “ran” into the nice folks at uTest, and they asked me a handful of questions.

I answered… in a shockingly (for me) succinct way.

1. As a long-time agile coach, you can probably tell right away if agile is going to be employed successfully within a company or organization. If you had to pick one quality or trait that’s required for agile success, what would it be? In other words, what’s the first thing you look for when beginning a coaching project?

[JK] Willingness to change. That’s all I ask. Be open-minded to trying things a different way.

2. Looking back, did you ever think the agile movement would grow to where it is today? What’s surprised you the most about agile’s course over the last decade? The good and the bad.

[JK] No. How could 4 measly bullet points cause so much ruckus?! The biggest problem I see is the co-opting of the term “agile.” That is, folks are doing agile in name only. They don’t really get the subtle nuances about what it means to be agile, and simply go through some motions and try to “do” agile. While learning by doing is a key technique for learning anything new, somehow, many people seem to just do a handful of activities without much reflection or introspection.

3. Fill in the blank: The most common agile mistake development teams make is ____.

[JK] Not thinking. Agile requires continuous use of thinking… Are we improving? Will this help? Should we stop doing this activity? Should we do more of this activity? It takes effort to avoid complacency, which is hard for most of us.

4. From what we read, much of the inspiration for the agile movement originated not in the software space, but rather in the production/manufacturing space. How often (if at all) do you consult on non-software projects and how does it change the way agile is applied?

[JK] I’m not so sure that is true of the original 17 co-authors. While many of the lean/kanban concepts popular today owe their theories to manufacturing/production processes, I don’t recall any of the original folks waxing eloquent about being inspired by some non-software gigs. But I could be wrong. I have consulted on manufacturing automation/tracking/planning processes – and for that, a lot of the agile techniques apply. But I mostly focus on software projects.

5. A previous guest of our blog once referred to the “victims of fake agile” – i.e. the people whose lives were ill-affected by the misapplication of agile. Is this similar to what you refer to as the “pseudo-master of Agile”? And in your opinion, what’s the biggest threat to an organization that adopts agile in a half-hearted manner?

[JK] There have been snake-oil salesmen since the dawn of mankind. If an organization is not able to hire good talent or good agile consultants, then a lot of damage can be done. Although, mostly, it would be the cost of lost opportunity going forward. That is, by not embracing and practicing “Real Agile ™,” the company wastes time, and time just might be money. However, as a counterpoint/cynical view… Most companies that do agile in name only are often large, matrix orgs, where the software is one small aspect of their business. Screwing up Walmart.com likely has very little impact versus someone screwing up their entire logistics system that moves products to stores.

6. We assume (and we could be wrong) that there was a healthy amount of debate amongst the authors of the Agile Manifesto. If so, what was the biggest point of contention within the group and how was it resolved?

[JK] I think the biggest area where we disagreed was the “how long is an iteration” – that is, how frequently should we expect tangible results? Many were at the two-week level, and others (Alistair) were at the 4+ weeks.

7. As a longtime agile coach, you’ve helped countless organization achieve better results with the approach. We’re curious to know when it hasn’t worked so well. Have you ever advised a company or organization to forgo agile in favor of another method? If so, what were the circumstances?

[JK] Agile is ALWAYS the right answer. What can be wrong about doing better with a set of resources? What can be wrong with reducing the gap in time between taking some action, and getting some feedback? Agile is a state of mind.

8. As with any manifesto, people are bound to misinterpret or misapply the main tenets. If you had to single out one particular way that agile has been misinterpreted, what would it be?

[JK] The classic missteps are usually NO documentation and NO design work upfront.

9. As we’re sure you are aware, Agile has its fair share of detractors and skeptics – and they can be a very vocal bunch. Why do you think agile is so strongly disliked in some quarters? And what is the one argument against agile that irks you the most?

[JK] I don’t really care to change people’s minds. The Agile Manifesto is irrefutable, as it gets to the root of human nature in a software development context – and is analogous to the founding documents of the United States. Agile promotes strong, disciplined individual and team responsibility and continuous participation from the development “citizenry.” It is much easier to fall back on some process just because someone wrote it in a book than it is to use your brain. No particular argument irks me, because I don’t care what people with closed minds think. A fool with a tool is still a fool.

10. Fill in the blank: The key to a successful agile testing team is: ____

[JK] being totally involved, working the upstream part of the process in addition to downstream verification.

11. Have you stayed in touch with the other authors of the Agile Manifesto? And have you considered “getting the gang back together” to publish any other materials?

[JK] I “hang” with Ron, Chet, Bob, Alistair, and Martin mostly in cyberspace. We got together for the 10th-year anniversary (the only Agile Alliance conference I went to, as it was paid for). We talked about getting together sooner than in another 10 years because we had a great time. But who knows if it will come to fruition. Much like the USA’s Founding Fathers, they got together for a momentous occasion but then went their separate ways.

12. What’s Jon Kern doing when he’s not helping companies improve their development process?

[JK] I like to mountain climb, hike, drive my Audi on the track or autocross, and ski. But when I am not doing that, I am writing ruby and rails code using MongoDB, git, and the wonderful world of ruby gems. I wish this remarkable constellation of language and tools existed when I was doing C++ way back when!

Read more on:

Testing the Limits With Jon Kern, Agile Manifesto Co-Author

 


Capybara Support for Multiple Submit Button Types

We had a case where we wanted to create smoke tests to ensure each customer’s subdomain was working (used pre- and post-deployment). Unfortunately, not all of the customer’s login pages were consistent in how to “submit” the login form 🙁

The Cucumber tests looked something like this:

  Scenario Outline: Check that the navigation is correctly customized per org
    Given I login as "<user>" of "<org>"
    And I am on the "<page>" page
    Then I should see only the expected "<menu_items>" in top nav bar
  Examples:
    | user       | org      | page | menu_items                                      |
    | acme-admin | acme     | Home | Home, Preferences, Feedback, Help, Logout       |
    | wyle-admin | wyle.com | Home | Home, Preferences, Links, Help, BI Tool, Logout |

Here is how I used Capybara’s find() method to get around this issue:

# A bit of a hack, org_name is normally a subdomain, but sometimes it is the complete domain
def login(user, org_name)
  # Use the below to automatically hit each user's org's server
  if org_name.include? '.com'
    Capybara.app_host = "http://#{org_name}"
  else
    Capybara.app_host = "http://#{org_name}.mydomain.com"
  end

  visit '/'
  fill_in 'username', :with => user
  fill_in 'userpwd', :with => '***'
  begin
    click_on 'submit'
  rescue Capybara::ElementNotFound
    page.find(:link_or_button, 'Log In')
    click_on 'Log In'
    rescue Capybara::ElementNotFound
      pending "Need to determine how to invoke the Login button for #{org_name} near Line ##{__LINE__} of #{__method__} in #{__FILE__} "
  end

  # Ensure that login was successful
  page.should_not have_content 'Login failed'
end

Since our analysts write a bunch of these tests, I also added in a helpful error message should a new org get added that has yet another style of login.


Keep your Cukes Narrow

It is not uncommon to wonder about how to create data for cukes…

  • Keep it high level?
    Given I have 4 products
  • Or explicitly define data; e.g., using a table

As a broad answer to this question, it all depends on what behavior you are specifying. There is no single, right way.

My usual rule of thumb is to limit the setup to just those parts of the problem domain “object graph” that you care to test in the current scenario. That helps draw attention to the most “narrow” bits of the system that are under test. Otherwise, if you continue to build everything from scratch for all scenarios, it is sometimes hard to see the purpose of the test because it is lost in all of the setup code. Sometimes you care about the details in the parent object, sometimes you want to test the sum of the parts, and other times you are focused only on a small aspect of the object model.

Examples

Suppose we are making bread, and we have a set of recipes. Each recipe has a set of ingredients. When we go to make 5 loaves of bread, the list of ingredients are properly re-sized and displayed so we can mix the dough and make a new batch of bread.

My first scenario might be detailed around setting up the core recipe/ingredient relationship:

Scenario: View a recipe
  Given I have the following recipe:
  |Name | Artisan Bread       |
  |Yield| 2 1-lb oblong loaves|
  |Prep | 30 min              |
  |Proof| 3 hours             |
  |Baking| 35 min. at 450 deg F|
  With the following ingredients:
  |Ingredient       |Quantity|
  |White Bread Flour|6 cups  |
  |Whole Wheat Flour|0.5 cups|
  |Granulated Yeast |1.5 Tbsp|
  |Coarse (sea) salt|1.5 Tbsp|
  |Water, 100 deg   |3 cups  |
  When I view the recipe
  Then I should see the recipe

So the above scenario gets us focused on the basic bits of the Recipe ----*-> Ingredients part of the model, and the desired behavior of what a recipe display looks like. Note: on the “Then” I chose not to focus on how it is displayed. I could have said something like “…with the recipe info at the top, followed by a list of ingredients.”

Now suppose the next scenario we tackled was the ability to “resize” the recipe to make some multiple of the base quantity? Do we need to repeat the same sort of setup as we did above? Or can we get away with defining less information? That is, using something like FactoryGirl, we could predefine some basic recipe data, if nothing specific is needed.

Scenario: Resize the batch to triple the yield
  Given I have a "Hard Tack" recipe that yields "25 cakes"
  With the following ingredients:
  |Ingredient | Quantity  |
  |Flour      | 4 cups    |
  |Water      | 2 cups    |
  |Salt       | 4 tsp     |
  When I resize the recipe to 3 times the size
  Then I should see the following ingredients
  |Ingredient | Quantity  |
  |Flour      | 12 cups   |
  |Water      |  6 cups   |
  |Salt       | 12 tsp    |
  And a yield of "75 cakes"

While the difference is subtle, the point to the above scenario is to not clutter it with the core recipe elements as were visible in the first scenario.

For a more extreme example of “narrowing” the focus, lets look at another scenario. This time, the business tells us they want users to be able to rate the recipes.

Scenario: Users can 'Like' a recipe
  Given I have a "Swedish Hard Tack" recipe
  When I Like the recipe
  Then I should see the Like Count increment by one
  And I should not be able to Like the recipe a second time

So here you can see there is no reason whatsoever to care about the details of the recipe. In fact, I could have left off the recipe name, but sometimes I like to keep some sense of the domain visible. Had I written the Given to show all of the detailed data, it would have obscured the meaning of the scenario, as this scenario would then look like the other scenarios.

Scenario: (BULKY VERSION!) Users can 'Like' a recipe
  Given I have the following recipe:
  |Name | Artisan Bread       |
  |Yield| 2 1-lb oblong loaves|
  |Prep | 30 min              |
  |Proof| 3 hours             |
  |Baking| 35 min. at 450 deg F|
  With the following ingredients:
  |Ingredient       |Quantity|
  |White Bread Flour|6 cups  |
  |Whole Wheat Flour|0.5 cups|
  |Granulated Yeast |1.5 Tbsp|
  |Coarse (sea) salt|1.5 Tbsp|
  |Water, 100 deg   |3 cups  |
  When I Like the recipe
  Then I should see the Like Count increment by one
  And I should not be able to Like the recipe a second time

Again, this is a subtle point. But making it easier for readers of the feature file to see differences without having to “strain” can improve understanding and reduce potential for errors.

For more on Cucumber, peruse my other posts on the topic, and see this “Crib Sheet.

Easing New Developer Ramp-up Time

On a recent healthcare start-up team, it grew from my buddy (who moved on after 6 months or so) and I, to a handful of developers/sub-contractors.

Here is how we tried to make it fairly efficient. We just started tracking what was needed, getting feedback as each new developer went through the process, and improving the instructions and process along the way. If something was missing, we added it. If something was not clear, the new developer could amend the wiki.

By the 3rd new developer, or so, we had it down to where they could get started and begin a legitimate issue in less than a half day — from getting set up to being able to commit and deploy a new “feature.”

There was a section at the top that shared a good team chat room session with a new remote developer:

Getting Started Chat Room Conversation

That was followed by the FAQ-like list of links:

One of the first reasons I wanted to make it easy for a new team member to get rolling, was so that our friend Max — who would be doing our QA from Russia — could get started. As we added the first couple of devs, we probably decreased the start-up time as follows:

As part of “Getting Started,” I would include a simple Jira issue that helped them ensure that everything was working and that they followed our dev process:

  • Git and Dev and database (MongoDB) environment obviously had to be set up
  • Access to Jira to assign themselves to the issue, and move it — Kanban style — to the In Progress state.
  • Commit the work and the passing tests
  • Drag the Jira issue to “Done”

 

Since Atlassian’s Confluence Wiki does a stellar job at versioning pages, I actually looked back to see how the page grew and morphed over time. It started out rather modestly (and empty):

After it grew a bit bloated:

It was successively refactored into its current state, here is a snippet of the 70 versions that this page underwent from March 2011 through July 2012.

Wikis, like code, need to be tended to, nurtured, and refactored to provide the best value.