Showing posts with label rails. Show all posts
Showing posts with label rails. Show all posts

Thursday, March 26, 2009

Constant Hashes w/defaults in Ruby

Hi there. I'm back after a long hiatus. Since my last post, I've moved across the country from Buffalo, NY to Berkeley, CA, had 2 jobs, and become a father. So I ask your forgiveness for the long period between posts.

On to some code. I like to use Constants in Ruby whenever feasible. It's a logical and readable-to-the-next-coder way to store information in a way that indicates it should not change. It also gets some compile-time optimization for speed, and takes up less memory as a datum shared across the various instances of a class.

I'm particularly fond of constant Hashes for small lookup tables. Let's imagine some generic Rails controller with this code snippet:

BANAL_MESSAGE_FOR = {
:edit => 'You are editing.',
:show => 'You are viewing a single instance.'
}


Hashes in Ruby have a handy method called default= that sets what the default looked-up value should be when the key for the lookup is not found in the Hash. (You can think of the default default as nil, if that makes any sense.) However, default= returns the default value, rather than the new Hash. So this gets problematic:


BANAL_MESSAGE_FOR = {
:edit => 'You are editing.',
:show => 'You are viewing a single instance.'
}.default = "I don't know what you're doing".


The example above will break, as BANAL_MESSAGE_FOR is no longer a Hash at all.


BANAL_MESSAGE_FOR = {
:edit => 'You are editing.',
:show => 'You are viewing a single instance.'
}
BANAL_MESSAGE_FOR.default = "I don't know what you're doing".


The example above will lead to compile-time warnings about modifying a Constant.

What alternatives exists for this issue?



I've grown fond of the following approach:

BANAL_MESSAGE_FOR = lambda do
message_for = {
:edit => 'You are editing.',
:show => 'You are viewing a single instance.'
}
message_for.default = "I don't know what you're doing".
message_for
end.call


This allows us to define the particular cases with explicit Hash pairs, set a default value, and keep everything in Constant world. Depending on the particulars, we could instead go with either a class variable (@@banal_message_for) or a class method.

I still like constant-from-a-lambda, though - even despite the somewhat off-putting complexity of the lambda/call syntax. It makes it clear that we're dealing with constant data, and the complexity from the call syntax seems less egregious to me than having an additional method whose only purpose is to be called once at app start.

What do you think?

Wednesday, September 17, 2008

Boston, San Francisco and SDD

My colleague Jim Lindley and I will be going to Boston for a few days for our employer. We do TDD/BDD with RSpec and Rails currently, and the folks in the Boston office are at some point along a similar continuum. We'll show them what we do, they'll show us what they do, we'll learn and grow and laugh and share and love, etc. Then I'm off to San Francisco for some interviews related to my planned relocation out there.

Yesterday, I came across a blog post by Paul Barry about SDD with Rails. The two upcoming trips already had me thinking about my workflow, and Jim and I had been talking about trying move another abstraction step up from our current speccing practice, and SDD seems like a good match for our next project. It's a rewrite of an existing app that is currently in a different language - our job would be to match it feature-for-feature and also to make some necessary changes and additions.

SDD seems like a good way to keep the QA folks who already know how the app should work more involved in the the speccing process in a way that actually has impact. That's the beauty of having the human-readable descriptions be executable.

Paul also links to Bryan Helmkamp's talk on SDD at GoRuCo2008, which is very good. I would encourage anyone to read Paul's post and watch Bryan's talk.

Monday, July 28, 2008

Mea Culpa re: Typing

I was going through some Rails code today, making sure that I had good coverage and writing or modifying whatever specs as needed. I found this code:


module DisplayHelper
# snip ...
EMPTY_STRING = %q[]
# snip ...
def should_see_edit_link?(options)
return EMPTY_STRING if options[:new_record]
return false unless (memoized_user = options[:user])
# more stuff with memoized_user ...
end
end


Do you see the problem? The first line within should_see_edit_link? should be


return false if options[:new_record]


