Front-end Maintainability with Sass and Style Guides »

Created at: 20.01.2011 04:22, source: Engine Yard Blog, tagged: Uncategorized haml sass ui ux

At Engine Yard, the User Experience team works frequently on the front-end (HTML & CSS) of our application, AppCloud. It's also common that our Ruby developers write front-end code as well. When the UX team began realigning the AppCloud UI, it involved refactoring the HTML & CSS for better efficiency. We also created a style guide to document the new front-end architecture. We're sharing the methods we've used and how it's helped us to work more efficiently on the AppCloud UI.

Modular CSS

Haml and Sass are two gems that are easy to include into your Ruby on Rails application. At Engine Yard, we use both of these to maintain our front-end code. Sass variables and mix-ins are amazing resources that make managing styles much easier. This is fantastic for maintaining UI elements and adhering to brand guidelines. Within our AppCloud front-end framework we have variables we've set up for our colors based on our branding color palette. That can look something like this:
// --------------------------------------------------
// COLOR
// --------------------------------------------------
$color_border =           #ccc      // light grey
$color_background =       #f8f8f8   // lightest grey
$color_background_alt =   #cfdbe8   // light blue
$color_background_alt2 =  #e3e5cf   // light beige
$color_text =             #555      // dark grey
$color_text_alt =         #999      // medium grey
$color_text_alert =       #910f0f   // bold red
$color_text_callout =     #236DA6   // bold blue
This way, when we need to use the color for our borders, we can just call on the color variable, $color_border. If we decide to change this color, we only need to change it in one place. If we need variations on this color (like for shadows and highlights), we can use that variable combined with Sass's built-in functions:
h1 {
  border-bottom-color: darken($color_border, 10%);
}
We've used the "color_" prefix in these variable names to help avoid any clashes we might run into. It also helps provide some inline context (documentation is always a good thing). The important thing here is we keep our variable and mix-in names descriptive, but we avoid using presentational names that could change one day. By using $color_text_callout instead of $color_text_blue we don't have to change all of our variable names if we change the text from blue to red. We can use comments to help remind us of hex value colors which are located in the one place we'd make changes, if need be. Variables and mix-ins are a great way to help improve and clean up semantic HTML (if it's done right). In our last related blog post, we mentioned that we're using the 960 Grid System which uses CSS classes like “grid_1”, “prefix_9”, and “alpha”. For the semantic front-end neat-freaks out there, this can be cringe-worthy. However, if you're not already using a framework like Compass, you can simply modify the 960 Grid System, allowing you to have the best of both worlds (modular efficiency and clean, semantic HTML). You can turn all the class names within the framework into mix-ins, which will make HTML go from this:
<div id="sidebar" class="grid_1 prefix alpha">
  (content goes here)
</div>
to this:
<div id="sidebar">
  (content goes here)
</div>
That's so much better, isn't it? We can do this for other common styles like clear fixes, rounded corners, visibly hiding elements, etc. If you define your UI elements' visual design styles as variables or mix-ins, you can have a much easier time updating these styles in a consistent way.

Maintaining an Interface Style Guide

Interface Style Guides are an essential way to keep track of branding and visual design guidelines and front end architecture requirements. The key to keeping a style guide useful is that it should stay relevant and informative. However, this can be a tedious task that often gets forgotten or avoided. Online style guides are easier to maintain and distribute as opposed to printed documents. To keep our style guide relevant, it lives in our internal-only admin section on the very same application it describes. We display our color palette alongside the relevant Sass variables and since we've built the style guide into the application using the same front-end, we can use the same variables we're referencing to render this palette. When we change values to these variables, the palette updates automatically. Another benefit to adding your online style guide to your application is you get one central place to check to make sure all HTML elements are looking the way they're supposed to. If the styles are broken here, most likely they're broken elsewhere. Finally, this method allows development teams to have a reference guide so they know what code they would use to get the effect they're looking for, such as icons. We continue to evolve the AppCloud front-end through iterations; good organization and documentation is essential to make this front-end architecture work for both designers and developers on our team. What methods does your company or team use? We'd love to hear from you.


more »

