<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/">
    <channel>
        <title>Art, Code</title>
        <link>https://artcommaco.de/</link>
        <description>The occasional blog of @ccommma</description>
        <lastBuildDate>Mon, 17 Aug 2026 14:12:03 GMT</lastBuildDate>
        <docs>https://validator.w3.org/feed/docs/rss2.html</docs>
        <generator>https://github.com/jpmonette/feed</generator>
        <language>en</language>
        <copyright>All rights reserved</copyright>
        <item>
            <title><![CDATA[July 24, 2026]]></title>
            <link>https://artcommaco.de/posts/2026-07-24-diy-home-weather-monitoring.html</link>
            <guid>https://artcommaco.de/posts/2026-07-24-diy-home-weather-monitoring.html</guid>
            <pubDate>Fri, 24 Jul 2026 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>diy home weather monitoring setup for less than half the price of a single netatmo sensor</p>
<p><picture style="flex:1.3333">
  <source srcset="/images/2026-07-24-diy-home-weather-monitoring-1_1000.webp 1000w, /images/2026-07-24-diy-home-weather-monitoring-1_1600.webp 1600w, /images/2026-07-24-diy-home-weather-monitoring-1_2000.webp 2000w" sizes="100vw" />
  <img src="/images/2026-07-24-diy-home-weather-monitoring-1_1000.webp" alt="a eps32 with display in a 3d printed case displaying the temperature and humidity of four locations around a house" loading="lazy" />
</picture></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[May 18, 2026]]></title>
            <link>https://artcommaco.de/posts/2026-05-18-back-in-the-hardware.html</link>
            <guid>https://artcommaco.de/posts/2026-05-18-back-in-the-hardware.html</guid>
            <pubDate>Mon, 18 May 2026 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>back in the hardware mines</p>
<p><picture style="flex:1.3333">
  <source srcset="/images/2026-05-18-back-in-the-hardware-1_1000.webp 1000w, /images/2026-05-18-back-in-the-hardware-1_1600.webp 1600w, /images/2026-05-18-back-in-the-hardware-1_2000.webp 2000w" sizes="100vw" />
  <img src="/images/2026-05-18-back-in-the-hardware-1_1000.webp" alt="a few raspberry pis, an orange pi, a breadboard, a power bank and some cables" loading="lazy" />
</picture></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[October 28, 2025]]></title>
            <link>https://artcommaco.de/posts/2025-10-28-i-should-probably-start.html</link>
            <guid>https://artcommaco.de/posts/2025-10-28-i-should-probably-start.html</guid>
            <pubDate>Tue, 28 Oct 2025 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>i should probably start documenting this thing, considering i’ve been working on it in down time for months now</p>
<div class="images"><picture style="flex:0.75">
  <source srcset="/images/2025-10-28-i-should-probably-start-1_1000.webp 1000w, /images/2025-10-28-i-should-probably-start-1_1600.webp 1600w, /images/2025-10-28-i-should-probably-start-1_2000.webp 2000w" sizes="100vw" />
  <img src="/images/2025-10-28-i-should-probably-start-1_1000.webp" alt="terminal logs of a running python server" loading="lazy" />
</picture><picture style="flex:0.75">
  <source srcset="/images/2025-10-28-i-should-probably-start-2_1000.webp 1000w, /images/2025-10-28-i-should-probably-start-2_1600.webp 1600w, /images/2025-10-28-i-should-probably-start-2_2000.webp 2000w" sizes="100vw" />
  <img src="/images/2025-10-28-i-should-probably-start-2_1000.webp" alt="an orange pi plugged into various devices, some sony headphones and a buddha box in the background" loading="lazy" />
</picture></div>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[December 1, 2024]]></title>
            <link>https://artcommaco.de/posts/2024-12-01-it-s-weird-owning-a.html</link>
            <guid>https://artcommaco.de/posts/2024-12-01-it-s-weird-owning-a.html</guid>
            <pubDate>Sun, 01 Dec 2024 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>it’s weird owning a car only 20 years old, never had something with a computer i can talk to before. ahc pressures and steering angle sensor fixed</p>
<p><picture style="flex:1.3333">
  <source srcset="/images/2024-12-01-it-s-weird-owning-a-1_1000.webp 1000w, /images/2024-12-01-it-s-weird-owning-a-1_1600.webp 1600w, /images/2024-12-01-it-s-weird-owning-a-1_2000.webp 2000w" sizes="100vw" />
  <img src="/images/2024-12-01-it-s-weird-owning-a-1_1000.webp" alt="a photo of toyotas techstream software, showing in-spec values" loading="lazy" />
</picture></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Lot Can Change In Five Years]]></title>
            <link>https://artcommaco.de/posts/2022-03-28-a-lot-can-change-in-five-years.html</link>
            <guid>https://artcommaco.de/posts/2022-03-28-a-lot-can-change-in-five-years.html</guid>
            <pubDate>Mon, 28 Mar 2022 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>And a lot can stay the same.</p>
<p>A little over five years have come and gone since I wrote <a href="/posts/2017-03-06-questions-about-tooling.html">Questions About Tooling</a>, and as I was paging through my site &thinsp;&mdash;&thinsp; handling my quarterly SSL certificate reissuance, because it's easier spending five minutes re-running the same <code>certbot</code> command every three months than 20 minutes figuring out how to automate it &thinsp;&mdash;&thinsp; I found this post pretty interesting to look back on.</p>
<ol>
<li>Yarn vs npm</li>
</ol>
<p>I completely switched to Yarn shortly after writing the post, and I loved the experience. But I've recently come back to npm after the yarn 2.0 release and the sheer <a href="https://yarnpkg.com/getting-started/migration">number of steps</a> required to migrate legacy codebases &thinsp;&mdash;&thinsp; of which I maintain many &thinsp;&mdash;&thinsp; to their <a href="https://yarnpkg.com/features/pnp">PnP</a> architecture. I keep forgetting to add <code>run</code> to my commands, but other than that npm is just fine.</p>
<ol start="2">
<li>webpack vs browserify</li>
</ol>
<p>Well, webpack definitely won this one. I still maintain a few repos with browserify-based scripting, but any new project will have webpack enabled from the start. The experience with webpack is a lot better now too, as this will typically be abstracted away from you via <code>create-react-app</code>, <code>create-next-app</code>, <code>create-remix</code>, or whatever scripts you're using to bootstrap your platform of choice. All of the advantages of webpack with none &thinsp;&mdash;&thinsp; well, less &thinsp;&mdash;&thinsp; of the googling to figure out what packages you need to install for your code to compile.</p>
<ol start="3">
<li>VS Code vs Atom</li>
</ol>
<p>I'm still very happy with VS Code &thinsp;&mdash;&thinsp; to the point that we're now using it's <a href="https://microsoft.github.io/monaco-editor/">core architecture</a> to power the <a href="https://www.superhi.com/editor">SuperHi Editor</a> &thinsp;&mdash;&thinsp; though I no longer put as much effort into theming as I once did. I'll set the typeface to <code>16px IBMPlexMono-Regular</code>, choose a <a href="https://marketplace.visualstudio.com/items?itemName=wicked-labs.old-serendipity">nice theme</a> with light and dark modes and leave everything else. Once I've added <a href="https://marketplace.visualstudio.com/items?itemName=esbenp.prettier-vscode">Prettier</a>, <a href="https://marketplace.visualstudio.com/items?itemName=eamodio.gitlens">GitLens</a> and <a href="https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint">ESLint</a> of course.</p>
<ol start="4">
<li>Typescript vs Flow</li>
</ol>
<p>Another resounding win in the column, this time for Typescript. The tooling's gotten even better and the team are constantly adding <a href="https://www.typescriptlang.org/docs/handbook/release-notes/overview.html">new features and various improvements</a> to the way that it works. At this point I'm uncomfortable whenever I have to write vanilla JavaScript, as I need all of the various safeties and niceties of Typescript to protect me from myself.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Surviving TypeScript with React + Redux + Redux Thunk + Redux Immutable + Redux Batched Actions + Reselect]]></title>
            <link>https://artcommaco.de/posts/2019-11-20-typescript-react-and-all-the-trimmings.html</link>
            <guid>https://artcommaco.de/posts/2019-11-20-typescript-react-and-all-the-trimmings.html</guid>
            <pubDate>Wed, 20 Nov 2019 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>The first thing you'll need to do is check out the instructions on using TypeScript in the <a href="https://redux.js.org/recipes/usage-with-typescript">Redux docs</a>, they're extremely well written and are our saving grace here, allowing us to get up-and-running quickly with a slightly verbose &thinsp;&mdash;&thinsp; but clean and type-safe &thinsp;&mdash;&thinsp; initial set-up.</p>
