Archive

Archive for the ‘Software Engineering’ Category

BDD in Squeak Smalltalk: An exploration

April 27th, 2010 Sean DeNigris No comments

Coming from Ruby, I’m obsessed with Behavior Driven Development.  The community (e.g. Rspec, Cucumber) is alive, and there is a body of practices to follow.

Since TDD was born in Smalltalk, I expected to find the same energy and guidance in Squeak.  Squeak represents the most profound, empowering environment I’ve ever seen (I will never go back to C, C++, or even Ruby – which misses the boat by not being a living system).  However, the testing situation seems frozen in the early days.

My intention is to create do a series of experiments, which will lead to BDD best-practices in Squeak.  My vision is code that is pulled into existence by what matters to its users, that is easy to understand, and easy to change.

I’ll keep you posted…

Premature optimization – wait, I learned that 10 years ago

February 12th, 2010 Sean DeNigris No comments

In reading Refactoring: Ruby Edition, I’m “learning” a lot of things that I already know, lol.

Optimization vs. Clarity

For instance… how many times have I heard “avoid premature optimization?” Yep, check, got that one; I would never do that.  Except I do!  I mean, I won’t go out of my way to optimize at first.  But I’m in this loop, and I want to record this other information that has nothing to do with what I’m doing right now… Let me just throw it in this temporary variable to use later.

Judges (Fowler, Beck, et al.).  Buuuuzzzzzzz, wrong answer.  Their advice (and you may not believe this, but I actually feel free now that it’s sunk in): don’t optimize with that temporary variable now, just code for clarity and repeat the loop as many times as it takes to get the info you need.  ”Holy crap,” I thought.  ”I’m not going to repeat that loop three times – that’s so inefficient!”  But luckily, the authors could sense me squirming in my seat, and added that I shouldn’t worry because, although this idea frequently causes “angst” in their presentation audiences

almost all the time extra method calls won’t matter; in the rare cases they do, they can be dealt with later

This is great, Kent Beck gave me permission to repeat loops over and over if the code is cleaner!

Categories: Software Engineering Tags:

A Small but Effective Tweak to Vim’s snipMate plugin

February 6th, 2010 Sean DeNigris No comments

Already awesome

If you haven’t tried snipMate, you have to give it a test-drive.  If you want to define a new ruby class in Vim, type “cla<tab>” and you’re presented with your choice of class templates:

Enter a number, and the code is automagically generated for you.

The tweak

By default, hitting enter at the menu cancels the snippet.  However, a user can already easily cancel using escape, and this probably won’t happen all that often anyway (I don’t think ever for me).  So I altered the code to choose the first (most common) snippet if no number is entered.  This saves me a non-home-row keystroke in almost 100% of my usage.

The code

In plugin/snipMate.vim, comment out the last line of the s:ChooseSnippet function and add two lines in it’s place:

fun s:ChooseSnippet(scope, trigger)
  [snip...]
  " Original last line (which cancels on enter) commented out
  "return num == -1 ? '' : s:multi_snips[a:scope][a:trigger][num][1]

  " Two lines added to choose first snippet if none are selected
  let snip_to_return = num == -1 ? 0 : num
  return s:multi_snips[a:scope][a:trigger][snip_to_return][1]
endf

Pretty simple, huh? Oh, just remember to save a copy of the changed lines somewhere.  When you update the plugin, your changes will be erased and you’ll have to re-paste them.

Categories: Software Engineering Tags:

Autospec with custom directory/file names

January 17th, 2010 Sean DeNigris No comments

