Continuous Testing (part 2)

In my last post [Continuous Testing part 1] I described what a typical build script inside a continuous integration tool looks like. And how they’re often a nightmare to maintain.

I didn’t even get to the point I wanted to talk about — which is that
something about continuous integration is broken.

Part of the problem is that people are trying to code in text boxes and doing setup and configuration through a GUI.

With discipline and practice, you can have everything within a tidy, modular build script so that all your CI server is just calling that (and nothing else)

Your job looks like :

/path/to/build_script.sh $OPTION1 $OPTION2 $OPTION3

but no more than 3 options!

It becomes nothing more than a glorified GUI on top of a cron job.

Which is all a CI server should be.

But was it JWZ or ESR who said something about every program attempts to expand until it can send email (and parse lisp?)

I think that Continuous Integration promises something more.

That’s what “Continous Delivery” tries to reach for too — and has gotten bogged down in the task of provisioning and managing build & deployment environments.

We have two tasks here that are really quite separate:

  1. Building a product.
  2. Deploying it to a working environment and running it.

But they’re both trying to accomplish the same goal:

Testing

You want to build a product continuously so you can test it frequently. Both unit tests, and system tests.

The “I” in Continuous Integration stands for “Integration Testing”

Likewise, you want to deploy a production continuously so you can test it frequently.

The “D” in Continuous Delivery stands for “Integration Testing” too.

Because to test something completely you need to deploy it to a production-like environment and run it through it’s paces there.

It just so happens that the environment you build a product on is also almost always an environment you can run it on. Developers know this because that’s how they know it works when they’re building it.

This is called a development environment. Your build system needs the runtime to build it but it needs a lot of other things.

Developers need javac to compile their code, but they also need java to run it. If they’re building web apps, they need a web server to deploy it to, a browser to connect to the web server, and maybe a database or two to get data from. They probably also need to mock out a service or call a development version of a service that doesn’t scale.

But a production environment looks nothing like a development environment.

And a testing environment is always a compromise between the two.

Since developers build developer tools, they build them with themselves in mind.

They’re thinking about unit testing, mocking services, and deploying to dev environments — preferably with as few steps between compile and deploy as possible.

That’s why we have CI servers that work the way they do. They were build by developers for developers.

But dev environments aren’t good for integration testing.  Ever heard a developer say “it works on my box?”

Similarly, we have Continuous Delivery servers that work the way they do because they were build by (devops) for sysadmins. They’re interested in getting the tools and processes for provisioning and deploying products in place — because that’s what they care about.

But as I said, the purpose of CI & CD is to facilitate testing. What if we had a Continuous Testing server that was designed (if not build) by testers, for testers?

Maybe it’s a piece that fits in between (or after) Continuous Build and Continuous Delivery. Or maybe it’s part of the same tool. But I think it’s the next step.

Continuous Testing

I’ve done a lot of setup and administration of continuous integration servers — cruise control (including variations cruisecontrol.rb and cruisecontrol.net), luntbuild, hudson, jenkins, bamboo, TFS, go. I have my favorites (and not so favorites.)

I’ve seen them used well and abused for continuous delivery and deployment as well.

Ironically, the ones that seem to work best seem to have lots of shell scripts written in text boxes. These are a nightmare to maintain, and impossible to recover from.

They often look like this:

  1. Set a bunch of environment variables in the CI tool
  2. Have a bunch of environment variables set (or overridden) within the job script
  3. Take a few more environment variables as user selected configuration parameters for the job
  4. Do some environment cleanup
  5. And then run the “build script” – a shell script that calls a python script that does a bunch more of the same stuff – and then eventually calls maven or rake
ENV_VAR1=$DEFAULT ENV_VAR2=$FRAMEWORK_DEFAULT /usr/local/bin/custom_shell build_script.sh -ex $OPTION1 $OPTION2

build_script.sh:

ENV_VAR3="DEFAULT"
ENV_VAR4=$OPTION1
ENV_VAR5=${OPTION2:-"DEFAULT"}</pre>
ENV_VAR5=`some_script.sh $ENV_VAR1 $ENV_VAR2`
export ENV_VAR3; export ENV_VAR4; export ENV_VAR5</pre>
/usr/bin/python cleanup_script.py $OPTION1 "hard_coded_value"</pre>
/usr/local/bin/custom_python build_script.py

