Skip to content

Instantly share code, notes, and snippets.

View cch1's full-sized avatar

Chris Hapgood cch1

  • Sun Tribe Trading
  • Center of the Universe
View GitHub Profile
@cch1
cch1 / schema.md
Created September 24, 2025 19:16
Why ensure schema as part of system startup?

I realize this is going to seem heretical, but here goes: there is value in ensuring schema as part of instance startup. At Sun Tribe, we've been doing it for years.

The biggest advantage is the ease of binding the schema to the code. When combined with a testing strategy that stands up an in-memory database from scratch (many times, in fact, while running the test suite), it's easy to guarantee that the schema and code are exactly that which will be eventually ensured and run in production. It's also easy to travel back in time locally (schema and code) by starting the system on a previous commit, sometimes making forensics a little easier.

I realize there are limitations with this approach. For example, long-running data corrections need to be carefully considered lest they block system startup for "too long". It's also important to have lifecycle hooks that can declare a startup failure and roll back a deploy (cough, cough... Datomic Ions). Otherwise a schema mismatch (really only possible if someo

@cch1
cch1 / gist:5919f52cbca92d366c30d5003066f153
Created September 24, 2025 19:15
Why ensure schema as part of system startup?
I realize this is going to seem heretical, but here goes: there is value in ensuring schema as part of instance startup. At Sun Tribe, we've been doing it for years.
The biggest advantage is the ease of binding the schema to the code. When combined with a testing strategy that stands up an in-memory database from scratch (many times, in fact, while running the test suite), it's easy to guarantee that the schema and code are exactly that which will be eventually ensured and run in production. It's also easy to travel back in time locally (schema and code) by starting the system on a previous commit, sometimes making forensics a little easier.
I realize there are limitations with this approach. For example, long-running data corrections need to be carefully considered lest they block system startup for "too long". It's also important to have lifecycle hooks that can declare a startup failure and roll back a deploy (cough, cough... Datomic Ions). Otherwise a schema mismatch (really only possible if someo
@cch1
cch1 / template.clj
Created June 23, 2021 19:57
An example of a simple templating capability that heavily leverages built-in features of clojure.
(ns template
(:require [clojure.edn :as edn]
[clojure.string :as string]))
;; Tagged literals do not need to be limited to being represented by a single string. Here we represent a value with a tuple of `magic` and `value`.
(defn read-magic [[magic value]]
(case magic
:c (string/capitalize value)
:l (string/lower-case value)
:u (string/upper-case value)))
@cch1
cch1 / test_helpers.clj
Last active December 31, 2015 00:09
feedback streams
(ns test-helpers
(:import [java.io InputStream OutputStream IOException])
(:require [clojure.java.io :as io]))
(defn- swap-!
"Atomically swaps the value of atom to be:
(apply f current-value-of-atom args). Note that f may be called
multiple times, and thus should be free of side effects. Returns
the value prior to the update."
[a f & args]
@cch1
cch1 / pick-and-rename.clj
Created July 30, 2012 17:07 — forked from edw/pick-and-rename.clj
Let-Over-Lambda
(let [undefined-value (atom :undefined-value)]
(defn pick-and-rename [col pick-map]
(apply assoc
{}
(flatten
(filter (fn [[k v]]
(not (= v undefined-value)))
(map (fn [[k v]]
[v (get col k undefined-value)])
pick-map))))))
@cch1
cch1 / mocking-ex.clj
Created February 6, 2012 21:43 — forked from mwmitchell/mocking-ex.clj
with metaconstants
(facts "/locations/:id/rates should limit the rate response count by the :limit param"
(let [params [:check_in (gen-check-in)
:check_out (gen-check-out)
:guests 1
:rooms 1
:limit ...limit...]]
(apply location-rate-request (:tid location-one) params) => truthy
(provided
(apij.models.hotel-search/search
(contains {:params (contains {:limit apij.views.rates.common/max-hotels})}))
;;(require 'copterj.git-version) ;; Pick up DRY'd version numbers
(require 'clojure.contrib.io) ;; Needed to locate newrelic
(let [java-agent (str "-javaagent:" (clojure.contrib.io/pwd) "/lib/newrelic.jar")]
(defproject apij ~(copterj.git-version/git-describe)
:description "Hotelicopter's API"
:dependencies
[[com.hotelicopter/copterj "1.0.0-SNAPSHOT"]
@cch1
cch1 / Emacs.md
Created May 6, 2011 20:45
Setting up Emacs daemon on OS X

Setting up Emacs daemon on OS X

Tired of waiting for emacs to start on OS X? This step by step guide will teach you how to install the latest version of emacs and configure it to start in the background (daemon mode) and use emacsclient as your main editor.

Install Homebrew

First you'll need to install the [Homebrew package manager][brew] if yo haven't already. It is amazing.

@cch1
cch1 / deploy.rb
Created October 19, 2010 19:05
Post-Migration version
# Please install the Engine Yard Capistrano gem
# gem install eycap --source http://gems.engineyard.com
require "eycap/recipes"
require 'new_relic/recipes'
# The following code has been lifted from config.rb
AppConfig = begin
require 'ostruct'
require 'yaml'
From 36f25bf11b9e61b6361c829534dea2de0cf08acd Mon Sep 17 00:00:00 2001
From: Chris Hapgood <[email protected]>
Date: Mon, 11 Oct 2010 09:42:05 -0400
Subject: [PATCH] Let respond_to do the heavy action cache lifting
In determining the best content type for a response, let respond_to consider
available content types using existing logic. Work hard to ensure that
cached content has an extension to indicate its content type.
---
.../lib/action_controller/caching/actions.rb | 73 ++++++++++----------