1/10/2015

Tribe Level Ceremonies

We take new words from Spotify to describe a scaled agile organization. Tribes contain squads which deliver features. Guilds share subjects and Chapters share skills.

This is about extending traditional Agile to optimize for larger teams. Scrum talks of teams with daily Stand Ups and a Scrum of Scums to share between teams. It assumes that information is shared between teams via a Scrum of Scrums representative but this doesn't really work.

We don't do team Stand Ups anymore. We don't do Scrum of Scrums anymore. Instead, all Squads in a Tribe attend a daily Stand Up and share red, yellow, green status of the Squad. Thirty people in one room for 10 minutes. Thats four Squads in one room for 10 minutes. Thats four announcements of green most days, occasional yellows with some details and followup actions assigned and a rare red where everyone takes note and assesses how to change resource, blockers or what ever it takes.

This benefits us in a few ways. We decided a long time ago that a Squad Stand Up with a single developer reporting "Finished X, moving on to Y today, no blockers" was not effective. Its not effective because the information is too detailed for most listeners, and redundant for everyone on the Squad because they are all working and communicating everyday. The goal of Stand Ups is to decide if the current plan needs changing and how to change it. Everyone knows the current plan so no point reiterating it but risks and blockers potentially drive change and that is the key that these discussions should focus on.

So, from the old Stand Up definition.

- Please tell everyone what you did yesterday, what you are going to do today and any blockers you have.

We now have a definition:

- Your Squad must indicate the red, yellow, green status of your Sprint commitments and, if not green, what the projected problems are.

This change is made possible because these people have been doing Agile for years and so the need for a single team to "share status" every day is irrelevant now, they do that all day. They all sit within 10' of each other and openly announce issues as they occur. They commit and push code all the time and they ensure the build is always watching them.

If you have developers sitting in cubes, don't do this. If you are new to Agile, don't do this. The habits of the people on your team can not sustain this kind of automatic behavior.

How do you know if you can do this? Do you feel an uneasy fear if you have't pushed for more than 15 minutes? When you pull do you look at the code changes and immediately give feedback? Do you feel strange not having someone sitting next to you arguing with your approach to a problem? Would you feel comfortable if the code you just pushed was to be release to production now.

People go through changes when they practice Agile. Its more than a process, its a re-programming of a developers instincts. 








Making Change a Habit

I adopted a new rule in 2000 that states, "If you think the problem can be solved by just trying a little harder, then you have wrong solution". We spent decades of wasted time telling ourselves to just try harder to write tests, then TDD came along and it was obviously a better answer.

The try harder admonishment is an endless, repeated, diatribe about of our personal failures and how we should just buckle down and be better. Stop trying harder and start thinking.

I am not saying that, on an individual level, we don't have things we can do better at, and need to be pushed and cajoled into doing something about, but as an answer to an industry of professionals that work hard to build the best solutions they can, "try harder", is wasted breath.

Some things we here today are "Developers just have to try harder to make their code secure", this will never happen so just stop saying it. Instead, change the process to make security a primary focus on every team. Add a security engineer to every team who only, reviews, writes tests and verifies a product evolves appropriately. Enterprise level security initiatives are valuable but are not the full answer, as evidenced by the hacked reality we see every day.

Have you heard this one; "We have to try harder to share information from Scrum of Scrums with the rest of the team". I get that some of you probably do this well, but most do not, and the solution of trying hard doesn't work. Getting the right information into the right minds at the right time is an adventure in frustration. However, allowing for time-to-share and getting how-to-get-information concepts shared is much easier. The human brain works well in a limited number of prescribed scenarios and no-everything-all-the-time is not one of them. Optimize focus, intentionally limit sharing till required and allow time for understanding.

What about from your ops team; "If developers would only try harder they would understand the operations requirements and build the products we could use". Does your ops team hate you? If you are doing it right, a member of your ops team is sitting next to you for some hours of the day talking to you about what they will need to operate the feature you are adding. DevOps is a hard change, do it. Add operational intelligence as an aspect of every feature you implement with acceptance criteria and functional tests. Think of it as BI for the operations teams.

Has  your business every asked you to try harder to get BI reports out faster? "Why does it takes so long for the reporting about a feature to come out after the feature is in production? BI teams and dev teams are usually separated. This doesn't work. Every feature has a BI impact and needs consideration at the time the feature is implemented. Release your feature and the BI reporting as one package.

We have a support desk that answers the phone every day, and they hate us. "Oh please try harder to ensure we can answer customers questions. Just try harder to tell us what you are changing". How do we get support teams, with the hours they work, synchronized with feature development activity that we are working on. Send an email on release day? Sure that will work. "Oh, by the way, that button you used to use, just moved, good luck."  I don't know what the next change needs to be for this one, yet.

