Sunday, October 30, 2005

Openness

The Detroit News has the text of a speech by Delphi's CEO Steve Miller. For those of you that don't know the situation, Delphi was GM's auto parts supplying arm until it was spun off in 1999. Their US operations recently filed for bankruptcy protection.

I don't know too much about him, but I was really impressed by this speech. The best line from the speech: "As someone said, buy a Hyundai and get a satellite radio as an option. Buy a Chevy, and social welfare comes as standard equipment!"

I've always been interested in learning about what makes a good manager. This guy seems to demonstrate a few of these qualities-- especially openness. The speech has nothing that seems to be obvious BS (to me at least), he is very open about the company's problems and how they relate to bigger issues in American manufacturing. Apparently, he also replies to all of his hate email from employees.

Sapient (the company I work for) is also really really big on openness-- its one of our core values and is ingrained into a lot of the processes in the company (ex, our feedback processes, our interactions with clients, the accessibility of our leadership team). This is one of the reasons I decided to work there. I'm sure you'll hear much more from me about Sapient's culture in future posts.

I am surprised how other companies function without creating a culture of openness. For example, Mark Fields, president of Ford's Americas division recently asked its employees for ideas. Wow-- why is this news? Asking your employees for advice and ideas should be a part of EVERY company. They know their jobs best, they know what parts of their jobs are inefficient, and they know tons of little tricks that get let them get their work done a little faster.

Think of all the knowledge stored in the minds of your employees-- unlocking that and sharing it would make everyone more efficient. Just look at the success of the open source development model or of the many community-based online businesses-- no single person's knowledge (manager or programmer) can match the amount of knowledge and expertise stored in a large community.

Sounds like lots of large corporations could use a good dose of Openness. Hopefully others will follow Mr. Miller's and Mr. Field's examples and make this a part of their companies.

Thursday, October 27, 2005

Ruby Meta-Programming: Software Contracts

Update: I posted an updated version of this code sample on my projects page. The new version allows for custom contract definitions and looks a *lot* cleaner

When I was an undergrad, I spent a summer working on PLT Scheme. My project was to add software-enforced contracts to the HtDP learning languages.

Using the awesome power of Scheme's hygienic macros, I was able to let students specify their own contracts in their code, and signal runtime errors when they were violated.

Anyway, on to what this post is really about: I've been teaching myself Ruby for about a week now. It has some pretty cool meta-programming features that let you write things that give you similar functionality as a macro in Scheme or Lisp would. Moreover, Ruby (like Scheme) is dynamically typed-- in other words, if I tried to pass a string into a function that expects a number, nothing will go wrong until I try to do something to it that only numbers can do. A software contracts system for Ruby would help programmers catch these bugs early. So I was thinking about this, and I wondered: "How hard would it be to build a similar system for Ruby?"

The answer: not too hard at all. There are a few systems out there that do this already, such as the ruby-contract library, and a proof-of-concept by Andrew Hunt (of "Pragmatic Programmer" fame). Keeping with the hacker spirit, I decided to build a VERY simplified contract library as a to explore meta-programming in Ruby.

Here's my approach: I'll define a module Contracts, that when mixed into your class, would let you call a function 'contract' that takes two arguments: the name of the function the contract applies to and the type of its argument. Ideally, it would work this way:

# our testcase
require "contracts"
class TestContracts
extend Contracts
contract :hello, :number
def hello(x)
x.times { puts "hello!" }
end
end

t = Test_contracts.new
t.hello(2)
t.hello("asfsad")
# output:
# ruby test-contracts.rb
#hello!
#hello!
#test-contracts.rb:18: contract violation: argument of
#function 'hello' must be a(n) number (Contracts::ContractError)

Cool. Let's see if we can make it happen (it turns out I couldnt, exactly). Let's start with this contract function: It will rename the function given as its first argument to something else, and then define a new function that checks the contract and then calls the original function. For example, the above code would result in something like this being added to the TestContracts class:

# our goal
...
def hello(x)
if (x.kind_of?(Integer)) then
return __hello(x)
end
raise StandardError, "contract violation"
end
def __hello(x)
x.times { puts "hello!" }
end
...

