Mike Dalessio's blog



Mike DalessioMike Dalessio
NYC Tech Talk: 19 Jan 2010
edit Posted by Mike Dalessio on Tuesday January 19, 2010 at 02:19PM

Pivotal NYC was lucky enough to have Ben Stein in the office to give a beta presentation entitled "Beyond the Hype: What it Really Takes to Build a Technology Business on the Cloud". Ben has built his own successful startup, Mobile Commons, using some of the principles he discussed.

Boiled down to its essence, Ben's theme was (with apologies to Chris Carter): Trust No One.

More specifically, Ben talked about ways to build your business and technology to better handle the inevitable failures of your vendors, partners and infrastructure providers.

Technical highlights from Ben's talk included a recipe for constructing a vendor-agnostic library (heretofore known as the "Stein Stack"), and actionable rules-of-thumb to make API consumers and producers more robust and debuggable.

If you're interested in attending a future Pivotal NYC Tech Talk, please subscribe to the mailing list.

Mike DalessioMike Dalessio
NYC Standup Round-up for Dec 28th - Jan 8th
edit Posted by Mike Dalessio on Monday January 11, 2010 at 11:54AM

Points of Interest

  • Following a recipe from Dan Chak's Enterprise Rails, we came across code following this pattern:

    class Thing
      def foo
        def bar(args)
          # some code        
        end
        # some code that calls bar()
      end
    end
    

    The structure of this code suggests that bar is scoped only within the context of foo. But alas, that is not the case. Ruby simply defines Thing#bar the first time foo is called, analogous to define_method :bar. Misleading syntax, for sure.

  • Ryan Davis's Flay is awesome. If you're not familiar with it, Flay parses your Ruby and compares subtrees with each other to find where code has been duplicated (or nearly so). Run on a codebase of over 20,000 lines of Ruby, Flay was able to quickly indicate places where we had duplicate code lying around, as well as many likely targets for refactoring work. We've found it to be helpful in keeping code DRY.

  • This looks interesting: MagicPrefs gives you gestures for your Magic Mouse (Yes, Pivotal NYC has Magic Mice, as well as 27" iMacs. Apply today!).

  • In Snow Leopard, mapping CapsLock => Ctrl when two keyboards are plugged in is problematic. You can do it by plugging in one keyboard at a time and mapping each one individually. If anyone knows the story behind why this is, or how to deal more easily, please comment!

  • Another interesting link: Open Frameworks is a "creative coding" toolkit (like Processing) that's implemented in C++. Why ask why?

  • Another lesson learned the hard way: starting up a bunch of leopard machines at the same time wreaks havoc on the network for a few minutes. Packet storm, dropped packets, etc. Is Bonjour to blame? Inquiring minds want to know.

  • If you're trying to stub a subclass of ActionMailer::Base with Double Ruby (also known as RR), and you're having issues, try stubbing the method on ActionMailer::Base directly. There's some weirdness there with method_missing in Rails 2.3.

Help Wanted

  • Does anyone know how to make command-1 through command-9 switch tabs inside of Term.app? By default, these keys are bound to switching windows, and we'd love to be able to do this on tabs instead.

  • Rails's select_tag(..., :multiple => true) option doesn't properly set selected on the generated options. This appears to be a boog, and anyone who's interested in helping a Pivot write a patch, please comment below!

Mike DalessioMike Dalessio
NYC Standup Roundup for Dec 14th - Dec 24th
edit Posted by Mike Dalessio on Monday December 28, 2009 at 07:17AM

Happy Holidays from NYC!

Interesting

  • Someone noticed that rspec's should_not (rdocs here) returns false when the spec passes, whereas should returns true when it passes. This has unexpected results when a should_not is used within a Webrat wait_for loop (code here) -- wait_for loops until its body returns true. Fail!
  • John Resig has implemented a jQuery.require method that should be in the next release. Check out the commit and the lengthy discussion here. Everyone's a critic.
  • One Pivotal project that recently switched from MySQL to Postgres noticed that PG sorts NULL values differently than MySQL. The default in PG is NULLS FIRST when ordering DESC, and NULLS LAST otherwise. You can override this behavior by using a NULLS FIRST or NULLS LAST clause in your ORDER BY.
  • Someone was reminded the hard way that Ruby's rescue, by default, only catches exceptions inherited from StandardError.

Help

  • Does anyone know of a service or library that will convert an email into a tracker story? The use case is stake holders who send UI/UX requirements within emails with attachments, etc.

Mike DalessioMike Dalessio
SOLID Object-Oriented Design (Sandi Metz)
edit Posted by Mike Dalessio on Saturday May 30, 2009 at 06:39PM

Sandi Metz, a Dukie visiting from NC, will be talking about SOLID principles of software development:

  • Single Responsibility
  • Open Closed
  • Liskov Substitution
  • Interface Segregation
  • Dependency Inversion

All of Sandi's code is available here.

Change

Fact: your application is going to change. How will your application handle that change?

Robert Martin says your app can behave a couple of different ways:

  • Rigid: Making a change somewhere will break something somewhere else.
  • Fragile: You can't predict where that break will be.
  • Immobile: It's hard to change your code.
  • Viscous: It's easier to do the wrong thing than to fix things.

In the beginning, though, your app was perfect. "Dependencies are killing you!"

Design might save you.

The Design Stamina Hypothesis says that, after a certain point, you'll have done better if you had designed first.

"Skip design, if you want your app to fail."

To avoid dependencies, your design should be:

  • Loosely coupled
  • Highly cohesive
  • Easily composable
  • Context independent

Ignorable Rules

SOLID principles we can ignore in ruby:

  • Interface Segregation

    Really only a problem for statically-typed, compiled languages. Because we're in Ruby, we don't have this problem! Win!

    "Dynamic languages obey this rule in the most extreme way possible: duck typing."

  • Liskov Substitution

    When you design, don't break the contract of the superclass in the subclass.

Testing Interlude

Sandi draws her examples of applicatoin change from the source code at: http://skmetz.home.mindspring.com/img28.html.

Lesson #1: Resistance is a Resource.

  • Don't be attached to your first idea
  • Embrace the friction
  • Fix the problem

If testing seems hard, examine your design. Tests depend upon the design of the code. "TDD will punish you if you don't understand design."

During refactoring, ask yourself:

  1. Is it DRY?
  2. Does it have one responsibility?
  3. Does everything in it change at the same time?
  4. Does it depend on things that change less often than it does?

The answers should all be 'yes'.

Important Rules

Sandi references her code to demonstrate when and how to mock and use dependency injection to achieve Single Responsibility, in which a class both downloads and acts upon the downloaded data.

She urges developers to do the simplest possible refactoring when extracting responsibilities from a class.

"Refactor, not because you know the abstraction, but because you want to find it."

Sandi uses a very interesting example of building a Config class which behaves differently in different Rails environments. The first version had a lot of smell, and with a combination of hash parameters, YAML file, and metaprogamming, she demonstrates how to be open for extension, but closed for modification.

Sandi explains that paying attention to your classes' dependencies is important. If a relatively static class is dependent on a class that changes more often, that's a smell! Use dependency injection to avoid Dependency Inversion.

Summary

"TDD, BDD and DRY are all good, but they are not enough."

"Design because you expect your app to succeed, and the future to come."

Sandi recommends reading:

Mike DalessioMike Dalessio
ROA with Waves (Dan Yoder)
edit Posted by Mike Dalessio on Saturday May 30, 2009 at 03:53PM

Dan Yoder is the Director of Development at ATTi R&D, and will be talking about Waves, a Ruby architectural framework for developing RESTful apps.

A Brief History

Ruby web development came of age with MVC and Rails. Later, people who didn't need a full MVC invented Sinatra and other frameworkes. Which brings us to today, and ...

Waves Introduction

Waves can do simple apps in just a few lines of code. And by using "foundations", developers can build more advanced apps with MVC-like functionality. You can build your own foundation for whatever web framework you envision (there are several for MVC and REST).

Waves supports rack::cache and JRuby. It's Actually In Production(tm)!

Web as Services

As more rich browser apps use AJAX and COMET, server-side APIs are becoming more important. This is where REST shines.

"HTTP isn't MVC, but our frameworks think in MVC."

REST and ROA

"REST" shouldn't be applied to things that are "REST-influenced" (just ask Roy). Dan likes to use "Resource-Oriented" for these situations.

HTTP-based ROA uses the existing infrastructure, and has proven scalability. HTTP defines a protocol for a distributed hash table:

  • put(key, value)
  • get(key)
  • delete(key)

Q: "What about post?" A: "Post is for 'everything else'." Some things aren't clearly RESTful, and post is the catch-all for other operations.

What's in the hash? Resources, and keys are the URIs.

What's the point? Platform-neutral distributed objects! RDF can be used to describe discoverable resources.

ROA in action: rss/atom. It's one link to a resource describing your blog. "Boom! Podcasts for free." Dan describes this as the law of "unintended consequences," in a good way.

Edge caching is another big win for HTTP-based ROA.

How Does Waves Help?

Waves makes it easier to write resourceful applications like this today. New foundations will make it even easier going forward.

You can check out Waves at http://rubywaves.com, and on their Google Group.

Mike DalessioMike Dalessio
Ruby Guide to *nix Plumbing (Eleanor McHugh)
edit Posted by Mike Dalessio on Saturday May 30, 2009 at 03:08PM

Eleanor McHugh, a physicist by training, will be talking about how to make *nix systems work naturally within the Ruby environment.

The Unix Way

Eleanor actually hates Unix, but recognizes that it's a very effective operating system for getting things done. It's DRY: build little things, build them well, don't build them twice. There's a natural marriage between agile Ruby and the Unix philosophy.

Unix provides basic services which make it a very useful OS to "muck about with":

  • virtual memory
  • process management
  • hierarchical file system
  • user permissions
  • interprocess communication

Ruby provides some "really lovely" utilities:

  • Kernel.system
  • Kernel.spawn
  • IO.popen
  • Open3.popen3

However, if you're doing a lot of IO, you end up doing a lot of select()s and keeping a lot of file descriptors open.

System Calls with Ruby DL

DL, which Ruby delivers out of the box, is a way to wrap a C library with a Ruby call. This is a nice way to access the underlying kernel system calls without relying on the Ruby IO implementations.

This is superior to Ruby's syscall, in that you can actually get results back from the function call.

Using mmap allows you to do much faster memory reads, rather than do slower file reads.

Using kqueue/epoll/inotify allows you to build evented ruby (like EventMachine, but without EventMachine).

Using pipes allows you to build efficient IPC.

The drawback is that using DL means more verbose code, and more error prone code. (Pointer math FTL!) So, for things like sockets, use the Ruby API unless you specifically need kernel-level eventing.

Multicore

The lack of real thread support in Ruby can be addressed by using multiple processes, held together with IPC (sockets, pipes, memory mapped files). This is the traditional "Unix way" for handling multiple processes.

Mike DalessioMike Dalessio
Where is Ruby Really Heading? (Gregory Brown)
edit Posted by Mike Dalessio on Saturday May 30, 2009 at 02:01PM

Gregory Brown is the creator of Ruport and Prawn, and the author of the upcoming Ruby Best Practices. He'll be talking about the various-and-sundry Ruby implementations.

Moving to 1.9

On Ruby 1.8, strings are sequences of bytes. On Ruby 1.9, strings are proper characters (not bytes!). Even if your app only speaks "American", you still need to be aware of this to handle data properly. Plus, some of the new syntax in 1.9 is not backwards compatible with 1.8.

Recommended steps for upgrading from 1.8 to 1.9:

  1. make sure you have good test coverage!
  2. make sure your test are checking the output (some end-result validation)
  3. run on 1.9
  4. hammer on your code until the tests pass
  5. decide whether to continue to support 1.8

Prawn only officially supports 1.8.6 and 1.9.1 to make life easier, but if support more versions is necessary for your project, check out ZenTest's multiruby features.

Greg recommends using conditional-execution blocks to make version-dependent code look nicer:

if RUBY_VERSION < "1.9"
 def ruby18
   yield
 end
else
 def ruby18
 end
end

Greg opines that moving to Ruby 1.9 is not a magic bullet, but has lots of advantages, so try it out!

Ruby 1.8.7

Ruby 1.8.6 is a workhorse (insert image of beat-up pickup truck). Ruby 1.9 is a Lamborghini (we think). "What the hell is 1.8.7?"

Answer: 1.8.7's patch set is largely 1.9 backports. It's a platypus!

However, this doesn't mean that code written for 1.9 will magically work on 1.8.7. Or that code written for 1.8.7 will work on 1.8.6.

What should authors be doing? Should we release for 1.8.6 or 1.8.7? Greg recommends releasing for 1.9, especially if you're writing a Ruby book (wink wink).

Peanut Gallery

Eric Hodel (maintainer of Rubygems), is planning on dropping 1.8.6 support within the next year, but continuing support for 1.8.7 and 1.9.

Writing Extensions

FFI (Foreign Function Interface) is supported "all over the place", and is an alternative to writing a C extension. FFI works across implementations (JRuby, Rubinius, and MRI).

On Windows, Greg proclaims that JRuby is the easiest way to wrap a C library. "WTF?"

Oversimplified Explanations of Ruby Variations

According to Greg. (Not all of the nuance may be captured here, since Greg was moving pretty quickly. Blame me, not him.)

  • 1.8.6 is ubiquitous, and may be slowing adoption of other, better interpreters.
  • YARV (1.9) is faster than Matz's implementation and is the only complete m17n implementation of Ruby.
  • Ruby Enterprise has a great installer!
  • JRuby is great and new, but requires C extensions to be rewritten
  • Rubinius is what created the RubySpec project and FFI, and is very innovative.
  • MacRuby is, um, Ruby for Macs.

Mike DalessioMike Dalessio
Welcome to Goruco!
edit Posted by Mike Dalessio on Saturday May 30, 2009 at 01:54PM

Good morning! Today Ben Woosley and I will be live-blogging what's going on during Goruco at Pace University.

You can check out some photos of the conference.

Mike DalessioMike Dalessio
Parallelize Your RSpec Suite
edit Posted by Mike Dalessio on Friday May 08, 2009 at 02:17PM

We all have multi-core machine these days, but most rspec suites still run in one sequential stream. Let's parallelize it!

The big hurdle here is managing multiple test databases. When multiple specs are running simultaneously, they each need to have exclusive access to the database, so that one spec's setup doesn't clobber the records of another spec's setup. We could create and manage multiple test database within our RDBMS. But I'd prefer something a little more ... ephemeral, that won't hang around after we're done, or require any manual management.

Enter SQLite's in-memory database, which is a full SQLite instance, created entirely within the invoking process's own memory footprint.

Mike DalessioMike Dalessio
Deliver Tracker Stories from Capistrano
edit Posted by Mike Dalessio on Sunday February 15, 2009 at 09:39PM

The scene: Pivotal NYC
Jeff Dean walks up to Dan Podsedly, manager of Pivotal Tracker development.

Jeff: Hey Dan, you asked what features we wanted in Tracker. How about a way to automatically mark all my "Finished" stories as "Delivered", all at once?

Dan: (with a sly smile) Well, we have an API call for it ...

Thus was born my humble capistrano task which marks all your "Finished" stories as "Delivered". Hook it into your demo deploy task and save yourself some time.

As an added bonus, if you have Paul Dix's sax-machine gem installed (it's a SAX object parser that uses nokogiri, which I co-wrote with Aaron Patterson), you'll even get a brief summary report of the delivered stories in your cap output.