<p>We'll only be writing a small application that toggles a single property in the store, but everything here gives you the toolset you need to expand upon and build a real-world application with. In fact, most of the code is taken directly from the new <a href="https://subeditor.superhi.com/">SuperHi Editor</a> that I've been working on.</p>
<p>We'll dive in:</p>
<pre><code class="language-typescript">import { Record } from 'immutable'

export type AuthStatus = 'LOGGED_IN' | 'LOGGED_OUT'

export interface AuthStateProps {
  status: AuthStatus
}

const initialAuthState = Record&#x3C;AuthStateProps>({
  status: 'LOGGED_OUT'
})

export class AuthState extends initialAuthState implements AuthStateProps {}

export const LOGGED_IN = 'LOGGED_IN'
export const LOGGED_OUT = 'LOGGED_OUT'

interface LoggedInAction {
  type: typeof LOGGED_IN
}

interface LoggedOutAction {
  type: typeof LOGGED_OUT
}

export type AuthActionTypes = LoggedInAction | LoggedOutAction
</code></pre>
<p>The first file is <code>auth/types.ts</code>, it's very similar to the Redux docs on <a href="https://redux.js.org/recipes/usage-with-typescript#type-checking-actions-action-creators">Type Checking Actions &#x26; Action Creators</a> but deviates with the use of <code>immutable.js</code>, we're using <a href="https://immutable-js.github.io/immutable-js/docs/#/">Immutable</a> in the SuperHi Editor because it's noticeably faster than working with large JavaScript objects. The Redux docs on <a href="https://redux.js.org/recipes/using-immutablejs-with-redux">Using Immutable.JS with Redux</a> are again a good starting point but we're ignoring their best practices &thinsp;&mdash;&thinsp; such as using a Higher order Component to convert Immutable objects to JS objects &thinsp;&mdash;&thinsp; in the name of speed, <em>everything</em> is an Immutable object &thinsp;&mdash;&thinsp; typically <code>Record</code>s &thinsp;&mdash;&thinsp; and we'll work with them directly.</p>
<p>Why Immutable Records? Because they're much "safer" than Immutable Maps. Basically, a record allows us to guarantee the keys, so when we type <code>record.get('filenamr')</code> instead of <code>record.get('filename')</code> TypeScript will tell us we've done something wrong.</p>
<p>First we set up the plain object &thinsp;&mdash;&thinsp; or "props" &thinsp;&mdash;&thinsp; for the state:</p>
<pre><code class="language-typescript">export interface AuthStateProps {
  status: AuthStatus
}
</code></pre>
<p>Then we create the initial state given the default props:</p>
<pre><code class="language-typescript">const initialAuthState = Record&#x3C;AuthStateProps>({
  status: 'LOGGED_OUT'
})
</code></pre>
<p>And then we build a <code>class</code> that extends this Record, allowing us to build records with <code>new AuthState(props)</code>:</p>
<pre><code class="language-typescript">export class AuthState extends initialAuthState implements AuthStateProps {}
</code></pre>
<p>Typically in this <code>class</code> we'd also want to add the props &thinsp;&mdash;&thinsp; in this case there's just one: <code>public readonly status!: AuthStatus</code> &thinsp;&mdash;&thinsp; but if you're using <code>create-react-app</code> &thinsp;&mdash;&thinsp; as we do in the SuperHi Editor &thinsp;&mdash;&thinsp; then you're compiling your TypeScript with Babel, not with TypeScript itself and this will lead to a runtime error of <code>Cannot set on an immutable record</code>.</p>
<p>Now for <code>auth/actions.ts</code></p>
<pre><code class="language-typescript">import { LOGGED_IN, LOGGED_OUT, AuthActionTypes } from './types'

export const loggedIn = (): AuthActionTypes => ({
  type: LOGGED_IN
})

export const loggedOut = (): AuthActionTypes => ({
  type: LOGGED_OUT
})
</code></pre>
<p>This is really simple and &thinsp;&mdash;&thinsp; for now! &thinsp;&mdash;&thinsp; exactly the same as the Redux docs. We'll come back to actions when we implement thunk actions later.</p>
<p>For <code>auth/reducers.ts</code></p>
<pre><code class="language-typescript">import { AuthState, AuthActionTypes, LOGGED_IN, LOGGED_OUT } from './types'

export const initialState = new AuthState()

export default (state = initialState, action: AuthActionTypes) => {
  switch (action.type) {
    case LOGGED_IN:
      return state.set('status', 'LOGGED_IN')
    case LOGGED_OUT:
      return state.set('status', 'LOGGED_OUT')
    default:
      return state
  }
}
</code></pre>
<p>Pretty similar here too, though we build an <code>initialState</code> with our <code>AuthState</code> Record and <code>export</code> it for later. Because we're using <code>AuthActionTypes</code> here TypeScript will know
exactly what payload to expect with each <code>case</code>, although in our demo it'll always be empty.</p>
<p>We'll also add <code>auth/selectors.ts</code> so we can grab that <code>status</code> as needed:</p>
<pre><code class="language-typescript">import { createSelector } from 'reselect'
import { AuthStatus } from './types'
import { AppState } from '../reducers'

