Category: Webdev


Go like defer functionality in Python

Go has a nice keyword defer, which is used to defer the execution of some code until the surrounding function returns. It is useful for registering cleanup work to be done before the function returns. The prototypical example is closing a file handle:

package main

import (
  "os"
)

func main() {
  // Open a file   
  file, err := os.Open("test.txt")
  // I'm leaving out error handling and other stuff you would have in reality.

  // Lots of code here

  // Close the file handle when done
  file.Close()
}

You must remember to close the file handle when done with it, which means calling file.Close() when you return from the function. That can be tricky if there you write a lot of code in between opening the file and closing it. There can also be multiple early returns, and you need to remember to close the file in each. Even worse, the function could panic, and then you would still wish to close the file.

As a solution to this Go offer the defer statement. defer essentially tells Go to run some code when the function returns, no matter how it returns, even if it is a panic. So, you would instead do something like this:

package main

import (
  "os"
)

func main() {
  // Open a file   
  file, err := os.Open("test.txt")
  defer file.Close()
  // I'm leaving out error handling and other stuff you would have in reality.

  // Lots of code here
}

Here Go will defer running file.Close() until the function returns. This is one of the niceties I really like about Go. It lets me schedule cleanup at the same time as I create the mess, and whatever happens later it will be taken care of.

Sadly, in my DayJob, I don't program in Go, but in Python, and that left me feeling bereft of defer. Python has the with construct, which sort of does this, but it is not as neat once you have a lot of file handles and stuff to clean up. I set out to whip up a replacement in Python. Using it looks like this:

@defer
def main(defer):
  file = open('test.txt')
  defer(lambda: file.close())

I am using a decorator defer to inject a defer function as an argument into the python function. I then pass the function a lambda with the code I want to write on return. I need the lambda in order to delay running the code, otherwise the file.close() would run immediately. This is not as slick as the Go version, but I can't add language built-ins.

The implementation of defer is the following:

from functools import wraps

def defer(func):
  @wraps(func)
  def func_wrapper(*args, **kwargs):
    deferred = []
    defer = lambda f: deferred.append(f)
    try:
      return func(*args, defer=defer, **kwargs)
    finally:
      deferred.reverse()
      for f in deferred:
        f()
  return func_wrapper

Aside from the standard boilerplate for creating a python decorator the implementation is straight forward. I create a deferred list to store all the lambdas that are deferred. I then create a defer lambda that just appends whatever it receives to the deferred list. I pass the defer lambda to the function so that the function can use it to add things to the deferred list. Finally, after the function has run I reverse the order of deferred list do that things are cleaned up in reverse order they were created. Lastly, it’s just looping through all the deferred lambdas stored in deferred and running them.

I use try/finally so that the cleanup is run even if the function raises and exception instead of returning normally.

React mounting performance differences

I've been creating tables in React+Redux in a simple and functional way. I've never really bothered with the performance since it’s been mounting fast enough when there are only a few rows. But I recently was putting together a table of people which could be up to 1000+ rows, and that was enough to cause me to stop and think about performance implications. I had a hunch I could change how I construct the rows for some clear performance wins. That called for some quick benchmarking.

Let me setup a benchmark case: There is a redux store with 2000 people in it that needs to be displayed in a table. Something like this:

{
  data: {
    people_ids: [1, 2, ...],
    people: {
      1: {
        id: 1,
        firstName: 'Some 1',
        lastName: 'One 1',
        team: 'Team 1',
        group: 'Group'
      },
      2: {
        id: 2,
        firstName: 'Some 2',
        lastName: 'One 2',
        team: 'Team 2',
        group: 'Group'
      },
      ...
    }
  }
}

Each table row should display name, team and group, and when you click a row it navigates to a page showing that person. The way I would normally construct it is like this:

// TableV1.js
import React, { Component } from 'react';
import {connect} from 'react-redux';

import TableRowV1 from './TableRow';

function mapStateToProps(state) {
  const ids = state.data.people_ids;
  return {ids};
}

