Adventures in blogging 📝

Motivation

I like the idea of shared learning and working together as a team, and in a way that’s independent of employment.

The desire for independence takes a couple forms:

  1. Minimizing loss of work due to employment boundaries. For example, learning documented on an internal blog may be lost when changing roles.
  2. Maximizing opportunities that would otherwise be constrained by company goals. For example, exploring professional growth areas that may never be a company priority.

Prakhar pointed me at Nathan Marz’s post on blogging, which provides excellent motivation specific to blogging.

Megha shared her experience at Write/Speak/Code, which recommends professional writing as an essential aspect of career development. I like Write/Speak/Code’s recommendation to seek feedback from trusted sources. Inline comments and explicit comment permission, like in Google Docs, would be ideal.

(Write/Speak/Code also brought Open Source Misfeasance to my awareness 👍 esp the slide “open source is like being an adult – it seems magical until you realize nobody knows what the hell they’re doing.” 🙂

I’m inspired by the meta-knowledge community on Github.

A New Yorker article on Jonathan Ledgard mentions he “carried two notebooks—red for his reporting notes, blue for thoughts and observations to use in fiction…”

Current approach

A simple note app (currently Google Keep) to capture and access thoughts with minimal fuss.

WordPress for blog hosting. It feels relatively old-school, but it’s stable, feature-rich and has a large community. Signal v Noise, Joel Spolsky and Bill Gates use it, so I’m in good company. A few features I appreciate in particular:

  • Full-text search, which is especially useful for finding and updating posts
  • Navigation by tag and category
  • A convenient native app
  • Easy navigation from viewing to editing
  • Basic stats and “likes” aren’t the reason I’m writing, but are reassuring

Separate professional from personal content, to facilitate usage of content at work, hence the desire for multi-account support.

Alternatives explored

  • Medium is clean and modern, but the monetization strategy of charging readers seems relatively high-friction, and it doesn’t have multi-account support
  • Write.as is clean, and has a sustainable business model and an interesting tie-in to content federation, but it’s missing comments, search, etc
  • Github Pages is simple, but relatively inconvenient for frequent content management
  • Forestry CMS to manage Github Pages is an improvement, but I still want for search, comments, etc
  • Siteleaf is good, but doesn’t provide preview in free mode, and renames files according to date front-matter (after import)
  • I tried Prose.io in the past, but saving content was flaky
  • jekyll-admin seems interesting if/when it’s supported by Github Pages

Solarized code highlighting for Jekyll

Problem

I’d like to improve readability of the code on this blog by highlighting syntax, solarized ideally.

Solution

Jekyll makes syntax highlighting easy, and the following gist makes solarization easy too:

/* Solarized Light
For use with Jekyll and Pygments
http://ethanschoonover.com/solarized
SOLARIZED HEX ROLE
——— ——– ——————————————
base01 #586e75 body text / default code / primary content
base1 #93a1a1 comments / secondary content
base3 #fdf6e3 background
orange #cb4b16 constants
red #dc322f regex, special keywords
blue #268bd2 reserved keywords
cyan #2aa198 strings, numbers
green #859900 operators, other keywords
*/
.highlight { background-color: #fdf6e3; color: #586e75 }
.highlight .c { color: #93a1a1 } /* Comment */
.highlight .err { color: #586e75 } /* Error */
.highlight .g { color: #586e75 } /* Generic */
.highlight .k { color: #859900 } /* Keyword */
.highlight .l { color: #586e75 } /* Literal */
.highlight .n { color: #586e75 } /* Name */
.highlight .o { color: #859900 } /* Operator */
.highlight .x { color: #cb4b16 } /* Other */
.highlight .p { color: #586e75 } /* Punctuation */
.highlight .cm { color: #93a1a1 } /* Comment.Multiline */
.highlight .cp { color: #859900 } /* Comment.Preproc */
.highlight .c1 { color: #93a1a1 } /* Comment.Single */
.highlight .cs { color: #859900 } /* Comment.Special */
.highlight .gd { color: #2aa198 } /* Generic.Deleted */
.highlight .ge { color: #586e75; font-style: italic } /* Generic.Emph */
.highlight .gr { color: #dc322f } /* Generic.Error */
.highlight .gh { color: #cb4b16 } /* Generic.Heading */
.highlight .gi { color: #859900 } /* Generic.Inserted */
.highlight .go { color: #586e75 } /* Generic.Output */
.highlight .gp { color: #586e75 } /* Generic.Prompt */
.highlight .gs { color: #586e75; font-weight: bold } /* Generic.Strong */
.highlight .gu { color: #cb4b16 } /* Generic.Subheading */
.highlight .gt { color: #586e75 } /* Generic.Traceback */
.highlight .kc { color: #cb4b16 } /* Keyword.Constant */
.highlight .kd { color: #268bd2 } /* Keyword.Declaration */
.highlight .kn { color: #859900 } /* Keyword.Namespace */
.highlight .kp { color: #859900 } /* Keyword.Pseudo */
.highlight .kr { color: #268bd2 } /* Keyword.Reserved */
.highlight .kt { color: #dc322f } /* Keyword.Type */
.highlight .ld { color: #586e75 } /* Literal.Date */
.highlight .m { color: #2aa198 } /* Literal.Number */
.highlight .s { color: #2aa198 } /* Literal.String */
.highlight .na { color: #586e75 } /* Name.Attribute */
.highlight .nb { color: #B58900 } /* Name.Builtin */
.highlight .nc { color: #268bd2 } /* Name.Class */
.highlight .no { color: #cb4b16 } /* Name.Constant */
.highlight .nd { color: #268bd2 } /* Name.Decorator */
.highlight .ni { color: #cb4b16 } /* Name.Entity */
.highlight .ne { color: #cb4b16 } /* Name.Exception */
.highlight .nf { color: #268bd2 } /* Name.Function */
.highlight .nl { color: #586e75 } /* Name.Label */
.highlight .nn { color: #586e75 } /* Name.Namespace */
.highlight .nx { color: #586e75 } /* Name.Other */
.highlight .py { color: #586e75 } /* Name.Property */
.highlight .nt { color: #268bd2 } /* Name.Tag */
.highlight .nv { color: #268bd2 } /* Name.Variable */
.highlight .ow { color: #859900 } /* Operator.Word */
.highlight .w { color: #586e75 } /* Text.Whitespace */
.highlight .mf { color: #2aa198 } /* Literal.Number.Float */
.highlight .mh { color: #2aa198 } /* Literal.Number.Hex */
.highlight .mi { color: #2aa198 } /* Literal.Number.Integer */
.highlight .mo { color: #2aa198 } /* Literal.Number.Oct */
.highlight .sb { color: #93a1a1 } /* Literal.String.Backtick */
.highlight .sc { color: #2aa198 } /* Literal.String.Char */
.highlight .sd { color: #586e75 } /* Literal.String.Doc */
.highlight .s2 { color: #2aa198 } /* Literal.String.Double */
.highlight .se { color: #cb4b16 } /* Literal.String.Escape */
.highlight .sh { color: #586e75 } /* Literal.String.Heredoc */
.highlight .si { color: #2aa198 } /* Literal.String.Interpol */
.highlight .sx { color: #2aa198 } /* Literal.String.Other */
.highlight .sr { color: #dc322f } /* Literal.String.Regex */
.highlight .s1 { color: #2aa198 } /* Literal.String.Single */
.highlight .ss { color: #2aa198 } /* Literal.String.Symbol */
.highlight .bp { color: #268bd2 } /* Name.Builtin.Pseudo */
.highlight .vc { color: #268bd2 } /* Name.Variable.Class */
.highlight .vg { color: #268bd2 } /* Name.Variable.Global */
.highlight .vi { color: #268bd2 } /* Name.Variable.Instance */
.highlight .il { color: #2aa198 } /* Literal.Number.Integer.Long */
view raw solarized-light.css hosted with ❤ by GitHub

Blog search

Problem statement

I’d like to provide a quick way to retrieve information from this blog.

In terms of constraints, this blog is statically generated and hosted on Github, which disallows arbitrary plugins, limiting many solutions to client-side and/or external vendors. I’d also prefer to keep things free.

Solutions

Tags

Jekyll supports tags, and the Forestry CMS I use enables me to manage tags alongside content, so I can start by including tags in my index of notes.

Client-side search

Ideally, I could provide inline keyword search.

Search providers understandably require UI control.

Lunr provides a convenient JS library to perform keyword extraction and lookup, and supports pre-building the search index to improve client performance. However, the index for my content was 500kb and the search syntax, although powerful, was unintuitive for my simple needs.

Google’s published the most common English words. I could strip these from my content and then include the remainder in my index, eg:

{% raw %}
  {% unless site.data.stop_words contains word %}
    {{word}}
  {% endunless %}
{% endraw %}

This still yields more words than wieldy for displaying in an index. I’m also limited to Liquid syntax for index generation, which complicates things like excluding code snippets.

So far, the best solution has been constructing a regex from an input string, applying it to the titles and tags of my index and then hiding entries that don’t match.

Server-side search

I can take advantage of Google’s search indexing by defining a Jekyll sitemap. I can get closer to inline filtering by using Chrome’s omnibox. Here’s the blog’s opensearch.xml.