One of the first things I do when starting on a new project is pull these scripts (and their associated environment variable settings) into version control.

And then I delete the jobs and never think about them again. I wish.

But I put them under version control because I don’t want to lose them.

And then I start refactoring.  And then I start trying to rebuild the functionality from scratch.  And then I congratulate the build engineer (who’s probably a developer trying to get work done on a completely different project) on his job security.

 

Who is my customer?

When looking for a customer, what do you need to know about them?  Understanding who your customer is is an important exercise for a startup that should be drilled into your skull.

But the same thing applies to everyone, not just startups.  Whether you’re trying to sell a product, land a client, or even find a job, apply the same principals.  Finding the right customers not only increases your chance of selling, but also can lead to happier, more fulfilling work.

Start with your target market.  Who is buying what you’re selling?  Narrow it down, and choose the niche of that market you want to serve.  Identify the qualities you want in a customer, and determine the risks and pains you’re willing to deal with.

For me, I develop testing software, but I also do test consulting, and I’ve also been (and will likely be again) an employee.

Let’s treat the potential employers as potential customers.  What do you look like in a customer/employer?

My customer is obviously software development organizations.  Without code, there’s nothing to test.

Note, that it doesn’t have to be a company that sells software [e.g. Microsoft].  It could be a company that sells hardware (and writes software to use it) [e.g. Apple].  It could be a company that modifies existing software for clients [e.g. Salesforce].  It could be a company that has nothing to do with software on the surface but has internal software they depend on for daily use [e.g. Ford].  That isn’t doing a good job of narrowing it down though.

It doesn’t matter the company (though it doesn’t hurt to focus on companies who specialize in developing software) because companies don’t hire people.  People do.  And so I can narrow it down even further — people who make decisions about testing within software development organization.

Where do I find these people?  They’re managers.  I’ll mostly be working with engineers, but the engineers won’t be writing checks and making hiring decisions.  They may be attending conferences, they may be posting on job boards, they may have their own discussion groups — but this post isn’t about finding customers, it’s about identifying them.  So I will recognize them when I see them.

So back to who is my customer.

Software organizations.  Who do testing.  Who want automation.  Who use open source tools.  Who like agile practices.  Who are willing to have distributed teams.

I’m going to make some arbitrary decisions.  I don’t have to stick with them, but they’re the sort of “all other things being equal, I’d prefer…” decisions.  They’re also stereotyping clues “If he does this, he probably also does…”  They help me to narrow my focus, highlight desirable (and undesirable) traits.

I want to work for a small organization.  But not too small.  And growing quickly.  Has to have stability, but not stagnation.  About 50 employees seems about right to me.  But on track to have 100.

I tried to narrow down the platform choices but didn’t have too much success.  I’d prefer Linux, over Windows, but I like C#.  I don’t want to get stuck using CodedUI or TFS or Microsoft Test Manager though.  I also don’t want a hardcore Java Spring/Hibernate/JSF/whatever shop either.  I don’t really want to test PHP/Wordpress/Magento/etc. plugins.  I don’t especially to be boxed into the Ruby on Rails corner either.   I don’t want to just write Selenium tests, or Cucumber tests.  I want to learn and explore.

I don’t want to be stuck just testing the UI.  I believe testing should be pushed lower as much as possible.  I want to test APIs.  I want to write mocks.  I want to work on mobile apps and REST services.  I want to work in the cloud.

I’m ambivalent about B2C or B2B. I think the trickier stuff is business oriented, but the funner stuff is consumer oriented.

 

Visualizing the Browser Object Model

I’m working on conceptualizing how web apps relate to the browser. Thinking about single page (and multi-page) apps and the different elements they need to control.  It became apparent to me that there are two models and two sets of state that exist side by side.

There is the browser, along with the DOM and all it’s related elements:  window, location, status, history — and then there is the application, with it’s model, state, and actions.

Turns out the W3C (*ahem* Netscape) did a pretty good job of of designing the browser object model.  Here’s a diagram I drew to help me visualize the browser object model based on the documentation at W3Schools:

browser object model

The actual Browser Object Model is almost exactly what I conceptualized needing to work with (in an abstracted way) for my applications.

Next step is to design an application so it interacts with the BOM (not just the DOM) in a clearly isolated way.

BTW, pro-tip for those of you building “single page apps” and want to keep it on a single page. Don’t set window.location.href=url Instead, use window.location.replace(url) and keep your back button gray.