class Table extends Component {
  render() {
    const {ids} = this.props;
    return <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Team</th>
          <th>Group</th>
        </tr>
      </thead>
      <tbody>
        {ids.map(id => <TableRow key={id} id={id} />)}
      </tbody>
    </table>;
  }
}

export default connect(mapStateToProps)(Table);
// TableRowV1.js

import React, {Component} from 'react';
import {connect} from 'react-redux';
import {push} from 'react-router-redux';

function mapStateToProps(state, ownProps) {
  const person = state.data.people[ownProps.id];
  return {person};
}

class TableRow extends Component {
  navigate = () => {
    this.props.dispatch(push(`/person/${this.props.person.id}`));
  }
  render() {
    const {person} = this.props;
    return <tr onClick={this.navigate}>
      <td>{person.firstName} {person.lastName}</td>
      <td>{person.team}</td>
      <td>{person.group}</td>
    </tr>;
  }
}

export default connect(mapStateToProps)(TableRow);

Assume some wrapper component that sets up Redux, React Router, and React Router Redux. Basic idea is that there is a Table.js component that gets the ids from the store, creates the table and table header, and finally maps over the ids to create a TableRow for each one. The TableRow.js component in turn uses the id that is passed to it to get the person from the store, and then renders a tr with the person's details. It then uses push from React Router Redux to dispatch a push action on click to navigate.

I find it a nice clean design, but the performance left something to be desired. There is a lot of work happening in each row. The mapStateToProps function needs to run, both to mount each row and each time state changes, and there is also a need to create a navigate method for each instance of TableRow. I thought it would be better to avoid as much work as possible in the TableRow. That means it would be better to move as much of the work up to the parent Tabel component and then pass down everything needed as props to each row.

After hoisting out as much as possible up to Table the code looked like this

// TableV2.js
import React, { Component } from 'react';
import {connect} from 'react-redux';
import {push} from 'react-router-redux';

import TableRow from './TableRow';

function mapStateToProps(state) {
  const ppl = state.ui.ids.map(id => state.ui.dict[id]);
  return {ppl};
}

class Table extends Component {
  constructor(props) {
    super(props);
    this.navigate = this.navigate.bind(this);
  }
  navigate(id) {
    this.props.dispatch(push(`/person/${id}`));
  }
  render() {
    const {ppl} = this.props;
    return <table>
      <thead>
        <tr>
          <th>Name</th>
          <th>Team</th>
          <th>Group</th>
        </tr>
      </thead>
      <tbody>
        {ppl.map(p => <TableRow key={p.id} person={p} navigate={this.navigate} />)}
      </tbody>
    </table>
  }
}

export default connect(mapStateToProps)(Table);
// TableV2.js
import React, {PureComponent} from 'react';

class TableRow extends PureComponent {
  constructor(props) {
    super(props);
    this.handleNav = this.handleNav.bind(this);
  }
  handleNav() {
    this.props.navigate(this.props.person.id);
  }
  render() {
    const {person} = this.props;
    return <tr onClick={this.handleNav}>
      <td>{person.firstName} {person.lastName}</td>
      <td>{person.team}</td>
      <td>{person.group}</td>
    </tr>
  }
}

export default TableRow;

Besides moving all the redux action up to Table, I also made TableRow a PureComponent, and I bind this to handleNav in the constructor to avoid having to create a new method for each instance of the component. The PureComponent not make a big deal for initial mount but can save some rendering time when something causes table to re-render.

So, enough with the details. What was the performance difference? As test data I generated 2000 random people. To measure the performance I used the Chrome Performance Profile, which with User Timings makes it easy to get performance details on React components. I also set CPU slowdown to 4x, to help put emphasis the performance difference.

The results were clear: Time to mount for V1 was 2.63 seconds but the time to mount was 1.03 second. Honestly, the difference was bigger than I thought. That's a solid 60% improvement. Of course, the difference would not be meaningful with only a few rows in the table, but it will amount to a something noticeable once the table gets bigger. I guess I'll have to rethink how I build tables in React in the future.

