Jezen Thomas

Jezen Thomas

CTO & Co-Founder at Supercede. Haskell programmer. Writing about business and software engineering. Working from anywhere.

We Deserve Better Than BEM

The past decade has seen a number of CSS methodologies come and go in web development. The approach that seems to have become most widely adopted is called Block Element Modifier (BEM).

BEM aims to make user interface code more manageable by ignoring the cascading part of Cascading Style Sheets, keeping the specificity of selectors low, and avoiding naming collisions. It does this by imposing a naming convention which programmers should rigidly adhere to.

Applied BEM looks something like this:

<header class="header">
  <img class="header__logo header__logo--success" src="/slava_ukraini.jpg">
</header>

<style>
  .header {
    background: linear-gradient(-180deg, royalblue 50%, yellow 50%);
  }

  .header__logo--success {
    position: absolute;
  }
</style>

The block in this case is header. We delimit the block and the element with a couple of underscores, and appending two hyphens and some string denotes a modifier.

In practice, not only does this turn into a mess of punctuation, but this approach is also rather fragile.

There’s nothing but human discipline to stop you from accidentally mistyping a selector, or inadvertently introducing a naming collision. When the visual design of your software changes and some markup is removed, there is nothing to indicate that the associated styles are now dead code and can safely be removed.

Fundamentally, I don’t believe that relying on human discipline is a sensible way to scale a software project. We deserve better. Computers are perfectly capable of managing the relationships between components of a software system, whether that’s some markup and its associated styles and scripts, or classes and functions and the data types that flow between.

The tools are available to us. We just need to use them.

At Supercede we’re leveraging a technique which I think scales better than BEM. The technique is facilitated by Yesod which is the Haskell web framework that we use, but there’s no reason why this technique couldn’t be recreated in other frameworks.

Approaching the previous header component in Yesod would look like this1:

header :: Widget
header = do
  theId <- newIdent
  [whamlet|
    <header id="#{theId}">
      <img class="logo success" src="/slava_ukraini.jpg">
  |]
  toWidget [cassius|
    ##{theId}
      background: linear-gradient(-180deg, royalblue 50%, yellow 50%)
      .logo.success
        position: absolute
  |]

The interesting part here is the use of newIdent. This is a monadic action which will bind theId to an identifier which is guaranteed to not collide with any other identifiers on the page which are generated the same way.

This works by maintaining a counter in some request-specific internal state. At runtime when a request comes in and the application begins building up the page to serve to the user, every run of the newIdent action asks the state for the current count. The count is then incremented and stored back in the state, and the new count is used to generate a unique identifier.

Composing a couple of widgets together illustrates this effect.

myWebPage :: Widget
myWebPage = do
  theId <- newIdent
  [whamlet|
    <div id="#{theId}">
      ^{header}
      ^{footer}
  |]
  toWidget [cassius|
    ##{theId}
      margin: auto
  |]

  where

  header :: Widget
  header = do
    theId <- newIdent
    [whamlet|
      <header id="#{theId}">Some header text…
    |]
    toWidget [cassius|
      ##{theId}
        background: royalblue
    |]

  footer :: Widget
  footer = do
    theId <- newIdent
    [whamlet|
      <footer id="#{theId}">&copy; Copyright Acme Inc. 2022
    |]
    toWidget [cassius|
      ##{theId}
        background: yellow
    |]

This Haskell code generates markup and styles which look like this:

<div id="hident3">
  <header id="hident1">Some header text…</header>
  <footer id="hident2">&copy; Copyright Acme Inc. 2022</footer>
</div>

<style>
  #hident1 { background: royalblue; }
  #hident2 { background: yellow; }
  #hident3 { margin: auto; }
</style>

So, correct use of the framework ensures our IDs are unique even when they’re all composed together, and the compiler ensures we don’t mistype the names that bind the HTML elements with their associated CSS and JavaScript. The compiler also helps us clean up dead code along the way.