export const selectAuthStatus = createSelector(
  (state: AppState) => state.getIn(['auth', 'status']),
  (authStatus: AuthStatus) => authStatus
)
</code></pre>
<p>We can use <code>createSelector</code> here as <code>authStatus</code> is going to be a standard JS string but if we instead wanted to select the entire <code>auth</code> slice of the store we'd need to do:</p>
<pre><code class="language-typescript">import { createSelectorCreator, defaultMemoize } from 'reselect'
import { is } from 'immutable'
import { AuthState } from './types'
import { AppState } from '../reducers'

const createImmutableSelector = createSelectorCreator(defaultMemoize, is)

export const selectAuth = createImmutableSelector(
  (state: AppState) => state.get('auth'),
  (auth: AuthState) => auth
)
</code></pre>
<p>This allows us to use Immutable's <code>is</code> function to compare two immutable objects &thinsp;&mdash;&thinsp; in this case the previous auth state and the new auth state &thinsp;&mdash;&thinsp; guaranteeing whether or not they're the same and making sure we don't re-render the React app accidentally.</p>
<p>Our root <code>reducers.ts</code> file is where things get a little messy:</p>
<pre><code class="language-typescript">import { Record } from 'immutable'
import { Reducer } from 'redux'
import { ThunkDispatch as TDispatch, ThunkAction as TAction } from 'redux-thunk'
import { combineReducers } from 'redux-immutable'
import { BatchAction } from 'redux-batched-actions'
import authReducer, { initialState as initialAuthState } from './auth/reducers'
import { AuthState, AuthActionTypes } from './auth/types'

interface AppStateProps {
  auth: AuthState
}

const initialAppState = Record&#x3C;AppStateProps>({
  auth: initialAuthState
})

export class AppState extends initialAppState implements AppStateProps {}

export type AllActionTypes = AuthActionTypes | BatchAction

export type ThunkDispatch = TDispatch&#x3C;AppState, null, AllActionTypes>

export type ThunkAction = TAction&#x3C;void, AppState, null, AllActionTypes>

const rootReducer = combineReducers({ auth: authReducer })

export default (rootReducer as unknown) as Reducer&#x3C;AppState, AllActionTypes>
</code></pre>
<p>The first thing we do is set up <code>AppState</code> just as we did with <code>AuthState</code>, using the <code>initialAuthState</code> we defined in <code>auth/reducers.ts</code></p>
<p>We <code>export</code> a union of all action types, this includes the <code>AuthActionTypes</code> &thinsp;&mdash;&thinsp; and as any other action types you might've used &thinsp;&mdash;&thinsp; as well as the special <code>BatchAction</code> type, allowing us to safely dispatch <code>batchActions</code> too. We also <code>export</code> a <code>ThunkDispatch</code> built up of the <code>AppState</code>, <code>void</code> &thinsp;&mdash;&thinsp; because we're not using any extra arguments with <code>redux-thunk</code> &thinsp;&mdash;&thinsp; and <code>AllActionTypes</code> as well as <code>ThunkAction</code> built the same way, with <code>void</code> as the first type argument as we won't be returning anything from our thunk actions.</p>
<p>Finally we build the <code>rootReducer</code> and then, because <code>redux-immutable</code> only allows us to use a <code>Map</code> here, we lie to TypeScript &thinsp;&mdash;&thinsp; and ourselves &thinsp;&mdash;&thinsp; and say this is actually a <code>Reducer</code> of <code>AppState</code> and <code>AllActionTypes</code>. This will give us type-checking for keys in the store even though in practice we don't have these guarantees, the API for Immutable Maps and Records are very similar so we can get away with it here.</p>
<p>And then in <code>store.ts</code>:</p>
<pre><code class="language-typescript">import { createStore, applyMiddleware } from 'redux'
import { enableBatching } from 'redux-batched-actions'
import thunk from 'redux-thunk'
import reducers from './reducers'
import middlewareReducer from './middleware/reducers'

const middleware = applyMiddleware(thunk, middlewareReducer)

const store = createStore(enableBatching(reducers), middleware)

export default store
</code></pre>
<p>This looks pretty much as you'd expect, but wait, where did that middleware come from? We'll have a look at how to use middleware with all of this:</p>
<pre><code class="language-typescript">import { MiddlewareAPI } from 'redux'
import { AllActionTypes, ThunkDispatch } from '../reducers'

export default ({ dispatch }: MiddlewareAPI&#x3C;ThunkDispatch>) => (next: ThunkDispatch) => async (
  action: AllActionTypes
) => {
  next(action)
}
</code></pre>
<p>It's actually not too bad! We're using our previously declared <code>ThunkDispatch</code> here to make sure we can <code>dispatch</code> on both normal actions and thunk actions. We could even set up a <code>switch</code> statement here and get the same level of safety we did in <code>auth/reducers.ts</code>. Note if you add your own special middleware-only actions you're also going to want to set up <code>middleware/types.ts</code> and <code>middleware/actions.ts</code> files for these and add the actions to <code>AllActionTypes</code> in <code>reducers.ts</code>.</p>
<p>Speaking of auth, we'll add a thunk action to <code>auth/actions.ts</code>:</p>
<pre><code class="language-typescript">export const handleLogIn = (payload: {
  username: string
  password: string
}): ThunkAction => dispatch => {
  // do stuff with the username and password, typically done in middleware for
  // side-effecting stuff like this.
  dispatch(loggedIn())
}
</code></pre>
<p>We'll use our <code>ThunkAction</code> here from <code>reducers.ts</code> to keep TypeScript happy, and if we use this in a component:</p>
<pre><code class="language-js">import React from 'react'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { AppState, ThunkDispatch } from '../store/reducers'
import { selectAuthStatus } from '../store/auth/selectors'
import { handleLogIn } from '../store/auth/actions'

const mapStateToProps = (state: AppState) => ({
  authStatus: selectAuthStatus(state)
})

const mapDispatchToProps = (dispatch: ThunkDispatch) =>
  bindActionCreators({ handleLogIn }, dispatch)

type Props = ReturnType&#x3C;typeof mapStateToProps> &#x26; ReturnType&#x3C;typeof mapDispatchToProps>

const Index = ({ authStatus, handleLogIn }: Props) => {
  return authStatus === 'LOGGED_IN' ? (
    &#x3C;div>Logged In&#x3C;/div>
  ) : (
    &#x3C;div
      onClick={() =>
        handleLogIn({
          username: 'artcommacode',
          password: 'this-is-not-my-password'
        })
      }
    >
      Log In
    &#x3C;/div>
  )
}