Taxonomies in Gutenber 0.4

I finally have categories in my sidebar!

This comes from the move to Gutenberg 0.4, with its new taxonomies setup. Getting it migrate took a bit figuring out so I thought I would document it here.

Unlike earlier Gutenberg, which had the predefined taxonomies category and tags, Gutenberg 0.4 allows you to define whatever taxonomies you want. The hierarchy goes like this: At the top you have a list of taxonomies. Each taxonomy consists of a name and a few other options. categories would be a taxonomy with the name categories. Then each taxonomy itself has a list of taxonomy items. Like the categories taxonomy can contain the taxonomy items Webdev and Books.

To setup taxonomies in 0.4 the first step was to define taxonomies in config.toml file. The only taxonomy I used was categories, so I defined it like this:

[[taxonomies]]
name = "categories"
rss = false

Once I had my one taxonomy, categories, defined I needed to update the front matter on all my pages. Where before there was just a category key you could set, there is now a taxonomies section. On this post it looks like this:

[taxonomies]
categories = ["Webdev"]

Categories is now also a list because you can assign multiple taxonomy items in the same taxonomy to a page, like tags used to work. Mappings between a taxonomy items and pages is always many-to-many. You do not need to define taxonomy items, Gutenberg creates the for you based on when you assign them to pages.

The next step was to update the page.html template for the new taxonomies. Where page used to have a category key, it now has a taxonomies key, which is a HashMap from the name of the taxonomy to a list of the names of the assigned taxonomy items. So on this post it looks something like this (expressed in JSON):

"page": {
  "taxonomies": {
    "categories": [
      "Webdev"
    ]
  }
}

You can still use the get_taxonomy_url to get a url to the page for a specific taxonomy item. It takes two parameters: kind, which is the name of the taxonomy; and name, which is the name of the taxonomy item. So you get a link to the page for the Webdev taxonomy with: get_taxonomy_url(kind="categories", name="Webdev").

I updated the post header to this:

<header>
  <h2>{{page.title}}</h2>
  <div class="post-info">
    Date: {{page.date}}
    {% if page.taxonomies.categories %}
      | Category: <a href="{{get_taxonomy_url(kind="categories", name=page.taxonomies.categories[0])|safe}}">{{page.taxonomies.categories[0]}}</a>
    {% endif %}
  </div>
</header>

I check if there are any categories assigned to the post, and if there are I show the first one as a link to the page for that category. This design means I can only show one category per post, but I figure it would do for now.

The old hard coded category.html template is gone in 0.4, so the next step was to make templates for the categories taxonomy. Each taxonomy gets two templates now, in a folder named after the taxonomy. The two templates are:

  1. list.html. This is the template for the entire taxonomy, with access to a list of taxonomy items. You can see how it looks like for my categories taxonomy here.
  2. single.html. This is the template for a single taxonomy item, like Webdev. You can see what it looks like for Webdev here. It is also what the Webdev at the top of this post links to.

The list.html template get passed in a global variable called terms, which is a list of taxonomy items. Each item consists of the name of the item, the slug for the item, the permalink for the item and pages, a list of pages that has that taxonomy item assigned. My list.html for categories is quite simple. The main component are two for loops that loop through each taxonomy item in the taxonomy and then through each page in the taxonomy item:

<ul class="categories-list">
  {% for term in terms %}
    <li>
      <a href="{{term.permalink}}">{{term.name}}</a>
      <ul>
        {% for page in term.pages %}
          <li>
            <a href="{{page.permalink}}">{{page.title}}</a> - {{page.date}}
          </li>
        {% endfor %}
      </ul>
    </li>
  {% endfor %}
</ul>

The single.html templates gets passed a term variable, which is the taxonomy item being rendered. My template is basically just replicating my index.html template but now it loops through the pages in the taxonomy item.