The code is below (you'll need to generate a Tracker API key). Now go deliver some stories!

#
#  To use this task, simply set the following variables:
#
#    set :pivotal_tracker_project_id, PROJECT_ID
#    set :pivotal_tracker_token, TOKEN
#
#  Then, inside the task for your demo platform, add
#
#    task :demo do
#      ...
#      after :deploy, 'pivotal_tracker:deliver_stories'
#    end
#
namespace :pivotal_tracker do
  desc "deliver your project's 'finished' stories"
  task :deliver_stories do
    require 'rubygems'
    require 'activeresource'

    class Story < ActiveResource::Base
      self.site = "http://www.pivotaltracker.com/services/v2/projects/:project_id"
    end

    Story.headers['X-TrackerToken'] = pivotal_tracker_token
    puts "* delivering tracker stories ..."
    response = Story.put(:deliver_all_finished, :project_id => pivotal_tracker_project_id)

    begin
      require 'sax-machine'
      class Story
        include SAXMachine
        element :name
        element :story_type
        element :estimate
        element :description
      end
      class Stories
        include SAXMachine
        elements :story, :as => :stories, :class => Story
      end
      doc = Stories.parse(response.body)
      puts "* delivered #{doc.stories.length} stories"
      doc.stories.each do |story|
        puts "  - #{story.story_type}: #{story.name} (#{story.estimate} points)"
      end
    rescue LoadError => e
      puts "* stories delivered."
    end
  end
end