Feeds:
Posts
Comments

Views deserve thought

On Sundays I normally try to sit down and watch some football, but usually the computer is open and I’m watching my fantasy team lose fantastically while attempting to work between the distractions of the game. This is obviously not very productive so, on a recent Sunday, I decided to close the computer and just watch the games. I made a mistake.

I grabbed a notebook I had laying in front of me and started scribbling. I honestly don’t recall how it started, but I started jotting down some Haml and began asking myself questions like “why do I need to code the for loops?”. Haml is so far away from HTML I was wondering why not take the extra steps and make it smarter? Why couldn’t there be an attribute like :collection, that could tell Haml to repeat the contents for each item of the collection, roughly like:

%ul{:collection => users}
   %li
     = first_name

I quickly then jumped to why can’t I just do this in HTML, again, roughly like:

<ul ruby="collection: users">
  <li ruby="first_name"> User's First Name</li>
</ul>

I immediately started digging into this idea and quickly created a core list of keywords that could provide some core functionality:

  • _if: for conditional execution
  • _unless: for conditional execution
  • _collection: for looping

With this core functionality in place, I did a brief announcement and had some great conversations. Peter Cooper suggested the move from ruby to data-ruby for HTML5 compliance and then the suggestion was made to move from data-ruby to data-ruhl to protect against potential naming collisions. More great conversations followed, one thing led to another and before I knew it, RuHL was officially born.

I didn’t have huge plans for this, I just wanted to see if I could pull off Haml/Erb functionality with just the data-ruhl attribute. While I wasn’t sure where this was going, I knew I wanted to stick with this idea because I believe code in views is bad and this didn’t open the view like other template languages.

To this point, the data-ruhl attribute simply calls methods. Instance variables were initially supported, but it became clear that they promoted more code and therefore were removed. This strengthened the belief that opening up your view to code encourages bad design.

With this thought in mind, I started reviewing a bunch of views to see what would have to change. It was a lot and in order for RuHL to pull this off, the presenter pattern would have to be implemented.

This was not a comfortable change for me and I didn’t know if RuHL was a viable option at first, but I stuck to the belief that “code in views is bad” is correct. I’m pleased I did because employing the presenter pattern has resulted in very clean code. This separation of code from the view separates testing and this has been very good indeed.

Here’s where I think it really gets interesting. What if the difficulty with view testing has been due to the fact that views are coded wrong? When writing tests for controllers, it’s generally accepted that bad controller code complicates your tests and therefore makes them difficult. In order to avoid these headaches, people have learned that skinny controllers are good. Why haven’t we learned the same lesson with testing views?

Using the presenter pattern pushes logic into classes that are much easier to test and doesn’t require passing through controller methods to setup the various testing scenarios. My view tests can be simplified to check for the correct data-ruhl attributes and to do this I don’t have to render my views, I can just parse them with Nokogiri. Since these attributes call the methods that are covered in my presenter tests, I’m pretty well covered.

I’m still putting RuHL to real world tests and refining the library as use cases arise. If you’ve had the same thought over the years and don’t mind HTML, give RuHL a shot.

Agile Corporation

Regarding processes and practices, a lot of what is published or promoted in the Rails world comes from the consultant point of view. I think it’s fantastic these companies and individuals share their lessons learned and there is great value in those lessons. If you are in a Rails shop looking at these examples as templates for organizing your team please take this information as guidelines. Very good guidelines indeed, but not everything that fits for a consultancy will directly translate for your organization. It is important for your team to discover what works for you in your environment. Here’s the discovery process we went through, hopefully this will help you and your team.

Many months ago we started down the wrong road trying to do things in a rigid agile manner. Sound weird? Well it was, but we didn’t know any better at the time. We were ignoring our gut instincts hoping this agile thing would prove us wrong. After a short time, the word agile became an excuse used by some to avoid any architecture (any thought into the long term goal). In fact, the term architecture became a symbol of everything anti-agile and therefore evil. It was at this point for me that agile became an evil term and a symbol of avoidance. These were not good times.

After a couple of missed deadlines and the realization that the ‘extra’ time wasn’t producing a better product, we revolted. Now this isn’t like we had opposition during this revolt, just the opposite. We given charge of this and the revolt was against our own blind stupidity. It was embarrassing.

We then decided that nothing was sacred. From the tools we used to the processes we employ, anything could be challenged and changed.

As we were just starting down this path we had the great fortune in having Hashrocket come aboard and pair with us. With their help we delved deeper into the practices we already employed: pairing, bdd and daily scrums to name a few. We were also introduced to tools like PivotalTracker and Campfire.

