FF7: Voices of the Lifestream

February 9th, 2010

<sigh/> For once, I have more to say than will fit in a tweet.

Over the weekend I pulled down OC ReMix’s Final Fantasy VII: Voices of the Lifestream project. I listened to the entire four-disc set while coding at work yesterday, and about half of it while coding in bed last night.

I really enjoyed listening to the album while coding, but I did not enjoy listening to the songs as my primary focus. I have two theories about this. One, these songs were composed to be background music, so if you pay too much attention to them, you break the spell. Or two, listening to these songs directly conjures up images of tireless sitting in front of a small television with a Playstation controller in my sweaty hands, desperately trying to figure out where to go next, and hoping that I don’t run into a battle along the way, because the battle music always makes me jump out of my skin when it starts at 3 AM, and I am pretty low on life anyway, though I really could use the XP, all the while wondering why Aeris had to die.

Yeah, my money is on the second theory.

[Disclaimer: I worked on this game on and off from mid 1998 through about 2005. I never finished, stuck in the ice mountains on the third disc. Oh, and the movie was beautiful, but it sucked, so I protested by buying it anyway.]

Rake recipes for working with Visual Studio projects

February 3rd, 2010

Despite spending my day job coding in Microsoft-land, I find myself using ruby tools more and more during my daily development. I recently wrote some rake tasks that I think are worth sharing and explaining. Specifically, I wrote a tasks to control building with msbuild (seems redundant, I know) and some tasks for starting and stopping Cassini (or webdev.webserver as it is now named).

Monkey patch Pathname for Windows paths

Since I am using the Pathname class to build paths in my examples, I need to give you the monkey patch that I use to make Pathname correctly display win32 paths.


require 'pathname'
class Pathname
  alias_method :original_to_s, :to_s
  def to_s
    original_to_s.gsub('/', '\\')
  end
end

Visual Studio command line environment

Running command line Visual Studio tools requires having certain environment variables loaded. This can be done by running vsvars32.bat directly or by launching a Visual Studio command prompt from the start menu. This is something that I always forget to do; my terminal windows spring into life by typing cmd in the run box. So, I wanted to write a task to ensure that the environment was properly set up.

I am working with Visual Studio 2005. If you want to use the Visual Studio 2008 tools then you will need to adjust the vsvars32_bat variable accordingly.


vsvars32_bat = Pathname.new(
  "c:\\program files\\") +
  "microsoft visual studio 8" +
  "common7\\tools\\vsvars32.bat"
task :vsvars do
  if ENV["VSINSTALLDIR"].nil?
    `\"#{vsvars32_bat}\" && set`.each do |line|
      if line =~ /(\w+)=(.+)/
        ENV[$1] = $2
      end
    end
  end
  raise "Eek!" if ENV["VSINSTALLDIR"].nil?
end

This code is the product of about 30 minutes of googling. I eventually found this trick in the shoes rakefile[1].

Now any task that needs to call a Visual Studio command line tool just needs to declare vsvars as a prerequisite, like so.


task :csc => [:vsvars] do
  sh "csc test.cs"
end

Building with msbuild

This is actually pretty easy once we have the environment set up correctly. Just create a task that calls msbuild from a sh call.


namespace :build do
  desc "Build the core project"
  task :core => [:vsvars] do
    sh "msbuild #{core_solution_path}"
  end
end

Controlling Cassini (or webdev.webserver)

There is a lot going on here, so let me first overwhelm you with the code, and then explain what it is doing.


def wait_until_site_loaded
  puts "Please be patient. Waiting for site to respond...."
  site_loaded = false
  until site_loaded
    site_loaded = system
      "curl -L -I -f http://localhost:2088/Default.aspx > NUL 2>&1"
  end
  puts "done."
end

namespace :web do
  desc "Start the local web server"
  task :start => [:vsvars] do
    Thread.new do
      sh "webdev.webserver /path:#{web_root_path} /port:2088 /vpath:/"
    end    

    wait_until_site_loaded
  end

  desc "Stop the local web server"
  task :stop => [:vsvars] do
    `taskkill /im webdev.webserver.exe > NUL 2>&1`
  end

  desc "Restart the local web server"
  task :restart => [:vsvars, :stop, :start]