Ordinarily you might feel uncomfortable using a name as nondescriptive as theId, but in practice we tend to only use one unique identifier per widget. Each binding is scoped to its respective widget, and the name doesn’t appear verbatim in the generated HTML, CSS, or JavaScript.

This approach also allows us to improve the locality of the code. Associated markup, styles, and scripts can all be written in adjacent code which makes the writing process less cumbersome.

Because naming collisions are prevented by the application, we’re free to embrace specificity in CSS and just use IDs everywhere instead of limiting ourselves to classes. Relying on IDs in web development is usually avoided because they’re hard to manage manually at scale, but this pain goes away if you can delegate that management to a sufficiently sophisticated mechanism.

Widget composition is one of the unsung heroes of the Yesod framework. Given that the framework is written in Haskell, I think people are often more interested in talking about exotic-sounding ideas like zygohistomorphic prepromorphisms, but the truth is that more basic concepts make up the vast majority of web development work, so those are the areas we should be focusing on. The composition of widgets and their associated styles and scripts is exactly one of those areas.

I’ve found that the more responsibility I delegate away from humans and into the compiler, the fewer mistakes I tend to see in production. The mechanisms I’ve described here aren’t exactly new either — they’ve existed in Yesod for more than a decade. If your web framework of choice doesn’t have something like this, you should be asking yourself an important question: Why not?


  1. Actually, it’s more typical to use syntactical conveniences that Hamlet provides. The verbose version is used here so there is less unfamiliar syntax for the reader.↩︎

Static Asset Hashing in Hakyll

A problem I encountered while working on this website is that when I edit one of the CSS files and publish my changes to the Internet, there’s a good chance your browser will have cached the previous CSS files that it served you, and you won’t see the new styles that I have written.

To mitigate this, I decided to hack the compilation step in Hakyll so that my stylesheets are concatenated together, compressed, and then turned into an MD5 hash. This hash is then used as the path to the resulting file which forces the browser to download the new file whenever I update the styles.

The first step is to list the filepaths of the CSS files that should be compiled. The order in which rules are declared in CSS is important, so I prefer to list these filepaths explicitly.

-- | All CSS files which should be compiled
styleSheets :: [FilePath]
styleSheets =
  [ "css/normalize.css"
  , "css/default.css"
  , "css/syntax.css"
  ]

Next, we need to generate the MD5 hash for the compiled CSS file’s ultimate filepath. By leveraging Hakyll’s preprocess function, it’s possible to run some arbitrary IO effects during the site’s compilation step.

The approach here is to:

  1. Read the contents of each CSS file.
  2. Concatenate the CSS files into one big string with mconcat.
  3. Compress the string with Hakyll’s default compressCss function.
  4. Pack the string into a lazy bytestring, and build an MD5 digest with the md5 function.
  5. Convert the MD5 digest back into a filepath and return it.
main :: IO ()
main = hakyllWith config $ do

  compiledStylesheetPath <- preprocess $ do
    styles <- mapM readFile styleSheets
    let h = md5 $ fromStrict $ pack $ compressCss $ mconcat styles
    pure $ "css/" <> show h <> ".css"

  let cssPathCtx = constField "cssPath" compiledStylesheetPath

  -- …

The cssPathCtx binding is a convenience. It’s handy because most pages that Hakyll generates will want CSS applied, which means most pages will need to know where to find the compiled stylesheet.

Continuing on in our Rules monad, we need to add a rule that generates the file at the filepath we calculated in the preprocessing step. The route to this file is already correct, so we keep it as is with route idRoute. In the compilation step for this rule, we are again loading our list of CSS filepaths and adding them to some page context. The context here is only used in a special file that we’ll use in a moment to render all of the CSS.

main :: IO ()
main = hakyllWith config $ do

  -- …

  create [fromFilePath compiledStylesheetPath] $ do
    route idRoute
    compile $ do
      styles <- mapM (load . fromFilePath) styleSheets
      let ctx = listField "styles" pageCtx (pure styles)
      makeItem "" >>= loadAndApplyTemplate "templates/all.css" ctx

  -- …