Some of the practices we were doing (pre-Hashrocket) were so weak that saying we employed them was almost laughable. We got a lot of help in those areas. We also were given rules for some practices that just did not transfer to our environment. Did we expect them to? Well yes, but that was incorrect to do so. What we have done is taken the ideas as a starting point and let team define the rest.

Are we done, do we have everything ironed out and run flawlessly? Absolutely not, but our team has grown in fantastic leaps and bounds and while things will continue to evolve, here are a few of core practices we will not abandon. They are the reasons we will continue to learn and improve.

**wow that was a really long intro for a short list

Weekly Retrospective
Every Friday afternoon our dev team gets together, closes the door and talks about the week. What we should keep doing, what we should stop doing and what did we learn are all discussed. We have removed/added/altered processes, practices and tools from the result of these meetings. This is the single greatest impetus for change.

Iteration Leads
In order to spread knowledge about the different projects across the team we assign someone to the iteration lead role. This is the go to person for the iteration and is responsible for seeing it through to a successful release.

Team Board
This is simply a rolling whiteboard that we use to show the following:

  • Pairs for the iteration and what they are working on.
  • Iteration leads
  • Release dates

Daily Standups
We actually have two different sessions every morning. Since we have multiple products, the dev team breaks apart and goes to their product related standup. We then get together and have a developer only standup to relay any information. This divide and conquer technique has proven to be very efficient.

Last and not least:

Pairing
This one is a post in itself, I’ll only briefly cover pairing. Pairing is good, but like most things in the computer world doing something ALL the time usually fails. At a minimum, I think there are times when pairing should be approached differently. For example: If the pair is tasked with researching something that neither knows, I think researching the problem individually and regrouping later is a better approach. Not everyone process information the same way. More on this later, but as a basic rule: Pairing is good.

Over the past few months I have become more and more interested in what people are doing in the corporate setting. I even went so far as to create RubyTrends.com in an effort to get a picture of the entire Rails landscape, not just the consultancies. While the site is rough right now (updates are coming soon), I would appreciate you voting on the projects, books and practices you use. I think this information would be beneficial to us all.

Thanks for reading,
-stonean

I have a bunch of links I need to build on page, links that are a modification to the current path. I wanted to be able to do my modifications and return the modified path (@updated_path) without changing the original path variable (@path).

This isn’t difficult stuff, the only thing that I had to ponder on for a moment is how to get the updated path and reset it to the original state (@path.dup) in one nice little call.

This worked out nicely:


def updated_path
  @updated_path
ensure
  @updated_path = @path.dup
end

The updated_path method will return the old value and reset it afterward. Nice and simple, I like.

config.gem

When the config.gem statement was introduced I was pleased. It was great to have a centralized list of what gems were required by your application and with the rake gems:install task it would, in some cases, install the gems defined. More about that later, in another post.

After some time issues started to surface due to the lack of thought put into how to use config.gem. Here’s a list of some do’s and don’ts:

  • Use absolute version references!. This is really important when you want to roll back. If you update gems as a part of your deployment and your config.gem statement has :version => “>= 0.9″ and version “1.0″ had api changes. When you roll back, you’re still going to pick up the new version and potentially go boom!
  • Don’t put config.gem statements related to your application server. e.g. don’t put references to mongrel, passenger, etc… That’s a pain when you develop with passenger but deploy to mongrel boxes.
  • Use :lib => false, if you don’t want Rails to require the gem.
  • Do put testing related gems in your config/environments/test.rb, don’t put them in environment.rb (even if you use :lib => false, I think it’s a better practice. )
  • Don’t install the gem then add the config.gem statement. Add the config.gem statement, then use rake gems:install. This will help you find any issues before you deploy.

If you have some best practices that have saved you, I would love to hear about them!

Thanks to Hashrocket for at least one of the above. Can’t remember where each one originated.

RubyTrends.com

On Sunday I released RubyTrends.com. As I had only worked on this site for a few days, it was definitely an early release but I thought there was enough there to start gathering feedback.

There are a couple things I will add over the next couple of days: openid login and badges. OpenID login is self explanatory. Badges may not be, so here it goes. I hope that developers put a simple link to RubyTrends to get people to acknowledge they use the project. I’ll put sample code on the trend view page that links to the site. It will direct the user to login/register and then count the vote. This hasn’t been done yet, but will be soon.

The more action the site gets, the better we will be able to determine which projects people are using (based on tags). That is the goal. Just as much for me as someone new to Ruby.

So, if you have some ideas I’d love to hear them!