The renaming aspect is simple: Ruby provides the "alias_method" function in the Module class that does this. Introducing the new bindings into the calling class can be accomplished by using the "class_eval" method from Module. All that is left is translating ":number" into the test for the if statement and generating the "hello" function's name, which is simple enough to do. Lets look at the resulting code:

#implementation 1
module Contracts
def contract(methodname, inputtype)
renamed = rename(methodname)
tester = parse_type(inputtype)
class_eval <<-endofeval
alias_method #{renamed.inspect}, #{methodname.inspect}
def #{methodname}(arg)
if #{tester}.call(arg) then
return #{renamed}(arg)
end
raise ContractError, "contract violation: argument of function '#{methodname}' must be a(n) #{inputtype}", caller
end
endofeval
end
class ContractError < StandardError
end
def parse_type(s)
case s
when :number then "proc {|x| x.kind_of?(Integer)}"
end
end
def rename(s)
("__" + s.id2name).intern
end
end

And everything works as planned: When contract is called, we compute the new name for the "hello" function and the test we need to call on the argument. Then using class_eval, we put all of the pieces togther, and produce code very similar to the "goal" code above.

A slight problem: If we run the test case exactly as above, we get the following error message:

./contracts.rb:6:in `class_eval': (eval):1:in `alias_method':
undefined method `hello' for class `Test_contracts' (NameError)
from (eval):1:in `class_eval'
from ./contracts.rb:6:in `class_eval'
from ./contracts.rb:6:in `contract'
from test-contracts.rb:6

??!?! But hello is right there! Actually, its not-- when the "contract" method is called, the definition of hello hasnt been executed yet... If we move the call to "contract" after the definition of "hello," the code works as we would like, and we are all happy. This probably isnt a big deal, but we would like to keep the contract call as close to the definition as possible, which is right BEFORE the definition, as in the test case.

Thankfully Ruby provides lots of hooks that let you do what you want when certain events are triggered. One of these hooks, "method_added" is run when a method defined in the class. So our new approach: when contract is called, we will store its arguments in a hash. When a method is added to the class, we check in this hash if it has a contract attached to it. If so, we call the old contract function. Here is my final implementation, which executes the test case as we wanted:

#final implementation
module Contracts

def contract(methodname, inputtype)
if not @definedcontracts
@definedcontracts = {}
end
@definedcontracts[methodname] = inputtype
end

def method_added(method)
input = @definedcontracts[method]
if input
@definedcontracts[method] = nil
contract_doit(method, input)
end
end

def contract_doit(methodname, inputtype)
renamed = rename(methodname)
tester = parse_type(inputtype)
class_eval <<-endofeval
alias_method #{renamed.inspect}, #{methodname.inspect}
def #{methodname}(arg)
if #{tester}.call(arg) then
return #{renamed}(arg)
end
raise ContractError, "contract violation: argument of function '#{methodname}' must be a(n) #{inputtype}", caller
end
endofeval
end
# ..... the rest is unchanged
end

Conclusion: We built a really simple contract checking library in Ruby to explore its cool meta-programming features. Ive been really impressed by Ruby so far-- its great to see these powerful meta-programming features in more mainstream languages.

Wednesday, October 26, 2005

puts 'Hello, World!'

After spending too much of my free time (and "work" time) reading blogs, I've finally decided to make my own contribution to the blogosphere.

About me:

My name is Maurice Codik. I was born and raised in the Dominican Republic, and now living in Seattle working as a software development engineer for Amazon.com's community content team. What's community content? We're the "Web 2.0" part of Amazon: my department owns customer reviews, discussion boards, lists and guides, etc. My particular team is customer media upload -- our platform allows customers to attach media to entities on the website. This is currently limited to additional images on products and a few other places, but give us some time: we're still a young team :)

Even though I'm not working for a startup, I like to think I'm an entrepreneur at heart. Everytime I read one of Paul Graham's articles, I swear it almost makes me want to quit my job and move to Palo Alto or something like that. A lot of the postings in here will be about technology & startup culture- Web 2.0, programming (especially in "non-mainstream" programming languages), software engineering, venture capital, marketing, business, etc. I'm sure there will be plenty of rants as well.

And for some context, here is a list of projects/groups I've worked on/with in the past:
Thats it for now-- stay tuned for more.