Finally, I got to the reason for this entire migration: a list of categories in the sidebar. Gutenberg 0.4 adds another function to templates: get_taxonomy. It takes one argument, kind, which is the name of the taxonomy. It returns a Taxonomy object with two fields: kind, with details about the taxonomy from the config.toml file; and items, a list of taxonomy items. With this function you can access the details of a taxonomy anywhere. I updated my sidebar template like so:

{% set categories = get_taxonomy(kind="categories") %}
<h2>Categories</h2>
<ul>
  {% for category in categories.items %}
    <li>
      <a href="{{category.permalink}}">{{category.name}}</a> ({{category.pages|length}})
    </li>
  {% endfor %}
</ul>

And so, at long last, a list of categories in the sidebar!

Gutenberg short code for making columns

One of the things I like about Gutenberg (the static site generator used for this blog) is the support for short codes. Short codes are essentially tiny Tera templates you can call in the markdown files for the content. This immediately lead me to look for a way to make short codes for multiple columns of content.

My first attempts looked something like this:

{% columns() %}
{% column() %}
Content in the left column
{% end %}
{% column() %}
Content in the right column
{% end %}
{% end %}

It didn't work. Turns out the short code parser in Gutenberg doesn't support nested short codes. The reason I wanted to nest two short codes is that the essential bit in embedding some columns in the content is that you need two levels of divs: An outer div as a container for the columns, and inner divs wrapping each column.

So, I was stuck. Later, when browsing the Tera docs for an unrelated reason, I was that it has a split method. That gave me an idea. I don't really need an inner short code, I just need a way to tell apart the content for different columns. What I could do is have one short code that splits the body of the short code based on some specified string.

The use of the new columns short code looks like this:

{% columns() %}  

Content in the left column

[[gutter]]

Content in the right column

{% end %}

It splits the body into columns any time it comes across [[gutter]]. One weakness of this is that there is no way to escape [[gutter]] so you can't write about it in a column. There is also no way to specify different column sizes. The code for the short code ended up being short and sweet:

<div class="columns">
  {% set cols = body|split(pat="[[gutter]]") %}
  {% for col in cols %}
    <div class="column">
      {{col}}
    </div>
  {% endfor %}
</div>

Then all that is needed is some CSS to layout the classes. Here is an example using flexbox to be compatible with IE11:

$gutter: 1rem;
$min-viewport-size: 600px;

.columns {
  display: flex;
  flex-direction: column;
}

.column {
  margin-bottom: $gutter;
  flex-grow: 1;
  flex-basis: 0;
  &:last-child {
    margin-bottom: 0;
    margin-right: 0;
  }
}

@media (min-width: $min-viewport-size) {
  .columns {
    display: flex;
    flex-direction: row;
  }
  
  .column {
    margin-bottom: 0;
    margin-right: $gutter;
  }
}

It uses two variables:

  • $gutter: Space between column.
  • $min-col-size: Min viewport width for switching from single column to multi column mode.

If IE11 support doesn't matter, then one could, of course, do something slick with CSS grids:

.columns {
  display: grid;
  grid-gap: 1rem;
  grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
}

That is a lot less CSS to write. This one spills columns over onto the next row to avoid them being narrower than 260px. It end up looking like this:

Bacon ipsum dolor amet leberkas ham beef ribs bresaola drumstick frankfurter cow tail. Sirloin cow picanha short loin short ribs turkey prosciutto landjaeger brisket cupim tail pig strip steak. Alcatra turducken meatloaf picanha, venison chuck pork chop ham hock. Strip steak sirloin pork chop biltong. Picanha chuck jowl turkey, doner salami ground round corned beef cow tri-tip ham brisket biltong.
Burgdoggen strip steak frankfurter tenderloin capicola, sirloin ball tip andouille tri-tip rump chicken. Shankle pork belly boudin, turducken jerky andouille bacon tenderloin ham hock capicola jowl filet mignon bresaola short loin. Bacon meatball cow sausage meatloaf. Chicken capicola cow shank frankfurter.
Spare ribs alcatra short ribs doner drumstick biltong ribeye pork chop ball tip frankfurter picanha pork loin short loin tail pancetta. Picanha ground round spare ribs pork belly landjaeger burgdoggen bresaola salami. Pig hamburger strip steak short loin doner. Short ribs t-bone shankle kevin corned beef. Fatback strip steak meatloaf, short loin ground round pancetta sirloin landjaeger. Ham chuck pig andouille ball tip kielbasa cupim sirloin jowl meatloaf chicken shankle.

