Useful Dockerfile Setups

e.g. alpine

FROM alpine:latest
LABEL maintainer="Michael Durrant<>"
RUN apk add bash git vim
COPY alpine_bashrc /root/.bashrc
COPY /root
COPY .bash_aliases /root
COPY .git-completion.bash /root
RUN "/bin/bash"
RUN git config --global 'Michael'
RUN git config --global ''

Some common docker commands:

docker version
docker images
docker pull alpine
docker ps -a
docker start container_name
docker attach container_name
docker ps

Without a Dockerfile…
docker run -it alpine
docker attach container_name

With a Dockerfile…
docker build -t alpine_plus_some .
docker run -it alpine_plus_some
docker attached container_name


What A Week

In planning a future week I realized that right now my calendar is a good reflection of my priorities and how I ideally would like to spend much of my time.  Usually I have a lot more standard and recurring meetings, so this is really a rare week that works out this way.

  • Running a workshop
  • 1:1 with directs plus my manager plus others
  • Presenting on Ruby
  • Working on Docker with the SIT team
  • Leading a book club
  • Quarterly Town Hall
  • Quality Foundation Initiative meeting

There’s nothing proprietary ( i covered up 1 mtg details) so here it is

Screen Shot 2018-10-10 at 7.14.50 AM


Obstacle Course Weekend

But not the physical kind.

I decided to play around with using Ruby for minimal testing setup, a current interest of mine – basically trying to reduce dependencies in a world where we want to spin up vm images such as docker in seconds all day long and the less to install the better for many reasons.

The obstacles I run into were not unusual to me at this point, but the ‘newbie person’ within me could clearly see that a newbie would be so lost with this stuff.

What happened:

1) I created a Gemfile to make sure my dependencies are installed.  Pretty minimal:

$ cat Gemfile
source ''
gem 'minitest'
gem 'rspec-expectations'
gem 'selenium-webdriver'
Then I bundle to install them and got this:

$ bundle
Fetching gem metadata from
Fetching version metadata from
Resolving dependencies...
Installing ffi 1.9.25 with native extensions

Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

current directory: /tmp/bundler20180805-19518-uwhdxgffi-1.9.25/gems/ffi-1.9.25/ext/ffi_c
/usr/bin/ruby2.3 -r ./siteconf20180805-19518-1pqqp5e.rb extconf.rb
mkmf.rb can't find header files for ruby at /usr/lib/ruby/include/ruby.h

extconf failed, exit code 1

Gem files will remain installed in /tmp/bundler20180805-19518-uwhdxgffi-1.9.25/gems/ffi-1.9.25 for inspection.
Results logged to /tmp/bundler20180805-19518-uwhdxgffi-1.9.25/extensions/x86_64-linux/2.3.0/ffi-1.9.25/gem_make.out
Using diff-lcs 1.3
An error occurred while installing ffi (1.9.25), and Bundler cannot continue.
Make sure that `gem install ffi -v '1.9.25'` succeeds before bundling.

Which is pretty cryptic !  At first it just seemed like some issue with ffi
What caught my eye though was the “mkmf.b” error.  That seemed odd.  Googling that showed that some folks needed ruby-dev so (on Ubuntu) I did

sudo apt-get install ruby-dev

and then bundle again and this time the webdriver dependency on ffi was able to be resolved.

I also noticed my sudo prompt kept saying

unable to resolve host my-machine-name

and I found that was because the /etc/hosts file had the old machine name before I changed it.  So I fixed that while I was at it too (required sudo vi /etc/hosts)

Not Rocket Science and resolved in 5 mins but this is the sort of thing that just trips so many folks up – including myself before I went through this sort of thing regularly and just got used to it.

Functional creepin’ in?

Practicing the craft (programming).  Couldn’t stop messing with this one.
Kinda proud
– max 1 param on methods!
– 5 line max on methods !
– 50 line class
– readable code

But what’s what all the Proc’s and map operations (selects)?
Seems like I’m starting to get that functional feelin’!

class FerryBookings
  attr_accessor :current_side_of_river
  attr_accessor :number_of_ferry_trips
  attr_accessor :passengers

  def initialize
    @passengers = []
    @current_side_of_river = 'N'
    @number_of_ferry_trips = 0

  def add_passenger(direction_headed)
    passenger =
    @passengers << passenger

  def ferry_person(person)
    person.moved = true

  def ferry_all_passengers
    not_moved = { |p| !p.moved? }
    while > 0

  def make_trip_south_and_north(passengers)
    ['S','N'].each do |direction|
      by_direction = { |p| p.direction_headed == direction }

  def ferry_trip(passengers)
    if passengers.count > 0
      ferry_person( passengers.first )
    elsif passengers_left_to_move?
      @number_of_ferry_trips += 1

  def passengers_left_to_move?{ |passenger| !passenger.moved? }.size > 0

  def switch_river_side
    @current_side_of_river = (@current_side_of_river == 'N') ? 'S' : 'N'
    @number_of_ferry_trips += 1