export default connect(mapStateToProps, mapDispatchToProps)(Index)
</code></pre>
<p>Here it's again mostly the same as you'll see in docs, the trick is using <code>AppState</code> and <code>ThunkDispatch</code> from our root reducer file in <code>mapStateToProps</code> and <code>mapDispatchToProps</code>, and <code>ReturnType&#x3C;typeof mapStateToProps> &#x26; ReturnType&#x3C;typeof mapDispatchToProps></code> to get the actual shape of our props for the component. You can also extend <code>Props</code> if there's any props being passed in from above. We're also using our selector from <code>auth/selectors.ts</code> to make sure our data is memoised.</p>
<p>One final gotcha is if you're importing your <code>store</code> in a file and using that directly &thinsp;&mdash;&thinsp; say you're trying to do something right up top before you add your <code>&#x3C;Provider></code> wrapper &thinsp;&mdash;&thinsp; and dispatching a thunk action. Instead of <code>store.dispatch(action())</code> you'll want to do <code>(store.dispatch as ThunkDispatch)(action())</code> so TypeScript knows what you're trying to achieve here.</p>
<p>We're also using Apollo in the SuperHi Editor and I considered adding detailed instructions on getting that set up as well, but in practice it depends on what you need. The easiest method is to throw out Redux and just use Apollo, but although Apollo gives you an internal cache it doesn't have the tools &thinsp;&mdash;&thinsp; see above for the sheer number of them we're using here! &thinsp;&mdash;&thinsp; for working on state like you would in Redux.</p>
<p>Instead, the solution we came up with was to implement Apollo as a Redux middleware which allows us to use Apollo's <code>client.watchQuery</code>, <code>client.mutate</code> and <code>client.queryManager.startGraphQLSubscription</code> methods directly to talk to our API. It looks something like this:</p>
<pre><code class="language-typescript">switch (action.type) {
  case APOLLO_WATCH_QUERY: {
    const { name, query, variables, onResult, onError } = action.payload
    try {
      const observable = client.watchQuery({ query, variables })
      const { data } = await observable.result()
      if (data &#x26;&#x26; data[name]) {
        dispatch(onResult({ [name]: data[name] }))
      } else {
        throw new Error(`${name} wasn't found in the response`)
      }
    } catch (error) {
      dispatch(onError({ error: error.message }))
    }
    break
  }
}
</code></pre>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Questions About Tooling]]></title>
            <link>https://artcommaco.de/posts/2017-03-06-questions-about-tooling.html</link>
            <guid>https://artcommaco.de/posts/2017-03-06-questions-about-tooling.html</guid>
            <pubDate>Mon, 06 Mar 2017 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>Recently I've been asking myself some questions about the tools I use day-to-day and their possible alternatives. Please note all answers are purely personal and it's likely your own experiences will differ, but if you feel you need to tell me I'm wrong &thinsp;&mdash;&thinsp; or right! &thinsp;&mdash;&thinsp; feel free to get in touch with me on <a href="https://twitter.com/ccommma">Twitter</a>.</p>
<ol>
<li>Should I use <a href="https://yarnpkg.com/">Yarn</a> over <a href="https://www.npmjs.com/">npm</a>?</li>
</ol>
<p>Not just yet. <a href="http://heroku.com/">Heroku</a> &thinsp;&mdash;&thinsp; my deployment method of choice &thinsp;&mdash;&thinsp; say they support Yarn but my builds often fail. Added to this: Yarn can't be installed the recommended way when using <a href="http://nvm.sh">nvm</a>, global installs (unfortunately sometimes necessary) don't work as expected and the promised speed increases over npm aren't noticeable when my 80KB/s internet connection is the bottleneck. As such I'm putting Yarn to the side for a little longer.</p>
<ol start="2">
<li>Should I use <a href="https://webpack.js.org/">webpack</a> over <a href="http://browserify.org/">browserify</a>?</li>
</ol>
<p>Probably not. From spending time in Slack and on Twitter you'd expect the gains to be massive but although my browserify scripts occasionally end up looking like the below there's many methods to clean that up. Going back to <a href="https://github.com/facebookincubator/create-react-app/blob/fe7b5c212b5127775287ce444947f4c604c024dd/packages/react-scripts/config/webpack.config.dev.js">hundreds of lines</a> of JavaScript to control my builds feels too much like a return to gulp.</p>
<pre><code class="language-json">"NODE_ENV=production browserify ./src/App.js -t [ babelify --presets [ es2015 stage-2 react ] --plugins [ transform-flow-strip-types transform-class-properties ] ] | uglifyjs > ./public/js/bundle.js"
</code></pre>
<p>If you use browserify and feel like you're missing out or if you use webpack and want to know how to do bundle splitting, loaders, source maps or more then I recommend checking out <a href="https://github.com/substack">substack</a>'s great post "<a href="https://gist.github.com/substack/68f8d502be42d5cd4942">browserify for webpack users</a>".</p>
<ol start="3">
<li>Should I use <a href="https://code.visualstudio.com/">VS Code</a> over <a href="https://atom.io/">Atom</a>?</li>
</ol>
<p>Absolutely! It's less resource intensive, much faster and has a great set of defaults including: tooltips, css completion that actually works, debugging, great git integration and many <a href="https://github.com/Microsoft/vscode-tips-and-tricks">neat tricks</a>. Plus if you don't mind hacking it up <a href="https://github.com/orta/Essence#using">a little</a> you can have a beautiful editor as well.</p>
<p><picture style="flex:1.5347">
  <source srcset="/images/tooling-2_1000.webp 1000w, /images/tooling-2_1600.webp 1600w, /images/tooling-2_2000.webp 2000w" sizes="100vw" />
  <img src="/images/tooling-2_1000.webp" alt="VS Code with Ayu light theme" loading="lazy" />
</picture></p>
<ol start="4">
<li>Should I use <a href="http://www.typescriptlang.org/">TypeScript</a> over <a href="https://flowtype.org/">Flow</a>?</li>
</ol>
<p>Maybe? Although TypeScript's known to be unsound they make a <a href="https://github.com/Microsoft/TypeScript/issues/9825#issuecomment-234115900">good case for that</a> and in my experience Flow has many issues with soundness too. VS Code's TypeScript tooling makes it an obvious winner when using the editor but TypeScript also beats out Flow in the <a href="https://github.com/DefinitelyTyped/DefinitelyTyped">shear number</a> of typings available for external libraries and hasn't once yet told me that an <code>EventEmitter</code> isn't an <code>EventEmitter</code>.</p>
<p>Either way they're both a good midway point between untyped, vanilla JavaScript and something strongly typed like Purescript. I'm currently choosing between them on a project-by-project basis and usually use Flow for React and the frontend and TypeScript on the server.</p>
<p><strong>Edit 03/2022:</strong> I have some more recent thoughts around JavaScript tooling <a href="/posts/2022-03-28-a-lot-can-change-in-five-years.html">here</a></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Simplifying Iteration Through Iteration]]></title>
            <link>https://artcommaco.de/posts/2016-09-27-simplifying-iteration-through-iteration.html</link>
            <guid>https://artcommaco.de/posts/2016-09-27-simplifying-iteration-through-iteration.html</guid>
            <pubDate>Tue, 27 Sep 2016 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>Given an input of <code>"a monad is just a monoid in the category of endofunctors"</code> and an output of:</p>
<pre><code class="language-js">"a monad is just a monoid in the category of endofunctors"
"monad is just a monoid in the category of endofunctors"
"is just a monoid in the category of endofunctors"
"just a monoid in the category of endofunctors"
"a monoid in the category of endofunctors"
"monoid in the category of endofunctors"
"in the category of endofunctors"
"the category of endofunctors"
"category of endofunctors"
"of endofunctors"
"endofunctors"
</code></pre>
<p>How would you handle the transformation? My first idea was to use two folds (or <code>reduce</code> in JavaScript speak):</p>
<pre><code class="language-js">const permutations = (str) => {
  const words = str.split(' ')
  return words.reduce((p, _, i) => {
    return p.concat([words.reduce((s, word, j) => {
      return j >= i ? s + ` ${word}` : s
    }, '').trim()])
  }, [])
}
</code></pre>
<p>Here I'm splitting the string into an array of words and folding over it twice to build an array of strings of words. However the first fold is basically <code>xs.reduce((ys, x) => ys.concat([fn(x)]), [])</code> and is equivalent to <code>xs.map(fn)</code>, meaning the above can be rewritten as:</p>
<pre><code class="language-js">const permutations = (str) => {
  const words = str.split(' ')
  return words.map((_, i) => (
    words.reduce((s, word, j) => (
      j >= i ? s + ` ${word}` : s
    ), '').trim()
  ))
}
</code></pre>
<p>Which is already a little easier to understand. But I don't need that second fold at all, as instead of taking an array of words, finding all words past a certain index and concatenating them into a string it's much neater to simply <code>slice</code> the array at that index and <code>join</code> it back into a string. If I re-rewrite the function I get:</p>
<pre><code class="language-js">const permutations = (str) => {
  const words = str.split(' ')
  return words.map((_, i) => words.slice(i).join(' '))
}
</code></pre>
<p>Much better! And seeing as JavaScript gives us the original array as the third argument to <code>map</code> I can take the whole thing down to a tweet-sized chunk:</p>
<pre><code class="language-js">const permutations = (str) => (
  str.split(' ').map((_, i, words) => words.slice(i).join(' '))
)
</code></pre>
<p>I have a habit of jumping straight to folds as the solution to list problems. Seeing as they're the root of all iteration methods (it can be seen above how I accidentally implemented <code>map</code> and the same can be done for <code>filter</code>, <code>some</code>, <code>find</code> and all the others) the answer won't be wrong, but it <em>will</em> be overly complicated. I'm quite happy with how easy it is to read the solution when compared to my initial attempt.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[geordiewood.com]]></title>
            <link>https://artcommaco.de/posts/2016-07-12-geordiewood-dot-com.html</link>
            <guid>https://artcommaco.de/posts/2016-07-12-geordiewood-dot-com.html</guid>
            <pubDate>Tue, 12 Jul 2016 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p><picture style="flex:1.5329">
  <source srcset="/images/geordie-1_1000.webp 1000w, /images/geordie-1_1600.webp 1600w, /images/geordie-1_2000.webp 2000w" sizes="100vw" />
  <img src="/images/geordie-1_1000.webp" alt="geordiewood.com, main page" loading="lazy" />
</picture></p>
<p>Recently I had the pleasure of working with <a href="https://twitter.com/hassanrahim">Hassan Rahim</a> on <a href="http://geordiewood.com">Geordie Wood</a>'s new website.</p>
<p>It was fantastic. Working with Hassan's clean, intelligent designs for a man who's photographed the greats &thinsp;&mdash;&thinsp; from <a href="http://geordiewood.com/projects/obama">Obama</a> to <a href="https://twitter.com/GuwopSnap/status/745304872912818178">Gucci Mane</a> &thinsp;&mdash;&thinsp; was an inspiration. Hassan's attention to detail is immense and after his carefully labelled Dropbox folders and intensely annotated <a href="https://www.invisionapp.com">Invision</a> boards I may never be happy to go back to the ubiquitous, industry standard PDF…</p>
<p>There were three main requirements for the project; a near instantaneous front end with the highest possible visual fidelity and an easy to use backend.</p>
<p>Now, these may seem fairly obvious requests for a photographer's portfolio site but they're not as common as you'd expect so here's a little about how I went about it.</p>
<p>Starting with the frontend, working with large images meant I had to be sure I was sending correctly sized files to each and every client. Previously I'd resize the images on upload to the CMS, but this slows down the editing process and leaves me with just a few sizes to choose from.</p>
<p>So this time I turned to <a href="http://imgix.com">Imgix</a>, and all I had to do was point it to an <a href="https://aws.amazon.com/s3/">Amazon S3</a> bucket and make a request with the filename and dimensions of the image (calculated based on the size the image is to be shown at, the screen size and <code>window.devicePixelRatio</code>). I rounded all sizes to the nearest 50px to make sure I'd hit Imgix's cache as often as possible, as a cache hit takes only a few milliseconds but with a miss it can be over a second as we wait for Imgix to resize the image before sending it back.</p>
<p><picture style="flex:1.5329">
  <source srcset="/images/geordie-2_1000.webp 1000w, /images/geordie-2_1600.webp 1600w, /images/geordie-2_2000.webp 2000w" sizes="100vw" />
  <img src="/images/geordie-2_1000.webp" alt="geordiewood.com, slide" loading="lazy" />
</picture></p>
<p>As an aside, I'm only using a few libraries on the frontend &thinsp;&mdash;&thinsp; <a href="https://facebook.github.io/react/">React</a> and <a href="https://github.com/reactjs/react-router">React Router</a> are the two big ones &thinsp;&mdash;&thinsp; and all my code's written in what I've taken to calling ES6+ (ES6 with a few neat ES7 extras such as <code>async</code> and <code>await</code>) and compiled with <a href="https://babeljs.io">Babel</a>.</p>
<p>With the image sizes sorted I had to make sure they were loaded as quickly as possible. For the desktop I went with a very aggressive caching strategy that loads all of the slides in the background one-by-one. Though I made sure to take the first slide out of each project and loaded those in immediately so they were ready when the user interacted with the homepage.</p>
<p><picture style="flex:1.5329">
  <source srcset="/images/geordie-3_1000.webp 1000w, /images/geordie-3_1600.webp 1600w, /images/geordie-3_2000.webp 2000w" sizes="100vw" />
  <img src="/images/geordie-3_1000.webp" alt="geordiewood.com, main page hover" loading="lazy" />
