1. We discussed how to improve the group's resilience and scale its
organizing. We identified roles that are used to support the group:
arranging meetings (e.g., scheduling venue, soliciting content, posting
announcements), encouraging people to interact (e.g., list, meetings),
moderating/MC'ing (e.g., list, meetings), recording and posting notes,
managing resources (e.g., site, list). If you'd like to assist, drop
Igal a personal email with what you're interested in helping with and
roughly how much time you can commit a month.
2. We talked about ideas for changing or improving content of meetings.
Most present seemed satisfied, it was hard to tell what folks that
weren't there would have suggested. The mailing list, open discussions
at meetings and the after-meeting meetings help a lot by letting people
get answers and discussions on topics as they need them. A suggestion
was to setup a matchmaking system to collect topics that people wanted
to hear more about and what people wanted to present, as opposed to
having it done by mailing list discussion.
3. We listed additional meeting types to supplement regular meetings:
- If you've got an open source project you'd like to work on, we can
organize formal code sprints. For example, we really need to do some on
Calagator, but also need to find a good new place to hold these.
- The Portland Weekly Hackathon events, 7pm every Thursday at the Lucky
Lab on Hawthorne provide a fun way to chat and casually work on stuff.
TECHNICAL PRESENTATIONS AND DISCUSSIONS
1. Ian McIntosh demoed Luz, an open source Ruby-based music visualizer
- Ian's blog with many Luz related posts: http://gnomecoder.wordpress.com/
- Luz homepage and source: https://launchpad.net/luz
2. Markus Roberts presented another in his series of popular Ruby
hangman quizes. This month's mind-bender featured a frightening
implementation of the #blank? method whose implementation baffled
experienced Rubyists even after all the code had been guessed. Bravo!
3. Bryan Stearns asked for advice on versioning ActiveRecord data with
plugins. After some discussion about Bryan's need, the group agreed with
Markus Roberts suggestion that it may be best to deliberately structure
the database and objects for storing historical data to provide more
direct access, rather than piling a separate versioning system on top
that puts old data into a kind of quarantine.
4. Igal Koshevoy talked about versioning ActiveRecord data using various
plugins, for cases where one needs simple change tracking and an audit
trail. The upside is many of these are easy to work with, the downside
is that old versions of records have to be accessed through APIs or
different tables and thus are harder to get at.
- The +paper_trail+ plugin provides versioning and undelete by
serializing old records into a dedicated +versions+ table. It's
well-designed and was easy to add to calagator.org, where it versions
the Event and Venue records, and is used by a ChangesController for
viewing changes and reverting them.
- The +acts_as_versioned+ plugin was used in the past at calagator.org.
It provides less-sophisticated versioning and stores old records in a
table with an identical schema as the one storing the current data,
which is good for providing more direct access, and bad because you must
maintain two table schemas rather than one. However, it lacks an
undelete, this wasn't easy to add and this was why there was a switch to
- The +acts_as_paranoid+ and +acts_as_deletable+ plugins were briefly
investigated, but skipped because they focused on undelete and were hard
to combine with +acts_as_versioned+.
5. Ian McIntosh asked for advice about how to implement undo, such as
undoing a change to a Luz configuration that modifies many objects.
- Memento design pattern, which uses a separate object to keep track of
an object's previous state. It makes in-place state-change operations
like "sort a list" very easy to undo because you've got a copy of the
data before and after. Details: http://en.wikipedia.org/wiki/Memento_pattern
- Serialization, keep entire old objects around as a crude alternative
- Command design pattern, which uses a stack of commands that it can
step through to reverse operations and is frequently used for
multi-level undo and transactions. However, it's more complex and will
probably need to be paired with Memento to store state of complex data
structures, like arrays before sorting. Details:
6. Ian McIntosh asked for advice about garbage collection (GC),
particularly those affecting Luz because it creates and destroys many
objects. Suggestions included:
- Trying to figure out if and why GTK bindings were adding overhead to GC:
- Trying Ruby Enterprise Edition, because it includes improvements to
garbage collection and additional ways to tinker with GC settings. Ruby
Enterprise Edition homepage: http://www.rubyenterpriseedition.com/
- Trying JRuby (assuming it's possible to use the GTK bindings that Luz
needs via FFI) because it likely uses the sophisticated GC offered by
the JVM. JRuby homepage: http://jruby.org/
- Trying Rubinius (assuming it's possible to use the GTK bindings that
Luz needs via FFI) because it provides the ability to do very low-level
instrumentation for tracing and debugging. Rubinius homepage:
- Implementing application-specific manual garbage collection, which
Brian Rice suggested because it'd offer greatest control and is used
effectively in applications requiring high-performance and responsiveness.
- However, the suggestion most agreed with was that it was vital to
identify why so many objects were being created at all. It was
recommended that the shortest possible script be written that could
demonstrate the problem, which could then be used to profile, debug and
7. Tim Trautmann asked for advice on RSpec and Cucumber TDD/BDD best
practices. Suggestions included:
- TDD/BDD and pair programming are especially valuable when working on
complex, expensive algorithms where the time spent evolving a spec as
coding progresses isn't a significant concern. For example, the
algorithm for generating the OpenSourceBridge.org schedule was so
complex that three days of on-and-off attempts to implement it failed,
until Igal Koshevoy and Reid Beels finally pair programmed for three
hours to write out the spec and then managed to implement the solution
in just over an hour.
- TDD/BDD are less valuable for simpler coding, where it's often quicker
to bang out a couple hours of functionality and then write specs for all
the new stuff at once.
- Code coverage (e.g., "rake spec:rcov") is incredibly valuable in
helping to identify code without specs that needs to be written.
- Write specs that provide the most value first, and maybe skip writing
some others. The model specs are THE most valuable and must be written,
because most of the logic lives there. The controller specs are the
second most useful and are a good value to write. The view specs are
hard to justify, unless you have very complex views and you probably
shouldn't -- in general, you can get good value by writing controller
specs with integrated views instead. The routing specs are useful for
specifying complex routes.
- Integration specs, be they in Rails or Cucumber, are mostly useful for
acceptance and sanity checks, but the effort required to setup all the
state is significant and may be hard to justify. Worse still, these are
the most fragile and tricky to adapt as the code changes, which again
hurts their value. However, integration specs can catch problems in the
stack or between controllers that other specs can't, so they do have
- Cucumber, when used well, can provide clear high-level executable
English text describing high-level behavior that helps familiarize a
coder with an app's features and record a customer's requirements. These
can be useful for other coders that don't necessarily know or need to
know the details of the implementation, but want to know the
higher-level behavior of a feature.
- Cucumber's approach to having external routines implement the
specification adds indirection ... which isn't necessarily wanted. It
can be hard to write these specs and even more difficult to figure out
how they work. Worse still, there's often a lot of impedance mismatch
between the simple English description and its underlying code
implementation, because the implementation often does much more than the
description says just to setup the state. In contrast, integration and
controller specs written with a tool like RSpec keep the description and
implementation together, and thus make it easier to read these together.
- RSpec features that are worth learning:
- Execute only a certain spec file: script/spec spec/model/myspec.rb
- Execute only a spec on the given line in a file: script/spec
- Write helpers to use across multiple spec files and keep them
either in `spec/spec_helper.rb` or a file run from it.
- Make good use of the `before` calls to setup state and then many
`it` calls to describe it.
- Make good use of nesting `describe` blocks to describe behavior
specific to a context.
- Use `it_should_behave_like` calls to reuse behaviors common to
multiple `it` descriptions.
- Use tools like +autospec+, +watchr+, and +stakeout+ to
continuously run specs to monitor progress.
PS: I'll try to post the October meeting notes in the next couple days,
sorry for the delay.