payoff time

I’ve spent the last 9 months leading, training, cajoling, inspiring and refining 30 new software engineers during their first major software engineering jobs.

This has been an amazing learning experience and has led me to a whole new appreciation of how much value I can add as 1 person vs. the value I can add in helping a large number of engineers achieve quality in their job.

I’ve also received a lot of positive feedback from these engineers and others around me and I am humbled by how many folks have told me how much they admire my passion for quality which is behind everything I do.

I’ve been honored to see these new engineers grow fantastically in their first few months.  I’ve treated them with respect and humility and I’ve put their growth and success as my main goal.  It’s paid off fantastically.

I’ve focused on Total Candor so I can be a kick-ass boss which happens to also be the name of a great book I recently read .  Other recent great reads have included:

  • Powerful: Building a Culture of Freedom and Responsibility
  • Metaprogramming Ruby 2: Program like the pros
  • The Managers Path: A Guide for Tech Leaders navigating growth and change
  • The Clean Coder: A Code of Conduct for Professional Programmers
  • Managing the Unmanageable: Rules, Tools and Insights for Managing Software People and Teams

I am now even more charged to chart the right course and do the right things!

Good Advice from Great Programmers

Fix the hard problems first – Joe Armstrong

When I’m just writing the first version of a program, I tend to put everything in one file. And then I start seeing structure in that file. Like there’s this block of things that are pretty similar… and the API sorts of builds up organically that way. The design process is definitely on an on-going thing; you never know what the design is until the program is done. So I prefer to get my feet wet as soon as possible; get something on the screen so I can look at it sideways. – Zawinski

Not knowing something doesn’t mean you’re dumb – it just means you don’t know it yet – Zawinski

It doesn’t matter how good you are; you can’t get an API right until you’ve tried to code to it – Joshua Bloch

How to Debug? print statements – multiple authors.

I’m really quick on the trigger for throwing stuff out – Ken Thompson

That was how I learned programming – basically taking one program that I made up myself and sitting at a machine over a period of some weeks, and kept getting it to work a little better and a littler better – Robert Knuth

So if I can get my kicks out of finding errors then I just have to make sure that I forget that I was the author of the program. I try to imagine that someone else was the author – Robert Knuth

Organizational Change

When a person or an organization wishes to change, one of the hardest parts of that change can be allowing yourself to accept what others see in you and your organization.

Command and Control is a good example of this.

Using the term “Command and Control” and categorizing ones current organization as that is a very risky and provocative approach.  It is almost guaranteed to annoy folks who will frequently reject the categorization as unfair and inaccurate and feel that it is missing the point and missing the value of current processes within in the organization that have been learned over time and through hard lessons.

Here’s a different approach to identifying command and control:

When a person is asked for information and the response is “sure. I will ask [other people] about that and get back to you” this is a different indicator, but a clear indicator non the less, that command and control is at play.  When the person who is initially asked for the connection remains in the loop they are seeking to validate their position and ego.  This is an uncomfortable fact that I have seen in every organization and industry I have worked in over the past 30 years.  It is defended in many ways as reasonable, practical and simply common sense.  Modern and re-invented organizations have learned however that this doesn’t work well at all in today modern, agile, flexible world.

In many agile organizations, different approaches are taken when this situation (a person seeks information) comes up:

  • The person who knows the other people connects the two third parties to each other and then _steps back and removes themselves_ from the current and future  conversation.
  • All relevant parties are invited to a custom conversation (for example a slack channel) created on-the-fly just for the directly involved people.  The ‘person in the middle’ may be one of the members but again they largely ‘step back’ and allow the other members to communicate directly for the current and future conversation.

Tech Traveler Ten Tips

– Join your airlines frequent flyer program
– Join your hotels frequent visitor program
– Install the hotel mobile app on your phone
– Install the airlines mobile app on your phone
– Enable your phone as the room key if available
– Have and charge a powercell for device charging
– Upgrade seats soon after booking instead of at check-in
– Use airplane mode anywhere when you need to save battery power
– Avoid “basic economy” tickets on orbitz, expedia, etc. – no upgrades
– Buy wifi access ahead of time and be sure your login works before flying

Building my own cloud testing pipeline

This used to be hard.  Take weeks and months.  Now the only hard piece is believing just how easy it is.  I did the following in a matter of minutes.

  • Set up a new git hub project in my account (1 minute)
  • Added some UI tests I wrote last week (they took me 2 weeks to write).
  • Created a Jira+Confluence account & project and wired them into Github (1 minute)
  • Add content to the CMS (confluence) (5 minutes)
  • Created a Slack account and wired its notifications into Github (3 minutes)
  • Created a CircleCI account and wired its notifications into Github (10 minutes)

So now I can:

Have a master document in Confluence which refers to tickets which are links to…

Screenshot from 2017-10-26 21-40-29

^ Jira tickets which you can click on and immediately click through to see commits