</picture></p>
<p>For mobile it's a little different as I couldn't take the desktop strategy because at best it noticeably slowed things down and at worst it crashed the tab entirely (something that happened a lot on earlier iPads as low internal memory and large images aren't a good mix). So instead the site waits until the user hits a slide and simply loads in that slide and the one immediately after it. It's not a perfect solution but it still feels rapid and doesn't cause any slow-downs.</p>
<p><picture style="flex:1.1983">
  <source srcset="/images/geordie-4_1000.webp 1000w, /images/geordie-4_1600.webp 1600w, /images/geordie-4_2000.webp 2000w" sizes="100vw" />
  <img src="/images/geordie-4_1000.webp" alt="geordiewood.com, mobile views" loading="lazy" />
</picture></p>
<p>The backend is very different, while the frontend is rendered almost entirely in the browser the backend is a more typical website. I use <a href="http://expressjs.com">Express</a> (I <em>am</em> a member of the <a href="https://github.com/orgs/expressjs/people">organisation</a> and an operator in the IRC channel #express after all), <a href="http://www.postgresql.org">Postgres</a> and a relative newcomer to the Node.js ORM scene: <a href="http://vincit.github.io/objection.js/">Objection.js</a>. Prior to this I'd been using <a href="http://bookshelfjs.org">Bookshelf</a> in all my projects but was increasingly dissatisfied with the way it forces a <a href="http://backbonejs.org">Backbone</a>-like structure on you and felt that it made too many things (such as validation and nested relations) harder to implement than they should've been.</p>
<p>The <a href="http://vincit.github.io/objection.js/">Objection documentation</a> is also a lot more thorough than Bookshelf's and an <a href="https://github.com/Vincit/objection.js/tree/master/examples">example repo</a> showing you how to write a basic site in ES5, ES6 and ES7 is an added bonus. Seeing as I was compiling everything anyway I took the ES7 route, allowing me to write code like:</p>
<pre><code class="language-js">router.get('/', async (req, res, next) => {
  const projects = await Project.query().orderBy('position')
  res.render('projects/index', {projects})
})
</code></pre>
<p>and:</p>
<pre><code class="language-js">const project = await Project.query()
  .where('id', +req.params.id)
  .eager(
    '[slides(orderByPosition), slides.images(orderByPosition)]',
    {orderByPosition}
  )
  .first()
</code></pre>
<p>(Objection's <a href="http://vincit.github.io/objection.js/#eager-queries">eager queries</a> make nested relations absolutely painless)</p>
<p>The main part of the backend is the drag-and-drop slide editor:</p>
<p><picture style="flex:1.3474">
  <source srcset="/images/geordie-5_1000.webp 1000w, /images/geordie-5_1600.webp 1600w, /images/geordie-5_2000.webp 2000w" sizes="100vw" />
  <img src="/images/geordie-5_1000.webp" alt="geordiewood.com, editor" loading="lazy" />
</picture></p>
<p><picture style="flex:1.3474">
  <source srcset="/images/geordie-6_1000.webp 1000w, /images/geordie-6_1600.webp 1600w, /images/geordie-6_2000.webp 2000w" sizes="100vw" />
  <img src="/images/geordie-6_1000.webp" alt="geordiewood.com, editor" loading="lazy" />
</picture></p>
<p>With this Geordie can simply upload images and drag and drop them into the layout grid. They fall where they're dropped &thinsp;&mdash;&thinsp; snapped to the nearest column &thinsp;&mdash;&thinsp; and a click can set their width. I used the standard HTML5 drag-and-drop API for this:</p>
<pre><code class="language-js">const onDragStart = e => {
  const {offsetX, offsetY} = e
  e.dataTransfer.effectAllowed = 'move'
  e.dataTransfer.setData('text/plain', JSON.stringify({offsetX, offsetY}))
}

const onDrop = e => {
  e.preventDefault()
  const {offsetX, offsetY} = JSON.parse(e.dataTransfer.getData('text'))
  // ...
}
</code></pre>
<p>The rest is just some maths to figure out which column we're on and then sending this data to the server. There's only two fields needed in the database for this; <code>columnsLeft</code> (the column number the image starts at) and <code>columnsWide</code> (the width of the image in columns). Everything else is extrapolated from this and our 16 column grid.</p>
<p><picture style="flex:1.3474">
  <source srcset="/images/geordie-7_1000.webp 1000w, /images/geordie-7_1600.webp 1600w, /images/geordie-7_2000.webp 2000w" sizes="100vw" />
  <img src="/images/geordie-7_1000.webp" alt="geordiewood.com, slide" loading="lazy" />
</picture></p>
<p>And that's the majority of it!</p>
<p>Thanks to Hassan and Geordie for being such a delight to work with, thanks ​<em>again</em> to <a href="https://twitter.com/_EricHu">Eric Hu</a> for setting me up with them and thanks to the <a href="https://snek.slack.com">snek</a> team on Slack for helping me brainstorm the best way to lay out the thumbnails.</p>
<p>If you have any questions about this project, or any other projects, get in touch with me via <a href="https://twitter.com/ccommma">twitter</a> or at <a href="mailto:ryan@artcommaco.de">ryan@artcommaco.de</a>.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[paintingid.com]]></title>
            <link>https://artcommaco.de/posts/2015-06-26-paintingid-dot-com.html</link>
            <guid>https://artcommaco.de/posts/2015-06-26-paintingid-dot-com.html</guid>
            <pubDate>Fri, 26 Jun 2015 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p><picture style="flex:1.5725">
  <source srcset="/images/painting-1_1000.webp 1000w, /images/painting-1_1600.webp 1600w, /images/painting-1_2000.webp 2000w" sizes="100vw" />
  <img src="/images/painting-1_1000.webp" alt="Painting ID website, painting page" loading="lazy" />
</picture></p>
<p><em>Update 06/16: paintingid.com has been turned off, but you can visit an archive of the site at <a href="http://paintingid.artcommaco.de">paintingid.artcommaco.de</a>.</em></p>
<p>I recently had the pleasure to work on <a href="http://paintingid.artcommaco.de">a website</a> for the NYC artist <a href="http://brendansmithstudio.com">Brendan Smith</a> with designers <a href="http://eeshirtay.com">Harry Gassel </a> and <a href="http://www.sethhoekstra.com">Seth Hoekstra</a> and 3D Illustrator <a href="http://www.jamesorlando.net">James Orlando</a>.</p>
<p>One of those short-notice jobs that always has the potential to become a nightmare it nontheless turned out to be a great time thanks to the professionalism of my main-point-of-contacts Harry and Seth. However, <a href="http://threejs.org">three.js</a> was another matter entirely. A mess of horrible documentation, awkward anti-patterns and hundreds of mutable variables it took me a week before I could even display a painting on the screen and when I did it looked something like this:</p>
<p><img src="/images/painting-2.png" alt="3D painting, broken render" /></p>
<p>After that it was a matter of figuring out rotations, positioning, texturing, hooking up controls and how to swap out colours and paintings on the fly. I then discovered how tricky it is to light a scene to show anything from white to bright purple to black. On the advice of <a href="https://twitter.com/aeleitch">a friend</a> I ended up going with two lights, a very dark blue-black ambient light and a very bright yellow-white directional light.</p>
<p>Despite the pains of three.js it was great to have the opportunity to learn some new skills.</p>
<p><picture style="flex:1.5725">
  <source srcset="/images/painting-3_1000.webp 1000w, /images/painting-3_1600.webp 1600w, /images/painting-3_2000.webp 2000w" sizes="100vw" />
  <img src="/images/painting-3_1000.webp" alt="Painting ID website, opening page" loading="lazy" />
</picture></p>
<p><picture style="flex:1.5725">
  <source srcset="/images/painting-4_1000.webp 1000w, /images/painting-4_1600.webp 1600w, /images/painting-4_2000.webp 2000w" sizes="100vw" />
  <img src="/images/painting-4_1000.webp" alt="Painting ID website, painting page" loading="lazy" />
</picture></p>
<p><picture style="flex:1.5725">
  <source srcset="/images/painting-5_1000.webp 1000w, /images/painting-5_1600.webp 1600w, /images/painting-5_2000.webp 2000w" sizes="100vw" />
  <img src="/images/painting-5_1000.webp" alt="Painting ID website, preview page" loading="lazy" />
</picture></p>
<p><picture style="flex:1.5725">
  <source srcset="/images/painting-6_1000.webp 1000w, /images/painting-6_1600.webp 1600w, /images/painting-6_2000.webp 2000w" sizes="100vw" />
  <img src="/images/painting-6_1000.webp" alt="Painting ID website, about page" loading="lazy" />
</picture></p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Development of 2015 in Development]]></title>
            <link>https://artcommaco.de/posts/2015-04-10-the-development-of-2015-in-development.html</link>
            <guid>https://artcommaco.de/posts/2015-04-10-the-development-of-2015-in-development.html</guid>
            <pubDate>Fri, 10 Apr 2015 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<ol>