Autotest is a great time-saver when doing BDD (or TDD for the less-enlightened, lol).  Autospec seemlessly integrates Rspec.  However, if you don’t use the expected “spec/*_spec.rb” structure, autotest will not find your specs – or examples, as I call them.

It is very easy to use whatever structure you want using the following steps:

Telling Autotest to use Rspec as the test runner

The first thing you want to happen is for Autotest to use Rspec as the test runner.  This usually happens automatically using autospec, which tests for the presence of the spec directory.  Since we do not want a spec directory, we must tell explicitly tell Autotest to do this.  So:

Step 1: in your project directory create a file autotest/discover.rb with the following line:

Autotest.add_discovery { "rspec" }

Teaching Autotest about our custom directory structure

In order to do this, we have two options.  If we want to use the same structure for all our projects, we can put a file in our home directory, otherwise we can add custom files to each project directory.

Step 2: create a file .autotest with the following code:


class Autotest::Rspec < Autotest remove_method :consolidate_failures def consolidate_failures(failed) filters = new_hash_of_arrays failed.each do |spec, trace| if trace =~ /\n(\.\/)?(.*example\.rb):[\d]+:/ filters[$2] << spec end end return filters end remove_method :add_options_if_present def add_options_if_present # :nodoc: File.exist?("examples/spec.opts") ? "-O examples/spec.opts " : "" end end Autotest.add_hook(:initialize) {|at| %w{.git .svn .hg .swp .DS_Store ._* tmp}.each do |exception| at.add_exception(exception) end at.clear_mappings # take out the default (test/test*rb) at.add_mapping(%r%^(examples|third_party)/.*_example.rb$%) { |filename, _| filename } at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m| ["examples/#{m[1]}_example.rb"] } at.add_mapping(%r%^examples/(example_helper|shared/.*)\.rb$%) { at.files_matching %r%^(examples|third_party)/.*_example\.rb$% } #nil }

Let’s take it piece by piece:


def consolidate_failures(failed)
  filters = new_hash_of_arrays
  failed.each do |spec, trace|
    if trace =~ /\n(\.\/)?(.*example\.rb):[\d]+:/
      filters[$2] << spec
    end
  end
  return filters
end

This method tells Autotest which test files have failed by pulling the file names out of the test output. Since autospec looks for *_spec.rb files, it will not find our custom files. I use *_example.rb filenames, so you should replace that part of the regex with whatever you use.


def add_options_if_present # :nodoc:
    File.exist?("examples/spec.opts") ? "-O examples/spec.opts " : ""
  end

This method tells Rspec where to find an option file. Again, replace the details with whatever you use.

In Autotest.add_hook(:initialize):

  %w{.git .svn .hg .swp .DS_Store ._* tmp}.each do |exception|
    at.add_exception(exception)
  end

This tells Autotest to ignore certain files that are irrelevent to testing

at.clear_mappings

This tells Autotest not to use any other mappings i.e. the default test/test*rb, or Rspec’s spec/*_spec.rb

at.add_mapping(%r%^(examples|third_party)/.*_example.rb$%) { |filename, _|
  filename
}
at.add_mapping(%r%^lib/(.*)\.rb$%) { |_, m|
  ["examples/#{m[1]}_example.rb"]
}
at.add_mapping(%r%^examples/(example_helper|shared/.*)\.rb$%) {
  at.files_matching %r%^(examples|third_party)/.*_example\.rb$%
}

This is the meat of the customization. It tells Autospec, based on which files have changed, which tests to run. Replace my regexes with your custom matches.

The end

Once you have added both these files, running autospec from your project directory will work as it should!

Cucumber.vim

December 12th, 2009 Sean DeNigris No comments

Awesome plug-in!  Uh, ok… but what the heck does it do?!?!  Here’s a list of the goodness:

  • syntax highlighting

  • Jump to steps
    • CTRL-] opens the step definition in the current window
    • CTRL-W ] opens it in a split window (optionally hold CTRL with the ‘]’)
    • CTRL-W opens in a split preview window
  • Autocomplete – it seems from the source that it should work, but I can’t get it going.  I posted a question on the cucumber mailing list.
    Categories: Software Engineering Tags: ,

    Ruby, Vim, and Windows

    December 11th, 2009 Sean DeNigris 2 comments

    It is unbelievably easy to create a wicked setup, although I spent half a day googling to narrow it down to the exsentials:

    Downloads

    1. Ruby with the One-click installer.
    2. Vim’s self-installing Windows executable (this comes with many customizations you read about online, and ruby support, included)
    3. snipMate, a plug-in that automatically expands common Ruby constructs (e.g. you type ‘cla<tab>,’ which becomes class…end with placeholders!)
    4. AutoComplPop (must have!!!), an autocomplete plugin very much like Xcode’s – start typing and a popup list of completion options appears.  superTab, another plug-in that allows you to use tab to auto-complete Ruby code
    5. wombat, a great color scheme

    Global configurations

    Add the following settings to /path/to/vim/_vimrc.

    note: the autocomplete menu colors, and vim’s default font are disgusting, hence the changes.

    Ruby-specific Configurations

    In the vimrc above, the following is added:

    • the first line sets up superTabs to look in the right place for Ruby completions (I use AutoComplPop now, see above)
    • adds line numbers to several source code file types
    • changes the ridiculous 8-space tabs to 2

    That’s it!  Happy coding :)

    Categories: Ruby, Software Engineering Tags: , ,

    BDD in the field

    December 3rd, 2009 Sean DeNigris 2 comments

    I am on fire about Ruby.  I always hated Objective-C’s weirdness (coming from C++), and read the most awesome idea recently – given the amazing power of modern computers (now pay attention, this is the good part): writing code in anything but the highest level, easiest language is… premature optimization!!!  The instant I read that statement (sorry to the author, I can’t remember where), I knew it was true.  Add that you can drop down from Ruby to lower level languages where you need extra speed, and that MacRuby and HotCoca are going to make it ridiculously easy to use Cocoa via Ruby and…

    That’s it – I’m hooked.  To get myself up to speed in Ruby and Cocoa, I’m re-writing the examples from Aaron Hillegass’s awesome book Cocoa Programming for Mac OS X.  I’ll be writing about the intricacies of BDD in Ruby using Xcode, and I’ll be posting all the code, as well as custom file and project templates for Xcode.

    Applescripting Xcode

    November 11th, 2009 Sean DeNigris No comments

    Have you wanted to automate your Xcode workflow, but couldn’t figure out exactly how to work the AppleScript commands? Well, here’s a whole object-oriented library of handlers for ya!

    (Sorry I haven’t figured out a better way to format AppleScript code in a blog; any ideas, please let me know)

    on target_object(the_target)
        script target_obj
            property target_ref : ""
    
            to add_source_file(the_file)
                tell application "Xcode"
                    add the_file to (get compile sources phase of target_ref)
                end tell
            end add_source_file
    
            on set_header_search_paths_for_all_configurations(the_path)
                tell application "Xcode"
                    (* configuration is Debug or Release *)
                    set value of build setting "HEADER_SEARCH_PATHS" of build configurations of target_ref to the_path
                end tell
            end set_header_search_paths_for_all_configurations
    
            to add_run_script_phase(the_name, the_script)
                tell application "Xcode"
                    tell target_ref
                        return make new run script phase with properties {name:the_name, shell path:"/bin/sh", shell script:the_script}
                    end tell
                end tell
            end add_run_script_phase
        end script
    
        tell application "Xcode"
            set target_obj's target_ref to the_target
        end tell
        return target_obj
    end target_object
    
    on group_object(the_group)
        script group_obj
            property group_ref : ""
    
            to add_file(the_path, the_file_name)
                tell application "Xcode"
                    tell group_ref
                        return make new file reference with properties {full path:the_path, name:the_file_name}
                    end tell
                end tell
            end add_file
    
        end script
        set group_obj's group_ref to the_group
        return group_obj
    end group_object
    
    on active_project()
        script project_obj
            property project_ref : ""
    
            to add_group(group_name)
                tell application "Xcode"
                    tell project_ref
                        -- Get project directory
                        set project_dir to project directory
    
                        -- Create new folder for group's files
                        tell application "Finder"
                            set file_lib to load script alias "Macintosh HD:Users:sean:Library:Scripts:My Library:Files.scpt"
                            make new folder at (file_lib's posix_string_to_hfs_file(project_dir)) with properties {name:group_name}
                        end tell
    
                        -- Create new group
                        tell root group
                            return my group_object(make new group with properties {name:group_name, path type:project relative, path:group_name} at beginning)
                        end tell
                    end tell
                end tell
            end add_group
    
            to make_new_shell_tool_target(target_name)
                tell application "Xcode"
                    tell project_ref
                        set unit_test_template to target template "BSD/Shell Tool"
                        return my target_object(make new target at end of targets with data unit_test_template with properties {name:target_name})
                    end tell
                end tell
            end make_new_shell_tool_target
        end script
    
        tell application "Xcode"
            set project_obj's project_ref to project of active project document
        end tell
        return project_obj
    end active_project
    

    You can also download the scpt file here.

    And here’s a script that uses the handlers.

    Categories: Applescript, Xcode Tags: ,

    Only running unit tests in Xcode if the build was successful

    August 14th, 2009 Sean DeNigris No comments

    My workflow in Xcode is typical TDD – write a test, run the tests, write some code, run the tests…  I set up a “Run Script” build phase, so that every time I build the tests, they are automatically run.  The only problem is that the “Run Script” happens whether the build was successful or not.  So, I try to build and fail, and then the same exact tests that I already ran, automatically run again – while I sit there and wait.

    The solution turned out to be very simple.  ”Run Script” build phases in Xcode can have input files and output files.  The phase is only run if some input files were more recently modified than some output files.  Thus, if we set the input file to be the test executable, and the output files to be all the source files, then the tests will only run if the build is successful.  It will look something like this when set up:

    Conditional Run Script Phase

    Staying humble

    August 10th, 2009 Sean DeNigris No comments

    I’m sitting here reading Dave Astels’ awesome beta book The RSpec Book and I’m so impressed by the revolutionary (to me) idea to “write the code you wish you had.”  About 10 minutes later, I stumble upon a video from a class that’s been taught at MIT since 1981, in which they talk about programming by “wishful thinking.”  Yeah… the same exact concept… 28 years ago…

    Categories: Software Engineering Tags: