Semantic CSS grid layout with LESS

Semantic CSS grid layout with LESS

I have a confession to make. After eight years since we first met, I still don’t quite get CSS.

Sure, I can do typography, sprite backgrounds and understand the basics of the box model. I even know about browser-specific CSS extensions for CSS3 effects. But when it comes to clearing floats, vertically-aligning form elements or figuring out inline parents with block children, I go to a very dark place and start cursing.

I freely admit my CSS layout and positioning skills are lacking, and I probably shouldn’t even be blogging about it. But when I discovered CSS grid frameworks, I was naturally interested — anything that helps me get up and running quicker in a foreign language is a win.

Grid frameworks: CSS for dummies

For those that don’t know, grid frameworks like 960gs, YUI grids and Blueprint CSS provide a simple 12, 16 or 24 column grid that abstracts away complicated CSS layout and positioning rules.

For example, using the Blueprint CSS framework, this markup produces the following layout, neatly centered in the middle of the browser window:

<html><head>    <link rel="stylesheet" type="text/css" href="blueprint/screen.css" /></head><body>    <div class="container">                <div class="push-4 span-15">header</div>                <div class="push-4 span-4">menu</div>                <div class="span-7">main</div>                <div class="span-4">ad space?</div>                <div class="push-4 span-15">footer</div>    </div></body></html>

How easy was that? As a CSS newbie, not having to worry about floats, clears, negative margings and other positioning tricks is a very attractive proposition.

So CSS grids are very powerful for quickly laying out elements. But there is a trade off you should consider — HTML marked up with grids is not at all semantic. Peppering your HTML with classes like .span-12 or .yui-t3 for layout is no better than specifying table widths and heights everywhere.

Wouldn’t it be great if you could keep using these grid classes, but somehow mask them behind semantic class names?

LESS: CSS preprocessor

About the same time I discovered grids, I stumbled upon LESS: a ‘leaner’ CSS command-line preprocessor that extends CSS with its own syntax and features. The .NET port, .Less, has a smaller feature set than the rails version, but it lets you do stuff like this:

.rounded_corners {        @radius: 8px; /* variables */        -moz-border-radius: @radius;        -webkit-border-radius: @radius;        border-radius: @radius;}#header {        .rounded_corners; /* mix-ins */        img.logo { /* nested styles */                margin: (@radius * 2) + 1px; /* expressions */        }}#footer {        .rounded_corners;}

I have .Less is setup as an HttpModule in my web.config. It intercepts any requests to *.less files, translates them to real CSS, and optionally minifies (compresses) them. So you can you can simply reference the .less file directly in your markup, with no extra compilation step required:

<head>    <link rel="stylesheet" type="text/css" href="site.less" /></head>

Grid CSS frameworks + LESS = semantic grids

I’ve been using LESS for a few weeks now, and to be honest, I never want to go back to writing ‘raw’ CSS again. So what happens when you combine the CSS grid framework with LESS? Here’s the new stylesheet:

@import blueprint/screen.css;div.container {        div.header {                .push-4;                .span-15;        }        div.menu {                .push-4;                .span-4;        }        div.main {                .span-7;        }                div.ads {                .push-4;        }                div.footer {                .push-4;                .span-15;        }}

All that’s left is semantic class names using grids styles as mix-ins. Now the markup is looking acceptable again:

<html><head>    <link rel="stylesheet" type="text/css" href="site.less" /></head><body>    <div class="container">                <div class="header">header</div>                <div class="menu">menu</div>                <div class="main">main</div>                <div class="ads">ad space?</div>                <div class="footer">footer</div>    </div></body></html>

Using grid classes as mix-ins gives us the best of both worlds — you get the power of the grid CSS framework, but without introducing layout concerns to your markup.

Agile: convincing stakeholders

Agile: convincing stakeholders

Yesterday I attended BarCamp Agile Wellington, and although I had to leave early, I thought the event was a great success.

In keeping with the theme of BarCamp I thought I’d share my notes from one of the sessions: an unmoderated group discussion on Agile advocacy in large organisations, and how to convince stakeholders to adopt it.

Problems

  • Unfamiliar jargon.Terms like Agile, Scrum and Extreme Programming can be unfamiliar and scary to those who don’t understand them. What was wrong with regular programming?
  • Agile can’t guarantee certainty. A CIO’s job is to manage risk, and having watertight specifications locked down before projects commence is one way to combat it. Agile may appear riskier by leaving too much room for change, particularly in the public sector.
  • Getting the customer on team. Heavy time commitments and taking a burden of responsibility for the project’s success may not be attractive to customers.
  • Agile is not about playing cowboys or cutting corners. Agile is actually more disciplined than traditional waterfall-style frameworks.