<li>Less jQuery, more <a href="http://browserify.org">Browserify</a> and <a href="https://www.npmjs.com">npm</a> packages.</li>
<li>Less grunt and gulp, more <a href="/posts/2015-04-10-npm-directives.html">npm scripts</a>.</li>
<li>Less underscore and lodash, more <a href="http://ramdajs.com">Ramda</a> and pure JS.</li>
<li>Less Sublime Text, more Emacs, particularly with <a href="https://github.com/syl20bnr/spacemacs">Spacemacs</a>.</li>
<li>Less EJS and HTML, more Jade.</li>
<li>Less Node.js and JavaScript, more Clojure and ClojureScript.</li>
<li>Less MongoDB, more Postgres.</li>
<li>Less devops, more <a href="https://heroku.com">Heroku</a>.</li>
<li>Less note-taking apps, more Markdown.</li>
</ol>
<p>Overall I'm moving towards simpler, more focused tools that I can combine to produce smaller, more easier to understand packages.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[npm Directives]]></title>
            <link>https://artcommaco.de/posts/2015-04-10-npm-directives.html</link>
            <guid>https://artcommaco.de/posts/2015-04-10-npm-directives.html</guid>
            <pubDate>Fri, 10 Apr 2015 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<pre><code class="language-js">"scripts": {
   "build-js": "browserify src/js/script.js | uglifyjs -mc > build/js/script.js",
   "build-css": "cat src/css/*/*.css src/css/*.css | uglifycss > build/css/style.css",
   "build-html": "jade src/jade/*.jade -o build",
   "build": "npm run build-js &#x26;&#x26; npm run build-css &#x26;&#x26; npm run build-html",
   "watch-js": "watchify src/js/script.js -o build/js/script.js -dv",
   "watch-css": "catw src/css/*/*.css src/css/*.css -o build/css/style.css -v",
   "watch-html": "jade src/jade/*.jade -o build -w",
   "watch": "npm run watch-js &#x26; npm run watch-css &#x26; npm run watch-html",
   "start": "npm run build &#x26;&#x26; cd build; http-server",
   "start-dev": "npm run watch &#x26; npm start",
   "postinstall": "npm run build"
 }
</code></pre>
<p>I recently replaced my 100 line gulp file with 10 lines of npm directives which have already proven to be simpler and more reliable. </p>
<p>Not happy with the hacks that were piling up in my gulpfile.js I started looking at the alternatives. Makefiles are too magical for me but I haven't ruled them out completely. For anybody interested in using them I highly recommend James Coglan's post "<a href="https://blog.jcoglan.com/2014/02/05/building-javascript-projects-with-make/">Building JavaScript projects with Make</a>".</p>
<p>Instead I found substack's post "<a href="http://substack.net/task_automation_with_npm_run">task automation with npm run</a>" and have liberally copied from it. Because this current project is a static site and not one of my usual <a href="http://expressjs.com">Express</a> applications I've also added <a href="http://jade-lang.com/command-line/">Jade</a> to convert my .jade files to HTML and <a href="https://www.npmjs.com/package/http-server">http-server</a> to serve the site. </p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Doing Away with Express-Messages]]></title>
            <link>https://artcommaco.de/posts/2014-08-25-doing-away-with-express-messages.html</link>
            <guid>https://artcommaco.de/posts/2014-08-25-doing-away-with-express-messages.html</guid>
            <pubDate>Mon, 25 Aug 2014 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>Although I was recently appointed as a maintainer of <a href="https://github.com/expressjs/express-messages">express-messages</a> by the <a href="https://github.com/expressjs">expressjs</a> organisation I no longer use it any of my projects. There's a lot I don't particularly agree with – HTML as strings, lack of support for templating engines and particularly the way it locks you into a structure – but I can't deny it's been very useful to me in the past and I hope I can keep it that way for others in the future.</p>
<p>So I'm going to show you what I do instead. Lets get rid of that <code>app.use(require('express-messages')())</code> and replace it with:</p>
<pre><code class="language-js">app.use(function (req, res, next) {
  var flash = req.flash()
  res.locals.messages = Object.keys(flash).reduce(function (messages, type) {
    flash[type].forEach(function (message) {
      messages.push({type: type, message: message})
    })
    return messages
  }, [])
  next()
})
</code></pre>
<p>What we're doing here is taking the object of arrays generated by <a href="https://github.com/jaredhanson/connect-flash">connect-flash</a> and turning it into an array of objects so I don't have to do any fiddly logic to include it in my templates. If I'm using <a href="https://github.com/visionmedia/jade">Jade</a> (my personal favourite) I can do this: </p>
<pre><code class="language-js">ul.messages
  each message in messages
    li(class="#{message.type}")= message.message
</code></pre>
<p>and if I'm using <a href="https://github.com/visionmedia/ejs">EJS</a> I do this:</p>
<pre><code class="language-html">&#x3C;ul class="messages">
  &#x3C;% messages.forEach(function (message) { %>
    &#x3C;li class="&#x3C;%= message.type %>">&#x3C;%= message.message %>&#x3C;/li>
  &#x3C;% }) %>
