Automated regression testing of Chromecast using Cucumber, JRuby and Rukuli

As you may know, i work as a Developer In Test for Media Playout at the BBC. We enable audio and video playout on the web (desktop, tablet and mobile) using our Standard Media Player.

We recently added support for Chromecast, and i want to write a bit about how i automated testing for it.

Chromecast HDMI dongle

Chromecast HDMI dongle

Chromecast is a HDMI dongle that plugs into a normal television and adds connected TV functionality. The neat thing is you can control it from your laptop, tablet or mobile using the media apps that you already know, such as YouTube, Netflix and now BBC iPlayer. Google also provides an API so that new Chromecast apps can be written all the time.

So how do you test a Chromecast? Well, personally i like to test things from an user’s point of view, actually clicking things and observing what happens as a result. But there’s only so far you can take this. I don’t want to rely on a television having a Chromecast being plugged in all the time and on the same network so that i can talk to it.

Though i’ve got to say .. it would be quite awesome to use a television 2 metres wide for my automated regression testing! :p

About to start casting

About to start casting

I didn’t need to test the Chromecast receiver app; that had already been written and tested by the guys in Salford for use by the iOS iPlayer app. I realised, what we actually care about is the communication between our player and the Chromecast. And there is a well documented Chromecast API. So with the help of colleagues Tim Hewitt and Wyell Hanna, i set about creating a fake Chromecast. Pretty much a bit of javascript that would respond in the same way as a real Chromecast, so that we could test how our player would respond to it.

And now i present to you .. the fake Chromecast!

https://gist.github.com/sermoa/10988494

A lot of it is empty methods that are neccessary to the API. But there are some neat tricks here too. I’ll talk you through a few of the more interesting bits.

Firstly we need to load the fake Chromecast into the page. We can achieve this with a @chromecast tag and a Before hook.

Before('@chromecast') do
  $chromecast = Chromecast.new
end

My Chromecast class has an initialize method that inserts the javascript into the page.

class Chromecast

  def initialize
    $capybara.execute_script <<-EOF
      var el=document.createElement("script");
      el.type="text/javascript";
      el.src = "https://gist.githubusercontent.com/sermoa/10988494/raw/82e08c5a29b5689b5e9f3d03c191b8c981102d85/fakeChromecast.js";
      document.getElementsByTagName("head")[0].appendChild(el);
    EOF
    @media_alive = true
  end

end

With this in place, so long as i set up our player with the relevant business logic that says casting is available, when i hover over the player, i get a cast button!

  @chromecast
  Scenario: Chromecast button appears
    Given Chromecast is available
    When I play media
    Then I should see the Chromecast button
A cast button appears!

A cast button appears!

So how does that work? I assure you, i don’t have a Chromecast on the network right now. I’m not using the Google Chrome extension. I’m actually running it in Firefox! What is this voodoo?!!

Have a look at the fakeChromecast.js file:

window.chrome = {};
window.chrome.cast = {};
window.chrome.cast.isAvailable = true;

See that? We’ve set up a Chromecast and said it’s available! Sneaky, hey? It’s that easy, folks! :)

The Standard Media Player will now attempt to set up a session request with its application ID. That’s fine: we’ll happily enable it to do its thing.

window.chrome.cast.SessionRequest = function(a) { }

Obviously a real Chromecast does something rather significant here. But we don’t have to care. This is a fake Chromecast. We only provide the function so that it doesn’t break.

Next, the media player makes a new ApiConfig. It’ll pass the session request it just obtained (in our case it’s null, but that doesn’t matter), and two callbacks, the second being a receiver listener. That’s the important one. We want to convince it that a Chromecast is available, so we trigger this callback with the special string “available”.

window.chrome.cast.ApiConfig = function(a, b, c) {
  c("available");
}

So Chromecast is available. Now suppose the user clicks the button to begin casting. This should request a session.

  @chromecast
  Scenario: Click Chromecast button and connect to a session
    Given I am playing media
    When I click the Chromecast button
    Then I should see Chromecast is connecting
Connecting to Chromecast

Connecting to Chromecast

How did we do this? Easy! The media player requests a session, sending a success callback. Fake Chromecast store a references to that callback – on the window so that we can trigger it any time we like! The callback function is expected to provide a session. We send it a reference to a fake session, which is entirely within our control. Oh it’s all so much fun!