Rails and Merb Merge: ORM Agnosticism (Part 5 of 6) »

Created at: 23.02.2010 20:15, source: Engine Yard Blog, tagged: Technology ActionPack ActiveModel activerecord api datamapper haml Rails 3 Railties

It’s been a little while since I’ve last posted in this series. During that time, we released Rails 3.0 beta, and announced the launch of RailsPlugins.org. Plugin authors have registered almost 150 plugins, with 40 already boasting compatibility with Rails 3. Over the next few weeks, we’re going to roll out some more features to help users find projects to help get updated, so keep an eye out.

Today I’m going to talk about the features we added to Rails 3 to provide ORM agnosticism. When we first started, the idea of such agnosticism was pretty fuzzy. As we approached the beta, we became convinced that we would shoot for the moon and give DataMapper, Sequel and other ORMs first-class access to all of the same parts of the framework that ActiveRecord had. Again, this sounds pretty fuzzy, so let me lay it out for you.

ActiveRecord is a Framework Extension

You read that right. While Rails itself ships with ActiveRecord as a default, the Railties gem, responsible for bootstrapping Rails, knows nothing about ActiveRecord. In order to achieve this, we had to make that bootstrapping process much more pluggable. While this is amazing for extensions, like DataMapper, that want to replace a built-in framework, it also exposes more functionality to any Rails extension distributed as a gem.

Rails::Railtie

In short, Railties now coordinates the initialization process, which involves the activation of a number of individual Railtie subclasses. Cute, no? Every Rails framework has its own Railtie subclass, which provides a number of useful pieces of functionality:

  • The ability to add a key (like config.active_record) to an Application’s configuration, and assign it defaults that will exist before Application configuration. For instance, a plugin could use this functionality to set a configuration key as an Array, so the Application could simply do config.action_view.view_paths << "my_path". While this isn’t exactly earth-shattering, it levels the playing field between Rails components, like ActiveRecord, and third-party extensions, like DataMapper or Haml
  • The ability to create additional generators that hook into Rails’ default generators. For instance, Rails’ scaffold generator invokes sub-generators for stylesheets, template engine, test framework, helpers, and ORM. For instance, when a user installs Haml as a gem, it can register itself as the handler for template engine generators, and provide replacements for each case where Rails provides a default implementation. In this case, Haml would replace the template engine generators provide by ActionController’s Railtie
  • The ability to supply Rake tasks to load when the user invokes the Rake command. If DataMapper supplies the same named Rake tasks as those supplied by the ActiveRecord Railtie, the user can completely remove ActiveRecord and replace it with DataMapper, retaining all of the named Rake tasks. This would allow other tasks, such as those used in testing, to automatically prepare the database and other tasks it performs by invoking tasks with certain names (like db:create)
  • Supply a log subscriber to integrate seamlessly with the uniform request logging. This allows extensions like DataMapper to add their timings into the log output. In this case, DataMapper simply replaces the “Model” timing that ActiveRecord provides, allowing a level of very tight integration with the rest of the framework
  • Specify initializers that should run at specific points in the initialization process. This allows extensions to set things up very early in the boot process, but then defer some setup until after the user has configured their application, or after specific parts of the initialization process have occurred. Each initializer also receives an instance of the Application object, giving it full access to the user’s configuration

In fact, if you take a look at ActiveRecord’s deep integration with the rest of the framework (which is roughly equivalent to its highly coupled implementation in Rails 2.3), you’ll find that it looks extremely similar to DataMapper’s equally deep integration. In fact, a major goal of the work we put into improving modularity in Rails 3 was to maintain the same level of stack integration we’ve historically had, while exposing the same toolchain for those who wanted to replace only certain elements of the stack.

The ActiveModel API

Giving DataMapper access to the same level of integration with Railties as ActiveRecord is one of two major pillars in making Rails truly ORM agnostic. The second part is decoupling Rails’ historic connection between ActiveRecord, its ORM, and ActionPack, its controller and view layer. In this area, Rails takes a holistic, very conventional approach to linking the model and the view using REST principles.