Screenshot from 2017-10-26 21-59-40

^which you can click through to see

Screenshot from 2017-10-26 21-41-12

^ Github Change Requests which you can learn about because when they are changed by developers you get…

Screenshot from 2017-10-26 21-42-39

^ Jobs submitted to CircleCI which have…

Screenshot from 2017-10-26 21-43-40

^ Slack notifications in public channels

With most of the integration work boiling down to:

Screenshot from 2017-10-26 20-47-51

Continue reading “Building my own cloud testing pipeline”

Agile Transformation and Management

Many companies have gone or are undergoing Agile transformations.
There is typically a large focus on the dramatic change for regular ‘workers’ in how they do their daily activities.

One item that can easily be over-looked however is the change in daily practices for Management.  Some new organizations have eliminated all ‘supervisor’ and ‘manager’ roles, just leaving developers and a director.  Other, existing organizations that are transforming to Agile have difficult decisions to make about how to retool their management.

Failing to recognize and change can lead to management continuing to use waterfall approaches and not understanding the new empowerment model for workers.

Some of the mis-matched approaches seen in this area are:

  • Using personal checklists to make sure a project is on track
  • Using personal relationships to get non-planned work done
  • Adding ‘important and urgent’ tasks without going through the full process
  • Praising off-board work as heroic
  • Discussions on team effectiveness without the team present
  • Assigning or changing team resources without full team involvement
  • Using traditional project management skills to try and manage the Agile process

Tech Traveler Tips

Tips for Tech for Frequent Travelers

  • Multiple ipods if used
  • Audio cable in every bag
  • Install airline mobile apps
  • Charge check the night before
  • Volutz USB cables in every bag
  • Install travel booking mobile app
  • Extra laptop charger just for travel
  • Kindle for all books and magazines
  • Clear cosmetic bag for cable storage
  • Battery for mobile device charge ups
  • Bluetooth noise cancelling headphones
  • USB wall power plug adapter in every bag
  • Check comfort seat upgrades 2 weeks ahead
  • Use Airplane Mode anywhere to save battery life

The Ultimate Quality Challenge

The Ultimate Quality Challenge has become clear to me.
Here’s some of the things that I’ve found it is NOT about:

  • Programming
  • User Experience
  • Standards and Guidelines
  • Agile Workflows
  • User Acceptance Testing

Don’t get me wrong, all the above are critical to Quality Engineering.
However I am increasingly finding that the Ultimate Quality Challenge is one thing – hiring competent and passionate quality engineers.  This is a prerequisite to all of the above quality activities – without actual people, nothing is implemented (even automation!)

Hiring engineers in the quality space is very challenging for a number of reasons:

  • Historically QE was QA and meant manual testing, typically a lower job grade
  • Quality Engineering now means automation with different skill requirements
  • The majority of engineers like to work with application code, not tests only
  • Quality Engineers may suffer from several ‘second class citizen’ issues
  • Compensation may lead the best and brightest to switch to app dev roles
  • Peer respect may lead some to switch to app dev roles as they become skilled
  • Availability of QE Engineers for hiring is extremely limited (2017)
  • Current automation engineering differs from new javascript practices
  • Quality Engineering is often not championed as a cool and useful thing

I want to help change that!
Some of the things I am doing:

  • Active on asking and answering questions to promote good quality practices.  I am #1 world-wide in 2017 !
  • Active in Ministry of Testing slack community
  • Presenter on Quality at work, local meetups, national and international conferences

ES6: Destructuring, Object Literal Enhancement and the Spread operator


Scoping an object locally

From an object

    var {pref1, pref2} = user  // user is object w/ keys pref1, pref2