window.chrome.cast.requestSession = function(a, b) {
  window.triggerConnectingToCC = a;
  window.triggerConnectingToCC(window.fakeSession);
}

As the documentation says, “The Session object also has a Receiver which you can use to display the friendly name of the receiver.” We want to do exactly that. We decided to call our fake Chromecast Dave. Because Dave is a friendly name! :)

window.fakeSession = {};
window.fakeSession.receiver = {friendlyName:"dave", volume:{level:0.7}};

I think i found our app expected the session receiver to supply a volume too, so i added that.

The media player does some shenanigans with media that we don’t need to care about, but when it sends a request to load media it passes its callback to trigger when media is discovered by Chromecast. That’s another important one for us to keep, so we store that one. We wait 1 second for a semi-realistic connection time, and then trigger it, passing a reference to .. fake media, woo!

window.fakeSession.loadMedia = function(a, b, c) {
  window.pretendMediaDiscovered = b;
  setTimeout(function() {
    window.pretendMediaDiscovered(window.fakeMedia);
  }, 1000);
}

And now we are almost there. The last clever trick is the communication of status updates. The media player sends us a callback it wants triggered when there is a media status update. So we store that.

window.fakeMedia.addUpdateListener = function(a) {
  window.updateCCmediaStatus = a;
}

The magic of this is, we stored the references to fakeMedia and fakeSession on the browser’s window object, as well as the callbacks. This means the test script has access to them. Therefore the test script can control the fake Chromecast.

So you want Chromecast to report playing? Make it so!

  @chromecast
  Scenario: Begin casting
    Given I am playing media
    When I click the Chromecast button
    And Chromecast state is "PLAYING"
    Then I should see Chromecast is casting
We are casting!

We are casting!

What does that mean, Chromecast state is “PLAYING”? It’s pretty straightforward now, using the objects and callback functions that the fake Chromecast has set up:

When(/^Chromecast state is "(.*?)"$/) do |state|
  $chromecast.state = state
  $chromecast.update!
end

Those two methods get added to the Chromecast Ruby class:

class Chromecast

  def initialize
    $capybara.execute_script <<-EOF
      var el=document.createElement("script");
      el.type="text/javascript";
      el.src = "https://gist.githubusercontent.com/sermoa/10988494/raw/82e08c5a29b5689b5e9f3d03c191b8c981102d85/fakeChromecast.js";
      document.getElementsByTagName("head")[0].appendChild(el);
    EOF
    @media_alive = true
  end

  def state=(state)
    @media_alive = false if state == 'IDLE'
    $capybara.execute_script "window.fakeMedia.playerState = '#{state}';"
  end

  def update!
    $capybara.execute_script "window.updateCCmediaStatus(#{@media_alive});"
  end

end

Note that i had to do something special for the “IDLE” case because the media status update expects a true/false to indicate whether the media is alive.

So, using these techniques, sending and capturing events and observing reactions, i was able to verify all the two-way communication between the Standard Media Player and Chromecast. I verified playing and pausing, seeking, changing volume, turning subtitles on and off, ending casting, and loading new media.

This fake Chromecast is a lot faster than a real Chromecast, which has to make connections to real media. It’s also possible to put the fake Chromecast into situations that are very difficult to achieve with a real Chromecast. The “IDLE” state, for example, is really hard to achieve. But we need to know what would happen if it occurrs, and by testing it with a fake Chromecast i was able to identify a bug that would likely have gone unnoticed otherwise.

For the curious, here’s a demo of my Chromecast automated regression test in action!

This is all a lot of fun, but there is nothing quite like testing for real with an actual Chromecast plugged into a massive television!

Testing Chromecast for real

Testing Chromecast for real

So that’s how i test Chromecast. If you want to test Chromecast too, please feel free to copy and tweak my fakeChromecast.js script, and ask me questions if you need any help.

Getting chromedriver to work with Ruby selenium-webdriver under OSX Mavericks

I interrupt my soprano-saxophone-and-bass-guitar-playing evening to write very quickly about something that annoyed me today. I can’t find the fix anywhere else on the internet, so i guess it’s up to me to provide the solution.

Yesterday i upgraded to OS X Mavericks. Which is nice. Free upgrade, woo! Most things work well, though i had a few Java version issues.

Today i found that selenium-webdriver was not able to launch Chrome with chromedriver. It would open and immediately quit.

A quick google reveals that the workaround is to start chromedriver with the --verbose flag and then it magically works again. Which is true in my experience. But all the examples are for selenium wedriver called by Java or Python and i couldn’t find one for Ruby.

The first thing i did was upgrade selenium-webdriver gem to 2.37.0 and chromedriver to 2.4. I checked my version of Chrome; it is 30.0.1599.101 which is apparently up to date. When none of those things made any difference, I investigated the verbose option.

I thought i would just have to pass --verbose to the Capybara::Selenium::Driver via the args or switches option. But no. That will send the flag to Chrome when it launches, but i need the flag to be set on chromedriver.

Ruby open source to the rescue!

I poked around in the source code for service args and found this:

# selenium/webdriver/chrome/bridge.rb

module Selenium
  module WebDriver
    module Chrome

      class Bridge < Remote::Bridge

        # ...

        def extract_service_args(opts)
          args = []

          if opts.has_key?(:service_log_path)
            args << "--log-path=#{opts.delete(:service_log_path)}"
          end

          args
        end

        # ...

      end
    end
  end
end

Hmm, so the only service arg you can set is the --log-path. That’s no good.

Ruby monkey patching to the rescue!

In my cucumber features folder i made a support file to monkey patch that method, and add a possibility of sending any service args i like.

# features/support/selenium_webdriver_monkey_patch.rb

module Selenium::WebDriver::Chrome
  class Bridge
    def extract_service_args(opts)
      args = []
      args += opts.delete(:service_args) if opts.has_key?(:service_args)
      args << "--log-path=#{opts.delete(:service_log_path)}" if opts.has_key?(:service_log_path)
      args
    end
  end
end

Now in my env.rb file i just have to require the monkey patch file and i’m able to send the verbose flag.

# features/support/env.rb

# ...

require 'selenium-webdriver'
require 'selenium_webdriver_monkey_patch'

# ...

Capybara.register_driver :selenium_chrome do |app|
  Capybara::Selenium::Driver.new(
    app,
    browser: :chrome,
    service_args: ["--verbose"])
end

# ...

Hey presto, now i can set the verbose flag on chromedriver, and sure enough, it works. I am testing in Chrome again.

It seems a really horrible hack, and i hope a better solution is found soon, either from a Mavericks update, or chromedriver, or maybe selenium-webdriver will add this option for service args in a future version.

I still don’t really know why verbose works when normal mode does not. But there we go. I can test again tomorrow, and that makes me happy!

Now, back to my bass guitar! :)

Testing apps that depend on external services or APIs

A lot of web programming these days doesn’t live in isolation. We consume services over the internet via APIs, and we send information to other services, such as Google Analytics, to track what users are doing.

I’m currently back at the BBC, where we have a lot of teams working on components that cooperate together: programme scheduling and publishing, video encoding, media streaming, DRM verification, content delivery networks. Testing becomes a great challenge when dealing with so many moving parts, across multiple environments (dev, int, stage and live) .. and even when it works, integration tests can get slow.

What do we really mean by integration testing?

I think automated integration testing should test the integration points .. not whether they actually do all line up and integrate correctly. There is a place for both, of course. Sometimes you need full end-to-end integration tests. But they are slow and brittle. I think we can add a little bit more control here.

Example of a dependency on an external API

Suppose I want to test an app that relies on an external service. In this case it’s a weather app.

Weather in Bristol

You can visit this now if you like: aimeerivers.com/weather/Bristol

Change the city in the URL and you’ll find out the weather for that city.

The way it does this is by parsing an API provided by OpenWeatherMap.

http://api.openweathermap.org/data/2.5/weather?q=Bristol

It gives us something like this:

{
  "coord": {
    "lon": -2.59665,
    "lat": 51.45523
  },
  "sys": {
    "country": "GB",
    "sunrise": 1368850387,
    "sunset": 1368907233
  },
  "weather": [
    {
      "id": 800,
      "main": "Clear",
      "description": "Sky is Clear",
      "icon": "01d"
    }
  ],
  "base": "global stations",
  "main": {
    "temp": 286.78,
    "pressure": 1008,
    "humidity": 81,
    "temp_min": 284.15,
    "temp_max": 289.35
  },
  "wind": {
    "speed": 2.6,
    "deg": 230,
    "var_beg": 200,
    "var_end": 270
  },
  "rain": {
    "3h": 0
  },
  "clouds": {
    "all": 0
  },
  "dt": 1368907010,
  "id": 2654675,
  "name": "Bristol",
  "cod": 200
}

If we didn’t know anything about the API dependency, we might write the following feature file:

Feature: Weather report
  As a visitor to Bristol
  I want a page that tells me what the weather will be
  So that I can decide what clothes to wear

  Scenario: Report says it's going to be clear
    When I look at the weather report for "Bristol"
    Then I should see the weather is "Sky is Clear"

We could use Capybara to test, and step definitions would look like this:

When /^I look at the weather report for "(.*?)"$/ do |city|
  visit "/weather/#{city}"
end

Then /^I should see the weather is "(.*?)"$/ do |expected_weather|
  page.should have_css '.description', text: expected_weather
end

I’m sure the problem here should be immediately obvious: the weather changes! So how do we allow for changing weather?

One way is to make the step definition more vague: “Then I should see the correct weather” .. the step definition would have to make a call to the same API, parse the JSON, and make the expectation based on the response it finds. If it comes up with the same answer as the app, we can assume the app is behaving as expected.

It’s is a viable solution, but i don’t think it’s the best.

Stub out the API

Ideally, i should be able to run the app locally. There are a number of good reasons for that anyway: i can debug the code, i am able to trace log files and get more meaningful error messages, it’s faster to run, and i can run it offline (once i have stubbed out the API dependencies!)

If i can’t run the app locally, it’s okay, but i have to be able to configure the app somehow to fetch data from a different source, one that is under my control. We did this a lot in the Olympics, using REST-assured to return responses to API requests. It was a good way to gain control over the ever-changing data.

But if i can run the app locally, i can reroute api.openweathermap.org to localhost, and then it’s mine to play with as i wish.

sudo vim /etc/hosts

Add a line:

127.0.0.1 api.openweathermap.org

Now my machine is going to reroute requests for api.openweathermap.org to localhost. Hurrah! Successfully intercepted!

Intercepted API

And of course, my app, running locally, encounters the same thing.

App broken because i have intercepted the API

Now i can put the data that i want there. Oh, there’s a catch: we have to run on port 80. But that’s okay, we can do that. Considering it means the app will be completely unaware of the change, i think that’s a small price to pay.

Introducing RackDoubles

RackDoubles allows you to create, change and remove endpoints at runtime.

Start off with a very simple config.ru file to run a Rack app that uses RackDoubles. You have to define a run method but it’s as simple as it could possibly be.

require 'rack_doubles'
use RackDoubles::Middleware

run lambda { |e|
  [404, {'Content-Type' => 'text/plain'}, ['Not found']]
}

Because we need it on port 80, we have to use sudo to run it, or in my case rvmsudo because i use and love Ruby Version Manager.

rvmsudo rackup -p 80

And just leave it running. The magic is about to happen.

Now, watch this. Here’s what we’re going for:

  Scenario: Report says it's going to be clear
    Given the weather API is stubbed to return "Bristol.json"
    When I look at the weather report for "Bristol"
    Then I should see the weather is "Sky is Clear"

I have saved the JSON i want into a file features/support/stubs/Bristol.json

So let’s use RackDoubles to set up the stub response:

def client
  RackDoubles::Client.new('http://127.0.0.1')
end

Given /^the weather API is stubbed to return "(.*?)"$/ do |filename|
  response = File.read(File.join(File.dirname(__FILE__),
                       '..', 'support', 'stubs', filename))
  client.stub('/data/2.5/weather')
  .to_return(200,
             {'Content-Type' => 'application/json'},
             response)
end

Now the data is entirely under my control. The test passes.

The best news is, now i have the opportunity to simulate bad data from the API. And did you spot the 200 status code there? I can easily write a step definition to stub the API to return a 503 Service Unavailable, to see how the app handles that.

  Scenario: API is unavailable
    Given the weather API is unavailable
    When I look at the weather report for "Bristol"
    Then I should see "Please try again later"

Here’s the step definition:

Given /^the weather API is unavailable$/ do
  client.stub('/data/2.5/weather')
  .to_return(503,
             {'Content-Type' => 'text/plain'},
             'Service unavailable')
end

Now if that test fails i have something to tell the developers about. I can easily demonstrate a scenario in which the API is unavailable. These are things that a manual tester cannot easily do. A developer might simulate them with unit tests, but i am able to test it in a reliable, repeatable way that may not be a full end-to-end test, but i think it’s a pretty good integration test.