If you and your team want to be better, first change how you do things, then measure, and then change again. If you are not changing, you make it hard to change, and inevitably become a lagger in the ways of our ever improving approach to our profession.

If you believe that change damages teams because it introduced confusion, then you see change as an obstacle and will never master it. Don't use change as a tool, if you are not ready. With change comes chaos, and only teams experienced with change know how to own chaos. If your team members do not communicate, do not challenge each other and are not willing to be part of a solution, then change will destroy them. First empower the team, then master change.

On an experienced team, what happens is, a team member sees a change, and reacts by calling the team to order and facing it, they argue about how to address it, devise an approach to it and then reengage to the mission.



Change does disrupt, but since it offers the opportunity to grow, mastering it must be a primary goal.

Change is exciting.

12/08/2013

RubyConf 2013 - What Changed?

I have noticed that the last few Ruby Conferences I have attended, Ancient City Ruby and Ruby Conf 2013, have not lived up to some of my expectations. This is not a fault of the conferences but of how I perceive improvements.

In the early days of Ruby, relatively speaking, when all the giant advancements were being made, like Rails, gems, migrations, rake, Capistrano and _why's latest ideas. I am sure we can all have our own lists of world altering ideas that fundamentally changed how we work every day. Some of this radicalization has waned.

I have been reflecting on how progress can be measured by tiny changes as well though the impact is slower and less measurable. For example, Jim Weirich works on Argus and, then Artoo changes how we approach Robotics in Ruby. Independently they are simple API's, but that simplicity becomes a fundamental driver of adoption and the growth of new ideas.

John Mair works on an improved Ruby shell and that simple improvement drives some re-birth of Small Talk ideas. What I can edit and interact with code at runtime? Small Talk got to where it is for many reasons both good and bad, but what will happen when we re-grow the good ideas into something new?

For me, I am going to pay more attention to the micro-drivers of our future. Keep it simple so that we can all be part of the growth.

Ruby is creating a thrilling world.


8/17/2013

Ruby Warrior - Game Emulation

Emulating the black box behavior allows us to build tests that prove your code works, as long, as the emulation remains close to the real thing. The Ruby Warrior runtime has features within it, that I do not know yet since I am still at level 7.

The output from my game emulator looks nice and allows me to great new alternative levels that exercise all the features of my player that I wish to.

GAME START
| ^     >|
|  ^    >|
|   ^   >|
|    ^  >|
|     ^ >|
|      ^>|
|       ^|
GAME OVER: ALIVE
GAME START
| ^ C   >|
|  ^C   >|
|  ^    >|
|   ^   >|
|    ^  >|
|     ^ >|
|      ^>|
|       ^|
GAME OVER: ALIVE
GAME START
| ^ S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^S   >|
|  ^    >|
|   ^   >|
|    ^  >|
|     ^ >|
|      ^>|
|       ^|
GAME OVER: ALIVE

A simple rspec runner of these game layouts and a way to encode the game boards makes setup easy.

 describe "Game" do  
  let(:player) { Player.new }  
  
  it "plays empty board" do  
   game = Game.new("    >")  
   game.play(player)  
   
   player.should be_alive  
  end  
   
  it "rescues a sad caged pair of eyes" do  
   game = Game.new("  C  >")  
   game.play(player)  
   
   player.should be_alive  
  end  
   
  it "attacks some sludge" do  
   game = Game.new("  S  >")  
   game.play(player)  
   
   player.should be_alive  
  end  
 end  
   

The simple Game runner.

 class Game  
  def initialize(pieces)  
   @pieces = pieces  
  end  
   
  def play(player)  
   warrior = Warrior.new  
   warrior.board = Board.new(@pieces)  
   
   puts "GAME START"  
   while (warrior.alive? && warrior.on_board?) do  
    puts warrior.board.with_player_at(warrior.position)  
    player.play_turn(warrior)  
   end  
   puts "GAME OVER: #{warrior.alive? ? 'ALIVE' : 'DEAD' }"  
   
   warrior.alive?  
  end  
 end  
   

Ruby Warrior - Trying Again

It is clear that a solution to a problem like this can't just be imagined out of thin air. I am just not that smart. Just writing if statements was satisfying and productive to start with but once level 7 hit and I had to change direction there was no alternative but to throw everything away and start again.

This time, I decided to create a fake warrior implementation, an write some rspec tests to ensure that the actions I chose were appropriate. Then "release" (copy) that code to "production" (paste) to see if it worked there as well.