From a functions arguments

    var function_x = ({firstname}) => {
      full_name = `${firstname} of boston`

From an array

var [first_town] = ['Boston', 'Salem', 'Ham']  // 1st_town= Boston
var [,,last_town] = ['Boston', 'Salem', 'Ham']  // lst_town= Ham

Object Literal Enhancement

I’m guessing that name is going to change…
The opposite of destructuring.
Puts objects and methods together.

Objects from variables

var shell='bread'
var filling='butter'
var sandwich = {shell, filling}  
// New object 'sandwich' with contents
// {shell: 'bread', filling: 'butter'}

Object methods from variables

// Method is 'toast'
var toast = function() { console.log('Toast it for {time}') }
var toastedSandwich = {shell, filling, time}

Spread Operator “...

Array values

The actual values from an array (not the array itself)

var arr1 = ['Buick', 'Ford']
var arr2= ['Edsel', 'Dodge']
var arr3 = [...arr1, ...arr2]

Function argument values as an array

function direction(...args) {}

Object Values

The key-value attributes from an object, not the object itself, e.g.

obj1={a:1, b:2}
obj2={c:3, d:4}
obj3={...obj1, ...obj2}


More Javascript for testers

Objects have prototype methods which are shared for all instances

Useful for methods that apply to all instances

Person.prototype.some_method_name=  function() {

Avoid for properties that store state data, e.g. arrays with elements managed by various methods.

When you need to define multiple methods on the prototype you can use the format below, however they should also define the constructor as shown so that the prototype is Person and not just Object:

Person.prototype = {
  constructor: Person,
  first_method: function() {...},
  second_method: function() {...};  

You can add methods to prototypes for all objects including builtins objects such as Array, String, etc.

Inheritance is through above Prototype Chain, e.g.

var instance2 = Object.create(instance1, {
  name: {
    value: "some_new_thing",


IIFE – Immediately Invoked Function Expression

Commonly used in javascript for modules.
Note surrounding parens and parens at end

Module Pattern

var person = (function() {
  var age = 25;  // This is private
  return { ... } // These are closures and are public 

Revealing Module Pattern

var person = (function() {
  var age = 25;
  function x() {...}
  return { x: x, ...}; // Note same name (x)

Private Members use ‘this’

  this.getAge = function () { return age; };


Javascript Goodies


function declarations

function thing(p1,p2) {
  return value;
  • Starts with word ‘function’
  • Not separately assigned to a variable
  • WILL be hoisted and declared at top


function expressions

var thing = function(p1, p2) {
  return value;
  • Assigns function with no name (annoymous) to a named variable
  • Will NOT be hoisted to top, will be defined inline

IIFE’s – immediately invoked function expressions

(function(){ /* code */ }()); // Like this
(function(){ /* code */ })(); // or this
– key identifier is surrounding parens – ()
– invoked at actual runtime

Function Overloading

Achieved with functions by examing arguments, e.g.
function abc() {
   if (arguments.length === 0) {     this code; }   
else {
     other_code;   } }

The three ways to use ‘this’ with methods in javascript functions

1 With call, "text")

A particular value for ‘this’ and specific parameters

2. With apply
some_function.apply(this, "text")

A particular value for ‘this’ and, specifically, an array for any parameters

3. With bind
some_function.bind(this, "text")
‘this’ is the value for the new function, the rest are named parameters for ‘new’

Object Properties

Common Internal Properties
  • Extensible
  • Prototype
Data Properties, i.e. values
All Data Properties also have two attribute methods:
  • value
  • writeable
Accessor Properties, i.e. functions
All Accessor Properties also have two attribute methods:
  • get
  • set
var tree = {
  _name: "Oak",
  get name() {
    return this._name;
  set name(value) {
    this._name = value;

Retrieving Property Attributes


Constructors and Prototypes

Constructors use ‘new’ to create a new instance of a method.

Functions should be capitalized when they are used as constructors – you will be creating new instances of them with ‘new’.

All functions have an internal prototype property
You can check for it with object.hasOwnProperty(name)

Rubyists may find its usage has some similarities to Ruby’s class level methods.

When an object (function w/new constructor) has methods that are shared by all instances use a prototype function for the Object

YourObject.prototype.yourFunctionName = function() {...}

When an object (function w/new constructor) has attribute values that are shared by all instances use a prototype attribute for the Object

YourObject.prototype.yourVariableName = value


Javascript Landscape for Testers

Introduction – Javascript

There’s a lot to know in order to understand what’s going on with the javascript landscape for Quality Engineering testers, especially for those involved in writing browser automation.  One of the biggest complaints recently is literally not knowing where to start, what the dozens of acronyms and terms mean and also what to study and in what logical order to study it.

There is also getting your head around the current use of Object Oriented javascript.  When I first used javascript it was all about making simple web page effects.  Now it is a very popular web language with Object Oriented functionality, used for building full fledged internet applications and used server side with technologies like Node.

Understanding a brief history of javascript is helpful to understanding how to use javascript today and what it means to write javascript tests:

What Object Oriented means in todays javascript is explained well in the following book.  I’ve read many javascript books and as someone with existing knowledge in both Scripting and Object Oriented languages, this is definitely the book that’s been most helpful to me:

Another interesting aspect of Javascript Testing is that that are elements for all 4 of the Agile Testing Quadrants – Unit, Integrated, Performance and Exploratory.

Part I – User acceptance / Integrated testing with Selenium

For BDD there is:

  • Cucumber –
    Using the Given, When, Then Gherkin format

For user acceptance testing there is web page testing with Selenium using javascript, e.g.

For TDD/BDD in Ruby there is:

  • rspec with capybara
  • watir (pronounced “water”)

There is also javascript based Selenium testing for javascript frameworks such as AngularJS:

There is also ‘headless’ browser testing which attempts to address the speed issue of any browser based testing by not actual bringing up a browser window.  Its success will depend on the specifics for a given web site / application.

Part II – Javascript Unit Testing

Then there is the testing of actual javascript itself.  This is primarily about unit testing javascript code.  Here we have two broad areas, one is Node based and one is not.  Node is about server side javascript.  You have a ‘node’ server running that responds to requests.  You can build and use frameworks such as Angular and React and you can also use server side javascript that is compiled into regular javascript which is then sent to browser clients.

As you advance in javascript testing you’ll also want to get a good understanding about spies, mocks and stubs:

As you advance further you may find it useful to understand and use chai – an assertation library for all those ‘should’, ‘expect’ and ‘assert’ statements!


Part III – Performance and Load Testing

Apache Bench
is a (node based) option here.

ab is a tool for benchmarking your Apache Hypertext Transfer Protocol (HTTP) server. It is designed to give you an impression of how your current Apache installation performs. This especially shows you how many requests per second your Apache installation is capable of serving.”


Part IV – Exploratory Testing

You can explore, debug and test javascript by using the browser Console tab to interact with the browser and issue commands

Screenshot from 2017-06-01 07-58-25

You can also use Node at the terminal command line by simply typing node or nodejs

Screenshot from 2017-06-01 07-59-32

A new way to think about tests

Tests that pass are good. right?

That is such a given that it may seem strange to even question it! So here goes:

Tests only add value when they fail

There it is. Failing tests. A good thing. ok I’ve said it.
I’m already removing the arrows, ow! so let me explain:

The idea here is that tests that never ever fail indicate a problem. Tests are supposed to break – when you break the application. After all, that’s why they are there – as safety rails so you can develop in comfort, changing the application as needed and letting you know when your changes break existing functionality.
So what happens when they do break? Well here’s where the quality of the test itself also comes into play. It’s not too hard to write tests that, when they do break (yeah!) they give meaningful information.

Unfortunately it’s also fairly easy to come up with tests that break and tell you something like this:

“Expected true to be true but was false instead”

Sound good? Can you fix that now? Of course not.
So write a test whose failure looks like this:

“Expected the child to be a member of the customers family but they are not listed in the family plan” – now that’s something you can work with !

This is also support for the concept of making sure your tests fails first, i.e. Red, Green, Refactor.  Making sure it fails first provides an opportunity to hone and refine the failure message.

The main caveat to this idea is that tests, if well written, act as documentation  So even if they never fail they can still fulfill that function.  Indeed I have learned about more than one system just from reading the test suite!

A downside to such ‘wordy’ tests is that we can have test code descriptions that don’t match, or get out of sync, with the code being called. This is why we avoid program comments whenever possible, in favor of meaningfully named code objects and function descriptions. However I believe the upside of good and meaningful tests outweighs this downside for these tests.

How to be a TV Trump supporter

Guide to being a trump supporter on TV

– Don’t EVER actually answer the question. Your ONLY goal is to get airtime and then express and expand on the presidents views
– When pressed on questions, find an unrelated incident in the questioners past to talk about
– When pressed more, personally insult the questioner. Find a physical characteristic you can belittle
– When pressed more, find a general thing you disagree about politically and start talking about that
– When pressed more, switch roles and start asking questions instead of answering them
– When pressed with more with facts reply with different facts about somewhat similar topics.
– Wait for the ads to come
– Repeat

Perfected By Kellyann Conway and Jeffrey Lord and Scottie Nell Hughes

Such a shame they have no morals, but hey, find this and I’ll be next on their list !


World of Testing Forums

Mega Meta List of Automated Software Testing Information:

My Favorites
Google’s blog – mind blowing information about flaky tests
“our robot army has been working hard at fuzzing, processing 10 trillion test inputs a day”
“Google has around 4.2 million tests that run on our continuous integration system. Of these, around 63 thousand have a flaky run over the course of a week. While this represents less than 2% of our tests, it still causes significant drag on our engineers.”
Avoid “Tests that use the UI to test business logic that’s exposed through an API (use an API-level test instead!) or implemented in code (how about those unit tests?). Not testing at the right level supports shallow feedback and increased execution time. Goodbye fast feedback.”
“There are no magic, unicorn-filled companies employing all-knowing developers who are creating perfect software.”
“How often have you walked onto a project and everyone on the team got excited and jumped up and down saying how happy they are to have you there?” (i.e. few)
“One thing I consistently ask teams to do during feature design is to include how they plan to measure the value of the feature to customers or business value. Often, only a proxy metric is available, but those work way better than nothing at all.”

Daily vim


/   Search forwards in file
?   Search backwards in file
f   Next on the line
n   Next in the search
N   Previous in the search
set ic       Set search to be case sensitive (default)
set noic   Set search to be case insensitive


/^foo   Search for text ‘foo’ at start of line
/bar$   Search for text ‘bar’ at end of line
/\<foo\>   Search for the word foo
/[a-c]blob   Search for the text ablob, bblob or cblob

Daily Vim

cc – change whole line
c$ change to end of line
:%s/this/that/gc  –  Change ‘this’ to ‘that’ globally in the file and on the line & confirm each
:1,100 s/this/that  –  Change this to that for lines 1 through 100
:e!  –  Reset all edits made in current file
vi + [file]  –  Edit and go to end of file
vi +/string [file]  –  Edit and go to string

Top Ten Terminal Tips

  1. One Letter aliases x=’exit’; alias l=’ls -alFtrG’; alias p=’pwd’; g=’git status’
  2. user – pwd – git branch in the bash prompt, e.g. durrantm@Castle2012:~/Dropnot/webs/rails_apps/linker (master) with
    parse_git_branch () {
    git branch 2> /dev/null | sed -e ‘/^[^*]/d’ -e ‘s/* \(.*\)/ (\1)/’
    PS1=’\[33[01;32m\]\u@\h\[33[00m\]:\[33[01;34m\]\w\[33[01;33m\]$(parse_git_branch)\[33[00m\]\n\$ ‘
    (Add above to your .bashrc file)
  3. automatic CDing shopt -s autocd
  4. git branch completion script (
  5. use tmux
  6. alias hg = ‘history | grep ‘l
  7. .vimrc file for better editing preferences
  8.  mousing in tmux panes with a .tmux.conf file with  set -g mouse-select-pane on &  set -g mouse-resize-pane on
  9. Use locate over find when possible
  10. alias for current code, e.g. alias q=’cd ~/Dropbox/95_2014/work/code/ruby__rails/ruby/ruby_quiz’

Daily Vim

cc  –  change whole line
c$  –  change to end of line
:%s/this/that/cg  –  globally change and confirm each one
:n,m s/this/that  –  change within this range of lines
vi +/this_string  –  open and go to string
vi +  –  open and go to end of line
:e!  –  sreset all changes

Best Bugs Yet

This week ended up representing the cumulation of a years worth of experience at my current employer and it happened through some very special bugs that had been haunting us for months.

1. Ajax Timing

First of all, our UI automated tests have been failing due to ajax and javascript timing issues.  Intermittently and actually quite rarely, say 1-5%.  That’s a problem though because, including branches, we frequently do several hundred CI runs a day, so that means sometimes dozens of runs fail.  This leads to the dreaded lack of trust in test runs which has very negative consequences as ultimately you no longer can trust them to reflect if the product is actually working.

The mystery was why.  The page loads up in 2-3 seconds on our macs and we had a 15 second max wait time which seemed ample.

The clue finally came when I ran the UI tests locally at home on my Ubuntu machine, which ironically is the same OS as the CI machines and also with lower power than my mac.  I ran the specs and they brought up the browser locally, but instead of 2-3 seconds for the page and all the js to load it took 30-40 seconds!

Finally I had the cause of our issues and was able to adjust the 15 in this piece of code for implicit waits to 60 to allow the page to fully load.  Boom.  5 months of a mysterious ajax loading issue finally nailed!

                                         -->  <-- 15 changed to 60
def wait_for(condition_name, max_wait_time: 15, polling_interval: 0.01)
  wait_until = + max_wait_time.seconds
  while true
    return if yield
    if > wait_until
      raise "Condition not met: #{condition_name}"

2. Slow Automated Mobile Tests

Finally tests are passing for mobile devices through the browserstack automated service.  But they are soooo slow.
One of the most simple’fixes’ for this was to simply reduce the tests being run to reflect those workflows actually used on mobile devices.  Two of our workflows are only on desktop.  This reduced the mobile test specs from 24 to 9 and the run time from 42 mins to 18 mins

3.  Passing, Failing, Passing and stopping randomly

The mobile tests have been behaving very erratically in other ways.  At various different points it seems like the device suddenly stops working or responding.  Then we would get 3 test suites in a row passing.  With that good sign we ran a bunch more.  But most failed.  Except the last one.  After a long day of runs, pattern finally spotted.  The different test runs on circleCI (we can have 3 running simultaneously) have 4 slots (machines) with each run).  They create **and destroy** a tunnel to virtual devices at Browserstack, so different runs are killing each others connections.  Not obvious until running multiple (or the same) branch at the same time as other CI runs.  Proved by running one run at a time.  Fix is to start/stop the tunnel once.

command line playtime, grep, xargs, cat and head

Search for this in any of files with filename *.rb

  grep 'this' *.rb

Search for this in files and cat them

  grep -l 'this' b*.rb | xargs cat

Search for this in files and then show their contents with filename on the first line:

  grep -l 'this' b*.rb | xargs head -999

Search for this AND that:

  grep -l 'this' b*.rb | xargs grep --color 'that'

Search for (this OR that) AND other:

  grep -E '(this | that).*other' b*.rb

Rspec Style

My current style for writing feature specs

require 'rails_helper'
RSpec.feature 'Consumer completes 3 step minimal flow' do
  include ThreeStepMinimalFoundationSetupHelper
  include LandingPageHelper, AutoPoliciesHelper, ExitPageHelper
  let!(:zip) { generate_zipcode }
  let!(:vehicle) { FactoryGirl.create(:polk_vehicle, :with_year_make_and_model) }
  let!(:insurer) { FactoryGirl.create(:insurer) }
  let(:auto) { }
  let(:s2_path) { '/auto_policies/three_step_minimal_foundation/s2_primarydriver' }
  let(:s3_path) { '/auto_policies/three_step_minimal_foundation/s3_coverage' }
  let(:p) { }
  before :each do
    setup_landing_page('myquote_non_sem', config_set, mobile: false)
    setup_exit_page('myquote_non_sem', config_set, layout: 'empty_page_with_theme', mobile: false)

  context '3_step_minimal_foundation UI test', :js do
    before :each do
      visit_ready landings_path
    scenario 'landing page with a required field NOT entered', :sad do
      fill_in :landing_zip_code, with: ''
      click_button p.eqv_continue_button
      expect(current_path).to eq landings_path

    context 'landing page with all required fields entered' do
      before :each do
        fill_out_form zip.zip_code
        with_readiness_wait do
          click_button p.eqv_continue_button
      scenario 'now we are on stage#1, the auto_policies path', :happy do
        expect(current_path).to eq auto_policies_path
      scenario 'happy thru all the stages', :happy do
        fill_out_auto auto
        select vehicle.submodel, from: p.css_vehicle1_auto_submodel
        select p.eqv_label_ownership, from: p.css_vehicle1_ownership
        select p.eqv_label_primary_use, from: p.css_vehicle1_primary_use
        select p.eqv_label_miles_per_year, from: p.css_vehicle1_miles_per_year
        select p.eqv_label_parking, from: p.css_vehicle1_parking
        with_readiness_wait do
        fill_out_driver p
        fill_in p.css_driver1_age_licensed, with: p.eqv_age_licensed
       select p.eqv_credit_rating, from: p.css_credit_rating
        select p.eqv_education, from: p.css_driver1_education
        with_readiness_wait do
        select p.eqv_coverage_type, from: p.css_vehicle1_coverage_type
        fill_in p.css_street_address, with: p.eqv_street_address
        select p.eqv_residence, from: p.css_residence
        fill_in p.css_phone, with: p.eqv_phone
        fill_in p.css_email, with: p.eqv_email
        with_readiness_wait do
        expect(page).to have_css p.css_quotes

  context 'sad stages', :js do
    before :each do
      visit_ready landings_path
      fill_out_form zip.zip_code
      with_readiness_wait do
        click_button p.eqv_continue_button

    scenario 'submit of stage1 with vehicle year not selected redisplays with errors and retains changed field values', :sad do
      select p.eqv_option_auto_year_blank, from: p.css_vehicle1_auto_year
      select ownership_option, from: p.css_vehicle1_ownership
      select primary_use_option, from: p.css_vehicle1_primary_use
      select miles_per_year_option, from: p.css_vehicle1_miles_per_year
      select parking_option, from: p.css_vehicle1_parking
      with_readiness_wait do
      expect(page).to have_css p.css_select_vehicle1_auto_year
      expect(page).to have_select p.css_vehicle1_ownership, selected: ownership_option
      expect(page).to have_select p.css_vehicle1_primary_use, selected: primary_use_option
      expect(page).to have_select p.css_vehicle1_miles_per_year, selected: miles_per_year_option
      expect(page).to have_select p.css_vehicle1_parking, selected: parking_option
      expect(page).to have_error_fields

    scenario 'submit of stage2 with driver last name blank redisplays form with error and retains changed field values', :sad do
      visit_ready auto_policies_path(current_step: s2_path)
      fill_in p.css_driver1_last_name, with: ''
      select gender_option, from: p.css_driver1_gender
      select marital_status_option, from: p.css_driver1_marital_status
      with_readiness_wait do
      expect(page).to have_css p.css_input_driver_last_name
      expect(page).to have_select p.css_driver1_gender, selected: gender_option
      expect(page).to have_select p.css_driver1_marital_status, selected: marital_status_option
      expect(page).to have_error_fields

    scenario 'submit of stage3 with street address blank redisplays form with error and retains changed field values', :sad do
      def choose locator
        page.choose locator
      visit_ready auto_policies_path(current_step: s3_path)
      fill_in p.css_street_address, with: ''
      select years_at_residence_option, from: p.css_years_at_residence
      select residence_option, from: p.css_residence
      choose p.css_vehicle1_parked_at_mailing_address_false
      choose p.css_homeowner_insurance_true
      choose p.css_add_violation_true
      choose p.css_add_insurance_claim_true
      choose p.css_add_driver_true
      choose p.css_add_auto_true
      with_readiness_wait do
      expect(page).to have_css p.css_input_street_address
      expect(page).to have_select p.css_driver1_years_lived_there, selected: years_at_residence_option
      expect(page).to have_select p.css_residence, selected: residence_option
      expect(page).to have_field p.css_vehicle1_parked_at_mailing_address_false, checked: true
      expect(page).to have_field p.css_homeowner_insurance_true, checked: true
      expect(page).to have_field p.css_add_violation_true, checked: true
      expect(page).to have_field p.css_add_insurance_claim_true, checked: true
      expect(page).to have_field p.css_add_driver_true, checked: true
      expect(page).to have_field p.css_add_auto_true, checked: true
      expect(page).to have_error_fields

Feature spec

Always aiming to write readable specs

require 'spec_helper'

feature 'Consumer adds additional info' do

  include FullformSetupHelper
  include AutoPoliciesHelper, FullformAdditionalStepHelper, ExitPageHelper

  let!(:policy)  { FactoryGirl.create(:auto_policy, :with_additional_auto_flag, arrival: arrival) }
  let!(:vehicle) { FactoryGirl.create(:polk_vehicle, :with_year_make_and_model) }
  let!(:insurer) { FactoryGirl.create(:insurer, :with_insurer_insurance_type) }
  let(:additional_step_path)  { '/auto_policies/fullform/s2_additional' }
  let(:p) { }

  before :each do
    FactoryGirl.create_list(:tip, 5)
    FactoryGirl.create_list(:auto_insurance_term, 5)

    visit_ready auto_policies_path(current_step: additional_step_path)

  context 'consumer adds a driver', :options do
    context 'correctly', :happy do
      scenario 'sees the name of the new driver on the form', :js do
        first_name, last_name = Faker::Name.first_name, Faker::Name.last_name

        add_additional_driver(first_name, last_name)

        expect(page).to have_content(first_name)
        expect(page).to have_content(last_name)
        expect(policy.drivers.reload.length).to eq 2

    context 'incorrectly', :sad do
      scenario 'does not persist a driver to the database', :js do
        expect{ add_invalid_driver }.to_not change{ Driver.count }

      scenario 'sees field_with_errors', :js do

        expect(page).to have_error_fields

  context 'consumer adds a vehicle', :js, :options do
    context 'correctly', :happy do
      scenario 'sees the vehicle year-make-model for the added vehicle' do
        add_additional_vehicle(vehicle.year, vehicle.make, vehicle.model)

        expect(page).to have_content("#{vehicle.year} #{vehicle.make} #{vehicle.model}")
        expect( eq(2)

    context 'incorrectly', :sad do
      scenario 'does not persist an auto to the database' do
        expect{ add_invalid_additional_vehicle }.to_not change{ Auto.count }

      scenario 'sees field_with_errors' do

        expect(page).to have_error_fields

  context 'consumer adds a violation', :options do
    context 'correctly', :happy do
      scenario 'persists the additional violation', :js do

        expect(Violation.count).to eq(1)

      scenario 'sees the violation added', :js do

        expect(page).to have_content('Violation 1')

    context 'incorrectly', :sad do
      scenario 'sees field_with_errors', :js do

        expect(page).to have_error_fields

      scenario 'does not persist a violation to the database', :js do
        expect{ add_invalid_violation }.to_not change{ Violation.count }

  context 'allow only one driver association form', :js, :options do
    before :each do
      visit_ready auto_policies_path(current_step: additional_step_path)

    scenario 'hides add buttons' do

      expect(page).not_to have_selector p.css_violation_add, visible: true

    scenario 'brings back add buttons on cancel' do
      with_ajax_wait{ find(p.css_remove_driver2).click }

      expect(page).to have_selector p.css_add_driver, visible: true

    scenario 'brings back add buttons on successful save' do

      expect(page).to have_selector p.css_add_claim

    scenario 'does not bring back add buttons on failed save' do

      expect(page).not_to have_selector p.css_add_claim, visible: true

Ruby Flavored Design

Ruby Flavored Design.
– Assign instance variables in initialize methods (Define variables in one place only)
– Wrap instance variables with attrs (Define Behavior not Data)
– Break down complex calculation to reveal hidden methods (Decompose for simplicity)
– Remove dependencies from methods for other: Class Names, Method Names, Parameters, Parameter Order (Decouple to avoid dependencies)
– Remove 2nd order dependencies to follow the Low of Demeter (Reduce coupling)
– Removing Class Name dependency: Move Class to instance variable in initialize (Reduce Coupling through Dependency Injection of the object)
– Remove Method Name dependency: Wrap other_object.method in method (Reduce Coupling)
– Remove Parameter Order Dependencies: Change parameter list to hash for named keys (Reduce Coupling)
– Remove Parameter Dependencies: Provide defaults when possible (Reduce Coupling)
– Choose dependency Direction: Choose the object that changes less, e.g. ruby vs. rails vs. local code (Dependency Injection).
– Choose dependency Direction: Choose abstract classes over concrete ones (Dependency Injection)
– Choose public or private interfaces: Reflect the need and control the dependencies (Dependencies)
– Use Delegation to avoid method chaining (Law of Demeter)
– Use Duck Typing to increase flexibility (Reduce Cost of Change)
– Use Abstract Superclasses (“Vehicles”) but ONLY instantiate through their subclasses (‘’)
– Use Inheritance to share universal common behavior (Inheritance)
– Use Modules to share specific common behavior (Modularity)
– Combine Objects with composition (Composition)
– Test public interfaces (Testing)