end

Before the code block above will work, you will need to create a web_root_path variable that points to the absolute path of your website. Relative paths will not work.

The web:start task will start the web server. If an instance is already running at the specified port, then you will get an error message in the form of a dialog box. I wish I knew how to make it fail silently. (I also wish I knew how to prevent it from displaying an annoying balloon notification.)

After starting the web server, the web:start calls out to curl to make sure that the site is responding to get requests. I have curl installed as a result of installing cygwin. There are other ways to get curl, but you will need to make sure your path points at it’s location to use the code above without modifications. curl is pretty chatty, so I have silenced it by routing its standard out and standard error streams to NUL.

The web:stop task will kill all instances of Cassini. This might be annoying if you have more than one instance running. If that is the case, then you will need to write in some form of accounting for the process id of the web server process, or develop a way to figure out which process id owns the port you want. Once you know the specific pid, you can call taskkill /pid and pass it the pid of the process you want to kill.

The web:restart task will call web:stop task followed by web:start task.

One more thing: display available tasks from default task

Note: This recipe does not apply to just Windows development. It will work on any platform.

You can get a list of documented tasks by calling rake -T, but I always forget to do that. I usually just call rake when I want to know what it does. So I created a :default task that displays the same task list that you get when you call rake -T.


task :default do |task|
  puts "You must specifiy a task. Available tasks are listed below:"
  task.application.options.show_task_pattern = /.*/
  task.application.display_tasks_and_comments
end

That’s it. I hope you found these recipes helpful. Happy coding!

[1]: This is way off topic, so I stuck it in a footnote. I know it’s old news, but the way _why, the creator of shoes, committed Internet suicide really irritates me. There were a lot of people benefiting from his contributions to the ruby world, and then one day he just decides to take his toys and go home. He could have bowed out graciously, explaining that he had moved on, but he instead chose identity death. His works remain in archived form, but I am not sure if there is still any energy behind them.

Watir Wait

January 7th, 2010

I have been working with watir over the last couple of days. I quickly became frustrated with numerous errors claiming that the element I wanted to perform an operation on did not exist. I found the Watir::Waiter class and started using it extensively. So extensively, that I decided to write a little monkey patch to make my life easier.

The application that I am working with performs a lot of client-side DOM manipulation. This can create instances where my script was asking Watir to perform operations on DOM objects that didn’t exist. To defend against that, every time that I called click or set or select on various DOM objects, I wrote two additional statements. One to make sure the browser had finished whatever it was working on, and one to make sure that the element I was about to interact with actually existed.

The code looked something like this.


  @browser = Watir::Browser.new
  @browser.goto("http://localhost")

  @browser.wait
  Watir::Waiter.wait_until { @browser.text_field(:name, /UserName/).exists? }
  @browser.text_field(:name, /UserName/).set("Admin")

  @browser.wait
  Watir::Waiter.wait_until { @browser.text_field(:name, /Password/).exists? }
  @browser.text_field(:name, /Password/).set("Password")

  @browser.wait
  Watir::Waiter.wait_until { @browser.button(:name, /Submit/).exists? }
  @browser.button(:name, /Submit/).click

While that works, I got really sick of having to re-type the selector for the DOM element that I wanted to muck with. What I wanted to do was write code that looked something like this.


  @browser = Watir::Browser.new
  @browser.goto("http://localhost")

  @browser.text_field(:name, /UserName/).wait_to_set("Admin")
  @browser.text_field(:name, /Password/).wait_to_set("Password")
  @browser.button(:name, /Submit/).wait_to_click

Wow. That is much more concise and easier to understand. Even a non-programmer can understand what is happening now.

To make this code actually work, I decided to write a quick monkey patch that adds a “wait_to_” alternative for every method that can be called on input elements and links. These methods call @browser.wait, ask Watir::Waiter to wait for the element to exist, and then call the requested method.

I called my monkey patch Watir Wait. (Get it? I crack myself up! :)) Take a peek and let me know what you think. If I get enough positive feedback, I’ll rework this into a proper patch and submit it to the Watir team for inclusion.

Blood sucking time vampire

December 29th, 2009

A blood sucking time vampire. That is what XKCD is. I clicked on a link from twitter, and 25 minutes later, I had all of the following pages open in tabs, because I wanted to share them. Too long for a tweet.

More letters: this time, Sprint about device pricing and cancellation fees

December 22nd, 2009

It appears that I am on a letter writing binge. Here is the email that I just fired off to Sprint’s CEO, Dan Hesse, and President of Strategy and Corporate Initiatives, Keith Cowan.

Mr. Dan Hesse and Mr. Keith Cowan:

I am writing to talk about the differences I have noticed between the way Sprint treats new customers versus the way it treats existing customers. My observations are specifically based on pricing, but I feel that the pricing sends a message. I am not sure it is the message that Sprint intends to send. Furthermore, I would like to propose a new method for calculating device discounts and cancellation fees.

Starting service in 03/2009, I am a data only user of the Sprint network. I use a PC card with my laptop when I am out of the house. I am very happy with the coverage area the speeds that I have been getting with the device on Sprint’s network. I have recommended Sprint’s data services to friends and family, and I plan on continuing to do so.

I recently learned about the Novatel MiFi 2200, and I wanted to know the cost for purchasing one. I am greatly discouraged by what I have learned.

Sprint is selling the Novatel MiFi 2200 to new customers for $50, after instant savings and a mail-in rebate. Since this offer is only available to new customers, I was expecting to have to pay a little more for the device. My price for the device is $299. No instant savings and no mail-in rebates. Full price. Repeat, no discounts.

After talking to a representative in a Sprint store, I learned that after one year of service, I am eligible for a $75 discount on a new device. After two years of service, I am eligible for a $150 discount on a new device. The Sprint store employee was only able to estimate my cancellation fee at about $150.

Reading through the website and a quick customer service chat, transcript attached, confirmed this information. The chat customer service representative was able to provide me the exact cancellation fee: $140.

Here are the options that I put together after collecting this information.
* remain a current customer and purchase the new device: $299.
* terminate service and sign a new contract: $190.
* wait until I have been a customer for one year: $224.
* wait until I have been a customer for two years: $150.

It appears that preferential pricing is being given to new customers, while existing customers are forced to pay higher prices. In my case, the cancellation fee when combined with the cheap introductory price is encouraging me to cancel my service. I find it startling that Sprint would ever introduce pricing schemes that make it appealing for me to discontinue service. Because if I am willing to sign a new contract with Sprint then why not a competitor?

I feel that the discount pricing and cancellation pricing has become too confusing. Steps need to be taken to simplify the pricing model. While doing so, care should be taken to ensure that discounts are applied fairly to both new and existing customers. Care should also be taken to ensure that cancel fees do not appear to be alarmingly high.

Arguments that have been given to the FCC and Congress by cell phone providers in response to inquiries about high cancellation fees have lead me to assume that the cancellation fee exists to defray the cost of discounting devices for customers.

If this is truly the case, then should be clear in Sprint’s initial pricing. And it should apply to upgrade pricing as well. To make this clear, I have a three part proposal.

First, make device prices the same for everyone but fluctuate the discount based on how long the person has been a customer. New customers pay full price minus $240, called the “new customer discount”. (Example: $299 – $240 = $59) Existing customers pay full price minus $10 multiplied by the number of months the customer has had service, called the “existing customer discount”. (Example: $299 – (10 * 9) = $209) In this scheme, an existing customer gets the same discount as a new customer every two years.

Second, the cancellation fee should be $240 minus $10 multiplied by the number of months since the customer has purchased a device with a discount. (Example: $240 – (10 * 9) = 209).