The snippet above references a template which doesn’t exist yet. We create that file, and add a single line of Hakyll’s templating DSL to render all of the contents of each of the CSS files by iterating over the styles context we defined.

$for(styles)$$body$$endfor$

At this point, the compiled stylesheet is being generated correctly, but the site’s outermost template layer doesn’t reference it yet. Any time you load and apply the outermost template layer — in this case called templates/default.html — you’ll need to pass in the cssPathCtx bound earlier, likely monoidally joined with some other context for that template.

main :: IO ()
main = hakyllWith config $ do

  -- …

  match "index.html" $ do
    route idRoute
    compile $ do
      let ctx = cssPathCtx <> someOtherCtx
      getResourceBody
        >>= applyAsTemplate (field "posts" (const (recentPostList 3)))
        >>= loadAndApplyTemplate "templates/default.html" ctx
        >>= cleanIndexUrls

  -- …

Now that the default template knows the path to the compiled CSS file, we can update that reference.

<!DOCTYPE html>
<html>
  <head>
    <title>$title$</title>
    <link rel="stylesheet" type="text/css" href="/$cssPath$" />
  </head>
  <body>
    <!-- etc … -->

Everything works as expected when compiling the site from scratch, but a typical development workflow involves running Hakyll’s filesystem monitor to watch for changes and incrementally recompile the site. If you run the watch command from your compiled Hakyll application binary and change one of the stylesheets, the files referencing the compiled stylesheet don’t yet know that they also need to be recompiled to reflect the new stylesheet path.

Fortunately, Hakyll provides some building blocks for declaring extra dependencies in rules. Here’s the final necessary change.

main :: IO ()
main = hakyllWith config $ do

  -- …

  match "index.html" $ do
    route idRoute
    dep <- makePatternDependency "css/*"
    rulesExtraDependencies [dep] $ compile $ do
      let ctx = cssPathCtx <> someOtherCtx
      getResourceBody
        >>= applyAsTemplate (field "posts" (const (recentPostList 3)))
        >>= loadAndApplyTemplate "templates/default.html" ctx
        >>= cleanIndexUrls

  -- …

Now during local development the outermost template layer will always reference the correct compiled stylesheet.

An added benefit of this approach is the concatenation step, which results in only a single HTTP request necessary to fetch all of the styles on page load.

This approach is working nicely on this website. If there’s a neater way to do it, please let me know.

Solving a Maths Riddle with Bad Haskell

At a previous company off-site, a colleague shared a mathematical brain teaser with the team:

With the numbers 123456789, make them add up to 100. They must stay in the same order but you can use addition, subtraction, multiplication, division, brackets etc. All numbers must be used exactly once.

I’m admittedly not great at arithmetic, and I didn’t make much progress when trying to brute-force a solution in my head. Naturally I decided to reach for my big hammer: Haskell.

The first idea I had to attack this problem was to enumerate all possible expressions you would have as a result of combining the different permitted mathematical operators, slotted between each of the digits.

Whenever I need to generate all the combinations of things, I usually reach for Haskell’s list comprehensions. For example, if you wanted to generate all possible pairs of the numbers 1, 2, and 3, you might write the following list comprehension:

[ (x, y) | x <- [1..3], y <- [1..3] ]

