Why use HAML (and SASS)? I already know HTML.
http://chart.apis.google.com/chart?chs=200x200&cht=p&chd=t:10,20,40,30
The title of the post is more-or-less a verbatim quote from a coworker, as well as from an unrelated colleague of mine from a previous job. I was asked that question and, to be honest, I was a little thrown both times. I didn’t actually know why I use HAML. I guess I’d never really considered it much after I started doing everything with it. It just seemed better and more fun.
So I spent all last night thinking about the answer. Why use HAML? For that matter, why use SASS either? It’s notable, I guess, that yesterday Chris Eppstein was polling his twitter followers on whether they wanted to break SASS and HAML apart to be separate gems … clearly others out there are using one but not the other.
And I suppose it’s not enough to answer that I use HAML and SASS because other luminaries in the Ruby world swear by it. As my Mom was fond of saying, “If all the other kids jumped off a cliff…” So I guess that’s not entirely a valid reason.
So, here’s my attempt to coalesce my various reasons for using HAML (and SASS) into a single post, and to try and convince you why I think it’s a great idea. And to throw a bone to Eppstein, I’ll try to make a case for why, though I have no problem with them being split into separate gems, I still believe they should always go together, just like peanut butter and grape jam.
SIMPLER, SHORTER, LESS WORK
So this is the obvious one. Check out the two chunks of code below:
ERB (525 characters; 24 lines)
<% if @users.empty? %>
<div class="empty_collection">
<em>Could not find any users.</em>
</div>
<% else %>
<table class="users_list">
<thead>
<tr>
<th>Name</th>
<th>Email</th>
<th>Age</th>
</tr>
</thead>
<tbody>
<% @users.each do |user| %>
<tr class="<%= cycle('odd','even') %>">
<td><%= user.name %></td>
<td><%= user.email %></td>
<td><%= user.age %></td>
</tr>
<% end %>
</tbody>
</table>
<% end %>
HAML (331 characters; 16 lines)
- if @users.empty?
.empty_collection
%em Could not find any users
- else
%table.users_list
%thead
%tr
%th Name
%th Email
%th Age
%tbody
- @users.each do |user|
%tr{:class => cycle('odd','even')}
%td= user.name
%td= user.email
%td= user.age
Just in terms of key presses, you’re hitting the keys 37% less in this case if you use HAML. In terms of lines of code, you’re getting a 33% reduction. (Hell, Wordpress doesn’t even need to display a scrollbar for the HAML example). I don’t know about you, but to me that’s a significant win right there. Every second I spend typing monotonous stuff is a second I didn’t spend building a feature. And when you’re writing hundreds of lines of code in a day, that can add up to a lot of extra time to either drink beer or add extra polish to the feature you’re implementing.
COGNITIVE DISSONANCE BETWEEN HTML AND CSS
That’s just a fancy way of saying “my brain has to switch gears too much or too drastically, reducing its efficiency.” Anyone who has done significant amounts of HTML and CSS can tell you that the constant back-and-forth between the stylesheets and the html templates becomes something of a rhythm, a development pulse of sorts. But with that rhythm comes delay and context shifts.
In HTML, I type:
<div class="highlight">
this is some stuff
</div>
In CSS, to style this, I type:
.highlight {
border: 1px solid #f00 }
For those of us well-versed in modern web development, that shift isn’t tough, but it’s still a shift.
Using HAML:
.highlight
this is some stuff
That alone improves the contextual parity some, even if you don’t use SASS and just use straight CSS. You type “.highlight” to make the div. You type “.highlight” to style it. Simple.
If you use SASS, it gets even better:
.highlight
border: 1px solid #f00
Now, you don’t even have to worry about the curlies (which don’t exist in HTML, causing cognitive dissonance). In fact, the “code” in both the HAML and SASS templates is nearly identical in structure. The only difference is that in the former, you provide the data to display, and in the latter, you provide the presentation styling for that data. If you buy the whole concept behind “separation of concerns” (and you should!), this makes life clean and satisfying.
LOWER BARRIER TO REFACTORING
If you’ve spent as much time as I have looking at someone else’s legacy code in massive enterprise apps, you know how painful it can be to jump in at first. What the hell does this construct even do? Why did they implement this? Why did someone write 6 lines of code that duplicate a function that Ruby/PHP/Java/whatever already has? What are all these non-standard method calls and where do the actual methods live?
This path of fiery hoops must be jumped through before you can really get down to a level of comfort with the code. And you need that comfort to reach your full development speed when implementing or refactoring in that part of the app. The faster you can get there, the sooner you’ll be able to demonstrate your value to the team and to the product.
The bane of my existence has been so-called “cowboy coders,” those individuals who feel it necessary to hack together fast, poorly-considered implementations in order to move on to the next thing and prove to their superiors how “awesome” they are, because they can knock out 10 new features a day. Nice. Good for you, buddy. But you’re costing me, and your team, and therefore yourself, even more time in the long run, with your mistakes, poor architecture that becomes “too big to remove” (hmm…where have I heard that before?), and a product that becomes shackled to the cowboy, who is the only one who understands the parts of the app they wrote. And God forbid if they ever leave the team…
HAML/SASS provide a buffer against the cowboy.
Forcing Harassing Coercing your teammates to use HAML (and SASS) reduces the cognitive complexity of the presentation layer (aka the ‘view’ for you MVC folk), both in terms of number of lines and characters your brain has to process, and in terms of its immediate understandability. And that makes you faster, and your team faster, and your teammates faster. Faster means more features with more polish sooner in the release cycle, with less bugs. And the reduced complexity has the additional benefit of helping to prevent future bugs, because it’s more obvious what’s going on in a particular template. Think of it as the programming equivalent of Scotchgard sprayed on your templates; it might not prevent every stain, but it helps you get the carpet clean quicker.
Sure, the cowboy might still plow through poorly thought-out code (that’s a problem for another day), but at least now it’s easier to understand WHAT he’s doing with 200 lines of business logic jammed into the view. And it’s easier to see why it should be refactored immediately!
ENCOURAGING BEST PRACTICES
At the risk of igniting some holy war about what actually constitutes best practices in the various spheres of HTML, CSS, Ruby, Rails, etc, I think it’s worth discussing the concept of “best practices.” I think adopting Best Practices has gotten a bad rap in the eyes of some developers, especially those for whom learning the latest and greatest tech in the community seems like “following a fad.” Sometimes, the latest and greatest is actually better, because people in the community are actively thinking about better ways to do the things we do every day. Don’t dismiss it out of hand because you’re defending your little island of knowledge. Any time you hear yourself saying, “I already know how to do this. Why should I learn something else?” … stop! Pause and consider your own motivations. There’s a chance you’re dismissing the new tech because you feel threatened by it. Embrace change, people! Embrace new ideas! Try new things! It will make you (A) more educated in your field and (B) more marketable, which gets you (C) better pay and more responsibility. This is a much better and more-fulfilling path to job security than defending your turf and digging in your heels while the programming community moves on past you.
So, that said, I think HAML provides a major advantage here, as well. It’s established best practice that presentation templates (whether in Rails, or Django, or home-brew MVC-based architectures) should not contain business logic or even much in the way of presentational logic. HAML does a great job of gently encouraging you to avoid this problem:
This bit of ruby code is straightforward in HAML and, I would argue, reasonable in the view:
- @users.each do |user|
But in ERB, you’ll sometimes see things like this:
<%
@users.each do |user|
full_name = user.first_name + ' ' + user.last_name
savings = sprintf("%.2f", user.savings)
if savings == 0.0
savings = false
savings_row_class = 'red'
end
%>
While you could do all that in HAML, the inability to break stuff across multiple lines without starting a new hyphen-fronted line makes it feel icky somehow. So then it gently encourages you to break up that code into the model and/or helper methods, where it should have been in the first place.
I’m not saying that HAML and SASS are silver bullets that make you or your teammates code better, but it sure helps. And when someone you know starts bitching about not being able to break a HAML ruby line into multiple lines, you’re probably safe in assuming that they are on the path to doing something Naughty™
CONCLUSION
So there you have it. There are many other reasons to use HAML and SASS that I’m sure I didn’t cover here. The “fun-ness” of it, the beauty of the syntax, the ability to have it render templates in different formatting modes depending on production or development environments, etc. But hopefully this gives you some food for thought on why I use it, and why maybe you should give it a look (or a second look, maybe?)