Third, make the device discount and the cancellation fee very visible. They should be visible when you log in to the website, and they should appear on the paper bill. Being more transparent about the fees and discounts is going to significantly cut down on the confusion and frustration surrounding them.

In this scheme, customers are incentivised to stay with Sprint in two ways, accumulating discounts towards new devices and avoiding a high cancellation fee.

I thank you for taking the time to read my suggestions. I wish you and your family a happy holiday season.

Sincerely,
M. Scott Ford

I wrote my respresentatives today. About food.

December 21st, 2009

I sent the following letter to my congressman, Eric Cantor and to my senators, Mark R. Warner and Jim Webb.

<Mr. Representative>:

This letter was prompted by my viewing the recent documentary, Food, Inc. by filmmaker Robert Kenner.

I encourage you to reintroduce, or support the reintroduction, of “Kevin’s Law,” introduced in the 109th Congress as H.R.3160. I feel strongly that granting additional authority to the Secretary of Agriculture and subsidiary agencies will lead to a safer food system and a healthier public.

I also encourage you to support the “local food” movement. The public needs better access to local food sources. Having a “local food” section in every grocery store will go a long way to providing this access. A more practical solution is to encourage and support the development and growth of farmer’s markets, especially in urban areas.

I would like to close with an appeal to watch the documentary, Food, Inc.. This movie has greatly affected how I feel about the food that reaches my mouth, however, I feel powerless to effect change. My hope is that if more public officials with power to effect change become aware of the current situation then true change will begin to take shape.

Thank you for your time. I wish you and your family a wonderful holiday season.

Sincerely,
-M. Scott Ford

Database Dump: export the contents of your Oracle database

December 18th, 2009

I created another small utility written in ruby. This one dumps the entire contents of a database to a text file. Contents are spewed to standard out, so you will have to pipe the output to a file if you want to do anything useful with it later.

Enjoy!

Ever wanted a database equivalent to grep?

December 17th, 2009

I am always banging my head against the wall when working with legacy databases, because it is difficult tell where information is stored. Reading through the entire application code base to find the location of a string on the user interface is a very frustrating task. It would be much faster if I could just run grep '.*message.*'. I have been wishing that such a thing existed for quite a while, but I was unable to find one that did what I wanted. Start with a dash of ruby, add an hour of my time, throw in some tinkering, and bang. It’s done.

This version only works with Oracle databases, but it should not be too difficult to rework this to talk to database management system that you are mucking with.

Requirements: ruby 1.8.7 or later, ruby-oci8 version 2.0 (if on Windows, make sure you download the binary gem from rubyforge instead of trying to do gem install ruby-oci8)

Enjoy!

Instrumenting assemblies with Mono.Cecil and IronRuby

December 16th, 2009

I just finished working on a script that I am really proud of. So proud that I want to share it with all of you.

I am working on making modifications to a third party application. I have source for some of the application, but unfortunately just having the source has not answered all of my questions. The application’s architecture is rather convoluted, and the source code is filled with hints that it was produced by very inexperienced hands. To steal a quote that I read on twitter a couple of months ago, “I was hoping to at least get spaghetti, but this code is just soup.”

So, I wanted to instrument the code so that I could get a better idea about what was going on in one particular library, specifically one that leverages Microsoft’s Workflow Foundation. My first stab at this was to just read the source in and add code to each method that marks the insert and exit points. I was planning on using the System.CodeDom libraries for this, and I was rather disappointed to discover that CodeParser is not implemented by the .NET Framework for C#.

So I turned to Mono.Cecil instead. I wrote a utility that modifies every constructor and every method. For each one, a message is inserted at the beginning of the method to note that it has started, and a message is inserted right before the return statement to note that the method is complete. Messages are transmitted through log4net, so you will need to play with your app.config to make the tracing messages show up.

The utility is written in ruby and will only run from IronRuby, because it makes heavy use of the .NET Framework. Oh, and the utility has the ability to apply and remove the instrumentation to an assembly, so you can put it back the way you found it.

Enjoy and let me know if you find any problems.

Using log4net with IronRuby

December 7th, 2009