My initial version was not a proper predicate, in that it did not restrict its returned values to only true or false. Bad coder. For what it's worth, the methods that use should_see_edit_link? themselves return EMPTY_STRING if should_see_edit_link? is truthy. Alas, not a good enough excuse.

This is exactly the sort of error that advocates of static typing mention as support for their preferred type system. The most experience I have with bondage & discipline typing is with Haskell, where I find it takes its proper place as part of a cohesive whole for understanding Haskell's approach to currying, implicit typing, the pointfree style, and so on. All of that is great, I just haven't found that static typing reduces the error rate in my code. In fact, it gets in my way more often than anything else. Maybe that's why I'm getting more into Erlang rather than Haskell. All of this is probably inseparable from the fact that I got into coding with dynamic languages.

The type error that prompted this blog post is atypical for me. I'm not claiming to write completely bug-free code, it's just that my errors tend not be the sort that can be caught by a static type checker. In fact, the only errors of this sort that I can remember making are this individual error and some others in Perl related to composite data structures being coerced into scalar context. The latter were more indicative of Perl's idiosyncratic (and in my opinion, failed) experiement with context than with dynamic typing as it's generally implemented outside of Perl. So I'm not sure that they count.

How about anyone else? Has static typing ever really saved your butt dramatically?

Caveat: Please don't interpret this post as going anywhere near addressing static typing as it relates to hardware optimizations during compile time. I'm just taking about human errors resembling the example.

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 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.

Tuesday, April 22, 2008

5 Rails Tips

If you're not already watching Ryan Bates' screencasts at Railscasts.com, I strongly recommend it. They're really quite well done and interesting. He's running a contest, in which participants suggest 5 Rails tips. For my examples, I've decided to focus on areas that are either informed by ideas from functional programming (which this blog is ostensibly about), or areas in which Ryan and I have different approaches (or both). Here are my tips:


Use Module methods


Here's where I disagree with something Ryan said in his 101st Railscast, in which he suggests using Class (or instance) methods with variables over using Module methods. I prefer to use Module methods. Here's a typical (truncated) example:


module DisplayHelper

def self.get_stylesheets_by_request(request)
user_agent = request ? request.user_agent : nil
self.get_stylesheets_by_ua(user_agent)
end

def self.get_stylesheets_by_ua(some_user_agent)
return STYLESHEETS_FOR[:palm] if some_user_agent =~ %r[Palm]
STYLESHEETS_FOR[:normal]
end

end


Then, in the RSpec file:


describe %q[get_stylesheets_by_request] do
mobile = %w[mobile]
it %Q(should add the stylesheet #{mobile} for Palm browsers) do
user_agent = %q[Some Palm User Agent]
request = mock_model(Object, :user_agent => user_agent)
DisplayHelper.get_stylesheets_by_request(request).should == mobile
end
normal_browser = %w[normal_browser]
it %Q(should add the stylesheet #{normal_browser} for all other browsers) do
user_agent = %q[Some User Agent]
request = mock_model(Object, :user_agent => user_agent)
DisplayHelper.get_stylesheets_by_request(request).should == normal_browser
end
end


As I said above, Ryan and I have different preferences regarding Class vs. Module. I like having helper methods that are testable in a more "purely functional" paradigm, wherein we mock a request, but don't need to mess around within the base controller object or the like. We just pass our mock request model into the get_stylesheets_by_request method and take it from there. Either approach works, you may find that one or the other matches your own thought process more closely.


Use Constants


In the code example above, notice the use of the STYLESHEETS_FOR Constant, which we can define as follows:


STYLESHEETS_FOR = {
:normal => %w[normal_browser],
:palm => %w[mobile]
}


It gives us access to either normal_browser.css or mobile.css, as appropriate. This is a somewhat contrived example, but you could use whatever list of stylesheets you want for the values in each pair, expanding to customize for Safari, Epiphany, Opera, etc.

This technique could be used for any data that is unlikely to change in the course of an app running, but is not tied specifically enough to a given model to be stored in the DB. This allows you to avoid continually reconstructing never-changing local variables inside a method call. Some more realistic examples appear again in the MessageHelper tip below.


Return guards can simplify flow control


I loath if - elseif - else - end flow control, and strongly prefer return guards. It's a personal bigotry that I freely admit, because I think return guards make code more readable, shorter, and more in line with how I think. Here's a rewrite of Ryan's star_type method from Railscast #101 that uses return guards rather than an if block.


def star_type(value)
return 'full' if value > 1
return 'half' if value == 1
'empty'
end


You save 4 lines, and also comply with my enraged, semi-coherent rantings. You can also get some additional shrinkage with a ternary. Here's star_type again, with a ternary:


def star_type(value)
return 'full' if value > 1
value == 1 ? 'half' : 'empty'
end


You save a line. I find it more readable than the if block. That may be because I like reading Haskell code. Who knows. Again, your flow control preference mileage (or kilometrage) may vary.


DRY up your messages in a MessageHelper


I like to create a MessageHelper.rb file that contains my messages. I usually have several Constant Hashes that vary depending on the purposes of the message.


module MessageHelper

DESCRIPTION_OF_RESOURCE = {
:name_of_resource => %q[My description...]
}

EXPLAIN = {
:not_empowered_to_delete => lambda { |type| %Q[You are not empowered to delete a #{type}.] }
}

ERROR = {
:overlapping_blocks => %q[Overlapping blocks of time]
}

MESSAGE = {
:confirm_short => %q[Are you sure?],
:confirm_long => lambda { |x| %Q[Are you sure you want to destroy this #{x}?] },
:logout_successful => %q[You have been logged out.]
}

TITLE = {
:new => lambda { |x| %Q[Make a new #{x}] },
:owner => lambda { |x| %Q[Owner of #{x}] },
:show => lambda { |x| %Q[Show #{x}] },
}

end


These are obviously truncated. I use DESCRIPTION_OF_RESOURCE and EXPLAIN for hover explanations and the like. Notice also that the EXPLAIN and MESSAGE[:confirm_long] values are Procs, allowing you to reuse them abstractly. The purpose of the ERROR, MESSAGE and TITLE hashes should be obvious from their names.1 The main benefit of this practice is that you can conform to DRY principles, while also separating your messages logically according to what they'll be needed for.

Of course, you can wrap the use of each of these hashes inside helper methods, like explain, message, or what have you.

1(Maybe the purpose of TITLE isn't obvious: It's to facilitate link differentiation with <a> titles as per http://www.w3.org/TR/WCAG10-HTML-TECHS/#link-text.)


Use parallel (pattern-matching) assignments


Whenever assigning into multiple variables, it can often be helpful to do simultaneous parallel assignments using pattern matching. Here's an example from an RSpec file. I have a resource called Preceptor which has many Rotations, and a helper method called create_preceptor_and_rotations that does what you (hopefully) expect:


@preceptor, @preceptor_rotations = create_preceptor_and_rotations
@preceptor, discard__rotations = create_preceptor_and_rotations


In the first case, I want to use both @preceptor and @preceptor_rotations for some purpose. In the 2nd case, I want to keep the @preceptor, but the name of the rotations variable informs anyone reading the code that I don't care about the rotations in this particular spec instance. In both cases, I've done assignments into two variables simultaneously.

This sort of pattern is common in situations like this:


def some_method_that_takes_a_list(*args)
head, *tail = *args
# do some operations, maybe something recursive
return [head, tail]
end

Which returns as follows:

some_method_that_takes_a_list(7) -> [7, []]
some_method_that_takes_a_list(7, 8) -> [7, [8]]
some_method_that_takes_a_list(7, 8, 9) -> [7, [8, 9]]
some_method_that_takes_a_list([7, 8, 9]) -> [[7, 8, 9], []]
some_method_that_takes_a_list(*[7, 8, 9]) -> [7, [8, 9]]





So there's my list. These are all obviously fairly subjective points, but I find that these approaches work well for me, and my co-workers seem pretty agreeable to them. Maybe they'll work for you, too.