Solutions

  • Hold the jargon, please. Don’t mention Agile, Scrums, Extreme Programming, or the Agile Manifesto by name. They aren’t really that important anyway. Perhaps ‘Agile: Everything but the name’ would be a good mantra to adopt?
  • Agile produces a self-managing team. With greater involvement from team members and customers, the traditional project manager role becomes redundant.
  • Lock it down. Sell a fixed timeframe with a fixed budget, but leave the scope open. Focus on the overall end result of the project rather than individual requirements. This way the size of your project box will be limited, but the blocks that fill it can be swapped and rearranged as you go.
  • Sell it inside out, from the bottom up. Instead of trying to convince CIOs about Agile (who more-likely-than-not will see any change as risk), focus on the people who will actually use it. Change and new ideas are interesting to developers, but scream risk to stakeholders.
  • Don’t tell upper management. Do they even need to be aware about Agile before it can be used? Do they even know what current frameworks their organisations use? Trying to convince them on the benefits of Agile may be a complete waste of time. Sell them on completion of a successful project instead.
  • Just get on with it. Why bother convincing people about Agile at all? The evidence is there, so just get on with it!

Implementing access control in a tiered application

Implementing access control in a tiered application

Recently I have been working on a reasonably-large ERP system that supports around 2,000 users. The system has approximately forty access control groups to which individual users can belong. Each of these groups grants or restricts access to parts of the system. For example, a user may be allowed to edit the price of a product if they are in the SalesManagers group. If they are in the InventoryManagers group, they can edit the number of items in stock. If they are in the Admins group they can do everything.

public class User{        // A list of groups the user belongs to.        public List<string> MembershipGroups { get; };         // ... etc}

To handle all these access groups and their associated rules, a form page’s load method contained several screenfulls of business logic to determine which elements should be editable by the user and which should not.

Here’s a simple example of what it might look like on an EditProduct page:

public class EditProductPage : Page{        // Form elements.        private TextBox ProductName;        private TextBox Price;        private TextBox NumberInStock;         public void InitializeForm()        {                if (CurrentUser.MembershipGroups.Contains("Admins"))                {                        // Admins can change anything.                        ProductName.Enabled = true;                        Price.Enabled = true;                        NumberInStock.Enabled = true;                }                else if (CurrentUser.MembershipGroups.Contains("SalesManagers"))                {                        // SalesManagers can change the product's price.                        ProductName.Enabled = false;                        Price.Enabled = true;                        NumberInStock.Enabled = false;                }                else if (CurrentUser.MembershipGroups.Contains("InventoryManagers"))                {                        // InventoryManagers can change the inventory levels.                        ProductName.Enabled = false;                        Price.Enabled = false;                        NumberInStock.Enabled = true;                }                else                {                        // Regular users can't do anything.                        ProductName.Enabled = false;                        Price.Enabled = false;                        NumberInStock.Enabled = false;                }                 // ... other complex business logic        }}

Now this is all good and well, but what happens if someone is a member of SalesManagers and InventoryManagers? Or if we add rules related to editing certain types of products? What happens if we need to make another form? This code will grow exponentially and start to spaghetti out of control.

I believe there are two fundamental problems with this design. Firstly, it is not clear what the different access groups mean in the context of the form. For example, if you’re a member of the InventoryManagers group, which fields should be editable and which should be locked? These rules are probably defined clearly in a requirements document somewhere, but are difficult to understand from reading the source code.

The second problem is that these rules are implemented at each point they are consumed, i.e. in the presentation layer. Each form is free to access and interpret what each group means. This logic clearly don’t belong here: a form page should only know how to hide and show elements! On the other hand, it seems this responsibility doesn’t lies exclusively with the business layer either, as it relates to form-specific elements. So where should it go?

In a well-designed application, the relationship between group membership and access privileges would not be exposed to the UI. Instead, we should define a list of easily-understood permission flags that have direct meaning to consumers of our model. Each of these flags will explicitly define what a user can and cannot do. They must be as simple to understand as possible.

public class AccessPermissions{        // Correct: these flags can be applied directly to a form.        public bool CanEditName { get; };        public bool CanEditPrice { get; };        public bool CanEditNumberInStock { get; };         // Incorrect: this flag is too vague.        bool IsAdmin { get; };}

We can then add these permissions to our User class:

public class User{        // A list of groups the user belongs to.        public List<string> MembershipGroups { get; };         // The user's access permissions.        public AccessPermissions Permissions { get; };         // ... etc}

Setting these flags may involve complex and conditional business logic, which is now removed from the presentation layer. These simplified flags can then be directly used by the form’s Supervising Controller:

public class ProductEditFormController : ISupervisingController         // The passive view for the current form.        private IEditFormView Form;         // Set up form state.        public void InitializeForm()        {                AccessPermissions permissions = CurrentUser.Permissions;                 if (permissions.CanEditName)                        Form.ProductName.Editable = true;                 if (permissions.CanEditPrice)                        Form.Price.Editable = true;                 if (permissions.CanEditNumberInStock)                        Form.NumberInStock.Editable = true;                 // ... etc        }}

Privileges should be separated amongst multiple classes, specific to different areas of functionality. For example, you might provide a UserPermissions class for a user management form:

// Permissions related to user management.public class UserPermissions{        bool CanEditName;        bool CanEditMembershipGroups;        bool CanDeleteUser;}

By removing access level-related logic from the point of consumption and declaring them as explicit, immediately-usable flags, we can make it much easier for developers to consistently apply access control. Removing potentially complex business logic from the presentation layer cuts down on code duplication (and bugs). The overall quality of the system improves.