Using log4net with IronRuby is something of a pain. This is for two reasons.

  1. log4net violates Microsoft’s API naming guidelines by naming the root namespace in the log4net assembly as ‘log4net’. A conforming name would look more like ‘Log4Net’.
  2. IronRuby ignores any namespaces that start with lowercase letter. It will flat out refuse to load them.

These two facts together lead to total suck, but I have found a work around. I wrote a wrapper class that invokes the log4net assembly via reflection. This lets you call log4net.Config.BasicConfigurator.Configure() so that log4net gets configured from the app.config file. The wrapper class also allows you to access named loggers and provides a way to output the log levels that are configured for the root logger.

Enjoy!

IronRuby and the Configuration (app.config or exe.config)

December 4th, 2009

I was trying to write a quick little IronRuby application that talks to a third-party library that I am working with. I ran into some problems related to configuration files, and I thought I would share how I got around the problem.[2]

The library I am working with requires that some values exist in the application’s configuration file, which could be either the app.config file or the executable_name.exe.config file. But I have no way to specify these values, because IronRuby’s ir.exe[1] has it’s own configuration, ir.exe.config that sets up paths and other options for the Dynamic Language Runtime (DLR). Any application that you execute with IronRuby is run within the context of ir.exe, and so it inherits ir.exe’s configuration.

I should mention I could have added the values directly to ir.exe.config, but I dismissed this solution as unacceptable. I am really a stubborn person.

During my extensive research into the issue I encountered several suggested solutions, but none of them worked. Most discussions that I came across ended with someone giving up and modifying ir.exe.config.

The .NET Framework provides no approved way to modify the configuration once it is loaded into memory. I imagine that this is due to security issues. You would not want malicious code to get access to the configuration file and change the values. My second of two attempts to solve this problem resulted in success.

First, I tried creating a new AppDomain with its own configuration. However, I was not able to use any IronRuby constructs to get code to execute within the context of the child AppDomain.

To do this I first tried creating a MarshalByRef descendant that contained the code requiring the configuration settings. However, the way IronRuby creates CLR versions of the Ruby types made this very difficult. It looks like the types are created in an in memory assembly, but I could not get a reference to that assembly that would let me load my custom type into a different AppDomain. I kept getting errors complaining that the assembly could not be found. After hours of trying and trying I gave up and decided to call AppDomain.DoCallBack instead.

Here I encountered an issue with IronRuby delegates. I created a proc with the code that I wanted to execute and passed it into the constructor for the delegate type that is expected by the DoCallBack method. However, I got a really strange error complaining about not being able to serialize the delegate into the new AppDomain. Strike two. At this point giving up is starting to look like a really good option.

Not knowing another way to solve the problem, I decided to hack my way to a solution. With my friendly companion, Reflector, I started deciphering the logic that reads configuration files into memory. I wanted to find out how to change the configuration file that the current AppDomain is using and then force the AppDomain to read from the new configuration file. The result is the ConfigurationSettingsHackery class. It uses reflection to dig into System.Configuration and change some key private members. After doing so, the AppDomain re-reads the configuration the next time that configuration information is requested.

I hope this helps someone. It would have really been nice to have this class two days ago. I should warn you, however, that this is a nasty, nasty hack. As such, it it most likely not work on the next version of the .NET Framework.

[1]: I am using IronRuby 0.9.2.
[2]: This discussion is also applicable to IronPython users that are trying to do the same thing, as it has the same issues and limitations.

Mono.Cecil and Type Forwarding

November 23rd, 2009

Just a quick note to help those that may be searching for the ability to use Mono.Cecil to create an assembly that forwards types to another assembly. I after trying several different ways to call the library to do what I wanted, I decided it was time to dive into the source and see what was going on. Well the answer to my frustrations was found after much searching. Take a peek at the source for Mono.Cecil.ReflectionWriter and search for TODO. You will find the VisitExternType method. It contains nothing but the comment, TODO. Oh, and the method is never called, so good luck trying to figure out how it is supposed to work.