The making of a blog

I figured the most navel-gazing way to start a new blog is to talk about how the blog was made.

This blog is made with a static site generator, an (CLI) application that takes some content and templates and generates all the html/css files needed for the site offline. You then deploy the resulting files to any static files host. The means that you don't run any code on the server and don't have a database. The advantage of this is that you don't need to pay for any compute/db server side, and there is nothing that can be hacked or that needs to be administered. Also, because all pages are generated ahead of time its fast because there is no need to generate the pages as requests come in. The downsides are that the site is static, so there is no possibility for dynamic content like comments. (Unless you embed some third-party comment system like Facebook's.) The advantage of a static site generator over plain static sites is that you still get templates and stuff, so you don't need to copy/paste everything for every page on the site. Also saves you a lot of work for creating category pages and similar.

The static site generator I ended up using is Gutenberg. This was not the result of some in depth investigation into all the static site generators out there. Rather it was something I had stumbled upon in a Reddit thread at some point that had been sitting in a half-forgotten tab ever since.

Gutenberg appealed to me for a few different reasons:

  • It is a single statically compiled binary you can download from GitHub so there is no need to install any programming language runtime to get it working.
  • It uses Tera as a templating language, which is based on Jinja2, and Sass for css. Since I use Jinja2 and Sass at my $dayjob I felt right at home.
  • Content is written in markdown with a special header for to specify metadata.
  • It has a local serve functionality where it will watch the filesystem for changes, and when it sees them it will recompile the site and refresh it in the browsers (via some injected js). It is fast enough that a recompile takes on the order of milliseconds.
  • It has the concepts of shortcodes from WordPress, where you can define small snippets of templates that you can then call from a markdown content file.

There is one clear shortcoming I've run into with Gutenberg so far: There is no way to globally access a list of categories. I wanted to have a list of category link in the sidebar, but I can't do that. You can even see an empty box in the sidebar where I wanted to put them. There is an open issue on GitHub about User-defined taxonomies, which apparently should enable that as well.

Gutenberg does have a theme system and a few existing themes, but I didn't use it. Instead I just hand rolled a few templates. The design is based around grey lines and rounded corners. This was originally driven by laziness. It is something that can be easily done in CSS so I wouldn't need to muck about with raster images (aside from the favicon). Given that I started on design centered around shades of grey I decided continue on that path and go for a monochrome look. For example, links are black (which is a bit darker than normal text) when unvisited but switch to a shade of grey when visited. I'm also using the circle ul list style because it fits in with the rest of the design. The one exception to the monochrome design is syntax highlighting, where is use an existing built in theme called ir-white, that is light but still colored. It looks like this:

fn main () {
  println!("Hello world");
}

I also took the opportunity to finally get to play with css grids. This is something I've been drooling over for a while but never been able to take into use due to the need to support Internet Explorer. This means this blog doesn't look great in IE11. It falls back to a boring looking single column layout, which works but isn't as pretty. The advantage of making a site for your own use is that you can just choose to ignore the IE11 users. :)

For hosting I use netlify, which works great with Gutenberg and GitHub. Just push a change to the master branch on GitHub and a git hook at netlify runs gutenberg and compiles the site and deploys the result. It also has nice features like deploying a preview of the site based on a branch. Simple support for custom domains and automatic TLS via Let's Encrypt. Oh, and you can't beat the price: $0/month. How do they pay for things? They have a lot of upsell to fancier features, but nothing I need for a simple static blog.

Overall, I'm really pleased with this setup. We'll see how long it lasts before I run into something it won't do for me, or just the urge to tinker becomes overwhelming.