In particular, domain objects, persisted via the ORM, can have canonical URLs that are used pervasively throughout the controller and view layer. The specific URLs can be configured via the router, and Rails 3’s router is particularly powerful, but once configured, objects do have canonical URLs.

@post = Post.first
 
redirect_to @post           #=> Location: /posts/orm-agnositicism
redirect_to Post            #=> Location: /posts
 
form_for @post              #=> <form action="/posts/orm-agnosticism" method="PUT">
form_for Post.new           #=>
 
error_messages_for @post    #=> a representation of the validation errors that exist on the object
 
link_to @post.title, @post  #=> <a href="/posts/orm-agnosticism">
                            #     Rails and Merb Merge: ORM Agnosticism (Part 5 of 6)
                            #   </a>
 
posts_path                  #=> "/posts"
post_path(@post)            #=> "/posts/orm-agnosticism"
 
@posts = Post.where(:author => "wycats")
 
render @post                #=> renders "_post.html.erb", passing in @post as a local
render @posts               #=> renders a collection of "_post.html.erb", passing in each
                            #   Post instance as a local in turn
 
respond_with @post          #=> performs content negotiation between the formats
                            #   the client is willing to Accept (xml, json, html),
                            #   and the formats the @post object is willing to
                            #   provide. The available providable formats are
                            #   transparently determined by introspecting the @post
                            #   object. Additionally, if the object has not been persisted,
                            #   redirect it back to the editing page for further modification.
                            #   If it has been persisted, redirect it back to the index (or
                            #   some other appropriate path).</form>

In short, Rails 2.3 provided a fair bit of integrated functionality between ActiveRecord and ActionPack. For instance, to determine what an object’s canonical URL was, Rails called an internal .class.naming method on it, which provided the information needed to form the canonical URLs. And while other ORMs could attempt to emulate these internals, there was no guarantee that they’d be used in the same way from release to release (and, in fact, they evolved quite a bit, making them a moving target at best).

In Rails 3, we opened them up, exposing an explicit public API via ActiveModel. The ActiveModel API requires that objects respond to to_model, returning an Object that complies with the larger ActiveModel API. This allows objects that already implement methods with the same names as those required by the API to create a facade that presents itself to ActionPack as a fully compliant model.

The API itself is fairly small, with a few methods around validation, the ability to determine whether an object has persisted or not (which can be safely stubbed by objects without persistence), and a number of methods that tell ActionPack how to convert the object into a canonical URL or template name. By doing this, Rails has completely decoupled ActionPack from ActiveRecord directly, and ActiveRecord becomes just one of many ORMs to implement the ActiveModel API.

The DataMapper ORM has already released a Rails extension (called dm-rails) that implements both the Railtie functionality and ActiveModel, making it a full drop-in replacement for ActiveRecord. The Sequel ORM is also hard at work on their Railtie and ActiveModel adapter.

The really great thing about all of this is that we didn’t need to sacrifice one bit of the (some have said overly) tight integration between various parts of Rails, to provide the ability to swap in entirely different components with the same apparent “coupling” that the Rails frameworks have with each other.

As always, questions and comments are welcome!


more »

Double Shot #644 »

Created at: 09.02.2010 13:10, source: A Fresh Cup, tagged: auto_timeout aws css devise haml mapreduce rails riak ruby savon sinatra textmate

There's certainly no shortage of goings-on to link to lately.


more »

Double Shot #641 »

Created at: 04.02.2010 14:17, source: A Fresh Cup, tagged: Double Shot dterm haml localization maps os x tableau toto

Sleep seems overrated until you have to skip it for a while.

  • gMap - jQuery plugin for Google Maps. Looks way easier than the last way I've done it.
  • webtranslateit - Gem to integrate a Rails app with Web Translate It, a web service to help provide localization.
  • Why use HAML (and SASS)? I already know HTML. - Another argument in favor of switching to HAML/SASS. This is rapidly becoming the vi vs. emacs of templating languages.
  • toto - Blog engine built atop rack and aimed at heroku deployment.
  • Ubiquitous Analytics and Tableau Public - This looks nice; the Tableau data visualization app is one of the things I remember from Windows days, and now they're bringing it to the web.
  • DTerm - Popup command line for OS X.


more »