I am going to try to get this to work with Microsoft’s CCI instead. I will report my findings in another post.

Importing an existing git repository into subversion

November 12th, 2009

I been scouring the net for a way to take an existing local git repository and apply all of the commits to a subversion repository. I finally found the answer. I am going to rewrite the procedure here while I wait for my code to be commited.

Assume you have an existing git repository, and you are currently in that directory, run the following commands to link your git repository to the subversion repository.


  $ git svn init -s svn://my/svn/server
  $ git svn fetch

The result of the fetch command should display a series of revisions from the subversion repository.

Now run the following command and store the result somewhere.


  $ git show-ref trunk

This should yield a sha-1 hash for the remote repository.

Now we need to grab the hash for the local repository.


  $ git log --pretty=oneline master | tail -n1

Finally, we need to let git know that these two revisions should be “grafted” onto one another for that do the following.


  $ echo "<second value>  <first value>" >> .git/info/grafts

Running git log should reveal that the last commit from subversion now appears right before the first commit in your local repository. Perfect!

Now run the following command to push everything into the subversion repository.


  $ git svn dcommit

Sit back and watch the output scroll by. My commit is still running, even after typing this entire post. :)

Go, Go gadget Google!

November 11th, 2009

Okay, so the title of this post needs some work, but I wanted to take a few moments to comment about the new programming language on the street today, Go.

Go was born out of one of Google’s famous 20% projects. I have been reading through the documentation on the project site, and I am starting to get a feel for the motivation behind the development of the language.

It appears that someone at Google was a really big fan of C. Such a big fan, that they designed a language with the same basic feel, but with some newer and improved syntax sugar.

With most of the sexy languages in the land being of the dynamic variety, it is interesting to see such an improvement in the static space. The Go language utilizes many features that are really popular in dynamic languages, but provides the advantages that come only as an after-thought with most dynamic languages.

It is going to be interesting to see how this language becomes adopted. I, for one, am not anxious to start using it. Mainly because I have been working with Ruby in my free time. (Ha! Free. right. More on that some other day.)

I am going to remember Go though for one particular use case. If I find myself unhappy with Ruby runtime performance, and I want to optimize by writing closer to the metal, then I am more likely to reach for Go than I am to reach for C or C++. Very interesting.

vaderpi.com has moved

November 11th, 2009

If you are reading this, then everything is working with my website’s new home in the cloud. I have only moved over the blog, and I am redirecting all traffic from the main url to here. I have not updated the content on the home page in at least three years. I might get to that at some point, but I really doubt it. This blog’s archive is littered with posts of me claiming to update the content there, yet nothing has happened. :)

Oh, and if you try to contact me at an email address that is not scott [at] vaderpi [dot] com, then you will not get me. That is the only personal email address that I am checking anymore.

sudo, Ubuntu, and the PATH environment variable – a love story (of sorts)

November 7th, 2009

I just started setting up a Ubuntu Karmic Koala (9.10) server in the cloud, and I became very frustrated very quickly about the default behavior that is compiled into sudo. Since there is not much info laying around the net on how to solve this problem, I thought I would throw this post together. So if the big search engine in the sky brought you my way, then I hope this helps you.

Sudo on Ubuntu Karmic has been compiled with the –with-secure-path option. This causes sudo to ignore any changes to the path environment variable. And I do mean any changes. Changing the path in the user’s environment ala PATH=$PATH:/opt/other-bin sudo gem will not work. Neither will modifying the path variable in the /etc/environment file. And don’t try to modify the PATH in /etc/profile or /root/.profile or /root/.bashrc because none of those will work either.

If you want to see the path that sudo is using then take a peek at /usr/share/doc/sudo/OPTIONS. There you will see the exact path that was compiled into the sudo command.

This “secure path” can be modified. But before I tell you how, I should insert a word of caution. My research indicated that this was done for your protection. As with many things that are done for your protection, it is annoying as hell. But it evidently makes it harder for trojans to run commands as root. So make sure that you think twice before making changes to the “secure path” that sudo uses when it runs.