With this approach, I am making headway but can only solve level 2 because I haven't reimplemented the resting process yet.

Warrior Fake

class Warrior
  attr_accessor :position
  attr_accessor :board
  def self.at_position_1
    warrior = Warrior.new
    warrior.position = 1
    warrior
  end
  def self.next_to_sludge
    warrior = Warrior.at_position_1
    warrior.board = [:sludge]
    warrior
  end
  def initialize
    @position = 1 #zero based
    @attacked = false
    @board = []
  end
  def walk!
    @position += 1
  end
  def attack!
    @attacked = true
  end
  def has_attacked?
    @attacked
  end
  def feel
    @board
  end
end

Player Implementation

require './warrior_fake'
class Context
end
class Action
  def self.choose(warrior, context)
    if !warrior.feel.empty?
      Attack.new
    else
      Walk.new
    end
  end
end
class Walk
  def run(warrior)
    warrior.walk!
    warrior
  end
end
class Attack
  def run(warrior)
    warrior.attack!
    warrior
  end
end
class Player
  def initialize
    @context = Context.new
  end
  def play_turn(warrior)
    action = Action.choose(warrior, @context)
    action.run(warrior)
    warrior
  end
end

Specs

require './spec_helper'
require './warrior_fake'
require './warrior'
describe Player do
  let(:player) { Player.new }
  context "walking" do
    it "moves forward" do
      warrior = player.play_turn(Warrior.at_position_1)
      warrior.position.should == 2
    end
  end
  context "sludge" do
    it "notices sludge" do
      warrior = player.play_turn(Warrior.next_to_sludge)
      warrior.should have_attacked
    end
  end
end
describe Action do
  let(:context) { Context.new }
  let(:warrior) { Warrior.at_position_1 }

  context "construction" do
    it "walks forward" do
      action = Action.choose(warrior, context)
      action.should be_a Walk
    end
  end
end
describe Walk do
  it "forward" do
    walk = Walk.new
    warrior = walk.run(Warrior.at_position_1)
    warrior.position.should == 2
  end
end
describe Attack do
  it "forward" do
    attack = Attack.new
    warrior = attack.run(Warrior.next_to_sludge)
    warrior.should have_attacked
  end
end


Thank-you Ruby Warrior

I just ventured into the dungeons of the Ruby Warrior and spent an hour of my life that I can not get back, but would like to if that is at all possible. What a great time to be writing ruby, to program a knight, in a live dungeon.


I made it to Level 7 before my code was so complex that refactoring is inevitable. I count at least infinity code smells in this. Flags, single method, no intentional behavior, no single responsibility. I am considering some UI testing tool to prove that I can pass each level with the same codebase.

Good times.

class Player
  def play_turn(warrior)
    if !warrior.feel(:backward).empty?
      if warrior.feel(:backward).captive?
        warrior.rescue! :backward
        @saved_captive = true
      else
        warrior.attack! :backward
      end
    elsif !warrior.feel.empty?
      if warrior.feel.captive?
        warrior.rescue!
        @saved_captive = true
      else
        warrior.attack!
      end
    elsif warrior.health < 20
      if warrior.health < @health
        if warrior.health < 12
          warrior.walk! :backward
        else
          warrior.walk!
        end
      else
        warrior.rest!
      end
    else
      if @saved_captive
        warrior.walk!
      else
        warrior.walk! :backward
      end
    end
    @health = warrior.health
  end
end

8/03/2013

Waterfall Disease - Symtoms, History and a Cure

It is easy to spot the symptoms in aggressive cases but can present in subtle ways as well. It effects individuals and teams and is communicable. The cure is long and slow but the young heal much faster. If you have been infected with this disease for more than 20 years, the chances of a full recovery is slim.

Symptoms

A programmer feels the strong urge to open a documentation tool before a code editor. This is not a guarantee of infection but a strong indicator.


An infected team will wait for a task to be given to them and then talk about how it is the wrong task or how long it will take to implement. Similarly infected product owners will first ask how long before asking what should be accomplished.

A programmer will, when asked what it would take to implement a feature, answers in terms of the complexity and duration. For example, "OH that would be difficult, we would even have to change the code", or "We would have to talk to that other team, so that will take much longer".

An infected team or programmer assumes that the deadline means they will have to hack in a bad fix, even when there is no stated deadline. These individuals just assume that they will be pushed to make bad decisions so make them as the default, as thought there is no other approach.

A team member states "that is his responsibility", or makes a suggestion or proposal for a change like "I think we should do X". Each of these forms of communication relinquishes responsibility to others, ensuring that the team member does not have to take ownership of the idea they are sharing.

