Friday, June 27, 2008

What are Rails Helpers for?

I was reading Dan Mange's Smart Model, Dumb Controller post, which has a very interesting comment from Greg Willits in which he proposes an additional logic layer between Controllers and Models. He and Dan go back a forth a bit on this - check it out.

This prompted me to think about what I use Helpers for. The exchange above brought up Helpers in their canonical sense, as being a sort of glue between the Controller and the View. My colleague Jim Lindley and I certainly use Helpers in that fashion, witness


module PreceptorsHelper
def self.select_list
Preceptor.find(:all).map { |p| [p.dropdown_name, p.id] }
end
end


Pretty typical. We have a Preceptor model, and our PreceptorsHelper has a select_list method that DRYs up how all of our Preceptor-related views get their select lists for dropdown menus.

Additionally, we have a dropdown_name, which differs from the plain old name field of the Preceptor, but neither the PreceptorsHelper nor the views know about that - it's properly encapsulated within the Preceptor model itself. This is basic OO design that provides tools for managing multiple levels of complexity and abstractions to handle that complexity. No surprises so far.

However, this all led me to reflect on my own use of Helpers that may not be textbook Controller<->View glue activity. I also use Helpers for logic that pertains to a given model (or more likely a collection of those models) without being a characteristic of any one of those model instances. This sounds a bit like Greg's additional controllers idea. Here's an example from another of our helpers:


module EnrollmentsHelper
def self.filter_by_readiness(enrollments, params)
ready_for_review = params[:ready_for_review]
return enrollments unless ready_for_review
enrollments.select { |e| e.ready_for_review? }
end
end


Something akin to this could also be accomplished via named_scope nowadays, I realize. However, let's abstract a bit. This is an operation on a set of things - Enrollments in this case. We certainly don't want this in the EnrollmentsController. We could make the case that it should be a class method of Enrollment. But making it a function that takes the Enrollments as a parameter makes this much easier to test. It's also more of a functional style, which I freely cop to preferring.

I guess I don't even think about Helpers as necessarily needing to provide utility for views so much as providing utility that is "about" a given topic without being a characteristic of any one of those instances.

Note that the topic doesn't even need to be a model. Our current app has several Models presenting different types of humans, and some of our clients care about gender. Presto:


module GenderHelper

VALID_GENDERS = %w[m f M F]
VALID_OPTIONS = {
:in => VALID_GENDERS,
:allow_blank => true,
:allow_nil => true,
:message => MessageHelper::MESSAGE[:invalid_gender]
}

MALE_VARIANTS = %w[BOY MAN MALE]
FEMALE_VARIANTS = %w[GIRL WOMAN FEMALE]

def self.distill_gender!(gender)
gender.andand.upcase!
gender = %q[M] if MALE_VARIANTS.include?(gender)
gender = %q[F] if FEMALE_VARIANTS.include?(gender)
gender
end

end


(Note also the similar delegation to MessageHelper). This allows us to DRYly do something like this in our Student and similar models:


validates_inclusion_of :gender, GenderHelper::VALID_OPTIONS


Nothing view-related there.

Much of this coding style sprang from a desire to simplify controllers. After doing this, I noted many comparatively large model files. One of them, Lottery, had a lot of activity that dealt with processing collections of Enrollments, which I've blogged about before. Why not move this into something more directly related to Enrollments?, I thought.

I like the results.

What do other people think about Helpers used in this fashion? Should there be two different ypes of them: view-related and non-view-related? More? I'm still sorting out my thoughts on this, and welcome new ideas to think about (or old ideas to consider anew).

Tuesday, June 24, 2008

First-Class Procedures, Part II: passing as an argument

SICP demands that for functions to qualify as First Class Citizens,
they must satisfy several requirements. I've written about this before in reference to the first requirement: being able to assign names to procedures. The second requirements is the ability to be passed as an argument to another function, which is the topic of this post.

I'll just dive in, again showing multiples languages: Ruby, SICP's original Scheme, Erlang, and Haskell. Again, my friend Aubrey Keus has provided some JavaScript, as well.

This post is fairly Ruby-heavy. A lot of them are likely to be, as it's the language I know best among those being discussed, as well as the the one I use to earn my Yankee Dollars.

In Ruby:


$ irb

irb(main):001:0> def call_proc_arg_on_2(first_class_proc)
irb(main):002:1> first_class_proc.call 2
irb(main):003:1> end
=> nil
irb(main):004:0> add1 = lambda { |x| 1 + x }
=> #
irb(main):005:0> call_proc_arg_on_2(add1)
=> 3


Here we've defined a method that expects an argument called first_class_proc, which is (as you might expect) a Proc. add1 is such a Proc which adds 1 to its argument - hence the name. When we pass that in as the argument for call_proc_arg_on_2, we get the expected value of 3.

Proc & block syntax


Ruby has a curious subtlety in its treatment of Procs. Notice that we need to use the call method in order to make the Proc do its thing. Not true for some other languages below. Why would anyone do this when designing a language?

Below we see a more typical way of passing a procedure as an argument to a higher-order method.


irb(main):006:0> def call_block_on_2()
irb(main):007:1> yield 2
irb(main):008:1> end
=> nil
irb(main):009:0> call_block_on_2 { |x| 1 + x }
=> 3


The main differences between this and the previous example are as follows:

  1. The name of the method reflects the differences in expected arguments: a Proc vs. a block

  2. call_block_on_2 does not have a parameter in its declaration, just the empty parentheses

  3. When we call call_block_on_2, we don't pass a variable with a name (like add1), instead we just give it a block, which is the business between the {} braces. Note that this block is what we give to the lambda method to create a full-fledged Proc in the earlier example.

  4. The yield method is roughly akin to the call method, except that it automatically knows that it should operate on whatever block was given, without having to refer to it by name.



So what's the deal with this? Standard Ruby style is to call methods with blocks for operations like iteration (with each), list transformation (map) and filtering (select, partition), and so on. This is so common that the syntactic sugar of being able to easily do this outweighed the consistency of being able to call function arguments without needing the call method.

In MIT Scheme:


$ mit-scheme

1 ]=> (define call-on-2 (lambda (x) (x 2)))

;Value: call-on-2

1 ]=> (define add1 (lambda (x) (+ x 1)))

;Value: add1

1 ]=> (call-on-2 add1)

;Value: 3


Check it out. Simple procedure declarations, and procedures that can be passed as args with no special syntax. Some would say no syntax at all, both among the pro- and anti-Lisp communities. Not wishing to add to an old flame war, I'll move on.

In Erlang:


$ erl

Erlang (BEAM) emulator version 5.5.5 [source] [async-threads:0] [hipe] [kernel-poll:false]

Eshell V5.5.5 (abort with ^G)
1> Add1 = fun(X) -> 1 + X end.
#Fun
2> CallOn2 = fun(F) -> F(2) end.
#Fun
3> CallOn2(Add1).
3


I'm becoming a pretty big Erlang fan. Note that the variable Add1 is in all caps - this serves a semantic purpose in Erlang. User-defined entities in Erlang that are in lower-case are generally either straightforward functions or atoms, which are essentially just values. They're very similar to Ruby's Symbols, for example.

This Erlang example lets the coder define a function as a variable which is then usable as an argument to another function without any special syntax tricks. CallOn2 just applies the function arg F to the literal number 2 and returns the result, which is just what we want in all these examples.

In Haskell:


(I haven't written about Haskell before now. It's purely functional, strongly typed with inferencing, and offers lazy (non-strict/non-eager) evaluation. Check it out. It has several implementations - I'll show it in hugs, a REPL shell.

Assuming this file CallOnTwo.hs:

add1 = (+) 1
callOnTwo f = f 2


Executing hugs as follows:

$ hugs CallOnTwo.hs
__ __ __ __ ____ ___ _________________________________________
|| || || || || || ||__ Hugs 98: Based on the Haskell 98 standard
||___|| ||__|| ||__|| __|| Copyright (c) 1994-2005
||---|| ___|| World Wide Web: http://haskell.org/hugs
|| || Bugs: http://hackage.haskell.org/trac/hugs
|| || Version: September 2006 _________________________________________

Haskell 98 mode: Restart with command line option -98 to enable extensions

Type :? for help
Main> callOnTwo add1
3


What's going on here? The actual use of callOnTwo in the REPL example should be readable enough - it's quite similar to all of the other examples.

The lib file CallOnTwo.hs is a bit more interesting. Note the definition of add1 as (+) 1 - it leaves off the argument to add1. Rather than saying the equivalent of add1 of x is x plus one, it says (in Haskell) add1 is the function that adds one to whatever it gets.

This is what Haskell calls pointfree style. In the pointfree style, a coder leaves off terms from a definition when able. The resulting code is generally thought to be cleaner and more compact. It also lends itself well to groking function composition.

One further complication is that the + is in parentheses. This is because + is most commonly used as an infix operator, such that its arguments appear on either side, as opposed to Scheme's (+ x 1), where the function appears first (as is usual in Scheme), and the arguments follow. The wrapping in parentheses converts the traditionally infix + into a prefix function.

One could argue that this slight syntax massaging is roughly similar to Ruby's need for call, thereby angering fans of Ruby, Haskell, and Scheme simultaneously. Probably others too. Maybe F# fans. Who knows?

More Ruby:


In Ruby again, following the Object-Oriented nature of the language, we can do similar operations in which the functions are explicitly understood to be methods attached to specific objects. In this case, the Integer 1.

Assuming the existence of this file func_as_arg.rb:

class Integer
def call_symbol_arg_on_2(first_class_proc_as_sym)
2.send(first_class_proc_as_sym, self)
end
end


We can then do operations in irb again.


$ irb -r func_as_arg.rb
irb(main):001:0> 1.call_symbol_arg_on_2(:+)
=> 3
irb(main):002:0> 1.call_symbol_arg_on_2(:-)
=> 1


With the results that you'd expect.

In JavaScript:



function call_proc_arg_on_2(first_class_proc) {
return first_class_proc(2);
};

Number.prototype.call_proc_arg_on_2 = function(first_class_proc) {
return first_class_proc(this);
};

call_proc_arg_on_2(add1);
Number(100).call_proc_arg_on_2(add1);


Aubrey's JavaScript code demonstrates both the initial example common across all the languages, as well as the equivalent of my second Ruby example, in which the desired behavior is attached to existing number objects within your language's existing workspace.




I split infinitives. If such things get you riled up, I suggest you read about scientific linguistics a bit more. A good starting point is Language Myths, edited by Laurie Bauer. In this particular case, the splitting was to clarify that easily modifies the use the use of the more-common block syntax in Ruby, rather than suggesting that easily modified the strength of the outweighing. Embedding the adverb within the verb is excellent for disamgiuation of this sort. Try it - you'll like it. Trust me.

Wednesday, June 11, 2008

(Road to) Partition

I'm a big fan of Ruby's Enumerable#partition method. It's very functional, and comes in quite handy. Here's the basic deal: it takes a block and returns two Arrays. The first of which contains all elements for which the block is truthy, and the second of which contains all elements for which the block is false. Here's some code that more-or-less duplicates how it works:


module Enumerable

def my_partition(&block)
return select(&block), reject(&block)
end

end


It returns a comma-separated list, so you can pull the returned values out into two separate Arrays, use the * operator to cram them together, what have you.



Before


Here's some Rails code in its initial quick 'n dirty state. One of the models in the app is called Enrollment, and restore_previous_state! is basically an undo method for some operations on enrollments. Methods run earlier in this app either set the ready_for_review boolean flag to true, or autovivified some enrollments entirely. So this takes in some enrollments, destroys them if they were autovivified, and just marks those that it didn't create itself as unready.

I also wanted to keep track of how many changes of each type were done, for reporting purposes. Hence the += 1 counter operations. Then I spit out the results Hash at the end to know what I did. I think this version is fairly procedural for Ruby code, at least for my usual style. That's not necessarily bad, although I do prefer the changes below.


def restore_previous_state!(enrollments_to_modify)
results = { :reset => 0, :destroyed => 0 }
enrollments_to_modify.each do |e|
if e.autovivified?
e.destroy
results[:destroyed] += 1
else
e.ready_for_review = false
e.save
results[:reset] += 1
end
end
results
end



After


Here's the same method after some functionally-oriented refactorings that use the partition method.


def restore_previous_state!(enrollments_to_modify)
to_destroy, to_reset = enrollments_to_modify.partition(&:autovivified?)
to_destroy.map(&:destroy)
to_reset.map { |e| e.ready_for_review = false; e.save }
{ :reset => to_reset.size, :destroyed => to_destroy.size }
end


In the new version, I partition the enrollments based on whether or not they were autovivified, because (as we already know) my method has to behave quite differently in each case. Then I just map the destroy operation onto all the enrollments that I should destroy, and a combined unready & save for the others. Since to_destroy still exists in memory after the destroy operations (it just had its database records deleted), I can still get its size. And of course to_reset is still around, just with some readiness changes.

Presto, spit out an anonymous Hash reporting how many changes of each type, and the external behavior of the method stays entirely the same, which is as it should be for a refactoring. The new version trims some lines (14 -> 6), and I also find it more readable.




Elsewhere, the app goes even further with partition. I won't explain this in as much detail, because if you followed the stuff above, this should be fairly clear as an additional example.

One curious thing about this is that it uses a state-changing operation (save) as the partitioning condition, so it becomes a try to save, and separate based on whether or not it worked composite operation. Also, since I only need to keep counts, I immediately map the size method onto each sub-Array that comes out of partition.

My co-worker Jim calls this sort of code dense. I prefer compact. He assures me that he was just teasing me.


def save_cleanup_and_report!(post_delayed_rules_to_save, rejected_potentials)
ready_to_save, invalid_for_saving = post_delayed_rules_to_save.partition(&:valid?)
actually_saved_count, failed_save_count = ready_to_save.partition(&:save).map(&:size)
invalid_for_saving.map(&:destroy)
rejected_potentials.map { |e| e.ready_for_review = false; e.save! }
[actually_saved_count, (rejected_potentials.size + failed_save_count)]
end


I apologize for the pun in the title, of course.

Monday, June 9, 2008

I am Jesus of Borg



I don't want to pick on anyone, and I realize this doesn't speak for all of the world's approximately Billion self-identified Christians, but does anyone else find this a bit disturbing?

Tuesday, June 3, 2008

Notes from RailsConf, sort of


I just got back from RailsConf2008 in Portland, and I'm still a little jet-lagged. Lots of good stuff, especially about scaling, the deployment ecosystem, and distributed / "cloud" computing. Everyone and their brother will be talking about the presentations, so I'm going to relate a couple of anecdotes.



Predicate Truth vs. Resource Protection


When is a vegan not a vegetarian?




I'm a vegan (just reporting data - eat what you think best). They had food for us at the conference, as well as for other dietary needs. I had a nice but brief chat with a guy waiting for the Kosher food, for example. So I would go up to the little cart labelled vegan with the intention of getting food. Nothing shocking there.




The guy serving the food would then ask people who approached Are you a vegetarian?. Since the category vegetarian is a subset of the category vegan, I answered yes. He then directed me to the standard food tables, since people who are ovo-lacto vegetarians had plenty of options among the standard fare. I then pointed out that I'm also a vegan, and got some food.




This raises some interesting points - interesting to me, anyway. I told the guy that among a group of programmers, we're culturally very inclined to answer predicate questions with the literal truth: some_vegan.vegetarian? => true. He then explained that his primary goal in asking the question was not to enquire about someone else's eating habits, but to make sure they don't run out of the vegan options too early. He was basically acting as a return guard, making sure that I had enough to eat.




Another interpretation is that his question was based more on the weirdness factor. Vegetarians are weirder than omnivores, but to a lesser degree than vegans. So a vegan in that scenario would reject the boolean type signature implicit in Are you a vegetarian? and offer more information: I'm not just a vegetarian, I'm a vegan.



Who Pays for Dinner?


Sushi as a load balancing problem




When out eating dinner with my colleagues, we discussed the issue of payment. Initially, we decided on a simple hocket: one guy pays, and then the next night a different guy pays, and so on. My fellow nerds will recognize that as a Round Robin load balancer approach.




Things were fine until the fourth night. They were only three of us, so this was the first instance of a potential repeat. I had paid for very good (and very expensive) sushi meal two nights earlier, and my colleague Jim had splurged for Quizno's the previous night. Jim volunteered to shift to Fair load balancing, using how much some one had paid so far in the trip as the fairness criterion - which of course stuck him with paying for the final meal.