Of course, there is still a need for full end-to-end test coverage, but i think that’s best covered by manual exploratory and smoke testing, which are still necessary and highly valuable. As Developers in Test, we have the skills to make life a bit easier for ourselves and our teams, so let’s use them.

Automating Cucumber test scripts on a Mac

I’m really enjoying my work at the BBC on the Olympics team! I’m primarily implementing Cucumber scenarios to verify the work that the developers are doing. I’m also using other tools for stress testing and performance monitoring.

My work here is leading me to use Cucumber in weird and wonderful ways! Here’s an example. Yesterday i was asked to run a script every half an hour that tests the Olympics video player to see if it’s playing successfully, and if not, to email people to say that it’s broken. Not your usual Cucumber scenario, but amazingly enough, it can be used to do that!

Forgive the jargon below. PID is a programme identifier, and IVP is the Interactive Video Player that we are building.

  Scenario: Check LIVE video player
    Given a live PID 
    When I check the IVP 
    Then I should email people if anything goes wrong

I can use a combination of javascript hooks and taking screenshots a few seconds apart and comparing them to tell whether the video is running. I decided to run some step definitions that i’ve already defined and rescue any errors to be emailed. There are a few more steps in here but i’ve stripped it down a bit for simplicity.

When /^I check the IVP$/ do                                                                         
  if @pid
    begin
      step 'I attempt to view the IVP host page with that PID'
      step 'the video should be ready'
      step 'the video should be playing'
    rescue Exception => e
      @error = e.message
    end
  end
end

Notice that there might not actually be a live PID at the moment. It feels very weird, to put conditional logic in Cucumber step definitions like this!

Now comes the email part. I used Pony and sendmail as a simple email sending mechanism.

Then /^I should email people if anything goes wrong$/ do
  if @pid && @error
    subject = "Assurance test failed in #{ENV['ENVIRONMENT']}!"
    body = "#{page.current_url} caused this error: #{@error}"
    recipients = ['send_to@me.co.uk']

    Pony.mail(:to => recipients,
              :subject => subject,
              :body => body,
              :via => :sendmail)
  end
end

So, with that working, i set about putting it on a schedule. I thought i could just call the script from a cron task, but it turns out that wouldn’t work because i need to launch Firefox with Selenium to test the flash player.

I found this cool built-in Mac tool called Automator. You can set up all sorts of tasks into a workflow. I just needed a simple shell script:

And now, we can call that from a cron job every 30 minutes! You might have to hunt around a bit for where it saves the file. For me it’s in my Library/Services.

*/30 * * * * automator /Users/daniea16/Library/Services/IVP\ Test.workflow

Another creative alternative to the cron job is to set up recurring calendar appointments in iCal. You can set an alarm that runs a script. Pretty awesome, hey?! :)

I know Cucumber is meant to be a BDD framework, and was never intended to be used for automated regression testing or assurance testing, but isn’t it cool that with a little bit of imagination you can bend it to fit these alternative uses? :)

An Android app to send prayers to Jerusalem

I have just finished a two-week project building an Android app called @TheKotel – Prayers to Jerusalem.

Now, anyone who knows me even slightly might think this is a bit weird, and believe me, i had a long conversation with myself about it before deciding to take on the work. These are the reasons that i did.

  1. I think it’s a nice idea. Putting thoughts into words and feeling that you’ve offloaded them somewhere is sometimes all people need to feel better.
  2. I saw a video of Alon printing the prayers and cutting them up and taking them to the wall. It made a personal connection for me.
  3. There’s already a successful iPhone app with over 10,000 downloads, so i saw this is definitely something that people want, which is all good publicity for me.
  4. Alon raised money from the people who already use the iPhone app to pay for the development of the Android app.
  5. I saw it as an opportunity to learn a bit more about Android development, try out PhoneGap and Sencha Touch (which i dropped when i found i wasn’t happy with the quality).
  6. I had saved up enough money in the back that i could offer this more-or-less as a gift, not expecting much money for it but instead doing it for reputation and for another Android app in my portfolio.

The concept is very simple. You type your prayer on a piece of paper (or pray out loud with Android’s speech-to-text feature) and press “Amen” and the prayer gets sent to Alon in Israel.

Combined with all the prayers that get sent via twitter and the iPhone app, Alon prints out thousands at a time, cuts them into little slips, rolls them up tight and takes them to the Western-Wall, or The Kotel, the remains of the Second Temple in Jerusalem.

