SASS Antipatterns: Scoping to a Page

This is a story about a Rails project and how its SASS became difficult to manage.

The designers were still getting used to Rails’ structure and sometimes had trouble figuring out which view was being rendered, so we added something like this to the application layout:

<body id="<%= params[:controller].gsub('/', '-') %>-<%= params[:action] %>">

When you saw id="settings-profile" you would know the server was rendering the SettingsController’s profile template, and have a rough idea of where to look to modify the output.

This worked! And once we had it we realised that we could use the #settings-profile selector to restrict styles to that one page - useful if you need to tweak something in a single situation

This was a bad idea.

Proliferation of selectors

As we added features to the application, components that were part of one page would be included in other pages as well. An element with the class avatar might start on the profile settings page, and then later be added to the rest of the settings pages.

So we would end up with something like this:

#settings-profile, #settings-contact, #settings-applications, ... {
  .avatar {
    ...
  }

  ...
}

Every page id added to the list produced n extra selectors in the generated CSS.

This bloated the CSS, but the bigger problem was that it led us straight into Internet Explorer’s 4095-rule limit. If you’re not already aware of it, it’s very puzzling to discover that IE is refusing to apply the last half of your CSS. The only fix is to reduce the number of selectors you’re using, or to split your CSS up.

Specificity wars

Now that your selectors have an id in them, CSS’ specificity rules make it difficult to override them. You can’t customize a component with a generic class selector; you either need to add !important to its properties, or make the selector more specific by adding an id - probably the page id you scoped the original selector to.

This might cause problems later on, but you can worry about that when it happens, right?

The slippery slope

Once you have some major components scoped to the page id, the logic of specificity slowly sucks in more and more of your CSS. Your styles are now organized by the pages they appear on, instead of their purpose. Most of your CSS is contained in really big and difficult-to-maintain chunks.

It’s a trap door - if you fall through, you’ll have a tough time getting back out. When you try to move things out of the page id scope, your carefully constructed mess of overrides falls apart. You’ll have to verify every page and state on the site.

Conclusion

Adding the controller and action names to the layout template was a neat trick, but led us to a bad place. Putting those names in an HTML comment would have accomplished the same thing, without giving us a hook that was so easy to misuse.

CSS is cleanest when its selectors include the absolute minimum, i.e. when components of the page do not depend on what contains them. If a component should look different when it’s on a different page, it should probably have a different class or id. Component identifiers should be specific enough that they don’t need to be scoped to a particular part of the application.

SASS made it very easy to do the wrong thing. Nobody would ever write the generated CSS by hand, it’s obviously unmaintainable. This should have been a clue.

I’m sure there are times that attaching CSS to a page-specific id is a great idea, but it’s a technique that should be used judiciously.

Learning Rust: First Impressions

For the past few weeks I’ve been learning Rust by working on the Matasano Crypto Challenges (apparently I am not unique in this).

It seems quite suited to the task. Fast, easy to write, with a simple FFI (which I’m judging based on the excellent readability of its OpenSSL bindings) and good string and vector libraries (except for the curious lack of functions for “first n elements” and “last n elements”).

For 90% of my code things flow as smoothly as they would in Ruby. Unfortunately I spend 95% of my time on that last 10%, mostly locked in combat with the compiler.

My understanding of Rust’s pointer borrowing rules is fuzzy, but I’m not always sure whether the problem is me or the compiler. For example, sometimes

do_thing2(do_thing1());

will fail to compile but

let x = do_thing1();
do_thing2(x);

will work fine. I assume that this is a compiler bugs rather than a language specification bug. Rust 0.7 should be out in the next couple of weeks, hopefully it will fix some of these quirks. Apparently the language has changed quite a bit in the few months since version 0.6 (but I had difficulty installing the git version on Arch).

Apart from these issues, I love the language. It’s like working in C with sane strings and lambdas and destructuring, and compiler errors instead of segmentation faults.

Matasano Crypto Challenges

I’m most of the way through the second set of problems. They’ve been great so far. I don’t get much chance to do this kind of algorithmic reasoning these days - it’s a lot of fun (and probably good for me, despite the insomnia it seems to have induced).

An odd thing I like about it is how haphazardly the problem descriptions seem to have been thrown together. They give enough information and enough of a primer to get you started, but there’s not enough information in their structure for you to rely on cues in the problem description itself. When I did Stripe’s Capture the Flag last year I found myself basing my approaches on the information (detailed, carefully constructed) level introductions, which felt a bit like cheating.

Overcompensating

In 1850 people said “There are real differences between men and women. That’s why women don’t need to be educated.”

In 1900 people said “There are real differences between men and women. That’s why women don’t need to vote.”

In 1950 people said “There are real differences between men and women. We don’t have women in the workplace because they don’t want to be in the workplace.”

In 1970 people said “There are real differences between men and women. Women get paid less because they’d rather spend more time with their families.” (And they’re still saying that today.)

Today people say “There are real differences between men and women. The reason there are so few women in computer science/engineering/open source is that they are naturally less suited to these occupations.”

Historically, people aiming for a society that reflects the “real differences” between men and women tend to find that they’re already there, no more effort needed. Then (after a whole lot of effort) the situation changes, and we live in a new society that supposedly reflects those real differences. Funny how that works.

“Real differences” function as a defense of the status quo. If we want real change, we need to aim for something totally unreasonable: a society in which there are no differences between men and women whatsoever. If we discover a barrier to that which remains after several decades of sustained, focussed effort - well, we can rethink things then.

One day of snow mocks everything I enjoy about cycling.