A team member will hand-off a task with the statement "you need to do X so that we can accomplish goal Y". This team member will, and watch for this for it is quick, turn on their heals quicker than normal, and walk away with a slight smile believing they have helped but actually are just passed the blame.

An infected team member will act out, taking actions in direct opposition to the teams goals, and other infected members will watch as though they have no control. They are thinking that the boss should fire that person, not realizing that they should also be considered.


History

Waterfall disease has been with us for decades. Until the late 1990's it was thought of as normal, even part of the best practice of what a programmer was. Only as the year 2000 approached and the new Agile medicine was introduced to the market did everyone start thinking that there might be another way.

Unfortunately, this Agile medicine tastes very bad and patients remain in denial of the problems, just because of that possible bad taste. It is not uncommon for teams, thrashing uncontrollably and screaming about the unacceptability of their plight, to also state that "the medicine will never work" and refuse to sign-up for the treatment program.

Cure

The treatment for waterfall disease is not easy and takes time. Unfortunately, this conflicts directly with the infected parties who have no patience for change.

The cure comes in 3 main phases: a strict diet of learning, combined with the constant guidance of mentors to re-map the brain pathways and finally a change inoculation.

The learning pills must be dosed carefully across time to avoid overload. An ideal learning pill regimen might look like this though results may vary depending on how acute the infection is.

  • Complete removal from the environment that promotes the infection. This might mean leaving the programming environment, the building where re-contamination is possible or even, in the most aggressive cases, leaving the company that actively promotes the disease, is the only way to avoid a relapse.
  • Daily doses of TDD to begin with interspersed with insights into why the current feelings they are experiencing are actually not normal. Knowing that they have a problem is an excellent step toward recovery but do not expect this to occur in these first rounds. Continue this repetitively for 2 weeks switching from a training environment to a practice environment until you start seeing the natural antibodies of the human body kick into gear. These changes show themselves in the form of surprised questions like "so this actually means I don't have to fix bugs anymore"?. Be gentle with the initial naive questions for the physical changes that are underway are only loosely bonded.
  • At some point a sense of wonder, and excitement about the future starts to seep in. Recognizing these moments is key to cementing the changes and reducing the possibility of relapse. Show your excitement about the future and talk of your new life, clean of disease.
  • Once two "sense of wonder" moments have passed it is time to move to the next phase of treatment. Collect one or more of these patients into a team and task them with a green field solution. The use of a green field solution simplifies the continuing diagnostic work that is going to be necessary as the work progresses. This also starts the mentoring phase of the cure.
The mentoring must be administered throughout the process for at any time, day or night, an infected individual will take an action that completely undermines their cure. Examples, might be:
  • Mid-night implementation of a new feature. Attempted under the guise of improving the teams velocity (and they will use that word even if they do not understand it), but actually, this action is driving a sense of self-congratulatory excitement of achieving goals without the mentor's gaze and without tests. Protect against this with early investment in fully automated functional tests. The next days failing build will identify the culprit and allow the mentoring to focus appropriate action.
  • Active creation of cliques, through a sub-team secret design sessions that can then be presented as great successes to the team, when in-fact, they serve more to isolate and inject mistrust amongst the team members.
  • Little code changes without tests will leak into the codebase, often with a source control comment unrelated to the change or misdirecting the mentor to a larger change. When challenged the response will likely be a sheepish grin, as though that still works now that they are fully grown up adults, and the statement like "that was just a one character change", or "its only in a tool, not the real app". These are actions that must be stopped, in group therapy sessions, to ensure that everyone agrees that they want to be cured.
The change inoculation is where most of the physical and mental pain is experienced. Analysis of relapsed patients bring to light complaints about the deep personal loss of family pictures and the requirement to move that caused discomfort. Screen sizes, keyboard types and strange IDE's are many of the hurdles that patients must push through. Also they will attempt apparently logical arguments explaining why sending an email is fare faster than walking 10 feet; "plus they have a record of the conversation don't they? Perhaps they want to refer back to it later? They won't have to come and ask me again? Just consider the time savings of not having to move."

This phase should not be trivialized. Your patients complaints will seem small and full of self-interest but they are one of the biggest drivers of resistance to the medication. Failure to attend to these details will initiate a slow drift back to habits that are more comfortable. Many retrograde steps will be subtle, almost imperceptible; a head turned to the floor during a standup, an extra second of reluctance to approach the board and be part of the team. The feelings of isolation, and failure will compound this situation accelerating the relapse.