My company is currently working on multiple Rails sites simultaneously. This involves multiple development groups and an infrastructure team tasked with providing multiple environments (continuous integration, qa, staging and production) for each project. There are many elements required to make this happen and we are in the process of working through the kinks. This post is about one of the solutions, convention of configuration.

There are definitely some things that have been done with the current version of Rails to help us. There are definitely some things I would like to see changed in a near-future release (3.0?) of Rails that would provide a more ideal configuration solution. I’ll get to that in a bit, but let’s start off with what can be done now.

Take advantage of the environment files in RAILS_ROOT/config/environments. These should be THE place you look for your applications’ configuration. Take advantage of the fact you can provide a default setting in RAILS_ROOT/config/environment.rb and then override that setting in RAILS_ROOT/config/environments/production.rb or any environment you choose. Also take advantage of the fact you can create an environment called staging and as long as there is a corresponding RAILS_ROOT/config/environments/staging.rb, you’re good.

How do you take advantage of this? This simplest solution I’ve found is to create a file in your RAILS_ROOT/config directory that defines the configurations you need. Here is a sample file we’ll call mycompany.rb:


module MyCompany
  module Configuration
    def google
      MyCompany::Google
    end
  end

  module Google
    class << self
      attr_accessor :api_key
    end
  end
end

Rails::Configuration.send :include, MyCompany::Configuration

Then in your RAILS_ROOT/config/environment.rb add the following line after the require for ‘boot’:


require File.join(File.dirname(__FILE__), 'mycompany.rb')

This will require your file and allow you to do something very simple and expected in your Rails::Initializer block:


    config.google.api_key = 'THISISSSOMEVALIDAPIKEY'

If you create a default in environment.rb and override for other environments it will work as expected. You can later reference this through your app as MyCompany::Google.api_key.

As you need more configurations, you can expand your mycomany.rb functionality and you will have your one expected place to go for both the development and infrastructure teams.

This is good, but it’s not perfect. We can’t attempt to reach perfection with the current configuration construct provided by Rails.

What’s wrong? Well, instead of having the RAILS_ROOT/config/environments directory contain environment files, I would like them to contain environment directories. For example, RAILS_ROOT/config/environments/production/environment.rb would be ideal. This would allow applications like Capistrano to take advantage of this construct and place its environment related files in these directories. A single place to look for production related settings would rock!

In order to avoid conflicts between development environments, development and test should not be stored in your source control. Instead, give everyone a helping hand and start them out with an example (that should be in source control):
RAILS_ROOT/config/environments/development/environment.rb.example
This example should be updated as needed to provide the latest configuration examples.

Another feature wish for the RAILS team is to do away with database.yml. I think these settings belong with the rest. Think of the code duplication you could save! I could set my adapter, encoding and database in RAILS_ROOT/config/environment.rb and leave the username password and host to be overridden by my different environments.
You could start out with this:


  config.database.adapter = 'mysql'
  config.database.encoding = 'utf8'
  config.database.database = 'my_database'

Then in RAILS_ROOT/config/environments/production/environment.rb you could just


  config.database.username = 'super_secret_user'
  config.database.password = 'super_secret_pass'
  config.database.host = 'another_host'

I would like to hear what you think and if there are other conventions your team has adopted. The more we can reduce the amount of documentation required between teams and develop an expectation, the more efficient our company will be.

We are working every day to reach this goal and I will continue to share our findings in hope that they can be further refined.

Git: Branch from a tag

In git, you can’t update a tag directly, but you can branch the code to create a new tag. Here’s how you would do that:

First, you need to checkout the tag:

git checkout <tag_name> 

Then create a branch:

git branch -b <branch_name>

After you make your changes, commit them (there are a few ways to do this, keeping it simple):

git commit -am 'my descriptive comment on this commit'

You can create a new tag:

git tag <new_tag_name>

Then you can push the tag:

git push --tags

Lockdown ATLRug presentation

My first presentation ever was at the ATLRug meeting this past Wednesday.

It’s a little rough, but I’ll get better at them. Since I didn’t pay attention to where the mic was, you’ll have to turn up the volume to hear me. This is fine until the end, the applause (thankfully) is loud, so remember to turn down the volume.

Also take the time out to listen to ReinH’s ‘Ruby loves you’ presentation, it’s very good.

Lockdown 0.8.1 Released

Lockdown version 0.8.1 has been released!

The session[:access_rights] was being constructed as a nested array structure instead of a flat array structure when a permission had multiple controllers associated to it.

Thanks to Robert Rowland for finding and reporting this issue!

You can use Lockdown::System.access_rights_for_permission(:perm_name) to get the array of access rights associated to the permission.

This is handy for testing.

Older Posts »