&#x3C;/ul>
</code></pre>
<p>Now instead of asking <code>express-messages</code> to concatanate some strings into HTML for us to include as a function in our template we get a nice <code>messages</code> array on the <code>locals</code> object that we can include wherever and however we want.</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[A Type Driven Approach to Functional Design]]></title>
            <link>https://artcommaco.de/posts/2014-06-04-a-type-driven-approach-to-functional-design.html</link>
            <guid>https://artcommaco.de/posts/2014-06-04-a-type-driven-approach-to-functional-design.html</guid>
            <pubDate>Wed, 04 Jun 2014 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>Michael Feathers’ (<a href="https://twitter.com/mfeathers">@mfeathers</a>) “<a href="http://www.infoq.com/presentations/Type-Functional-Design">Type Driven Approach to Functional Design</a>” is a perfectly-sized 20 minute talk on how to think about solving design problems in a functional way.</p>
<p>It also serves as a gentle introduction to Haskell's <a href="http://learnyouahaskell.com/types-and-typeclasses">Type Annotation</a> which I personally find useful even when not working in Haskell, or in languages without proper typing at all! (JavaScript I'm looking at you)</p>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[The Right Solution to the Wrong Problem]]></title>
            <link>https://artcommaco.de/posts/2014-05-14-the-right-solution-to-the-wrong-problem.html</link>
            <guid>https://artcommaco.de/posts/2014-05-14-the-right-solution-to-the-wrong-problem.html</guid>
            <pubDate>Wed, 14 May 2014 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>So I thought I'd come up with a pretty neat solution to organising a collection of posts in the format "YYYY [title]" by year:</p>
<pre><code class="language-js">Collection.findAndPopulate({
  title: this.controller
}, function (error, collection) {
  if (error) return callback(error);
  collection.pages = _.filter(collection.pages, function (page) {
    return _.first(page.title.split(' ')) === req.params.year;
  });
  callback(null, collection.pages);
});
</code></pre>
<p>Pretty cool right? <a href="http://underscorejs.org/">Underscore</a> is great when working with lists. However, a few hours after pushing the new code to production I realised (while in the shower) I could've skipped the Underscore and just done:</p>
<pre><code class="language-js">Page.findAndPopulate({
  title: new RegExp('^' + req.params.year),
  collection: this.controller
}, callback);
</code></pre>]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Technical Papers]]></title>
            <link>https://artcommaco.de/posts/2014-05-13-technical-papers.html</link>
            <guid>https://artcommaco.de/posts/2014-05-13-technical-papers.html</guid>
            <pubDate>Tue, 13 May 2014 00:00:00 GMT</pubDate>
            <content:encoded><![CDATA[<p>I have many dozens of technical papers saved to my hard drive but I thought I'd open up with some links to a selection of great papers I found from <a href="http://rsms.me/">Rasmus Anderson</a>'s <a href="https://twitter.com/rsms">Twitter</a>:</p>
<ul>
<li><a href="https://www.dropbox.com/s/v95nri7awtieplf/A%20History%20of%20Haskell%20-%20Being%20Lazy%20With%20Class.pdf">A History of Haskell - Being Lazy With Class</a></li>
<li><a href="https://www.dropbox.com/s/4eeipdwgl4o1x08/Design%20of%20LISP-Based%20Processors%20%28AIM-514%29.pdf">Design of LISP-Based Processors (AIM-514)</a></li>
<li><a href="https://www.dropbox.com/s/7w11b2rznh2m9i7/Design%20Principles%20Behind%20Smalltalk.pdf">Design Principles Behind Smalltalk</a></li>
<li><a href="https://www.dropbox.com/s/1mhfnnn1hiogrnu/Kqueue%20-%20A%20generic%20and%20scalable%20event%20noti%EF%AC%81cation%20facility.pdf">Kqueue - A generic and scalable event notiﬁcation facility</a></li>
<li><a href="https://www.dropbox.com/s/s1jdcr8g383gkn8/Making%20reliable%20distributed%20systems%20in%20the%20presence%20of%20software%20errors%20%28Erlang%2C%20Armstrong%29.pdf">Making reliable distributed systems in the presence of software errors (Erlang, Armstrong)</a></li>
<li><a href="https://www.dropbox.com/s/0165ofhe9ccrkta/Organizing%20Programs%20Without%20Classes.pdf">Organizing Programs Without Classes</a></li>
<li><a href="https://www.dropbox.com/s/oaa0jsmaj9hdaqb/PC%20Assembly%20Language%20%28Paul%20A.%20Carter%2C%202001-2004%29.pdf">PC Assembly Language (Paul A. Carter, 2001-2004)</a></li>
<li><a href="https://www.dropbox.com/s/m2l9a1w51n2bvqe/Recursive%20Functions%20of%20Symbolic%20Expressions%20and%20Their%20Computation%20by%20Machine%2C%20Part%201%20%28John%20McCarthy%2C%20lisp%2C%201960%29.pdf">Recursive Functions of Symbolic Expressions and Their Computation by Machine, Part 1 (John McCarthy, lisp, 1960)</a></li>
<li><a href="https://www.dropbox.com/s/o0iiofe1zo3j5ki/RRB-Trees%20-%20Efficient%20Immutable%20Vectors.pdf">RRB-Trees - Efficient Immutable Vectors</a></li>
<li><a href="https://www.dropbox.com/s/9lz3tdf94gvmttt/Synthesis%20-%20An%20Efficient%20Implementation%20of%20Fundamental%20Operating%20System%20Services.pdf">Synthesis - An Efficient Implementation of Fundamental Operating System Services</a></li>
<li><a href="https://www.dropbox.com/s/pi0g4sgk6r3ra8h/The%20GrAIL%20language%20and%20operations.pdf">The GrAIL language and operations</a></li>
<li><a href="https://www.dropbox.com/s/vuxspyue6lca4jg/The%20Implementation%20of%20Lua%205.0.pdf">The Implementation of Lua 5.0</a></li>
<li><a href="https://www.dropbox.com/s/94fvc5ink5a7rb7/x86-64%20Machine-Level%20Programming%20%28CMU%29.pdf">x86-64 Machine-Level Programming (CMU)</a></li>
</ul>
<p>Of these already great papers, <a href="http://joearms.github.io/">Joe Armstrong</a>'s thesis “<a href="https://www.dropbox.com/s/s1jdcr8g383gkn8/Making%20reliable%20distributed%20systems%20in%20the%20presence%20of%20software%20errors%20%28Erlang%2C%20Armstrong%29.pdf">Making reliable distributed systems in the presence of software errors</a>” is my stand-out favourite. Written in a clear, concise manner it defines the problems he and his team were facing and goes on &thinsp;&mdash;&thinsp; through it's nearly 300 pages &thinsp;&mdash;&thinsp; to solve each of them. I could (and probably <em>should</em>) dedicate an entire post to this paper alone.</p>]]></content:encoded>
        </item>
    </channel>
</rss>