Thanks for patiently reading the disclaimer. Now for the juicy details. To modify sudo’s “secure path” you just need to add a line to the /etc/sudoers file. This file is best modified using the visudo command. So fire up visudo and add the following line.


  Defaults        secure_path=<your new path>

I highly recommend that you start with the value that sudo was compiled with and then append to it.

I hope that helps you.

It would have been really nice if this was documented better somewhere. I was only able to piece this solution together after reading a lot of confusing forum posts and after several head-scratching reads of the sudo man page.

Cukeness

October 22nd, 2009

While I have not worked on it in a few weeks, I would like to talk about Cukeness. Cukeness is an open-source project that I started right after attending Agile 2009. I actually started writing features/stories for the application in my Moleskin sketchbook on the plane flight home.

So what is Cukeness?

Cukeness aims to be a web-based user interface for Cucumber.

Wait. What is Cucumber?

Cucumber is a Behavior Driven Development tool that allows developers and product owners to have a conversation about how an application should work. This tool is great for the product owner, because the conversation is held using terms that she understands using plain English (or another natural language, like French or Italian). This tool is great for the developer, because the log of the conversation can be executed against the system under development to evaluate if it meets the product owner’s need.

Okay. And Behavior Driven Development is?

Behavior Driven Development, or just simply BDD, is an approach to software development that primarily focuses on delivering business value, not just technical value.

Got it. Now what does this conversation between product owner and developer look like?

The focal point of the conversation is the “feature”. Some approaches refer to this instead as a “story” and other approaches refer to this concept as a “use case”. The term you use does not matter. What does matter is that the developer and product owner work together to describe how the system is supposed to implement a particular feature. To do this, Cucumber provides the “scenario”. Each feature contains a set of scenarios. Each scenario describes, in detail, how the application is supposed to behave within the context of the feature that the scenario belongs to.

To convey this level of detail, scenarios are written with three kinds of sentences, each starting with either “Given”, “When” or “Then”. Given sentences are used to describe the steps that are taken to establish the scenario. When sentences are used to describe the actions that are performed. Then statements are used to describe the result that is expected from performing the action described in the When statement. These statements are written in a simple text file (example) with a name that ends with “.feature”.

Alright. How does Cucumber actually talk to the system under development?

Feature files (any file with a name ending with “.feature”) are given to the Cucumber command-line utility. Cucumber reads each sentences in the feature files and tries to find a corresponding “step definition”. Each step definition is responsible for talking to the system under development and performing the action that is described by the scenario sentence, or step.

Step definitions are written by the developer in a computer programming language. At this point, many different languages are supported, but ruby is the most common. Product owners should not have to worry about writing the step definitions. They only need to make sure that the step definitions get written.

So why does Cucumber need a user interface?

Perhaps it doesn’t. But not everyone is comfortable using a command-line interface, especially your typical product owner. At the moment, that means that developers become responsible for executing the feature files to determine if the system is behaving correctly. I would like to give this power to the product owner.

How does Cukeness let product owner execute the feature files?

Well, right now, Cukeness still needs a little bit of work, so instead I should talk about how Cukeness will do this.

Cukeness provides wiki-like editing capability for features and scenarios. This gives Cukeness users the ability to read existing features or scenarios and create new ones through a comfortable user interface.

Cukeness users also have the ability to execute the features and see the results of the execution. Users are able to execute all of the features at once, execute a single feature or execute a single scenario. Results are displayed by annotating each scenario sentence with the status that resulted by running the scenario sentence. Furthermore, sentences are colored coded to provide better visual feedback. Cukeness uses the same colors that the Cucumber command-line utility uses.

When can I use it?

Well, like I said, Cukeness still needs some work, and is not ready yet for public consumption. Not even as a beta. However, I encourage any developer that is interested to fork the source code on github and start playing around. I would really like to see someone contribute some patches to move the project further along.

I have been distracted by another side project that I am exploring, and as a result I have not worked on Cukeness in a few weeks. However, I am committed to seeing the project succeed.