Trade your charger for a donkey (your swallow for a penguin, your greyhound for a Saint Bernard).

Replace “nimble” with “wallowing”; replace the confidence of solid ground with an anxious search for clarity.

I once welcomed the glory of sun on bare skin; now I must defend against a conspiracy of elements.

But it’s still human. I’ll be used to it in a month or two.

Overheard on 11-1-1

In a Vietnamese restaurant:

… vermiselli …

In #freenode-newyears:

<yarrack_logging> #In Memory of Hans Reiser# We will always remember and cherish you. Your acts of selflessness will be passed down from generation to generation. The lies that dishonor your name will be vanquished. You were a true patriot and a lover of all men, all races, all religions.

Yup, the world’s still a funny old place.

Ian Bushfield has posted a comparison of the U of A’s budget to Simon Fraser University’s, and some potential solutions to the university’s supposed budget problems.

One thing he points out is that provincial funding has actually been increasing as a proportion of the budget, but the money has been going to projects in the capital fund (i.e. new buildings). These are what should be affected by provincial cuts, not the general operating budget.

If the university administration cut down on expansion - and on their own exorbitant salaries - they wouldn’t need to shove students down and take their milk money.

The Great ESS Swindle

Here’s a special bonus add-on to my post on graphing the University of Alberta’s finances:

This morning I discovered (thanks to a post by Ian Bushfield) that not only are “market modifiers” (a pretty term for “massive increases”) to engineering tuition going through, the Engineering Students’ Society is endorsing them!

The usual excuses are made, and I’m perfectly willing to accept that there is nothing that the ESS could have done about this. What leverage do they have? The only possible result of negotiations was to present the Faculty’s decision as a fait accompli.

The ESS may have to accept this, but we don’t.

This is not just an issue for engineering undergrads. Grad students at the U of A have already seen other “market modifier” proposals, and at the University of Calgary, students in business, education, engineering, law and medicine are affected by similar fees.

If we can’t depend on the ESS (or other official groups) to work effectively against tuition increases, then we can’t depend on them to make sure this money is spent properly, either. We need a society for engineering students (and all students) that actually involves the students it claims to represent, and uses the power that only an angry mob can generate.

Financial Information of the University of Alberta, Graphs and Analysis

I’ve published income and expenditure graphs for 2000-2008 for all Canadian universities and colleges. Read on for background information and analysis of the University of Alberta’s graphs.

Background

In the face of provincial government budget cuts and bad investments, the University of Alberta is looking for more money. The government prevents them from raising tuition faster than inflation, so they’re planning a new $550 student fee, and “market modifiers” that will do nasty things to the tuition of students in professional programs.

So where is the money going? This is the question asked by a Maclean’s article written in January. Based on the Financial Information of Universities and Colleges (FIUC, an annual report published by the Canadian Association of University Business Officers (CAUBO)), it paints a grim picture for undergraduates across Canada. As tuition has risen over the last 20 years, the proportion of budgets allocated to instruction has dropped, while the proportion allocated to administration and research has risen.

I and other Student Worker Action Group (SWAG) members resolved to take a look at what FIUC could tell us about the U of A. Since the source databases are available from CAUBO, it was relatively simple to generate graphs for all institutions in the dataset. (See the full graphs for the University of Alberta, or continue reading for the highlights.)

Income

The proportion of total income going into the general operating budget (the fund used for instruction, libraries, student services - the things that we undergraduates care about) has dropped significantly:

Tuition has decreased as a percentage of the general operating budget, but other student fees have risen accordingly:

Apparently the University needs better investment advice:

The investment loss in 2002-03 is more than 10% of the entire budget! The university also blames investment losses for its projected deficit. Why is the university so dependent on investment?

Expenditure

Less off the general operating budget is being spent on professors, and more is being spent on benefits and non-instruction staff:

Looking at the entire budget, the university appears to be outsourcing more and more of its work; the proportion of the budget spent on externally contracted services has more than doubled:

And the actual dollar amount has quadrupled, from $13 million to $53 million.

My favorite graph is this one, produced from the FIUC data, the university’s financial reports, and projection of fee growth rates:

The university’s income from tuition has risen steadily, as has the expenditure allocated for instruction. Fair enough (but note that the tuition line does not include the hefty “market modifiers” that have been proposed).

The combined salaries of the university’s president and vice-presidents (the purple line) have more than tripled in the past decade.

The red line (and its projection) is the university’s per-student income from non-tuition student fees. (Note that this does not include fees collected for other agencies, e.g. the U-Pass or the SU health plan). Including the new $550 fee for 2010-11, non-tuition student fees will have almost quadrupled.

Conclusions

I’m no expert (and my eyes are tired and sore), so I invite you to draw your own conclusions. There may be further insights hidden in the full graphs.

It’s clear that government limitations on tuition have driven the university to seek other ways to extract money from students. The new fee is simply a particularly blatant example of this.

Students should not be treated as the university’s personal piggy bank, to be turned upside down and shaken whenever a bad investment leaves the university scrambling for cash.

These figures would be even less pleasant if they included FIUC data going back to the 80s.

What should we do about it? The march to the legislature on the 18th is a start, but I’m doubtful of the effectiveness of one-off protests. Past evidence suggests that our representatives in the Students’ Union have little power to affect university decisions on these matters. Those of us with the Student Worker Action Group are discussing ways to confront the university directly, but this can only work once we’ve built a broad base of support.

(A much lesser issue is that we should pressure our university to publish this data in consistent machine-readable forms so that this kind of analysis is easier. I have spent a ton of time on this, I hope you get something out of it.)

← older entries