The app is free, and the service is totally free, but donations are gratefully accepted. There is also a Connect screen giving options to share the app with friends and feel connected to the Western-Wall and Jerusalem. We also included some background information about the Wall and how the service got started, as well as some personal messages from a few supporters who helped to raise funds.

Best of all, there’s the gallery where you can see where the prayers are going. I really like this image of Alon putting the prayers in the Wall.

I am very pleased with the final result. It’s nice and fast, good native Android experience, and i think people are going to love it! I enjoyed coming back to Android development, say what you want about Java, but i like it!

If you can bear to listen to me talk about this anymore, Alon asked me to record a video in my “enchanting” British accent, heheh! :)

Device graphics were generated with Device frame generator and released under CC BY 3.0 license.

Build and launch a web shop in a day

My day yesterday began at Winchester station at 05:19 in the morning, with a big ambition:

I arrived in Kent at 08:25 and was met by Alanna who owns Aphrodite’s Desire. We got straight to business. By 08:45 we were settled in with a cup of tea and signing up to Shopify.

Let me back-track a little. We had already had several email conversations and had met previously to discuss options, and decided that Shopify was the best solution. Alanna needed something that is easy to manage, looks good, and can handle orders and payments reliably.

Our first concern was that Alanna’s debit card might not be accepted as Shopify says it wants credit cards. According to two people i spoke to at Shopify, some debit cards work, but not all. Fortunately, Alanna’s Visa card was accepted.

I began by demonstrating how to add products. Alanna’s immediate reaction was, “Oh, it’s just like Facebook!” Alanna was already uploading product photos before i’d even pointed out the option! Huge props to Shopify! Fortunately, Alanna had done a lot of good preparation work writing up descriptions for the products and getting all the photos ready. This was a major advantage to launching in a day.

In the meantime i worked on installing and customising the theme that we’d previously chosen. I asked Alanna’s opinion on a few fonts and we chose some photos for the banner.

I installed the iPhone extension. Alanna had already downloaded the app, and it was cool to see products appearing on the iPhone. We were both impressed by Shopify’s handling of discounted products, and combinations of different variations, some being available and some out of stock. I was impressed at how easily i could extend the theme and add a message that invites people to contact Alanna to ask about unavailable items.

By lunch time we had a pretty good looking shop! We were admiring it on the iPad over lunch. We went out for a quick walk and fresh air before coming back like, “Right! we have a shop to launch! Let’s get to it!”

Adding the facebook and twitter integration was fun. You can ‘like’ products and add comments and it all gets synchronized to facebook. Alanna can click a button to promote products on twitter and facebook. It’s great! Shopify extension apps are awesome!

We spent a bit of time doing the PayPal integration, and then a lot of time signing up for Sage Pay. A lesson learnt: if you want to accept credit/debit cards directly on day 1, you must apply for your Sage Pay merchant account in advance. But it wasn’t so bad to launch only with PayPal.

We had a dilemma when it came to shipping options. Because Alanna hadn’t weighed any of the products, we were leaving them all as weighing nothing. But this meant we couldn’t calculate the shipping. Alanna wanted to charge £5 for a single product, and £1 extra for every additional product. So we came up with the idea of making every product weigh 1lb just so that we can count them in the cart.

That being done, we just needed to tidy up the additional pages and navigation links. I was keen for Alanna to do this, so as to be able to do it again in the future. Shopify provides a very nice content management system which is simple to use. I did a little bit of graphics work on images for Alanna to use.

I think it was about 17:00 when we launched! We spent about half an hour tweeting and facebooking about it like crazy … and then an order came in! Alanna was just looking at the iPhone app and said something like, “Oh, is something wrong here? It says …” and it was an order from one of my friends!

Fantastic! A working web shop in one day! It is totally possible! The shop had 171 unique visitors on its first day.

My day ended with this from my mentor:

I went to bed feeling very satisfied and utterly amazed at knowing i get paid to have a lot of fun and do what i really love to do. It was a brilliant day!

Please visit aphroditesdesire.com to have a look at what we did. Kisses to shopify.com for making it all possible!

Well, hello!

Hello to everybody who knows me from my two previous blogs: edendevelopment.co.uk/blogs/aimee and aimee.mychores.co.uk. I have decided to merge the two into one, which for convenience i’ve decided to have hosted on wordpress.com now.

Big news