What tools were used to develop Cukeness?

Cukeness is a ruby on rails based web application. Application behavior is described using feature files and are executed with cucumber. Tests are written with the rails unit testing framework, although I have been considering switching the rpsec for this.

The State Of Me

September 29th, 2009

Introduction

There have been a bunch of recent events that I need to catch my friends up on. Some people know some details, but very few people know all of the details. So what better way is there to communicate with the masses than my blog?

I guess there is no better place to start than the beginning.

I can’t stay awake

For the last few years, I have been struggling with a sleep disorder. The diagnosis that best describes my issue is hypersomnia. The basic gist is that I cannot stay awake during the day. This also means that I have trouble getting up in the morning. Not just a little bit of trouble, but a lot of trouble. So much trouble that some days I don’t make it into the office. This got so bad that I was missing about 5-6 days of work a month. If you do the math that is about once a week, sometimes more.

It became clear to me that the quality of my work was severely suffering as a result of this condition. With that in mind, I asked to be placed on medical disability leave. Basically, I hit rock bottom. All this happened about two weeks ago.

A really good friend of mine also made it clear that I needed a change of scenery in order to really get better. I needed a soft place to land and a really good social support network. People to keep an eye on me as I worked through my issues and to be there through whatever treatment is required. His suggestion was to move back home. So I did. I have been living with my parents in the Richmond, VA area for the last 2 weeks.

My parents have been crazy supportive through all of this. They have been helping me monitor my sleep habits, and they have been using their social network to get me in touch with some of the best doctors in the area.

Serendipity

An uncanny coincidence of having to move home was having to face the people of my past. My ten year high school reunion was the same weekend that I actually made the move back to my parents house.

There were a few things that I did before the reunion. I watched the movie Gross Pointe Blank, and I contacted Andrea Goulet, perhaps my best female friend from high school, to find out if she was going to be there.

After much internal struggle about where I was/am in the world, I decided to go to the reunion, and I sought out Andrea. We reconnected and chatted. We reminisced about the past, laughed and share small-talk. Eventually, we confessed that we had crushes on each other in high school, but never acted on them.

What else could I do? I had to ask her out on a date, I just had to. There was really no option. My heart was pounding faster than the beat of the bar stereo system, and every muscle in my body was shouting that it was the right thing to do. Her response, “Here’s to finally growing a pair.”

So we went out on a few dates, and it was not long at all before we decided that we were not interested in dating anyone else. Of course we had to make things official by changing statuses on Facebook.

I am happier than I have been in a long time. Andrea is aware of my current situation, more aware about details that I am not yet comfortable sharing in a public forum, and she has not run away. She is staying by me, and she is being really supportive. Just another node in the support network that my good friend told me I needed to go find.

We have a lot in common, but we are are also really different. Seems like the perfect match. And, hey, she has a thing for geeks. :)

The Future

What’s next? I am not sure. I am working with my doctors to get to the bottom of my problem. In my spare time, I am trying to stay fit both physically and mentally. Physically, I have been riding my bike, running, and going on hikes. Mentally, I am keeping my programming skills sharp by working on cukeness, a project that I am sure to write more about in a later post.

Where am I going to end up? I am feeling a really big pull to stay in the Richmond, VA area. I really missed being here. The pace of life is so much different than it was in the Washington, DC area or the Roanoke, VA or the Blacksburg, VA area. I am glad to be back, and I think that … no scratch that … I am going to stay.

Twitter Updates for 2009-09-26

September 26th, 2009
  • A late night trip to Waffle House caused me to wake up with really bad indigestion. Let’s hope the Fruit Loops I just ate help. Any bets? #

Powered by Twitter Tools.

Twitter Updates for 2009-09-25

September 25th, 2009
  • I have a giant smile and it is @andreagoulet’s fault. :) #
  • @andreagoulet Heros was pretty good. It was a big distraction, though. I did not get much done on cukeness because of it. #
  • At InLight in Richmond with @andreagoulet. #

Powered by Twitter Tools.