Technology Musings

August 26, 2008

Project Management / How to Do Well


This slashdot discussion starts out as a specific question, but then digresses into a much more general (and very interesting) conversation about how to handle problems in companies.  The summation is:

  • it's not a problem with someone else's company that someone else needs to fix - it's a problem with our company that we need to fix.  The difference in language is essential.
  • don't just point out problems, also come up with solutions
  • make a plan for implementing the solution, and offer to lead the team yourself
  • attach a cost to what you are doing now, and a cost for implementing the solution, so that management will know why it is important
  • if you are given the tasks, report regularly on the status and how close you are to the budget and the schedule
  • possibly look for other ways to use the solution to profit the company - i.e. move the solution from a cost saver to an income generator
Another option presented - just do it yourself without getting approval.  Send someone a memo when you're done.
This was an interesting tidbit:

I also work for a biotech but we're lucky enough to have a CEO who's a computer scientist so he knew the importance of IT. As such we have a rather larger IT dept which includes a software development team.

In order to show the bossesses that proper software maintenance/creation/validation procedures are important just explain what would the FDA or some other regulatory agency do to your collective bung holes if they were to probe deeper into your practices.

Mission critical data being handled by non-validated/non-documented software is just like having untrained people working with samples in the lab, it's a big no-no.

You need paperwork that supports your claim, start with all the areas where un-validated software is used, then add to that a second section explaining the cost of poorly planned development iterations. We work using monthly iterations and when we told the people responsible for the software in the field that an iteration cost about 30 000$ just in labor costs they started paying attention and making the lists of demands count, i.e. removing the superflueous demands (ex: "it would look nicer in blue" was replaced with "The standard deviation calculation should be done with X+1, not just X.")

August 25, 2008

Amusing / How Not to Advertise Websites at Baseball Stadiums


See here.

August 25, 2008

Snippets / Rails Sorting


I always have trouble formulating exactly how sorts should work on Rails controllers that are called from sortable_element.  Therefore, I created the following method for ApplicationController which helps out a lot:

  def sort_assoc_members(assoc, ary, position_method = :position)
ary.each_index do |ary_idx|
assoc.find(ary[ary_idx]).update_attributes(position_method => (ary_idx + 1))

Then, to use it, just create a sort action like this:

def reorder
sort_assoc_members(WhateverItem, params[:whatever_list])

This makes life much easier.

August 21, 2008

Amusing / Nerd Shopping


From xkcd:


August 20, 2008

Platforms / Go Gobo!


GoboLinux is trying new things in the filesystem hierarchy department (details here)  i think this is fantastic!  Linux definitely needs to do this, plus it needs to adopt OSX's bundle concept.

It looks like there is already some work in this area, but it surely needs to be extended and accepted by the Linux community.

August 13, 2008

Snippets / TinyMCE + Prototype AJAX + RAILS


NOTE - I have no idea why the formatting here is all messed up. It should be usable anyway since the snippets are fairly small

Using TinyMCE from Ruby on Rails is sometimes a bit tricky.  We tend to assume that all HTML components work the same - they can be added and removed at will.  However, TinyMCE components have to be explicitly added and removed - and as such they can be really painful.

In addition, TinyMCE components have to be saved back to the form in order to be serialized by Prototype (which is used by Rails for remote forms - remote_form_for, link_to_remote, etc.).

Therefore, I came up with the following, which doesn't completely remove the pain, but it at least eases it somewhat.  First of all, it modifies the Prototype library slightly to trigger a tinyMCE.triggerSave(true, true) every time a form is serialized (i.e. for remote forms and links).  Now you don't have to remember to do that anymore! Next, it provides a simple RJS helper to unregister/reregister TinyMCE editors when doing Ajax page manipulation in Rails.

Anyway, here are the steps:

Step 1

Put the following code into application.js:

//Register all TinyMCE instances on the page
function register_all_tiny_mce_editors() {
mode : "textareas",
theme : "advanced",
editor_selector : "editor"
//NOTE - if you have other registration functions, put them here, too.
//Unregister all TinyMCE instances on the page
function unregister_all_tiny_mce_editors() {
tinyMCE.triggerSave(true, true);
for(editor_id in tinyMCE.editors) {
editor_elem = $(editor_id);
if(editor_elem) {
editor = tinyMCE.editors[editor_id];
//Convince Prototype to do a TriggerSave anytime it is doing form serialization
var original_form_serialize_elements = Form.serializeElements;
Form.serializeElements = function(elements, gethash) {
try {
//Copy TinyMCE values back onto the regular form elements
tinyMCE.triggerSave(true, true);                
} catch(err) {
//Don't do anything - just means TinyMCE isn't loaded
return original_form_serialize_elements(elements, gethash);

Step 2

Put the following code into your layout:

<%# Modify this to wherever you put TinyMCE %>
<%= javascript_include_tag "tiny_mce/tiny_mce.js" %>
<script type="text/javascript">
mode : "textareas",
theme : "advanced",
editor_selector : "editor"
<%# Add/modify the init statement to include any other options you want  %>
<%# Be sure to use the same code as you used above in the register_all_tiny_mce_editors() function %>

Step 3

Now, put the following in application_helper.rb:

  def tmce_update(page, &block)
page << "unregister_all_tiny_mce_editors();"
page << "register_all_tiny_mce_editors();"

Step 4

Now, in all RJS files which could cause TinyMCE textareas to appear/disappear, you can do the following:

tmce_update(page) do
#Perform RJS operations which affect TinyMCE areas here 

And now all TinyMCE areas will start behaving for you!  Note that this ONLY works with RJS-based Ajax calls - it doesn't work if you use the :update parameter, but you shouldn't be using that anyway.  Always do Ajax updates with RJS!

July 15, 2008

Project Management / Two good articles on effective subversion use


Here are two articles on subversion usage in projects.

July 07, 2008

Snippets / Scoped has_many :through


In Rails, has_many :through is an excellent way to do join tables.  For example, I can have a person, a project, and a person_project to define the people I have assigned on projects.  This would be setup as follows:

class Person < ActiveRecord::Base
has_many :person_projects
has_many :projects, :through => :person_projects
class Project < ActiveRecord::Base
has_many :person_projects
has_many :people, :through => :person_projects
class PersonProject
belongs_to :person
belongs_to :project

So, if I have a Project object called proj, I can do proj.people and get access to all the people on the project. I can also use it as a straight arra, and push individual Person objects onto proj.people, and the appropriate records in PersonProject will be created.

However, let's say that we add an additional value to PersonProject called "role".  Let's say this can be set to 'ADMIN', 'DESIGN', or 'TECH'.   Now pushing onto the proj.people array doesn't help much, because it doesn't fill out the role.  I created a snippet of code inspired by Josh Susser's solution, but which I think works a little better.  With this new code, I can rewrite the Project class (and the Person class, if I wanted) like this:

class Project < ActiveRecord::Base
has_many :person_projects
has_many :people, :through => :person_projects
scoped_has_many_through :admins, :through => :person_projects, :source => :person, :scope => { :role => "ADMIN" }
scoped_has_many_through :techs, :through => :person_projects, :source => :person, :scope => { :role => "TECH" }
scoped_has_many_through :designs, :through => :person_projects, :source => :person, :scope => { :role => "DESIGN" }

So the code to do that is as follows, although there's probably a more Rails-ish way to do this:

module ActiveRecord
class Base
def self.scoped_has_many_through(assoc, opts)
has_many_scope = opts.delete(:scope)
conditions_scope = Hash[*{|ent|
["#{opts[:through].to_s.pluralize}.#{ent[0]}", ent[1]]
opts[:conditions] ||= {}      
if opts[:conditions].is_a?(Hash)
opts[:conditions] = opts[:conditions].merge(conditions_scope)
raise "Conditions must be a hash for conditions_scope!"
has_many assoc, opts do        
#Using define_method instead of def in order to make it lexically scoped
define_method(:construct_owner_attributes) do |reflection|
atts = super(reflection)
return atts.merge(has_many_scope)

I have a few things like this.  I might package them together into a plugin sometime.  On the one hand, code snippets this small seem silly for a plugin.  On the other hand, plugins make it easily reusable, and perhaps I could batch several of them together, even if they aren't related.

July 02, 2008

Features / named_scope is really cool


Rails 2.1.0 has, among other things, one very cool feature - named scoping.

class Whatever < ActiveRecord::Base
  named_scope :active, :conditions => { :active => true }
end  #yields all active whatevers #only runs find() on active whatevers

You can even have parameters that get passed in through anonymous functions. It's a very powerful mechanism, and makes everything much more beautiful.  Learn more here.

June 18, 2008

General / Firefox 3 is Fast and Featureful


For anyone curious, the upgrade to Firefox 3 is well worth it.  I couldn't believe the speed increase, especially on image and Javascript-heavy sites.  They have done some excellent work!  In addition, they have added a lot of animations and user-interface touch-ups that just make using it a joy.  It's pretty amazing when you can add user-interface touches and still get massive performance improvements.

Bravo Firefox Team!