The inoculation itself can take many forms but centers around making change the norm through the use of intentional disruption. For example,
  • Throw away all desktop computers and replace them with laptops to promote movement. In the same vein, ensure that wireless network access is available and the old wire is disconnected.
  • Interrupt the team with cake but do not take it to their desks. Instead, place it 20 feet from them so that they are encouraged to move. Repeating this makes movement more normal and bridges the gap to a time when movement to communicate with team members is the new habit.
  • Mandate pair programming and make sure that it is with new people all the time. Having to work with team mates ensure that they know each other's names and start gaining insight into other cube silo's.
  • More radical, but utterly required to ensure success, is the removal of cubical sitting structures. Some powerful conversations with CIO's will be necessary to drive this kind of medication. 
  • Disabling email for periods of time forces movement for simple conversations, changing the quality of communication so much that teams will start experiencing a high velocity team feature known as "common thought". At first this is startling, and must be called out by mentors as a healing step, but will soon become the natural order in which simple 30-second exchanges can accomplish what was once days worth of drifting, misinterpreted email exchanges.
The change inoculation is fraught with complaints like "but I liked my privacy" and I would rely on your mentor to resolutely and clearly state the futility of these gestures. Perhaps offer "we could build you your own office if you like" or "aren't we all so lucky to have private homes to go to". Lean on the emotional content of these interactions, logic is not as effective in this inoculation process. Only the emotions of team membership and commitment to common goals will drive the lackadaisical thoughts from the air. These thoughts are drivers of relapse so be attentive in all locations: sit with the team in the team areas, be there in break rooms, and accompany likely offenders during the walk to their car, especially if they are accompanied. Contamination is an ever present threat.

This cure is a 3 to 6 month process and after the 6 months is over the need to continue to encourage advanced learning is critical to maintaining the positive progress.

Waterfall disease shares a similar trait to alcoholism. Once infected, you will always carry the old urges. Even well established mentors have been known to succumb to the comfortable old habits of believing their code actually works without tests. Why just yesterday, I was party to the disabling of thousands of distributed machines because I knew of a change being made and said nothing about it not being tested.

Yes, I have waterfall disease.

10/07/2012

Ruby, SSL and Untrusted Certs

It has been a long time since focusing exclusively on writing Ruby code. So much fun.

The last two years have been groovy only which is a great language but there is something pure and simple about Ruby that just takes your breath away.

Enough of the emotional stuff, why, on earth, is it so hard to disable SSL cert trust verification. Such a common problem, google is full of Rails ActionMailer solutions but of coarse that doesn't help the rest of us.

Ruby 1.8.7

I approached the problem from Net:HTTP library makes it pretty easy. You just have to remember to require the correct classes and note that you are not disabling SSL just the trust verification part. # irb(main):001:0> require "net/https" # => true # irb(main):020:0> h = Net::HTTP.new("YOUR_SSL_SERVER",443) # => #<Net::HTTP YOUR_SSL_SERVER:443 open=false> # irb(main):021:0> h.use_ssl = true # => true # irb(main):022:0> h.verify_mode = OpenSSL::SSL::VERIFY_NONE # => 0 # irb(main):023:0> h.get("/") # => #<Net::HTTPOK 200 OK readbody=true>

My actual goal was to access a WSDL, over SSL, with an untrusted cert. This was not so easy. Took me about 5 hours to work out this solution. Expensive.

I used the Soap4R gem and since performance is not an issue I figured the dynamic proxy from the WSDL parsing would be the way to go:

factory = SOAP::WSDLDriverFactory.new("#{@url}?WSDL")

The problem was that there is no simple API to set the verify_mode of the connection so you have to root around in the code until you find where to monkey patch. This is what I came up with.

# # Monkey Patch HTTP Client # Sets SSL verify mode to NONE so that we can connect to an SSL server # that does not have a trusted certificate. # class HTTPAccess2::Client def initialize(*args) super(args[0], args[1]) @session_manager.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE end end

If someone has a cleaner solution I would love to hear it.

Ruby 1.9.3

Upgrading to 1.9.3 broke my Monkey Patch as expected so here is the updated one that handles both for the time being:

# # Monkey Patch HTTP Client # Sets SSL verify mode to NONE so that we can connect to an SSL server # that does not have a trusted certificate. # # The 1.8.7 patch adds a new constructor. # The 1.9.3 patch intercepts the existing constructor now that the class # name has changed. if RUBY_VERSION == "1.8.7" class HTTPAccess2::Client def initialize(*args) super(args[0], args[1]) @session_manager.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE #@session_manager.debug_dev = STDOUT end end else # > 1.8.7 class HTTPClient alias_method :original_initialize, :initialize def initialize(*args) original_initialize(args[0], args[1]) @session_manager.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE #@session_manager.debug_dev = STDOUT end end end