-- evaluates to:
--   [(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]

Applying this approach to the maths riddle is essentially the same:

let ops = [ '+', '-', '/', '*' ]
 in [ [ '1', a, '2', b, '3', c, '4', d, '5', e, '6', f, '7', g, '8', h, '9' ]
      | a <- ops, b <- ops
      , c <- ops, d <- ops
      , e <- ops, f <- ops
      , g <- ops, h <- ops
      ]

Each of the digits and mathematical operators are represented as character values, because Haskell lists are homogenous — all values must be of the same type. The let binding cleans up what would otherwise be quite a bit of tedious repetition.

Evaluating this expression generates a whole bunch of mathematical expressions encoded in strings — 65,536 expressions to be exact. The expressions look like this:

[ "1*2*3*4/5-6-7*8-9"
, "1*2*3*4/5-6-7*8/9"
, "1*2*3*4/5-6-7*8*9"
, "1*2*3*4/5-6/7+8+9"
-- etc.

Now that we have a collection of expressions, we need to evaluate each of them and find those which evaluate to 100. Evaluating string values as code is something that even a decade ago in the JavaScript world would have been frowned upon. JavaScript provides the eval() function for this, but conventional wisdom states that eval() is evil, and should never be used.

I beg to differ.

But even still, eval() is just this gross hacky thing that only exists in languages like JavaScript, right? Surely you can’t do the same thing in a pure, ivory-tower language like Haskell, right?! As it turns out, you can!

If you add the hint package, you can do something like this:

import Language.Haskell.Interpreter

f = runInterpreter $ do
  setImports ["Prelude"]
  eval "3 + 5" -- evaluates to `Right "8"`

Pretty cool, if not somewhat heretical.

Essentially all that’s left to do is plug the 65,536 mathematical expression strings into the machinery that evaluates them, and filter the results to only those where the result is 100. Here’s what I came up with:

import Control.Monad (forM)
import Language.Haskell.Interpreter

expressions :: [String]
expressions =
  let ops = [ '+', '-', '/', '*' ]
   in [ [ '1', a, '2', b, '3', c, '4', d, '5', e, '6', f, '7', g, '8', h, '9' ]
        | a <- ops, b <- ops
        , c <- ops, d <- ops
        , e <- ops, f <- ops
        , g <- ops, h <- ops
        ]

result = runInterpreter $ do
  setImports ["Prelude"]
  exprs <- forM expressions evaluate
  pure $ filter (\(_, a) -> a == "100") $ fromRight [] exprs
  where
  evaluate expr = eval expr >>= \a -> pure (expr, a)

The above is an expanded version of what I originally wrote. When I was playing with this, I actually wrote it as a one-liner directly in GHCi, which is a similar experience to composing a Unix command line. Is my approach an efficient way to find the possible answers? No. Do I care enough to optimise my approach? Also no. Who said Haskell can’t do quick and dirty scripting work?

Running this produces 14 possible answers, and that’s without enumerating all those possible answers that would result from changing the order of operations with brackets. After submitting my answers, my colleague rejected my approach because I “used a program”, and “that’s cheating.”

$$ 1 + 2 + 3 + 4 + 5 + 6 + 7 + 8 * 9 $$ $$ 1 + 2 + 3 - 4 * 5 + 6 * 7 + 8 * 9 $$ $$ 1 + 2 - 3 * 4 + 5 * 6 + 7 + 8 * 9 $$ $$ 1 + 2 - 3 * 4 - 5 + 6 * 7 + 8 * 9 $$ $$ 1 + 2 * 3 + 4 * 5 - 6 + 7 + 8 * 9 $$ $$ 1 - 2 + 3 * 4 * 5 + 6 * 7 + 8 - 9 $$ $$ 1 - 2 + 3 * 4 * 5 - 6 + 7 * 8 - 9 $$ $$ 1 - 2 * 3 + 4 * 5 + 6 + 7 + 8 * 9 $$ $$ 1 - 2 * 3 - 4 + 5 * 6 + 7 + 8 * 9 $$ $$ 1 - 2 * 3 - 4 - 5 + 6 * 7 + 8 * 9 $$ $$ 1 * 2 * 3 + 4 + 5 + 6 + 7 + 8 * 9 $$ $$ 1 * 2 * 3 - 4 * 5 + 6 * 7 + 8 * 9 $$ $$ 1 * 2 * 3 * 4 + 5 + 6 + 7 * 8 + 9 $$ $$ 1 * 2 * 3 * 4 + 5 + 6 - 7 + 8 * 9 $$