In case anyone is not aware, let me share the news that eden development, my place of employment for nearly 3 years, closed its doors in March. For me this is sad news: eden was a truly remarkable place to work.

Through eden i met many amazing people, and learnt to hone the craft of developing excellent quality software. I have learnt how to listen to clients and understand their needs. I have been privileged to take on despo and Alberto as apprentices, imparting my knowledge and care and seeing them develop. Most importantly, i have grown in self confidence, to the point where i am now able to journey out on my own, taking on contracts and freelance work.

Contracting

My contracting has begun at a consultancy firm in London. I have been contracted as a front-end developer, doing HTML, CSS and a bit of Javascript. It is easy work for me, not really particularly challenging. I am happy with that: at the moment i have big challenges to do with commuting and getting used to being self-employed, keeping control of expenses, invoices and tax. I didn’t want the added pressure of difficult work on top of that.

It turns out that the job is suiting me very well. I get on well with the people i work with, and i found i was able to start providing value for the company from my first day. I’m working hard and i believe i am exceeding their expectations of me. At the same time i’m learning how to use Demandware, a powerful ecommerce platform, and i may well find that the skills i learn here could come in useful for me again at some point in the future.

Looking ahead

My contract takes me until the middle of May, at which point i’d like to spend one week working on a freelance project. After that i’d like to take on another contract, and this time i’m particularly looking for something that uses my Ruby skills, as well as my knowledge of behaviour driven development. There are two possibilities i’m looking at, and i’m fairly confident that one of them will work out.

I am always interested in meeting new people to talk about work that i may be able to help with. I am really enjoying the freedom of contracting, so i’m not looking for permanent employment at the moment, unless it’s a very good offer. I’ve realised that job security is a myth, and painful though it was to leave eden, i think i needed that push to venture out on my own.

Right now

At this very moment i am at Scottish Ruby Conference in Edinburgh. I really enjoyed it last year, and this year seems even better. I am meeting new people and rekindling previous friendships. Today i have been inspired to work on a charitable project, i enjoyed an entertaining discussion on programming etiquette by Jim Weirich and Chris Nelson, and i was excited to see how MacRuby works.

It’s lovely that my mentor Enrique is here at SRC, sharing an apartment with me, and my apprentices are both here too. Edenites Chris and tooky are also around, and it’s great to spend time together again. Our shared experience of being part of eden is something that will remain with us, and we will always be good friends.

Notice that i say “edenites”, not “ex-edenites”. For me, eden was all about the culture and the people. My pride for quality of work, my valuing of client relationships, my commitment to learning, my honesty, my humility, these are eden’s values that have become deeply ingrained in me, that i intend should never leave me.

Thank you

If you read this far, thank you. You can see why this post has been a long time coming. It’s only now that i’m at Scottish Ruby Conference that i can really take the time to relax and reflect. The last few weeks have been like a whirlwind for me. Thank you to all who have supported me and encouraged me. It has been scary and exciting, and i’m relishing these new opportunities!

Here’s to my ongoing journey! :)

My software apprenticeship

I have recently had the privilege of being accepted as an apprentice to software craftsman and philosopher Enrique Comba Riepenhausen. This is part of Eden Development adopting a craftsmanship approach to software creation.

I am very excited at this new development in my career. It’s going to be hard work because i have a lot to learn, but i am pleased to have made the commitment and to know that i have someone who is playing a very active part in my personal and professional development. Funnily enough, the more i learn, the more i realise how little i really know. The first task that i have been set as part of my apprenticeship is really showing me that.

Eden Development has given me a blog to talk about my progress during my apprenticeship. So i have decided that my apprenticeship blog will become the place that i talk about my technical and coding interests, leaving this blog to be more personal. So if you are interested in me from a technical point of view, please follow edendevelopment.co.uk/blogs/aimee.

There are actually now five apprentices at Eden Development. If you are interested in software craftsmanship it is well worth looking at the Eden staff blogs aggregation to read all our thoughts and experiences on our own journeys.

Glimmers of Hope

This beautiful photo was taken by @ecomba at Barton Farm this morning:

Glimmers of hope

Quite appropriate, since the team have a big project to deliver today, which has been months in the making. I have worked on the project but i’ve been busy doing other things more recently.


Today i was safely out of the way pair programming with @edentodd at the Coffee House in Winchester:

The Coffee House, WinchesterProjected Pair Programming

We projected the code on the projector downstairs, it worked really well!

Coffee shop coding, ftw! :D