diff --git a/.netlify/functions-internal/render.js b/.netlify/functions-internal/render.js new file mode 100644 index 0000000..a61fb1f --- /dev/null +++ b/.netlify/functions-internal/render.js @@ -0,0 +1,73 @@ +const { init } = require('../handler.js'); + +exports.handler = init({ + appDir: "_app", + assets: new Set(["FivoSansModern-Regular.otf","SpaceGrotesk-Regular.woff2","favicon.png","normalize.css","thomaswilson.css"]), + mimeTypes: {".otf":"font/otf",".woff2":"font/woff2",".png":"image/png",".css":"text/css"}, + _: { + entry: {"file":"start-04adc41e.js","js":["start-04adc41e.js","chunks/index-a4575d00.js"],"css":[]}, + nodes: [ + () => Promise.resolve().then(() => require('../server/nodes/0.js')), + () => Promise.resolve().then(() => require('../server/nodes/1.js')), + () => Promise.resolve().then(() => require('../server/nodes/5.js')), + () => Promise.resolve().then(() => require('../server/nodes/4.js')), + () => Promise.resolve().then(() => require('../server/nodes/3.js')), + () => Promise.resolve().then(() => require('../server/nodes/2.js')) + ], + routes: [ + { + type: 'page', + id: "", + pattern: /^\/$/, + names: [], + types: [], + path: "/", + shadow: null, + a: [0,2], + b: [1] + }, + { + type: 'page', + id: "blog", + pattern: /^\/blog\/?$/, + names: [], + types: [], + path: "/blog", + shadow: null, + a: [0,3], + b: [1] + }, + { + type: 'endpoint', + id: "api/blog.json", + pattern: /^\/api\/blog\.json$/, + names: [], + types: [], + load: () => Promise.resolve().then(() => require('../server/entries/endpoints/api/blog.json.ts.js')) + }, + { + type: 'endpoint', + id: "api/blog/[slug].json", + pattern: /^\/api\/blog\/([^/]+?)\.json$/, + names: ["slug"], + types: [null], + load: () => Promise.resolve().then(() => require('../server/entries/endpoints/api/blog/_slug_.json.ts.js')) + }, + { + type: 'page', + id: "blog/[slug]", + pattern: /^\/blog\/([^/]+?)\/?$/, + names: ["slug"], + types: [null], + path: null, + shadow: null, + a: [0,null,4], + b: [1,5] + } + ], + matchers: async () => { + + return { }; + } + } +}); diff --git a/.netlify/handler.js b/.netlify/handler.js new file mode 100644 index 0000000..da1bbb4 --- /dev/null +++ b/.netlify/handler.js @@ -0,0 +1,105 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +require('./shims.js'); +var _0SERVER = require('./server/index.js'); +require('node:http'); +require('node:https'); +require('node:zlib'); +require('node:stream'); +require('node:util'); +require('node:url'); +require('net'); + +/** + * Splits headers into two categories: single value and multi value + * @param {Headers} headers + * @returns {{ + * headers: Record, + * multiValueHeaders: Record + * }} + */ +function split_headers(headers) { + /** @type {Record} */ + const h = {}; + + /** @type {Record} */ + const m = {}; + + headers.forEach((value, key) => { + if (key === 'set-cookie') { + // @ts-expect-error (headers.raw() is non-standard) + m[key] = headers.raw()[key]; + } else { + h[key] = value; + } + }); + + return { + headers: h, + multiValueHeaders: m + }; +} + +/** + * @param {import('@sveltejs/kit').SSRManifest} manifest + * @returns {import('@netlify/functions').Handler} + */ +function init(manifest) { + const server = new _0SERVER.Server(manifest); + + return async (event, context) => { + const rendered = await server.respond(to_request(event), { + platform: { context }, + getClientAddress() { + return event.headers['x-nf-client-connection-ip']; + } + }); + + const partial_response = { + statusCode: rendered.status, + ...split_headers(rendered.headers) + }; + + // TODO this is probably wrong now? + if (rendered.body instanceof Uint8Array) { + // Function responses should be strings (or undefined), and responses with binary + // content should be base64 encoded and set isBase64Encoded to true. + // https://github.com/netlify/functions/blob/main/src/function/response.ts + return { + ...partial_response, + isBase64Encoded: true, + body: Buffer.from(rendered.body).toString('base64') + }; + } + + return { + ...partial_response, + body: await rendered.text() + }; + }; +} + +/** + * @param {import('@netlify/functions').HandlerEvent} event + * @returns {Request} + */ +function to_request(event) { + const { httpMethod, headers, rawUrl, body, isBase64Encoded } = event; + + /** @type {RequestInit} */ + const init = { + method: httpMethod, + headers: new Headers(headers) + }; + + if (httpMethod !== 'GET' && httpMethod !== 'HEAD') { + const encoding = isBase64Encoded ? 'base64' : 'utf-8'; + init.body = typeof body === 'string' ? Buffer.from(body, encoding) : body; + } + + return new Request(rawUrl, init); +} + +exports.init = init; diff --git a/.netlify/multipart-parser-431aff0b.js b/.netlify/multipart-parser-431aff0b.js new file mode 100644 index 0000000..2b344ce --- /dev/null +++ b/.netlify/multipart-parser-431aff0b.js @@ -0,0 +1,451 @@ +'use strict'; + +require('node:fs'); +require('node:path'); +var node_worker_threads = require('node:worker_threads'); +var shims = require('./shims.js'); +require('node:http'); +require('node:https'); +require('node:zlib'); +require('node:stream'); +require('node:util'); +require('node:url'); +require('net'); + +globalThis.DOMException || (() => { + const port = new node_worker_threads.MessageChannel().port1; + const ab = new ArrayBuffer(0); + try { port.postMessage(ab, [ab, ab]); } catch (err) { return err.constructor } +})(); + +let s = 0; +const S = { + START_BOUNDARY: s++, + HEADER_FIELD_START: s++, + HEADER_FIELD: s++, + HEADER_VALUE_START: s++, + HEADER_VALUE: s++, + HEADER_VALUE_ALMOST_DONE: s++, + HEADERS_ALMOST_DONE: s++, + PART_DATA_START: s++, + PART_DATA: s++, + END: s++ +}; + +let f = 1; +const F = { + PART_BOUNDARY: f, + LAST_BOUNDARY: f *= 2 +}; + +const LF = 10; +const CR = 13; +const SPACE = 32; +const HYPHEN = 45; +const COLON = 58; +const A = 97; +const Z = 122; + +const lower = c => c | 0x20; + +const noop = () => {}; + +class MultipartParser { + /** + * @param {string} boundary + */ + constructor(boundary) { + this.index = 0; + this.flags = 0; + + this.onHeaderEnd = noop; + this.onHeaderField = noop; + this.onHeadersEnd = noop; + this.onHeaderValue = noop; + this.onPartBegin = noop; + this.onPartData = noop; + this.onPartEnd = noop; + + this.boundaryChars = {}; + + boundary = '\r\n--' + boundary; + const ui8a = new Uint8Array(boundary.length); + for (let i = 0; i < boundary.length; i++) { + ui8a[i] = boundary.charCodeAt(i); + this.boundaryChars[ui8a[i]] = true; + } + + this.boundary = ui8a; + this.lookbehind = new Uint8Array(this.boundary.length + 8); + this.state = S.START_BOUNDARY; + } + + /** + * @param {Uint8Array} data + */ + write(data) { + let i = 0; + const length_ = data.length; + let previousIndex = this.index; + let {lookbehind, boundary, boundaryChars, index, state, flags} = this; + const boundaryLength = this.boundary.length; + const boundaryEnd = boundaryLength - 1; + const bufferLength = data.length; + let c; + let cl; + + const mark = name => { + this[name + 'Mark'] = i; + }; + + const clear = name => { + delete this[name + 'Mark']; + }; + + const callback = (callbackSymbol, start, end, ui8a) => { + if (start === undefined || start !== end) { + this[callbackSymbol](ui8a && ui8a.subarray(start, end)); + } + }; + + const dataCallback = (name, clear) => { + const markSymbol = name + 'Mark'; + if (!(markSymbol in this)) { + return; + } + + if (clear) { + callback(name, this[markSymbol], i, data); + delete this[markSymbol]; + } else { + callback(name, this[markSymbol], data.length, data); + this[markSymbol] = 0; + } + }; + + for (i = 0; i < length_; i++) { + c = data[i]; + + switch (state) { + case S.START_BOUNDARY: + if (index === boundary.length - 2) { + if (c === HYPHEN) { + flags |= F.LAST_BOUNDARY; + } else if (c !== CR) { + return; + } + + index++; + break; + } else if (index - 1 === boundary.length - 2) { + if (flags & F.LAST_BOUNDARY && c === HYPHEN) { + state = S.END; + flags = 0; + } else if (!(flags & F.LAST_BOUNDARY) && c === LF) { + index = 0; + callback('onPartBegin'); + state = S.HEADER_FIELD_START; + } else { + return; + } + + break; + } + + if (c !== boundary[index + 2]) { + index = -2; + } + + if (c === boundary[index + 2]) { + index++; + } + + break; + case S.HEADER_FIELD_START: + state = S.HEADER_FIELD; + mark('onHeaderField'); + index = 0; + // falls through + case S.HEADER_FIELD: + if (c === CR) { + clear('onHeaderField'); + state = S.HEADERS_ALMOST_DONE; + break; + } + + index++; + if (c === HYPHEN) { + break; + } + + if (c === COLON) { + if (index === 1) { + // empty header field + return; + } + + dataCallback('onHeaderField', true); + state = S.HEADER_VALUE_START; + break; + } + + cl = lower(c); + if (cl < A || cl > Z) { + return; + } + + break; + case S.HEADER_VALUE_START: + if (c === SPACE) { + break; + } + + mark('onHeaderValue'); + state = S.HEADER_VALUE; + // falls through + case S.HEADER_VALUE: + if (c === CR) { + dataCallback('onHeaderValue', true); + callback('onHeaderEnd'); + state = S.HEADER_VALUE_ALMOST_DONE; + } + + break; + case S.HEADER_VALUE_ALMOST_DONE: + if (c !== LF) { + return; + } + + state = S.HEADER_FIELD_START; + break; + case S.HEADERS_ALMOST_DONE: + if (c !== LF) { + return; + } + + callback('onHeadersEnd'); + state = S.PART_DATA_START; + break; + case S.PART_DATA_START: + state = S.PART_DATA; + mark('onPartData'); + // falls through + case S.PART_DATA: + previousIndex = index; + + if (index === 0) { + // boyer-moore derrived algorithm to safely skip non-boundary data + i += boundaryEnd; + while (i < bufferLength && !(data[i] in boundaryChars)) { + i += boundaryLength; + } + + i -= boundaryEnd; + c = data[i]; + } + + if (index < boundary.length) { + if (boundary[index] === c) { + if (index === 0) { + dataCallback('onPartData', true); + } + + index++; + } else { + index = 0; + } + } else if (index === boundary.length) { + index++; + if (c === CR) { + // CR = part boundary + flags |= F.PART_BOUNDARY; + } else if (c === HYPHEN) { + // HYPHEN = end boundary + flags |= F.LAST_BOUNDARY; + } else { + index = 0; + } + } else if (index - 1 === boundary.length) { + if (flags & F.PART_BOUNDARY) { + index = 0; + if (c === LF) { + // unset the PART_BOUNDARY flag + flags &= ~F.PART_BOUNDARY; + callback('onPartEnd'); + callback('onPartBegin'); + state = S.HEADER_FIELD_START; + break; + } + } else if (flags & F.LAST_BOUNDARY) { + if (c === HYPHEN) { + callback('onPartEnd'); + state = S.END; + flags = 0; + } else { + index = 0; + } + } else { + index = 0; + } + } + + if (index > 0) { + // when matching a possible boundary, keep a lookbehind reference + // in case it turns out to be a false lead + lookbehind[index - 1] = c; + } else if (previousIndex > 0) { + // if our boundary turned out to be rubbish, the captured lookbehind + // belongs to partData + const _lookbehind = new Uint8Array(lookbehind.buffer, lookbehind.byteOffset, lookbehind.byteLength); + callback('onPartData', 0, previousIndex, _lookbehind); + previousIndex = 0; + mark('onPartData'); + + // reconsider the current character even so it interrupted the sequence + // it could be the beginning of a new sequence + i--; + } + + break; + case S.END: + break; + default: + throw new Error(`Unexpected state entered: ${state}`); + } + } + + dataCallback('onHeaderField'); + dataCallback('onHeaderValue'); + dataCallback('onPartData'); + + // Update properties for the next call + this.index = index; + this.state = state; + this.flags = flags; + } + + end() { + if ((this.state === S.HEADER_FIELD_START && this.index === 0) || + (this.state === S.PART_DATA && this.index === this.boundary.length)) { + this.onPartEnd(); + } else if (this.state !== S.END) { + throw new Error('MultipartParser.end(): stream ended unexpectedly'); + } + } +} + +function _fileName(headerValue) { + // matches either a quoted-string or a token (RFC 2616 section 19.5.1) + const m = headerValue.match(/\bfilename=("(.*?)"|([^()<>@,;:\\"/[\]?={}\s\t]+))($|;\s)/i); + if (!m) { + return; + } + + const match = m[2] || m[3] || ''; + let filename = match.slice(match.lastIndexOf('\\') + 1); + filename = filename.replace(/%22/g, '"'); + filename = filename.replace(/&#(\d{4});/g, (m, code) => { + return String.fromCharCode(code); + }); + return filename; +} + +async function toFormData(Body, ct) { + if (!/multipart/i.test(ct)) { + throw new TypeError('Failed to fetch'); + } + + const m = ct.match(/boundary=(?:"([^"]+)"|([^;]+))/i); + + if (!m) { + throw new TypeError('no or bad content-type header, no multipart boundary'); + } + + const parser = new MultipartParser(m[1] || m[2]); + + let headerField; + let headerValue; + let entryValue; + let entryName; + let contentType; + let filename; + const entryChunks = []; + const formData = new shims.FormData(); + + const onPartData = ui8a => { + entryValue += decoder.decode(ui8a, {stream: true}); + }; + + const appendToFile = ui8a => { + entryChunks.push(ui8a); + }; + + const appendFileToFormData = () => { + const file = new shims.File(entryChunks, filename, {type: contentType}); + formData.append(entryName, file); + }; + + const appendEntryToFormData = () => { + formData.append(entryName, entryValue); + }; + + const decoder = new TextDecoder('utf-8'); + decoder.decode(); + + parser.onPartBegin = function () { + parser.onPartData = onPartData; + parser.onPartEnd = appendEntryToFormData; + + headerField = ''; + headerValue = ''; + entryValue = ''; + entryName = ''; + contentType = ''; + filename = null; + entryChunks.length = 0; + }; + + parser.onHeaderField = function (ui8a) { + headerField += decoder.decode(ui8a, {stream: true}); + }; + + parser.onHeaderValue = function (ui8a) { + headerValue += decoder.decode(ui8a, {stream: true}); + }; + + parser.onHeaderEnd = function () { + headerValue += decoder.decode(); + headerField = headerField.toLowerCase(); + + if (headerField === 'content-disposition') { + // matches either a quoted-string or a token (RFC 2616 section 19.5.1) + const m = headerValue.match(/\bname=("([^"]*)"|([^()<>@,;:\\"/[\]?={}\s\t]+))/i); + + if (m) { + entryName = m[2] || m[3] || ''; + } + + filename = _fileName(headerValue); + + if (filename) { + parser.onPartData = appendToFile; + parser.onPartEnd = appendFileToFormData; + } + } else if (headerField === 'content-type') { + contentType = headerValue; + } + + headerValue = ''; + headerField = ''; + }; + + for await (const chunk of Body) { + parser.write(chunk); + } + + parser.end(); + + return formData; +} + +exports.toFormData = toFormData; diff --git a/.netlify/package.json b/.netlify/package.json new file mode 100644 index 0000000..0292b99 --- /dev/null +++ b/.netlify/package.json @@ -0,0 +1 @@ +{"type":"commonjs"} \ No newline at end of file diff --git a/.netlify/server/chunks/2016-02-28-eating-disorder-powerful-0af4a0ee.js b/.netlify/server/chunks/2016-02-28-eating-disorder-powerful-0af4a0ee.js new file mode 100644 index 0000000..afcb014 --- /dev/null +++ b/.netlify/server/chunks/2016-02-28-eating-disorder-powerful-0af4a0ee.js @@ -0,0 +1,61 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2016_02_28_eating_disorder_powerful, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "My eating disorder was dangerous because it was\xA0powerful (feat. hip hop\xA0lyrics.)", + "author": "Thomas Wilson", + "draft": true, + "slug": "2016-eating-disorder-awareness-week", + "date": "2019-02-28T00:00:00.000Z", + "tags": ["eating-disorder"] +}; +const _2016_02_28_eating_disorder_powerful = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return ` +

This post is published right at the tail-end of Eating Disorder Awareness Week 2016. It has been inspired by a lot of people\u2019s choices to share their experiences with EDs. I\u2019m trying to do the same: just share my experiences, and how my personal relationship with food and mental health have impacted my life. I\u2019ve also been unsure if I should publish this on my personal Medium blog (and therefore associate it with me and my professional work and personal identity). Ultimately I think it\u2019s important to see how mental health and ED can affect anyone. It simply wouldn\u2019t be the same if I published this anonymously. Within reason, experience with mental health or ED doesn\u2019t put any limits on the kind or quality of work you can pursue\u200A-\u200Athis is something I want to showcase with actions, not just sentiments. I also think it\u2019s important to represent the male corner of this conversation (not that I in any way feel under-represented or pushed into submission). With that in mind I hope any future employers or professionals can see this for what it\u2019s intended to be.

+

Me and food have had a funny relationship since I was little and terrified of choking (still can\u2019t swallow pills). Like all things it changed with me in life. Depression hasn\u2019t left since aged around 19, and at 24 now anxiety\u2019s joining the party a bit too often for my liking\u200A-\u200Abut I guess I\u2019m too much of a polite host to ask it to leave. These are important because, for me at least, my relationship with food was never the problem, it\u2019s just been a coping mechanism. Feel sad? Don\u2019t eat. Feel stressed? Maybe eat less? Uncomfortable with the fact you\u2019re 24 and still get the same acne you did when you were 16? Yeah, definitely eat less. +I only really came to terms with the fact that this isn\u2019t what everyone does when I was about 21. That\u2019s one of the dangers with mental health\u200A-\u200Athat it\u2019s not possible to simply be someone else, so you don\u2019t know what\u2019s unusual, or what you should watch out for. An interesting point, and one that highlights heavily the importance but difficulty of empathy, but not the one I\u2019m trying to make. +As with any social or human problem, the range of possible factors and causes in eating disorders is huge. This doesn\u2019t detract from anyone\u2019s pain\u200A-\u200Athat\u2019s not even an argument worth having. If someone is homeless because of substance abuse, immigration, or complete lack of financial resources\u200A-\u200Anone of these detract from the problem of homelessness, or suggest that we shouldn\u2019t help someone. I\u2019ve spoken to people who have eating disorders they attribute to the need for control, feelings of security, anxiety-coping mechanisms, guilt, and body dysmorphia. This is not an extensive list. +You ain\u2019t worth more cause you got more stuff. I don\u2019t care what the colour of your skin is. I don\u2019t care \u2018bout your fortune and fame. I just want for us to have more perspective. And understand that everybody\u2019s pain is the same. (Perspective\u200A-\u200ABlueprint) +Because I never wanted to be super skinny, because I never strictly restricted my calorie intake, because I never went through binge-purge-restrict cycles, I did not believe myself to have any kind of eating disorder. But I do not have a healthy relationship with food, and the absence of all these factors does nothing to argue against that. +The past 6 months of my life have undoubtedly been some of the most turbulent. I left (not by choice) a relationship, and with that I lost one of my most valued supports for dealing with my ED. I lost someone who understood better than most what it\u2019s like, but also knew exactly how little tolerance to have for it (spoiler: it was none). +Even though starving myself was never a thing in its own right, I had a lot to cope with and very little to stop me. Quite predictably I spiralled, and for some reason my urge to simply not eat changed into a need to over exercise. In retrospect it\u2019s not a surprise things didn\u2019t go so well. +Going to the gym 3 times a day and eating 20% below the RDA (probably about 30\u201340% what I should be eating) is bad for your health. But this wasn\u2019t about calories for me, this wasn\u2019t about losing weight, or gaining muscles, these were just side effects. I did it because I couldn\u2019t not. +I was like a toddler in an increasingly small doctor\u2019s waiting room\u200A-\u200AI had too much energy and started bouncing off the walls (bedroom, office, bus, any wall really). +The danger of my situation that it made me incredibly powerful. It put me at the top of my game. It\u2019s like drug use. People talk about the long-term health effects, but if it wasn\u2019t for the short-term incredibly desirable effects, we wouldn\u2019t see the problem with substance abuse that we do today. +At the most simple level: if you\u2019re running 10k every day, you get better at running 10k. If you\u2019re lifting weights every evening, you can start to lift heavier things. +This is how I justified my behaviours to myself. How can I be unhealthy when I am physically, unquestionably, demonstrably, the most fit I have ever been in my life? I\u2019m getting complements from friends about my body, people are noticing an improvement in my strength and performance. I was hitting personal best 5k and 10k literally every week. +Have you ever heard athletes talk about their training schedule? It\u2019s crazy, but they\u2019re good and they\u2019re proud, and no one\u2019s telling them to stop. Have you ever heard anyone successful talk about how they got there, about the sacrifice, devotion, and difficulties? If you want to be good at something you put in hard work, and sacrifice comfort and security. If you\u2019re getting good at something, you\u2019re not supposed to be comfortable. Is what I told myself. +Long hours, lack of sleep, writing paragraphs for weeks\u2026 Trading my social life to writing bars with preciseness (Understand\u200A-\u200ARashad & Confidence) +This started bleeding over into other areas of my life. I dance. I started attending workshops for professional and graduate dancers (I am neither of those things). I started choreographing my own work, and corresponding with producers who work with graduate and emerging artists. I started attending as many classes as I could, looking obsessively to find workshops I could wing myself into. I was travelling to the theatre to watch live dance at least every other week. The results? I was in the best place with dance I\u2019ve ever been in my life. I was the most creatively fulfilled and challenged I\u2019ve ever been, and I was simply happy proud of the quality of my movement. +With my Ph.D. and work in web-development I would sit down and just work for hours. I had exhausted my body to the point of physical damage, I had no choice but to sit very still and do a lot of work. The quiet introverted kind of work where you can\u2019t be distracted. I started taking risks and setting ambitions much higher than I had done before. And I met them. I was producing new software, reading a great deal of literature, and subsequently conducting my most planned research I had ever done in my life. I felt on top of my Ph.D., and I was achieving the things I wanted to do. +All of these things were fuelled almost solely by the thing that underlies my relationship with food, and so I suppose my eating disorder (whatever that is). The voice inside my head that told me I simply couldn\u2019t do anything until it physically hurt to move, and kind of ached when you sat still. This is obviously physically dangerous, but the real danger was that the voice followed up on its promise: I was incredibly focused and by literally everything I valued in my life (fitness, dance, and my studies) I was doing well. I was doing really well. +There is no explanation or solution. I can\u2019t tell you how I started to realise I was making ultimately bad decisions. In truth I still don\u2019t fully think I was\u200A-\u200AI\u2019m a stronger, more experienced, and focused person because of it. But at the same time, I know that if I had carried on down that road with my head down it would have gone badly. I was falling into bed every night, and would role out in the morning. I am not joking or exaggerating, I was taking every resource my body could find, and exhausting it every day. I was praying and meditating every day that this will end, that I wouldn\u2019t wake up tomorrow feeling like I have to physically defeat myself just to function. +Nothing hit me until I started seeing concern in my friends. I have 4 people in my life who I see as my true friends. These are people I trust and respect more than myself. They are all people I love at a very deep level. All of them became obviously distressed when I would talk about my life or wellbeing during this phase. Two of them asked me to consider going to counselling or seeking professional help. This is when I realised I have not made a sustainable choice. This cannot go on forever. This is unhealthy and bad for me, even if it\u2019s doing me so much good. +It\u2019s only been about a month since I made a conscious decision to get out of that place. In that time I\u2019ve realised that i) I have to start being selfish, and ii) Wherever I am, or anyone else is, in life\u200A-\u200Ait\u2019s temporary, and it\u2019s where we\u2019re supposed to be. Living with an unusual mental health landscape isn\u2019t something that changes with any urgency, and seeing myself lose fitness, and skill in dance is hard. But my outlook is changing. I feel myself wanting to forcibly start controlling my life agin\u200A-\u200Aand this is the danger of eating disorders in my life. +Then I think back to when I was 22 and breaking up with the first girl I ever truly deeply loved in a mother-of-my-children kind of way. And I think back to the year that came after that, and how all I wanted it to do was end. I thought back to desperately searching for my purpose in my final year of my master\u2019s degree. I look back on when I really started pushing contemporary dance as part of my life, and wanted desperately to improve. +Whenever we look at things in retrospect we lose the immediacy or urgency that are all we think about in the moment. In 3 years I\u2019ll be 27. I know that 27 year old me will tell 24 year old me exactly the same as what 24 year old me tells 22 year old me: be patient. Whatever needs to happen will happen. I am demonstrably not the most trustworthy person to be making decisions about how I should live my life. I should stop trying to make those decisions. +Simz talk to the younger Simz what would you tell her? Try make a mil \u2018fore you get a deal. See nothing\u2019s impossible long as you keep your head up. And when it comes to the points where you\u2019re fed up. Take a step\xA0back. +What would you say To the younger you? Would you tell you to be patient? Would you say to be true? (Time Capsule\u200A-\u200ALittle Simz & Caitlyn Scarlett)

`; +}); diff --git a/.netlify/server/chunks/2017-03-03-loss-and-ed-d4b1c1a5.js b/.netlify/server/chunks/2017-03-03-loss-and-ed-d4b1c1a5.js new file mode 100644 index 0000000..77d7669 --- /dev/null +++ b/.netlify/server/chunks/2017-03-03-loss-and-ed-d4b1c1a5.js @@ -0,0 +1,89 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2017_03_03_loss_and_ed, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Loss and my ED\u200A (\u200AED awareness week\xA02017)", + "author": "Thomas Wilson", + "draft": true, + "date": "2017-03-03T00:00:00.000Z", + "slug": "loss-and-ed-2017", + "tags": ["eating-disorder"] +}; +const _2017_03_03_loss_and_ed = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return ` +

Last year I wrote a piece for Eating Disorder Awareness Week 2016. Twelve months of living later and things aren\u2019t the same as they were.

+

To recap, twelve months ago I was several months out of an abrupt breakup, which saw me lose a big part of my support network. It turns out that when I\u2019m left to my own devices I\u2019ll try and wear my body town until most or all of it hurts as I lay in bed at night, asking why I keep making bad decisions. I did this because it brought me to some extreme levels of focus in my personal and professional life. An accidental outcome of that was an unhealthy calorie deficit. I\u2019m not sure if what I have is strictly an eating disorder. I think at that point we\u2019re arguing semantics, though, because it\u2019s probably not normal.

+

Losing it

+

Some time around March-April last year, I slipped after a few weeks of progress (more food and sleep, less running). I have vivid memories of sitting, in tears, in my room, on Skype to a dear friend.

+

I very rarely get angry. Frustration or impatience are well known, but to be truly deeply angry at a person, for a very distinct and obvious action\u200A-\u200Athat was a very unwelcome and new feeling for me. I felt angry that someone could do something, and then appear to just not acknowledge it and move on. If you\u2019re mean you say you\u2019re sorry. If you\u2019ve taken my mental and physical stability from me then you\u2019ve been (perhaps unintentionally) really quite rude.

+

What struck me is that nothing seems to stop me from feeling these pains. That is: when I\u2019m in a bad place, I always feel the same kind of bad. It\u2019s like I said last year\u200A-\u200Amy brain is a toddler in a waiting room, I have to get out. As far as I can tell, this will be the pain I feel for the rest of my life (that section of it where I\u2019m in pain, at least). Acknowledging that was hard. Very hard.

+

Losing dance

+

Until the last nine months, contemporary dance made up an exceptional part of my life. I was dancing four-five days a week, most weeks. This involved open and professional classes and workshops (in the case of the latter, it involved a bit of creative lying).

+

For me, dance has always required a monastic devotion: ultimate focus on my current actions, while lining up the next 10, 30, or 60 seconds of movement in my head. Picking out moments and extensions I could sink into. A sense that my body existed to move this way, and for a very short period of time my body was not my own. That\u2019s pretty appealing when you\u2019re seemingly trying to erode your body.

+

Around the time I wrote the last article I began to realise that being in a dance studio wasn\u2019t making me happy. Attending classes with your recently ex-girlfriend while you\u2019re simultaneously excelling and nose-diving isn\u2019t something I can describe. It guess it was like trying to fly a plane through a thunderstorm. I don\u2019t know where I was or if I was going forwards or downwards. Sometimes I would just have to leave the space at a minute\u2019s notice, because I couldn\u2019t be in there any more.

+

So I stopped attending classes at my university. So now I\u2019m dancing at most three times a week. I stop seeing progress and start plateauing. I\u2019m frustrated that I can\u2019t pick up choreography quickly, I\u2019m lagging in routines, my technique isn\u2019t as sharp as it was. And there\u2019s nothing I can do about it. I have ideas, I\u2019m trying to work on choreographic pieces, pieces that I feel really passionate about\u200A-\u200Abut what\u2019s the point when you can\u2019t even do your own ideas justice?

+

So I made the decision to stop dancing. Beyond a shadow of a doubt, dance saved my life. Knowing I had a class to attend, or an upcoming workshop, or that there\u2019s a weekly choreography course starting 40 minutes away and that you could definitely make it back in time if you got the last train\u2026 When these 60\u201390 minute periods are your islands, you become very concerned when the sea level rises. But they were putting me in a worse place, so I had to stop.

+

This has freed up time for me to focus on acroyoga (or sports acro)\u200A-\u200Aa mixture between partner acrobatics and yoga. Twelve months later and I am paid (a symbolic amount) to teach every week, I get to introduce people to something I love on a weekly basis, I train with people who treat me better than I deserve, and I can find moments of complete peace and calm. These moments are no longer mid-pirouette, but in some other equally obscure position, often on some else\u2019s feet.

+

I\u2019ve recently started seeing dance again. I\u2019m realising that a dance studio is different when it\u2019s full of people. Dancers who are driven by their selves or by competition act very differently to artists in a studio with an idea. I\u2019m realising it wasn\u2019t dance that meant I had to leave, but the culture. Dance was always a tool for me, but for a lot of people I danced alongside it was an end goal. This produces some truly exceptional performers but I couldn\u2019t handle the heat, and nor did I really like the kitchen\u2019s decor so for now at least I\u2019m staying out.

+

Losing fitness

+

Demonstrably and repeatedly I am less fit than I was 12 months ago. I cut my PB 10k time by 20\u201325% over the course of a few months. I was fast, by my standards. Putting that 20\u201325% back on to my 10k time was hard. It makes me feel inadequate. If I could do it before, I should be able to do it now.

+

It\u2019s not just that: I can\u2019t get up at 7am to work out, then go to work, go to a fitness or dance class at 7pm, then go back to the gym at 9pm. I have all these other things I have to do. Like work a job that excites me and gives me meaning. Like read these excellent books, or spend time with badass humans. +This doesn\u2019t mean I don\u2019t catch myself in the mirror when I\u2019m getting changed and notice a loss of definition. It doesn\u2019t stop me watching other people run or cycle, and constantly compare myself to them. It doesn\u2019t mean I don\u2019t want to count calories before I go to bed every night to double check I\u2019m doing \u2018okay\u2019. But it does mean that my life is enriched in other areas.

+

The overwhelming gains

+

I spoke about the people I met through acroyoga. One of whom I now live with. These are people I respect a great deal, with who I meet 2\u20134 times a week to share, learn, and play. People who are kind to me, who accept my neurotic sense of what a movement should look like, and who (in the best way) strengthen me physically and mentally. This is a place I can use my physical strength and passion for teaching.

+

I\u2019ve recently been involved in a number of creative projects, and I\u2019ve got several more on the horizon. No it\u2019s not choreography as I know it. But it\u2019s taking what I loved from dance, and helping me explore it in an environment where I feel I belong.

+

Some time in June-July I entered a relationship, with a girl I call Angel because I don\u2019t know what else you call someone who accepts and understands that sometimes I want to starve myself or make unfair quick judgements of a person or that I have a compulsive need to go to new places, be in bed by 9.30pm, and work too many hours at a job that I value too much.

+

I have realised that I can damn well do whatever I want for my job. If I want to be a web developer then I can probably just go and do that. So what if I\u2019ve got a Master\u2019s in Environmental Science\u200A-\u200Aa department of chemistry happily pays me for work when I stopped studying their subject at 16. If I want someone to pay me money to keep improving some software I made when I was told explicitly by my supervisor to \u201Cnot spend too much time on it\u201D\u200A-\u200Athen I should start asking a lot of people very nicely. These people do not care that I specialised in quantitative models of poverty, they care that I can show my current project has value and potential.

+

I realised that we\u2019re living in a world that is literally the best it has ever been. No really, we are doing just fine. Not perfect, could still improve, and perhaps we should stop trusting the general public with internationally consequential votes, but there\u2019s like no polio, fewer women are dying in childbirth, and more of these children are living and then learning to read (even the girl ones). I\u2019ve started giving 5\u201310% of my salary to the issues I care about (you\u2019re welcome, forest elephants), and 25% of the money I earn from teaching goes to other charities.

+

I am constantly aware that nothing is permanent, which includes my feelings and life (obligatory reminder that you\u2019re going to die). I\u2019m working on being humble. I\u2019m working on being openly thankful. I\u2019m grateful to all the people that made me feel unwelcome and unaccepted, because I was never going to fit in. I\u2019m grateful to the excellent group of humans I have around me very often. I\u2019m grateful to all the artists around me who have a vision and have to see it realised. I\u2019m grateful to the hip-hop artists who reminded me what\u2019s important. I\u2019m grateful to the authors who helped me explore these ideas in greater depth. I am grateful to my to my parents and to the universe for just being pretty cool.

+

Managing a brain that advises you poorly on proper fitness routines, and which overly values an obscure art form you discovered 12 years too late to be any real good at it isn\u2019t easy. But nothing\u2019s really easy. I don\u2019t expect it to be, and I expect my situation to look different in another 12 months.

+

I strongly agree we should be bringing discussion of mental health to the forefront of people\u2019s awareness. But you need to show continuity and narrative. I don\u2019t think a mental health story can ever truly be retrospective, because you\u2019re always living it. I want this piece to show that mental health is still there, always there, and a part of who I am\u200A-\u200Aand just because it\u2019s no longer influencing my life to any great extent, does not mean this isn\u2019t an important discussion and it doesn\u2019t mean I don\u2019t think about it often.

+

I hope more people who have opened up about their mental health continue these narratives to help themselves and others understand how it affects them day-to-day, but also year-to-year, and event-to-event.

+

Wilson\u2019s tip-top hip-hop recommendations

+

Last year I was pretty clear that hip-hop played a massive part in my self-exploration. Below are a couple of the songs that constantly resonate with me, that I keep going back to, and that I think help to explain me a little better.

+
I ain't got the time to be your enemy +That shit is draining, they're taking up too much energy +I'd rather invest in something that's worth it, the time is precious +So for Simz to waste it is something you'll never see, hold me to it +Wings \u200A -\u200ALittle Simz. +
+
From the view of an atom the human body's a universe +How impossibly big it be, this symmetry +This brutality, and beauty and synergy +And beyond what we'll live to see, I know nothing can limit me +Just take everything ever and we are that times infinity +Tiny Glowing Screens pt. 3\u200A-\u200AWatsky
+
This is your life, you can't escape this bitch when it's hard +Just know that it passes, but you'll collect scars +They never go away, but they will make you who you are +This is a beautiful struggle, I share it in song cause +I can't control this, remember: the moment's beyond us +Hold Your Head Up\u200A-\u200AMacklemore
+
I feel the waves getting far too big to handle +Fail to turn this shit the other way +Sail back to the harbor like your average Joe and play it safe +But that's not life it's not what I chose +Reflection\u200A-\u200AATO X EDEN
`; +}); diff --git a/.netlify/server/chunks/2019-08-15-goodbye-bear-799aed90.js b/.netlify/server/chunks/2019-08-15-goodbye-bear-799aed90.js new file mode 100644 index 0000000..aeca108 --- /dev/null +++ b/.netlify/server/chunks/2019-08-15-goodbye-bear-799aed90.js @@ -0,0 +1,78 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2019_08_15_goodbye_bear, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Back to Bear, Goodbye Notion", + "author": "Thomas Wilson", + "date": "2019-08-15T00:00:00.000Z", + "draft": false, + "slug": "back-to-bear", + "tags": ["apps", "markdown", "bear", "notion"] +}; +const _2019_08_15_goodbye_bear = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

This piece turned out a little long than expected because I really want to clarify that this is not a \u201CWhy Bear is better than Notion\u201D article. It is a \u201CWhy Bear suits my needs right now better than Notion\u201D discussion. So there\u2019s a little more nuance in my explanation. +The crux of my point it is this: I am a scatter brained person who develops software, makes dance, and exercises semi-seriously - and I need a digital tool to help me manage my thoughts, writing, documentation, and general projects. I previously used Bear, a beautiful and simple markdown-esque note keeping app, but forgot about it when I moved cities and jobs pretty much all at once. In my new life I started using Notion, a cross-platform feature-rich editor, but I\u2019ve gone back to Bear. +I went back to Bear because I like the simplicity - it let me categorise, expand, delete, and move things around in a way which is much closer to how I think about my life and work. Also, as a developer, if I want complexity I\u2019ll roll my own: between Google Docs and serverless providers I can achieve a lot.

+

A brief love letter to Apps

+

I live my life in a couple of lanes: I\u2019m a front-end software engineer in a small team at a rapidly growing scale-up, and also a dancer/producer for a small contemporary dance company, and someone who likes to write and journal for their own personal development. I am asking a lot from any app, I want it to collate my thinking of software architecture; document specific practices across a range of projects; and keep track of myriad side projects, restaurants I want to visit, narrative structures and scene ideas; document research material and my evaluation of it; and outline workflows for funding applications. I want to do these things with as little context switching as possible. I want a killer app that doesn\u2019t exist: not only are these a contrived set of requirements, but how I think about each of them, my mental models for them, are different. +But I really love the search. I love apps. I love the promise that a new App brings - it\u2019s like buying a new blank notebook, non-blank regular book. It\u2019s the promise of a new you, a new way of thinking, doing, producing - one step closer to the way you work now, and a more productive, happier, wealthier, and skinnier version of yourself. I think this is the feeling which fuelled first decade after the iPhone was released, when everyone wanted to talk, read, write about the killer app for iOs (and now iPadOS) or OSX (and now OSX). +It definitely feels now like this conversation has slowed down, the conversation is less around specific apps. However, every now and again, hype rises out of Product Hunt or Hacker News to offer up some crafter, artisanal interfaces. Bear and Notion have been two such apps: I\u2019ve seen them on twitter, in online publications, and other developers mention them.

+

Bear

+

Bear is a beautiful note-taking App built for the Apple ecosystem (iOS, iPadOS, MacOS) by Shiny Frog. The premise is simple: you write in a markdown (or markdown-esque) syntax, which gives you access to a limited set of features: body text, headings, lists, links, images, inline code, bold, italics. Notes themselves are organised by any number of tags ( anything starting with \u2018#\u2019 ) which can be nested, e.g. post/post versus blog/portfolio. It\u2019s been recognised by Apple number of times for their fantastic visual design. Which makes sense: it does one thing well, feels simple, but can be integrated into very powerful workflows (e.g. exporting to markdown and plain html). This is Apple\u2019s philosophy, surely.

+

In Praise of Bear

+

There are a couple of things I really liked about using Bear:

+
  • Creating notes comes with much lower entry requirements, I just hit \u2318N and I get a new note, it doesn\u2019t need to be anyway, I can just dump whatever I need into it and then organise it later.
  • +
  • Both apps are visually beautiful, but that doesn\u2019t mean I shouldn\u2019t mention it twice: the UI is very nicely designed.
  • +
  • It specialises in one kind of content: slightly-enhanced text, and executes on that one idea well.
  • +
  • Easy to export: I can get from a note to sanitised HTML, markdown, pdf, docx is two clicks and 5 seconds - which makes it so easy to integrate into any workflow.
+

My time with Bear (2017-2018)

+

After graduating my Ph.D. into my first software development job I was looking around for note taking apps, so I could keep track of what was happening in meetings, product development ideas, and my own personal learnings. My first job came with a lot of context switching - I was on a number of different projects, so flexibility was important. +I came across Bear, probably from an App Store feature, and loved it. But around 6 months after starting the job, I relocated from Southampton to London, and not soon after I started actively looking for new job opportunities. The job I was in was okay, but not what I imagined it would be, or what I needed at that time in my professional journey. this is important because I was going through a lot of personal change and turbulence - I didn\u2019t have a system in place for anything, and it would have been pointless to develop one because things were changing so rapidly. +So I left bear behind accidentally, I simply stopped using it and it never occurred to me to start using it again around the time I moved to London in early 2018.

+

Notion

+

Describing Notion is much less simple than Bear, they describe themselves as an \u2018all-in-one workspace\u2019. It offers an astonishing amount of functionality: Kanban boards, structured tables with filters, embedded web pages, todo lists\u2026 honestly I do a disservice in trying to list them all. +I started using Notion in early 2018 after moving cities and jobs - two big changes which broke a lot of my old habits and tools. I think I first saw it in a coding livestream by MPJ on his YouTube channel funfunfunction , and then finding this profile by invision on Ivan Zhao, the co-founder and CEO. He seems like a cool guy, really product focused, and making something productive and beautiful. So I started using Notion personally, and at work. +I used it to help me organise my first ever cycle tour across France in 2019 (I got half way through and then rained off - 3/10, would not recommend), to track my route and AirBNBs. I used it to write documentation for projects at work. I kept a track of my personal and seasonal goals (shoutout to Cortex for introducing me to the idea of yearly and seasonal themes.)

+

In praise of notion

+

I initially got on really well with Notion, it had a number of really nice features:

+
  • It is beautifully designed by people who care deeply about visual and software design.It is very obviously a well-considered piece of software.
  • +
  • It\u2019s cross platform, and even has a fully functional web-app, meaning I could access it from anywhere, at any time.
  • +
  • The number of ways it lets you store and present data, statically and dynamically, make it a very versatile tool. I used it to write long-form opinion pieces, plan cycle tours, and document software projects.
  • +
  • It provides an opinionated way to store information: systems for categorising are very personal and it\u2019s very easy to over-architect or make inconsistent. By enforcing a hierarchical structure, it\u2019s harder to let things sprawl
  • +
  • The structured content, and collaborative team sharing features built in, make it very obviously an excellent tool for organisations - so it\u2019s a nice future-proofing tool.
+

Moving away from Notion

+

After 4-5 months, I started to notice some noteworthy drawbacks to using Notion in practice:

+
  • Sporadic offline support. I would get semi-randomly logged out of my machine, and I the data would often not be available locally. To get deep work done, I like to take myself to wifi free areas and focus, and a number of times, Notion put a spanner in that plan.
  • +
  • I rarely reached for the vast array of functionality available to me. I largely stuck with headings, web page embedding, and some tables, sometimes.
  • +
  • When I write, I like to be hyper-focused (I am writing this on a plane, in full screen mode, with noise cancelling headphones) - my brain will get distracted by anything I can tweak (colours, spacing, organisation). Notion gave me a lot of options to get distracted by.
  • +
  • Poor iPad smart keyboard support. Even something as simple as pressing the down arrow to go to the new paragraph wasn\u2019t supported. This is my one feature-related complaint. +Underneath all of these was a really nebulous feeling that reaching for Notion felt like work. I had a couple of more systemic, underlying problems with using it which are harder to look past than UI or features. +Fundamentally, I felt a growing gap between how I thought of myself and my work, and how Notion made me present it. Notion organises each file as if it were a page on a website - in a tree-structure, with siblings, parents, children. This meant that everything had to belong somewhere, which is fine for fully formed ideas, organisations, or processes - but I found it didn\u2019t support the growth or development of concepts so well. Sometimes this is fine, because you know the content will mature - e.g. when you are documenting the architecture of software: you know the moving parts, their function, and their relationships. It becomes easy to add new parts and modify existing ones. +Sometimes, however, I found this limiting, and I had to force my ideas or notes to fit a structure that I hadn\u2019t defined and didn\u2019t want to define. I had a number of pages in Notion which were essentially lists of half-formed ideas, or were links to pages for half-formed ideas. This structural organisation felt so final, and high-cost. Like changing anything would require a lot of boilerplate and formulated thinking, when for me the note making and moving is the thinking. +When does something move to its own page versus sitting in bullet list of other whacky ideas? Where does this new page live? In my mind, it belongs with other half-formed ideas, because it\u2019s in progress, but it also belongs with its thematic brethren: if it\u2019s a software idea it doesn\u2019t belong next to a meal plan, cycle route database, or fitness training regime. +This is at the route of my move away from Notion: I learn best through experimenting and demonstrating to myself - and for this to be accessible, I need to have no investment in the results of experimentation. If I need to set up five different routes on Strava before I find the right one, I will happily just discard the old ones - it\u2019s 2019 and data has never been cheaper. I could not learn a language, framework, or library by reading the docs or a blog post. +Notion is about creating a product., a well formed artefact. My process is about creating a lot of mess at very low cost. I felt guilty about deleting things or moving them within Notion, which is strictly a personal feeling, and not a design intention by the team behind the product (it might be, but I really don\u2019t think it is.) f1
+

Returning To Bear

+

Since moving back to Bear, I\u2019ve found writing a lot more pleasant and less intimidating. I actually managed to start and then finish this piece, for example. Migrating all of my information from one to the other has been a little bit of a pain, but it\u2019s now so easy for me to get started creating something, without worrying about where it belongs or how I should categorise it at the moment of creation. I have my beautiful, overflowing dumping ground, and in six months I look forward to coming back to Notion begging for their opinionated organisational structure. Until then, vive l\u2019ors.

`; +}); diff --git a/.netlify/server/chunks/2019-09-20-why-use-css-in-js-9fcc7d49.js b/.netlify/server/chunks/2019-09-20-why-use-css-in-js-9fcc7d49.js new file mode 100644 index 0000000..e9504bf --- /dev/null +++ b/.netlify/server/chunks/2019-09-20-why-use-css-in-js-9fcc7d49.js @@ -0,0 +1,74 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2019_09_20_why_use_css_in_js, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "author": "Thomas Wilson", + "title": "What is CSS-in-JS and why do people keep using it?", + "date": "2019-09-20T00:00:00.000Z", + "slug": "what-and-why-use-css-in-js", + "draft": false, + "tags": ["css-in-js", "javascript", "frontend"] +}; +const _2019_09_20_why_use_css_in_js = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The elders tell us of a time where you would build websites by literally writing your .html files. If you wanted to add some styles, you\u2019d write them in a .css file and then <link rel="stylesheet"> the two together. So you\u2019d write your entire site in semantic HTML, about whatever it is people did back then (like mammoth hunting or pyramid building) and then you would ftp that onto your server, and other people could view it. At least as long as they could fight off polio or resist rebelling against the bourgeoisie. Maybe you\u2019d go out and celebrate at the tavern afterwards, but actually that one sounds pretty relevant today.

+

Component-orientated architectures arrive

+

In the modern (but still terrifying) world of 2019 - HTML, CSS, and JS remain three central tenants of the internet: HTML providing content, CSS styling it, and JS adding functionality on top of everything. The way we get the result of these technologies, HTTP, has remained pretty constant too. +However, at some point people started to realise that writing just HTML could make it difficult to edit parts of their website. Say you have a navigation header, and you want to add a new page to your website. Well now you need to go through every .html file, find the navigation header, and add an item. And what happens if you miss one file by accident? +This is the problem which facilitated the evolution of component-centred architecture: a component being some pre-defined visual element, simply a \u201Cthing\u201D on a website: a tweet in a list of tweets, a list of currently trending articles on BBC News, a user\u2019s avatar image.
+This lead to building websites as a set of components which you compose together, as opposed to single monolithic pages. This practice evolved, and more responsibility was handed over to JS and other technologies. People started writing Single Page Applications (SPAs), and static-site generators increased in popularity - where we could define and update components in a single place, and see them updated across our site without having to delve into the nested HTML ourselves. It doesn\u2019t matter if the site is actually just a single JS function or runtime which hooks into the browser\u2019s URL (e.g. a SPA written in React or Vue) or if it generates a set of HTML files (a static site generator). Component-based architecture is the practice of breaking out our visual element by their role, not their location. +Pairing components with external data sources, like in a CMS or a databases, means that a website does not need to be rebuilt or re-made whenever a new product is added to a store, or the price of an item changes. It has given a lot of power to people in the business, but who weren\u2019t developers. And it\u2019s freed up developer time to focus on more developer-y things, like complaining about meetings and fixing their parents\u2019 wi-fi.

+

Where does CSS come into this?

+

Look, the point I\u2019m making is that modern web development considers a web page as composed of many components, which can be shared across pages (and even sites). But the way we do styling with CSS didn\u2019t immediately go through a similar revolution. In a lot of cases we were still left with one global CSS file, which we would simply <style ref=\u201Cstylesheet> into our application. +This isn\u2019t to say it was still 1998 - we developed build chains and pre-processors - tools which would generate CSS, but gave us more advanced features - like inheritance and extension, and functions and variables. This made it much easier to update CSS, and quicker to write in general. +Despite this, these processes often output a single global stylesheet. In the past couple of years, some web developers have created technologies which remove this separation between components and styling - allowing developers to declare styles in the same way they declare components.

+

Why not CSS-in-CSS?

+

(First off, let\u2019s acknowledge the fact that it\u2019s now completely valid to specify that I\u2019m talking about CSS as in a .css file - how weird is web development?) +CSS is incredibly powerful, with a lot of nuance. It\u2019s a great technology and some people really love it - it can make websites beautiful and fast and just joyful. Despite what I\u2019m about to say, I really like CSS, and I\u2019ll use it by default where it makes sense. +Despite this, there are very legitimate criticisms being levelled at CSS. Principally, these criticisms are due to the way that CSS is authored, managed, and generated - and the sprawling, dynamic, and unpredictable HTML content tree which is tightly coupled to it. +There are a couple of problems which emerge from these large, single, often append-only stylesheets. These problems become more apparent, and costly, as an application reaches a certain size, and exists in the real world, where maybe several developers are authoring styles and creating different bits of the website. Even as a solo dev on side projects, I\u2019ve felt some of these negatives:

+
  • Name collision: Different parts of you application share the same logical name, like .navigation-item - but is that the nav item in your footer, side bar, or header ? All of a sudden, css is vying to apply the same styles to three three separate navigation items, which you might not necessarily want to look the same. This can lead to\u2026
  • +
  • Over-specific selectors: To combat the above, you might start chaining your selectors (e.g. header > .navigation-item) which is fine, until you have to chain 2, 3, 4 selectors - at which point re-structuring your HTML introduces visual regression and style changes, because your css nesting no-longer matches your HTML.
  • +
  • Keeping styles in just-in-case: It can be surprisingly hard to know which styles in css you are using, especially when paired with the above: it\u2019s easy to see if a single class name is being used, but much harder to know, reliably, at a glance, if you have header > .navigation > .navigation-item > .navigation-icon. Imagine the complexity you add in when you start dynamically rendering elements with a JS library, or just using JS to add or remove classes from elements. This can lead to bloated CSS files which no one wants to touch or modify, for fear of introducing unforeseen regressions. Which is basically\u2026
  • +
  • Unpredictable side effects from modifying or deleting code: This affects the developer experience and process - well-architected software presents a clear process for change, refactoring, or extension. When you cannot make changes with the knowledge of what you\u2019re going to affect, or at least where you\u2019re going to affect - it is hard to maintain and extend software into the future. You end up with long, append-only style sheets, and worse, the cursed !important tag.
  • +
  • Source order specificity: With more of our client-side applications being rendered, loaded, and managed by JS frameworks or libraries - we cannot reliably predict the order which CSS styles will be loaded into the DOM, because it may be loaded only for a specific page - either intentionally, or from automated code-splitting. Files which load later have higher source order specificity and can override styles declared earlier. So styles can be unpredictably overridden by the way our users use the application.
+

CSS-in-JS as a solution ?

+

As the name suggests, CSS-in-JS is the process of using JS to generate valid CSS style syntax. This is opposed to managing their styles by creating separate .css files (or .less and .scss for that matter). It is typically defined alongside a component, e.g. the JSX in a React component, or the template in VueJS. This is strongly related to the component-first architecture of modern web development - an extension of the idea that everything about the View of the application (capital V as in MVC) should be defined in one place - not two (a .js file and a .css) +It\u2019s briefly worth mentioning here that CSS can be scoped to single files - meaning that not all of this functionality is specific to JS. However, the ability to generate and modify styles with the JS language offers a lot of the power of CSS to the hands of those without intimate knowledge of the CSS syntax. Dangerous indeed. +CSS-in-JS is not a singly library or package, and it is not an agreed syntax. A number of approaches have emerged from the community to address this problem. Some example libraries include:

+ +

Why do people keep using CSS-in-JS ?

+

Fundamentally: It\u2019s a component-first way of thinking. it takes the way modern web development thinks about web pages, and the widgets on them - and applies that philosophy to way we write our styles. It gives us a one-to-one relationship between our components, and their styling declaration (as opposed to one global stylesheet and many components.) This means your selectors aren\u2019t traversing the DOM to find the .navigation-item that they really mean. +This makes it easy and familiar to think about, and it centralises our visual code into one place. This is a nice philosophical benefit, but it pragmatically helps us by constraining where a set of styles are used. This means they could be edited or deleted with more certainty that we aren\u2019t about to accidentally change styles across the DOM. +For me, the strongest advantage of CSS-in-JS is the addition of functionality from a programming language, like JS. This allows you to set styles based on global variables (e.g. a theme) or local state and props, and use functions and conditional statements. This adds a huge range of flexibility and functionality, without having to manually add or remove class names from a DOM element. This drastically reduces the cost of creating complex or delightful user experiences (e.g. having cards hover when they\u2019re under the cursor, or a button glow if it\u2019s toggled on) without tightly coupling it to specific css classes or selectors. UI libraries and frameworks should abstract the author from the implementation details (i.e. managing the DOM), and CSS-in-JS fits this philosophy. +When we declare styles at author time, our library of choice (e.g. styled-components) handles the transformation into valid CSS, and inserts it into the DOM. As part of this, the library will likely generate a unique (hashed) classname, this means developers don\u2019t have to worry about creating unique, or strictly-structured class names for their css - they can just declare styles, and assume they will be correctly scoped. +What\u2019s more, the build chain which does all of these is integrated into the existing build process for the website. We can keep our JS project as purely JS, and don\u2019t have to worry about building and bundling .scss or .less files.

+

Articles I found useful

+

I came across a couple of really nicely written articles when I was researching this piece. I\u2019d recommend them if you\u2019re curious:

+`; +}); diff --git a/.netlify/server/chunks/2019-10-30-culture-i-devoured-in-september-2019-46f09e61.js b/.netlify/server/chunks/2019-10-30-culture-i-devoured-in-september-2019-46f09e61.js new file mode 100644 index 0000000..08c9b7f --- /dev/null +++ b/.netlify/server/chunks/2019-10-30-culture-i-devoured-in-september-2019-46f09e61.js @@ -0,0 +1,47 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2019_10_30_culture_i_devoured_in_september_2019, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Culture I devoured in Autumn 2019", + "author": "Thomas Wilson", + "date": "2019-10-30T00:00:00.000Z", + "draft": false, + "slug": "culture-i-devoured-autumn-2019", + "tags": ["culture", "arts"] +}; +const _2019_10_30_culture_i_devoured_in_september_2019 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

This season turned out to be surprisingly busy with culture. I started the month by talking at two tech events in London, meaning I arrived into the full body of the month having produced some very technical, thoughtful output. I needed some really well-considered and curated culture to put everything back in the right places. Kind of like an internal tidy-up after I\u2019d rummaged through all of my draws to produce someone who was definitely more knowledgeable than I am, and probably a lot funnier and more extroverted.

+

Historic Centre of Florence

+

Italy, UNESCO World Heritage Site

+

Hard as it is to believe now, a stonking four weeks later, but I started off this month in the centre of Florence, Italy. It\u2019s a city I\u2019ve visited every year since 2014, sometimes alone, sometimes with romantic partners, other times with friends. It is a place unlike anywhere else I have been on earth. The city is old and sprawling, the centuries-old city wall no longer even resembles an outer limit. It is one of the centres of the European renaissance, a hub of craftspeople, artisans, religion, philosophy, and hot blooded commitment to creating something beautiful. I don\u2019t care that it\u2019s full of tourists (myself included). I don\u2019t care that I was only there for three full days, and that my Italian really has plummeted. I don\u2019t care that it\u2019s a romanticised ideal that I\u2019ve created of a city in a country with some very real economic and political problems, and a culture which I don\u2019t think would fit me very well at all. The city reminds me of the wonder and joy of travelling to new places, and to the higher ideals of art and craftspersonship which I value, but can be pulled away from by the urgency of the day-to-day. It is a city which speaks volumes to me, in a quiet, old language that I have to be very still and quiet to hear. The historic centre is a UNESCO World Heritage site, and I make the rules so I say it counts as culture, and boy am I glad to have had the chance to visit to visit there again.

+

House of MinaLima

+

Soho, London

+

MinaLima are a design studio founded in 2002 to create the entire visual language and style of the Harry Potter universe as it was being brought from page to screen. They contributed hugely to the visual props in the franchise. If you\u2019ve seen the films, you have seen their work: The Daily Prophet (the wizarding newspaper), the most-wanted posters for Sirius Black and Bellatrix Lestrange, the Black family tree tapestry, the penmanship in Molly Weasley\u2019s howler that she sends to Ron after he flies a Ford Anglier into a magical tree. The whole thing is situated across four floors in a historic london terrace, with charmingly wonky floors, windows, and ceilings. The walls are full of all of the attention to detail that you could so easily miss by \u201Cjust\u201D watching the films. I grew up with Harry Potter, the books and the films, and that house felt so wholesome and warm - it is a really wonderful example of an intersection between visual design and world-building. If you are in north-ish London and want to kill 20-40 minutes, go and take a look. It\u2019s most wonderful.

+

Faith Hope and Charity

+

The National Theatre, London

+

This piece makes up the final in a trilogy of new work by Alexander Zeldin. I haven\u2019t seen either of the previous pieces, though I rather wish I had. Faith Hope and Charity takes place in a community centre in London across a couple of months, seeing a host of believably-guarded and warey characters, as they come for a free lunch and choir practice. While I was watching it, I felt the pacing to be unbearably slow at times - but on reflection, the whole thing was staged and timed exactly as it needed to be. You were never force-fed any ideas, and the eight-or-so principle characters tore you between a number of simultaneous plots or points of interest. Certain people and events became more of a centre-piece later on, but for most of it I got such a real sense of London: disjointed conversations hindered by people not wanting to share or give too much - because they either don\u2019t know things about themselves or are scared to let other people see them as weak or frightened. Of people deflecting questions and awkwards conversations by busying themselves, or talking about anything (the biscuits, the leaky ceiling, anything) other than the things which very much needed to be talked about. Susan Lynch, one of the actresses put it perfectly when she said that the piece is \u201Cabout moments between people, and it\u2019s about small acts of human kindness\u2026 the audience is as vulnerable as the players\u201D. It\u2019s also the second time I\u2019ve seen Cecilia Noble on stage, and the second time I\u2019ve watched her command my attention - the woman is fantastic to watch.

+

Akram Khan\u2019s Giselle

+

Sadlers Wells, London

+

I feel lucky that I got a chance to see this piece. Based on the classical ballet, in its characters and broad plot points, but has been adapted into contemporary movement and narrative by Khan\u2019s choreography and vision. There is always a risk when you see contemporary movement given to classically trained dancers. They could hold back from the rawer moments or the unclean lines. Ballet dancers like to look good, it\u2019s understandable. For the most part, if you weren\u2019t looking at them thinking about this - I don\u2019t think you would worry so much about it. Tamara Rojo\u2019s performance as Giselle was, appropriately, otherworldly. From innocence and smitten to fear-driven anger, she mixed vulnerability and strength in a way which I can\u2019t imagine ever being able to replicate. The first act was bullish, raucous, misplaced energy. Some wonderful folk dancing, animalistic movement, and very physical violence. The second act, all forty minutes of it, were heartbreaking, and I was furious when the curtain came down without letting me know what I need to do with these new emotions. It was wonderful to see the piece reimagined in this way, and set to a powerfully composed original score and soundscape, which pleased the contemporary dancer in me to no end.

`; +}); diff --git a/.netlify/server/chunks/2019-12-20-nuxt-to-gatsby-fc2a6097.js b/.netlify/server/chunks/2019-12-20-nuxt-to-gatsby-fc2a6097.js new file mode 100644 index 0000000..ae1fba0 --- /dev/null +++ b/.netlify/server/chunks/2019-12-20-nuxt-to-gatsby-fc2a6097.js @@ -0,0 +1,48 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2019_12_20_nuxt_to_gatsby, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Moving my personal site to Gatsby", + "author": "Thomas Wilson", + "date": "2019-12-31T00:00:00.000Z", + "draft": false, + "slug": "moving-from-nuxt-to-gatsbyjs", + "tags": ["javascript", "gatsby", "vue", "react"] +}; +const _2019_12_20_nuxt_to_gatsby = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

A few weeks ago I was having a conversation with someone about modern web design, and we spoke about web fonts and variable fonts. In my experience, people who work in software development have a couple of hills that they will die on, if so required. For this person - the idea of not using system fonts (i.e. typefaces which are already installed on a user\u2019s device) was completely baffling. Why are we increasing the time-to-load and packet size required to display a web page - just for a typeface. What about that horrible (re)appearing text, or worse, shifting text which happens when the browser finally loads the typeface.

+

System fonts, I had argued to me, are designed and considered specifically for the device viewing the page. They\u2019re curated in a way that we, as site authors, cannot easily curate.

+

Ever since they introduced that tiny bit of doubt into my mind, I couldn\u2019t help thinking that maybe I should just be using system fonts. Long story short, I rewrote my entire personal site (https://thomaswilson.xyz) from Nuxt (a Vue.JS application framework) into Gatsby (a React.JS static site generator). It took me like to evenings and I\u2019m happy with my decision.

+

Look, there were a couple of other factors in this. Like, I had just taken the jump to go freelance so I needed to move my increasing portfolio over to my professional site. I wanted to move some of my older pieces of writing from Medium onto pages on this site. I was creating a beautiful list of my favourite albums of 2019. There was a lot going on, and I was finding a lot of friction in the process of writing blog posts for this site.

+

Why React, not Vue ?

+

Fundamentally, I have more personal and professional experience with React. I have created a lot of static sites and dynamic apps with React, I\u2019ve used a lot of styling solutions, state management libraries, application architectures, and third-party packages. I know my way around the ecosystem, around React-ive thinking. We should be careful of using tech just because we\u2019re comfortable with it, but when it\u2019s your personal website which no one else will see or touch - familiarity is a major benefit.

+

It definitely didn\u2019t help that I was having big problems getting my codebase to build on a new Laptop (a 2019 MacBook Pro, not even something obscure). It couldn\u2019t get the Nuxt -> TypeScript build chain to work, despite hours of debugging. I\u2019m not a dev-ops or build-chain kind of developer, but really this shouldn\u2019t have happened, and should not have been so obscure to solve.

+

Additionally, at the time of writing, the proposed V3 of Vue.JS will contain a lot of changes to the library and recommended practices. I am excited to see these changes, and I think Vue.JS is a better web application framework out-of-the-box than React and Angular - I believe V3 will bring a lot of hard-learned lessons about web apps into the framework. However, right now I didn\u2019t fancy re-writing most of a failing Vue app to have to re-write it again in a few months. A la AngularJS vibes.

+

Why Gatsby?

+

I\u2019ve used Gatsby a few times to build quick/simple sites for friends. It\u2019s very fast, both in development process, build process, and then loading times. I was looking for something I could be productive in quickly, at Gatsby was that.

+

I want to give a special shoutout here to the gastby-image package for lazy-loading images (alongside the GraphQL support and image-sharp library for image processing. This kind of support for blur-up images, and an easy ability to control image size at build time are incredible, and a great step forward for the modern web.

+

Speaking of GraphQL (smooth, I know) - I think GraphQL is going to play a big part in web development in the next 3-5 years. No, not everything is going to be re-written to be GraphQL endpoints, obviously. That would be a bad idea, obviously. Yet, as a front-leaning full-stack developer, GraphQL is powerful and expressive enough to make me take notice. Gatsby gives you a GraphQL layer to query for all your data (local files, site metadata) - the chance to get familiar with this tech is something I am appreciative of.

+

Recently the core-team has been pushing Gatsby Themes (as I heard about on here, here, and here). I love web design (have I mentioned that yet?) - and I love seeing the core-team take such an interesting, systematic approach to design as a core part of their framework\u2019s architecture. It looks like I\u2019ll be able to learn a lot about systemised design through Gatsby.

+

Lastly, I wanted to quickly/easily deploy my personal site on Netflify - a service which can build, deploy, and host static sites incredibly easy. It took, and I am not exaggerating, about 120 seconds to go from creating a git repo to having this website available on the World Wide Web.

`; +}); diff --git a/.netlify/server/chunks/2020-02-20-introducing-eating-disorders-d2e86304.js b/.netlify/server/chunks/2020-02-20-introducing-eating-disorders-d2e86304.js new file mode 100644 index 0000000..95fd8f1 --- /dev/null +++ b/.netlify/server/chunks/2020-02-20-introducing-eating-disorders-d2e86304.js @@ -0,0 +1,42 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_02_20_introducing_eating_disorders, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Re-publishing my writing on my experiences with food and eating disorders", + "author": "Thomas Wilson", + "draft": false, + "date": "2020-02-20T00:00:00.000Z", + "slug": "introducing-eating-anthology", + "tags": ["eating-disorder"] +}; +const _2020_02_20_introducing_eating_disorders = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

tl;dr - I have moved the writing I have created on my experiences with eating disorders to this site (and off of Medium.). You can find them here.

+

For at least the past five years, my mental health has been affected through and alongside a weird relationship with food, exercise, and eating. I find writing helps me clarify my thoughts and my situation to me. While a lot of this writing is intentionally private, there are a couple of piece I want to be publicly available.

+

Back when I published my first piece on this subject, I put it on medium.com - however that site has recently favoured the advertiser over the reader. Back in 2016 it was very much the opposite, and while I understand they need to make money from people reading their writing - I don\u2019t, and so I can afford to favour the reader experience. When I\u2019ve written something so personal and meaningful, I wanted people to read it in the same way.

+

So I have collated my writing into a small anthology, which you can find on my personal site, here or each piece individually at:

+ +

I\u2019ve left the initial pieces as untouched - with only some minor styling changes to bring some of the long lyrics I mention into life.

`; +}); diff --git a/.netlify/server/chunks/2020-02-24-hereabouts-devblog-1-18e93c36.js b/.netlify/server/chunks/2020-02-24-hereabouts-devblog-1-18e93c36.js new file mode 100644 index 0000000..680a3c0 --- /dev/null +++ b/.netlify/server/chunks/2020-02-24-hereabouts-devblog-1-18e93c36.js @@ -0,0 +1,58 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_02_24_hereabouts_devblog_1, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Hereabouts devblog #1", + "author": "Thomas Wilson", + "draft": false, + "date": "2020-02-24T00:00:00.000Z", + "slug": "2020-02-24-hereabouts-devblog-1", + "tags": ["hereabouts"] +}; +const _2020_02_24_hereabouts_devblog_1 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Hi, my name\u2019s Thomas Wilson but I often go by my just my surname. I\u2019m 28 years old, currently based in London, England, and I design and build software for a living through my small independent studio tinyfox studio. At the beginning of 2020 I quit my job to do this independently, and now I\u2019m building hereabouts - an app that provides self-paced walks, tours, hunts, and races for travel adventurers +In this devblog series I want to record to the process of building something modern and beautiful from the ground up.

+

My problem/frustration

+

I love being in places. I love walking around the streets of London, and especially love how London feels like 30-40 little villages that you can find yourself in at any moment. I love learning things about the people who lived and made this place what it is today. It\u2019s my favourite part about travelling solo - is that I can walk around a new city at my own pace.

+

The Pre-Raphaelites had studios in Bloomsbury, Virginia Woolf lived and wrote some of her work just south of King\u2019s Cross, Sherlock Holmes got coked up just east of Regent\u2019s Park. You could maybe walk between all of these locations in 60 minutes, and comfortably within an afternoon. Maybe you\u2019d notice something things if you read the blue plaques but really what\u2019s a sentence to describe a life\u2019s work?

+

When someone visits London from somewhere else, or when they move here, or even if they just need a good idea for a fourth date - I want them to feel connected to the place and idea of London. Not caught up in frustration at the man who get on the tube before letting other people off, or the blind panic when you misjudge the timing of the turnstiles coming into the tube station. But these are both very real experiences of London, everyone who visits should have them. But there\u2019s so much more in a place.

+

Hereabouts: self-paced walks, tours, hunts, and races for travel adventurers

+

Hereabouts is the name of the app I am building to address this problem. I want to create an app that lets people explore a new or old city by giving them guided tours, stories, puzzles, and races. +I want to reach adventurous travellers and sate their appetite to learn more about what makes a place beautiful.

+

I don\u2019t know what exactly it will look like or do. That\u2019s part of the development process.

+

What I want to achieve

+

By building this idea out there are two things I want to achieve, neither of which are overtly technical:

+
  1. I want people to experience joy and connection form the place they\u2019re in or connected to
  2. +
  3. I want to provide high quality story telling and information resources
+

For a while I\u2019ve wanted to build an app that helps people discover a place by being in it. I want to help people discover the same feeling I have when I\u2019m somewhere and I learn something about it. I want people to have fun in the real world, in real spaces without being tied to their screen, or a paper guide, or part of a pack of tourists.

+

I love storytelling, and humans keep re-inventing how the do it. Oral stories, pictures, words, theatre, tv, movies, podcasts. Storytelling is probably the least talked about oldest profession. So I want to share the stories of the people who frequented, built, ruined, or just passed the streets.

+

I hate that when I go to learn about a certain place, or person, or idea - the information is scattered and made distant. It is made boring - because it is hard work, very skilled and professional work to weave together narratives of people, places, movements, and ideas. But you create value by providing high quality, unique resources that appeal to humans (not users.)

+

Why build an app?

+

Something I keep re-learning about myself is that I have this drive to build and create things for me any myself. I first learned this about myself during my Ph.D. where I taught myself software development so I could make a web app for my education research. In the three years since I finished that, I have worked for a large company and a growth-stage VC-backed startup. I happily sacrificed a lot of myself into these jobs because I learned a lot from other people. Being self-taught is a good start but it\u2019s a terrible middle.

+

And to be honest, I think the things I want to achieve can only be done on modern handheld technology (i.e. phones) because I want to bring multimedia (picture, audio, text) to someone based on the place they\u2019re in. I think it could be done by being walked/shown around by a professional. However that\u2019s not an idea that excited me, and I also think it\u2019s too much like forced fun. Part of being an explorer or adventurer is being able to go down side streets, get surprise ice cream, or spend twice as long somewhere you find interesting. There should be guidelines, not fences/rails.

+

This is also overlooking the fact that I am a software developer by trade/craft. It influences to way I see the world, solve problems, and build solutions. I enjoy designing and building software, and I\u2019m sure that\u2019s affecting my decisions.

+

I also want to call out a couple of very influential sources to me when thinking about if this is something that I can or should even be doing:

+
  • Basecamp\u2019s books - specifically \u201CRework\u201D and \u201CIt doesn\u2019t have to be crazy at work\u201D have shown me the kind of company it is possible to build, and the way you can go about making something.
  • +
  • The indie hacker movement have been excellent at showing me countless examples of people who have built businesses at various speeds and with various goals.
`; +}); diff --git a/.netlify/server/chunks/2020-03-15-ux-with-components-screens-state-and-actions-0c39ac14.js b/.netlify/server/chunks/2020-03-15-ux-with-components-screens-state-and-actions-0c39ac14.js new file mode 100644 index 0000000..5cac9c6 --- /dev/null +++ b/.netlify/server/chunks/2020-03-15-ux-with-components-screens-state-and-actions-0c39ac14.js @@ -0,0 +1,97 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_03_15_ux_with_components_screens_state_and_actions, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Kickstarting UX Design with ugly working documents: Screens, Components, Actions, and State.", + "author": "Thomas Wilson", + "date": "2020-03-15T00:00:00.000Z", + "slug": "2020-03-15-ugly-but-functional-ux-design", + "draft": false, + "tags": ["ux", "design", "figma"] +}; +const _2020_03_15_ux_with_components_screens_state_and_actions = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

UX design resists standardisation or templates. It can\u2019t be a one-size-fits-all approach, and the nature of the product, audience, and production team all mean that something different is needed each time. Whenever I get past the early stages of UX design (like understanding what a product does, and who it does it for) - I find myself with a different working document and process than I\u2019ve needed before.

+

I wanted to share the things I do that give me the momentum to get to a place where I can do this more specific kind of document.

+

I am a very visual person, so this starts with low-fidelity UI mockups: clunky boxes and text, that I can setup and tear down quickly. My process is built around forcing me to move through all the parts of an app quickly. This means I force myself to encounter all the information an app needs,every way that it\u2019s displayed, and everything a user can do with it. Seeing these things within a short time makes repetition and patterns more obvious - and helps me make connections and similarities.

+

Tl;dr

+
  1. You are going to make a list of all the Screens & Components in your app. You\u2019re going to do it in an ugly-ass looking document that you\u2019re never going to share and actively should not spend time to make pretty. Make this document however makes sense for you - Figma, Sketch, Paper, whiteboard, plaintext, WHATEVER I DON\u2019T CARE AND NOR SHOULD YOU - YOU\u2019RE NEVER GOING TO SHARE IT
  2. +
  3. First, make a list of all the Screens in your app, and lay them out (roughly, don\u2019t fiddle with arrows) in an order that someone could realistically move through your app. I like to group similar screens closely together, and I also look for common screen patterns (e.g. screen with a header and a footer nav).
  4. +
  5. You\u2019re going to make a note of all the high level Components on the screens. Start by just making a boring old box with really clear terms on it: e.g. \u201CAccount Details\u201D, \u201CSign in form\u201D, \u201CCreate account form\u201D, \u201CRecent transactions\u201D.
  6. +
  7. Go through these high level components and start making the low level, more abstract/utility ones: \u201CTextField\u201D, \u201CButton\u201D, \u201CIcon\u201D, \u201CLabel\u201D. And begin to compose these together in your higher level components.But do not lay them out nicely.
  8. +
  9. Take your Screens and Components, and list all the variants in State that you can have: can a TextField be selected or disabled ? Can an event in a calendar be upcoming or passed ? Can the Screen for editing an article be in edit mode or read mode ?
  10. +
  11. You\u2019re going to look at all the components you have that are Actions - i.e. can I click it, slide it, interact with it in a way that does something: navigates me somewhere, opens a modal, logs me out. Use this as a chance to understand all the ways a user can navigate around the app - going from one screen to another.
  12. +
  13. Look at all this amazing information you have about your app or product, and how you can organise it to help your team design and build a product in a way that creates the most value most quickly.
+

Why even do UX?

+

I mean, honestly, if you don\u2019t think it will serve you, your product, or your team, don\u2019t do it. Don\u2019t invest in work uncritically, if you don\u2019t see how it ultimately makes you more money or a better product. If you think what I\u2019m saying is dumb, don\u2019t listen or read - I think plenty of people have useless opinions, especially on the internet.

+

For clarity, when I talk about UX design, I am talking broadly at developing an understanding of an app or service from the end-user\u2019s perspective. How will they interpret the thing we put in front of them, and what can a design/engineering team to do make sure that the creative vision is the same as the user\u2019s experience?

+

It\u2019s like viewing a miniature model of a town: you can see distinct regions, connections between them, and kinds of buildings in each. But you don\u2019t get bogged down in the specifics, like \u201Cis that store a pharmacy or a grocery store?\u201D.

+

More concretely, this understanding is useful in making a product that actually does what you want it to. It\u2019s no good having an app that does something \u201Cin theory\u201D - because truly most of your users don\u2019t care about \u201Cin theory\u201D. They want to learn a another language, make a claim on their insurance, or get a new beautiful handmade scarf. This is similar to the Jobs to be Done mentality.

+

From an engineering perspective, as someone who makes apps, doing UX design helps break a \u201Csimple\u201D app into exactly how many things need to be built, and what they need to do. It lets me build the necessary things, in a sensible order, and gives me a shared language/understanding that then lets me communicate effectively with a team.

+

0: Screens & Components, State & Actions

+

Everything I do in this early UX process is designed to help me understand my app along four heuristics: Screens, Components, State, and Actions. These are the things that I find it useful to break an app into - they might be useless to you and that\u2019s okay. Do read on, and see what sticks.

+
  • Screens - these are easy to intuitively grasp but hard to define. Assuming prior knowledge of the internet: they\u2019re like URLs of a website, which will take you to a specific page, like a profile, sign-up form, or edition of a newsletter. More abstractly, they\u2019re discrete, separate views into an application which are containers of other content (i.e. Components).
  • +
  • Components - are also really hard to define - they\u2019re visual things on the screen. The ReactJS docs calls them \u201Cindependent, reusable pieces, [that let you] think about each piece in isolation\u201D. The most commonly thrown-around example of components are Buttons or Cards - they\u2019re just reusable bits of UI, that can be really small (like a button) or larger (like a log-in form).
  • +
  • State - is a way of modelling what information/data the app will store, it usually affects what will be displayed or how it will appear. For example, what\u2019s the name of the current logged-in order, what are the details of the current search/filter being set by the user?
  • +
  • Actions - are the things a user can do on a screen, what can they press, swipe, toggle, move, type into, etc. The consequences of these actions can be things like opening a modal (a Component, by the way) or navigating to a new Screen .
+

You are creating a low-fidelity working document.

+

To help identify these things, we\u2019re going to make a visual representation of each. At the early stage on the UX design process I have to remind myself often that I am creating a working document - one that won\u2019t be shared widely (or at all) within my team, let alone outside of it. This is just a way for me to organise my thinking. This isn\u2019t about making any kind of mockup that looks pretty, or crafting meaningful naming conventions.

+

Your working document will probably be ugly. Mine definitely are. I have intentionally put ugly images / mockups in this article so you can feel better about how bad yours look and how little you want to share them. Anything you create during this process is meant to serve you, not Dribbble or Instagram. Embrace the brutality and Spartan utility of your UX diagrams.

+

Trying to optimise for visual and semantic consistency at this stage makes you feel busy, without having to address the important questions. So long as I know what a component or screen means, then it doesn\u2019t matter.

+

I also really encourage you to work with pencil and paper next to you. Even if you\u2019re prototyping on paper - have more paper ready just to jot down questions, sketches, ideas as they arise to your brain. You can\u2019t go chasing down every rabbit hole - it will break your flow, and I really think it\u2019s important to build up a good flow, in this process. This flowcess. But you also don\u2019t want to lose any legitimate ideas or questions you have, they can help you a lot when you\u2019re doing higher-fidelity design.

+

Oh my plants

+

In this article I\u2019ll be using the example of an app that helps you keep track of all of your houseplants. I\u2019ve called it \u201Call my plants\u201D and I\u2019ve given it a very predictable green theme.

+

1: Identify Screens

+

So let\u2019s imagine the following user journey in oh my plants - I want to get to a page that has a whole bunch of details about a specific herb. I can get there by searching for it, by seeing it in a list of plants I\u2019ve said I own, and perhaps by an automatically created list of plants (like what\u2019s in season). This gives us five screens: starting at Home we can end up at Plant Details by going through either of the three possible routes.

+

+

This kind of layout, with the arrows drawn between them, is useful at some points, but it\u2019s exactly the kind of over-optimisation I just warned against. Because what happens if I need to add in a new screen or remove one? I have to re-structure all of the positions and arrow flow.

+

Robust software architecture is about fighting rigidity and letting developers change individual parts quickly - because requirements are always changing. Good UX design can learn from this - build a working document is about rapid change - the tool you use should work as close to the speed of your thought process as possible so that one isn\u2019t lagging behind the other.

+

I\u2019ll end up with something like this: simply a list of screens, in some semblance of order that make sense to me. In Figma I make each of these into its own Component (or Symbol in Sketch) so that when I begin fleshing out user journeys later on (like the pretty arrow diagram above) - we\u2019ll see something less abstract than just white boxes and black text to represent a screen.

+

+

2: Identify the Components

+

Once you\u2019ve got all the screens, start going one-level deeper by identifying Components - distinct bits of UI. I find it most useful to start with the high-level components - i.e. Start with high-level components - things driven by their use cases. I name these in very opinionated ways: \u201CUser Owned Plants\u201D is a list of plants the user has said they one, and \u201CIn Season Plants\u201D might be a list of plants that are ripe for planting.

+

After I\u2019ve done that, I start identifying the lower level components: things which are not so closely tied to specific use cases. Prime examples are Lists and List Items, as well as Buttons or Cards. Use your own discretion and opinions here: is a SearchBar component distinct from a TextField - or should they be the same thing? I would advise leaning towards how you communicate things to the user: do you want them to conceptualise a search bar as the same thing as a field in a form? For me, I would keep them as different components, but I could very easily see it argued either way.

+

+

3: Identify State

+

With your new list of screens and components, you\u2019re going to want to go through and make a note of every possible variant based on state.

+

+

This is when things start to get a little complex/tedious, because it can massively increase the sheer number of screens and components that it looks like you\u2019re going to have to design. It\u2019s also worth paying attention here to the kinds of State - chances are there aren\u2019t that many discrete ones, and they can come in groups and are conceptually related: selected/disabled, read-only/edit, locked/available, active/not-active.

+

When it comes to the actual design, you\u2019ll be able to share visual metaphors here. In fact I would suggest that kind of consistency can make complex business logic or states feel much more simple than their implementation details. If things are disabled/inactive/locked, for example, the result in very similar to a user: there\u2019s a thing on the screen that I can\u2019t interact with right now.

+

Wait, why do I need state on my components AND screens?

+

Yeah, this is a very fine line - and totally is a matter of opinion. This is one of the points that makes product and UX design a skilled profession.

+

For me, it comes back to what I said at the beginning: UX is about understanding how the user will perceive the product. Even if the information we\u2019re presenting is correct, it\u2019s the way it\u2019s presented that makes the difference between a good and a great experience.

+

Enough talk, let\u2019s give an example. Imagine oh my plants knows when\u2019s the perfect time to plant each garden herb. It has a PlantList screen - which is a simple list view of PlantListItems.

+

A PlantListItem represents one individual plant - which is the thing that\u2019s in season. Following that logic, we want to flag each plant as in \u201Cin season\u201D.

+

+

In practice, however, the fact that all the plants are highlighted means that none of the plants are highlighted. It also just looks weird and cluttered and busy. Instead, what if the PlantList was highlighted with some special way of saying that it is in-season?

+

4: Identify Actions

+

An action is normally something that changes the state of a component or screen, or that navigates the user around the app.

+

If you identify actions at this point in the design process, it should be really easy for you. It\u2019s probably anything that uses a component like button or select or switch or tab\u2026 you get the idea.

+

+

Conversely, if you recognise there are actions that are triggered by clicking non-typical components, like undecorated text or header - then maybe these are interaction patterns you need to make discoverable to your users.

+

What\u2019s considered \u201Ctypical\u201D depends on the conventions of the platform, e.g. long-press and double-tap on mobile don\u2019t really have equals on the web.

+

5: Go forth

+

Look, you made it all this way, congrats because even I struggled to make it this far down when I was proof-reading. Hopefully at some point along this journey you\u2019ve thought \u201Cwait, why am I doing this next bit, surely I should go off and do something else instead\u201D - then good. Go do that other thing, like thinking about adding new features or, even better, removing others, or making clearer visual metaphors or condensing many metaphors into one.

+

You\u2019ve hopefully got a much more complete and accurate (read: big and scary) picture of your product: all the things it needs to do, what you need to build, and exactly how many designs you\u2019ve got to flesh out and then build. Or throw over the wall to the developers and hear them argue over for the next 2-9 months.

+

Take this blueprint forward and make something you\u2019re proud of, or ignore my opinions and become successful anyway - I truly do not mind.

`; +}); diff --git a/.netlify/server/chunks/2020-03-22-chosing-react-native-for-hereabouts-b7863833.js b/.netlify/server/chunks/2020-03-22-chosing-react-native-for-hereabouts-b7863833.js new file mode 100644 index 0000000..3f3c1a1 --- /dev/null +++ b/.netlify/server/chunks/2020-03-22-chosing-react-native-for-hereabouts-b7863833.js @@ -0,0 +1,73 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_03_22_chosing_react_native_for_hereabouts, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Why I chose React Native to build a new app in 2020", + "author": "Thomas Wilson", + "date": "2020-03-22T00:00:00.000Z", + "slug": "2020-03-22-why-i-chose-react-native-for-app-in-2020", + "draft": false, + "tags": ["react-native", "react"] +}; +const _2020_03_22_chosing_react_native_for_hereabouts = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I am currently in the process of building herabouts - an app that\u2019s like a tour guide, only cooler. Most of my previous engineering work has been web-based (react and vue) because the internet is an accessible and very capable system for building modern applications. However hereabouts needed certain native functionality - like location, reliable offline data access, battery status, and access to the camera. Yes some of these things are possible on the web, but they\u2019re much more native functionality.

+

I\u2019ve made the decision to write the app in React Native - a library for creating applications for native platforms (like iOS and Android) using React and JavaScript.

+

I wanted to share the reasons I made this decision because despite having worked with React Native for clients in the past, I was cautious about adopting it for a personal project. AirBNB famously abandoned React Native in 2018 citing a couple of pretty damning reasons: long initialisation and first-render times; lack of code-sharing between platforms; mixed developer experience.

+

In the same post, however, they say that most (80%) of their devs found the experience at least slightly \u2018positive\u2019 (subjective as that is), and acknowledged that a lot of their problems may relate to the the size and complexity of their team and product, alongside the early nature of React Native at the time. In the years since that was published, React Native and the surrounding ecosystem (like expo) have made the development experience of making a native app a lot better. Big tech companies, like Shopify, have also adopted React Native.

+

It\u2019s never a clear choice what tech to use, and it\u2019s especially difficult when you\u2019re starting something new and have no constraints. So I wanted to make sure I was making an informed decision, and this article outlines that process.

+

Why not native-native?

+

I initially started working on hereabouts as a native iOS application, written in Swift. At present (March 2020) Apple are transitioning the way UIs are written in Swift to use SwiftUI. The API for SwiftUI is still in beta (currently beta 4) and still has a few quirks (e.g. see this Reddit post) that made the process of building an app cumbersome and awkward. I was unsure of the relationship and split of responsibilities between the existing UIKit, storyboard, and SwiftUI. Given how SwiftUI is largely seen as the future of iOS development (and its declarative philosophy shared by react), I didn\u2019t want to tie myself to supporting an app written without it, nor did I like the possibility of having to maintain a hybrid UIKit/SwiftUI app where the roles and responsibilities of both parts were changing regularly.

+

This opened up the possibility of creating my app using a cross-platform library - not because I wanted a cross-platform app, but because I wasn\u2019t happy with the native tooling. This just happened to open up the Android market. Previously I made the decision to focus on iOS over Android because a) I am personally all in on the Apple ecosystem, and b) more money is spent in Apple\u2019s App Store and in the Google Play store. Although I\u2019m not making hereabouts to get rich, I\u2019d certainly like some gin money.

+

Reason #0: I already know React

+

The simplest reason for me choosing React Native, over say NativeScript or Flutter, is that I already know React. I\u2019ve got experience writing production and personal static websites and enterprise apps in it. The declarative and data-bound nature of writing React, especially with TypeScript, comes quite naturally to me now.

+

NativeScript supports Angular and Vue as first class citizens, which I simply don\u2019t use as much as React. I started off my Frontend Engineering career writing apps in Angular, and I\u2019ve written a couple of fast and easy websites in Vue. They\u2019re good frameworks, but right now I think React has a large (if not consistently good) community. I know how to handle complexity in React, and I have opinions about styling and architecture that React doesn\u2019t fight.

+

Additionally, Google has a reputation for sunsetting projects with little notice, which makes me a little apprehensive about Flutter.

+

Reason #1: React Native isn\u2019t a hybrid WebView app

+

Many people\u2019s gut reaction to creating a cross-platform app is to think of something laggy, and distinctly un-native. One of the simple and earliest approaches to adopting cross-platform mobile development was to use web technologies, which are famously cross-platform and system agonistic, and have the native app render the web app (in its own HTML, CSS, JS) through a WebView. This is how platforms like Ionic and Cordova work - and they\u2019re great for very simple apps, but they\u2019re notoriously not very performant.

+

Native apps are better than, and distinguished from, websites by how \u201Csnappy\u201D they feel - how responsive the app is to a button being pressed, giving haptic feedback, and then navigating somewhere. It\u2019s hardly noticeable when done right, but when there\u2019s a 400ms delay between pressing a button and seeing something happen - you will notice.

+

However, React Native works differently: you write your views using JSX, and these are then bridged to native code for iOS and Android - meaning, at some point, it becomes native, and is not just a DOM.

+

Let\u2019s just take a second to clarify some of these words: first JSX is an extension to JavaScript (or to give it its full title: ECMAScript) that introduces XML-like syntax for creating structured data. It looks an awful lot like HTML, but with a few syntactic differences, and the ability to include data in the structure:

+
${`import React from \u2018react\u2019
+
+const Message = () => {
+	return (
+		<div style={{colour: \u2018blue\u2019}}>
+			<h1>Hello!</h1>
+			<p className=\u201Cmessage__text\u201D>Welcome, friend</p>
+		</div>
+	)
+}
+
+export default Message`}
+

JSX is syntactic sugar - its goal is to makes the code easier to write and parse by the humans who have to read and write it. It\u2019s also a separate library from React and React Native, but is used by both libraries by default as a way to construct a virtual representation of view elements, like HTML Elements or DOM Nodes. It compiles down to something different, and instructs React to do React-y things like createElement() but we\u2019re not talking about that here.

+

The second term I want to bring out and talk about is bridging. For an application to run natively, it has to be able to talk to the system in a language and API it understands: e.g. UIKit and Objective-C/Swift for iOS, and android.View with Java/Kotlin for Android. This is a distinguishing factor between cross platform apps (like those in React Native) and the hybrid WebView Apps - we can use a cross platform application to communicate with native APIs, like maps or device orientation.

+

The part of the architecture that lets a JS thread, where a React Native application runs, talk to the native Threads, is called the Bridge. The details of how this works are covered for both iOS and Android in the React Native docs and aren\u2019t really relevant for this discussion - just know they happen.

+

This article isn\u2019t an explainer about JSX (but JSX is a interesting idea, regardless of what you think about React itself) or Bridges - but they\u2019re two big technological differences between React Native and other libraries that let you use web technologies to write apps.

+

Reason #3: The performance and benchmarking discussions are nuanced

+

One of my core beliefs (read: something I work very hard at, but am not necessarily always good at) is only releasing/selling products that I would be happy for someone to pay for. Above all other things, I want hereabouts to have a native feel - to be responsive and feel intuitive to use. It needs to hit that magical 60fps bar, and feel like a first class citizen on a mobile phone because that is what I would expect from an app that I paid for.

+

I\u2019ve seen a couple of blog posts that (like this one from inVerita, and this one from Thoughtbot) about the performance of React Native that had me worried that I\u2019d be fighting an uphill battle to get performance two where I wanted it.

+

Fundamentally, though, good performance in React Native is possible. It requires a thoughtful consideration around what you\u2019re doing, and building with the tools that let you investigate and profile your app to let you know when there\u2019s a problem.

+

It\u2019s much easier to read an article and see how React Native (or any tech) \u201Chas bad performance\u201D but this depends too much on what you\u2019re doing and how you\u2019re doing it. It\u2019s a nuanced discussion and it also gets at the whole \u201Csoftware engineering is a skilled profession\u201D thing. The research I did in this area was enough to assure me that I can code myself into a bad situation, but I can code my way (at least mostly) out of it.

+

So I\u2019m not overly concerned about poor performance in hereabouts just because it\u2019s written in React Native. Of course I am concerned about it, but I don\u2019t think this is a problem unique to the platform.

`; +}); diff --git a/.netlify/server/chunks/2020-04-02-hereabouts-devlog-2-264ab07c.js b/.netlify/server/chunks/2020-04-02-hereabouts-devlog-2-264ab07c.js new file mode 100644 index 0000000..7afcda5 --- /dev/null +++ b/.netlify/server/chunks/2020-04-02-hereabouts-devlog-2-264ab07c.js @@ -0,0 +1,83 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_04_02_hereabouts_devlog_2, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Hereabouts devblog #2 - March 2020", + "author": "Thomas Wilson", + "date": "2020-04-01T00:00:00.000Z", + "draft": false, + "slug": "2020-04-02-hereabouts-devblog-2", + "tags": ["hereabouts"] +}; +const _2020_04_02_hereabouts_devlog_2 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Hi, I\u2019m Thomas Wilson, I\u2019m a web and mobile engineer building Hereabouts - an app that\u2019s like a tour guide if the tour guide was like Roman Mars after three beers. This is a devblog where I talk about my progress building that app. Also I\u2019m very sorry, Roman, you\u2019re one of a handful of people who I genuinely aspire to be like please don\u2019t take me seriously.

+
+

Well March 2020 has certainly turned out to be quite the introduction to working on a side project. It\u2019s the month that the UK (and Europe, North America, etc.) started nationwide lockdowns to prevent and slow the spread of Covid-19. Social distancing, self isolation, and quarantine are all in full swing.

+

Imagine starting a side project based almost entirely on being able to travel somewhere new, or even just go outside and walk around. It\u2019s a strange time, but everyone\u2019s talking about it being a strange time, and honestly we\u2019re all just trying to find a new temporary normal. So with that in mind, here\u2019s an inconsequential update on Hereabouts.

+

I\u2019m still pretty undecided on the format of a devblog, which makes this one a brain dump, but definitely the kind of brain dump that you should read.

+

Notable things

+
  • The Covid-19 Pandemic.
  • +
  • By September-October, I want something that I would be happy for someone to download, and happy to ask them to pay for. Assuming there\u2019s still an App Store to host on, a functioning economy, cities to visit, or people to buy it. Okay that was my last Coronajoke. And that, my last coronamonteau.
  • +
  • Decided on running development in 4-6 week cycles. This is based off what I\u2019ve read from Basecamp, but also a general understanding about how long things actually take to design and build to a certain quality.
  • +
  • Started building more formal documentation (in Notion and Figma) for use case + market summaries, user journeys, business entities, and visual design language.
+
  • Purchased hereabouts.app domain, built a simple landing page (ReactJS on NextJS, hosted on Zeit\u2019s Now), and created a mailing list that so far only my friends (and not even my parents (?!)) have signed up for (SendGrid, NowJS API routes, and CloudFlare worker).
  • +
  • Started building the app. Started in Swift, moved to React Native. Enrolled in Apple Developer Programme (arguably too early - it\u2019s a motivator)
+

What an Emotional Rollercoaster, feat. The Covid-19 Pandemic

+

This past month has been one of the most varied emotional months I\u2019ve had in a long time. I my emotions to be strong in number and force at the best of times, but imagine quitting your job to go freelance in what is possibly the worst time in 30 years.

+

I am not a stranger to self-doubt. I often think I am about to get fired, when in reality I have never been fired, or come close to being fired. Maybe I have and I\u2019ve just instinctively played the \u201Cyou can\u2019t fire me I quit\u201D card.

+

The big situation here is the SARS-COV-19 pandemic that\u2019s needling through the globe right now, causing unnecessary loss of life and bringing an economic recession and a wake of social crises. What a time to be alive.

+

Can you imagine finally deciding on a side project you want to carry through to production/publication, and then a global pandemic breaks out. Not great for the global community or economy, or for an app specifically built around the idea of being outside. This comes at at time where most of the advice from European governments is to stay inside, with increasing policing and enforcement.

+

I\u2019ve had to seriously think if building this app remains a good idea, and I think it is. I really struggle with shiny-things-syndrome, where I flit between and around ideas and never commit fully to something. Hereabouts is the first side project in 3-4 years that I decided to see through seriously and then did something about. It\u2019s the only one that made it past a line in a note on my iPhone. It\u2019s not the only idea I\u2019ve got rolling around in my phone\u2019s notes, and it\u2019s probably not even the best one. But it\u2019s one that excites me: it\u2019s an app I would like to have and use, and it\u2019s something that I think can offer value to people. It\u2019s also going to teach me a lot about launching an app in the real world.

+

Yes, a pandemic with strong government response is a good mitigating factor - March 2020 has truly been wild, and I don\u2019t think anyone would blame me if I let the idea go to find something more stable. Like a Zoom alternative or remote yoga teaching software. Or just a Zoom alternative without extremely concerning privacy policies. I\u2019m sure video conferencing can\u2019t be that hard, there\u2019s no reason that all the alternatives are terrible to use.

+

What\u2019s more, the current economic climate has seen travel and leisure industries basically tank out, and it\u2019s looking a lot like many people this year won\u2019t be able to take holidays. Some of those holidays will be honeymoons, or retirement cruises, or long-overdue personal relaxation time. This pandemic is making a lot of us suffer in a lot of ways, but I digress. There\u2019s a global recession threatening and although central economic bodies are all trying to act to mitigate these factors, there\u2019s a chance that people don\u2019t have money to spend.

+

I am aware that I don\u2019t want to continue under the guise of hustle porn - I don\u2019t want to see this hardship and fight against it just because it\u2019s a struggle and it makes a great narrative. I don\u2019t want to think of myself as a company that was shaped by the COVID-19 quarantine and panic. I don\u2019t really see that as an influential factor in what I\u2019ve decided to do, or how. What\u2019s more, I don\u2019t think end users really care about how or when an app was made, especially as people will (hopefully) start to forget what things were like during these times within months of them ending.

+

The primary reasons I want to continue development of this idea, at least for now, is how early in development I am and how this remains a side-project. I have other full time work that lets me pay the bills and I don\u2019t need this to take off. I\u2019ve given this project about 6 months, taking it to the end of summer (September-is) which was always going to be just off-peak for summer for tourism. But it looks like we\u2019re not going to get peak tourism anyway on account of the global lockdown. I want Hereabouts to be an app that could be used by someone who already lives in a city, and as a cheap day activity for anyone. I think there remains a market for the app, and the possibility that I learn some interesting things from releasing it to a smaller audience.

+

In short: I\u2019m going to continue with development. It\u2019s just a weird part of the Hereabouts story - that the worst pandemic in literally 100 years strikes just as I get going with it. What impeccable timing.

+

Thinking about development cycle and Topic Lock

+

I disagree with common practice of two-week sprints and an endless backlog as the best way to manage and drive software development. I think it\u2019s short sighted and makes you feel comforted by how busy you are and how much work you have to do. If something\u2019s important, it will keep raising itself as important, and I shouldn\u2019t move on without it. If something feels important but I forget about it quickly, and didn\u2019t latch on and flesh it out - it probably wasn\u2019t actually that important.

+

This is especially true for right now: creating the idea for a new product, and then putting that into concrete UIs and code. What is Hereabouts, what does it do, and how is it used? These questions are the most rabbit-hole kinds of questions, because there\u2019s a lot of edge-cases and what-ifs that can found or ruin a feature idea.

+

I want to feel I have the freedom to go down these rabbit holes because they are important and I don\u2019t want to spend time and energy justifying that when I could spend that energy exploring them.

+

To counteract the (very real) chance that I spend all the time designing or thinking of possibilities, and no time actually building them, I am thinking about how I can integrate the Double Diamond process which is a needlessly buzzword-y way of saying that I am consciously separating out the processes of a) generating as many ideas as I can, and b) paring these ideas down to find the useful or recurring ideas.

+

Alongside that, I am thinking about Topic Lock. This is something I first heard from CGP Grey said in the Cortex podcast, in regards to his work as an independent content creator. It\u2019s influenced from the way movie studios produce movies, and the Kanban project methodology: have a fixed number of things that are in progress.

+

I am striving to build a way of working that allows me to create and shape ideas, but also then critically examine the ideas individually and as a collective.

+

This is getting abstract and I\u2019m only a month in, so I\u2019m going to save this for another time. But look - I\u2019ve been thinking about how to create a process and environment that works well for me, my brain, and the product.

+

User Journeys, Internal Documentation, and Design Language

+

This is my party, I\u2019ll do what I want, and I want to start by talking about the tools I used to do this work because I find that more interesting than the work itself. I\u2019m not proud of this part of me, but I love well designed, cool, and hipster apps.

+

Notion is hard to describe: it\u2019s like a Google Doc meets a database. I actually wrote about why I gave up using Notion back in August so this is a little embarrassing - but I stand by what I said: I cannot use Notion to write long form prose, like this. I am writing this blog post in Bear.

+

Notion does let me capture my thoughts in a much more organised way, compared to plain text and markdown. I\u2019m not going to go into detail about how I use Notion specifically, but I am using it for:

+
  • Writing that I don\u2019t intend to share but need to refer back to, e.g. business models, elevator pitch. Like a classic Wiki.
  • +
  • Articulating and formalising the goals I have for a particular development cycle.
  • +
  • Keeping track of the business entities or key \u201Cthings\u201D in the code base, like what is a \u201CTour\u201D and \u201CPlace\u201D, etc.
  • +
  • Noting down research for both the content of Hereabouts (like interesting places), and the meta research around running a business.
+

Notion gives me freedom but also constrains me a little more than free form text. This is useful when I just need to get my goals and intentions down, and not spend hours worrying about how it looks. Notion\u2019s got great design by default, kudos.

+

They\u2019ve also fixed the navigation by Smart Keyboard on the iPad THANK GOODNESS. Not being able to move around in a sensible way without using my slow meaty dumb fingers on the screen was infuriating. I didn\u2019t spend dozens of hours of my life forcing vim\u2019s philosophy into my own world view to have it ruined like this.

+

User Journeys and Design Language - Another blog post (in Figma and Notion)

+

I\u2019ve done a lot of work this month doing visual and UX design. The results, and how I manage these parts of my thinking and planning can\u2019t / shouldn\u2019t be described here because this is a devblog. I\u2019ve made a note to write about them in more detail later.

+

React Native

+

I wrote a more in-depth post about why I choose React Native, also on my blog. So yeah, I\u2019ll be writing this thing in TypeScript, using React Native, and the Expo platform.

+

Let\u2019s take a whole paragraph to acknowledge how good a job the Expo team are doing. Honestly, such brilliant tooling.

+

I started working on this project in Swift: first with SwiftUI then moving to UIKit.As someone\u2019s who\u2019s more fluent in frontend engineering (3 years full-time professionally), having to debug some of the problems and limitations of the new SwiftUI API wasn\u2019t productive. I simply don\u2019t have the frontline experience of using Swift in a production environment that made debugging and interpreting documentation a viable option.

+

Moving to UIKit very briefly made sense, but SwiftUI is the future of development on Apple platforms so why waste time working through that.

+

I\u2019d like to come back to SwiftUI in a couple of months/years, when it\u2019s out of beta. I hear good things about it, and it sounds like they\u2019re bringing in an opinionated declarative philosophy. I\u2019m excited to see how this affects the UI development community at large.

`; +}); diff --git a/.netlify/server/chunks/2020-05-31-unicorns-06ff6905.js b/.netlify/server/chunks/2020-05-31-unicorns-06ff6905.js new file mode 100644 index 0000000..f152389 --- /dev/null +++ b/.netlify/server/chunks/2020-05-31-unicorns-06ff6905.js @@ -0,0 +1,54 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_05_31_unicorns, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "I don't want to be a unicorn \u{1F984}, an engineer or a designer - I just want to build things better", + "author": "Thomas Wilson", + "date": "2020-05-31T00:00:00.000Z", + "draft": false, + "slug": "2020-05-31-unicorns", + "tags": ["frontend", "essay"] +}; +const _2020_05_31_unicorns = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I like building software, or parts of software, which are visual and interactive. I do not particularly enjoy the more abstract, very important, areas like technical optimisation, language design, or anything with the word \u201Cdistributed\u201D in it. I like building user interfaces (UIs); but also architecting and engineering the code that underlies these interfaces, so that engineers can build delightful and functional UIs, without going through as much effort. Good UI and user experience (UX) should be a norm, a default.

+

A lot of people either design or code. People with feet in both sides of this skillset are often referred to as Unicorns \u{1F984}, because people who do this are rare.

+

I don\u2019t like the term Unicorn, but it is dangerously close to describing where I am working hard to move my career. I have a difficult time explaining what I do to people. This is a problem when I want some of those people to pay me real human money to do that thing that I can\u2019t quite explain. The current software/technology landscape has made it hard for me to feel I can convey my self, my interests, and my skills using the small number of keywords (Engineer, Designer, Manager). I don\u2019t want to be a unicorn, or an engineer, or a designer - I would like to be seen as a professional who can help teams and companies build things better. And this little essay is nearly 2,000 words asking why is that so difficult to convey in a way which is taken seriously \u{1F937}\u200D\u2640\uFE0F?

+

Unicorns \u{1F984}

+

This is a subject I\u2019ve had to mull over since I entered the workforce 4-5 years ago. I have a very clear memory of listening to Episode 318 of the Design Details podcast, apparently in mid-late 2019, in which the co-hosts answer a question about the topic of unicorns (emphasis my own, I\u2019ve not transcribed the \u201Cerms\u201D and \u201Clikes\u201D which were superfluous, forgive me):

+

I\u2019ve been thinking about this idea of a unicorn, I think it\u2019s kind of a meme at this point. A designer being a unicorn is a designer who can code. I think that\u2019s actually not possible anymore, or maybe it hasn\u2019t been possible for a long time. And if we add in product management into the that, the ability for a single person to be really good at product, and also really good at design, and then when you get into coding it becomes so broad it\u2019s like: okay, can they make iPhone apps? Android apps? Websites? Can they do the frontend and the backend, are they really good at animation and visuals? Can they do user research? There\u2019s so many disciplines that to expect that of one person seems entirely unreasonable. And thus, kind of breaks the idea of a unicorn being one person who can do it all.

+

While I was searching around for other people\u2019s opinions on this matter, it\u2019s hard to find people praising the idea of hiring a unicorn, or marketing yourself as one. I\u2019ve seen them called \u201Cso hard to hire they might as well be imaginary\u201D. Or that \u201DHiring a generalist typically means you hire someone mediocre at everything.\u201D. Or criticised as \u201Dcreating teams that are light on experience and overly competitive to move onto the next skillset before mastering the previous one\u201D. These are all valid criticisms that any business looking for a cross-discipline employee should be aware of.

+

Despite this criticism, I think the relatively recent expansion and funding in the no/low code tools space is evidence that creating software shouldn\u2019t always be done by those with the technical knowledge or experience. Most directly with tools like Framer, which prides itself on being able to output code from visual prototypes. There\u2019s more to software than a robust codebase, and engineers can be better utilised than a widget/JIRA/feature factory. The notion of sliding pizza and some printed-off functional requirements under a door and waiting 3 months for the software to emerge is a funny trope. It\u2019s a trope because it was once more widespread than it is today, but also because it implies that engineers are only code machines. That they cannot bring technical and creative energy to a project.

+

Specialisation and language

+

I, like a lot of humans, am not just interested in one thing. I imagine very few accountants go home and keep thinking about accounting (by choice), and I\u2019d imagine even less janitors go home and think about building maintenance. In the west we accept having hobbies and interests outside of work as normal, and to some extent, w expect it. If I go on a date with someone and they have literally 0 hobbies (liking food, travel, dogs, and gin are not hobbies or a personality \u{1F645}\u200D\u2640\uFE0F) that\u2019s probably going to be the last date.

+

In a professional context, however, it\u2019s much more common to do one thing, or a narrow set of things. Sure, we change jobs, but this is mostly in seismic events - a promotion, a sideways move, a career change. Economically speaking, allowing people to specialise makes sense - it\u2019s division of labour. We should let jobs be done by those who are good at them, and we can offer more value to a company (and therefore the entire economy) by having a higher unit output per unit input. I can\u2019t turn up one day to work and play CEO, then turn up on Wednesday and be HR, then round the week off by being CFO. If you listen closely you can hear all the co/founders of small, scrappy startups blustering \u201CBUT THAT\u2019S WHAT I DO\u201D - listen Jennifer, you know as well as I do that the first thing you\u2019ll do if you have money is hire someone to do the things you don\u2019t like doing, and they\u2019ll do it better than you\u2019ve been doing it. You\u2019d be mighty annoyed if you hired Benedict to do your accounts for you, and two weeks later he\u2019s running your Instagram marketing campaigns instead of running payroll. Stay in your lane Benedict \u{1F44E}

+

Look, I got off track, let\u2019s bring this back to software. There\u2019s a lot of things to build when you\u2019re building a system of software to support a modern business. Sometimes, there\u2019s not a lot of room for mistakes in these systems: your bank and the government need the highest quality security, search engines need the fastest indexing, e-commerce websites need to load fast, and so on. No one person can master all of these things - if they could, then they would - but I would be so bold as to say that most software engineering teams are more than one person big.

+

Like a lot of things, the closer you look at each area of software, the more detail you see. I\u2019ve got a bit of experience working with web technologies - over the past few years, people have been really ambitious about what they can do with the web platform and technologies. The result is a bigger set of moving parts that you can plug together to produce really engaging, sturdy, and high quality software. Arguably, we\u2019re getting a little bit carried away with all we can do but let\u2019s stay on track.

+

I really like Chris Coyer\u2019s idea of The Great Divide, a term and an idea which evolved from conversations he has on the podcast he co-hosts (Shoptalk Show). The tl;dr is that \u201Cfrontend engineer\u201D or \u201Cweb engineer\u201D no longer gives you enough granularity to summarise someone\u2019s job, or skillset. Instead, you can think about it in terms of the \u201Cfront of the front\u201D and the \u201Cback of the front\u201D.

+

This division rings true for me personally. My interests and skills in web are around creating and systemising visual design, and creating accessible, usable pages. Equally valid is someone who loves working with web technologies because the challenges in data fetching, build process, authentication or security. These are different jobs, but both could very easily fit into the category of Frontend Engineer on a job board.

+

This isn\u2019t just a frontend thing: I see similar things happening with DevOps and Reliability Engineering: these are engineers tasked with making sure software is deployed in a sound and reproducible way, and consistently available to the end user. Some people say this is everyone\u2019s job, someone people say it\u2019s a speciality.

+

So\u2026?

+

So why does any of this matter? Look, if you want to get high minded about it, but you need to know what makes you happy on the day-to-day basis, because life is just a series of day-to-days and we shouldn\u2019t underestimate their importance. For me that\u2019s about knowing what kind of problems my brain enjoys solving, and what kind of work I find meaningful. It\u2019s also about knowing the kind of people I want to work with and for. I cannot really do any of that, if I cannot explain what I do professionally.

+

To make it more pragmatic, businesses need to know what kind of technical and creative talent they\u2019re trying to attract. We need the right words to describe the job - for some companies it will be \u201Call about the koolade-train\u201D - looking for Design Unicorns. For others it might be more toned-down, or basic, UI/UX Engineer or Design-Developer Hybrid. Even if these jobs are functionally identical, you will be signalling more than just the functional requirements.

+

The final thing I wanted to end on is something that I only realised when I was in the process of putting my stray and abandoned thoughts together into writing. It is dangerously easy to use these words, like hybrid or unicorn and accidentally misrepresent your ability or competencies. Or if, for example, you\u2019re writing - the vagueness makes it all too easy to make sweeping generalisations. The term Unicorn appears to have been adopted for the design-code boundary I discussed, but also a UX Unicorn, and also engineers who work at Unicorn (i.e. >\\$1bn valuation companies). We have to use language to make shortcuts, in part because not everyone can understand everything (like how we say \u201Ccompiler\u201D when really we mean \u201Cmagic box\u201D). When we use words like \u201Cfull stack\u201D or \u201Chybrid\u201D or \u201Cunicorn\u201D - they\u2019re so vague, you\u2019re asking people to fill in the blanks with their own colours or words, which is kind of like asking people to put words in your mouth. Something a true unicorn would never do.

`; +}); diff --git a/.netlify/server/chunks/2020-06-11-deploy-rails-in-render-30f28e2a.js b/.netlify/server/chunks/2020-06-11-deploy-rails-in-render-30f28e2a.js new file mode 100644 index 0000000..3947345 --- /dev/null +++ b/.netlify/server/chunks/2020-06-11-deploy-rails-in-render-30f28e2a.js @@ -0,0 +1,78 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_06_11_deploy_rails_in_render, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Deploying an MVP Rails App with Render like it's 2020 ", + "author": "Thomas Wilson", + "date": "2020-06-11T00:00:00.000Z", + "draft": false, + "slug": "2020-06-11-deploy-rails-in-render", + "tags": ["devops"] +}; +const _2020_06_11_deploy_rails_in_render = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

\u{1F4DA}tl;dr - I used Render to deploy a Rails app and database. It was very easy, very fast, and very modern. Would recommend to everyone.

+
+

Way back before the pandemic I had the idea for hereabouts - an app that people can use to explore the city they\u2019re visiting, or live in. After making a landing page, working hard to build a lot of UI and UX prototypes, and beginning the process of emerging from national and international lockdown from a pandemic, I\u2019ve had to come to the part where I build out a backend API - to store data, largely.

+

I\u2019ve decided to use Ruby on Rails, a framework for web applications written in Ruby, to build out my backend. I don\u2019t want to talk too much about why I made this choice - but the short answer is it\u2019s reliable, boring, and I\u2019m fast at building with it (or at least I was, back when I was using it every day). \u201CBut Wilson, why aren\u2019t you using Microservices\u2122\uFE0F\u201D - I don\u2019t know fictional question answer, probably because I don\u2019t expect to run into the problems that people argue microservices can solve for you. If you\u2019re interested, I think this panel discussion gives a good primer.

+

After building out the very basics of my rails app, I wanted to get it hosted so I could start toying with integration to the mobile app I\u2019m building. And I had an absolutely terrible time of it. I lost the best part of a weekend trying to solve this problem. Why? Why is the \u201Cdeploy this app to a server\u201D story so unclear, for one of the notorious and used web frameworks in the world.

+

The Demands

+

I\u2019ve spent the last few years mostly in FrontendLand, where all the cowboys and cowgirls have been absolutely spoiled by the modern deploy process for websites.

+

You can set Netlify to deploy a static website in probably under a minute, pay nothing, and it\u2019ll watch a git repo and re-build when it sees changes, provide you with immutable URLs for each version, and just\u2026 work. The list of integrated features from Netlify is impressive: split testing, cloud functions, a CMS, and some other. Netlify aren\u2019t event alone, Vercel (previously Zeit) are building out NextJS (a framework for building websites using React) and will host websites and cloud functions on The Edge. It\u2019s like GitHub pages, GitLab pages - but taken one step further.

+

For better or worse - modern software needs more than just a stateless interface - we\u2019ve got to put data somewhere. I don\u2019t want to have something beautiful and clean on the front, but disgusting and cumbersome on the back. Deploys should be frequent, which means they have to be easy and without friction for the developer.

+

I want to deploy my rails app\u2026

+
  • Easily - I want the app to build somewhere, and then be deployed. I am not a DevOps or infrastructure kinda-guy. I can ssh into servers but it makes me nervous, and fundamentally I\u2019d rather use my time to learn things other than unix and server platforms.
  • +
  • Cheaply - I want the server hosted somewhere, I can\u2019t just run it locally. But for the next 6-12 months at least it\u2019s going to see very little traffic, and I do not want to pay more than I have to for the resources I am not using.
  • +
  • Alongside a database - I\u2019ll happily throw up a Postgres database somewhere, and object storage somewhere else. I just want a server (real, or containerised) to run a ruby application, allow network traffic, support environment variables, and map between some ports.
  • +
  • Integrated with git - Having tasted modern dev ops, where test suites run, and deployment happen automatically alongside the git activity, I don\u2019t want to go back. I want easy integration between hitting git push locally, and seeing something happen on a server.
+

\u274C Create a Virtual Server

+

I\u2019ve been a fan of Digital Ocean\u2019s no-nonsense pricing and interface since 2014 when I deployed my first Rails app. So I went to their site, spun up a PostgresSQL database and small Ubuntu droplet for a combined cost of \\$25/month. An absolute steal, and enough power to probably go un-touched for the next 12 months.

+

What followed after was an entire day of figuring out how to configure rails to run as a daemon process on ubunutu, which rails-friendly web server to use (I tried puma, passenger, and mina), how to match that to the nginx configuration, and then how to re-deploy that.

+

I am at a loss as to why there are a) so many different ways to deploy a rails app on an unix system, and b) why trialling each of them in turn produced equally cryptic but entirely dissimilar errors.

+

For a framework who gives you Convention over Configuration (thank goodness) - why is there no simple, blessed, recommended path for deploying. Surely every rails app that gets spun up has dreams of one day being deployed in the big wide world, it\u2019s a basic use case. It is the use case. Why is the advise and experience here so different. Why did it take me, an engineer with at least some experience managing server deploys, a whole day to get something to not work.

+

Results:

+
  • \u274C Easy: Running the service wasn\u2019t always simple
  • +
  • \u2705 Cheap: \\$25/month for server and database
  • +
  • \u2705 Database: Got a hosted/managed Postgres database
  • +
  • \u274C Integrated with git: No native/simple git integration
+

\u274C Deploy on the Cloud

+

I turned my eyes towards the promising metropolis of Cloud Providers. I\u2019ve got a few other projects spun up on Google Cloud, so I gave them a go. It\u2019s worth noting that I\u2019m using their Cloud Storage for blob/data storage in the app (like images). I could have used AWS, yes.

+

The platform had some some documentation on how you could deploy a rails app, which was useful. They suggested three possible pathways:

+

Deploy on a virtual server with Computer Engine: We\u2019ve just been through this with Digital Ocean. Fool me once\u2026

+

Deploy with Kubernetes. I\u2019ve only got a passing familiarity with containerising apps, solely using Docker. I didn\u2019t much fancy having to learn a whole new set of technologies and terminologies to deploy an app, nor did I want to risk copy-pasting things from the internet. I\u2019ve heard horror stories of resource provisioning getting out of hand, which would obviously affect pricing and cause it to spike. At present, I would rather have a predictable pricing model, and not be worried that it could spike without warning.

+

Deploy as Backend As A Service on App Engine. This is Google\u2019s own platform for containerising and distributing apps as serverless. This looked good at first glance, but after using their pricing calculator I could end up paying somewhere between \xA330-50 per month. This is a fine cost for a production environment, but but not compared to the \\$10/mo Digital Ocean droplet I\u2019m comparing it to.

+

Results:

+
  • \u{1F937}\u200D\u2640\uFE0F Easy: I didn\u2019t actually try any of them
  • +
  • \u274C Cheap: At least \xA330/month just for the server
  • +
  • \u274C Database: Didn\u2019t come with a database included, would have to u
  • +
  • \u2753 Integrated with git: No, but it does integrate with the Google Cloud CLI so it could be easily configured with a hook
+

\u2705 Used Render.com

+

I can\u2019t remember how I found out about Render. I think they came to my attention when they won Tech Crunch\u2019s Disrupt award. I think I also heard about them in a conversation about next generation cloud providers making a market by essentially taking a single service in the current cloud providers, and doing it really well. I think that might have been on this episode of Software Engineering Daily.

+

Using Render to deploy the app took me maybe 30 minutes, and it reminded me a lot of the FrontendLand experience that Netlify normalised. It\u2026 just works. They\u2019ve got first-class support for Rails, and so I just connected the git repo and the Render built the container. It was that simple.

+

Then I spun up a Postgres database, which also just worked.

+

Result:

+
  • \u2705 Easy: Followed their docs on deploying a rails app
  • +
  • \u2705 Cheap: \\$14/month for server and database
  • +
  • \u2705 Database: Yep, managed Postgres instance
  • +
  • \u2705 Integrated with git: Yep, automated deploying, with logs
`; +}); diff --git a/.netlify/server/chunks/2020-08-07-where-i-go-for-ui-inspiration-fc5cd52d.js b/.netlify/server/chunks/2020-08-07-where-i-go-for-ui-inspiration-fc5cd52d.js new file mode 100644 index 0000000..f59f7e2 --- /dev/null +++ b/.netlify/server/chunks/2020-08-07-where-i-go-for-ui-inspiration-fc5cd52d.js @@ -0,0 +1,53 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_08_07_where_i_go_for_ui_inspiration, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Where I go for UI inspiration", + "author": "Thomas Wilson", + "date": "2020-08-07T12:00:00.000Z", + "draft": false, + "slug": "2020-08-07-where-i-go-for-ui-inspiration", + "tags": ["design-resources", "design", "links"] +}; +const _2020_08_07_where_i_go_for_ui_inspiration = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Like anybody who makes interfaces for apps/websites, I spent a lot of time looking at Design Inspiration (read: UIs, real or imaginary, made by other people). This is a really good way to look at visual conventions that other people made, and have used in their UIs and UX.

+

If I were to examine the time I spent \u201Cdesigning\u201D more closely, and divided it between actually pushing pixels around in Figma, and looking at other people\u2019s work on Dribbble I would be shocked and ashamed.

+

Allow me to justify this though: unless you are one of two-three social media giants, literally nobody spends the majority of screen time in your app. It would be incredibly arrogant to assume your app is good enough that people are willing to learn a whole new style of interaction, navigation, and visual metaphors for it. +In this teeny blog post, I just want to list some of the places I go when I want to find good UI to look at

+

A quick caveat though. These sites are good in the same way that a buffet is good. But they\u2019re also bad in the way that a buffet is bad. If you\u2019re not consciously selective in how you expand your UIs, it can feel like a collection of disparate widgets. Would you trust a website that could go from crunchy spring role to full-bodied bolognese, just because a designer fancied it? As a designer it is your responsibility to understand the types of data, interactions, and journeys that your app is trying to promote or facilitate. Sometimes \u201Cbecause it looks cool\u201D is enough of a reason - but this might not fly so well on a village GP surgery.

+

Anyway, this post isn\u2019t about that, it\u2019s about some sweet sweet list of cool sites for design inspiration. Well have I got a twist for you, I actually made two lists (Inception Horn).

+

Here are some sites that put words to visual design patterns:

+
  • UI Guideline : Web-focused, component-level naming.
  • +
  • ui-patterns : Mobile-focused, pattern and component-level naming.
  • +
  • lookup.design : Another great free library of examples of components used in the wild. Clean UI and tags, with a nice variety.
+

Here are almost endless numbers of mockups from people far more talented than I:

+
  • UI Sources (\u{1F4B8} paid) : A well-curated collection of app design patterns.
  • +
  • mobbin.design : Another nicely curated list of mobile app designs
  • +
  • UI Movement : Primarily mobile and animated interactions.
  • +
  • Muzli search : Find designs by searching words or colours, a cool little tool run by Adobe.
  • +
  • Dribbble : I\u2019m putting these guys on the list, but they don\u2019t need the recommendation.
+

And for Colour Palettes:

+
  • Muzli Colors : A really nice little tool that shows you a selection of colours in some standard UI mockups (pie charts, chats, cards, etc.)
  • +
  • Coolors : A classic tool I use very frequently to help me find complementary colours.
`; +}); diff --git a/.netlify/server/chunks/2020-08-14-thing-i-learned-05e37aa6.js b/.netlify/server/chunks/2020-08-14-thing-i-learned-05e37aa6.js new file mode 100644 index 0000000..2b5bf42 --- /dev/null +++ b/.netlify/server/chunks/2020-08-14-thing-i-learned-05e37aa6.js @@ -0,0 +1,38 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_08_14_thing_i_learned, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #1", + "author": "Thomas Wilson", + "date": "2020-08-14T00:00:00.000Z", + "slug": "2020-08-14-things-i-learned-1", + "draft": false, + "tags": ["things-i-learned"] +}; +const _2020_08_14_thing_i_learned = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This tidbit about a literary villa: Over three days in June of 1816 at a villa in Geneva, Mary Shelley started writing Frankenstein, or The Modern Prometheus and John William Polidori started The Vampyre (which preceded the modern romantic image of vampires). The latter inspired Lord Byron (who was also at the villa, by the way) to write A Fragment. Imagine being 2am whiskey drunk at that, wow.
  • +
  • This way to think about css/styling: The decisions we make about the naming, structure, and languages/frameworks for modern styling tools just move complexity, they don\u2019t solve it. If you use CSS, it doesn\u2019t matter too much how do you name it (BEM or utility classes?) or how do you build it (vanilla CSS, post-CSS, SASS?). Likewise, CSS-in-JS vs inline styles won\u2019t affect things. Be consistent and know where the complexity in your codebase is (source)
  • +
  • This thing about viruses during a pandemic: It makes evolutionary sense for a virus to be less virulent (to cause less disease). Those viruses which can infect more people will, by definition, be more evolutionary successful. This is one reason (alongside massive economic, medical, and societal changes) that the global death toll from HIV is lower now than it was in the pandemic of the late 1980s. (source)
  • +
  • This puur-fectly fitting French word: The*French word for the verb \u2018to purr\u2019 is ronronner* - which sounds simply excellent with a French guttural accent.
`; +}); diff --git a/.netlify/server/chunks/2020-08-21-things-i-learned-a798a2f9.js b/.netlify/server/chunks/2020-08-21-things-i-learned-a798a2f9.js new file mode 100644 index 0000000..ceb50d3 --- /dev/null +++ b/.netlify/server/chunks/2020-08-21-things-i-learned-a798a2f9.js @@ -0,0 +1,38 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_08_21_things_i_learned, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #2", + "author": "Thomas Wilson", + "date": "2020-08-21T00:00:00.000Z", + "slug": "2020-08-21-things-i-learned-2", + "draft": false, + "tags": ["things-i-learned"] +}; +const _2020_08_21_things_i_learned = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This useful thinking tool: good writing starts with observations, and moves to analysis. Making the transition is difficult. One way to spot a mental crutch is to see where you reach for words like \u201Cinterestingly\u201D, \u201Csurprisingly\u201D, or \u201Cnotably\u201D. These all hint at a significance or meaningfulness, but don\u2019t actually clarify it. (source)
  • +
  • This hot takeaway: Did you know that during the 1970s if you ordered a takeaway coffee it came in a styrofoam cup and a lid without a hole. If you wanted to drink your beverage, you had to take the lid off and then put it back on - can you imagine? Obviously impatient, the hardcore mobile coffee drinkers (think: taxi drivers) kept ripping holes in the lid to drink their Joe on the Go. Where there\u2019s demand, there\u2019s business and thus was born a whole field of design for designing the most safe and ergonomic way to drink coffee from a cup without having to actually take the lid off.
  • +
  • This Frank etymology: \u201CLingua Franca\u201D describes a common language between a group of people. It emerged in the late 1700s and translates functionally as \u201CLanguage of the Franks\u201D, with Franks being anyone broadly from Westen Europe. The original Lingua Franca was a mixture of simplified Italian, Greek, Old French, Portuguese, Occitan (a Romance language spoken around southern France and northern Italy and Spain - wiki) , Spanish, Arabic, and Turkish (source)
  • +
  • These Kinswomen: King James II had a thing for witty, plain looking mistresses. Two such mistresses were Arabella Churchill and Catherine Sedley. Arabella is described in The Ladies Dictionary (1694) as being \u201Cof no less Eminence for learning and ingenuous Parts than her Quality\u2026 she had a great facility in poetry and was a celebrated conversant among the Muses\u201D. Despite carrying four children for the man, she was later replaced by 16 year-old (yep) Catherine Sedley, who remarked of being chosen that \u201CIt cannot be my beauty, for he must see I have none\u2026 and it cannot be my wit, for he has not enough to know I have any\u201D. James, buddy - you did not deserve these women.
`; +}); diff --git a/.netlify/server/chunks/2020-08-23-why-are-you-like-this-javascript-843edfcd.js b/.netlify/server/chunks/2020-08-23-why-are-you-like-this-javascript-843edfcd.js new file mode 100644 index 0000000..bb2b70e --- /dev/null +++ b/.netlify/server/chunks/2020-08-23-why-are-you-like-this-javascript-843edfcd.js @@ -0,0 +1,106 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_08_23_why_are_you_like_this_javascript, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Why are you like this, JavaScript? Taking a look at JavaScript's single threaded nature.", + "author": "Thomas Wilson", + "date": "2020-08-23T00:00:00.000Z", + "slug": "2020-08-23-why-are-you-like-this-javascript", + "draft": false, + "tags": ["javascript", "why-are-you-like-this-js"] +}; +const _2020_08_23_why_are_you_like_this_javascript = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Sometimes you hear something so often that you don\u2019t really hear it anymore. One of those things for me is words to the effect of \u201CHow does this JavaScript code even run?\u201C. I choose to interpret this generously as \u201CHow does JavaScript itself run\u201D, and not \u201Chow does this hot garbage code you wrote run?\u201C.[^I really hope I don\u2019t write as much hot garbage JavaScript as I used to]

+

There\u2019s a lot of ways we could describe JavaScript (including some really colourful adjectives), but objectively it is an asynchronous, single-threaded, dynamic programming language. These characteristics, which are deliberate design decisions, are responsible for a lot of the quirks, gotchas, and design patterns that make being JavaScript developer tricky for anyone just getting started. Luckily it\u2019s almost never tricky for anyone else (he lied).

+

For example, have you written and run JavaScript code which:

+
  • Ran in the browser, got in an infinite loop somewhere, and prevented all interactions with the web page (including the ability to close a tab or the browser)?
  • +
  • Fetched data from another server, tried to access the data, and got an undefined or Promise related error?
  • +
  • Written server-side JS with a callback/promise chain for data processing/cleaning and had your code start, but not finish, its execution of this chain - leaving the request hanging for a response.
+

These are all common problems which I have encountered, realistically, hundreds of times by now. They\u2019re each a rough result of the design of the JS run time, i.e. how we go from JS you wrote to the commands being executed on the computer. I don\u2019t want to talk about JS run times / environments now, so don\u2019t worry about the details. Just know that the JS code you wrote is executed by the computer in a way that makes these kind of errors possible, and even likely, if you\u2019re not thinking like JS wants you to.

+

Over the past couple of weeks, I\u2019ve been trying to understand why JS wants us to think in this way. I\u2019ve been asking JS \u201Cwhy are you like this?\u201D and \u201Cdid I do something to upset you? I\u2019m sorry if I did, but please, this really shouldn\u2019t be undefined\u201C.

+

A brief aside: on JS\u2019s dynamic-ness

+

A brief side note before we get into the rabbit hole here: JavaScript will take an awful lot of mistreatment and still run. That\u2019s largely because it\u2019s a dynamic language (i.e. it isn\u2019t typed), and also partly because it\u2019ll try and do whatever it can with whatever types of data you give it. It\u2019s famous for it: (false == 0 or '30' + 10 === '3010').

+

But you better believe that you\u2019re renting this flexibility from JavaScript, because at some point it\u2019s going to undefined is not a function you and act like it did nothing wrong - largely because it didn\u2019t.

+

This is an entirely different type of problems and design decisions in the language, which I\u2019m just not going to talk about in this article.

+

JavaScript is Single Threaded

+

JavaScript is single threaded, that means that while something is on the call stack - JavaScript is unable to run anything else. Any function that gets called by anything in our JS code is going into the call stack - it\u2019s how the internals of our app (specifically the interpreter) knows where it is, and what it needs to do now and next.

+

So if something long-running is being done on the call stack, like a really long iteration function, then no other functions can be called until that iteration has finished. Say that we have a list of 1 million movies as a massive array of objects, and we want to get all their titles:

+
${`const movies = [{title: 'A Knights Tale', rating: 10}, ..]
+const titles = movies.map((movie) => movie.title)`}
+

This map function will go into the call stack, it will start executing. So it\u2019ll go to our movies array, and for each item in it, run our little anonymous function (i.e. function without a name), and then start populating the call stack with a million of these references:

+
${`// THIS IS ALL PSEUDO CODE, PLEASE GOLLY PLEASE DON'T TAKE LITERALLY
+
+// Find the specific `movie` from the `movies` array
+const movie = {
+  title:  "A Knights Tale",
+  rating: 10,
+}
+
+// Get a reference to the anonymous function
+function(movie) {
+  return movie.title
+}
+
+// Then: Add the above function to the call stack
+`}
+

This operation will block everything else from running until it\u2019s finished. This might sound sort of bad, but if we\u2019re often running JavaScript in the browser, that \u201Ceverything else\u201D can include like: rendering a web page, or allowing a user to interact with the page or browser tab.

+

At this point you\u2019d want to ask why the lingua franca of the web would allow such a thing to happen. And that\u2019s a great question. Unfortunately, this objection doesn\u2019t do anything to dethrone JS and its utility in the web. The burden falls on us as engineers to design around this single-threaded ness.

+

JavaScript is Asynchronous and Event-Based

+

So, if JavaScript is single threaded, and blocks everything else from running until it finishes a function - how does it handle asynchronous functions? For example: what happens when I fetch some data remotely (e.g. an updated list of movies) - will it stop everything else from rendering?

+

This is potentially a really bad design flaw. Especially as the modern web - which can\u2019t seem to help itself from making too many HTTP requests. Imagine if every time you wanted to read a BuzzFeed article you had to wait for bit of content, every external tracker, and every ad to load before anything appeared on the screen. It\u2019d be a nightmare and you\u2019d never find out which kind of Frappicino you are.

+

JS solves this problem, by having an internal understanding of asynchronous actions. In the previous example, where we wanted to get a million movie titles (for some reason) - our code is synchronous - there is a simple Control Flow: the code had a correct understanding that \u201Chere are a million items, I need to do this one thing to each of them, one at a time\u201D. And thus the single JS thread was occupied with those million and one tasks.

+

To give an async example similar to an example above, let\u2019s try and retrieve a list of movies across ten genres, from a single API:

+
${`// NOTE: This code is illustrative, and not perfect, pls ignore edge-cases and separation of concerns problems
+
+// Imaginary API
+const MOVIE_URL = "https://www.mymovieservice.com/api";
+
+// A list of genres
+const apiEndPoints = [
+  {
+    label: "action",
+    path: "/action-movies",
+    movies: []
+  },
+  // Imagine 9 others
+  ..
+];
+
+// Go and fetch remote data and update the array
+const updatedEndPoints = apiEndPoints.map((endPoint) => {
+  return fetch(`${MOVIE_URL}/${endPoint.path}`)
+    .then((res) => res.json())
+    .then((moviesData) => {
+      return {...endPoint, movies: moviesData.movies}
+    });
+});
+
+`}
+

An intuitive understanding of asynchronous behaviour would be for JS to see a call to fetch and understand that it needs to:

+
  1. Make an HTTP call to the specified endpoint;
  2. +
  3. Recognise that a response will come back at some point, so put this function aside, and get on with something else;
  4. +
  5. Recognise when the data from fetch returns, and then do something with it (in this case, format it with .json() then run the anonymous data handler function to add the movies
+

It\u2019s worth noting here that JS allows us to have this notion of asynchrony without asking us to manage multiple threads. This is the trade-off we are making with JS\u2019s design: we can have asynchronous behaviour relatively simply in our code, without having to manually manage memory threads.

+

This post is already too long, I think, and I don\u2019t want to get into the specifics of how this works - but understanding that JS is able to make these kinds of decisions at run time, and when they\u2019re made - is an important part of writing faster, less blocking JavaScript.

`; +}); diff --git a/.netlify/server/chunks/2020-08-28-things-i-learned-3-2e553969.js b/.netlify/server/chunks/2020-08-28-things-i-learned-3-2e553969.js new file mode 100644 index 0000000..22ee2d4 --- /dev/null +++ b/.netlify/server/chunks/2020-08-28-things-i-learned-3-2e553969.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_08_28_things_i_learned_3, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #3", + "author": "Thomas Wilson", + "date": "2020-08-28T00:00:00.000Z", + "draft": false, + "slug": "2020-08-21-things-i-learned-3", + "tags": ["things-i-learned"] +}; +const _2020_08_28_things_i_learned_3 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This medieval lingo: Have you ever wondered how to refer to the area where a good-old-fashioned joust took place? You know, jousts? Two men, two horses, two giant poles, and one film where Heath Ledger is irresponsibly handsome? Sorry, I got distracted there - did you know the area where the jousts took places is called a List, and the fence that separated the two riders is called the Tilt (source). Initially it seemed a little wild to me that people ever jousted without the tilt, seems a little bit like unnecessary risk but that seems a little like mopping up the seawater as the Titanic sinks.
  • +
  • This unusual payment: Between the 12th and 19th centuries there was a menagerie at the Tower of London. Around the 17th century, if you didn\u2019t fancy paying the three half-pence entrance fee, you could bring a cat or a dog - which was presumably used for food. source
  • +
  • This new word: Heterodox or Heterodoxy, meaning a belief which deviates from some norm or convention, but not enough to be unorthodox or unorthodoxy.
  • +
  • This Minoan jewellery: About three-four thousand years ago, the Minoans created some incredible bee jewellery. Created around 1800-1700 BE by the Minoans in what is now Crete, the Bees were symbols of nature/earth, with honey being used in holy rituals by the culture. I\u2019m amazed that humans made those so long ago, and that they survive until today to be seen.
+

Things I\u2019ve had on rotation

+
  • Something new: Broken Access by Theo Alexander (2020). The spacious, elegant classical tones of this piece make it a joy to drift off to and come back to. (Spotify, Apple Music)
  • +
  • Something old: Camp by Childish Gambino (2011). While I\u2019m glad that Childish Gambino has evolved into what he is, the mixtape, hype, and always-woke vibes of old Gambino are what you need sometimes. (Spotify, Apple Music)
+

Cool things:

+
  • screenshot.rocks - Create nice little screenshot mockups in your browser. Found this on r/webdev.
  • +
  • Arwes.dev - A futuristic sci-fi and cyberpunk GUI. I love me some retro-future aesthetic. Found this everywhere because people kept sharing it.
`; +}); diff --git a/.netlify/server/chunks/2020-08-29-apple-what-are-you-doing-a46abe23.js b/.netlify/server/chunks/2020-08-29-apple-what-are-you-doing-a46abe23.js new file mode 100644 index 0000000..b79b587 --- /dev/null +++ b/.netlify/server/chunks/2020-08-29-apple-what-are-you-doing-a46abe23.js @@ -0,0 +1,76 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_08_29_apple_what_are_you_doing, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Apple, What are you doing?", + "author": "Thomas Wilson", + "date": "2020-08-29T00:00:00.000Z", + "draft": false, + "slug": "2020-08-29-apple-what-are-you-doing", + "tags": ["apple", "news"] +}; +const _2020_08_29_apple_what_are_you_doing = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I have loved Apple solidly for eight years, since I was 20 and gifted a Mac Mini for Christmas. I wrote my Masters thesis on that thing in a ground floor bedroom of a student house overlooking suburbia at 3am on a Tuesday night. I finished my Ph.D. thesis on a MacBook Air (which certainly didn\u2019t deserve to be put through what I asked it to do) as I sat, hunched over, on a rainy November afternoon, in a tiny flat in Paris that smelled like fresh lemon and ginger.

+

MacOS is the operating system is the vehicle I drove from environmental scientist to software engineer, and so changed my life trajectory inexplicably. I love the build quality of their machines, the UI aesthetic decisions, and the entire world of Open Source software which was opened up to me by its POSIX compliance. This is helped by the fact that I moved into a Web Development: an argumentative ADHD-sort of community but one that really likes to share and discuss things openly.

+

This is the community which modelled to me \u201Cthis is how a good engineer behaves\u201D - looking around and seeing Kent C. Dodds, Sara Viera, MPJ, Chantastic, Dan Abramov, Sophie Alpert, and so many others just like\u2026 be chill patient folk who take the time to explain what they\u2019re doing and thinking and making.[^And surrounded, obviously, by so many other who are not chill or patient]

+

So to see one of the largest companies in the world (2T\\$ now) scrapping with developers and (multi-)national legal systems for using practices which look an awful lot like monopolistic and anti-competitive practices seems wrong to me, and also a lot of other people in the dev and tech spaces.

+

The Hey Drama

+

Hey.com is an e-mail service released by Indie Tech Darling Basecamp. They released Hey with admirable ethical (no tracking) and technological (no unnecessarily complex stacks) intentions to change some aspect of the e-mail domain. They priced their product at \\$99/year, which you could only buy through their website.

+

They created desktop, web, iOS, and Android apps for people to access their Hey e-mail accounts - and before the public release they had their iOS version approved on Apple\u2019s App Store. In the lead up from beta to release, Basecamp made bug fixes to their iOS and submitted it for review (as every developer must), and had their app rejected because it did not provide a way for iOS users to create an account in the App.

+

To be clear - this functionality had never been in the Hey app. It had not been present and then suddenly removed.

+

Any in-app purchases (IAPs) result in a 30% cut going to Apple (or a 15% cut in the case of a recurring annual subscription after the first year). It\u2019s not hard to understand Apple\u2019s immediate concern: Apple are missing out on a potential \\$30 each time a user downloads the Hey app and creates an account in app and signs up for a year\u2019s worth of service. Apple stated that until this IAP option was added, they won\u2019t approve any further changes to Hey\u2019s iOS app. This meant bugs would go unfixed, weeks-days before Hey was to be released to the world at large.

+

One can easily understand the outrage this caused in Basecamp, and then further afield. David Heinemeier Hansson (DHH), the CTO at Basecamp and general holder of strong opinions tweeted: +\\

+

There is no chance in bloody hell that we\u2019re going to pay Apple\u2019s ransom. I will burn this house down myself, before I let gangsters like that spin it for spoils. This is profoundly, perversely abusive and unfair.

+

In the end, Basecamp offered users the chance to create a two week \u201Ctrial\u201D account in the app - so technically users without an account could open the app for the first time and get started with sending/receiving e-mails.

+

This isn\u2019t even a satisfying conclusion or resolution - it feels more like Apple just wanted to do\u2026 something. Tim Cook\u2019s recent defence of the 30% cut included the argument that it\u2019s only included when a business \u201Cacquires a customer on an Apple\u201D (source). But now you\u2019re demanding a way for an App to turn a new user into a customer - even if that process has historically only been done outside the iOS ecosystem (e.g. Netflix)?

+

If you want to see more about the Hey scandal, Basecamp covered the issue in an episode of their own podcast, Rework.

+

The Fortnite Drama

+

In the weeks leading up to writing this article, a similar skirmish has started between Epic Games and Apple. This time it\u2019s over Epic\u2019s Fortnite, an extremely popular Battle Royale-style game (last-person-standing).

+

Fortnite was released on PC in September 2017, and later on iOS in March 2018. The app\u2019s in-game economy uses an in-game currency (V-Bucks) that lets people purchase cosmetic items, things that look fun but don\u2019t affect the core gameplay. Earlier this year, Epic updated the app to allow users to make IAPs using this in-game currency - as opposed to the system-level iOS integration.

+

In a similar argument they raised with Basecamp, Apple blocked updates to the App as these IAPs did not use Apple as the platform/payment provider, and so did not offer the 30% cut. As of 28th August 2020, Apple removed the Developer Account associated with Fortnite from the App Store. Users can no longer download the Fortnite App on iOS.

+

Similar to Basecamp, Epic\u2019s rejection of these terms has been very public. In fact, probably more spectacle-making than Hey\u2019s, with the release of a riff on Apple\u2019s famous 1984 Macintosh advert. Additionally, the opening pages of Epic\u2019s lawsuit read well enough that one could argue they were written for non-lawyers.

+

Unlike Basecamp, Epic have so far been willing to create some kind of compromise, no matter how purely technically correct that compromise is. Both Apple, and the US legal system have argued that Epic\u2019s repeated, intentional non-compliance with the rules mean that Apple are within their right to remove them from the App Store.

+

It\u2019s not just Epic Games anymore

+

The twist in the Fortnite story came when Apple threatened to remove the both the developer accounts associated with Fortnite and Unreal Engine - a free-to-start video game engine owned by Epic.

+

In case it is unclear: Unreal Engine is a technology for building games other than Fortnite. It\u2019s used by developers across the world, including games in Apple\u2019s own Apple Arcade

+

If it went away on iOS anyone building games for iOS that used Unreal Engine just\u2026 couldn\u2019t. Quoting Kevin Gammill the General Manager of Gaming Developer Experiences at Microsoft:

+

\u201DUnreal Engine\u2019s sudden loss of support for iOS and macOS would create significant costs and difficult decisions\u201D for game creators, who \u201Cwould have significant sunk costs and lost time using Unreal Engine for game creation, and would have to choose between (a) starting development all over with a new game engine, (b) abandoning the iOS and macOS platforms, or (c) ceasing development entirely\u201D\u2026 It is abundantly clear that Apple\u2019s retaliatory steps are intended to harm Epic and its licensees. (court proceedings p.9)

+

Luckily the courts swept in and prevented Apple from doing this. U.S. District Judge Yvonne Gonzalez Rogers commented:

+

Apple has chosen to act severely, and by doing so, has impacted non-parties, and a third-party developer ecosystem. In this regard, the equities do weigh against Apple

+

Creating a Developer Ecosystem

+

I am concerned that Apple\u2019s anti-competitive, monopolistic practices are harming the consumers of and third-party developers for their own platform. So I suppose, actually, my concern is this: Apple aren\u2019t distinguishing between end-users and developers - they\u2019re both just consumers of a service.

+

Or perhaps they see little problem with applying pressure to the development community to stop others from raising such vocal fights against the conditions of the App Store and IAPs.

+

This from a company which famously celebrates quality and diversity of their platform. Every years at WWDC they give out awards for the third-party Apps and games which are well designed.

+

Equally, from a business perspective they profit from the diversity and quality. The fact that indie-devs, talented teams, and huge corporations can all publish something into the App Store gives the iPhone an appeal across demographic, generations, and personality. Just want e-mail, a PDF viewer, and a spreadsheet viewer? No worries. Want to cram your phone as full of bright-and-loud games, also fine, friend. Artistic type who wants to take and edit photos or videos, check.

+

Apple are acting acting as if they\u2019re irreplaceable, and as if there are no alternatives for developers, or as if this diversity and quality across the board is inevitable and without condition. This is literally why they\u2019re on trial for anti-trust - they\u2019re abusing their market position, capitalising on a lack of viable alternatives, and influencing the ability of developers to speak out, or find alternative revenue streams.

+

In the recent antitrust hearings, Tim Cook argued the 30% cut is justified because the App Store is a trusted place for the discovery (user), distribution (developer), and payment (both) of Apps globally. A particularly pessimistic reading of this statement makes it sound as if the App Store is the only platform for doing so. That without Apple, all businesses, talented designers, and savvy engineers would be unable to reach customers - or that end users would be paralysed by choice or stifled by lack of options. The Wild West of the internet, with its ample e-commerce and payment platforms stands as a blatant contradiction of this statement.

+

How many people rely, if not entirely then at least notably, on IAP revenue for food and rent? How many people have had to increase prices for IAPs, or to encourage more IAPs just to negotiate around this 30% cut? Epic Games won\u2019t go broke because of a 30% cut of purchases made on iOS devices, but an indie-dev easily could.

+

Apple aren\u2019t willing to budge on this 30% figure. PayPal charges 2.9% + $0.3 for a transaction, so does Stripe. Gumroad charges 3.5% + $0.3. Shopify charge 2.4-2.9% + \\$0.3. Apple are justifying a 10x increase on web payment providers, and then fight back these claims of injustice from developers who try and find ways around them (ignoring that Netflix, Amazon, and other big players seemingly get around this without problem).

+

Instead, this is\u2026 The Developers\u2019 fault? In a statement made on the Fortnite case, Apple said:

+

Instead [Epic Games] repeatedly submit Fortnite updates designed to violate the guidelines of the App Store. This is not fair to all other developers on the App Store and is putting customers in the middle of their fight

+

There just seems too much irony, gaslighting, and hypocrisy in this statement. This cannot be an actual lack of self-awareness on Apple\u2019s part - someone must have raised these questions internally. Someone must have noticed.

+

As someone who builds software, it raises serious questions about the value that being on the iOS store adds, and the additional work that would need to be done to make a native app useful over, say, a web-based purchase. If I was building a new product, this would push me more towards web-only or a more read-only iOS experience. It makes me as a developer question how much Apple value my business, especially when they have global insights into the most valuable kinds of apps and could build out their own alternatives to crush my business if its part of a popular genre.

+

This is the environment that Apple are creating for consumers, developers, and businesses who want to use their platforms - and it doesn\u2019t seem right. This is bad PR, this seems damaging in the long run. It seems an awful lot like the company could maintain their standards of quality and security without a lot of these practices (he says, with literally no evidence to back it up). It worries me that one company can raise all these questions and concerns.

`; +}); diff --git a/.netlify/server/chunks/2020-09-04-things-i-learned-4-a37f698c.js b/.netlify/server/chunks/2020-09-04-things-i-learned-4-a37f698c.js new file mode 100644 index 0000000..3598060 --- /dev/null +++ b/.netlify/server/chunks/2020-09-04-things-i-learned-4-a37f698c.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_04_things_i_learned_4, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #4", + "author": "Thomas Wilson", + "date": "2020-09-04T00:00:00.000Z", + "draft": false, + "slug": "2020-09-04-things-i-learned-4", + "tags": ["things-i-learned"] +}; +const _2020_09_04_things_i_learned_4 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This world: The Word Kipple is a word invented by SciFi writer Phillip K. Dick, to mean the kind of rubbish/trash that accumulates if humans don\u2019t intervene. source
  • +
  • This part of our brain: You know when you suddenly remember that you need to reply to that e-mail, drop off that parcel, or pick up eggs before dinner? That\u2019s your prospective memory - which is kind of the opposite of your normal memory (your retrospective memory) because it \u201Cremembers\u201D things which need to happen in the future. Don\u2019t think about it too much.
  • +
  • This Chopstick Etiquette: Cultures who eat with chopsticks each have rules about where they can/not be be placed. In mainland China, you should never leave rested chopsticks pointing towards anybody else at the table. In Japan, unused chopsticks should be placed into a rest - and if no rest is provided then one can be fashioned from paper. In Korea, chopsticks must never be placed to the left of the spoon they are paired with. In Thailand, you should never leave your chopsticks stuck into food in a bowl, or to eat rice. In Vietnam, placing your chopsticks in a \u201CV\u201D shape when you\u2019re done eating is considered a bad omen. (source)
  • +
  • This one person\u2019s damage to the Scots Language: For the past 5-10 years, one guy in America (who does not speak Scots) has been contributing to the Scots language version of Wikipedia. What they\u2019ve actually just written is the English version with phonetic Scottish pronunciations. As a result, \u201Cthis person has possibly done more damage to the Scots language than anyone else in history.\u201D (article)
  • +
  • This unrecognised inventor: Early video game consoles had their games built into the circuitry of their computer-parts. In the 70s, Jerry Lawson, a self-taught African American engineer, invent ed the cartridge, i.e. a swappable bit of memory which you\u2019d insert into the machine to play a game. He built it a console called the Channel F which never had the popularity of the Atari/Sega/Nintendo consoles of the day, and his achievement wasn\u2019t ever really noticed for what it was: something that allowed for a Cambrian Explosion of video games.
+

Cool articles

+
  • \u200CMy three decades alone, basking in the company of a mountain, Susanne Sener for Psyche (link). A personal piece written by a woman who has spent over 30 years living alone in a cabin by a mountain. I\u2019ve been thinking about this importance of silence/lack of input recently.
  • +
  • Popular Writers: A Stephen King interview, Neil Gaiman on his own blog (link). King\u2019s written more books than a lot of us ever will, and I really enjoyed the following statement he makes on where/how he arrives at them:
+

I never think of stories as made things; I think of them as found things. As if you pull them out of the ground, and you just pick them up. Someone once told me that that was me low-balling my own creativity. That might or might not be the case. But still, on the story I am working on now, I do have some unresolved problem. It doesn\u2019t keep me awake at nights. I feel like when it comes down, it will be there\u2026

+

What I\u2019ve had on Rotation

+
  • Something Almost-New: The fall of Hobo Johnson by Hobo Johnson (links). This almost-poetry-almost-hip-hop-almost-punk sound is really great, it\u2019s got levity in places and untouched rawness in others. I\u2019ve really enjoyed it.
  • +
  • Something Old: Echos, Silence, Patience & Grace by Foo Fighters (links). This is such an absolute classic album from the 2000s for me (and I think a whole bunch of other people). If you\u2019re in the mood for some Excellent rock vibes, put this on and remember how good it is.
`; +}); diff --git a/.netlify/server/chunks/2020-09-06-js-promise-introduction-04a4a7c9.js b/.netlify/server/chunks/2020-09-06-js-promise-introduction-04a4a7c9.js new file mode 100644 index 0000000..4081c12 --- /dev/null +++ b/.netlify/server/chunks/2020-09-06-js-promise-introduction-04a4a7c9.js @@ -0,0 +1,167 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_06_js_promise_introduction, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Why are you like this, JavaScript? An introduction to Promises by using Fetch.", + "author": "Thomas Wilson", + "date": "2020-09-06T00:00:00.000Z", + "slug": "2020-09-06-javascript-promises-introduction", + "draft": false, + "tags": ["javascript", "why-are-you-like-this-js"] +}; +const _2020_09_06_js_promise_introduction = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Let\u2019s start with a correct, but pretty dense, definition: JavaScript Promises are a first-class abstraction for handling asynchronous actions, like:

+
  • Fetching data from a remote API.
  • +
  • Reading or writing (i.e. opening or saving) a file to the filesystem (in a server-side environment, not in a browser).
  • +
  • Retrieving a non-blurred-up version of an image based on a page-scroll event.
  • +
  • Using network or system utilities in native mobile frameworks like react-native or expo.
+

First class? That\u2019s a programming term to say that this kind of value (i.e. Promise) can be stored in a variable or passed as an argument. Other first-class citizens in JavaScript include booleans, arrays, and functions. This means that JavaScript has an internal way of representing and understanding Promises, and we don\u2019t have to do any kind of coaxing, coercion, or pollyfilling to use them since ECMAScript2015.

+

Asynchronous actions? Promises represent the eventual value returned from a function (or more broadly, an action). This means that when we ask for the value of a Promise, JavaScript can distinguish between what is the value at the time you requested, and is this the last, unchanging value of the Promise. In JavaScript Promises, we call these two states:

+
  1. pending - where we\u2019ve described and started the async operation, but it\u2019s not completed, or
  2. +
  3. settled - that async operation has completed (successfully or not) and the value we have isn\u2019t going to change again.
+

Let\u2019s take an example and show how we can use Promises. Actually, no, let\u2019s show how we can\u2019t/shouldn\u2019t use them. Imagine we own a taco truck, and we have a menu that changes every day. This means we don\u2019t want to build a fully static site, and we want to use JS to add a little dynamic behaviour. To make sure our website always shows us today\u2019s menu we:

+
  1. Run a fetch function as soon as the page loads which retrieves today\u2019s Taco Menu as an array of tacos from an API end point,
  2. +
  3. Parse that data to extract the id and the name for each taco in that array, and
  4. +
  5. Iterate through this parsed list and insert new DOM Elements onto the page using any number of JavaScript libraries or frameworks.
+

Which in some code would look like[^1] :

+

[^1]: There are some problems with this example (namely that it\u2019s actually using Promises under the hood, but please ignore those)]:

+
${`// \u26A0\uFE0F Code is purposefully error-ful, don't run
+// \u26A0\uFE0F gollyilovetacos doesn't exist (yet) - this is illustrative
+
+const menuItems = fetch("https://api.gollyilovetacos.com/v1/menu_items")
+const parsedMenuItems = menuItems.data.menu_items.map(item => ({
+  id: item.id,
+  name: item.name,
+}))`}
+

This is going to throw us an error (something like Uncaught TypeError: can't access property "menu_items", fetch(...).data is undefined). Why? No legit, it you genuinely don\u2019t know, please think about why.

+

It\u2019s because fetch returns us a Promise. The code above applies a synchronous way of thinking onto the Promise: we declare it, parse it and parse it (on those two last lines) exactly as if it was synchronous (i.e. the data would resolve immediately) - so on that last line we\u2019re looking to get the data attribute of the Promise, as if the Promise was an object representing the API response.

+

Promises are references to the eventual values, which is different to storing the value itself. We were trying to access the data.menu_items on the Promise which doesn\u2019t exist.

+

The only things that exist on a Promise are: then and catch. This is the most technical definition of a function: Promises are Objects in JavaScript which have a then function, so says the spec.

+

Before we dig more into promises, I think it\u2019s important to ask why bother? Especially when the JS community had a way of handling things like this before ECMAScript2015. Promises aren\u2019t technically anything new.

+

Can\u2019t I already do that in JavaScript?

+

So what? Can\u2019t I just use event handlers or callback functions? Yeah, you absolutely can. In fact, these are two ways that we handled async processes in the land before promises. They\u2019re both a little bit problematic, however. Events, for example, can fire before we (or rather, the control flow of our program) can assign event handlers to them. This means that can\u2019t always guarantee that an event will be handled using the event handler we define.

+

Alternatively you can use callback functions. Callbacks are kind of like events and handlers, only because you pass pass a function as an argument to a function (possible because functions are a first-class object in JavaScript btw, just like promises) - you don\u2019t run the risk of the event firing outside the scope of the event handler function. The problem with callback functions is they can easily get out of hand - as soon as you start chaining data through more than a couple of asynchronous functions, you can end up in Callback Hell: where you\u2019re calling callbacks in callbacks in callbacks.

+

Callback hell is actually a really good example of a particular kind of code smell: technically correct, but difficult for a human to parse, or interpret. We should always be thinking about how code reads to someone new, or even to ourselves if we context switch for five days or six months.

+

Using somebody else\u2019s Promise: Fetch

+

I want to round off this introductory post by using the Fetch function: which is one of the more common ways that JS devs interact with promises.

+

Fetch is (browser[^2]) JavaScript\u2019s own in-built function for making HTTP requests, and it uses promises. If you\u2019ve ever used XMLHttpRequest in browser JavaScript, it\u2019s a bit like that. If you\u2019ve not, then you\u2019ve not got anything to unlearn to alright, let\u2019s go.

+

For now, let\u2019s just get our hands on one, and not worry about what it looks like under the hood (as in, medieval fantasy hood not car hood, obviously).

+

This is one of the benefits of coding to an interface, and if you\u2019re really deep into JavaScript land and lost without a map I just want you to know how useful interfaces can be. If you\u2019re much newer to JavaScript Land or Software Continent, don\u2019t worry I\u2019m just throwing some playful shade.

+

[^2]: The fetch function is available in most browsers. If you\u2019re going to do this in the Node /server environment, you\u2019ll probably need a package like node-fetch or some other polyfill.

+

Sidenote: Emojis in code snippets

+

I like Emoji, I think they can quickly signify meaning. In the code snippets below I use the following emoji in code snippets to explain things:

+
  • \u270F\uFE0F to signify that you\u2019re about to write something, and this is what it is.
  • +
  • \u2139\uFE0F to signify that I\u2019m about to explain an output from the console.
+

Back to the show

+

If you\u2019re on a Desktop, I want you to go to Chrome[^3] and open the dev tools (\u2318 + \u2325 + I on a Mac, Control + Shift + I on Windows) and go to the Console tab. We\u2019re going to go ahead and get a random Game of Thrones quote because the kind people of the internet have not only created, but made freely available, servers which will serve us wonderful data like this for free (GitHub link).

+

[^3]: It does actually have to be Chrome, I tried on Firefox and some errors get thrown. Don\u2019t worry about them.

+

We\u2019re going to do all of this using Promises and I need to you shut your jaw, I know it\u2019s amazing but flies will get in there.

+

We\u2019ll be using an API endpoint to get a random Game of Thrones quote, it\u2019s a GET request to https://game-of-thrones-quotes.herokuapp.com/v1/random, and it\u2019ll return data that looks like:

+
${`// \u2139\uFE0F An example quote from the Game of Thrones Quote API
+{
+  "sentence": "Fighting bravely for a losing cause is admirable. Fighting for a winning cause is far more rewarding.",
+  "character": {
+    "name": "Jaime Lannister",
+    "house": {
+      "name": "House Lannister of Casterly Rock",
+      "slug": "lannister"
+    }
+  }
+}`}
+

Actually, if you\u2019re really new here, go ahead and just copy-paste that URL into Chrome\u2019s address bar. Because it\u2019s a GET request, we don\u2019t need to worry about anything fancy. You\u2019ll get back a plain-old bit of (unformatted and un-syntax-highlighted) text with the data right there in your browser window. This is just like any other HTTP request (the same as going to https://www.reddit.com), it\u2019s nothing special.

+

Calling Fetch

+

Let\u2019s crank the HackerMan dial up a notch and fetch that same data using the console in Chrome\u2019s dev tools. In the console type:

+
${`// \u270F\uFE0F Go to the Game of Thrones quotes server and get a random quote
+
+fetch("https://game-of-thrones-quotes.herokuapp.com/v1/random")
+
+// \u2139\uFE0F The console will log you something like:
+// Promse {<pending>}`}
+

Oh.

+

That\u2019s actually a little disappointing, no?

+

So what have we done here? I\u2019m being serious - read the gosh darn code and console output and think about what you did then try and explain it to yourself. I\u2019m being serious, say it aloud or write it out - actually go through with the words that you would need to say.

+

If you did it, I\u2019m proud of you. If you didn\u2019t then gee golly, friend I wish I had your confidence in my knowledge. Here\u2019s what we did:

+
  1. We instantiated the fetch function with a URL for the Game of Thrones quote API. By default, fetch knew that we wanted to make a GET HTTP request (and not a POST or PUT, etc.).
  2. +
  3. The console then logged out the implicit return value of our statement (which was to call fetch). From this log statement we can see that fetch returns us a Promise.
+

And that little <pending> sitting there? Why that just means it\u2019s not fulfilled - remember earlier where you learned about the possible states of Promises in JavaScript (fulfilled or pending. You know, like 500 words ago. That\u2019s that! An unfulfilled promise in the wild.

+

Storing the Promise in a variable

+

So how do you actually get the quote in the response, when it comes back?. Well, we didn\u2019t store the Promise we generated in the above code-sample, which means we have no way to do anything with it - like check if it\u2019s back yet.

+

Let\u2019s fix this, and take a look at the settled promise value:

+
${`// \u270F\uFE0F Go to the Game of Thrones quotes server and get a random quote, and save it to the `quote` variable
+
+const quote = fetch("https://game-of-thrones-quotes.herokuapp.com/v1/random")
+
+// \u2139\uFE0F The console will log you something like:
+// undefined
+
+// \u270F\uFE0F Wait a few seconds, then let's look at the value of `quote`
+quote
+
+// \u2139\uFE0F Will log
+// Promise {<fulfilled>: Response}`}
+

Oh cool, we made the request and it returned\u2026 now what? How do we get the data out of it.

+

You know what\u2019s really cool about Promises? When you create them, you don\u2019t have to specify what to do on their success/failure right away. You can create the promise, then handle it later. So assuming you did the above, and you\u2019ve got a variable called quote:

+
${`// \u270F\uFE0F Add the onFulfilled event handler to the promise
+
+quote
+  .then(response => response.json())
+  .then(data => {
+    console.log(data.sentence)
+  })
+
+// \u2139\uFE0F Will return something like:
+// "Fighting bravely for a losing cause is admirable. Fighting for a winning cause is far more rewarding."`}
+

You know the drill: tell me what you did here. In a list, out loud, what\u2019s happening?

+

Oh, there\u2019s not inline list this time. There\u2019s a lot going on here that we\u2019ve go to break down. Are you ready?

+

1: Call the then function

+

We take the Promise which has a Game of Thrones quote in it (somewhere) and we call the then function. This is really important: then is a function on a Promise.

+

then is a function that takes one or two functions as arguments:

+
  1. Argument #1 : The onFulfilled function - which runs when the async operation behind the promise is successfully completed.
  2. +
  3. Argument #2 : The onRejected function - which runs when (or if) there\u2019s a problem completing the async action.
+

Here, we\u2019re only giving it one argument, so we\u2019re only defining the onFulfilled part. JavaScript is cool with us leaving the onRejected argument as undefined so now everyone who didn\u2019t like that thing about Interfaces has smug little smiles on their joyous faces.

+

So we\u2019re calling the then function with one argument: an anonymous arrow function (i.e. a function that we\u2019ve not assigned to a variable somewhere else) which takes one argument: which we\u2019ve called response - which represents the HTTP Response that fetch returned to us.

+

2: The json function

+

We call the json() method, the return value from which is returned implicitly[^4]. The json function is defined on the Body of the Response object that fetch returned to us- so don\u2019t worry about where it\u2019s coming from.

+

json() essentially takes the HTTP response body that fetch got, and parses it like JSON, so that we can treat it like an Object in JavaScript.

+

One last thing: json() is an async function, so it returns another promise.

+

If you\u2019re curious about json(), here\u2019s the MDN docs

+

[^4]: Implicit returns in arrow functions in JavaScript don\u2019t have the curly ({ }) braces. For example () => 5 will return 5, whereas () => { 5 } will return undefined

+

3: Promise Chaining

+

Because that first then function (implicitly) retuned a Promise (from the json() function), we can then call the then function on that that Promise so that we can actually handle the data from the API. This is called Promise Chaining - because you are flowing the result of one async action into another async action handler.

+

All this work for a damned quote.

+

Promise chaining is an application of Functional Composition: the way we compose together individual functions into production lines, or conveyor belts, which take in raw data at one end, and produce formatted data at another.

+

So we take the result of the fulled Promise that the json() function invocation returned - which is a plain-old-javascript object. We refer to this as as data in that second then function - where we read and enjoy with humour or dread, or whatever it is that GRRM was going for.

+

This isn\u2019t the place to talk about functional composition, but if you\u2019re already familiar with JS, you can learn more about it here.

+

Doing the same thing at author-time for Promises

+

Now that we\u2019ve covered each of the individual parts of a promise, and you\u2019ve either got confused and left or scrolled to the bottom, I just want to mention that normally you\u2019ll declare your then functions in the same place you create your Promise.

+

This will give you code which looks like:

+
${`// \u270F\uFE0F Go to the Game of Thrones quotes server and get a random quote, then process the data in-situ (so don't take it anywhere else)
+
+fetch("https://github.com/shevabam/game-of-thrones-quotes-api")
+  .then(response => response.json())
+  .then(data => {
+    console.log(`${data.character.name} says:`)
+    console.log(data.sentence)
+  })`}
`; +}); diff --git a/.netlify/server/chunks/2020-09-11-things-i-learned-5-9ba86116.js b/.netlify/server/chunks/2020-09-11-things-i-learned-5-9ba86116.js new file mode 100644 index 0000000..fb2e49d --- /dev/null +++ b/.netlify/server/chunks/2020-09-11-things-i-learned-5-9ba86116.js @@ -0,0 +1,48 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_11_things_i_learned_5, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I Learned this week #5", + "author": "Thomas Wilson", + "date": "2020-09-11T00:00:00.000Z", + "draft": false, + "slug": "2020-09-11-things-i-learned-5", + "tags": ["things-i-learned"] +}; +const _2020_09_11_things_i_learned_5 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This missed opportunity to name something: Ping Pong is a weird name for a sport, right? Ping Pong is actually a trademarked name, but it\u2019s not uncommon to call a thing by a brand name: it\u2019s like Hoover vs. Vacuum Cleaner, or Kleenex vs. Tissue. The real-fun fact here is that in 1900 Slazenger, a sports company, filed a trademark for the term Whiff-Waff - and 120 years laters (somehow) Ping Pong prevailed while Whiff-Waff died out, despite the fact that it\u2019s clearly more joyful. (link to an oddly self-righteous article).
  • +
  • This stone man: The Apennine Colossus (link) is a stone sculpture in Tuscany, Italy, which is a personification (embodiment?) of the Apennine mountain region. This is why he\u2019s really big, but also I guess why he\u2019s made of stone? The use of stone to represent stone is perhaps a little on-the-nose, but the piece is gorgeous and captivating.It was created in the late 1500s by a Flemish sculptor residing in Florence, and some people argue that if it placed in the Piazza della Signora (and not in the private garden of a Medici home some seven miles from Florence) it would be considered a masterpiece.
  • +
  • This new word: Farrago means some kind of confused, haphazard, or disorganised mix - a word around which I appear to have been building a life philosophy.
  • +
  • This set of tarot cards: Don\u2019t ask how I got here, but this week I learned one can purchase a Hello Kitty themed set of tarot cards for a cool \xA3250 (etsy link)
  • +
  • This medical condition: Stendhal Condition, named after a French novelist, is characterised by dizziness, hallucinations, and heart palpitations which come on after being overwhelmed by the beauty of art. Amazingly, that means it\u2019s really common in Florence, Italy (link)
+

Cool Articles

+
  • What to talk about in 1:1s by Julia Evans on her wizard zines site. I really like the simplicity of this piece - it\u2019s just a collection of example things you might want to raise to a manager, so that 1:1s can actually be useful to you in the 6-12 month time span, and not just a box to tick, or reason to spend time away from your desk.
  • +
  • Against Waldenponding by Venkatesh Rao on their Breaking Smart newsletter. No one is quite sure on the effects of so much technology, content, and mediums (podcast, YouTube video, Netflix, Newsletter) on our brain. It\u2019s given rise to a counter-culture, which is almost a meme in some tech circles, where someone voluntarily completely disconnects and go to live in a cabin in the woods. This article argues against, and while I don\u2019t necessarily agree with all the points the author makes, I think it\u2019s an interesting counter point in a debate where I rarely see someone taking an opposing side.
+

What I\u2019ve had on Rotation

+
  • Something New: Pink Elephant, by Stand Atlantic (Pop Punk). I adore pop-punk, and I think everybody should embrace their inner teenager. This album is cathartic and comfortably pop-punk, but even better than that, it\u2019s a great album in its own right - it doesn\u2019t rely on nostalgia or tropes. Put it on play and relive the vibrancy of being 17-19 again. (links).
  • +
  • Something Old: Safe in the Steep Cliffs by Emancipator (Contemporary Instrumental). I\u2019ve spent a lot of time this week needing music without words, and I\u2019ve been rediscovering a lot of my old favourites during my time at University. The tempo and beat of this album is great to head-bop to while you\u2019re in a flow state, but perhaps a little too-high energy of more cognitively intense tasks (links)
+

Cool Things

+
  • By the Books - it\u2019s like the online experience of browsing a friend\u2019s bookshelf, but online. Created / curated by MailChimp.
  • +
  • blobs.app - soft and gooey blobs are becoming more commonplace in UI design. This little web UI will generate a simple svg (or Flutter) blob for you to use. I got this from the Smashing Magazine newsletter,
`; +}); diff --git a/.netlify/server/chunks/2020-09-11-wow-no-thank-you-a0ff4136.js b/.netlify/server/chunks/2020-09-11-wow-no-thank-you-a0ff4136.js new file mode 100644 index 0000000..c4c2603 --- /dev/null +++ b/.netlify/server/chunks/2020-09-11-wow-no-thank-you-a0ff4136.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_11_wow_no_thank_you, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "book_review": true, + "title": "wow, no thank you", + "author": "Samantha Irby", + "image": "wow-no-thank-you", + "slug": "wow-no-thank-you", + "score": 4, + "finished": "2020-09-06T00:00:00.000Z", + "date": "2020-09-01T12:00:00.000Z" +}; +const _2020_09_11_wow_no_thank_you = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Samantha Irby came onto my radar in 2019 after a reading slump from that time I was burned out by my job in a VC startup. We are never meeting in real life, her previous set of essays published in 2017, was displayed prominently in a central London bookstore it was a) bright yellow, and b) covered in a picture of a hateful cat - so I started believing in destiny and bought the book, read the book, and adored it.

+

In 2020 I went through a reading slump because of burnout caused by being freelance but also by the extremely pressing apocalyptic vibes of the time (which have totally passed). This time, Irby let me know that she was publishing another set of works on Instagram (by public posts, not DMs) and rather than thinking about how I\u2019m likely to deal with burnout in this cyclical manner until something changes, I bought the book, read the book, and felt a little bit better.

+

This is the second time Irby\u2019s books have been a tonic for worrying cases of Readers-Block - something I don\u2019t want to google because I\u2019m really hoping I just made it up[^1]. I read this book quickly because it is short, not because I am fast at reading - but I did read it quickly nevertheless, and I was sad it was over.

+

Despite the affection I feel towards this book and Irby\u2019s writing style, I have a hard time describing anything about her writing in a way that would make anybody actually want to read it. So if you think you\u2019re in the market for cathartic, nsfw, but still celebratory personal essays - then you should buy this book. If you can laugh at yourself and the way you\u2019re far less cooler than you want to be, but also low-key maybe resent yourself for it - then buy this book. It\u2019s good and it\u2019s funny and the days are long enough without having to read the contemporary literary city romance du jour just because everyone else is reading it and you don\u2019t want to.

+

[^1]: I just googled it and I\u2019m definitely not the first person to be this clever which is not surprising but it is a shame.

+

Now please, let me try and explain the punchline to somebody else\u2019s joke. Irby will let you know, in pretty much these exact words, that she either is, or has been, a dirtbag with leaky bowels who thought for much of her life that she would die alone, played out by endless CSI re-runs that dance light across her decaying body in an tiny flat in Chicago. But she\u2019s funny with it, ya know?

+

For example, in we are never meeting in real life she writes in one essay about the time she had ate a bad hamburger before an interstate drive and had to squat out diarrhoea on the side of the standstill, snow-covered highway in front of strangers and also her college friends. And then in literally the next piece she writes about her dead father. In wow, no thank you Irby flits well between insecurities in her roles as a step mum, staff writer in Hollywood (lol what), Somewhat Famous Person, friend, and newly middle-aged woman. But she also speaks about how, obviously, she shouldn\u2019t get a dog, about how dirt-poor she was growing up, and generally what an all round gross kinda human she was and continues to be.

+

I like self-derogatory humour. Some people use it as a way to fish for complements, some people genuinely think they\u2019re hot trash, but other people, like Samantha Irby, can talk bad about themselves and somehow do it without damaging meanness and with surprising tenderness and patience. Wow, no thank you is a hopeful book, and it made me feel less alone and strange. Even though nothing I just wrote (not even that bit about shitting on the side of the highway) would lead you to think that.

+

At the same time, Irby doesn\u2019t smother you with \u201Cjust be yourself \u{1F984}\u{1F308}\u{1F339}\u201D or hashtag-relatable content. I\u2019ve never got the impression that Irby is saying something just to make you feel good or just to make herself feel bad - she\u2019s just\u2026 talking. But talking in a way where she can tweak, re-word, refine, and prune the anecdote so that when you finally sit down for coffee/cocktails with her, the stories are honed. Sometimes they ramble, but so do I.

+

I enjoyed wow, no thank you - obviously. It\u2019s not scribbled with notes in the margin and I\u2019m not going to get it tattooed on by body, but it\u2019s dog-eared and battered from where I got half way through a chapter on a train or used it to grind along a kerbside (or however else it got so damaged). It\u2019s the kind of book you can easily resume and easily pause and therefore the kind of book that deserves to become a bit battered. I\u2019d recommend it, yeah.

`; +}); diff --git a/.netlify/server/chunks/2020-09-18-things-i-learned-6-43c7d35d.js b/.netlify/server/chunks/2020-09-18-things-i-learned-6-43c7d35d.js new file mode 100644 index 0000000..1c97d37 --- /dev/null +++ b/.netlify/server/chunks/2020-09-18-things-i-learned-6-43c7d35d.js @@ -0,0 +1,45 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_18_things_i_learned_6, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #6", + "author": "Thomas Wilson", + "date": "2020-09-18T00:00:00.000Z", + "draft": false, + "slug": "2020-09-18-things-i-learned-6", + "tags": ["things-i-learned"] +}; +const _2020_09_18_things_i_learned_6 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • These ways of thinking: When we hand over a new problem to our brain there\u2019s a lot of things we need to do to solve it. We need to understand the problem and the surrounding/causal concepts as well as the constraints on a solution. For example the challenge might be \u201Cwhat should I write about on my blog this week?\u201D, and a constraint might be that it a) can\u2019t be boring, and b) can\u2019t be too long. When we\u2019re doing these mental processes we have two broad types of thinking: Divergent Thinking, where we produce a lot of possible solutions and new ideas; and Convergent Thinking, which is where we hone in on a narrow \u201Cright\u201D answer. Often one will follow the other: we\u2019ll generate ideas with Divergent Thinking and filter them using Convergent Thinking. (source)
  • +
  • A word for this social media phenomenon: \u201CSadfishing\u201D is the act of exaggerating or highlighting personal struggle or problems online in order to gain attention. Interestingly, the same kind of person who is more likely to sadfish is also more likely to judge someone else\u2019s emotional/personal social media posts as less genuine (source)
  • +
  • This thing about embryonic cells: It\u2019s wild that as an embryo develops, each cell knows what it needs to become. The protein SHH, which actually genuinely short for Sonic Hedgehod (I\u2019m not joking) is a morphogen, which means it is used in the process of instructing cells in what they should become. Specifically, SHH, plays a role in the neural development of an embryo - letting cells know that they need to form the nervous system by forming the nerual tube (kinda cool, kinda gross name). Anyway, a beacon emits SHH into the surrounding area and the surrounding cells \u201Ceat it up\u201D, so the further away from the beacon the further cells know they are from the neural tube (and vice-versa). Nature\u2019s cool, yo. (amazing explanation on reddit)
  • +
  • This surprisingly relevant architecture: Nothing would stop the Italians drinking wine, not even the Black Death. During the 1600s, the Italians started building tiny windows in wine shops through which wine could be purchased and passed, without the need for face-to-face contact. They\u2019re called Buchette del vino and during the COVID-19 pandemic, certain Florentine cafes, bar, and gelaterias started re-serving food through them. (more info)
  • +
  • This thing that oak trees do: This year is apparently a mast year, which means that oak (and other fruit-bearing trees, like beech) produce loads and loads of their fruit (e.g. acorns). Evolutionarily speaking, this means that the animals who feed off these fruits are not able to eat everything the trees produce, and there\u2019s a higher chance that there will be leftover seeds for producing baby trees (saplings?) come spring. We\u2019re not sure how trees know when they should fluctuate their fruit production, but we suspect it\u2019s something to do with the weather in spring. (source)
+

What I\u2019ve had on Rotation

+
  • Something New: Boreas by The Oh Hellos (Folk). The folksy sound of this band are unlike a lot of similar bands. They\u2019re loud and delicate, joyful and mournful - they\u2019re a beautiful set of humans, and their new EP brings more of their delightful tones into my life. (links)
  • +
  • Something Old: Oh Wonder by Oh Wonder (Gentle Pop). I remember discovering Oh Wonder during my time at uni and I remember vividly listening to them in my car as I was driving around a busy but happy time of my life. This album is calm and gentle, and brings back a lot of those memories. (links)
+

Cool Articles

+
  • A supercomputer analyzed COVID-19 - and an interesting new theory has emerged by Thomas Smith on Medium\u2019s Elemental. We\u2019re all a little tired of hearing about COVID-19 but in this article, Smith breaks down a lot of the current pathological/biological theories behind COVID-19 which I don\u2019t hear a lot of discussion about. I don\u2019t think we\u2019re giving enough airtime to the global scientific community who are figuring this out as fast as is realistically possible, largely because these things are inherently uncertain and changing. The main takeaway for me was this increased view of COVID-19 as blood/circulatory disease, not primarily a respiratory one.
  • +
  • Web Brutalism, Seamfulness, and Notion by Brandon Dorn on Viget. As I\u2019ve moved further away from design as a UI-centric process (i.e. drawing rectangles and selecting the right kind of grey), I\u2019ve taken a lot more value from design as a UX or thought process. This piece covers the design/aesthetic/philosophy of brutalism, just in the context of web and software - as an approach which argues that we should embrace the underlying tools, materials, and concepts and not try to design them away. The author makes a compelling point, which is likely too extreme to be useful to many, but there\u2019s nearly always value in hearing an apposing opinion made coherently.
`; +}); diff --git a/.netlify/server/chunks/2020-09-20-how-do-we-know-were-doing-it-right-0baa332f.js b/.netlify/server/chunks/2020-09-20-how-do-we-know-were-doing-it-right-0baa332f.js new file mode 100644 index 0000000..a922026 --- /dev/null +++ b/.netlify/server/chunks/2020-09-20-how-do-we-know-were-doing-it-right-0baa332f.js @@ -0,0 +1,58 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_20_how_do_we_know_were_doing_it_right, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "how do we know we're doing it right?", + "image": "how-do-we-know-were-doing-it-right", + "slug": "how-do-we-know-were-doing-it-right", + "date": "2020-09-20T00:00:00.000Z", + "author": "Pandora Sykes", + "score": 3.5, + "book_review": true, + "draft": false, + "tags": ["non-fiction", "essays"], + "finished": "2020-09-11T00:00:00.000Z", + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Pandora-Sykes/How-Do-We-Know-Were-Doing-It-Right--The-Sunday-Times-best/24882488" + } + ] +}; +const _2020_09_20_how_do_we_know_were_doing_it_right = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Sykes\u2019 collection of essays covers a surprisingly large amount of ground for a relatively short book. She turns her attention to a lot of the inner turmoils that seem to plague millennials\u2019 inner monologues, as well as broader societal issues: fast fashion, the \u201Ctrue self\u201D, instagram husbands, and work-life balance all feature. How do we know we\u2019re doing it right? clearly comes from a lot of careful conversations, introspection, and research but at times Sykes seems to lose herself under disjointed quotations of other peoples\u2019 words. When she does start to connect others\u2019 research to her own opinion, the two feel a little disjointed, which is a shame because both raise good points worth discussing.

+

I hadn\u2019t heard of Pandora Sykes before I saw this book in a local bookshop. I\u2019m a sucker for strong feminist essayists, and also for buying books on a whim so I picked this up. It turns out this is Sykes\u2019 first collection of essays, though she\u2019s a seasoned editor, journalist, and broadcaster according to her own website.

+

I was initially worried that I\u2019d bought a well-written book aimed at a more female more middle-aged more parent audience. The first couple of chapters spoke about parenthood and domestic life, and the environmental and psychological toles of fast fashion. Both of these things are issues that we should all be aware of, regardless of our role as child guardian or garment buyer, but both aren\u2019t things I spend a lot of my time being affected by[^1]. Not to brag, but I have practically no children and I\u2019m really trying to avoid shopping in H&M (or at least feeling appropriately guilty when I do). Though it was fun to have a well-spoken and funny woman complain about the state of a hypothetical husband and baby-daddy - some parts of the book definitely felt less relevant or less targeted at me. I could clearly see what was being said, I just couldn\u2019t relate.

+

[^1]: Men can be equally as targeted by fashion marketing which preys on insecurities - fortunately the algorithms that serve us adverts never place them in front of me.

+

And then something happened. Suddenly Sykes was talking my language: in talking about social media use and its effects on us, she spoke about her own very purposefully spent time unplugged not because it was \u201Cso good\u201D or \u201Cwell balanced\u201D but because she recognised it\u2019s what she needs for her brain to function in a way that makes her happy. Not because she wants to humble-brag or shame others, but because genuinely it is the right choice for her. This is something I\u2019ve had simmering at the back of my brain for a while: that the inner monologue a lot of creatives rely on is being pushed aside for this content. It\u2019s not even limited to creatives - everyone can benefit from providing their mind more unoccupied space move in, or less noise to speak above depending on your metaphor of choice.

+

She mentions, but I don\u2019t think does justice, to the constant input from, or demands made by, technology on our attention and time. She makes some really great points about Cultural Homework - about how there\u2019s always that series or film to watch. But this almost already feels outdated against the algorithm-run media platforms of Twitter, podcasts, YouTube, and Netflix. There\u2019s always more material, there\u2019s always something \u201Cwe think you\u2019ll love\u201D or something \u201Ceverybody\u2019s talking about\u201D even if no one you know ever actually speaks about it. These recommendations will be served up to you unless you actively stop it. This is a different point to the Cultural Homework idea, but I think it\u2019s got a lot more potential to destroy the internal conversations, meandering thoughts, and quiet moments that make us\u2026 us.

+

I\u2019m a software engineer by day but creative by night, and these are issues I think about a lot, so I don\u2019t think it\u2019s fair to judge someone\u2019s work for not writing about things that I personally find very interesting. In all, Sykes does what all good essayists do: taken some nebulous thoughts and feelings and put them into coherent words.

+

It\u2019s also wonderful to hear the strong feminist currents through pretty much all the pieces. Sexism, like any other kind of prejudice, is plagued by the idea of a micro-aggression. While the right wing of the political spectrum have got a hold of this word and use is pejoratively to dismiss any discontent as an overreaction, Sykes is able to pinpoint specific examples and lay them in front of you. When she\u2019s talking about social media usage from a woman\u2019s perspective it becomes plain how female empowerment, voice, and worth still rely on external validation for their power, which often comes from their aesthetic beauty.

+

This slight shifting of the rules is not the same as the ground-up change that we need. Changing the standards of \u201Cbeauty\u201D is not the same as changing the \u201Csource of power\u201D. It\u2019s easy to be placated by a celebration of stretch marks and natural hair (looking at you, Kendrick) and Sykes reminds us that we still need to go further.

+

As a dude, I don\u2019t want to talk about why something might make me feel inexplicably icky, because often I am a witness not a participant, and often the last thing we need now is another dude speaking on behalf of women. This means that I don\u2019t have a lot of experience putting into words why something makes me feel icky - but this book gave me that. It gave me concrete examples and it gave me a well-considered viewpoint from both a participant and an observer perspective.

+

And she does all this without ever asking for, or demanding, you believe her. Perhaps if I came into this book without already agreeing with her, I wouldn\u2019t have found the arguments so convincing. But I don\u2019t think her intention is to convince or persuade so directly. I might as well score the book a 0 because it taught me nothing about the economics of wool in 1400s Morocco. Instead, the tone I got was of someone patiently and considerately explaining why they think and act the way they do, and let\u2019s stop for a second to realise that this is totally the ~magic of books~ and the wonder of reading.

+

While it\u2019s very clear that she has her own opinion on the matter, this often feels disconnected from the citations or research she puts in. She\u2019ll often throw in a bunch of quotes from books, or personal e-mail exchanges (which aren\u2019t published by the way, but I\u2019d 100% read that in a serialised newsletter, Sykes) and then in a paragraph move onto something which feels\u2026 sort of related? I got a lot of good book and author recommendations, but it felt like she had a quota for her bibliography? I\u2019d prefer to see these references linked better into the main body of text, or at least acknowledged consistently. Sometimes she\u2019ll come back to mention and author or a work, but a lot of the time it\u2019s \u201Cas [AUTHOR] says in [WORK] \u2018word word word\u2019\u201D and then we never hear about [AUTHOR] or [WORK] again in any detail.

+

With that said, I would recommend this book. I made a lot of notes in the margins - I got a lot of good further reading, and she gave me a lot of examples and words for things which I will use in the future. I look forward to anything Sykes write in the future and I\u2019ll definitely pick it up, as I think there\u2019s room for a tighter, more informed writing style. Alternatively, she can keep things just the way she is, and I can feel like my clever patient badass friend is explaining things to me and I\u2019d still read it. 3.5\u2B50

`; +}); diff --git a/.netlify/server/chunks/2020-09-21-finding-a-job-process-d482c66d.js b/.netlify/server/chunks/2020-09-21-finding-a-job-process-d482c66d.js new file mode 100644 index 0000000..1f291da --- /dev/null +++ b/.netlify/server/chunks/2020-09-21-finding-a-job-process-d482c66d.js @@ -0,0 +1,93 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_21_finding_a_job_process, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "My experience finding a new job as a software engineer in summer of 2020", + "author": "Thomas Wilson", + "date": "2020-09-20T00:00:00.000Z", + "draft": false, + "slug": "2020-09-20-interviewing-experience-2020", + "tags": ["interviewing"] +}; +const _2020_09_21_finding_a_job_process = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

In late summer of 2020 I moved from freelance software engineer to a full-time position. I want to outline this process for literally anybody who\u2019s interested because I\u2019ve found it useful when other people have done the same - like this post about interviewing at Google, this front-end, and this more generic post.

+

Web development is a joyfully open community. There\u2019s a lot of sharing, most often we share code, but we also share details about the wider context of our field. Navigating a career is hard, and that\u2019s not made easier when people don\u2019t talk about their experience of moving (up, down, sideways) within and between companies.

+

It can be hard to talk about these things with your current colleagues without sounding like you\u2019re planning on leaving. It\u2019s also just a weird industry, where applying for jobs can take a long time, require a lot of standardised hoop-jumping and box ticking, and just generally feels pretty daunting. Not to mention the global pandemic and economic down-turn that hit us in 2020.

+

Anyway, I\u2019ve managed to find a new job that I\u2019ll be starting in October 2020. I\u2019m (secretly) very excited and hopeful for it, and I want to share what it was like interviewing for a frontend / fullstack software engineering role in the summer of 2020.

+

A note on honesty:

+

I want to be as honest as possible here, and not skip over mistakes or hurtful events (like being rejected). I still have to be purposefully vague in some places. Honestly, the specifics don\u2019t really affect the trends and takeaways as a whole.

+

I\u2019m also not going to go into detail about my salary here. I would (and do) discuss salary in person with trusted peers because people and companies have (and do) get away with discriminatory (e.g. by gender) pay for people in similar positions. But this is the internet, yo - I\u2019m not going to talk about this right now.

+

If no one around you is willing or able to talk about salary, it\u2019s fairly easy to find average data for your city and job position. For example, the average salary for an engineer (which is a broad definition) in London in 2020 is about \xA350-60k:

+ +

Being open to opportunities

+

I am a software engineer with 3-5 years[^1] of front-end and full-stack experience. I have worked in academia, in large (>500 person), scaling (50-150 people), and small (~5 people) companies. I spent 2.5 years in companies, and about 8 months freelance.

+

I signalled myself as open to new opportunities for related positions around July-August of 2020. Around the middle of September I accepted a full-time position as a front-end engineer. In all, it took me ~10 weeks from first thinking \u201CI should see what\u2019s out there\u201D to signing a contract.

+

Much of my job hunting was through \u201Cpassive\u201D platforms, where recruiters and companies would come to me with information about positions. I used LinkedIn, hired.com, and talent.io[^2]. On the latter two platforms, you have the ability to set salary expectations and create a list of technology stack/work environment preferences.

+

[^1]: Depending on if you count my PhD as \u201Cprofessional\u201D experience or not. +[^2]: Each of those links are referrer links, we both get a rewarded if you find a job with that platform. If you feel weird about using a referral link it\u2019s very easy to get started on both platforms without them.

+

I also used various job boards, notable hacker new\u2019s monthly \u201CWho\u2019s Hiring\u201D (which are consolidated here) post, to look for jobs maybe once a week. There\u2019s a lot of nonsense, unclear, non-applicable job postings out there, and it\u2019s easy to spend too much time searching the noise for signal.

+

I want to be in my next position for ideally 3+ years so I was very selective about the companies I wanted to work with. I did not need a new job, and so I could be afforded this luxury.

+

In that time I had introductory phone calls with 10-15 companies, and interviewed with seven (i.e. arranged a follow-up from the introduction call). I ended up accepting an offer from one, was rejected by one, ghosted by two others, and declined three at the point where they asked me to complete some kind of code challenge.

+

The interview process

+

The interview process for all companies who I spoke with (more than the seven mentioned here) looked surprisingly similar:

+
  1. A pre-interview interview. Have a 30-45 minute one-to-one chat with a recruiter or product-person. The point of this chat is for both parties to get a sense for each other. I am good enough at faking extroversion to actually enjoy these, to chat with interesting people about interesting problems. If you\u2019re roughly qualified in the technologies, and find yourself actually engaging with the problems the startup are facing, then you\u2019ll normally be screened through these calls an invited to the next stage.
  2. +
  3. A technical chat. If you make it through the introduction call, a few days later you\u2019ll probably have a more focused conversation with somebody, or somebodies, more technical. These chats are about drilling down on the kind of work you\u2019ve done recently, and examples of your character. Be prepared to have a few case studies for specific projects you\u2019ve worked on, things which have made you proud, and things which you have done wrong. Smaller companies tend to have more free-form interviews but larger/scaling companies will have a more formalised process with more set criteria. Try to stick to your time, don\u2019t ramble (but don\u2019t be too short), be honest, and be kind to yourself, your colleagues, and the industry as a whole. If the company think you\u2019re as qualified as you say you are, and you\u2019re a good \u2728cultural fit\u2728 then you\u2019ll make it through this stage.
  4. +
  5. A code-based test. At some point they\u2019re going to want to see you write code, and you\u2019re going to want to show off how able to write code you are. The format of these varied, and I\u2019m really happy to see a move away from take-home tests as the only thing they ask you to do. Methods I either experienced, or would have experienced, include:
    • Walking someone through a codebase I had written, or was familiar with.
    • +
    • Taking a look at the company\u2019s codebase, and running a think-aloud style interview where I explain what I\u2019m seeing and what I think about both syntax and architecture.
    • +
    • A time-boxed take-home problem, i.e. being given a specific coding challenge but with an explicit deadline or limit on time (in the order of days, not hours). The company would tell you ahead of time if you needed to set anything up in particular (e.g. libraries, virtual environments, software).
    • +
    • The classic homework take-home problem, i.e. being given a problem and asked to submit a solution when it\u2019s ready.
  6. +
  7. An on-site interview. If you can write the code, and the company like how you write code - then you\u2019ll probably be invited to an on-site interview. All companies I spoke to (which weren\u2019t 100% remote) had an on-site part of their interview, and all made concessions given the COVID-19 pandemic (only meeting a certain number of people, social distancing measures, etc.)
+

The companies

+

In all, over the summer (6-8 week period) I interviewed with seven companies. I\u2019ve grouped them by outcome, the order other than that is completely random.

+

###\xA0Sustainable Laundry company

+

\u{1F38A} Accepted an Offer

+

What do they do? They wash clothes, I guess, with the USP of being zero carbon.

+

What happened: one-on-one intro chat with head of tech, two-on-one chat with CEO and head of tech, then an on-site with the wider team. Offer made the following day and accepted two days after that.

+

Hospitality/Services adjacent company

+

\u{1F64F} Declined before code-test

+

What do they do? They work with companies in the hospitality and services industry to increase efficiency.

+

What happened? After a productive chat with someone product-focused I had another productive chat with someone in the tech team. I was offered a take-home code test which I declined because I accepted the other job. I was offered contract work at a later date, and would have accepted it if I had the time, they were genuinely a good bunch of people.

+

Civil Infrastructure company

+

\u{1F64F} Declined before code-test

+

What do they do? The company use novel software to reduce losses and increase efficiency on civic infrastructure (think roads, water, sewage, power lines).

+

What happened? A successful introduction call with a product person, then a one-on-one with a C-level person. I declined the take-home coding test as I accepted the above offer, additionally their tech stack was far outside my current area of expertise.

+

Productivity software company

+

\u{1F64F} Declined after first interview

+

What do they do? A very early stage (almost-finished internal MVP worked on by small team) team building a real-time, collaboration-focused, web productivity tool for teams.

+

What happened? I declined a code-based assessment because I did not believe in the company\u2019s mission, especially in a crowded marketplace - they couldn\u2019t verbalise a strong, coherent USP or value proposition in a busy marketplace.

+

Logistics company

+

\u{1F645} Rejected

+

What do they do? A growth-stage startup with a vibrant and varied tech team who handle global-level logistic chains.

+

What happened? I was rejected after a personal fit interview with a number of employees. I received specific and targeted feedback.

+

HR company

+

\u{1F47B} (Almost) Ghosted

+

What do they do? They\u2019re working in the talent acquisition space to help recruiters find talent and streamline the process from applicant and recruiter side.

+

What happened? After ~4 weeks I got an e-mail back saying the position had been filled, but was offered short-term contract work with the team.

+

Data Privacy Company

+

\u{1F47B} Ghosted

+

What do they do? An international data-privacy company who were looking for frontend engineers to improve the UI of their products.

+

What happened? I saw the job advertised online and reached out to the contact e-mail address given (who was the CEO). The CEO asked for a CV and a cover letter which I sent in and never received an acknowledgement or reply.

`; +}); diff --git a/.netlify/server/chunks/2020-09-25-things-i-learned-7-3c1e1a8f.js b/.netlify/server/chunks/2020-09-25-things-i-learned-7-3c1e1a8f.js new file mode 100644 index 0000000..8259071 --- /dev/null +++ b/.netlify/server/chunks/2020-09-25-things-i-learned-7-3c1e1a8f.js @@ -0,0 +1,45 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_25_things_i_learned_7, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #7", + "author": "Thomas Wilson", + "date": "2020-09-25T00:00:00.000Z", + "draft": false, + "slug": "2020-09-25-things-i-learned-7", + "tags": ["things-i-learned"] +}; +const _2020_09_25_things_i_learned_7 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This unknown origin: No one is quite certain where the term \u201Crule of thumb\u201D came from. It has been mistakenly attributed to a British Judge\u2019s rule that a man can beat his wife if the stick so long as it is less wide than his thumb, however there\u2019s no evidence to support that this ruling was ever made. (source)
  • +
  • This heist: The police recently seized about \xA32.5m worth of books which were originally stolen in 2017. How were they taken? The thieves cut holes into the roof of the warehouse near Heathrow Airport and (I don\u2019t see how this can\u2019t be true) hummed the Mission Impossible theme tune as they lowered themselves down on carbon fibre grappling hooks past motion sensors (that bit\u2019s actually true) all the way to original copies of books by Newton, Copernicus, and Galileo. The books were stolen by a Romanian crime gang, and found buried under a house in rural Romania. (source)
  • +
  • This thing about conspiracy theorists: There\u2019s possibly an evolutionary reason behind conspiracy theories: people/groups of people who are more likely to believe others are maliciously conspiring against them are less likely to underestimate the power or potential of others. This may increase the survival rate of those who are more suspicious of others. This means that our disposition to believe in conspiracy theories may to some extent be favourable and innate. (source)
  • +
  • This thing about reading: On average, people onlyy read about 20% of the content on any given web page. This study was done in 2008, and I couldn\u2019t easily find a more up-to-date revision. That means most people would only read one of these five wonderful things I learned this week. (source)
  • +
  • This Roman god: Domitius is the Roman god who kept a woman in the house of her husband. His wife, Domiduca, protects children on the way back to their parents\u2019 house. Thanks for your service Domitius, but I think we can take it from here - you\u2019ve had a good couple of thousand years, yeah? Domiduca, go take a spa weekend or something - go somewhere outside the house and without children. (source)
+

What I\u2019ve had on rotation

+
  • Something New: Fragments, by Bear\u2019s Den and Paul Frith (Acoustic Folk Pop). This is such a gentle album, containing fully instrumental/acoustic remakes of their own songs, from across a number of their own albums. It\u2019s a great early autumn playlist to sit inside with, to read to, and to take the pressure out of an evening with. (links)
  • +
  • Something Old Blink 182 by Blink 182 (Pop Punk). I rediscovered this album on a bike ride I took earlier this week, in possibly the last of our summer sun. It was one of the first CDs I ever got, and the words to pretty much every song have been burned into somewhere deep in my brain. The pop-punk energy, distinct vocals, and general teenage melancholy make this a great album all round, if we\u2019re being honest. (links)
+

Cool Articles

+
  • Mark in the Middle by Casey Newton for The Verge. This is a great bit of reporting on both Facebook and Mark Zuckerberg\u2019s approach to leadership and management. Zuck is a man who appears increasingly out of touch with human and social sentiments that make up a lot of the human experience. The article also highlights some wider tensions around Facebook which I had never previously considered, for example that Facebook employees are largely left-leaning but its customer base is increasingly right-wing; and how Facebook sells its mission to its employees as a democratising force for opportunity and connection for all. Ultimately, however, management within the company seems to continue to ignore the damaging consequences of providing a platform, and even amplifying voices, of hate speech and conspiracy theorists. The recordings in this article are also tightly integrated, and I love the design of the piece as a whole.
  • +
  • After 15 Years as a Product Leader, CEO and Now VC, Here\u2019s the Advice I Always Share with Future Founders on the First Round blog. This is a nice reminder of the importance of always staying product and experience focused, accepting nothing less than what you envisioned. Even as products and teams grow (or bloat), these shouldn\u2019t slip (but pretty much always will). There\u2019s definitely some gems in there, but not every company can afford Google levels of financial, time, and mental resources. I don\u2019t think anyone can just stop everything and only ship excellence (as much as we all want to say we can and do).
`; +}); diff --git a/.netlify/server/chunks/2020-09-26-queenie-d51f811c.js b/.netlify/server/chunks/2020-09-26-queenie-d51f811c.js new file mode 100644 index 0000000..fb2f25a --- /dev/null +++ b/.netlify/server/chunks/2020-09-26-queenie-d51f811c.js @@ -0,0 +1,60 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_26_queenie, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Queenie", + "image": "queenie", + "slug": "queenie", + "author": "Candice Carty-Williams", + "score": 4, + "book_review": true, + "date": "2020-09-26T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "London", "contemporary", "race"], + "finished": "2020-09-20T00:00:00.000Z", + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Candice-Carty-Williams/Queenie--British-Book-Awards-Book-of-the-Year/24546409" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookstore.org", + "link": "https://bookshop.org/books/queenie-9781508277996/9781501196027" + } + ] +}; +const _2020_09_26_queenie = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Queenie is an excellent debut by Carty-William. The novel\u2019s titular narrator pins you to the page - she has a strong and unique voice, yet also unreliable and unlikable at times. It takes you through something which feels both personal and also cultural: micro-aggressions, personal and collective trauma, mental health, and love and friendship in the early 21st century. It\u2019s a really gripping and motivating work that Carty-Williams manages to end on a hopeful, if a little well-trodden, note.

+

Queenie is first-person narrative of a mid-twenties Jamaican-British woman living in London as she comes out of a big breakup. I can easily see the narrative resonating best with a younger audience, with sprinklings of e-mails and WhatsApp Group Chats scattered throughout the narrative, it feels like how I talk with my friends: frequently and with short messages. She\u2019s funny, but it rarely feels jarring or gimmicky or unrealistic. Sometimes the humour\u2019s intentional, sometimes its situational

+

As well as the titular Queenie, the book has a (mostly younger) cast of friends, colleagues, family members, and a whole bunch of awful men. I\u2019m serious, there are a lot of terrible men in this book, one of them calls his penis \u201CThe Destroyer\u201D, one of them licks Queenie\u2019s shoulder and says it \u201Ctastes like chocolate\u201D, even towards the end of the book they stop getting human names, and just get nicknames (Balding Alpha) which I think is a really nice subtle mechanic. Terrible men aside, Queenie\u2019s sassy young best friends (The Corgis) are 100% here for it, and her Jamaican family are trying their best. Sometimes the friends feel a little relegated to \u201Cbest friends of the protagonist\u201D, but that fits nicely with the sometimes selfish first-person perspective that dominates at least the first half of the book. Either way, it\u2019s nice to see non-romantic love given a lot of screen time and responsibility in forming a life in response to a trauma. Even if our narrator doesn\u2019t acknowledge it or see it all the time, the book\u2019s got a lovely sense of community.

+

As someone not from an immigrant family, who hasn\u2019t spent significant time in the homes of any first or second generation immigrant families - the and cultural presence and attitudes within a Jamaican household unit was introduced well and treated kindly. There is no othering of any party, nor does anyone explain more than is strictly necessary - you get a good sense at how some people live their day-to-day lives, and that\u2019s lovely.

+

I can however, speak more for life as a young person in London. Queenie is so clearly written by someone who lives, walks, and sees London. The painting of strangers, her relationships with her friends and co-workers, the bemoaned but helpless state of gentrification. As someone who also loves this city, it felt right at home. Similarly, as someone in their late twenties who doesn\u2019t doesn\u2019t feel as though they have their life together, as if some friendships are competitive and some life goals are unfulfilled - this book makes me feel seen and a little less worried. It doesn\u2019t belittle or undermine the time and personal effort it can take to rebuild a life after something comes through and sweeps all the pieces away. We all know these things, but it\u2019s never a bad thing to be reminded of.

+

It\u2019s not always particularly easy or comfortable reading, but Carty-Williams has created a deeply personal narrative without serving them up through a parade of unlikely or unrealistic scenarios. Issues of personal and cultural trauma, and self-destructive self-esteem issues are put in front of you but they often go unexamined or un-critiqued by the narrator, both because they are not noteworthy to her but also because she does not have the ability to recognise or confront them herself. This book draws empathy out of you like an angry tired toddler going to sleep - you might not want it to happen, but your brain\u2019s going to do it anyway.

+

I think this is made even more effective by the first-person narrative. The book feels personal, but more cohesive than a stream-of-consciousness might give. You get patterns and trains of thought which are mostly, but not always, refined or perfect. The first person perspective was pulled off very nicely by Carty-Williams. She combines this with elements of an unreliable narrator, with facts or events being omitted and only referenced later, sometimes by other characters. It\u2019s just enough to make you question Queenie, despite being inside her head. Similarly, the passing of time feels uneven and variable. This is an inveitable during a trauma or dramatic event - time can slip or crawl by, seemingly with little control over it. This is something we\u2019ve all been experiencing in the COVID pandemic, so maybe I\u2019m just a little sensitive to it right now.

+

With that said, the pacing wasn\u2019t perfect. Somewhere in the second third it certainly slumped, and some events or plot points felt a little awkwardly placed. It\u2019s like Carty-Williams had something she wanted to show a part of Queenie, or contemporary racism in London, but which didn\u2019t fit naturally within the flow of the plot. It\u2019s hard to find space between your protagonists\u2019 redemptive narrative and an ongoing societal observation/criticism, and that certainly shows at times.

+

On the whole though, Queenie handles societal criticisms with admirable maturity. With the recent massive (re-)rise in the Black Lives Matter movement throughout 2020, Carty-Williams manages to take an approach which does not feel clich\xE9 and which engages you in the conversation. It does not feel tired, fuelled entirely by emotion, or reliant on impersonal facts or figures. Carty-Williams has certainly benefited from the current awareness, but she does not depend on it. There doesn\u2019t seem to be any singular agenda being pushed ahead of the narrative and it remains foremost a work of fiction driven by characters and empathy. For someone who\u2019s interested in the lived experience of these cultural issues, Queenie provides them to you without always highlighting them. You get a real \u201Coh cool this again\u201D when people make what are quite clearly racist remarks, even though \u201CI don\u2019t see colours\u201D and \u201CI\u2019m not racist but\u2026\u201D

+

I think a lot of people, young or old, would benefit from reading Queenie: it\u2019s a well written, narrative-driven book which communicates in a thousand subtle ways how it feels to be mid-late twenties in London in 2020. I can\u2019t speak to how it conveys the lived Black experience, but it is explained clearly and introduced without pandering. Even if you just want an interesting read to understand mental health a little better, this book will do that. I really liked this book and I\u2019m very excited to see where Carty-Williams applies her noteworthy aptitude for character next. 4 \u2B50

`; +}); diff --git a/.netlify/server/chunks/2020-09-28-software-as-craft-24d74267.js b/.netlify/server/chunks/2020-09-28-software-as-craft-24d74267.js new file mode 100644 index 0000000..9f134a1 --- /dev/null +++ b/.netlify/server/chunks/2020-09-28-software-as-craft-24d74267.js @@ -0,0 +1,51 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_09_28_software_as_craft, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Software Engineering as a Craft", + "author": "Thomas Wilson", + "date": "2020-09-28T00:00:00.000Z", + "draft": false, + "slug": "2020-09-28-software-engineering-as-a-craft", + "tags": ["essay", "engineering"] +}; +const _2020_09_28_software_as_craft = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

A few months ago a prominent figure in the tech and software space was uninvited from a conference[^1]. In an (intentionally humorous) summary of this person, Melissa McEwan wrote a Tech Bullshit Explained about the person. I don\u2019t want to talk about any of allegations or (tellingly-immature) reactions to the allegations, but something McEwan said in her post didn\u2019t seem to fit, and to me seemed a little too far. She says:

+

[^1]: I don\u2019t want to name them in this post because this isn\u2019t about them, or really the situation. Please oh goodness please don\u2019t let anything I say here be seen as any critique or defence of anyone or their action.

+

They had to make Software Craftsmanship because Agile became too much about project management and not about code. This made software devs sad because they hate it when things aren\u2019t about them. [Person of Interest] and others thought too much code sucked. And people weren\u2019t paying enough attention to writing code that didn\u2019t suck. They decided the solution was to LARP as medieval craftspeople. And pretend they were making beautiful woodcarvings instead of pop up windows on websites.

+

Look, I\u2019m all for making fun of nerds, especially when they put on ill-fitting armour and probably very itchy wool and run at each other in a field, we\u2019ve all seen Role Models. Just as people make fun of the nerds who have nothing better to do on a Tuesday evening than write things no one will ever read because it feels mildly more productive than watching the third episode of Ru Paul\u2019s since dinner.

+

I don\u2019t take issue with calling it craftspersonship or artisanal. We can just go ahead and remove all the needless gendering from our language, it adds nothing and does damage as a whole. I also take some umbrage with the fact that damn near everything is artisanal: ice-cream, every Etsy store, and now apparently anyone who writes code.

+

I see the humour in the choice of naming: a bunch of engineers get tired of no one else understanding how hard it is to do their job and how clever and skilled they are. So they look around and the only analogy they can find is obviously something right out of a D&D game or fantasy trope: the student/master, artisan/apprentise model.

+

And finally, yep, we\u2019ve all met at least one Grumpy Engineer (TM) or Egotistic Engineer (TM). I think in part it\u2019s because the salaries are comparatively high (because they provide high value), another part because of the underlying nature of the job, and a further part selection bias for the kind of people who want to become software engineers. It is a good idea to account for this inflated sense of self-importance when making software: give an engineer 1-12 weeks and at some point they\u2019re going to demand this awful code needs a re-write because they wouldn\u2019t make something this messy. Part of managing and working alongside/within engineering teams is compressing this need for perfection, or the illusion of perfection, in favour of \u201Cyes but also we need to satisfy our customers because they pay you\u201D.

+

I do, however, take issue with the idea that we can use these easily mockable and related things to dismiss or diminish the sentiment behind what lead to the need for Software as a Craft (SaaC?). There\u2019s a clear underlying point to me, and one that doesn\u2019t even start with these old white men - in 1998 Freeman Dyson drew comparison between the historic practice of craft and the modern (at the time) software development.

+

In his essay Science as a Craft Industry, Dyson puts Craft against Mass Production as two ends of a spectrum. Both approaches have their pros and cons. Mass production has enabled pretty much everything, from water bottles to cars, to become massively affordable and therefore pushed societal advancement as a whole. But mass Production is all about producing one thing: that single factory only pumps out motorcycles or water bottles. It\u2019s not going to start producing jigsaws by mistake if you stop watching it for thirty minutes, but nor could you easily turn it into a jigsaw factory very easily.

+

The original Arts and Crafts movement emerged around the turn of the 20th century in response to increased mechanisation and mass production. William Morris was an even first-er \u201COld White Men\u201D that McEwan could point at. Morris argued strongly that artists and designers see themselves, and their work, as craftspeople would: working by hand to create the highest quality individual work. The Arts and Crafts movement criticised mass production or mechanisation, at times calling for all work to be done by hand and at other saying that so long as machines could produce work (designed by craftspeople, obviously) of good quality, then it was okay to use them.

+

In a much more moderate, less social reformist, argument Dyson argues for software as a craft from the perspective that humans are a tool-making species. We will continue to use the materials available to us (physical and conceptual) to craft tools and solutions which help us do things. Mass production may help spread those tools, but we\u2019re always going to be tinkering and building - and that is the craft. He argues that software development is just as much a craft as the development of better, more precise, more capable scientific equipment:

+

Because of the enormous variety of specialized applications, there will always be room for individuals to write software based on their unique knowledge. There will always be niche markets to keep small software companies alive. The craft of writing software will not become obsolete. And the craft of using software creatively is flourishing even more than the craft of writing it (Science as a Craft Industry Freeman Dyson, 1998)

+

When the production of software is a craft we appreciate, and even require, high levels of proficiency in a the problem domain and the technical tools available. This is what lets someone create, or purposefully work towards creating, software which is better, stronger, more efficient, cheaper, faster, easier to use, more stable, etc. - whatever the problem space demands.

+

When we see software only as a craft, as something which is entirely small scale in scope and also in team size, we risk producing only small-scale work. Perhaps worse, we risk having pockets of high quality work, undertaken by people who both love the craft, and have the mental aptitude to truly improve the craft. I would argue that software engineers have a duty to share experiences, best practices, evaluations, and tradeoffs. Part of being a craft, then, is the teaching/learning aspect of student and teachers. Though, given the already vast breadth and depth of modern software, all engineers should be coming into the craft with a student\u2019s mindset. I digress, though.

+

Both approaches, software as a craft vs. mass produced software, are necessary. It\u2019s a shame that we made the decision to point to the people who made furniture and cutlery 500 years ago and be like \u201Cdo it like they did it\u201D, because they\u2019re seemingly very different. However, the fundamental designs of a chair and a fork haven\u2019t much changed in the last 500 years, nor have we yet converged on a single utilitarian design for either. Take a metal worker or a carpenter from today and 500 years ago and watch them work, and it probably looks very similar. Now people might learn more from YouTube than they did in the 1500s - and people may not serve a seven year apprenticeship - I\u2019d imagine the two could sit down over a pint and make good conversation.

+

Ian Martin makes an interesting point related to this: the decreasingly tangible product of code, i.e. that all we have are files on a hard-drive, may make it easy to forget that writing software produces a thing. If you produce a wonky chair or an overly long fork, it\u2019s easy to see the quality of work was not great. By calling for a perception of software as a craft, we fight against that ability to forget or not notice the final quality of the product. You could watch two software engineers with different levels of experience, or in different domains, and it wouldn\u2019t necessarily be so easy to guess which is which, at least from a distance.

+

So maybe there is something to be said for the value of software as a craft, for sometimes focusing on the practice of making better, or at least different, software just for the sake of it. It\u2019s a shame that some developers get arrogant, zealous, and grumpy enough to give this idea a bad name. No matter how you justify it - as career advancement for yourself, value added to your business, or experience to your users - we should all be seeking to write better code and that doesn\u2019t happen by accident - that happens with the careful application and slow refinement of the craft. If you need to wear a leather gauntlet and call yourself Hilda The Blacksmith\u2019s Daughter to do that, then sure, buddy, I\u2019m with ya.

`; +}); diff --git a/.netlify/server/chunks/2020-10-02-things-i-learned-8-b54e3403.js b/.netlify/server/chunks/2020-10-02-things-i-learned-8-b54e3403.js new file mode 100644 index 0000000..b5db7e9 --- /dev/null +++ b/.netlify/server/chunks/2020-10-02-things-i-learned-8-b54e3403.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_02_things_i_learned_8, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #8", + "author": "Thomas Wilson", + "date": "2020-10-02T00:00:00.000Z", + "draft": false, + "slug": "2020-10-02-things-i-learned-8", + "tags": ["things-i-learned"] +}; +const _2020_10_02_things_i_learned_8 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

This week\u2019s Things I learned is a little shorter than usual because I\u2019ve been moving house. I hate every part of moving house. Anyway, enough excuses, here are some of the things I learned this week:

+
  • This thing about reading: I\u2019ve been thinking about how much we read recently. I think we\u2019d all like to read more, and you hear so often of speed readers who can devour books in hours. The thing about reading is that you\u2019re limited by a) how fast your eyes can move, and b) how much you actually take in when you read. Most Higher Education level readers can read and comprehend no more than about 400 words per minute, but you can typically expect to fall within the 200-400 words per minute range. (source)
  • +
  • This incredible woman: Pearl White was an American actress born in 1889 who worked as an adult on stage, screen, and also the circus when she was a kid. She started in America, moved to Paris, and by 1924 (aged 35) she had been divorced twice, saved \\$2m, invested in clubs, casinos, and race horses (name three more badass investments) and bought a house in Egypt. She died aged only 49 following years of heavy drinking. (source)
  • +
  • This Elizabethan law case: In 1623 a woman called Susan Baskervile, lived in London and was was married (not all at once) to various theatre- or actor-types (we\u2019ve all got our flaws, Susan). Susan sued the Queen Anne\u2019s Men - a theatre group, because the actors were not able to pay her stipulated pension, which Baskervile was given in the will of her deceased husbands. Not only did she win this lawsuit, but the documentation which was produced provided some of the best evidence in the pay, duties, grievances, and general operations of a theatre company in Elizabethan London. This period was known as the English Renaissance, and because of these documents we know a lot more about the behind-the-scenes aspects of the era. (source)
+

Cool Articles

+
  • The Parable of the Empty Boat a Zen parable explained by Sintagma. The core of this parable is that if you were sailing a boat out on a lake and you were crashed into by another boat you would be furious at whoever was in control of that boat. If that boat was empty, floating aimlessly about the lake, then you\u2019d be more willing to accept the random bad accident. It\u2019s a nice reminder that bad things can happen and that your reaction to them won\u2019t always be constant, so you can control it.
  • +
  • The End of Tourism? by Christopher de Bellaigue for The Guardian. Travelling, especially for western millennials, has become more about box-ticking than deeper investment, understanding, or a sense of seeing another culture. I\u2019ve thought this for a while, and it\u2019s why I normally holiday in the same couple of places. De Bellaigue puts forward some interesting ideas here bout how the current global pandemic can be a force to promote sustainable and responsible tourism, which tour operators, governments, and tourists may not previously have been encouraged to do.
+

What I\u2019ve had on rotation

+
  • Something New: 20/20 by Knuckle Puck (Pop Punk). I love when a new, fresh Pop Punk album drops, and that\u2019s exactly what this is: upbeat but low-key sad, pop punk. I\u2019ve been really enjoying this album. (links)
  • +
  • Something Old III by Bersarin Quartet (Contemporary Instrumental). I\u2019ve choreographed/danced to works by this band before - they\u2019ve got a wonderful ability to create space and ambience around surprisingly little sound. Their sound is delicate and careful, but intense at times. (links)
`; +}); diff --git a/.netlify/server/chunks/2020-10-03-cats-cradle-317a4017.js b/.netlify/server/chunks/2020-10-03-cats-cradle-317a4017.js new file mode 100644 index 0000000..b2ef8e7 --- /dev/null +++ b/.netlify/server/chunks/2020-10-03-cats-cradle-317a4017.js @@ -0,0 +1,61 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_03_cats_cradle, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Cat's Cradle", + "image": "cats-cradle", + "slug": "cats-cradle", + "author": "Kurt Vonnegut", + "score": 2.5, + "book_review": true, + "date": "2020-10-03T00:00:00.000Z", + "finished": "2020-09-20T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "modern-classic", "American"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Kurt-Vonnegut/Cats-Cradle/1528376" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/cat-s-cradle-9780385333481/9780385333481" + } + ] +}; +const _2020_10_03_cats_cradle = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

After Slaughterhouse 5, Cat\u2019s Cradle is the second Vonnegut book I\u2019ve read. I\u2019ve heard wonderful things about Vonnegut, and this book exemplifies a lot of those, namely uncomfortable observations and a black, dry humour. The book circles a number of themes, principally the dangers of purely objective or impersonal scientific research, and the role of religion to society and people. It hits these notes well throughout the piece, but I found the meandering, seemingly powerless, plot arch a little unstable at times - like there wasn\u2019t anything for me to reliably hold on to. Our narrator is very much at the whims of those around him, and feels more like a vehicle to show different things to the reader rather than a person.

+

This lack of depth to our narrator could be purposeful - he is, after all, essentially writing a memoir which covers his (ultimately unsuccessful) attempt to write a biography of the Dr. Felix Hoenikker. Hoenikker is a scientist working on the creation of nuclear weapons, who is the classic absent-minded genius. Though fictional, Hoenikker is a semi-transparent copy of (the real) Irving Langmuir: the Nobel laureate who actually did once leave a tip for his wife after she prepared him breakfast at home.

+

Hoenikker is dead, so we have to piece Hoenikker together from the testimonies of his children and people who knew him. We are presented a portrait of someone doing very dangerous work around nuclear weapons, but who cannot form or understand the most basic of relationships with even his immediate family. The placement of someone who is not aware of, let alone able to discuss, the moral implications of their possibly apocalyptic work is an undercurrent through the work. To be fair - it is an interesting note, it\u2019s easy to praise science for its own complexity, and forget the messiness of actually using it.

+

From this setup, we get some moments which show moral indifference and ignorance as almost indistinguishable. Hoenikker\u2019s work is purely hypothetical to him and his kind, but globally important to the rest of the world. I have never had to struggle with in any of these questions in the real or immediate context (which I\u2019m grateful for). It is fairly clear that the book was conceived in a place where the Arms Race and scientific research dominated the author\u2019s attention. Vonnegut clearly had to wrestle with these thoughts in a very applied setting. Historically and contextually, it is clear that this is a very important and well-timed book.

+

The world and events which form around our narrator is often full of moments of black humour, of the absurd, of hypocrisy where all you could do is laugh. Which is, from what I hear, the realm of Vonnegut.

+

Cats Cradle also throws us into the existential ocean with Bokonism - a fictional religion created by Vonnegut. The essence of Bokonism lies with foma - which are harmless untruths, and the related belief in some kind of predestination. Bokonism explores the genesis, adoption, and persecution of a religion - it\u2019s a very concise, sometimes oversimplified (though often for humour) examination of religion.

+

Again, here Vonnegut finds the most bleak or despairing parts of humanity and you\u2019re forced to laugh at it, because the alternative to feel a bone-deep worry or despair.

+

Unfortunately, these ideas weren\u2019t enough to carry me through the book. They could have been if I had found the narrator a bit more fleshed out, a bit less willing to just accept everything. He feels like an observer, like his role is just to document what\u2019s happening. He\u2019s a journalist/author writing a book, so it wouldn\u2019t be odd to pair these observations with some kind of cross-reference, anecdotes, fact-checks, or journalistic flair. He didn\u2019t subtract from the story, but he definitely didn\u2019t add anything to the book.

+

While this fits with the helplessness/comfort of predestination from Bokonism, and it is indeed fun to piece together the life/thoughts of a person through what other people share about them - the narrative itself just didn\u2019t engage me. Maybe I\u2019ve been ruined by expecting too much to happen in a plot, but I don\u2019t think that\u2019s true.

+

I felt I could have stopped reading at any point and not wonder about what was going to happen next. Especially towards the end of the book things just get more and more absurd, but it\u2019s left to us, the readers, to notice this absurdity. Which is a nice touch, but at the same time there doesn\u2019t seem to be a ceiling or climax to how weird things can get. There\u2019s no tension or threat, it just keeps getting weirder. This is only really in the last 10-20% of the book - it\u2019s a real gear change.

+

Admittedly, it has been a while since I have read a \u201Cmodern classic\u201D, and so I wonder if I would have enjoyed this book a little more if I was better prepared, more critical, or more aware of the historical/personal context. I read it in 2020, a year when literature served more of an escapist purpose than academic exercise. Nevertheless, the book had enough interesting ideas and darkly funny moments, and was frankly short enough, that none of these became deal breakers. I\u2019m glad I have read it, I just didn\u2019t particularly savour the reading. 2.5\u2B50

`; +}); diff --git a/.netlify/server/chunks/2020-10-09-things-i-learned-9-0fa38174.js b/.netlify/server/chunks/2020-10-09-things-i-learned-9-0fa38174.js new file mode 100644 index 0000000..2af1c67 --- /dev/null +++ b/.netlify/server/chunks/2020-10-09-things-i-learned-9-0fa38174.js @@ -0,0 +1,47 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_09_things_i_learned_9, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #9 (Nobel Prize edition)", + "author": "Thomas Wilson", + "date": "2020-10-09T00:00:00.000Z", + "draft": false, + "slug": "2020-10-09-things-i-learned-9", + "tags": ["things-i-learned"] +}; +const _2020_10_09_things_i_learned_9 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

In honour of the announcement of (some of) the 2020 Nobel Prizes, this week\u2019s edition contains entirely things I learned when reading about the people and work announced so far. Note that this doesn\u2019t include anything about the Peace or Economics prizes, which had not been announced at the time of writing.

+

I also started a new job this week so I\u2019m running at 5-10% mental capacity so we\u2019re in for another short edition this week!

+
  • This line of poetry: from Louise Gl\xFCck\u2019s Lullaby \u201CThe Soul\u2019s like all matter: / why would it stay intact, stay faithful to its one form / when it could be free?\u201C. Gl\xFCck is an American poet who has been publishing poetry since the 1960s. She has also taught at various American colleges. Her work carries various first-person narratives, often looking at intimate human relationships.
  • +
  • This weird name: Before we discovered Hepatitis C, we had only discovered Hepatitis A and Hepatitis B. The thing about Hepatitis C, is that it\u2019s chronic and it doesn\u2019t present many immediate symptoms (but it\u2019ll still kill ya) and we just hadn\u2019t isolated the virus yet. Around the 1960s, doctors started noticing something Hepatitis-y in patients who had received blood transfusions, or therapies derived from blood. So for a while, actually about a decade, we called this new virus Non-A, Non-B Hepatitis (NANBH) when really maybe we should have just called it Hepatitis C from the beginning. This year\u2019s Nobel Prize in Physiology or Medicine was awarded jointly to Harvey J. Alter, Charles M. Rice, and Michael Houghton for their work in discovering Hepatitis.
  • +
  • This use-case for genetic modification: The Nobel Prize in Chemistry was awarded to Emmanuelle Charpentier and Jennifer A. Doudna for their work on Crispr-Cas9, a tool for gene editing. The Revive & Restore project (link) is trying to use this technology to create a mammoth-like animal, using the Asian Elephant as a baseline. If this is successful, I put good money on someone farming these animals for food and selling Wooly Mammoth Burgers from a food van. Bonus points to that van being Flintstones themed.
  • +
  • This family: The Nobel Prize in Physics was awarded to Roger Penrose, Reinhard Genzel, and Andrea Ghez for their work on Black Holes. As a child Dr. Penrose, now a maths professor at Oxford, would go for walks with his family. During these walks, his brother and father would play chess entirely in their heads, and Dr. Penrose would run back and forth between them, relaying one\u2019s next move to the other.
+

What I\u2019ve had on Rotation

+
  • Something New DEMOTAPE/VEGA by BERWYN (Hip Hop/Genre-Queer). This is a personal album, BERWYN puts a lot of himself and his situation into it. It flits between genres but still makes a consistent rap-ish sound and story. This is a good album from a relatively new artist who\u2019s obviously got things to say and the ability to say them. (links)
  • +
  • Something Old Wild Rivers by Wild Rivers (Folk). With the shift of seasons from summer to autumn, it\u2019s a great time to be pensive. I\u2019ve always found folk music to fit this mood well, and this album has gentle vibes by the bucket. (links)
+

Cool Articles

+
  • Meet the Bears of Fat Bear Week on expore.org. Did you know about Fat Bear Week? You should, it\u2019s great. You can read all about your new best bear friends, or you can just look at the pictures of chubby bears.
  • +
  • The Widening Responsibility for Front-End Developers by Chris Coyier for CSS Tricks. Every year or so, Coyier, puts out a really great essay on the state of modern web development, without bending to trends, companies, frameworks, or click-baity titles. If you work in web, this piece is definitely worth reading.
  • +
  • Why Life Can\u2019t be Simpler on the Farnam Street blog. This article is filled with tiny nuggets worth making a note of, especially if you\u2019re in the business of making anything. One of my favourite such nuggets is is that \u201Ccomplexity is like energy. It cannot be created or destroyed, only moved somewhere else. When a product or service becomes simpler for users, engineers and designers have to work harder.\u201D
`; +}); diff --git a/.netlify/server/chunks/2020-10-10-five-questions-for-a-first-week-5fec9954.js b/.netlify/server/chunks/2020-10-10-five-questions-for-a-first-week-5fec9954.js new file mode 100644 index 0000000..af12b95 --- /dev/null +++ b/.netlify/server/chunks/2020-10-10-five-questions-for-a-first-week-5fec9954.js @@ -0,0 +1,62 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_10_five_questions_for_a_first_week, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Five (and a bit) useful questions to answer in your first week at a new job", + "author": "Thomas Wilson", + "date": "2020-10-10T00:00:00.000Z", + "draft": false, + "slug": "2020-10-10-five-useful-questions-new-job", + "tag": ["new-job"] +}; +const _2020_10_10_five_questions_for_a_first_week = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I\u2019ve just had my first week at a new job (I\u2019m now a frontend software engineer at Oxwash), which is cool. I find first weeks intense because I have to balance a) the immediacy of being introduced to everything and everyone in \u201Creal life\u201D, i.e. not an interview setting, for the first time, and b) trying to convey your long-term personal and professional ambitions to your new bosses without sounding like a career lunatic or emotionless psychopath.

+

Managing long and short term goals is hard for humans to do, but worthwhile and rewarding when you get it right. Long term goals are rarely immediately relevant or present, it\u2019s not always easy to go from \u201CI would maybe like to be an engineering manager\u201D to an actionable thing. It\u2019s even harder to consider long term goals in chaotic situations, like when you\u2019re being introduced to new people, places, processes, technologies, terminology, and expectations. Plus the added complexity of trying to present yourself as someone who can totally stay afloat and cognisant during all the above.

+

But if I don\u2019t have a long-term idea of who I want to be, even if it\u2019s subject to change, I worry that I\u2019ll be nudged into doing entirely what\u2019s best for the immediate concerns of others or the company. I would rather that my personal and professional development come from a dialog between what others need me to do, and what I think I want to be doing.

+

For that reason, I came into the first week at a new job with a couple of personal and career-focused questions to help me understand myself and others. These questions ended up being really helpful to me, even if the answer to the questions is was a (polite) \u201Ccan we come back to this later?\u201C.

+

These are the questions I arrived at when I thought about all these things. They could be riffed on to help find something useful to you, or taken verbatim. I don\u2019t think their usefulness is limited to the first week at a new job, nor do I think they necessarily need to be asked to anyone other than yourself. The act of answering your own questions is a good little meditation (and it\u2019s at least 50% of the reason I try to write so much).

+

So yeah, here are the five questions I came up with:

+

Imagine 12 months has passed - what could I do that would bring the quality of my work from \u2018Good\u2019 to \u2018Excellent\u2019?

+

There are a couple of dangerous implications with this question, especially in a first week: it implies that you are capable of doing excellent work. You may well be, but it definitely sounds like you could be over promising.

+

Despite that, I found this a useful question because it shows you how people understand, see, and value the kind of work you\u2019ll be doing. As an engineer, you\u2019ll get a different response to this question from people in management, product, operations, strategy, and tech. This is great - it shows you how the current tech team and offering are seen by the company at large, and how each person/team would define success.

+

Another little life hack for you is that people rarely have a well defined, concise response to this question. You\u2019re probably not going to get told \u201Ca 7.5% decline in response times over the next 12 months\u201D (obviously great if you do). Take a note of these points, of what people want, and use them when you\u2019re talking about, planning, and polishing tech internally.

+

What does the company look like in 12 months, five years, and ten years?

+

By default, your onboarding will give you a good idea about what you\u2019ll be doing immediately, maybe in the next 1-3 months. I found asking this question a great way to prepare me mentally for what I might be doing in the future.

+

Asking this question to anybody senior in product or strategy (even in C-Suite, if you can) will help you understand what you\u2019ll be working on if you stay at the company for a longer (in startup years) amount of time.

+

As before, this knowledge can help when planning and building software or roadmaps. Things will always change, and your software will always be somehow inflexible or caught off guard, but hopefully this question will help you minimise that.

+

This question is most valuable in early stage companies, because of the difference between present and planned situation is probably quite large. I have intentionally joined an early stage company, and while they\u2019re definitely no longer struggling for product-market fit (if that\u2019s even a thing anymore?), the chance that they have already streamlined and perfected everything by now is pretty close to 0%. This is great - you can use your knowledge you\u2019re gaining in answering these questions to help get them closer to that goal.

+

The caveat to this is that the uncertainty and unpredictability could mean that the longer-term projections or ideas are just words. Customers, economies, investors, management, talent, and global pandemics are all winds that will guide your ship. Don\u2019t get tied to these ideas, and keep a pulse on it - things can change fast and you\u2019ll have to learn when to stick to what you\u2019ve learned and when you need to learn new lessons.

+

When, and how, is my performance going to be evaluated?

+

This is probably the most boring of the questions, because it is self-serving. However it is important to know how you\u2019re going to be assessed, because you want little to no concern about losing your job, failing your probation, or what not. At the end of the day, any good company is going to be equally critical and supportive in examining your work, and feed back to you. This is naturally uncomfortable enough, and so the least you can do is make sure it\u2019s not happening against \u2753mystery criteria\u2753.

+

The answer to this question won\u2019t be relevant until you start digging in to actual work. I would still recommend making a note of it. It might encourage you to keep a better log of work you\u2019ve done, problems you\u2019ve faced, ways you\u2019ve improved, or whatever. It might let you know about the company\u2019s culture around sharing, feedback, and openness.

+

If I\u2019m struggling or have problems, where do I go?

+

This is the kind of thing you want to know before you need to know it. It might be your direct manager 95% of the time, but it\u2019s always good to have an idea about where to go if you were to have a problem with your manager.

+

Get a sense for which people are best for which problems: management questions, tricky technical work, variable mental health, and ongoing family problems will at some point affect your work. Understanding who needs to be told what, and what kind of support can be offered (internally or externally) is a good thing to suss out.

+

What are your immediate team\u2019s backgrounds and interests?

+

Get to know your team, as much as this is painfully obvious, it\u2019s surprisingly easy to forget in the chaos of starting a new position. Allow these conversations to happen naturally during your first couple of days working alongside your new team. Don\u2019t come in with forced or canned one-liners with your team, this is your first week not a corporate retreat.

+

I found it useful to get a broad idea about who my team is and what they find interesting. This goes for personal as well as professional interests. We\u2019re all complex, complete humans and you\u2019ll find something to bond about, even if it\u2019s just the weather, crowding on the underground, or the best kind of milk to have in coffee.

+

Knowing what people do/not know, or where they are/not confident could help you phrase future feedback or explanations in a slightly different way. I\u2019m not always great at asking for explanations of basic terms when someone explains something at a million miles an hour, and I know some people feel similarly. Likewise, when you need feedback or clarity on something, it\u2019s good to know where to go in order to get it.

+

Bonus Question: Does anybody have any dietary requirements or allergies?

+

If you\u2019re a cook or a baker you might want to bring in some sweet treats now, or in the future. It\u2019s always a good idea to know if anyone\u2019s going to be excluded, or mortally threatened, if you bring in a particular kind of baked good.

`; +}); diff --git a/.netlify/server/chunks/2020-10-16-things-i-learned-10-3f4d1b6f.js b/.netlify/server/chunks/2020-10-16-things-i-learned-10-3f4d1b6f.js new file mode 100644 index 0000000..a8a01e8 --- /dev/null +++ b/.netlify/server/chunks/2020-10-16-things-i-learned-10-3f4d1b6f.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_16_things_i_learned_10, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #10", + "author": "Thomas Wilson", + "date": "2020-10-16T00:00:00.000Z", + "draft": false, + "slug": "2020-10-16-things-i-learned-10", + "tags": ["things-i-learned"] +}; +const _2020_10_16_things_i_learned_10 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This Tiny City: St. David\u2019s is a city with a population of about 1,000 people. In 1886 it was stripped of its status as a city, being described as \u201Clonely, and the neighbouring district wild and unimproved\u201D. In 1994 Queen Elizabeth II requested it be restored as a city, and now it is. (source)
  • +
  • This Terrible Surgeon: In the 1800s Robert Liston, a London-based surgeon, was famous for performing amputations quickly. This wasn\u2019t just a neat party trick, at a time when surgical complications would kill a lot of people, being quick often meant less pain for the patient and less chance for something to go wrong. Liston once conducted a leg amputation in 28 seconds, during which he accidentally took off the thumb of his assistant and frightened a spectator to death (I\u2019m not joking, he accidentally hit their coat with his knife as he was waiving it about, and the spectator literally died). The patient as his assistant later both died from infections to their wounds. Liston\u2019s surgery clocked up a 300% mortality rate.
  • +
  • This Monastic Meal Plan: St. Benedict remains an influential figure in modern Christianity. He wrote a book (a really big book) on how to be a monk and how to run a monastery (which were, at the time, full of monks). St. Benedict thought that monks should have two meals a day, but sometimes one, eaten in complete silence except for one monk reading aloud from the bible. He had a surprisingly well-balanced nutritional plan: fresh fruit and vegetables, two separate dishes, about pound of bread, half a pint of wine (a hemina to be precise), and a except for the sick or very weak, \u201Clet all abstain entirely from eating the flesh of four-footed animals\u201D. (source)
  • +
  • This Play Houdini Was In: Houdini\u2019s business model was pretty weird when you think about it: do things that sound and look impossible, like escape from a sealed container of water in handcuffs, and make sure nobody figures out how you do it. Make it so cool and outrageous and impossible that people pay to see it. A very Victorian sensibility. In 1911, Houdini performed his famous Chinese water torture cell trick - in which he escaped from a sealed container of water (chained down, of course). He wanted to patent it, so that others couldn\u2019t copy it, but by filing a traditional patent he\u2019d have to reveal how the trick was done as part of the documentation. So instead, he performed the trick once, as a one-act play, to an audience of one. This allowed him to patent the trick as a performance, not as a device, and so did not need to provide any details about how it was done. Incidentally, no one figured out how he did this trick during his lifetime.
  • +
  • This Reasonless Nudity: No one knows why ancient Greek athletes used to perform naked. It was so inherent to the culture that the Greek adjective gymnos (on which \u2018gymnasium\u2019 is based) means \u2018Lightly clothed or naked\u2019 - yet there wasn\u2019t a clear reason for doing it. They started doing it about 50 years after the first Olympics and just\u2026 liked it, I guess? One story goes that a runner tripped over his loincloth and died, another story is that one sprinter (called Osippus) won a race nude, because he realised it would help him run faster.
+

What I\u2019ve had on Rotation

+
  • Something New: The Quiet City by David Wenngren & Library Tapes (Contemporary Instrumental). This is such a beautifully atmospheric album, it\u2019s perfect to put on as the evenings get colder and the rain starts coming in. The entire album flows into itself beautifully, and the orchestration is superb. (links)
  • +
  • Something Old: The Come Up by J Cole (Hip Hop). I really love some classic J Cole, this album has such a classic boom bap production sound and style, and the raw energy of an early J Cole. His new stuff is great, he\u2019s got a lot to say, but his old stuff is great to remember too. (links)
+

Cool Articles

+
  • How Duolingo designed the new character for its project world by Kim Lyons for The Verge. If you\u2019ve used duolingo, even if just for a bit, over the years you\u2019ll know Duo, the green owl mascot. Recently, Duo\u2019sgrown quite the little friendship circle. This article covers how the company behind the owl developed his new friends. There\u2019s a nice mix of psychology, education, and design in this article. It\u2019s a good read.
`; +}); diff --git a/.netlify/server/chunks/2020-10-18-hamet-528d07f6.js b/.netlify/server/chunks/2020-10-18-hamet-528d07f6.js new file mode 100644 index 0000000..c9c94f3 --- /dev/null +++ b/.netlify/server/chunks/2020-10-18-hamet-528d07f6.js @@ -0,0 +1,60 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_18_hamet, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Hamnet", + "image": "hamnet", + "slug": "hamnet", + "author": "Maggie O'Farrell", + "score": 4.5, + "book_review": true, + "date": "2020-10-18T00:00:00.000Z", + "finished": "2020-09-30T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "contemporary", "literary", "historical-fiction"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Maggie-OFarrell/Hamnet/24130702" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/hamnet-9780525657606/9780525657606" + } + ] +}; +const _2020_10_18_hamet = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Hamnet follows Agnes, the wife of William Shakespeare, and her family - her brothers, children, in-laws - as well as several of the greater village populous. The book makes very few references to William, and never actually names him. He is always \u201Che\u201D, \u201Chusband\u201D, \u201Cfather\u201D, \u201Chim\u201D. Describing Agnes as \u201Cthe wife\u201D, as I did mere sentences ago, serves only as an introduction, and as a drastic under-selling of Agnes.

+

Set in a 1500s southern England, the book darts between the characters\u2019 present - following the life and early death of Hamnet, Agnes\u2019 only son - and the years preceding these events: Agnes\u2019 childhood, meeting her husband, raising a family. The heart of the plot is sparked by an historical fact: Shakespeare did have a son called Hamnet, who died aged 11 in 1596 from the \u201CPestilence\u201D (the Black Death). Shakespeare never mentioned this death directly in his writing, and it\u2019s still unclear what impact this death had on the writer.

+

O\u2019Farrell never addresses this issue head-on, but rather through negative space and leaving feelings or events unaddressed or unexplained. This device is turned effectively against William, a man we know very little about - something which is true both in this book and in the broader historical perspective. His absence, rather than his presence, is what dominates this book.

+

Hamnet is an exploration of the death of a child, and how it could have such little evident impact on the work of someone from whom we have so much writing, and who we associate with such breadth and depth of human expression. Where did the grief and sadness go? Grief is certainly present in this book, though O\u2019Farrell spends more time, and perhaps more effort, on the theme of our identity set against our family and work. She covers love in various forms, secrecy, obsession, and obscurity in engaging ways - because we are all many people, circumstances dependent. Agnes struggles to reconcile a free and wild upbringing with the confinements and expectations of house-bound married life to a man who is rarely present, in any sense of the word.

+

Much of Hamnet\u2019s story pins on character, with major plot events or twists being thin on the ground. O\u2019Farrell shows us the small but rich inner lives of a village in the 1500s. We follow several characters throughout the book, and although Agnes is certainly given the most attention, O\u2019Farrell has a way of fleshing out characters in short phrases and segments which, although sometimes spread many pages apart, feel cohesive.

+

Just like you can\u2019t pull plot from character in this novel, I don\u2019t think you could pull character from language. To be frank, O\u2019Farrell\u2019s use of language in this book is masterful. It is precise and pointed, it is emotive but it does not linger or repeat.

+

There is a section near the middle where she describes how the Black Death arrived to England from Italy - it is a complete departure from the day-to-day lives in an English village, but she captures your attention and explains everything in human terms. This book paints portraits of people with familiar language, and allows the world to build around that - even if you don\u2019t realise you\u2019re building it.

+

I also want to praise the light mystic / magical elements which O\u2019Farrell scatters around Agnes. She is a woman who knows things. These are never fully addressed or explained, which is fitting: Agnes never questions or second guesses them herself. They are a part of her, and although Agnes knows other people don\u2019t have them, she never exploits or divulges too much to anybody. This adds an extra sense of life to the already very-much-alive world which O\u2019Farrell has created as a backdrop to a vibrant piece of work.

+

In Hamnet, O\u2019Farrell has written a study of the human psyche when it cannot define or express itself. She has written in such transportive language, with light mystic elements, but the plot is almost irrelevant at times. There\u2019s a seeming lull in pace at certain points, and perhaps, at times, O\u2019Farrell leaves a little too much unexplained or open to interpretation. Sometimes these are invitations to imagine the characters more deeply, but sometimes I felt conflicted or unsatisfied.

+

Despite this, I would recommend reading Hamnet - ideally in the Autumn/Winter season, under fairy lights, perhaps with a coffee or tea while the rain thrums gently outside. It is a literary work of art, allow it to transport you somewhere else. 4.5 \u2B50

`; +}); diff --git a/.netlify/server/chunks/2020-10-21-designing-mental-frameworks-41042d8b.js b/.netlify/server/chunks/2020-10-21-designing-mental-frameworks-41042d8b.js new file mode 100644 index 0000000..a2a087f --- /dev/null +++ b/.netlify/server/chunks/2020-10-21-designing-mental-frameworks-41042d8b.js @@ -0,0 +1,77 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_21_designing_mental_frameworks, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Think in Frameworks, build with Libraries - Thinking about CSS in Web Development", + "author": "Thomas Wilson", + "date": "2020-10-21T00:00:00.000Z", + "draft": false, + "slug": "2020-10-20-mental-frameworks-in-design-engineering", + "tags": ["design", "css"] +}; +const _2020_10_21_designing_mental_frameworks = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I\u2019m a few weeks into starting a new job as a frontend software engineer, and I\u2019ve been moving around our (Angular) codebases to make a few smaller changes, and bump a number of our core dependencies through a couple of major (e.g. 1.0.0 -> 2.0.0) versions.

+

This caused a few visual changes, and in fixing, or at least understanding, what\u2019s happened I was rooting around a lot of the component-scoped style files (which are SASS files). I noticed that a lot of the selectors, including nested selectors, are using elements to create queries, for example:

+
${`// random-component.scss
+main {
+  h1 {
+    font-size: 1.5em;
+  }
+
+  img {
+    width: 100%;
+  }
+
+  p {
+    font-size: 1.15em;
+    line-height: 120%;
+    padding: 12px;
+
+    span {
+      background-color: #f1f1f1;
+      font-size: 1.1rem;
+    }
+  }
+}`}
+

This is completely valid SCSS - it had done its job of styling random-component. There\u2019s a million ways to style a modern web app, plus there\u2019s just a set amount of complexity in a design\u2026 good CSS won\u2019t make it go away, it\u2019ll just help you manage it.

+

But I didn\u2019t like it. My gut feeling is that it feels very clinical - there\u2019s no notion of what exactly is in random-component. It\u2019s easy for a computer to read, but not for a human. Sure, it\u2019s easy to know that h1 is probably the page title, but what about that <span> nested in the <p> - is that an inline name of a product, a code sample, contact information? I wouldn\u2019t be comfortable changing this SCSS quickly - because I don\u2019t know how limited in scope that p > span styling is - is used only for contact information, or for contact information and inline code?

+

More technically speaking, is my concern that it ties our design specification and our DOM structure very tightly: we need a main > p > span in order to apply those styles. This might sound perfectly intentional, but what happens when you want to apply exactly the same styles in a main > block quote > span ? Do you copy-paste the code?. What happens if I add a wrapping div, caption, or another span before the actual for-real span that we want to give a background colour of #f1f1f1? Suddenly our implementation, i.e. our HTML/DOM structure, has changed, which has caused the need for our stylesheet to change.

+

At the root of these problems is a lack of abstraction between design, i.e. visual metaphors and language we\u2019re trying to show our users, and the implementation, i.e. the HTML code we\u2019re rendering into a web browser. When you\u2019re a small team, or when everyone has good functional knowledge of all the technologies involved, this is perhaps favourable - the code communicates to your audience. But what happens when someone more specialised in design, HTML accessibility, or responsive layouts comes in and starts changing things? The strict coupling of design and implementation could either a) slow down effective change, or b) cause unintended visual changes or regression.

+

This raises alarm bells in my little engineer brain: a change in HTML structure should not cause a breaking visual change. The structure of the DOM is largely for computers: to include the right information in the right format (an image, a header, a table) - and then let the browser render that out, allow accessibility tools to correctly understand it, and even allow other software to parse it to extract data.

+

Design, however, is entirely and selfishly for humans. We style on the web to make them clear and understandable to the human being who is viewing that document. There are, of course, a million other reasons why you\u2019d style something: increase legibility, brand consistency, pure aesthetics, and so on. And when you look at some of the most widely used CSS philosophies, e.g. Atomic Design, Block Element Modifier (BEM), or Object Oriented CSS\u2026 they\u2019re about creating opinionated names.

+

When I design, I am designing entirely for humans. I am creating visual metaphors, rhythm, conventions, and predictability which is linked to the content of the website, the structure of the page, the intended audience. The same applies to when I am writing CSS: I am trying to write verbally consistent, and mentally clear CSS. But I have never designed or written CSS for HTML elements.

+

When I design, I am asking questions like:

+
  • What kind of data are we showing the user here?
  • +
  • Do we show this data anywhere else in the application?
  • +
  • How can the user interact with this screen, and how would I like them to interact with the screen
  • +
  • Where can the user go from this screen?
+

Things I am not thinking about include:

+
  • How can I trim the user\u2019s name so there\u2019s minimal whitespace in this a tag?
  • +
  • Will this p tag by flex-grow: 1 ?
  • +
  • Does this div tag need to inherit display: none from its parent?
+

I think of design more as a framework than a library. In technical terms, a library is smaller, focused, single-purpose bit of code or tech that does one thing. There is typically one way to do one thing. A framework, however, comes with more opinions and scope: it\u2019s possible to have a \u201Cright\u201D and a \u201Cwrong\u201D way of doing things (sometimes called the \u201Cblessed path\u201D).

+

There are definitely more framework-esque approaches to design. Tailwind CSS and other atomic- or utility-first CSS libraries are increasingly popular. And also incredibly useful or clear for a lot of people. However here we see the CSS classes bundled together into a single component to encapsulate the complexity - you\u2019re making a framework based on Components, not CSS class names.

+

I see a lot of my role as a designer as taking various bits of tech and an understanding of a business context, and using both to create frameworks, and their associated mental models. I think that in-house design benefits when it comes with its own mental models. They\u2019re bigger, they\u2019re tied to a specific business/product - so they\u2019re not really sharable or useful to anybody else. But that\u2019s okay - because they\u2019re very useful to the people who need them.

+

So that\u2019s what I\u2019ve been thinking about this week: how some SCSS files made me realise that my role as an engineer and designer is to create mental models and frameworks, sometimes using tiny libraries.

`; +}); diff --git a/.netlify/server/chunks/2020-10-23-things-i-learned-11-04dedbc2.js b/.netlify/server/chunks/2020-10-23-things-i-learned-11-04dedbc2.js new file mode 100644 index 0000000..9ad8195 --- /dev/null +++ b/.netlify/server/chunks/2020-10-23-things-i-learned-11-04dedbc2.js @@ -0,0 +1,42 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_23_things_i_learned_11, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #11", + "author": "Thomas Wilson", + "date": "2020-10-23T00:00:00.000Z", + "draft": false, + "slug": "2020-10-23-things-i-learned-11", + "tags": ["things-i-learned"] +}; +const _2020_10_23_things_i_learned_11 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This thing about how we sleep: In Western Europe, about 35% of young adults sleep with a soft toy every night, and about 44% of people keep hold of their childhood soft toy. It can be especially helpful for people with low self-esteem, or higher anxiety to sleep with a soft toy, apparently. As someone who\u2019s kept firm tabs on their childhood bear (though I\u2019d say we sleep adjacent, not together), it shocks me that over half of people would throw their teddybear away. (source).
  • +
  • This older-than-expected coffee machine: The Nespresso capsule, those little pods of coffee grounds that you put in the coffee machines to get a single serving of espresso-based coffee, was initially invented 40 years ago by a rocket scientist. Eric Favre came up with the idea in the 1970s while in Rome, when he saw how one cafe in particular (Caffe Sant\u2019Eustachio, if you\u2019re curious) was more popular than all the others around it. He noticed that the baristas would aerate the coffee, and extract it for longer under higher pressures - to give it a stronger flavour, and more crema. In 1986 Nestle released the first version of the Nespresso machine and capsules to the public, but it took a while to take off, because the public didn\u2019t want it - they were happy with their instant coffee (can you imagine being happy with instant coffee?). It took 30 years, but the brand is now worth over \\$4 billion.
  • +
  • This children\u2019s book author: In the late 20th Century, a 13 year-old Walter Crane was apprenticed to a master woodcarver-cum-political-activist (us millennials think we own the \u201Cslash\u201D in occupations and side hustles). Crane got involved in the Arts and Crafts movement, which held that art has the power to educate and inform tastes, and also that \u201Cart\u201D doesn\u2019t just mean paintings - rather it means anything crafted. Arts and Crafts\u2019 most recognisable output is probably William Morris\u2019 floral patterns. Crane took a special interest in Toy Books - i.e. those made for young children learning to read. In 1899, in his 20s, Crane illustrated Steps to Reading, which was written by Nellie Dale. Dale was a teacher who pioneered a new (at the time) method of teaching children to read: pairing of words with pictures to convey the same meaning. When you write \u201CJack plays cricket\u201D - you pair it with a nice illustration of a young boy (probably called Jack) playing cricket. At the time, most other books took a phonetic approach: showing each letter and having children say the letters out loud. Crane\u2019s illustrations, and understanding of the required manufacturing process (wood engraving apprenticeship, remember?), produced delightful and detailed illustrations for Dane\u2019s book, which caused them to remain popular long after more refined teaching methods were discovered. I would highly recommend checking out the images in the source.
+

What I\u2019ve had on Rotation

+
  • Something New: Zephyrus by The Old Hellos (Folk). I\u2019ve mentioned this band before, and for good reason. I love their riotous folk vibes, which they\u2019ve still managed to create during 2020. True, a year full of actual riots, but also a year full of not gathering in groups. (links)
  • +
  • Something Old: Animal Magic by Bonobo (Instrumental/House). Bonobo\u2019s come a long way in the production of his music - his newer music feels so clean and refined, but I\u2019ve enjoyed rediscovering the simple/rawer sound of his older stuff this week. It\u2019s still beat-centric, makes you want to move, and doesn\u2019t quite fit in any genre. (links)
+

Cool Articles

+
  • Everything I know about a good death, I learned from my cat by Elizabeth Lopatto for The Verge. For a while now I\u2019ve been thinking about dignity in dying, and this article is a really great exploration of some of those ideas, but in the context of Dorothy Parker, a cat with cancer. It\u2019s a touching article, with some well written points.
`; +}); diff --git a/.netlify/server/chunks/2020-10-24-writing-for-recipe-cards-ae8f013d.js b/.netlify/server/chunks/2020-10-24-writing-for-recipe-cards-ae8f013d.js new file mode 100644 index 0000000..371e042 --- /dev/null +++ b/.netlify/server/chunks/2020-10-24-writing-for-recipe-cards-ae8f013d.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_24_writing_for_recipe_cards, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Tiny thought: Writing for recipe cards", + "author": "Thomas Wilson", + "date": "2020-10-24T00:00:00.000Z", + "draft": false, + "slug": "2020-10-24-writing-for-recipe-cards", + "tags": ["tinythought", "essay", "writing"] +}; +const _2020_10_24_writing_for_recipe_cards = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Tiny Thoughts are little (500 word) essays. They\u2019re concise.

+

I\u2019ve spent the past three months consciously trying to write and read more. I want to improve my ability to refine and communicate thought, and doing it in public helps motivate me to produce work.

+

One of the hardest problems I find myself addressing frequently is my desire to over-explain or provide too much information. I have read many times that good writing is about being concise. Being direct and undistracted help you get your point across. You\u2019re not tiring the reader, and you\u2019re not brining in unnecessary information. Being concise is good.

+

A few weeks ago I was listening to the JS Party podcast, a show I subscribe to but often skip. I picked up this episode because its title, Content is Queen, seemed relevant. I don\u2019t see my writing as content, but I know other people view theirs that way - and so I listened it.

+

Something that came from that episode, which I really liked, was the idea that you should write like you\u2019re creating a small recipe card. It\u2019s a good analogy, and it implies the following things to think about when you\u2019re writing:

+
  1. Realise sometimes you\u2019re trying to get to a point or a result, you\u2019re not trying to be witty or identifiable in your writing style.
  2. +
  3. Identify and sign-post the most important steps in a process, or points in an argument.
  4. +
  5. Figure out how to your points reproducible, undeniably clear, and re-usable.
  6. +
  7. Condense your points down to as small a number as possible, you\u2019re writing for a small recipe card.
+

I don\u2019t know how well these items hold for longer pieces, or opinion pieces. Sometimes you want to let your personality shine through in your writing, and sometimes you can let yourself wander. That said, I\u2019ve been working a lot harder on deleting sentences, rather than adding them in, for the past month or so. I think that\u2019s, at least in part, because of this little realisation.

+

You can see the full transcript for the episode on theepisode page, but the original quote comes from Stephanie Morillo that sent me on this thought is:

+

You know the recipes you get with a Blue Apron or a Sun Basket subscription? They fit on a card, right? And they\u2019re not superfluous and they\u2019re not using all these great words. Every word there is there for a reason, and they\u2019re not gonna give you the back-story and all that fun stuff. They are \u201CYou\u2019ve gotta do this, you\u2019ve gotta do this, you\u2019ve gotta do this.\u201D But the great thing is that as a result, you pretty much don\u2019t mess up the recipe.

`; +}); diff --git a/.netlify/server/chunks/2020-10-31-things-i-learned-12-8d6c0203.js b/.netlify/server/chunks/2020-10-31-things-i-learned-12-8d6c0203.js new file mode 100644 index 0000000..e637b54 --- /dev/null +++ b/.netlify/server/chunks/2020-10-31-things-i-learned-12-8d6c0203.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_10_31_things_i_learned_12, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #12", + "author": "Thomas Wilson", + "date": "2020-10-31T00:00:00.000Z", + "draft": false, + "slug": "2020-10-31-things-i-learned-12", + "tags": ["things-i-learned"] +}; +const _2020_10_31_things_i_learned_12 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This high fat diet: Whales, like dolphins but also humans, are mammals. This means they feed their young with milk. As you would expect, the blue whale has the largest mammary glands on Earth \u2013 each is about 1.5m long and weighs as much as a baby elephant. Blue whale mothers can produce 200 litres of milk per day, with a fat content of 35-50%. For reference, double cream is about 48% fat. It\u2019s no wonder blue whale calves gain about 90kg of weight a day for the first year of their lives.(source)
  • +
  • This 100 year old word: \u201CRobotics\u201D is 100 years old this year, although it was first published by Czech writer Karel \u010Capek in a play, R.U.R. (Rossum\u2019s Universal Robots), the author credits his brother, Josef \u010Capek, as the actual inventor of the word. Either way, the word itself derived from the Slavic word robota which means slave or servant, and originally referred to artificially manufactured humans who could be mistaken for real (organically manufactured?) humans, a la Blade Runner\u2019s (or Phillip K Dick\u2019s) Android.(source)
  • +
  • This reason behind a medieval punishment: In the 1500s, Queen Mary, England\u2019s first Queen who wasn\u2019t just the wife of a king, gained a reputation as \u201CBloody Mary\u201D. Mary was a deeply Catholic woman, which is especially surprising given her father, Henry VIII, formed the Church of England and had a real thing for getting divorced. During her reign, Queen Mary worked hard to stomp out the Protestant faith, electing to burn a lot of its public practitioners. There were numerous, surprisingly socially acceptable, ways to execute someone in Tudor England, but being burnt alive was chosen purposefully. It was supposed to give the victim a taste of the hellfire which was about to overwhelm their soul for all eternity - and a last chance to accept Catholicism and therefore prevent this. (source)
  • +
  • This Twitter Holiday:In April 2011, Ed Ball, the now retired British MP, simply tweeted his name. It turns out he was trying to search for articles about him on the site, but instead he just ended up tweeting two words: \u201CEd Balls\u201D. At the time he didn\u2019t know it was possible to delete Tweets, but even since learning he could, he\u2019s left the Tweet up. Every April 27 some people now celebrate \u201CEd Balls Day\u201D - which strikes me as as a joyfully silly holiday. Back in 2011 it was slightly more noteworthy for politicians to tweet absurd things. (source)
+

What I\u2019ve had on Rotation

+
  • Something New New Ruins by Indian Wells (Contemporary Electronic). I\u2019m not 100% sure what genre Indian Wells fits in - it\u2019s beat-heavy, synth-tactic, melodic, and rhythmic. It\u2019s good music to work to, but I also enjoy it if I\u2019m out on a run. This EP, released a few weeks ago, has been really great to put on when I need to focus in on something. (links)
  • +
  • Something Old All Eyez On Me by 2Pac (Old School Hip Hop). Man, 2Pac gets a lot of recognition and for good reason. He put this album out in \u201897, and it\u2019s two hours long - two hours of lyrically detailed, flow-heavy, classic gangsta rap that honestly still stands up in its own right over 20 years later. (links)
+

Cool Articles

+
  • What if Friendship, not marriage, was the centre of life? by Rhaina Cohen for The Atlantic. I like this article because it\u2019s able to point at something we hardly consider, e.g. that the most important and significant relationship in your life will be your romantic one, and ask why that is. I\u2019m not proposing we all try and label someone our platonic soulmate and buy a plot of land in the south of France together (but that would be fun for a bit), but rather ask why we don\u2019t have the words or cultural role models to explain this kind of relationship.
  • +
  • Quest Sprout: \u2018The most wholesome thing on the internet\u2019 by Michael Baggs for the BBC\u2019s Newsbeat. I saw these cartoons popping up on Reddit every now and again, and they lifted my heart. Quest Sprout is the creation of a a New Zealand-based artist and games tester (and all round nerd) who was trying to spread more positivity. Quest Sprout is a tiny, floral character who just loves going on quests but, like the rest of us, is scared sometimes. Quest Sprout is wholesome and reminds us to be kind to ourselves and others. Go and read the article and feel better on the inside.
`; +}); diff --git a/.netlify/server/chunks/2020-11-01-js-runtimes-and-environment-c2ddc8b0.js b/.netlify/server/chunks/2020-11-01-js-runtimes-and-environment-c2ddc8b0.js new file mode 100644 index 0000000..3fc351c --- /dev/null +++ b/.netlify/server/chunks/2020-11-01-js-runtimes-and-environment-c2ddc8b0.js @@ -0,0 +1,63 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_11_01_js_runtimes_and_environment, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Why are you like this JavaScript? JavaScript Runtimes and Engines", + "author": "Thomas Wilson", + "draft": false, + "book_review": false, + "date": "2020-11-01T00:00:00.000Z", + "slug": "2020-11-01-js-runtimes-and-engines", + "tags": ["javascript", "why-are-you-like-this-js"] +}; +const _2020_11_01_js_runtimes_and_environment = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Sometimes you keep hearing words but you\u2019re not actually sure what they mean, but you\u2019re too afraid to ask and keep forgetting to Google it. For me, two of those phrases have been \u201CJavaScript runtime\u201D and \u201CJavaScript engine\u201D. I\u2019ve never studied Comp Sci at uni, and I\u2019ve never practically needed to be able to define either of them.

+

If that sounds similar to you, then buckle up cowboys and cowgirls because you\u2019re about to go \u201Coh, yeah, cool\u201D a lot at some pretty basic distinctions that you probably intuitively knew but didn\u2019t have the words for.

+

I think there\u2019s innate value in understanding more about where and how your code actually runs. It\u2019s rarely directly applicable, but at some point in writing a large-enough app in JS, especially if it\u2019s full-stack, you\u2019re going to need to know these things. It\u2019ll also help you understand why Node.JS and client-side JS are different, and appreciate the overall portability (if not the performance) of JS in the wider context of software engineering. Or throw it out there in your next engineering interview and sound smart and informed, and hope they don\u2019t ask any deeper questions \u{1F937}\u200D\u2640\uFE0F

+

TL;DR

+

The JS runtime is the place where JS (or its machine-readable counterpart) is actually run. The browser is a runtime and it\u2019s how JS has access to things like the window object. Server-side JS runtimes also exist, like Node.JS.

+

Engines are the bit of software which take our source code, e.g. the human-readable JS code, and transform them to computer-executable instructions. There are a number of ways that engines can do this, some of them use Just in Time (JIT) compilation, but JS is an interpreted (i.e. non-compiled) language.

+

JavaScript Runtimes

+

I just assumed that the JS runtime was the browser or server where the JS actually ran, i.e. where the commands (like console.log('hello')) were executed. And I was right, but there\u2019s a little more detail to this answer.

+

JS runtimes get a bit of flack for causing bad performance, whatever that generic term means. Take this critique from Sebastian De Deyne:

+

We\u2019re adding heavy runtimes to support multiple platforms instead of staying close to the metal, and we pay the price in performance.

+

This criticism brings us a little closer to a useful definition of a Runtime: it includes the libraries and frameworks which act as the intermediary between the code you\u2019ve written, and the operating system it is running on. So if we take this mental model a little further, a runtime is the abstractions that sit between the bare metal and the running program (StackOverflow source).

+

Programming languages haven\u2019t always needed, or come with, a runtime. Some of the earlier languages, like FORTRAN and COBOL have such a limited set of features and syntax that the language is the runtime (at least conceptually). The difference between the source code (i.e. the code written by an author) and the machine-executable compiled code which are created from the source code, is pretty minimal in these languages. The code you write details explicit manual control over memory allocation, garbage collection (and a bunch of other features) that the source code doesn\u2019t need to bring in anything else. The computer can run that file just fine by itself. Obviously this shifts the role of a program from not only its intended computation, to include also the memory allocation and logistics around these computations.

+

The C programming language is a good example of when we bought in runtimes. C came with the ability to call other libraries or functions to achieve certain things. For example, the malloc function allows an author to allocate memory and get a pointer to its location. malloc is defined in stdlib of C - in a separate C file to the one the author is currently writing. The stdlib library defines exactly how memory is allocated through and the correct address is returned. This allows us, the authors, to focus on the logic of our code specifically, and not to have to re-write a memory allocation function in pretty much every bit of C code we write. This speeds us up, reduces errors, creates conventions\u2026 all good things in software engineering at scale.

+

That means that if we were to write a simple C script which invoked malloc, when we came to execute our code it would need to also have some way of gaining it access to the stdlib, as malloc is defined there, not in our code. The malloc function is not syntax in the language, in the way that if, char, and static are. The runtime of our C script would include access to the malloc function. These libraries would need to be linked.

+

Subsequent languages, famously Java and C#, came with a very heavy runtime - their Virtual Machine (VM). This is what allows both languages to boast portability between architectures and OSs - the source code runs inside of a VM, and the VM abstracts away all the complexity of interacting with the bare metal.

+

To return to JavaScript briefly, this is how browser-executed JS has access to objects like window - which we never define, and which wouldn\u2019t be defined if we ran our JS in a non-browser like environment (e.g. Node.JS). The runtimes of browser Javascript provide our source code with access to these APIs and libraries. They\u2019re not part of the core JS language, like Function and Object are.

+

When we talk about JavaScript runtimes we\u2019re talking about the environment in which the executing code lives and works.

+

Javascript Engines

+

A JS engine is what gets us from the human-readable JS code into a computer-interpretable set of instructions. E.g. const name = 'Thomas' isn\u2019t an instruction that an operating system or browser would understand. Instead, we need some way of letting our program find and manage memory, link things together, etc.

+

Let\u2019s take a moment to just cover some technical terms:

+
  • Source Code is the original code in JS, e.g. written by a human author. It may also be valid JS which has been minified by a build step.
  • +
  • Machine Code is a set of instructions for CPUs for loading memory, performing specific tasks etc. Machine code is not human readable (wikipedia)
+

Different JS engines go from source code to machine code in different ways, which vary with their target environment and can affect the performance of a script. For examples, the V8 engine compiles to machine code, whereas Rhino compiles JS to Java classes. Let\u2019s not talk about the implications of this - just assume that they\u2019re comparable but different\u2026 ya know?

+

The JS engine is what lets our JS code just\u2026 run. Engines are responsible for several low-level machine operations which are necessary on the journey from source code to machine code. They load the script into the computer\u2019s memory, link all the necessary libraries together so all parts of the program have access to each other (remember runtimes?), and then find the entry point (i.e. the instructions in the index.js file) and start executing those.

+

Unlike Java or C#, JavaScript is not a compiled language. Compiled languages are transformed to machine-readable code before the program is started or executed. Instead, JS is an interpreted language. This means that the code isn\u2019t compiled or prepared ahead of execution. It\u2019s building the runway as it takes off. The role of the JS interpreter is to take the source code and call the instructions on the processors and CPU of the computer where the code is running.

+

This is the source of one of the most defining \u201Cfeatures\u201D for novice and experienced JS authors alike, the cannot read property X of undefined error, caused by the fact that we have tried to access a property (X) of something which does not exist (undefined). This is a classic kind of error which a compiled language may be able to catch - by checking for potentially undefined variables. But we\u2019re getting off track.

+

With that said, the highly performant V8 engine uses Just in Time (JIT) compilation of JS to machine code. This means the JS source code is compiled, but as close to its execution as possible. I\u2019m not going to go into JIT compilation here because it\u2019s a little long, but Mozilla have a great summary on it.

+

So yeah - the engine is what takes our .js files, and allows a computer to do the relevant computer-y things with them. And here we all are, trying to remember which way round the Boolean logic works on filter().

`; +}); diff --git a/.netlify/server/chunks/2020-11-07-things-i-learned-13-87ae224f.js b/.netlify/server/chunks/2020-11-07-things-i-learned-13-87ae224f.js new file mode 100644 index 0000000..66f97e0 --- /dev/null +++ b/.netlify/server/chunks/2020-11-07-things-i-learned-13-87ae224f.js @@ -0,0 +1,45 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_11_07_things_i_learned_13, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #13", + "author": "Thomas Wilson", + "date": "2020-11-07T00:00:00.000Z", + "draft": false, + "slug": "2020-11-07-things-i-learned-13", + "tags": ["things-i-learned"] +}; +const _2020_11_07_things_i_learned_13 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

WHAT. A. WEEK. It feels the entire western world has had their eyes on the US presidential election, and it\u2019s been exhausting. Not exhausting in the way that the last 12 months have been for the US, but exhausting in the way that nothing in 2020 has lead us to expect anything good to happen. As I write this, Joe Biden and Kamala Harris have just been elected as president- and vice president-elect. It\u2019s not the start of a revolution, the structure of the US political system prevents power being torn too far one way or another (or at least intends to), but it\u2019s a collective sigh of relief from me, and a lot of the people in circles I follow.

+
  • The reason behind this saying: I recently heard the phrase \u201CA good wine needs no bush\u201D for the first time - it captures the notion that a good product doesn\u2019t need advertising. The origin of the saying comes from the centuries-old practice of vintner hanging a sprig of ivy, or other trees, outside the entrance of taverns to indicate they sold the wine. The idea being that a good wine doesn\u2019t need to be advertised in order for people to know it is available. (source)
  • +
  • This Swedish ritual: It is a cultural institution in Britain to stop work (or chores, or study, or anything) at some point between 1-5pm, to make a cup of tea and have a sit down with some biscuits. In Swedish culture they have Fika, where the focus is on taking a break for coffee and some kind of (ideally home-baked) cake. Socialising with your friends or colleagues, and slowing down are central to this ritual.(source)
  • +
  • This bit of Joe Biden\u2019s medial history: Joe\u2019s been attacked for being old, and it\u2019s true, when he get inaugurated he\u2019ll be 77 and the oldest US president. In 1988 Joe almost died from having two aneurysms, and later the same year he had a pulmonary embolism. That\u2019s wild - those are two things (or three) that could really easily kill a man, but here we are, 30 years later.
  • +
  • These emojis coming in 2021: I love emojis, I love that they\u2019re tiny cute works of art which represent parts of our culture and society better than words easily can. I love that anybody can submit an emoji proposal. Because of the coronavirus, some emojis have been delayed for 2021, but as things stand we can expect to see bearded men and women, some new faces, and 200 new skin tone combination for couples and kissing emojis. (source)
+

Cool Articles

+
  • Is technology scrambling my baby\u2019s brain? by Ben Popper for The Verge. I hear a lot of descent for exposing our children to screens at a young age - Tim Cook, the CEO of Apple famously said that he wouldn\u2019t let his child use an iPad. Popper takes a serious look, as both a parent and a tech-lover and -journalist, at our collective obsession with forbidding technology to our children, and asks if maybe we\u2019ve gone too far. It\u2019s a well-balanced article on a subject that I think a lot of people are very touchy about.
  • +
  • Essays on Programming I Think About a Lot by Jake Worth on their personal blog. If you develop software for a living, or work with teams who do, Worth highlights a lot of one-liners from essays by other software architects and engineers. There\u2019s a lot of wisdom in there, and links to the original sources. It\u2019s not something I suggest digesting all at once, but better as a slow burn.
+

What I\u2019ve had on Rotation

+
  • Something New: Positions by Ariana Grande (pop). No, you don\u2019t need anyone else talking about or recommending this album, but it\u2019s a good album. I love Ari\u2019s self-confident, sex positive, self-loving new album. It\u2019s a good take. (links)
  • +
  • Something Old: effloresce by Covet (instrumental). I don\u2019t know what genre this music is, it\u2019s like jazz meets acoustic guitar meets softer elements of metal rhythms. I don\u2019t know - but I do know that Yvette Young (the lead guitarist of Covet) has a talent that you should listen to. (links)
`; +}); diff --git a/.netlify/server/chunks/2020-11-08-an-absolutely-remarkable-thing-cc424996.js b/.netlify/server/chunks/2020-11-08-an-absolutely-remarkable-thing-cc424996.js new file mode 100644 index 0000000..529286e --- /dev/null +++ b/.netlify/server/chunks/2020-11-08-an-absolutely-remarkable-thing-cc424996.js @@ -0,0 +1,58 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_11_08_an_absolutely_remarkable_thing, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "An Absolutely Remarkable Thing", + "image": "an-absolutely-remarkable-thing", + "slug": "an-absolutely-remarkable-thing", + "author": "Hank Green", + "score": 3.5, + "book_review": true, + "date": "2020-11-08T00:00:00.000Z", + "finished": "2020-10-15T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "sci-fi", "adventure"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Hank-Green/An-Absolutely-Remarkable-Thing/23676697" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/an-absolutely-remarkable-thing/9781524743468" + } + ] +}; +const _2020_11_08_an_absolutely_remarkable_thing = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

An Absolutely Remarkable Thing (AART; because I\u2019m not paid by the word here) is a wonderful Sci-Fi(-ish) adventure by Hank Green, one of the content creators in the first wave of the YouTube-meets-mainstream movement. It\u2019s a delightful first piece in his The Carls series, and even if the characters fall a little flat - the story is compelling enough to make this book a delightful and worthy read. Green\u2019s obviously got a lot to say about the current state of internet, fame, media, and global attention. He doesn\u2019t stuff it down your throat, but uses it to shift his story forwards.

+

AART follows April May, a young twenty-something art graduate living in New York, who\u2019s thrust into international fame after she stumbles across a giant metallic samurai-like sculpture who she calls Carl, in the streets of New York. Pretty soon April, and then everyone she comes into contact with, start having the same dream every night: they \u2018awaken\u2019 in a giant uncanny-valley city, full of riddles and puzzles that feel like they were made by an AI who sucked information out of Wikipedia. We follow, from a first-person perspective, as April is thrust into international recognition and fame, as she tries to solve the mystery of the Carls, and facilitate international cooperation against a potential threat from outer space. It\u2019s pretty fantastic when you spell it out.

+

The thing about basically-instant fame thrust upon \u201Cnormal\u201D people is that they\u2019re completely unequipped to deal with it. The first-person narrative in AART does an excellent job of showcasing this, even if April\u2019s flaws are show-ponied in front of us sometimes. We get a good sense that reality, society, and her friends are warping in front of her. They may appear close or present, but they often feel out of reach, or beyond influence - as the person April was transitions into the idea or figure or character of April. Green does a good job of fleshing out the characters who stay in a relatively tight orbit of April, and doesn\u2019t parade a seemingly endless number of characters. He directs your attention to those who are important, and signposts clearly when someone\u2019s just passing through.

+

As the book goes on, the relationships become increasingly dominated by their dependence on April and the entire Carl phenomena to define them. In some places, peripheral characters\u2019 strengths and capacities are a little superficial or passed over. For example one of the characters spins up something like an entire tech start-up within weeks/months, and it\u2019s just sidelined as a narrative tool to push the story forwards. Other characters fall a little flat and only appear when they need to do something for April, even though their friendship pre-dates The Carls. Rarely does anyone else show weakness or signs of struggling. Sure, April becomes increasingly self centred, and it might be hard to force these details into the story, but I noted their absence.

+

However I find myself forgiving a lot of these flaws in characterisation and narrative in favour of an extremely compelling story. This book was an adventure, really. There were clues and puzzles to solve, a well established villain and tight pressure from them, and at least two moments which shocked me in their unpredictable-ness. The pacing escalated well throughout the book and maintained itself nicely, and the book didn\u2019t outstay its welcome. It is a relatively short read, and there\u2019s always something happening.

+

The world is pretty much a modern day (2020s) America, with the exception of a woman president which, look, actually including Trump in this novel would have been an awful idea. There\u2019s a nice inclusion of both internet and portable technology, which is refreshing - it seems almost inconceivable to me that a book about a 20-something woman from New York wouldn\u2019t have a ton of group chats. Green utilises this in the way we do in real life - it\u2019s not a thing, it\u2019s just a tool that the characters use.

+

Green clearly understands the modern world at both a macro and a micro level. He understands how people talk to each other, how \u2018traditional\u2019 and \u2018modern\u2019 media are in tension with each other, how the western world spends its attention, and how we conflate infamy and expertise. These kinds of critiques and commentaries are placed nicely within a Sci Fi-ish adventure, and never showcased explicitly. It becomes a high-resolution and completely believable backdrop to a more fantastic story. The book doesn\u2019t try to over-reach in those regards.

+

As someone who doesn\u2019t read a lot of Sci Fi, and who hasn\u2019t read a lot of Young Adult recently (as vague as the YA genre is), I enjoyed reading this book. It immediately left me wanting to pick up the sequel, if not for the poetic writing or poignant philosophy, for the compelling plot. When I read cheaper/junkier crime novels I\u2019m often left feeling a little embarrassed or like I should go read something \u201Creal\u201D. That wasn\u2019t the case with this book. I was invested in what was happening, so yeah it\u2019s a good book 3.5\u2B50

`; +}); diff --git a/.netlify/server/chunks/2020-11-13-things-i-learned-14-f6c9a803.js b/.netlify/server/chunks/2020-11-13-things-i-learned-14-f6c9a803.js new file mode 100644 index 0000000..785fc31 --- /dev/null +++ b/.netlify/server/chunks/2020-11-13-things-i-learned-14-f6c9a803.js @@ -0,0 +1,45 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_11_13_things_i_learned_14, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #14", + "author": "Thomas Wilson", + "date": "2020-11-13T00:00:00.000Z", + "draft": false, + "slug": "2020-11-13-things-i-learned-14", + "tags": ["things-i-learned"] +}; +const _2020_11_13_things_i_learned_14 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Happy Friday 13th. I hope it\u2019s spooky and magical.

+
  • This Roman Beverage: I\u2019d imagine the Romans were pretty thirsty. The Mediterranean is warm, and you\u2019d work up quite the thirst inventing a whole number system, apartments, a calendar, and like a million kinds of war machinery. Not that I\u2019d know. The Romans bloody loved posca: a mix of vinegar and water (or diluted wine), seasoned with herbs and salt. It was incredibly popular in both the military and with citizenry an. The acidic nature probably helped sanitise the water at the time, but unfortunately we\u2019re not 100% sure exactly how it tasted - recipes, ingredients, and proportions having changed some over the last 500-2,000 years. I personally don\u2019t love the idea of mixing wine, water, and fennel seeds but maybe that\u2019s why I\u2019ve never built a trebuchet (source)
  • +
  • These hunter women: Growing up my understanding of our women in prehistoric times was that they gathered and gossiped - which is some of the reason language and social bonds are so ingrained in us as humans, and why caring and communicating are typically seen as \u2018feminine\u2019 traits. A recent study of some 400 bodies from over 100 sites across the Americas, dating 6-12 thousand years in age, repeatedly found women buried with large-game hunting tools. Previously, when we\u2019d found women with these kinds of tools, we just assumed that they were used for scraping or cutting - not hunting. But the study found women buried with projectiles and large stones - so they were either grinding some big root vegetables, or hunting big game. Just a reminder that sexism here and now projects onto things in the past (source)
  • +
  • This reason they\u2019re called Roses: It\u2019s pretty established that Roses, the Cadbury\u2019s variety box of chocolates, are the taste of Christmas. Maybe they\u2019re not quite a bougie as Celebrations, but at least they\u2019re not Quality Streets. If you think Quality Streets are better than Celebrations then you should take a look at yourself and ask why you\u2019re so poor at judging chocolates. Anyway, here\u2019s the fact: did you know that Roses are called Roses after the name of the machinery which wraps the chocolates? (source)
  • +
  • This word: Milquetoast, which means timid or weak or feeble. The meaning comes from the 1920s cartoon character Caspar Milquetoast. The character\u2019s name is based on the American dish Milk Toast - which is toast served in warm milk. So a character was given a name after a dish which represented his weak character, and now we use a gallicised version (we Frenched it up a little) of that dish to describe those characteristics. Isn\u2019t language cool?
+

What I\u2019ve had on rotation

+
  • Something New: Some Kind of Peace by \xD3lafur Arnalds (Contemporary Classical). I\u2019ve always found Arnalds\u2019 music incredibly peaceful. This new album is pleasantly organic and calming, and doesn\u2019t sound exactly like anything he\u2019s made before. (links)
  • +
  • Something Old: Eagles by Eagles (Rock and Roll). I\u2019ve been digging into classic rock and roll figures over the past couple of weeks. Eagles are one of my dad\u2019s favourite bands, so it feels nice to be among my musical heritage. (links)
+

Cool Reads

+
  • Labors of Love; The Hidden Burdens of a Romanic \u201CLove Padlock\u201D Tradition by Kurt Kohlstedt for 99% Invisible. The first time I ever went to Venice, there was a brigade of men in high-vis jackets cutting the padlocks off some of Venice\u2019s famous bridges. This article covers some of the practicalities involved with this phenomena of engraving your name in a padlock, then locking it to public property and throwing away the key.
  • +
  • Car-free neighbourhoods: the unlikely new frontline in the culture wars by Tim Lewis for The Guardian. As an avid cyclist and London-resident my gut reaction is that we should get rid of all the cars we can. Ban \u2018em. Burn \u2018em. We don\u2019t need them. I\u2019ve had a bike totalled and another one run over by cars. Lewis does a good job at introducing the counter arguments to this way of thinking - a reminder that cities are shared spaces, lived in by many
`; +}); diff --git a/.netlify/server/chunks/2020-11-14-on-connection-f5179625.js b/.netlify/server/chunks/2020-11-14-on-connection-f5179625.js new file mode 100644 index 0000000..d933a3d --- /dev/null +++ b/.netlify/server/chunks/2020-11-14-on-connection-f5179625.js @@ -0,0 +1,58 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_11_14_on_connection, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "On Connection", + "author": "Kae Tempest", + "score": 4, + "image": "on-connection", + "slug": "on-connection", + "book_review": true, + "date": "2020-11-14T00:00:00.000Z", + "finished": "2020-11-12T00:00:00.000Z", + "draft": false, + "tags": ["non-fiction", "essays", "art", "creativity"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Kae-Tempest/On-Connection/24940706" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/on-connection/9780571354023" + } + ] +}; +const _2020_11_14_on_connection = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Kae Tempest is a London-based artist who works with words. I first discovered their work in 2016, with the release of Let Them Eat Chaos - a conceptual spoken word album which imagines a London street at 4:18am. To be perfectly honestly I think Tempest has a well honed skill with words. Their work has spoken to me with clarity in times when not a lot else could get through. Some of Tempest\u2019s phrases and lyrics are burned, deep, into my brain and emerge with remarkable frequency when I\u2019m just trying to live my life. So Tempest could have filled the hundred-or-so pages of this book with near nonsense and I\u2019d still recommend it to anyone. Fortunately, they didn\u2019t do that.

+

In this relatively short, and surprisingly personal, essay, Tempest talks about the purpose and process of making art. Of the difficulties of creation, of the things which make watching, hearing, seeing, experiencing art interesting, and of the things you have to accept as someone who wants to make art. I was delighted to find Tempest speak of their own past, and privilege, and experience. They have historically been rather cautious about sharing personal details, which is fair, but it\u2019s nice to see and read.

+

The margins of this book were filled with highlights and underlines, it\u2019s a short piece and it\u2019s crammed with things I want to pay attention to, and to remember. It doesn\u2019t go on when it can be concise, but there were perhaps moments of repetition, or points which were presented and then immediately abandoned. It\u2019s a refined set of thoughts, but that doesn\u2019t mean it doesn\u2019t branch off every now and again. Which is fine, this isn\u2019t a textbook.

+

As the book\u2019s title suggests one of the central turning points in this book is the role of art as a tool to connect us. As a tool for empathy, to remind us of others\u2019 inner lives, to connect us to ourselves. This connection is the source of tension - around which we can hang a narrative or theme to engage the audience with our art. Tempest asks us to consider both ourselves and the subject of our art - what are the things your character is trying to say, and what are the reasons you, the artist, think this is worth saying or hearing? What does this say about the subconscious version of your self, who you can watch but only if you really try? Tempest openly draws heavily from the Jungian ideas of subconscious.

+

A secondary point which Tempest mentions rather nebulously throughout the first third of the book is our culture of capitalism. A good thing to be aware of, and criticise, but something which they only detail relatively shortly. Despite the brevity, it\u2019s a wonderful point: we are surrounded by notions of productivity and efficiency which value taking something, extracting it, refining it, and making something more valuable from these raw materials. We cannot view our relationships with others, or with ourselves, in this way. We cannot connect with people if we are constantly looking to extract and refine whatever we can from them or from our relationship with them, even if that thing is art.

+

There\u2019s a bittersweet note in this book being released during the COVID-19 pandemic. Tempest talks about the unique ability of poetry to level an audience. To connect everyone listening to one act, one narrative, one performer, one voice. The ability of us to gather, hear something, and then move apart connected more closely to the people around us, despite having nothing more in common than when we arrived. It\u2019s pretty unique in human experience. We\u2019ll get back to gathering like that in the future, but it felt so implausible in the here and now, when I have been to precisely one live music event in the last eleven months, and I don\u2019t think I\u2019ll be going to any for the foreseeable.

+

Tempest lives by example in this book - encouraging us to ask if there is anything unspoken or unacknowledged in our art. To consider if we the audience, or we the creator, would benefit from considering art in relation to our self. The vulnerability and open-ness they share throughout the book is encouraging, though maybe could still seem cagey if the reader isn\u2019t aware of Tempest before picking up this book. Despite that, I think anyone who loves or makes any kind of art, or who spends a lot of time working with people, will recognise the heart of this manifesto as useful.

+

At very least, it is a short book, even if you hate it (but still feel compelled to finish it) then it\u2019s not going to take more than a few hours of your time. Not that that should be the ultimate selling point of a book, but you get my intention. Read this book, it might help you know yourself better, and give you a way to shape or vocalise your thoughts. 4\u2B50

`; +}); diff --git a/.netlify/server/chunks/2020-11-19-figma-components-9b57977b.js b/.netlify/server/chunks/2020-11-19-figma-components-9b57977b.js new file mode 100644 index 0000000..06fcd40 --- /dev/null +++ b/.netlify/server/chunks/2020-11-19-figma-components-9b57977b.js @@ -0,0 +1,92 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_11_19_figma_components, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Introducing Figma Variants with 5 Components that aren't Buttons", + "author": "Thomas Wilson", + "date": "2020-11-19T00:00:00.000Z", + "draft": false, + "slug": "2020-11-19-figma-variants-without-buttons", + "tags": ["design", "figma"] +}; +const _2020_11_19_figma_components = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Figma recently introduced Variants - a way of extending and varying your components. Components in Figma, and in modern web development, are reusable and encapsulated elements of a design - with the classic examples of a Button or a Card.

+

Variants add new flexibility, and utility, to components in Figma by introducing properties and values to them in a programmatic way. If you have experience writing modern web applications, these variants and properties are like a specific subset of props which you pass to a component. I say subset, because some things will still need to be manually edited within an instance of a component - like the text in a card. Other things, like a \u201Cvariant\u201D or \u201Ctype\u201D be be edited (e.g. info, danger, or primary) which in turn could switch the accent colour, and the icon used (from an i, to an alert, to a logo). Think about all the common variations of a component you make for different use cases - variants are a way to define those before you come to use them.

+

Variants were released relatively recently, and I think they\u2019re cool. While they require more conscious work to create, they make it much easier to compose a mockup or design using an existing design system. Additionally, the need to create a set of names for both your properties, and their possible values, forces you to develop a verbal language around your design.

+

In this piece I\u2019m going to give five examples of where variants have helped me, in the last couple of weeks. I\u2019m not going to use the Button component as an example - because that\u2019s a tired workhorse, and I\u2019m definitely a bit sick of it.

+

Component Examples

+

Don\u2019t bury the lead, here are some components to show how variants in Figma can be used. None of the are Buttons (did I mention that?), but they are all components I\u2019ve used in the past couple of weeks. Where I didn\u2019t make the component myself I\u2019ve linked out to the original author.

+

I\u2019ve standardised on Variant as a property name for a generic \u201Ctype\u201D, \u201Ccontext\u201D, \u201Ckind\u201D, or \u201Cvariety\u201D in components. This is the same language as Material UI uses to describe this property and variation. I personally don\u2019t like to use Type - because it\u2019s already a word loaded with meaning in typed language. Context also has a meaning in React. Naming these kinds of properties is hard, but you have to stay consistent.

+

Shoutout to UI Guideline for providing inspiration and starting points.

+

#1: Toast

+

Toasts are those little alerts that pop up or down into a screen with a transient messages. Often you want to vary the accent colour, or icon, depending on the context of the message. There\u2019s only one property here (Cariant) which controls this accent colour.

+
  • Variant: success, warning, danger, info
+

${

+

#2: Note or comment

+

Eduard Gim\xE9nez released a set of comment components into the Figma Community. The Note This file contains a set of sticky-note-like component which teams can use to annotate their designs in Figma.

+

Eduard has used two properties on his variants: Color, which describes the accent colour of the icon and top of the note, and Dark which is a boolean for if the note should be in a dark mode.

+
  • Color: Yellow, Peach, Coral, etc.
  • +
  • Dark: true, false
+

${

+

#3: Calendar Day

+

I\u2019ve recently been using the Eva Design System as the starting point for a design language. As part of this, I\u2019ve been working with calendars and date pickers - which have turned out to be a classic example of hidden complexity.

+

Calendar days represent a single day within a week or month view, often used in the date-picker component.

+

Eva broke them down across three properties, each a boolean flag:

+
  • Selected: true, false. Used to show if the day has been selected by the user (or by default), and is indicated with the box surrounding the day.
  • +
  • Has events: true, false. Indicates if there are additional details, events, or context on a specific day. Visually this is represented by the small dot underneath the number.
  • +
  • Disabled: true, false. Let the user know that the day cannot be selected or clicked. Visually greys out the day and reduces contrast between background, border, and content.
+

${

+

#4: Card or Modal

+

I\u2019ve been building a number of screens and modals recently (as part of my design work at Oxwash), and Variants have let me use a common component as the background on each of these instances.

+

The Card component typically represents the background and container for some content, e.g. a product in a product list. A Modal, however, is normally overlaid on the screen, as if it had a higher Z axis value (i.e. it pops out of the screen). Visually they are very similar, but conceptually they are quite different.

+

I found by adding or removing an icon in the top-right (e.g. to close a modal) - both were pretty much identical.

+
  • Platform: mobile, desktop. Depending on the size of the viewport, you may wish to change padding, but also reduce/increase the size of touch targets.
  • +
  • With Button: true, false. Place a button in the bottom right of the card, for a primary action.
  • +
  • With Close Button: true, false. Place an icon in the top right of the card which acts as a touch target to close a modal.
+

${

+

#5: Tooltip

+

I\u2019ve also been using Tooltips at Oxwash - tooltips are little containers of text that appear on hover (or tap, for mobile) to offer some additional information.

+

Technically, tooltips are quite complex, but in terms of design I\u2019ve kept them simple, with just a couple of properties:

+
  • Colour: light, dark. To switch between a global light or dark mode UI.
  • +
  • Anchor Position: bottom left, bottom right, etc. Which indicates where the little speech bubble anchor appears on the tooltip.
+

${

+

Wait, couldn\u2019t Figma do that before?

+

Erm, yeah, sorta? Previously you could use naming conventions of components to help organise related components and then swap them out with siblings/cousins/grandparents. You did this with the naming conventions of the component, e.g. you could organise your three different types of alert component by calling them:

+
  • alert/warning
  • +
  • alert/info
  • +
  • alert/success
+

This works when you\u2019ve only got a couple of variations of a component. Specifically it works when your components only vary along one dimension, e.g. the accent colour of the alert. What happens when we have a couple of aspects the component can vary by? What if we want different components for mobile, for dark mode, for actionable alerts (e.g. with a button or link)?

+

All we\u2019ve got is a single string, so we absolutely have to i) maintain strict naming conventions of both the possible values of a property, and ii) identical order of properties in those strings. For example, the following components both parse well to a human, but would be structured very differently within figma:

+
  • alert/mobile/warning/dark/withButton
  • +
  • alert/dark/noButton/warning/mobile
+

This would make it hard to swap components out with the related ones. Figma essentially creates a directory, or folder, -esque structure so these kinds of inconsistencies eventually force you to move around a lot, or do a lot of searching. This will also make your components less discoverable, which is essential if you\u2019re a design team who shares Figma files to a wider organisation.

+

Also it\u2019s just messy. I don\u2019t like non-productive mess.

+

Properties I have found useful

+

There are a couple of properties I have found myself reaching for, and finding useful - especially when you\u2019re trying to work out all the fiddly details in a specific design. These include:

+
  • Variant: Inspired by the material UI naming convention, this covers the possible contexts the component can appear in (info, danger, warning, success).
  • +
  • Platform: If you\u2019re designing the same screen across platforms and viewports you may need to adjust touch targets and font sizes (mobile, tablet, desktop)
  • +
  • Errored: If you\u2019re dealing with fields, forms, or processes - it\u2019s useful to know how we display a failure state and the related info (true or false)
  • +
  • Disabled: Useful if you\u2019re trying to show a certain form state is invalid, most commonly applied to Buttons (true or false)
  • +
  • Authenticated status: Who is the current user and what is their relationship to the page/component? Sometimes we want to show/hide certain actions depending on the authentication or authorisation status (user, admin, or no-user)
`; +}); diff --git a/.netlify/server/chunks/2020-11-20-things-i-learned-15-fcfff925.js b/.netlify/server/chunks/2020-11-20-things-i-learned-15-fcfff925.js new file mode 100644 index 0000000..8f6baa3 --- /dev/null +++ b/.netlify/server/chunks/2020-11-20-things-i-learned-15-fcfff925.js @@ -0,0 +1,47 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_11_20_things_i_learned_15, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #15", + "author": "Thomas Wilson", + "date": "2020-11-20T00:00:00.000Z", + "draft": false, + "slug": "2020-11-20-things-i-learned-15", + "tags": ["things-i-learned"] +}; +const _2020_11_20_things_i_learned_15 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

\u201CIsn\u2019t it getting dark early ?\u201D - how I\u2019ve started at least half of the conversations I\u2019ve had this week.

+
  • This thing that spreads like a disease: Look, I was a germaphobe before it was cool. I was very aware of how one thing can spread from person to person. However this contagious model of disease doesn\u2019t just apply to problems caused by bacteria/virus/any other vectors. Obesity can spread like disease, where if your friendships mostly comprise of obese people who normalise a sedentary lifestyle, or poor diet, you\u2019re nearly about 170% more likely to be obese than if you weren\u2019t in these friendships. (source)
  • +
  • This gossip circle: In Europe and North America in the 1800s-1900s we used to have a tradition called \u2018Telling the Bees\u2019 where people saw it as incredibly important to keep the bees up to date with what\u2019s going on in your little provincial circles. Were there any deaths, marriages, children, etc. Though especially they were seen as a sign of mourning, with some people even bringing bees to a funeral. I\u2019m glad that we\u2019ve stopped doing that bit, but anything which helps us pay more attention to the wonders of bees is good - they\u2019re adorable and useful - how many of us can say that?. (source)
  • +
  • This obligatory Covid thing: I took some time this week to ask why and how Covid actually spreads and how we trace that. Given the criticism of the track-and-trace system here in the UK, I wanted to know more about what they\u2019re trying to do, and why it\u2019s hard. It turns out the majority of new Covid cases are caused by a minority of people. A study in India found 8% of people with covid cause 60% of the secondary cases, with 70% of people not passing it on to anyone. Since the beginning of the pandemic we\u2019ve been focused on Super Spreaders and this kind of evidence suggests we should continue to maintain that focus. Well done to the 70% who effectively isolate, let\u2019s bump that number up. (source)
  • +
  • These rules for artists: In 1960s America Sister Corita Kent, a teacher and artist, taught a creative class. She brought these ten rules to the classroom and encouraged students to internalise them. They\u2019re not just good for students, or young people - they\u2019re wonderful reminders about how to live, and ended up being very popular among artists. They contain little wisdoms we\u2019d all benefit from: \u201CConsider everything an experiment\u201D and \u201CBe happy whenever you can manage it\u201D. These rules were later attributed to John Cage, so go and read them and attribute them to Sister Corita Kent. (source)
  • +
  • This old meaning: Did you know eye rolling was once a flirtatious gesture? Now it\u2019s used to express sarcasm or exacerbation, but go back a hundred years or so and all of a sudden you\u2019re making bedroom eyes \u{1F644} (source)
+

What I\u2019ve had on rotation

+
  • Something New Detroit 2 by Big Sean (Hip Hop). I\u2019ve been a little late in listening to Big Sean - he got a shoutout from Eminem in Kamikaze - the album where not a lot of other artists got positive attention. This album is packed full of collabs and features - it\u2019s a big production hip hop album. It\u2019s definitely not my normal kind of Hip Hop but I\u2019ve been bumping it this week. (links)
  • +
  • Something Old: Angles by Dan le Sac vs. Scroobius Pip (British Hip Hop). This, alongside Em, was one of my first introductions to hip hop/spoken word/poetry in music. It showed me that music can be serious and fun at the same time, that it can be British, and can teach something. Being 16 when this album came out I learned some things from it but, you know, you\u2019ve not done a lot when you\u2019re 16. Re-listening to it now (as a 28 year old) throws me back, but still speaks to me - which speaks to how truthful and personal the music is. (links)
+

Cool links

+
  • MYSTICAL by Neil Burnell (photo gallery). Burnell is a photographer, and this project is all about the beauty and mystery of ancient woodland.
  • +
  • When Christmas was Cancelled: a lesson from history by Martyn Bennett for The Conversation. With a very different Christmas and New Years on the horizon for a lot of us, which we\u2019ve got the chance to really mishandle, this article takes a little look at how this might not be entirely unprecedented.
  • +
  • UI Coach by Nero. This neat little site for improving your design skills generates you a challenge (e.g. \u201CDesign a goal management and sharing app\u201D), provides you with a colour palette, font pairing, and icon/illustration set. I firmly believe (past the complete novice stage) we learn the nebulous design skills by doing. This is a great idea.
`; +}); diff --git a/.netlify/server/chunks/2020-11-23-tiny-separate-design-engineering-b8124733.js b/.netlify/server/chunks/2020-11-23-tiny-separate-design-engineering-b8124733.js new file mode 100644 index 0000000..31e31bd --- /dev/null +++ b/.netlify/server/chunks/2020-11-23-tiny-separate-design-engineering-b8124733.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_11_23_tiny_separate_design_engineering, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Tiny thought: On the separation of design and engineering", + "author": "Thomas Wilson", + "date": "2020-11-23T00:00:00.000Z", + "draft": false, + "slug": "2020-11-23-on-the-separation-of-design-and-engineering", + "tags": ["essay", "tinythought", "design"] +}; +const _2020_11_23_tiny_separate_design_engineering = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Tiny Thoughts are little (500 word) essays. They\u2019re concise.

+

I make user interfaces, and I often participate in, or lead, the process of designing these interfaces. For a while I thought I wanted to transition fully into a design role. Ultimately I am drawn to the certainty and craft of engineering. However, the the mental models, sensibilities, and philosophies of design still appeal to me. I can like both, and businesses need both.

+

Separating design and engineering is a false dichotomy: design can benefit from the implementation-details of engineering; and engineering benefits from the non-linear and multi-faceted process of design thinking. It\u2019s symbiotic.

+

A while ago I got the chance to work in an environment where the two were separated. The design process and design thinking were both absent, and there was no appetite to bring them in.

+

During this time the mentality was to copy the UI of an existing, similar, already-successful product. A lot of people on the frontlines of tech have been told \u201Cjust copy company X\u201D where X is AirBNB, Twitter, LinkedIn, Pinterest, whatever. \u201CJust make the UI look like that\u201D.

+

At first glance, the thinking is sound: we don\u2019t have the money or time to invest in design, but this other company has. Let the whole design team over at Instagram/Reddit/Uber do the hard work, and we\u2019ll just steal from them.

+

At a personal level, I did not like working in this environment, because I felt alone. At a professional level, the working process was constrained, and the resulting software generic and left behind when the source material changed.

+

Some software has to be boring: I wouldn\u2019t want a whacky or zany bank app, menstrual cycle tracking app, government app, or crisis support app. There is a place for boring UI. Borings UI also removes a layer of difficulty in how the product is built. [^1: I would argue that it\u2019s not actually that much easier to build an app with a Boring UI - UI is just one part of any software.].

+

Behind a lot of boring UIs is a team of individuals who have thought an awful lot about their business, users, and problems. They have considered information architecture, interactions, users, and outcomes.

+

Just because the end result is boring, does not mean the process of designing it was short and simple.

+

When you copy just the final product, even a boring one, you diminish your entire business\u2019s ability to iterate, and any insight into the why of the UI are lost. You have limited your engineering team. Sometimes this limitation is significant (a client-facing product), sometimes it is not (an infrastructure service).

+

The product of engineering should not exist without the process of design. The discussions I have had, facilitated, and witnessed when deciding on UIs have made me a better engineer, and have made the product better.

`; +}); diff --git a/.netlify/server/chunks/2020-11-27-things-i-learned-16-d78b9827.js b/.netlify/server/chunks/2020-11-27-things-i-learned-16-d78b9827.js new file mode 100644 index 0000000..d9c7263 --- /dev/null +++ b/.netlify/server/chunks/2020-11-27-things-i-learned-16-d78b9827.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_11_27_things_i_learned_16, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #16", + "author": "Thomas Wilson", + "date": "2020-11-27T00:00:00.000Z", + "draft": false, + "slug": "2020-11-27-things-i-learned-16", + "tags": ["things-i-learned"] +}; +const _2020_11_27_things_i_learned_16 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • These Tattoos: In the late 1880s, a man called Sutherland Macdonald became the UK\u2019s first professioanl tattoo artist. Although he was already an artist, he started the tattoo craft after a trip to the South Pacific. Macdonald is the reason we have the word \u2018tattooist\u2019 (a portmanteau of tattoo and artist) - because the Post Office had to create a new category to place an advert for his services in. He also patented an electric tattoo gun in 1895, and created the first \u2018safe\u2019 green ink which did still contain lead so\u2026 (source)
  • +
  • This unconventional translation: In 1900, a newspaper in Reykjavik, Iceland, serialised Dracula - the classic horror novel by Bram Stoker. The translation, entitled Powers of Darkness, took some rather strong decisions in the translation. They shortened some parts, adding a deaf-mute handmade to the Count\u2019s castle, added some police investigations, completely omitted the fact that the Count drinks the blood of his victims, and removed the original ending by finishing the novel early. So they essentially took Dracula, riffed on it and did a little workshopping (more \u201Cyes and\u201D), rewrote the book in another language, gave it the same name and author, and then just presented it like it was the original, just translated (source)
  • +
  • These new bodies: This week, the details of two new remains of a master and slave were release at Pompeii - the Roman city that was famously wiped out when a volcano erupted nearby in 79AD. The pair consisted of an older (30-40) and a younger (20s) man who had been preserved in ash for the last two thousand years. I\u2019m just going to repeat that once more: two thousand years ago a volcano killed two men, their flesh and muscles were burned away, and then we found their very well preserved bodies in the ash. (source)
  • +
  • This historical insight: We know that the nature of religion and spirituality has changed a lot. Way back when we were more hunter-gather, our spiritual views were pretty Shamanistic and Animist: places and things had their own spiritual essence. Then at some point we moved to more mono-, and sometimes, poly-theistic place where we had spiritual entities distinct from worldly places or things. And also we started having Organised Religion. We used to think that this transition happened alongside the move from tribe to central metropolitan areas. It makes sense - if religion is (among other things) a way to teach and enforce morals, it helps to have an \u201Ceye in the sky\u201D that sees you if you steal, have sex sex with your neighbour\u2019s spouse, or murder. God Is Watching, even if the entire village/town/city is not. However, it actually seems that we evolved as a society and then spiritually. So for a while we had these older religions, as humans moved to larger and more complex settlements and cultures. The link in the source is interesting, go and check it out - it asks what role religion has played, does play, and could play as our socieities become more complex and geographically dispersed. (source)
+

What I\u2019ve had on rotation

+
  • Something New: Because I Wanted You To Know by Matilda Mann (Singer Songwriter). These songs are feminine, and cute, and well produced. This little EP is the feeling of seeing someone cute somewhere and the nerves of talking to them, then hoping they actually text you. (links)
  • +
  • Something Old: Eyes Open by Snow Patrol (Sad Pop?). This album takes me back so quickly to being 16 - and also makes me very sad to listen to, but also I really like the music? Genuinely I had to stop listening to it a few times this week because it was just making me too sad. But I kept coming back to it, so\u2026 (links)
+

Cool Articles

+
  • Jan Morris, historian, travel writer and trans pioneer, dies aged 94 by Richard Lea for The Guardian. I only learned about Jan\u2019s life, work, and passing on the radio earlier this week. Jan sounded like a really lively, passionate, and sparkly person. If you\u2019ve never heard of her either, I\u2019d advise reading a little bit about her amazing escapades, and wondering how amazing it would have been to run into her at a pub.
  • +
  • Is Resilience Overrated? by Jami Attenberg for The New York Times. It can feel like we live in a culture which celebrates overwork and exhaustion. Attenberg talks about how \u201CYou\u2019re so resilient\u201D can be code for \u201CYou\u2019re on your own, sorry\u201D. It\u2019s not enough to acknowledge difficulty and admire those who go through it, but instead we should be doing what we can to reduce human suffering - which can, at times, involve us getting our own boots dirty.
`; +}); diff --git a/.netlify/server/chunks/2020-12-02-the-phoenix-project-3360233b.js b/.netlify/server/chunks/2020-12-02-the-phoenix-project-3360233b.js new file mode 100644 index 0000000..5eb93df --- /dev/null +++ b/.netlify/server/chunks/2020-12-02-the-phoenix-project-3360233b.js @@ -0,0 +1,62 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_12_02_the_phoenix_project, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Phoenix Project", + "author": "Gene Kim, Kevin Behr, and George Spafford", + "score": 4, + "image": "the-phoenix-project", + "slug": "the-phoenix-project", + "book_review": true, + "date": "2020-12-02T00:00:00.000Z", + "finished": "2020-11-29T00:00:00.000Z", + "draft": false, + "tags": ["non-fiction", "software"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Amazon", + "link": "https://www.amazon.co.uk/Phoenix-Project-DevOps-Helping-Business-ebook/dp/B00AZRBLHO" + } + ] +}; +const _2020_12_02_the_phoenix_project = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The Phoenix Project (TPP) is a a fiction book for nerds (said the nerd, on his blog). It\u2019s a parable for people who design, build, or deploy software. I want this article to just be about the book itself, not its content. The things I, as an engineer, found interesting about The Phoenix Project deserve their own post. Instead, this piece takes a more literary, or meta, look at The Phoenix Project.

+

TPP is set in Parts Unlimited, a (fictional) automobile parts manufacturing company in America. As a company, Parts Unlimited is carrying a great deal of technical debt and business pressures. So it\u2019s set in a very boring, but realistic, scenario - and follows some very boring (but interesting and important) discussions and events which transpire in the process of building software in Parts Unlimited.

+

TPP follows Bill, an middle-rung operations engineer - someone who is responsible for deploying software to become available to the end users (clients, stores, internal staff). Within the first chapter of the book, Bill is promoted from his comfortable job into a higher management role, which he does not want to take. The rest of the book follows Bill as he slowly realises just how bad the process of building and deploying software has gotten in his own company. The titular Project Phoenix is a long-overdue software product which the company planned and built for the last 12-24 months as a response to increased velocity from their competitors. Bill, with the help of his mysterious sensei (and potential board member) Erik, spends three hundred pages implementing solid working principles and protocols into Parts Unlimited, informed heavily by current manufacturing practices.

+

It\u2019s actually quite a hard book to explain. While The Phoenix Project is technically fiction, in that the people and places are made up, its goal is to explain a certain (very real) way of building software - and similarly to explain the consequences of other approaches. Where other books may be concerned with exploring relationships, ideas, or language - this one wants you to understand that you really need to be able to visualise work-in-progress in your engineering teams. It shows you how a lot of people in a business think about both their job in the business, and the job of the business to them.

+

Look, if you\u2019re a software person, this book has probably already crossed your radar. It\u2019s one of the cornerstones of modern Dev-Ops, at least in the last five years. It spawned a number of other influential books like The Dev Ops Handbook, The Unicorn Project, and The Three Ways. If you\u2019re not aware of this book, or what words like \u201CDev-Ops\u201D and \u201CSofware\u201D mean, then you probably stopped reading half way through the last paragraph (at the latest).

+

My immediate reaction after finishing this book is that there should be more books like it. It is a fantastic way to introduce people to the forces and constraints in building and managing modern software. If you\u2019re inside of the software bubble, it showcases the nature and scale of business and financial forces; if you\u2019re in on the business front it introduces you to the pressures and complexities that software people are under. If you\u2019re both (like a CTO or CIO) then it will help you think about ways that communication and information flows between IT and other parts of the business.

+

I build software for the web, an area famous for evolving quickly, for re-inventing the wheel with new technologies, and for being an engineer with a degree in an unrelated subject (like music production or\u2026 environmental science, for example), thick glasses, and a MacBook Pro. There\u2019s a certain culture, at least that I\u2019ve experienced, that engineers should always be on the professional development hype. I don\u2019t think this is unique to web developers, or even to software engineers, but I do know it\u2019s pretty prolific in my field. This can make it very easy to jump from one project, language, framework, or trend to the next - and never stop to consider what you\u2019re building or why. It can mean reading sparse documentation, or just forging ahead and ignoring existing documentation.

+

TPP brings a much more abstract level of thinking to the process of building software, and places both engineers and software within their wider contexts. Individuals are in teams, which are in departments, which are in businesses. Software projects are managed by teams, and linked to business objectives, etc. etc. TPP shows the value of thinking about these things, and introduces them without ever pointing them out.

+

A lot of these benefits are emphasised strongly because the book only gives you an overview of the specific technologies used. It becomes almost impossible to get lost in the weeds, the book keeps you firmly out of the garden. In fact, to continue this analogy, the book sits you down with the head grounds-keeper and makes you follow them around for a few months while they do their job. For engineers, especially those who are closer to the strategic or planning aspects (or who wish to progress there), this is a really good thing.

+

Engineering tends to attract people who are problem solvers, and a lot of the problems which are presented in TPP are large and fuzzy. For example: how does the business decide what software gets built? When can we say software is \u201Cdone\u201D or requirements have been met? How do you know who needs to be aware of your planned actions and changes to hardware (real or virtualised)?.

+

You could begin to optimise tiny parts of these specific questions, maybe increasing the efficiency or throughput by 5-10% on a single part; or you could examine the system as a whole. TPP encourages tackling these big questions, and doesn\u2019t assume that people will hear you say \u201Cwe would like to completely redesign this from the ground up\u201D, and the respond with \u201Csounds great, take all the money and time that you need\u201D. These decisions are messy, both personally and for the business.

+

Something that works really well in the parable format is the introduction of archetypes: certain kinds of personalities or a certain kinds of jobs. Our tiny chimp brains find these things useful for understanding other people. For example it\u2019s why I actually enjoy hearing people talk about the star signs, and it\u2019s why we have so much fun arguing who\u2019s a Carrie, Samantha, or Miranda . TPP introduces us to a relatively small (maybe 10 person) cast of people who work at a company. This is a good number: it\u2019s enough to focus on each of them, their personalities, and the way they contribute to (or block) other people. Hopefully it\u2019s enough to help the reader think, at some point, \u201CAh, this guy\u2019s a bit like Brent\u201D or \u201CAh, she\u2019s a Patty\u201D. This is a hugely useful generic human skill which we encourage in our personal lives, but which we often assume \u201Cyou\u2019ll learn it on the job\u201D when it comes to our working lives. This is a nice little helping hand, especially if you\u2019re newer in your career or come from a smaller or less diverse team.

+

While I have praised TPP for not being too technical, this does come at the cost of giving us a lot of names and phrases to Google if we want to actually learn the details. This is good though, it gives you the vocabulary to go away and google things that are relevant, and the chance to ignore things which aren\u2019t. It means you can read this book in several sitting and get a good overview, but also to dig deep into anything you find particularly interesting. To this end, TPP knows its role is more of a gentle introduction than a technical primer - it assumes you don\u2019t know anything, and that you may not even be able to diagnose, let alone solve, any of the technical problems. Luckily, that\u2019s largely irrelevant.

+

With all this said, the book certainly wasn\u2019t one that I simply couldn\u2019t put down. In parts it was tough to read. Notably some of the characters and interactions were a little too caricature-ish, and some of the sections invoked horrible flashbacks of people who knew nothing about software asking something impossible or telling you how to do something in a bad way. I had quite a visceral reaction to these sections, and from conversations / online reviews, I know I am not the only one. This speaks to the authors\u2019 experience in actual workplaces, and their ability to capture the practical difficulties that enterprises might be facing.

+

I\u2019ve also got some other questions, primary among them: why has everyone in this book served in the military? Bill, our protagonist, has. So has his boss. And so has his teacher. And so have a couple of other people he meets. Why are all these veterans working at this failing automobile parts manufacturing company? I guess that it\u2019s a good way to signal \u201Cget to know about your colleagues\u2019 lives before their current job\u201D, but also it could be seen as \u201Cassume everyone loves routine, command chains, and discipline\u201D (which they don\u2019t).

+

Perhaps a more serious critique would be to ask why this book adopts the mystery-thriller literary practice of leaving us out of problem solving. There are plenty of \u201CI screwed my eyes tight and thought about it, I was so close to solving it\u201D and \u201CHe was almost onto something\u201D. It felt a little staged, but also I guess you need something to stop this book descending into some kind of technical swamp.

+

All in all, The Phoenix Project is a good book, mainly because it knew what it wants to be: an introduction to modern IT practices in an enterprise setting for anyone remotely involved in IT within a business. It\u2019s not got stunning language, considered character work, or a suspenseful plot - but it has a lot of clarity and charm. If you work in software, especially in a position where you can affect change, I would really recommend picking this up and reading it the whole way through - there\u2019s a very high chance that you\u2019ll find something useful to you. 4\u2B50

`; +}); diff --git a/.netlify/server/chunks/2020-12-05-things-i-learned-17-93c9716b.js b/.netlify/server/chunks/2020-12-05-things-i-learned-17-93c9716b.js new file mode 100644 index 0000000..7815c94 --- /dev/null +++ b/.netlify/server/chunks/2020-12-05-things-i-learned-17-93c9716b.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_12_05_things_i_learned_17, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #17", + "author": "Thomas Wilson", + "date": "2020-12-05T00:00:00.000Z", + "draft": false, + "slug": "2020-12-05-things-i-learned-17", + "tags": ["things-i-learned"] +}; +const _2020_12_05_things_i_learned_17 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

It\u2019s time of year again: Spotify have released their Rewind - showing you what you listened to throughout this year. After the year (or decade, or complete non-year, whatever helps you) that 2020 has been, I think a lot of people have looked to music for a bit of refuge, or good news, or distraction. Go and check yours out, it\u2019s a cool little use of data, presented in a really nice way. In other news, the UK has approved the Pfizer/BioNTech vaccine, and the first people should receive their doses in the next couple of weeks. Things are starting to look up, we may be over the hump of this.

+
  • These Different Ingredients: I remain a staunch defender of the Brussels Sprout. They\u2019re a seasonal, nutritional, deeply flavoured winter ingredient that goes beautifully fried in butter with garlic, baked in roast tins, or as part of any winter curry. They get a bad wrap, but there\u2019s a chance that even over the last 5-20 years we\u2019ve bred our sprouts to have different (e.g. stronger, or less bitter) flavour profiles than we had before. So the sprouts that gave a bad name to their brethren may no longer be around. Go on - give them a go. (source)
  • +
  • These COVID-affected Amazon Reviews: One of the symptoms of COVID-19 is a loss of smell and taste. One consequence of this, especially in the US which is handling this pandemic quite badly, is that people can\u2019t smell their scented candles. This is causing an increase in low-scored reviews of scented candles on Amazon, with more people mentioning that the candle has no scent. Whereas, in reality, people could be losing their sense of smell but not recognising it as a COVID symptom. (source)
  • +
  • These Best Mince Pies: Over the past couple of years I\u2019ve become increasingly aware of the competitive, and critically important, world of Mince Pie judging. Mince pies taste of Christmas, and I\u2019m personally a fan of having them hot (though I\u2019ll have a cold pie if the mood takes me). The real question we want to answer every year, though, is \u201Cwhich supermarket does the best mince pie?\u201C. Well, this year ASDA and Iceland are both leading the charge for both quality and value for money. Avoid Sainsbury\u2019s, though - they\u2019re not great and overpriced. (source)
  • +
  • This Cartoon Trivia: You know how, in Disney\u2019s 1991 Beauty and the Beast his castle is oddly full of weird grotesque sculptures? Like, inside and out? Anyway, a lot of those sculptures are actually based off of previous concepts for Beast that the animators and artists created before arriving on how he would actually look. (source)
  • +
  • This Origin Story: Fun fact: snow globes are man-made, they don\u2019t just grow in the wild. I mean, I didn\u2019t think they grew on trees but I can imagine that someone would. Again, that someone definitely wouldn\u2019t be me. Snow globes were invented in Austria in 1900 by Erwin Perzy, a medical repair man who was trying to invent a brighter light, for use in medical settings. He experimented with water-filled bulbs, in the hope that maybe if he filled it was water and a reflective material - more light would be reflected in the operating theatre. What he actually stumbled on was something that resembled snow, and so he gave up all hope of helping the medical profession and started selling gimmicks.
+

What I\u2019ve had on rotation

+
  • Something New: in Florescence (EP) by half\u2022alive (Indie). This little EP is four orchestrated versions of some of half\u2022alive\u2019s previous songs - and it\u2019s really great. It\u2019s light and magical, the vocals really shine through, and the original tone of the pieces is still there. (links)
  • +
  • Something Old: Yesterday\u2019s Gone by Loyle Carner (Hip Hop). I\u2019ve been really getting into Carner\u2019s music over the past couple of months - his unique mix of British and American influence is pleasing to me. He\u2019s right on the lyrical, poetic, and melodic end of hip hop, and this whole album strikes as very true to himself and his upbringing. His mum has a track on the album, which is just so great. (links)
+

Cool articles

+
  • Why Religion Is Not Going Away and Science Will Not Destroy It by Peter Harrison for Aeon. This is an interesting piece which looks at how a fanatical belief, in either secularism or religious-ideals, are not conducive to finding a middle ground. Instead they can lead to further conflict and bad-opt
  • +
  • The UK has approved a COVID vaccine \u2014 here\u2019s what scientists now want to know by Heidi Ledford, David Cyranoski, and Richard Van Noorden for Nature. The past month has been abundant with really great vaccine news for COVID-19. This is a massive step towards getting us closer to our pre-2020 lives. There\u2019s a still a lot we\u2019re uncertain of with the vaccines, like if people can still transmit the disease if they have been vaccinated; how long do people remain immune for?; or exactly effective are they in certain demographics (primarily age and gender)?
`; +}); diff --git a/.netlify/server/chunks/2020-12-10-things-i-learned-18-a1af1eed.js b/.netlify/server/chunks/2020-12-10-things-i-learned-18-a1af1eed.js new file mode 100644 index 0000000..c458099 --- /dev/null +++ b/.netlify/server/chunks/2020-12-10-things-i-learned-18-a1af1eed.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_12_10_things_i_learned_18, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #18", + "author": "Thomas Wilson", + "date": "2020-12-11T00:00:00.000Z", + "draft": false, + "slug": "2020-12-11-things-i-learned-18", + "tags": ["things-i-learned"] +}; +const _2020_12_10_things_i_learned_18 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I took a four day week last week, so managed to spend this week with all the energy that only a 3-day weekend can give you. That said, I\u2019ve found myself incredibly busy this week. This is the first evening (Thursday) where I\u2019ve managed to find some time to myself without something pressing. Lockdown continues, Brexit talks and COVID vaccine are competing for media attention, but also I bought two (2!) new types of coffee beans this week sooooo.

+
  • This fitness advice: Now that it\u2019s winter (and also a lockdown), I have to make my yearly switch from cycling to running as my primary form of cardio exercise. I\u2019ve been looking into training advice to make sure that I don\u2019t ruin my body in the long term, and I came across the following rules-of-thum: if you run, aim for less than 20 miles a week, run 3-4 times a week, and stay below 8mph (~13km/hr). (source)
  • +
  • This cat fact: Cats purr for a number of reasons, not just when they\u2019re happy and content. Some people have made the argument that the kitty vibrations can help heal them, or strengthen their bones. This is perhaps why cats typically seem to be fine with jumping (but never falling, ever) off of high things. They also purr to comfort themselves if they\u2019re feeling stressed, which is 10/10 adorable. I can relate strongly to the second of these two purposes, I grew up with an incredibly loud purring cat waaaay before the ASMR trend came to light. (source)
  • +
  • This Tweet: \u201CYou eat sausages your whole life but you refuse vaccine because you don\u2019t know what\u2019s in it.\u201D It\u2019s not really a thing I learned but I love the drama. (@julianpopov)
  • +
  • This early herbal pioneer: Elizabeth Blackwell lived in Scotland during the early 18th century. In 1737 she published A Curious Herbal: Containing Five Hundred Cuts of the Most Useful Plants Which Are Now Used in the Practice of Pyysick - perhaps not the most catchy title. But it contained 500-some full-colour paintings of local plants used in medicine, at a time before we had even begun to categorise plants thoroughly. Blackwell produced each of these drawings while taking care of her young child, while her husband was locked up for money he owed his debtors. The images are striking and classically beautiful, but also gave information for each plant\u2019s medical use (source)
  • +
  • This bardic AI: Deep-speare is an AI trained to write sonnets, a la actual Shakespeare. The researchers fed a deep-learning algorithm nearly 3,000 sonnets and then asked it to write its own. Unsurprisingly, the algorithm was able to spot (and reproduce) the structural patterns in a sonnet (14 lines, the rhyming patterns), but it was also able to pick up on the syntactic and language itself: posing problems, comparisons to nature, the rhythm of writing. Take the following example of a quatrain (four-line section): shall i behold him in his cloudy state; for just but tempteth me to stop and pray; a cry: if it will drag me, find no way; from pardon to him, who will stand and wait. It\u2019s oddly poetic but maybe a little abstract. This all came before the more recent GPT-3, which has produced consistent, intelligible, long-form writing in the past few months. (source)
+

What I\u2019ve had on Rotation

+
  • Something New Something to Feel Good About by Will Joseph Cook (Pop, 2020). Spotify decided to pass this album to me last week and it\u2019s cute. It\u2019s very cute. (links)
  • +
  • Something Old: Backbone by Roam (Pop Punk, 2016). I remember this album coming out and playing it (responsibly) loud on the speakers in my car as I was driving around. It\u2019s got great teenage summer energy. (links)
+

Cool Articles

+
  • Here comes the COVID-19 Baby Bust. COVID-19\u2019s had a couple of effects on family life, with a lot of couples making big decisions about marriage/divorce and children/no-children. This piece takes a look at the likely dip in birth of (American) babies, and how we might expect to see that self-correct over the next couple of years.
  • +
  • Real Talk: Behind the Music with 99pi Composer Seal Real & Her New Album. If you don\u2019t listen to the 99 Percent Invisible podcast, you should. If you do, then you probably know how beautiful the soundtrack is, and how well it fits the story and pacing of the piece. This piece shines a light on Sean Real, 99PI\u2019s composer, and their process of creating, and recently releasing, music.
`; +}); diff --git a/.netlify/server/chunks/2020-12-13-kings-of-the-wyld-75a05e60.js b/.netlify/server/chunks/2020-12-13-kings-of-the-wyld-75a05e60.js new file mode 100644 index 0000000..9585ea8 --- /dev/null +++ b/.netlify/server/chunks/2020-12-13-kings-of-the-wyld-75a05e60.js @@ -0,0 +1,61 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_12_13_kings_of_the_wyld, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Kings of the Wyld", + "author": "Nicholas Eames", + "score": 3.5, + "image": "kings-of-the-wyld", + "slug": "kings-of-the-wyld", + "book_review": true, + "date": "2020-12-13T00:00:00.000Z", + "finished": "2020-11-15T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "fantasy"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Nicholas-Eames/Kings-of-the-Wyld--The-Band-Book-One/20475980" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/kings-of-the-wyld/9780316362474" + } + ] +}; +const _2020_12_13_kings_of_the_wyld = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Kings of the Wyld is a fantasy book which feels like three or four middle (or-upper middle) aged dudes getting drunk, playing Dungeons & Dragons, while classic Rock and Roll plays in the background. In a fantasy world where adventurers are treated like rockstars, the book follows an old band of adventures getting together for one last hurrah to save one of their daughters. The book knows what it is, and doesn\u2019t try to overreach itself. But at the same time, it does a solid job of portraying personal trauma and the process of ageing. If you like fantasy, and are familiar with the tropes, I highly recommend this book as a fun, and slightly meta, piece of fantasy. If you\u2019re less familiar with the genre, you\u2019ll likely still enjoy it, but realise there are some in-jokes or puns passing you by.

+

The book is set in a fairly standard high fantasy setting - with the most notable geographic feature being The Heartwyld: an expanse of untamed forest and planes which are overrun by your standard fantasy monsters: centaurs, giant spiders, dragons, zombies, trolls\u2026 you get the idea. Though humanity was once terrorised by these creatures, humans have increasingly started killing them for sport and entertainment. Bands of adventures start to emerge, killing larger and greater numbers of beasts, before the sport is moved to giant Colosseum-like arenas. These bands of adventurers are treated just like the celebrities in our not-so-monster-ridden world.

+

The premise of the book is relatively simple: the daughter of Gabe, the band\u2019s frontman, is stuck in a besieged town on the other side of the Heartwyld. He gathers the old band, Saga, back together for One Last Adventure to get her back. Saga was once the greatest band of all time, but since then the members have retired to a quieter, provincial way of life. Bringing them out of retirement sounds like a good narrative, but Kings is pretty honest about showing us how much the group really have aged, and how they\u2019re not the spritely young men they once were.

+

We spend the book following Clay, Gabe, Moog, Matrick, and Ganelon - the members of Saga, as they trek across the map to save Gabe\u2019s daughter.

+

Kings of the Wyld brings a relatively unique (at least to me) perspective: that of older or retired adventurers. We come into the story once they\u2019re well past their glory days and once friendships have been formed. This allows the book to step back from the immediate, arguably senseless, violence that we would expect on a traditional Great Adventure fantasy trope, and have a more honest, if not flawed, look at the people and actions involved.

+

We\u2019re also introduced to a broad range of supporting characters: a new band of lovable rogues led by a charismatic archer, the band\u2019s old booking agent who\u2019s grown (even more) selfish and greedy, a two faced bounty hunter, a gold-loving cobalt. These all seem like familiar stereotypes, but they bring the world to life - the book doesn\u2019t focus solely on the members of Saga, and it feels like Saga really lived out their greatest day and then the world moved on past them. Somehow all the tropes and archetypes fit really nicely, and it never feels clich\xE9. Tongue in cheek? Yeah, but it treads a nice line.

+

The plot of Kings follows a similar pattern - although there\u2019s nothing particularly complex, unforeseen, or politically/socially astute contained within it - Eames builds a really interesting set of cultures, characters, and creatures. You\u2019re taken on a tour across a massive space, travelling in giant air ships, trudging through snow, burning down bars. It\u2019s really quite the adventure. You never hang around anywhere too long to get bored.

+

Not every book has to ask you to rethink the role of religion in society, or the nature of destiny and duty. Some fantasy books can just be a good romp with some realistic characters. Humans are empathetic creatures, and as a reader before long you start thinking about the characters, and their feelings or situations, even if they are ridiculous. Eames sneaks in some real emotional moments underneath the adventure, and that kind of tonal shift is the mark of a good storyteller.

+

Both pacing and language are only as long as they need to be, Eames has no issues with moving you on, even if you\u2019d maybe like to hang around for a few more pages to see what kind of insanity could ensue.

+

A lot of reviews I read for this book seemed to rate and note the humour in Kings - but I\u2019ve got to stay, I didn\u2019t find it especially funny. There are moments of levity or little puns, but for the most part it shows a pretty grim and unflattering world, every now and again poking fun at the fantasy and rock-and-role genres. I liked this decision, it made a nice change, especially as Eames didn\u2019t play up the meta-jokes about fantasy tropes so much, and I don\u2019t think he ever broke the fourth wall, which I was worried he might do. It was enjoyable but far from the Pratchett standard, but I don\u2019t think comparing anyone against that would be a good idea.

+

This book didn\u2019t bowl me over with anything unexpected, but it was a fun journey with an interesting twist, even if the premise itself is overcooked. It\u2019s a good escapist read if you know you\u2019re a fan of fantasy, but I don\u2019t know if I\u2019d recommend it if you\u2019ve not dipped into the genre for a while - or maybe I would, maybe it\u2019s the perfect re-introduction. I don\u2019t know, I\u2019m not very stedfast in my opinions. 3.5\u2B50

`; +}); diff --git a/.netlify/server/chunks/2020-12-18-things-i-learned-19-b5e2eca1.js b/.netlify/server/chunks/2020-12-18-things-i-learned-19-b5e2eca1.js new file mode 100644 index 0000000..ac589ab --- /dev/null +++ b/.netlify/server/chunks/2020-12-18-things-i-learned-19-b5e2eca1.js @@ -0,0 +1,45 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_12_18_things_i_learned_19, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #19", + "author": "Thomas Wilson", + "date": "2020-12-18T00:00:00.000Z", + "draft": false, + "slug": "2020-12-18-things-i-learned-19", + "tags": ["things-i-learned"] +}; +const _2020_12_18_things_i_learned_19 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • All of these species named after David Attenborough: The man\u2019s a living legend (he\u2019s also like 94 - he was a teenager in the 1930s which was before the second world war - this isn\u2019t the fact by the way, this is just some incredible side-facts). The collective scientific community has named over 20 species of animals and plants after him, including Attenborosaurus - the marine dinosaur, Pristimantis attenborough - a Peruvian frog, and Acisoma attenboroughi - a dragonfly. (source)
  • +
  • This naval rule: I recently came into some Navy Strength gin (60% lol), and I wondered why something would be called Navy Strength. It turns out that The Royal Navy used to require a certain amount of gin on board, to give out in rations to their sailors. This went on until the mid 20th century, by the way. To make sure that the gin was strong enough, they used to burn it to make sure it had a high enough (and pure enough) alcohol content. (source)
  • +
  • These tiny drivers: In a study to look at how an enriched environment can improve the ability of rats to learn and acquire new skills, some researchers at the University of Richmond TAUGHT SOME RATS TO DRIVE. Yes, they built tiny little cars for them, and encouraged them to drive towards treats. Yes, that\u2019s right, these tiny bastards got to drive adorable tiny cars and got treats. Ugh, what a life they\u2019re living. Unsurprisingly, the researchers found that rats who lived in a more social and enriched environment learned to drive much quicker than those kept in smaller numbers in bare cages. Check out the video in the linked article to watch tiny animals drive tiny cars. (source)
  • +
  • This early cultivated food: I thought that the first crops we started cultivating and harvesting, about 10,000 years ago, were grains/grasses like wheat. However, maybe 1,000-1,500 years before that we were selectively breeding and harvesting figs, so they may have been one of the first plants humans looked at and thought: \u201CThat\u2019s delicious, and I bet I can improve that\u201D. (source)
  • +
  • This way that we actually learn programming: A lot of people who do software engineering have drawn parallels learning a programming language and human languages, maths, and music. I\u2019ve always been a little skeptical of these analogies - the foundations of recognising rules and patterns aren\u2019t unique to software engineering, they\u2019re generic problem solving skills, and language acquisition is like\u2026 a whole thing. Recently, some people at MIT took some programmers, put them in an FMRI machine and showed them snippets of code and asked them to predict the output of the code, in order to examine which parts of their brains were involved in the processing of the information. The study found that parsing the code activated the multiple demand network - a cross-cortex region of the brain involved in many processes, and not specialised especially to language or mathematics. As a result, learning code isn\u2019t exactly like learning maths or a language, and while we can maybe draw generalities in the way we teach it, we shouldn\u2019t be dogmatic about it. (source)
+

What I\u2019ve had on Rotation

+
  • Something New: evermore by Taylor Swift (Singer Songwriter). Taylor dropped her second album of 2020 last week, which is good. Law of averages says that we have to have something good come from this year. This is a sister album to folklore, which she dropped over summer. The production quality, lyricism, and collaboration on this albums bring it true to her country/folk roots - it\u2019s earnest and true, but knows when to be tongue in cheek or when to crack a wry smile. While nothing will ever replace Red in my heart, evermore is genuinely a fantastic album that surprised me with how much I loved it. (links)
  • +
  • Something Old: Cole World: The Sideline Story by J. Cole (Hip Hop, 2011). Y\u2019all know I love hip hop, and when your favourite rappers call out J. Cole as one of their favourites, you know he\u2019s worth a listen. I\u2019ve been diving deep into his older, early albums this year. Cole World has jazz keys, samples, and lyrical hooks everywhere, but it also starts to bring in some of the more electronic/synth elements that are more familiar to modern Cole and hip hop in general. I can see entirely why he\u2019s rated by other rappers: he\u2019s good, he\u2019s sharp, and he\u2019s versatile. (links)
+

Cool Articles

+
  • The New Relationships That Fizzled Out in Quarantine by Ashley Fetters for The Atlantic. The COVID-19 pandemic has been a wild, wild time for anyone single and dating. My experience as a young metropolitan who, pre-pandemic, was in the dating scene is that a lot of people would go on a lot of dates with a lot of other people. A lot of the guidelines and laws around social distancing seem to ignore anyone who\u2019s not cohabiting with their partner, and I\u2019ve seen and heard of people feeling as though they\u2019ve completely lost a year of their dating life. People in pre-existing relationships have had to go through a whole other set of problems. As someone rapidly approaching 30, this isn\u2019t necessarily a year in dating that I feel I could lose easily. I think this situation is going to bring about a very particular set of personal and romantic issues in the next 24 months as people re-start dating. Fetters does a great job of bringing some case studies to light around this, from earlier in the pandemic, as dating changed suddenly and rapidly.
  • +
  • Zoom and Gloom by Nigel Warburton for Aeon. I\u2019ve heard a lot of people declaring how 2020 has shown all of us how unnecessary the office is, or conversely how completely irreplaceable the office is. At the same time, we\u2019re learning how the tools we have in place for remote work are largely inadequate. Something has to give here. In this piece, Warburton looks at the need to design tools which place human empathy above all else, especially in a time where we\u2019ve suddenly pushed pretty much all video-conferencing tools to their natural limits. This is a great reminder that things don\u2019t have to be the way they are, and that, although I think we need a blend of online and in-person work time, we shouldn\u2019t write off either type of experience given what we\u2019ve all gone through this year.
`; +}); diff --git a/.netlify/server/chunks/2020-12-20-how-are-we-going-to-write-about-this-d65432ee.js b/.netlify/server/chunks/2020-12-20-how-are-we-going-to-write-about-this-d65432ee.js new file mode 100644 index 0000000..6745134 --- /dev/null +++ b/.netlify/server/chunks/2020-12-20-how-are-we-going-to-write-about-this-d65432ee.js @@ -0,0 +1,55 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_12_20_how_are_we_going_to_write_about_this, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "How are we going to write about 2020 from 2022 onwards?", + "author": "Thomas Wilson", + "date": "2020-12-20T00:00:00.000Z", + "draft": false, + "slug": "2020-12-20-how-are-we-going-to-write-about-2020", + "tags": ["essay", "2020"] +}; +const _2020_12_20_how_are_we_going_to_write_about_this = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

2020 has been a terrible year in so, so many ways for so, so many people. At the very least, the Covid-19 pandemic has stolen a year from us all. I would say most of us have gone through a personal and collective trauma this year.

+

I do not believe this year will be a turning point for us as a society. I don\u2019t think this will be the moment people stopped flying transatlantic for a 2pm lunch meeting in LA. In 2025 people in offices are going to be just as much a victim of presenteeism as they are now. We\u2019re not going to value our independent artists or our local pubs any more, we\u2019re going to frequent franchises and chains. We\u2019re not going to pay healthcare staff more and politicians less. We\u2019re not going to have a meritocracy in government and purely data-led policy. We\u2019re not going to learn all the lessons we need to learn to stop anything like this from ever happening again - because our collective memory is short, and because our minds are excellent at rationalising our actions to ourselves.

+

I do believe that this is going to be a cornerstone in the life of everyone over the age of 14. This will be a comparison point for every freedom of movement we make, even if it\u2019s a fleeting memory as we board a plane or check into a hotel in 2050. We will remember the impact of distance in our relationships, and recognise the luxury of being inattentive to them. We will justify ordering aperitifs and dessert at restaurants. We will remember not being able to leave the house before we bid on a house with barely a fist full of dirt, or which is distant form our loved ones. We will consider it as we walk home, head-fizzy-drunk, from a friend\u2019s dinner party. The muscle memory in our hands and fingers will surface countless washings after getting home from any shop.

+

As individuals we are going to remember this year, and a culture we are going to try and move on from it.

+

How are we going to write about, and talk about this year in 2022?

+

Other than the inevitable trend of clinical and popular postmortems and retrospectives; of memoir from political and healthcare staff; in coded language from press-releases (due to the global health situation) - how do we relay what this year is and has been? Are we going to want to pretend it never happened, or will it crop up in books, plays, music, movies, or series? Will it be examined, blamed or credited, or will it become kind of harmless shorthand which takes the sting out of the year?

+

What are the analogies and comparisons you can draw on to explain this year? I have never experienced anything so physically and mentally stifling. There is no analogy for the drawn out uncertainty, the frustration, and the limited personal freedom, the conjuring of temporary hope and imagined futures almost solely to get us through a now which extends certainly backwards and hazily forwards.

+

I think I\u2019m leaving the year stronger than I came into it, but there was a real dip in the middle there where things could have gone either way. Despite being better off, there is space left in my life from the friends and family I haven\u2019t seen in a year, by the art I haven\u2019t witnessed, the meals I haven\u2019t eaten, the texts I haven\u2019t artfully crafted or \u201Caccidentally\u201D ignored, the wine I haven\u2019t drunk, the music I haven\u2019t heard crammed into tiny spaces with bustling strangers and distorted speakers, the sunsets I haven\u2019t seen, the taxis I didn\u2019t take, the impulse purchases I didn\u2019t make, the hands I didn\u2019t shake and the embraces I missed.

+

If you\u2019re lucky, the horrific scenes of crammed hospitals, overflowing wards, and people dying alone were fed to us through the screen or told to us by others. If we are not, we have lived them, or love someone who has lived them.

+

I have lost no one I know and I have managed to find and maintain fulfilling employment. I have been lucky, but I mourn the passing of this year from my life in a way that I don\u2019t know how to vocalise. I do not think I have regressed as a whole, but parts of my life have.

+

Doesn\u2019t every mental struggle feel like this, though? As though it could not be pinned down and showcased in words? In my experience, the feeling of being in a storm and then describing it afterwards are two very different skills. Once you\u2019re far enough way from something you can see the shape of it, its limits and reaches, with more clarity.

+

I can\u2019t do that for 2020 yet. I can\u2019t write a eulogy for this year which I desperately want buried and refunded. I am too close, and the loss feels too fresh and not yet finished - it is December 2020 as I write this and I know more will be taken from me, and more still demanded.

+

How long will it take for us to feel finally, firmly, like we can judge our vantage point far away enough to have some kind of valid, or at least semi-unused, criticism? Something other than a reaction.

+

I feel as though maybe in the last two or three weeks we have broken the back of the Covid pandemic. With three vaccines approaching, or already reaching, approval.

+

But perhaps the thing I have had to learn, and have seen us all trying to learn, over and again from this year is how little we can grasp time, or how poor we are at understanding and processing problems of this scale. That\u2019s not to speak of the people who make no allowance for the collective good, only for hedonistic and short-term impulses.

+

How often we have been six weeks away form this all being over? How the creation, approval, distribution, administration of a vaccine will solve anything - when in truth each is a herculean effort of knowledge, logistics, and finances. The world is going to have to produce billions of doses of vaccines. Billions. Each of which as to get into a person\u2019s bloodstream, and administered during a pandemic.

+

This year has felt entirely like waiting just that little bit longer. Like hanging on until the daily deaths and cases get below a set limit. Like things aren\u2019t good now, but we\u2019ll accept it because they will be.

+

How are we going to write about that feeling and that uncertainty? How can words do justice to successive realisations that both the problem and the solutions are so much more complicated than anyone was saying - because nobody wanted to be the one to say them, to reduce the substance of our hopes.

+

This has been a year of loss and trauma. We don\u2019t understand the full limit of either of those things, and how are we going to talk about it afterwards? Because there will be an afterwards.

+

How long will it take for these things to seep into our cultural and personal narratives? And how will we, in the future, draw from them? Will they become like war poems we read once a year, and become synonymous with charities and remembrance services? Or will they become briefly loved and adopted as a way for us to make sense, or something good, from all this?

+

I am very interested in how future us will write about this once it\u2019s passed.

`; +}); diff --git a/.netlify/server/chunks/2020-12-27-things-i-learned-20-deca546e.js b/.netlify/server/chunks/2020-12-27-things-i-learned-20-deca546e.js new file mode 100644 index 0000000..6ad3778 --- /dev/null +++ b/.netlify/server/chunks/2020-12-27-things-i-learned-20-deca546e.js @@ -0,0 +1,39 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2020_12_27_things_i_learned_20, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #20", + "author": "Thomas Wilson", + "date": "2020-12-27T00:00:00.000Z", + "draft": false, + "slug": "2020-12-27-things-i-learned-20", + "tags": ["things-i-learned"] +}; +const _2020_12_27_things_i_learned_20 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

This week\u2019s post comes a little lighter, on account of it being Christmas and all. I didn\u2019t want to break a streak, but also I want to get back to eating far too much and doing far too little. So let\u2019s get on with it:

+
  • This etymology: The word apocalypse comes from the Greek apokaluptein: to uncover, or reveal. This original meaning got adopted in bible translations in the context of revelations - which makes sense. Something have been revealed or uncovered. However, most of the revelations in the bible aren\u2019t\u2026 great news? So it started taking on a more negative, destructive tone. (source)
  • +
  • These first festive TV advert: Having a heart-warming, mini-movie of a Christmas advert has become a staple in the past decade. My personal favourite is the animated woodland scene and accompanying Lily Allen soundtrack for John Lewis is 2013. One of the pioneers of the British TV Christmas advert was OXO, the famous broth/gravy company, here\u2019s their 1984 advert, in which our child protagonist tells of her \u201Cmost wonderful Christmas ever\u201D. From across the pond, Coca Cola\u2019s 1995 Holidays are Coming TV Ad has now reached meme status, becoming synonymous with the festive season itself. From 2007, John Lewis started a trend of high production, narrative-driven adverts which I\u2019m honestly really glad we have. (source)
  • +
  • This most popular nut: What do you think the most popular nut of Victorian England was? My gut reaction was peanut, all the other nuts seem a little too fancy or exotic for wide consumption. However it turns out that chestnuts were the most popular nut in Victorian England. So there\u2019s a nice bit of trivia for you, and also it\u2019s roughly festive themed. (source)
  • +
  • This science of snowballs: You know how some snow makes excellent, compact snowballs which are perfect for throwing, but some is either a fine powder or ice which can\u2019t be thrown for love or money? It turns out that the underlying physics behind snowballs relies on the pressure of you compacting the snow together, with your delightfully mitten\u2019d hands, allowing some of the snow inside the snowball to melt back to liquid water. Then when you stop compacting the snow, the lower pressure forces the water to refreeze into ice, and it acts like a cement or a glue to hold all the snow together. When it\u2019s too cold (and powdery snow), the pressure from your hands isn\u2019t enough to melt the snow, and if it\u2019s too warm then the. (source)
`; +}); diff --git a/.netlify/server/chunks/2021-01-01-things-i-learned-21-a5c9e4ef.js b/.netlify/server/chunks/2021-01-01-things-i-learned-21-a5c9e4ef.js new file mode 100644 index 0000000..fbcc796 --- /dev/null +++ b/.netlify/server/chunks/2021-01-01-things-i-learned-21-a5c9e4ef.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_01_things_i_learned_21, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #21", + "author": "Thomas Wilson", + "date": "2021-01-01T00:00:00.000Z", + "draft": false, + "slug": "2021-01-01-things-i-learned-21", + "tags": ["things-i-learned"] +}; +const _2021_01_01_things_i_learned_21 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Happy New Year \u{1F38A}\u{1F973}\u{1F37E} It\u2019s been one hell of a ride, 2020, and I hope that I never know another year like you. This has been quite enough. We\u2019re at least six months from being slightly out of the woods, but we\u2019ve made it through nine-to-twelve (depending on where you live) months of surprise pandemic. We can make it through another six. I don\u2019t care that 365 days or a rotation around the sun is arbitrary. Money is arbitrary and so is language and art - let it be arbitrary but celebrate. I hope your festivities were socially responsible, and served you. I hope your 2021 is better, and I hope we see in 2022 surrounded by people, live music, fireworks, champagne, and a general hustle and bustle.

+
  • These good boys: Across the world, several dog trainers and medical researchers have been trying to train sniffer dogs to identify people who are positive for Covid-19. One of the big problems with this disease is asymptomatic carriers who may unwillingly infect others without knowing. Having dogs who can sniff-out people who may be positive, especially in high-touch areas like airports or event venues, is a great tool. It\u2019s also pretty cool that a) there\u2019s a reliable Covid-19 smell, and b) dogs can identify it. This research is still in the early stages, but it\u2019s arguably looking promising, even if we\u2019re not quite sure what the dogs are sniffing out, exactly. (source)
  • +
  • This version of the English Language: E Prime is a version of language without the verb to be. Proposed by D. David Bourland, Jr. in 1965, Bourland believed that people rely too much on to be in English writing and that it weakens the impact or strength of a statement, or distracts the reader from the subject. The infamous non-apology \u201Cmistakes were made\u201D, for example, would simply not do. It was also an attempt to stop us comparing things that aren\u2019t comparable - for example can a candle be burning, or does the candle burn? Look, it\u2019s wild idea that would never take off, but it\u2019s a nice smell to look for in your writing. Try and be more conscious when you\u2019re writing things (source)
  • +
  • This Railway Dog: In late 1800s, Bob the Railway Dog, was adopted by the South Australian railway community at large. Conductors would let him hop up into the front of a train, where he would travel thousands of miles around the country. This lifestyle was a little dangerous for a small dog (as it would be for any human) and during this time he fell off trains, had his coat catch fire, and almost got caught under several moving carriages. (source)
  • +
  • These letters from Santa: For twenty three years, up until 1943, JRR Tolkien wrote Letters from Father Christmas to his children. The letters feature a broad cast of characters, including his elf (naturally) secretary, and Polar Bear, a polar bear (naturally), who just keeps getting into mischief. The letters have Father Christmas chronicling some of his (mis)adventures around the North Pole. (source)
+

What I\u2019ve had on rotation

+
  • Something New: Be Slow by Harrison Storm (EP, acoustic singer-songwriter). The last week of a year always feels like a little bit of a blur. In 2020, the preceding nine months have also felt a little slippery. Storm\u2019s five song EP contains the right mix of chilled and comforting songs for this time of year. (links)
  • +
  • Something Old: Sign No More by Mumford and Sons (Folk). This album is very good, though maybe a little overplayed in the early 2010s. Some distance has done it wonders, as has nine months apart from rowdy crowds. The lovely harmonies and chaotic instrumentals are delightfully timeless. Would recommend a re-listen. (links)
+

Cool reads

+ +

Fun things

+
  • 2020 Ipsum. You\u2019ve heard of Lorem Ipsum, the placeholder Latin-looking text that you use as dummy text in design? This is that, but instead of Latin-esque words, it\u2019s 2020 buzzwords that are kind of like a stream of consciousness from a\u2026 year.
`; +}); diff --git a/.netlify/server/chunks/2021-01-02-yearly-theme-2021-03a7be39.js b/.netlify/server/chunks/2021-01-02-yearly-theme-2021-03a7be39.js new file mode 100644 index 0000000..4d97607 --- /dev/null +++ b/.netlify/server/chunks/2021-01-02-yearly-theme-2021-03a7be39.js @@ -0,0 +1,66 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_02_yearly_theme_2021, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "2021 Theme: The Year of Discourse", + "author": "Thomas Wilson", + "date": "2021-01-02T00:00:00.000Z", + "draft": false, + "slug": "2021-01-02-yearly-theme-2021", + "tags": ["2021"] +}; +const _2021_01_02_yearly_theme_2021 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Resolutions are dumb. They\u2019re unsustainable and you can fail at them. Humans are just awful at long-term behaviour or thought-pattern change. Instead, I like themes: broad ideas that only try to guide you, not dictate. They\u2019re not a single thing, they\u2019re like a north star, or a prompt for conversation and reflection when you pause for it. CGP Grey condensed his thoughts on them into a neat little six-minute video. If you\u2019re more into it, or like podcasts, here\u2019s an episode of Cortex to listen to.

+

A brief eulogy for 2020

+

Coming into 2020 I was hopeful. It was going to be the Year of Making Space, where I was going to trim away as many of the routines and commitments I had put myself in, to see what would happen. To see where my brain would go with this new time and opportunity.

+

I had handed in my notice at a job I liked but didn\u2019t love any more, I was going to go freelance for a little while, and I was going to use this as a chance to find the things that I loved. I was in a contemporary dance company and we were actively producing a piece to be performed in May. I had the entire of February off, for a proper rest. I was maybe thinking about planning another long-distance cycle tour, after getting (most of the way) across France last year.

+

I\u2019ll save the quips and the suspense - none of those things happened.

+

2020 pt.2: Year of Survival

+

Between March and April of 2020 there was a bloodbath. It\u2019s a vivid and morbid word to use. People were dying, and we were all scared. Large parts of the economy went into free-fall. Budgets were cut, people let go, customers canceled orders and subscriptions. Nothing felt safe or exempt. It was every person and every company trying to figure out how, or if, they could survive for the next one-to-six months. It was a bloodbath.

+

It was a bad time to be the newest freelancer on a team. I don\u2019t want to talk about the specifics of the lessons I learned during this time, but I would summarise them as \u201Cgood to know, but over-priced\u201D.

+

My burning mental image from this year is one of trying very hard to keep my head above the water. It turned into the Year of Survival. I had to draw a card then play it immediately, and I\u2019m grateful that I made it through.

+

Things eventually worked out, as they are want to do. I found employment at a company with a great team and vision, I moved house, I got a haircut, I did a lot of Zoom Happy Hours, made bread, and I neglected some plants until they died. Pretty standard 2020 things. Now, it means I can come into 2021 with a few more liquid assets in my attention economy.

+

2021: Year of Discourse

+

I have decided that 2021 is the Year of Discourse. I am currently thinking about this in two parts:

+
  1. How do I present and communicate?
  2. +
  3. What do I do with ideas presented by others?
+

I would like to consider how I present myself, my work, hobbies, thoughts, ideas, affections\u2026 I would like to think about how the things I feel and know on the inside are shown on the outside.

+

I want to balance this focus on self with a focus on others. While I don\u2019t feel I have ever struggled with accepting or facilitating feedback or information, I want to focus more on doing something with that it.

+

I initially started with the Year of Presentation, which focused only on the first of these points, but the idea didn\u2019t fit. It felt too selfish. It also sounded a little synonymous with the Year of PowerPoint & Keynote, which I\u2019m not ruling out.[^1]

+

[^1]: Shoutout to Prezi, who I\u2019m surprised to learn have adapted pretty well to the death of Flash.

+

Why ?

+

During this summer I was interviewing for new jobs. I ended up getting the one I really wanted, but one of the other companies rejected me on the basis that I did not have good self-knowledge or self-awareness.

+

I was surprised by this feedback. I think it\u2019s the first time someone\u2019s levelled that criticism. In fact I\u2019ve often heard the opposite: too self-critical and under confident. I try to keep a good tab on my shortcomings and this isn\u2019t one of them. I spoke this through with a few close friends and they agreed that it seemed a little out of character. Despite this, a group of people I did not know met me, interacted with me, and together agreed that this was appropriate feedback, so I do not want to dismiss it.

+

They met the professional version of myself, who is wholly more confident and opinionated than my actual self. For the sides of my personality which I showcased, their feedback was probably accurate. I can\u2019t let my ego stop me from hearing valid criticism. I don\u2019t want to dismiss this feedback by justifying it or explaining it away - because that isn\u2019t going to lead to meaningful change.

+

This is what gave me the initial idea for thinking about presentation and interactions, i.e. Discourse.

+

Cynical Everything (\u2122\uFE0F)

+

I am worried this could be the moment in my career where I turn into the Cynical Developer (\u2122\uFE0F). That person on the team who hates everything they don\u2019t like (or know). Who\u2019s not open to change or different ways of doing things, and who only has one moral framework (their own).

+

I don\u2019t want my opinion to become inflexible, and I don\u2019t want that reputation. Nor do I want this to be the precedent that I set myself on the pathway to mastery of something. I don\u2019t want to be a Cynical Anything: cook, fitness person, artist, creative, friend, whatever.

+

I want to remain open-minded and engaging, and obviously in love with the things I chose to do with my time. And if I don\u2019t love it, or care about it - don\u2019t hold opinions about it too tightly. Let parts of it go. The Year of Discourse is about opening that journey up, to share it and show it in an inviting and collaborative way.

+

Season #1: Winter 2021

+

I bloody love seasons. I fell in love first by eating with them, and then the Covid-19 pandemic made me fall in love with simply watching them. Time passes, the rhythms flow, and everything has its time.

+

I want to spend the Winter of The Year of Discourse working on the implicit beliefs I have: recognising them and putting them into words. I\u2019m hoping this will help me realise how differently I could be doing things, and potentially some of the things which are guiding my actions or decisions. I\u2019m also hoping it will let me cut away anything which is holding me back.

+

Some of this is going to look like writing, which could be public or private, professional presentations, and conversations with friends. I think the process of discovering these things and then refining them is the valuable part of the work. I do not think the product will have much value for others. I don\u2019t want to rush through everything with the intention of producing something sharable, or wrap-up-able.

+

Hopefully I\u2019ll keep you updated \u{1F937}\u200D\u2640\uFE0F

`; +}); diff --git a/.netlify/server/chunks/2021-01-09-things-i-learned-22-09d66b70.js b/.netlify/server/chunks/2021-01-09-things-i-learned-22-09d66b70.js new file mode 100644 index 0000000..caa7176 --- /dev/null +++ b/.netlify/server/chunks/2021-01-09-things-i-learned-22-09d66b70.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_09_things_i_learned_22, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #22", + "author": "Thomas Wilson", + "date": "2021-01-09T00:00:00.000Z", + "draft": false, + "slug": "2021-01-09-things-i-learned-22", + "tags": ["things-i-learned"] +}; +const _2021_01_09_things_i_learned_22 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

This week the UK Government has brought us Lockdown The Third, a threequel in the franchise after the straight-to-TV movie that was the November lockdown. Cases, deaths, and hospital admissions are at an all-time high in our country at the moment, with London in particular looking pretty scary. It might be the \u201Cthe last push\u201D like this (boy, I really hope it is the last push), but that doesn\u2019t help the healthcare workers being forced forward/backwards/downwards by this whole situation. So for goodness sake, just stay inside. Call out people who are making selfish choices. We\u2019re all making decisions for everyone else around us, it really is that simple. Arrange FaceTime calls, yoga sessions, happy hours, online games, book clubs, Netflix watch parties, and craft dates with people. Life isn\u2019t going to be normal for a while, but we\u2019re going to get through this together and then one day get irresponsibly drunk as we sit in or outside a pub until closing time with the people we love, and think about what life looks like now. Until then just\u2026 learn to crochet or cook or something.

+
  • This cat: Mike the Cat guarded the British Museum, who was \u201Cprobably the most famed British feline of the 20th Century\u201D. Which seems like a narrow competition, but look, I don\u2019t want to detract from Mike\u2019s notoriety. After a decade\u2019s service, he passed away in 1929, and officials at the museum placed a memorial stone near the Great Russell Street entrance of the museum. (source)
  • +
  • This not-fireworks display: At Mariana Bay, Singapore, officials organised a light show performed (which feels like the wrong word) by five hundred drones. Just watch the video, it\u2019s mesmerising to watch them twinkle, form into animals, or just geometric patterns. (YouTube video)
  • +
  • This over-qualified actor: Y\u2019all have seen Stranger Things, right? The Netflix original 80\u2019s horror show which lives in my heart forever because I watched it during my Ph.D. with my housemate and like a whole bunch of popcorn. Mate, honestly it\u2019s so good. Anyway, there\u2019s this iconic scene right at the end of the third season where the world is about to end, and some of the characters are driving their iconic 80s car away from a world-consuming monster. The Duffer brothers took nearly three minutes of screen-time during this climax for an over-the HAM radio rendition of the title theme from The Never-Ending Story. It\u2019s baffling and I\u2019m amazed it got approval. Susie, the long-distance (previously almost certainly fictitious) girlfriend is played by Gabriella Pizzolo, played the title role in Matilda on Broadway in 2013. Pizzolo gets less than a minute\u2019s screen time but she rocks it. Bonus fun fact: the composers for the show (Kyle Dixon and Michael Stein), who produced the iconic synth-heavy score and title theme music weren\u2019t even told about this musical number until they turned to set one day. (source)
  • +
  • This other Ancient Egyptian Script: We all know that ancient Egyptians wrote in hieroglyphs: the pictorial script of birds, plants, and other symbols which were ubiquitous in their crypts and monuments. However, after around 700BCE, most cultures in the Ancient Egyptian period had at least two scripts in use at any one time: hieroglyphs to record what was morally good and should endure for eternity (like holy texts and things you\u2019d write on your culture-defining monumental tombs), and demotic (meaning popular) which was a more cursive script used for day-to-day things. That said, we estimate only about 1-5% of the Ancient Egyptian population were literate. The script survived in use until about the second century BCE, when it was replaced by Coptic - notably it wasn\u2019t replaced wholesale by Latin, as one might expect when the Roman emperors decided they owned the Nile now. (source)
+

What I\u2019ve had on Rotation

+
  • Something New In Sickness & in Flames by The Front Bottoms (Rock/Punk, 2020). I only just discovered this rock/punk-ish duet, and I\u2019m a little bit in love. It\u2019s like they\u2019re shouting poetry, or little truths, or little anecdotes that are connected most of the time, but sometimes it\u2019s a very loose connection. It\u2019s energetic, it\u2019s erratic, it\u2019s honest, and it\u2019s not so hardcore or edgy that it\u2019s exclusionary or difficult to listen to. Put it on when you next go for a walk sometimes. (links)
  • +
  • Something Old A Moment of Madness by Izzy Bizu (R&B, 2016). I was recommended this album as something to have on in the background if I needed to get something else done, and I really liked it. It\u2019s upbeat, soul-ish R&B that can stand its own as the centrepiece of music, or can hold into the background. It\u2019s gentle and doesn\u2019t demand your attention, but he clear voice and clean production doesn\u2019t wither under it. (links)
+

Cool Articles

+
  • DALL\xB7E: Creating Images from Text by Open-AI. Isn\u2019t this a terrifying little read. The Open-AI team show how they trained an AI to generate images from free text prompts. For example they gave it the phrase \u201CA storefront with \u2018Open AI\u2019 written on it\u201D, and the AI went ahead and made it. Trained on a corpus of labelled images, it was able to throw together these images on demand. Some of them are terrifying because they\u2019re so accurate - others are terrifying because they\u2019re 90% of the way towards making the image, and sit in the \u2018Nightmare Fuel\u2019 region of the uncanny valley.
`; +}); diff --git a/.netlify/server/chunks/2021-01-10-an-ode-to-plaintext-notes-be3efccb.js b/.netlify/server/chunks/2021-01-10-an-ode-to-plaintext-notes-be3efccb.js new file mode 100644 index 0000000..c246895 --- /dev/null +++ b/.netlify/server/chunks/2021-01-10-an-ode-to-plaintext-notes-be3efccb.js @@ -0,0 +1,72 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_10_an_ode_to_plaintext_notes, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "author": "Thomas Wilson", + "date": "2021-01-10T00:00:00.000Z", + "draft": false, + "slug": "2021-01-10-an-ode-to-plaintext-notes", + "title": "An ode to note taking with markdown files", + "tags": ["notes", "markdown"] +}; +const _2021_01_10_an_ode_to_plaintext_notes = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

This is based off a sesh (think lightning talk, but\u2026 cooler?) I gave at Oxwash, where I am a frontend software engineer. I wanted to give an overview for how I take notes in pretty much every area of my life, including my job but also for holidays, notes from books I am reading, and for writing posts like this.

+

Over the past twelve months my thinking has converged towards the idea that plaintext files (like Markdown) are a great choice for note making and keeping. Please, let me explain why.

+

I\u2019m not going to talk about any particular software in this post, just explaining why I think plaintext is cool. God I love the internet.

+

What do I want in notes ?

+

The entire argument I am about to make relies on a couple of assumptions. The first is that you want some kind of personal productivity or knowledge management infrastructure in your life. You might not want any, or you might be okay with the default Notes and Tasks apps on your phone. That\u2019s fine.

+

The second is that this is the kind of thing you can get down and nerdy about.

+

Now that I\u2019ve weeded out anybody remotely cool, let\u2019s talk note taking and productivity.

+

No matter what tool I am using to take notes, I am trying to optimise for a couple of non-negotiable things:

+
  1. The speed of getting an idea out of my brain. My brain can get a little cluttered, and ideas can sometimes clamber over each other as they try to get out.
  2. +
  3. The ability to find a note after I\u2019ve written it. I don\u2019t care how it works, I can adapt, but normally at least one of the following things will stick around in my brain to let me find something:
    • A bit of the filename
    • +
    • A rough time when I made the note
    • +
    • A list of directories it\u2019s probably in
    • +
    • I remember that I mentioned the file in another file
  4. +
  5. I am able to integrate my meta-work easily into my actual work, as:
    • A software engineer
    • +
    • Someone who writes blog posts that no one reads
    • +
    • Part of my ongoing professional development and research
    • +
    • Reading / reviewing / keeping notes on books
  6. +
  7. A note can be deleted (or discarded) when I\u2019m done with them, without impacting anything else.
  8. +
  9. I want the reasonable ability to own my data and I don\u2019t want it to be in a proprietary format
+

Atomic vs. Ecosystem productivity tools

+

I\u2019ve gone through a lot of productivity tools and techniques in the past ten-ish years, where I\u2019ve gone from undergraduate, to doctorate student, to software engineer in small and large companies. Right now, plaintext, specifically markdown (.md), account for maybe 90% of my productivity and meta-work. I rarely find myself needing to move outside of them.

+

Previously, I flitted between two productivity ideals:

+
  1. Atomic tools where one job is done by one thing - task managers for TODOs, spreadsheets for data, notes for\u2026 notes. I have previously used apps like Bear (markdown-like notes), Google Sheets, and Todoist (task manager).
  2. +
  3. Ecosystem tools where one tool should contain everything: TODO lists should be aware of personal budgets, should be linkable to meeting notes and product designs. Notion is the current Platonic ideal of this philosophy.
+

I found atomic tools difficult to manage in practice, because you have to figure out how to tie multiple disparate systems together. You\u2019ve also got to learn how multiple tools think about data and workflows.

+

I didn\u2019t like ecosystem tools as much as I wanted to, because in practice they\u2019re trying to be a consumer-friendly operating system for information and workflows. As an engineer, I didn\u2019t like how ridged they are. Nor did I like how proprietary they are. I\u2019m good to not put all of my valuable information onto a boat captained by an engineer out in San Fransisco who doesn\u2019t particularly want to resist the siren call of VC funding.

+

Plaintext isn\u2019t an atomic tool, because it can contain a variety of different kinds of information. Nor is it an ecosystem, because it can\u2019t (ergonomically) contain every kind of information. Previewing tables and images in markdown is\u2026 not particularly user friendly.

+

That said, plaintext notes are simple and accessible - every smart device I own can download files from the cloud, and has a way of editing them. Sure the editing experience is inconsistent, sharing external web pages or files into them is also a bit of nightmare, but the file format is present. And how much of success is just turning up?

+

Plaintext is kinda like Lego

+

The fact that plaintext is just text is a disadvantage. But plaintext still lets you put different kinds of information together in the same place. They\u2019re composable and combinable. One note can contain TODO lists, links to web pages, single-sentence thoughts, headings for structure in the document. That means I can have a file that represents a single day, a project, or a planned period of work - I don\u2019t have to divide everything off arbitrarily. And I can do this differently for every note.

+

You can also link things together at the file level. By naming convention or location of the file, or just calling a file out - things can link together easily.

+

A single plaintext note can easily support most things from infancy to adolescence. Some things, like data-heavy lists or tables, have practically no room to grow (at least not without software-based enhancements). Others, like a collection of notes and quotes from books I am reading, are able to expand almost infinitely. Most things, sit somewhere in the middle.

+

Importantly, when something outgrows the medium of a plaintext document I am able to link the two. Even if this only a one way link, from markdown to a URL, or a copy-paste job from an e-mail. Is it perfect? No, but it\u2019s just plaintext. It\u2019s open source, it\u2019s human readable, and it makes sense to me. The computer doesn\u2019t need to understand everything I do and say, it just needs to remember what I say and let me do the figuring out.

+

Notes are a tool that serve you

+

Digital note taking brings together two very opinionated groups: people who think about software or digital systems, and people who work in research or communication. It is easy to find a lot of zealous doctrine online about what makes \u201Cgood\u201D notes.

+

Take their ideas as inspiration. Or ignore them. They\u2019re not going to hunt you down to ask why you don\u2019t implement their note template, and if they do they\u2019re probably weak from sunlight deficiency and lack of social awareness.

+

If you\u2019re serious about creating and then maintaining a habit, it has to offer some clear benefit to your life. Following an additional set of rules and guidelines for their own sake may work for some people who love following rules. You do not serve the monolith of your notes archive - it serves you.

+

If your notes are long and sprawling, that\u2019s fine. If they\u2019re short and clipped, cool.

`; +}); diff --git a/.netlify/server/chunks/2021-01-15-free-fonts-awwwards-83617597.js b/.netlify/server/chunks/2021-01-15-free-fonts-awwwards-83617597.js new file mode 100644 index 0000000..0ffa9b6 --- /dev/null +++ b/.netlify/server/chunks/2021-01-15-free-fonts-awwwards-83617597.js @@ -0,0 +1,35 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_15_free_fonts_awwwards, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Design Resource: Free Fonts from Awwwards (2021)", + "author": "Thomas Wilson", + "date": "2021-01-15T00:00:00.000Z", + "draft": false, + "slug": "design-resource-free-fonts-from-awwwards", + "tags": ["design", "design resources", "link"] +}; +const _2021_01_15_free_fonts_awwwards = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Awwwards have put out a collection of free (or free-adjacent) fonts. You can find them here.

`; +}); diff --git a/.netlify/server/chunks/2021-01-15-things-i-learned-23-bcc7f83d.js b/.netlify/server/chunks/2021-01-15-things-i-learned-23-bcc7f83d.js new file mode 100644 index 0000000..01342a5 --- /dev/null +++ b/.netlify/server/chunks/2021-01-15-things-i-learned-23-bcc7f83d.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_15_things_i_learned_23, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #23", + "author": "Thomas Wilson", + "date": "2021-01-15T00:00:00.000Z", + "draft": false, + "slug": "2021-01-15-things-i-learned-23", + "tags": ["things-i-learned"] +}; +const _2021_01_15_things_i_learned_23 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • These underwater drawings: Go back to 1860s and ask someone what coral reefs, or fish, or literally any marine life looked like. Go on. I bet they\u2019d tell you they had no idea. How would they? Sure, we\u2019d been sending people down there since the 1500s in these giant metal bells but those were more function-over-form. You couldn\u2019t really see out of them. Around the 1400s we maybe started sending people down with metal crates over their head and tubes attached to their suits to feed air to them. But what are they gonna do, take picture on their under-water cameras or pull out a little canvas to sketch the scenery. In the 1860s a guy did literally that latter thing, which is so metal. Eugen von Ransonnet-Villez designed a special 2 feet wide, 3 feet tall diving bell with glass viewing ports for light and the view. He sat in his little underwater cupboard and drew what he saw. He dangled his legs out the bottom so he could move around a little, which is perhaps my favourite mental image. A full version of his published work, entitled \u200CSketches of the Inhabitants, Animal Life and Vegetation in the Lowlands and High Mountains of Ceylon: As Well as of the Submarine Scenery near the Coast Taken from a Diving Bell, can be found here (description of the underwater stuff starts on page 21). (source)
  • +
  • This coffee myth: I always assumed I had to drink extra water before/after coffee, because it dehydrated me. Turns out that\u2019s a dirty filthy lie. A study in 1928 found that increased coffee consumption was associated with higher urine output. That\u2019s right, some science was done at a time before we had invented the synthetic toothbrush bristles found that if you drink more coffee, you also pee more. And then we just carried on believing that coffee made you pee more (which I guess isn\u2019t a lie). Some 2016 research investigated caffein consumption and dehydration - finding no evidence that increased caffein consumption works against your hydration. It is worth remembering that coffee isn\u2019t just caffeine, however. Either way, don\u2019t worry too much about it. (source)
  • +
  • This pilgrimage: Chartres Cathedral, near Paris, has a 42-foot single-pathed labyrinth pattern inlayed in their floor. We don\u2019t actually know who built it, or why, just that it came about in the early 13th century. Around the time it was constructed, it became impossible for Christians to make a pilgrimage to Jerusalem - because of political issues. Luckily we\u2019ve spent the past eight centuries working together to overcome these woefully antique problems. The labyrinth arose at a time when people wanted, but were unable, to undertake an important journey, in every sense. Chartres Cathedral became a pilgrimage destination for European Christians - with the single winding path acting as a tool for meditation and therapy as the walker made their winding (but definitely small) journey. Single-pathed labyrinths actually have a long, and continuing, history as tools to help guide and sooth thoughts. These single-path labyrinths are still used in therapeutic and mindfulness contexts because they are seemingly complex but they don\u2019t let you make choices, and they always lead to successful completion. (source)
+

What I\u2019ve Had on Rotation

+
  • Something New Kokoro by Stefano Guzzetti (Piano, 2020). This past week I\u2019ve been doing a lot of deep work, which I like to do in silence. So when I come to have music on, I don\u2019t want anything that jolts or shocks my system. Guzzetti\u2019s Kokoro is a delightful hour of melodic, pleasing, and still complex-in-places piano. It\u2019s good for these rainy, dark days where really who wants to leave the house anyway? (links)
  • +
  • Something Old Murs 3:16 9th Edition by Murs (Hip Hop, 2004). I absolutely love going back to find some of the great albums and artists of 21st century hip hop. This album has that timeless boombap style of productions: samples, synths, and drum machines. Murs\u2019 Have a Nice Life received a lot more critical acclaim, and deserved it (it\u2019s a maturer sound - I\u2019ll pick it some week), but this 3:16 gives a sense of perspective with its relative immaturity, anger, and hard-stances. Love where you\u2019ve come from, as well as where you\u2019re going - and that\u2019s what this album reminded me of. (links)
+

Cool Reads

+
  • State of JS 2020 Results. If you\u2019re a software engineer who writes for the web, you should read this article. It breaks down responses from almost 25,000 software engineers, and gives State of the Union for frontend technologies, and highlights where things could head in the future. The Svelte framework really shone through this year, and TypeScript continued its dominance in the wider ecosystem.
  • +
  • Dense Discovery Issue #120. I\u2019ve mentioned Dense Discovery in previous editions of things I learned, but I want to give a shoutout to this week\u2019s edition in particular. It\u2019s such a well curated, thoughtful newsletter run by Kai Brach. I really advise signing up for the newsletter. This week\u2019s issue had the following quote which stuck out to me, as someone who has recently found themselves thinking \u201CI really just should get my head down and finish this book\u201D, without considering my enjoyment of that book:
+

\u2026 as a society we increasingly see reading as \u2018mining\u2019 a text for information instead of it being an exercise of contemplation. He calls it \u2018the Silicon Valley view of the mind\u2019 that treats brains like computers: the more effective the input and the data processing, the better and therefore more successful the output. There is a whole category of tech \u2018innovation\u2019 that wants to make reading more efficient \u2013 from the many speed-reading apps to subscription services that give you the time-saving gist of annoyingly comprehensive books.

`; +}); diff --git a/.netlify/server/chunks/2021-01-23-the-silence-of-the-girls-47091b40.js b/.netlify/server/chunks/2021-01-23-the-silence-of-the-girls-47091b40.js new file mode 100644 index 0000000..6f2b92f --- /dev/null +++ b/.netlify/server/chunks/2021-01-23-the-silence-of-the-girls-47091b40.js @@ -0,0 +1,58 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_23_the_silence_of_the_girls, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Silence of the Girls", + "author": "Pat Barker", + "score": 3, + "image": "the-silence-of-the-girls", + "slug": "the-silence-of-the-girls", + "book_review": true, + "date": "2021-01-24T00:00:00.000Z", + "finished": "2020-12-10T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "greek-mythology", "historical"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Pat-Barker/The-Silence-of-the-Girls--Shortlisted-for-the-Womens-Prize-for-Fiction-2019/23606163" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/the-silence-of-the-girls/9780525564102" + } + ] +}; +const _2021_01_23_the_silence_of_the_girls = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Pat Barker\u2019s take on the classic story of the Battle of Troy is told from the perspective of Briseis, the noble taken slave when Achilles sacks Lyrnessus. Consigned to life as a bed slave for Achilles, she is later taken from Achilles by Agamemnon, which in turn causes Achilles to stop fighting for the Greeks. In the tradition of classic epic poems like the Iliad, women and slaves are treated entirely as property - not as humans. By re-telling a classic from this previously unconsidered, almost inanimate, point of view Barker is able to shift away the dignity and majesty that normally tint classic or epic poems. Barker\u2019s retelling is not quite a reimagining, but she does a wonderful job of maintaining focus on the broken societies and individuals involved in the story, and of just how crude things would have been during the seige on Troy.

+

Barker does a superb job of describing the setting: a war camp set up between a battlefield, Troy, and the ocean. Each of these settings are essential to the themes which run through the book: the idyll and treasures of war, and Achilles\u2019 own divine connection to the ocean (his mother, Thetis, was a Neried - a sea nymph). Barker describes the war camp as something which straddles permanence, as a home for many soldiers and the supporting staff and slaves, and the temporary make-shift encampment. Her descriptive prose are never indulgent, but over the course of the book they beat out an immediate world. The use of small comments are often the quick assessing glances of characters gives the entire book a great sense of place.

+

Briseis experiences the world around her immediately, but the events and beats of the plot often have to come to her. Word is brought, or she sees the consequences of battles and political manoeuvres. Her situation inside the house and bedroom of Achilles offers some nice speculation about what we don\u2019t see in the original epic poems. This small scale, domestic focus carries heavily throughout the book, and brings a sense of intimacy to Achilles and his inner circle. It brings pangs of sympathy for Briseis\u2019 own struggles as a woman taken from her life, moved from nobility to slave, and as witness to relentless violence.

+

The result is a story that keeps its pace up right up until the 80-90% mark. Towards the end, things really drift off, and I couldn\u2019t get a clear sense if Barker was trying to wrap things up or leave them open. The Silence of the Girls breaks the strict narrative structure of the original epic source material, that attempting to break form makes sense. I just didn\u2019t get a sense of commitment to this idea, which so I found the ending a little disappointing.

+

I was worried that Briseis would remain a victim to circumstance. That as a woman and a slave, I would commit three hundred pages to someone simply experiencing and coping with the world. This is a poignant part of the story, and not one I would want to be glanced over. Barker acknowledges it but doesn\u2019t overdo it. At times our narrators fears feel a little repetitive, and without any real bite, but she\u2019s fleshed out. I am always wary of books which adopt a diary or confessional style, which this one does. However it doesn\u2019t get in the way.

+

At times the pragmatism and frankness of her writing leave me wanting more. I always wanted a little bit more presence, a bit more flesh on the bones. The story is told almost entirely from the first person perspective, and it feels a little constrained by that, at times. This is entirely a personal preference, and Barker\u2019s style is consistent throughout. It just grated on me.

+

This doesn\u2019t get in the way of exploring the world or the themes, however. Personal and violent trauma is explored carefully and with respect. We see Achilles, and other great characters portrayed with more humanity and dimensions that the typical archetypes they can become. From the opening sentence of the novel, \u201CGreat Achilles, brilliant Achilles, shining Achilles, godlike Achilles\u2026 how the epithets pile up\u201D, you know this is going to be tackled. And it is. The reimagining of a more human, faulted, prideful and unloved Achilles comes through.

+

The themes were interesting, but delivered a little plainly. Nothing struck me suddenly, and little specific details or phrasing stays with me. Perhaps the book is too human and not godlike or mythical enough for my personal taste. What the narrative or style lack is made up for easily in the sturdy telling of a classic story. 3\u2B50

`; +}); diff --git a/.netlify/server/chunks/2021-01-23-things-i-learned-24-1b7b35ce.js b/.netlify/server/chunks/2021-01-23-things-i-learned-24-1b7b35ce.js new file mode 100644 index 0000000..837244c --- /dev/null +++ b/.netlify/server/chunks/2021-01-23-things-i-learned-24-1b7b35ce.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_23_things_i_learned_24, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #24", + "author": "Thomas Wilson", + "date": "2021-01-23T00:00:00.000Z", + "draft": false, + "slug": "2021-01-23-things-i-learned-24", + "tags": ["things-i-learned"] +}; +const _2021_01_23_things_i_learned_24 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This fitness research: I\u2019ve long been a fan of interval training to help improve my running and cycling speed. High intensity interval training (HIIT) is a method of training where you mix short bursts of intense activity (e.g. a 30 second sprint) between longer periods of low-intensity exercise (e.g. 90 seconds slow jog). It\u2019s time-efficient, evidence-backed, and makes me uncomfortably sweaty so it must be good. Our current guess is that by pushing through into very high intensity activity you trigger different physiological responses, compared to sustained moderate exercise. It turns out it might also be useful for less active, older adults - not just younger people and athletes. Some researchers at the University of Texas looked at a HIIT regime with just 4 seconds of exercise in a sixty second interval (4 seconds on, 56 seconds off), repeated fifteen times back-to-back. So fifteen minutes total, just sixty seconds of high intensity exercise. The researchers worked with both young adults (no age mentioned) and older adults (50-68 years old) and found that and found improvements to their strength and performance after three sessions a week over eight weeks. This is great news if you\u2019re looking to make the most of your exercise, but not great news if you hate running/cycling so fast you feel like you could be sick. (source)
  • +
  • These sheep: North Ronaldsay is a three-mile long island off the Scottish coast which used to be moderately populated (a couple of hundred people) and sustained by the seaweed which would wash ashore from the stormy North Sea. In the nineteenth and twentieth century we would burn seaweed for potash - a valuable industrial ingredient. We\u2019ve moved on from burning seaweed for potash, so the while island is still populated by seventy two people, it\u2019s also the home to some pretty unique sheep. Sheep love to eat things, like peoples\u2019 crops, so in 1832 the residents of North Ronaldsay constructed a two-metre high drystone wall (also the longest single drystone wall in the world, by the way) to confine the sheep to part of the shore. Nearly two hundred years later, and the sheep have adapted to life on the coast of a tiny island in the North Sea - mainly by eating seaweed instead of grass (or peoples\u2019 crops). They remain some of the few pure English-bread sheep stock in the world, and also they look incredibly grizzly. Seriously, go look at some pictures of them, they totally look like an old haggard Scottish shepherd. (source)
  • +
  • This vegetarian cereal inventor: John Harvey Kellogg (of Corn Flake fame), born in 1852 (i.e. twenty years after that dry stone wall), was one of America\u2019s early popular proponents of a meat-free diet. It\u2019s the reason he was dead keen on getting nutritional plant-based foods out there, despite his first recipes being incredibly bland and basically gruel. He wasn\u2019t vegetarian for the environmental or animal rights reasons that many associate with vegetarianism today. No no. He believed that a diet rich in meat was too full of fat and rich flavours (this is often the argument people give as to why they \u201Ccould never go vegetarian\u201D, so maybe work on your marketing, John). Kellogg believes that these irresistible flavours were basically making us too horny. Meat increased our sexual appetite, and therefore eroded our moral fibre. These beliefs actually pre-date the man\u2019s cereal infamy, and he opened the Battle Creek Sanitarium, a sort of health retreat / rehab centre / healthcare facility - but two hundred years before the term \u201Cwellness retreat\u201D really became popular. Here, he evangelised a plant-based diet and outdoor exercise. While there he ended up boiling some wheat, and thought \u201Cthis bland mush is so boring but healthy I bet it\u2019s great for your soul and wouldn\u2019t make anyone horny\u201D - or something like that. So yeah, now we have Corn Flakes and Cocopops. (source)
  • +
  • This CV of one of Parler\u2019s Founders: Parler is (was?, no wait, is) a Twitter-clone social media for people on the right of the political spectrum. The appeal comes from years of claims that Twitter was suppressing free speech. It\u2019s not that spending four years posting increasingly inflammatory and violent rhetoric isn\u2019t inherently appealing to social media. No. Twitter is hiding your tweets. So Parler was founded by a software engineer (John Matze) and billionaire heiress Rebekah Mercer. Some fun facts about Mercer, and why you should definitely trust her to run a tight ship: i) she owned a bakery in New York in the mid 2000s (and apparently made awful cookies), ii) she never does public interviews, and iii) she (and her father) were invested heavily in Cambridge Analytica (that unethical, and arguably illegal, data mining company). No, I\u2019m sure she\u2019s got all the bona fides to manage a social media company where \u201Dthere are going to be no fact checkers\u201D, and they can quickly handle the pivot after being de-platformed from the vast majority of the internet. (source)
+

What I\u2019ve Had on Rotation

+
  • Something New: SUCKAPUNCH by You Me at Six (rock/pop punk, 2021) . The band\u2019s seventh studio album is the first in a couple of years to make me feel like You Me At Six made me feel in 2013. The slightly electronic, punky, rocky vibe (a la their cohort Panic! At the Disco, All American Rejects, et. al) of SUCKAPUNCH has the high energy, and distinct Essex vocals of Josh Franceschi that make it lovable. (link)
  • +
  • Something Old: Have a Nice Life by Murs (hip hop, 2015). Last week I recommended Murs\u2019 2004 album, and the difference in production and content between these two is notable. An altogether more mature and even sometimes humble album, that has an absolutely fantastic golden era classic beat production. This one\u2019s going on my list of classic. It\u2019s not surprising I love this sound, Murs is currently collaborating with Slug and Eligh - two of the first rappers I loved when I first discovered hip hop. Anyway, this album is really great you should listen to it. (link)
+

Cool Articles

+
  • Here are some (entirely serious) predictions about tech in 2021 by Matt Reynolds for Wired. This delightful little satirical piece riffs on some of the zeitgeist/pop culture moments from 2020, which exist regardless of pandemics. My favourite is the prediction that in December 2021 we discover an asteroid on a collision course for earth, meaning that \u201Cexistential panic can resume as scheduled\u201D. Very good.
  • +
  • Longevity Linked to Proteins That Calm Overexcited Neurons by Veronique Greenwood for Quanta Magazine. This is a neat little piece of science journalism covering something published in Nature in 2019: that mice and worms with higher concentration REST (a protein which slows neural firing) have longer lifespans. There\u2019s a couple of really nice mental models in the piece, which slightly re-framed the ageing process for me. Notably the idea that ageing is a process where the body loses the ability to maintain equilibrium. It is not able to respond to environmental (or social, or cognitive, or whatever) stressors and return to a baseline \u201Cnormal\u201D state.
`; +}); diff --git a/.netlify/server/chunks/2021-01-27-albums-2020-5725fa4c.js b/.netlify/server/chunks/2021-01-27-albums-2020-5725fa4c.js new file mode 100644 index 0000000..d28e423 --- /dev/null +++ b/.netlify/server/chunks/2021-01-27-albums-2020-5725fa4c.js @@ -0,0 +1,38 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_27_albums_2020, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "My Top Albums of 2020", + "author": "Thomas Wilson", + "date": "2021-01-27T00:00:00.000Z", + "draft": false, + "slug": "2021-01-27-top-albums-2020", + "tags": ["project", "albums"] +}; +const _2021_01_27_albums_2020 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Just a quick blog post to highlight that I\u2019ve published my 2020 Top Albums of the Year. You can find it here. Seriously, go check it out.

+

I really enjoy making little specially art-directed pages like this. It feels very \u201Cthis is what the internet was made for\u201D. It\u2019s just a quirky little bespoke designed page which oozes my love for music. No tracking, no adverts, just a quirky font and cool colour scheme.

+

If you want to take a look at last year\u2019s albums, check out my Top Albums of 2019

+

Anyway, hope you\u2019re keeping well.

`; +}); diff --git a/.netlify/server/chunks/2021-01-29-things-i-learned-25-2a491e4b.js b/.netlify/server/chunks/2021-01-29-things-i-learned-25-2a491e4b.js new file mode 100644 index 0000000..dcb59cf --- /dev/null +++ b/.netlify/server/chunks/2021-01-29-things-i-learned-25-2a491e4b.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_29_things_i_learned_25, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #25", + "author": "Thomas Wilson", + "date": "2021-01-29T00:00:00.000Z", + "draft": false, + "slug": "2021-01-29-things-i-learned-25", + "tags": ["things-i-learned"] +}; +const _2021_01_29_things_i_learned_25 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This etymology: The word \u201Cpeculiar\u201D has come to mean odd or unique, so obviously its Latin root word (\u200Cpeculium) means somebody\u2019s cattle. Cows were pretty valuable assets back in the day: you can eat them, milk them, use them as work animals, so they became a symbol of wealth. Later, \u200Cpeculiaris evolved from this same root word to mean \u201Cof private property\u201D, i.e. belonging to one person. This link makes sense too - if cattle are the stereotypical idea of property and wealth, then they\u2019ll start to become synonymous. Sort of like how \u2018estate\u2019 mingles land and social status (sorry to introduce a second etymology here to explain the first, bad form, I know). This latter meaning, of private property, has more clear links to \u201Cunique\u201D or \u201Cindividual\u201D, a connotation which arose in seventeenth century Europe, and which remains dominant today. (source)
  • +
  • This statue of Lenin: Hey remember back in the 1920s when Vladimir Lenin headed up the Soviet Union and shaped and popularised the communist ideal? As part of the zealous, world-domineering showmanship for the Soviet Union, Lenin had his face put on a whole bunch of things, including a lot of busts. I mean a lot of busts. Lenin\u2019s personal brand was so strong during his leadership that his face was put on stamps, posters, newspapers, crockery, and generally anything. That\u2019s not to mention the fact that entire towns, as well as buildings and streets, were named after him. In a show of undeniable rigour and commitment to science (and communism), in 1958 a bunch of scientists and explorers from the USSR trekked to the most remote part of Antarctica, called the \u2018pole of inaccessibility\u2019, and erected both a research station and a Lenin bust. Out there, in the most remote part of the Antarctic desert in a bust of Lenin, cast in a synthetic polymer because no one\u2019s quite stupid enough to take marble to one of the hardest to reach places on earth. Originally pointing towards Moscow, a bunch of American made their way to the research site and rotated him to face Washington. So in \u201866-67 another bunch of Russians went out to un-rotate him and point him towards his home land. Now-a-days, little plastic Lenin is being slowly buried by the inevitable snow, and in about ten years he\u2019ll likely not be very visible. (source)
  • +
  • This second largest bird: If I was an emu, I wonder if I\u2019d feel self conscious about being second-rate to my taller, more famous cousin, the ostrich. But look, there are some wild things about the emu that I just did not know. For example, did you know that the male emus take responsibility for guarding and incubating the eggs. They\u2019ll not eat, and so likely lose weight, just to stay with the eggs and I don\u2019t think anything could make me want to do that. Another fun emu fact is the infamous 1932 emu war in Australia, where the animals such a nuisance (they kept eating the corn that humans wanted to eat) that the army tried to get rid of them but failed. Third emu fact: aboriginal Australians discovered that you could use emu oil (don\u2019t ask how it\u2019s collected, it\u2019s pretty sad and unpleasant) to oil and treat your tools. These days we use emu oil as a topical (i.e. on the skin) treatment for joint and muscle pain, as well as healing damaged skin. Last fun emu fact for now: they\u2019re the only bird with calf muscles. Because their bodies are so big, and wings are so small, the extra muscle allows them to move at faster speed, which is a clear evolutionary advantage. (source)
  • +
  • This use for leaches: Imagine, if you will, that it is the 1800s and you need a way of detecting if a storm is coming. Imagine also that you happen to have a bunch of leeches lying around, because scientists in the 1800s had stuff like that. Oh, to be a rich white victorian scientist. George Merryweather was one such lucky soul, and he invented the Tempest Prognosticator. As the name suggests, it\u2019s a device which is able to alert you to when a storm is coming. It came about after Merryweather noticed that his leeches would become more active (i.e. wriggle more) before a storm hit. He surmised that leeches must be sensitive to changes in air pressure, and will want to seek shelter when a storm is coming. He used this new-found knowledge to build a contraption (which is totally the right word for what he built) which placed leeches in glass jars, attached strings to the sides of the jars, and then attached those strings to bells. So that when the pressure dropped, and a storm was coming, the leeches would writhe around and cause a \u201Ctinkle tinkle\u201D of the bells. Merryweather never managed to successfully sell his Tempest Prognosticator to anyone, which is surprisingly because who wouldn\u2019t want to tend to a dozen jars of leeches every day? In an attempt to break into the luxury market, he constructed an ornate (i.e. hand crafted and artisanal) version for display at the 1851 Great Exhibition in London. (source)
+

What I\u2019ve had on Rotation

+
  • Something New Kvitravn by Wardruna (2021, \u2026Folk Rock?). I don\u2019t know how to describe this album. It\u2019s sort of metal, sort of rock, but definitely Celtic. Just listen to it, you\u2019ll know in the first few minutes if it\u2019s for you, or if it\u2019s some kind of medieval torture method. I personally find it earthy and grounding and moving. (links)
  • +
  • Something Old Invaders Must Die by The Prodigy (2009, EDM). This album takes you all the way back to 2009, but it still stands up really well as an EDM album. It\u2019s the signature sound of The Prodigy, and it\u2019s got me through some runs/cycles over the past couple of weeks. Maybe it\u2019s got me a little too hyped, but is that really a bad thing? (links)
+

Cool Articles

+
  • How Supergiant Secretly Launched Hades - Developing Hell #01 (video series) by Noclip. Noclip produce really high quality documentaries about video games on YouTube. They\u2019ve got a multi-part series which covers the development of Hades, the most recent game from Supergiant Games. They cover the multitudinous efforts required to create a video game which is beautiful to experience and fun to play.
  • +
  • Experience: I drink more than 50 cups of tea a day by Yasmin Lee for The Guardian. I\u2019m a super nosy person, so articles like this appeal to me. Lee gives an overview of what it\u2019s like to be a tea taster. I\u2019m very unsophisticated with my taste for tea (much to the chagrin of my best friend) - but it sounds like a pretty cool job, to be honest with you. You get to make and taste delicious things \u{1F937}\u200D\u2640\uFE0F
`; +}); diff --git a/.netlify/server/chunks/2021-01-31-tiny-thoughts-frontend-is-fullstack-765d7355.js b/.netlify/server/chunks/2021-01-31-tiny-thoughts-frontend-is-fullstack-765d7355.js new file mode 100644 index 0000000..5011203 --- /dev/null +++ b/.netlify/server/chunks/2021-01-31-tiny-thoughts-frontend-is-fullstack-765d7355.js @@ -0,0 +1,49 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_01_31_tiny_thoughts_frontend_is_fullstack, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Tiny Thought: Frontend Engineering is a Fullstack Problem", + "author": "Thomas Wilson", + "date": "2021-01-31T00:00:00.000Z", + "draft": false, + "slug": "2021-01-31-frontend-is-fullstack", + "tags": ["tinythought", "essay", "fullstack"] +}; +const _2021_01_31_tiny_thoughts_frontend_is_fullstack = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Tiny Thoughts are little (500 word) essays. They\u2019re concise.

+

Hypothesis: Frontend engineering cannot exist in isolation from backend technologies.

+

What sparked this: Thinking about building the next generation of web software at Oxwash.

+

All software is either\u2026

+
  1. Used by a human for a human-scale (i.e. nebulous and larger) task like updating a status on social media, download a bank statement, or send a message.
  2. +
  3. Used by other software to complete some computer-scale (i.e. smaller and specific) task like upload a file to S3, compress an image, query a database.
+

Frontend software is, by definition, the bit used by humans. Good frontend software makes the human user aware of what they can(not) do, and what\u2019s going on in the system. How many unread messages do I have? What class do I have at 4pm this Thursday?

+

This information is communicated in the User Interface (UI). UIs are interpreted by humans. The metaphors and language developed during design then used in UI are intended solely to communicate and explain. Humans can bend, abstract, and change concepts or language. So although UIs should be consistent, they can not be. You can present your blog page as a \u201Crecent articles\u201D page, and as a list view for the posts table in your database. Both are true, but have different ideas about how \u201Ccomputery\u201D an app is.

+

When a human tells the UI that they wish to do something, the UI then has to talk to another bit of software. Software cannot bend, abstract, or change its ideas. A blog post is a row in a database. Software has a pre-specified language of things it can do: the Application Programming Interface (API).

+

Frontend engineering is about working with both APIs and UIs. The skill of a frontend engineer can be proxied by their ability to design one or both. It\u2019s a skill because if you make these languages too similar, you risk a UI which is too technical or an API which is too inflexible.

+

A lot of engineers write code for engineers. I\u2019ve seen (and written) \u201Cclean\u201D code which prematurely optimised and abstracted. This does not guarantee a good Developer Experience (DX) when you actually use the API. Nor does it make the user experience or product quality inherently better.

+

These are strong code smells if I\u2019m building version 1, or the API only has one consumer.

+

As a frontend engineers, we have to advocate for users and software, situation depending. We should make better interfaces.

+

Recognising the need to design singular interfaces (APIs and UIs), and using a shared language is GraphQL\u2019s fundamental distinction from REST. GraphQL acknowledges that provider and consumer need to know about each other.

+

If your product is an API you should think especially hard about clear concepts and language.

`; +}); diff --git a/.netlify/server/chunks/2021-02-04-first-you-write-a-sentence-b830ceb2.js b/.netlify/server/chunks/2021-02-04-first-you-write-a-sentence-b830ceb2.js new file mode 100644 index 0000000..1362f1b --- /dev/null +++ b/.netlify/server/chunks/2021-02-04-first-you-write-a-sentence-b830ceb2.js @@ -0,0 +1,56 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_04_first_you_write_a_sentence, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "First You Write a Sentence", + "author": "Joe Moran", + "score": 4.5, + "image": "first-you-write-a-sentence", + "slug": "first-you-write-a-sentence", + "book_review": true, + "date": "2021-02-04T00:00:00.000Z", + "finished": "2021-01-15T00:00:00.000Z", + "draft": false, + "tags": ["non-fiction", "writing"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Joe-Moran/First-You-Write-a-Sentence--The-Elements-of-Reading-Writing--and-Life/24080553" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/first-you-write-a-sentence-the-elements-of-reading-writing-and-life/9780143134343" + } + ] +}; +const _2021_02_04_first_you_write_a_sentence = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I loved this book. Will love this book again, because I know I\u2019m going to read it again. And then probably again after that. Moran\u2019s two hundred page treatise on the process of writing and re-writing is meatier than you would expect. Every few pages serve you a meal, a new way to think about reading or writing: how active is the voice? Remember punctuation? Does this make sense? Moran shows you the importance of these questions, and the consequences of (not) adhering to them. I think this book does a superb job at explaining and dissecting written communication which, like a lot of human rules, are real but unspoken. It\u2019s not a dry style guide. Moran appeals to emotion and common sense to make his points, peppering his rationale with quotes and examples. More people should read this book, even if they \u201Conly\u201D write e-mails, press-releases, statements, love letters, long instagram captions, or anything else longer than a few sentences.

+

The thesis running through this book sounds something like \u201Cconsider your sentences carefully and you\u2019ll probably write better\u201D. Although the book zooms in (to grammar, and Part of Speech) and out (to paragraphs and narratives) it always returns home, to sentences. A good essay, to me, draws your full attention to something overlooked or undervalued, but which is full of life and worthy of consideration. Examine something and, invariably, you\u2019ll see beauty or beauty reflected. Fortunately, a good sentence doesn\u2019t hide its reward behind expertise or mental gymnastics. Sentences can be intuitively seen as good or bad, and your reader will be judging them. The pleasing-ness of a particularly rhythmic, expressive, or concise sentence is something most readers would notice. Stephen King reportedly wrote The Gunslinger, his magnum opus, from the first sentence: \u201CThe man in black fled across the desert, and the gunslinger followed\u201D, one of the finer opening lines. So by considering the quality of our sentences, we begin to improve our writing from the grass-roots up.

+

Writing a book on how to write must be daunting. You\u2019re describing a medium in that medium, so you\u2019ve got nowhere to hide. By the end of the first chapter I was convinced that Moran had enough craft and flare to keep me invested, and that feeling didn\u2019t change. This is the first Moran book I have read, however, so I cannot speak for the quality of his entire portfolio. There\u2019s some truth to \u201Cthose who cannot do, teach\u201D, but any trace of that is scent is overpowered by the waves of unconditional passion for writing and language that roll off this work. Moran fulfils the eccentric-university-lecturer stereotype we often see more in American media (we quite like grizzled and pessimistic educators here). There are times when you can hear him delivering these ideas in front of a whiteboard in a room built and decorated in the sixties, complete with grey-blue-black worn carpet. He\u2019s informed enough to be useful, and impassioned enough to make sure you know exactly why you\u2019re being taught something. The ideal traits of a Higher Education educator, which Moran is.

+

The book is set out across seven chapters, though each chapter is almost self-contained. The book moves from a general introduction of the book\u2019s thesis, to the more detailed grammatical and linguistic specifics, before opening back up to the implications and power of a good sentence. This seems like a sensible structure, it\u2019s possible to come back to the forty or fifty pages at a later date, and dig into something again. However, even at only two hundred pages long, it does make certain passages or ideas hard to re-find. This is a problem easily remedied by scribbled underlinings and notes in the margin, but it is frustrating if you want to revisit something but aren\u2019t sure where exactly it is. I suppose this is the price of a more intuitive, rather than ontological structure for the book. The book is narrow in scope - the chapters aren\u2019t vastly different enough to be truly distinguishable. Each chapter is a meal best enjoyed whole, and not in bits. Even so, I would recommend no more than a chapter a day - a lot of these ideas need time to percolate.

+

Moran strikes a difficult balance here: does he act as provost for platitudes, which the reader must take and apply as she sees fit, or does he provide us with the certainty of syntax, edge-cases, and rules. Too far into generalities and you\u2019re not actually offering anything useful, and you risk sounding self-aggrandising and vague. Too far into the specifics you\u2019ve lost the more creative, or fresher, crowds. Reading, and to a lesser extent writing, are intuitive acts - by waylaying out readers and writers with rules, you\u2019re sucking the joy out of the acts. The best way I can can describe the effect of reading this book is the introduction of a little voice at the back of my head whenever I am writing, and sometimes when I am reading. The little voice chirps along to Moran\u2019s ideas of good writing: that we can\u2019t assume the reader is interested or invested, we must explain ourselves, we can use active voice, sentence length, and order of clauses (claus-der?) to make sentences clearer. Or conversely we could use our new found powers to obscure and bore.

+

Broader than that, Moran has given me an appreciation for the sentence. I wouldn\u2019t be so bold as to say I\u2019m never going to write a mediocre or bad sentence again in my life. That\u2019s obviously going to happen, probably daily. But when I put the book down (surprisingly long after I picked it up), I felt convinced that no single sentence should go into my writing un-interrogated. The sentence might not actually be the purest, platonic ideal of writing, but it\u2019s important. At the meta-level, I adore the careful consideration of something so singular. The result tells you about the object of study and the person doing the studying, so this book packs twice the delight. Learning the process is more actionable than learning the product. The result is one of the clearest, most actionable, and impassioned calls for better writing from someone who just wants there to be better writing. 4.5\u2B50

`; +}); diff --git a/.netlify/server/chunks/2021-02-06-things-i-learned-26-ae9245db.js b/.netlify/server/chunks/2021-02-06-things-i-learned-26-ae9245db.js new file mode 100644 index 0000000..379e667 --- /dev/null +++ b/.netlify/server/chunks/2021-02-06-things-i-learned-26-ae9245db.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_06_things_i_learned_26, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #26", + "author": "Thomas Wilson", + "date": "2021-02-06T00:00:00.000Z", + "draft": false, + "slug": "2021-02-06-things-i-learned-26", + "tags": ["things-i-learned"] +}; +const _2021_02_06_things_i_learned_26 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This heartening fact: Altruism, more specifically altruistic behaviour, is an action done (at cost) by an individual for the benefit of another individual. Why do humans, and other social animals, engage in altruistic behaviour? How does it makes sense on the evolutionary balance sheets? There is increasing evidence that altruism is an evolved, or more specifically phylogenetic, behaviour and that it is not learned. As social creatures, humans have an innate ability to empathise with each other. It\u2019s one of the psychological reasons behind what makes horror films scary and emotional films draining. We\u2019re not able to stop ourselves from identifying, and sharing, in the emotional turmoil and mortal dangers we see on the screen. Disney and Pixar have mastered making us feel things for non-human animated things, like toys, souls, and fish. We, individual humans, favour people who have been kind or altruistic to us and we neglect those who have not been. This gives an evolutionary preference to societies where cooperation and bonding is stronger or more common, and therefore where altruism is more prominent. (source, and PDF Download)
  • +
  • This cubic poop: The bare-nose wombat poops cuboid pellets. About one hundred little cubes every day - so they\u2019re like tiny geometric poop machines. Interestingly, the faeces of wombats in captivity are rounder than their wild-and-free counterparts. This could mean that poop shape is an indicator of overall health and wellbeing. The wombats are the only mammal that make not-round faeces, and to uncover how this even happens some scientists dissected a couple of wombats\u2019 intestines. Don\u2019t worry, at least one of them was accidentally killed by a vehicle, which makes me wonder if they had the study lined up first, or if it was an impromptu affair? Anyway, the cubic shape comes from the irregular thickness of the animal\u2019s intestinal lining. Faeces sits in the intestines for quite some time, while the gut compresses and compacts it to extract water and nutrients. Your guts do this too, by the way, which is cool but also gross to think about. What these wombats have that we (and every other mammal) don\u2019t, other than 10x cuter faces, is the ability to compact some parts of the poop harder and faster, and some parts slower and gentler. This difference, somehow idk, produces a shape which isn\u2019t a cylinder. Look, if you need some bleach for your mind, just google \u201Cbare nose wombat\u201D. Here, I\u2019ll do it for you. (source)
  • +
  • This Italian cyclist: Gino Bartali won the Gira d\u2019Italia (twice) and the Tour de France (once) before the Second World War, and then once again for each after the War. Because he was so well known, during the Second World War he was able to cycle long distances around Tuscany unmolested by newly-Nazi authorities who didn\u2019t want the bad press of arresting a local celebrity. Personally I think the Nazis could have made a couple of other, higher impact, decisions if they cared about their public image that much. During this time, Bartali ran messages, photographs for forged documents, and news of raids for the Italian and Jewish resistance groups in the area. In total, these groups helped about 800 Jews escape death, and Bartali himself hid a Jewish family in his cellar - allowing them to escape death. His pivotal role in the resistance at the time largely came to light after the death of Giorgio Nissim, a Jewish accountant from Pisa who died in 2000. Nissim kept details in his diaries. Bartali didn\u2019t speak openly about his role, even after The War ended. He\u2019s attributed the quote \u201CThe good is done, but it is not said. And certain medals hang on the soul, not on the jacket\u201D (though unfortunately I couldn\u2019t track down the exact source). (source)
+

What I\u2019ve had on rotation

+
  • Something New: Isles by Bicep (2021, EDM). I\u2019ve been stepping up my cycling training over the past couple of weeks. I\u2019m back on the turbo trainer for interval and sixty-to-ninety minute training sessions three or so days a week. What I\u2019m saying is there\u2019s a reason I\u2019ve got more into EDM this past couple of weeks, despite the fact that we\u2019re still in lockdown. This is a great, upbeat (pun intended), electronic album which isn\u2019t monotonous but stays optimistic enough for when the going gets tough and the tough get sweaty. (link)
  • +
  • Something Old: When This Is Over by Shad (2006, Hip Hop). This is a hip hop album with a heart of gold, full of good intentions, and little narratives. If you \u201Cdon\u2019t like hip hop\u201D then this might be an album to check out. There\u2019s little bragging, violence, or general gaucheness that some people associate with hip hop (not unfairly, to be honest). To me, Shad is more of a storyteller who chose Hip Hop music as his narrative. It was nice to rediscover this album a decade after I had it on heavy rotation circa 2011. Both myself and my taste in music have changed since then, but this stands up. (link)
+

Cool Articles

+

This week I\u2019ve found two beautifully designed, and well considered essays. Sometimes the stars align, and your inbox / random internet wanderings bring you some really beautiful pieces.

+
  • Newsletters by Robin Rendle. I love newsletters and the independent web. The web should be more about allowing people to do weird, expressive, niche things just because. Rendle outlines this much better than I can/do.
  • +
  • Designer as Writer by Stas Aki. (Best viewed on desktop). This is a stunningly designed essay/treatise on the similarities between design and writing. Namely that both are about communicating a clear message and understanding the reader/user. Aki riddles the article with quotes, photos, and examples. It\u2019s very good.
`; +}); diff --git a/.netlify/server/chunks/2021-02-09-utopia-avenue-4d3c6168.js b/.netlify/server/chunks/2021-02-09-utopia-avenue-4d3c6168.js new file mode 100644 index 0000000..9318d10 --- /dev/null +++ b/.netlify/server/chunks/2021-02-09-utopia-avenue-4d3c6168.js @@ -0,0 +1,58 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_09_utopia_avenue, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Utopia Avenue", + "author": "David Mitchell", + "score": 4.5, + "image": "utopia-avenue", + "slug": "utopia-avenue", + "book_review": true, + "date": "2021-02-09T00:00:00.000Z", + "finished": "2021-02-02T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "fantasy"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/David-Mitchell/Utopia-Avenue--The-Number-One-Sunday-Times-Bestseller/24371226" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/utopia-avenue/9780812997439" + } + ] +}; +const _2021_02_09_utopia_avenue = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Utopia Avenue is David Mitchell\u2019s latest piece of fiction in the meta-novel he is writing. Which is to say this book is set in the same mild-fantasy universe as several of his others. It follows the motley crew of musicians and management which form the titular rock/folk/pop band in London in 1967, including cameos from near every famous London-based musician of the time. I\u2019ve no strong attachment to the era or to early rock-n-roll music and the book never relied on nostalgia or knowledge. Mitchell does a fine job of creating a sense of a time of social and artistic revolution. Maybe it\u2019s because I read it eleven months into a global pandemic, but man\u2026 he really sold it to me. Despite the often dark and sometimes fantastical undertones of this book, it is foremost about people and their relationships. Romantic, platonic, and professional relationships to each other. Our connection to ideals and philosophies through the art that we make and consume (\u201Cappreciate\u201D sounds less destructive but also less intense) and how that connects individuals to groups to societies. So I guess this is a book about\u2026 everything?

+

This need to balance stories and dynamics at the individual, ideal, and population/crowd level is tough. It\u2019s a lot of plates to keep spinning. Or to mix metaphors it\u2019s a lot of cattle to herd. Mitchell mostly does a fine job, but every now and then somebody, some strand, some mention gets left behind and is picked up later, occasionally with a feeling of curtesy over curiosity. Giving space and attention to certain characters often rewards us, looking at you Jasper - you enigmatic guitar prodigy who spent time in a psych ward. Other times, characters flit between cast and side-character. At times, certain narratives felt simplified or condensed.

+

These possible shortcomings are redressed by the weaving of Utopia Avenue into Mitchell\u2019s broader shared universe. The supernatural-cum-fantastical elements in this book are rewarding in their subtleties, unanswered-ness, and existential consequences. Utopia Avenue is a book which left me with a sense of animism: that the world is alive. That the separation of human, world, soul, and other aren\u2019t as strict as we see them here in the west. It\u2019s the same feeling that Studio Ghibli films leave me with, and it is one which is uncommon in western media. Little surprise, then, that Mitchell\u2019s wife (Keiko Yoshida) is a native Japanese speaker, and they met in Hiroshima. I\u2019ve not done the requisite research to attribute these things together, however, maybe Mitchell was like this anyway and that\u2019s why he\u2019s so drawn to the Japanese culture. I digress.

+

The final act of Utopia Avenue is as mystifying and bewitching. A feat it shares with Bone Clocks, Mitchell\u2019s 2014 novel. What I love dearly is both the magical elements, and how carefully they are placed and rationed, so that nothing can simply be dismissed as \u2728magic\u2728.

+

The book feels optimistic about humans, and about our ability to create for and inspire one and other. This quality is what draws me endlessly to John Green, who has entirely nothing to do with this book or David Mitchell but who proudly beats the same optimistic tune over a din of (not unreasonable) pessimism. One, perhaps forced and on-the-nose, moment has the aforementioned Jasper (or possibly Mitchell, through Jasper) consider aloud in front of a press conference if music can change the world:

+

Which begs a question. \u201CWho or what influences the minds of the people who change the world?\u201D My answer is \u201CIdeas and feelings.\u201D Which begs a question. \u201CWhere do ideas and feelings originate?\u201D My answer is, \u201COthers. One\u2019s heart and mind. The press. The arts. Stories. Last, but not least, songs.\u201D Songs. Songs, like dandelion seeds, billowing across space and time.

+

Despite adoring Bone Clocks, I really struggled to get into Cloud Atlas (2004). But Utopia Avenue has reminded me of what I loved so much about Mitchell, and also how many of his books I have not read (six). Leaving a book feeling excited to read the author\u2019s existing body of work, despite previously failed attempts, is one of the finest endorsements of a book I can think of. Unfortunately it is a purely quantitative, personal review which isn\u2019t so translatable to others, but it is symptomatic. This book delivers worthwhile ideas with an unusually captivating language.

+

So I hope you read this book and it reminds you of the wonder of the world. Of the joys of creativity and human connection, and of how you can bend genres because they\u2019re there to serve curators not creators. Even if you\u2019ve read all Mitchell\u2019s work and hate it (but still find yourself here) then I don\u2019t know what I could say to dissuade you. 4.5\u2B50

`; +}); diff --git a/.netlify/server/chunks/2021-02-12-blog-redesign-changelog-48103e19.js b/.netlify/server/chunks/2021-02-12-blog-redesign-changelog-48103e19.js new file mode 100644 index 0000000..b033cb6 --- /dev/null +++ b/.netlify/server/chunks/2021-02-12-blog-redesign-changelog-48103e19.js @@ -0,0 +1,48 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_12_blog_redesign_changelog, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Website Design 2.0 Changelog", + "author": "Thomas Wilson", + "date": "2021-02-12T00:00:00.000Z", + "draft": false, + "tags": ["redesign", "technical"], + "slug": "2021-02-12-website-design-2-0-changelog" +}; +const _2021_02_12_blog_redesign_changelog = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I\u2019ve redesigned the blog. This post just covers the technical whats and hows of it all.

+

What\u2019s changed ?

+
  • New Dark theme colours: Look around. Look at this dark purply-grey. Look at the same brand-orange, and the deliciously crisp white text. New colours!
  • +
  • 100% More Portfolio: I completely revamped the homepage so that it actually showcases my writing and my work. The content isn\u2019t hidden behind anything anymore.
  • +
  • 50% Less Bio: I\u2019ve shortened bios and text on the home page, they made the site feel a lot more static and like a placeholder site than I wanted.
  • +
  • Blog Series Highlight: I\u2019ve highlighted, and made accessible, certain series on my blog (like my \u201CThings Week I Learned\u201D series). You can now filter for just these posts on the blog page.
  • +
  • Personal Brand: The site sizzles a little bit more with personal brand and little \u201Cmoments\u201D in the UI. It\u2019s a \u201Cwebsite experience\u201D. This includes little self-aware UI labels which seem very post-modernist and bring me joy.
  • +
  • Tags: I added tags to blog posts. They don\u2019t do anything right now though lol.
+

Yeah but how?

+

I bloody love talking about workflows and processes. By brevity here is a mercy and a kindness:

+
  • Design: Any and all visual design was done in Figma. I bloody love Figma.
  • +
  • Code: This site was, and remains, a static site built with Gatsby (and therefore on React and GraphQL)
  • +
  • Deployment: Netlify, and they do a stunning job.
  • +
  • Writing: Everything is Markdown (markdown is cool). I write with iA Writer for longer pieces (like this) and Obsidian for research and emergent writing.
`; +}); diff --git a/.netlify/server/chunks/2021-02-13-things-i-learned-27-17f83b3f.js b/.netlify/server/chunks/2021-02-13-things-i-learned-27-17f83b3f.js new file mode 100644 index 0000000..e9cbee6 --- /dev/null +++ b/.netlify/server/chunks/2021-02-13-things-i-learned-27-17f83b3f.js @@ -0,0 +1,40 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_13_things_i_learned_27, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #27", + "author": "Thomas Wilson", + "date": "2021-02-13T00:00:00.000Z", + "draft": false, + "slug": "2021-02-13-things-i-learned-27", + "tags": ["things-i-learned"] +}; +const _2021_02_13_things_i_learned_27 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This seventeenth century petition: In 1674 in England, a pamphlet was made and published, titled The Women\u2019s Petition Against Coffee. The women (or alleged women, we don\u2019t actually know who wrote this) were fighting against the new trend of coffee houses in London, which had arrived some time in the 1650s. These proto-caf\xE9s became political and intellectual hubs in London, just as they had in other parts of the world, where men would meet and discuss all sorts of dangerous things like politics and science. The result was a bunch of intellectual, babbling, effeminate, arty-farty, pull-yourself-together-and-get-in-with-it men who couldn\u2019t muster so much as an ounce of passion. Or so say the authors of the pamphlet, who lamented that when a wife of a coffee house attendee \u201Capproaches the nuptial bed, expecting a man that \u2026\xA0should answer the vigour of her flames, she on the contrary should only meet\xA0a bedful of bones, and hug a meager useless corpse\u201D. Ouch. Drinking coffee (unlike it\u2019s manly brother, ale) was wasting away their husbands. The chances that the monarchy at the time were trying to iron out the crinkles caused by a civil war several years previous probably has little or nothing to do with this desire to keep people away from places where ideas could be discussed openly. We also suspect that sex workers at the time found custom in coffee shops, so maybe your man\u2019s coming home already sexually satisfied and blaming it on all the heady ideas of democracy he\u2019s been ingesting with William and Frances at the pub. (source)
  • +
  • This maybe-gay-maybe-brothers Ancient Egyptian duo: About 4,500 years ago, during the fifth dynasty of Ancient Egypt Khnumhotep and Niankhkhnum were the royal manicurists. So I guess part one of this thing I learned is that four thousand years ago the kings of Egypt had chief manicurists who would oversee the lesser manicurist. The shared tomb of Niankhkhnum and Khnumhotep was uncovered in 1964. The fun fact here being \u201Cshared\u201D. Ancient Egyptians buried people together so they could accompany each other in the afterlife. Often families would be buried together, with their servants if they had any. Because obviously one mortal lifetime of servitude is but an entr\xE9e to an eternity spent at the beck and call of a rich Ancient Egyptian family. Niankhkhnum and Khnumhotep were both dudes, by the way, in case you couldn\u2019t tell from the names. Depictions of the pair found within the tomb suggest the two could have been lovers (they\u2019re embracing, face-to-face), which would have made them the oldest recorded same sex couple. Some historians have argued they were brothers, as both are depicted in some frescos with wives a children - all of whom sit forlorn in the background of the frescos, playing second fiddle to the men. Also having a wife and children doesn\u2019t mean they weren\u2019t\u2026 anyway. Honestly, we\u2019ll never know unless we all end up in the Ancient Egyptian afterlife, in which case I\u2019ll hunt down these guys, get my nails did, and get the tea. (source)
  • +
  • This Stuart Little Trivia: On one of the walls of the set for 2000\u2019s Stuart Little, a banger of a film about a family who adopt a talking mouse, there is a painting. This painting. When Gergely Barki, a researcher at Hungary\u2019s National Gallery, watched this film in 2009 (with his daughter at Christmas, or so he insists) he noticed this painting and nearly immediately recognised it as one which disappeared from the gallery in the 1920s. Barki had only ever seen it before as a faded black-and-white photograph from a 1928 exhibition, so props to this man for remembering something so well when I keep buying noodles as part of my grocery shop, forgetting I have three unopened packets at home already. The piece, Barki knew, was R\xF3bert Ber\xE9ny\u2019s Sleeping Lady with Black Vase, an Avant-Guarde. Barki started sending e-mails off to set and production crew for the movie in a bid to find the piece. A meagre two years later, Barki heard back from a set designer who had purchased the painting for cheap at an antiques market in Pasadena, California, specifically for the Stuart Little set. After the wrap, she had taken the piece and hung it in her home before selling the painting to a private collector, who subsequently returned the painting to Hungary to give it back to the National Gallery there. I\u2019m joking, obviously, it was sold at auction for \u20AC230,000. (source)
+

What I\u2019ve had on rotation

+
  • Something New Medicine at Midnight by Foo Fighters (Rock, 2021). Dave Grohl, am I right? At only 30 minutes, this short album is punchy, with the distinctive vocals and sonic styling of Foo Fighters. I like the band, but I\u2019m not an authority on them or the genre - so from a casual visitor to the Fields of Rock take a very uncontroversial opinion: this is a good album. (links)
  • +
  • Something Old Donuts by J Dilla (2006, Hip Hop). J Dilla was one of the most influential figure in early hip hop in Detroit, if not the world. He pioneered and pushed the boundary of sampling as a musical instrument, finding, shifting, and relaying musicality from samples. Vox did a superb video on him. This album is a great way to connect with what was once the forefront of hip hop. J Dilla died three days after the release of this album (aged 32), and to think of the lost talent and beats is pretty heartbreaking. (links)
`; +}); diff --git a/.netlify/server/chunks/2021-02-17-closures-in-swift-b4cbc2f3.js b/.netlify/server/chunks/2021-02-17-closures-in-swift-b4cbc2f3.js new file mode 100644 index 0000000..fbc9160 --- /dev/null +++ b/.netlify/server/chunks/2021-02-17-closures-in-swift-b4cbc2f3.js @@ -0,0 +1,93 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_17_closures_in_swift, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Swift Closures: Inline functions explained by a web developer", + "author": "Thomas Wilson", + "date": "2021-02-17T00:00:00.000Z", + "draft": false, + "slug": "2021-02-17-closures-in-swift", + "tags": ["swift"] +}; +const _2021_02_17_closures_in_swift = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Hi, I\u2019m Thomas. I\u2019m a frontend engineer who\u2019s learning swift. Let\u2019s talk about closures in Swift from a very (very) introductory level. I\u2019m assuming you\u2019ve got some familiarity with JavaScript. You should definitely check out Apple\u2019s documentation on Closures, it\u2019s so much better than this page but also, like, less funny?

+

Closures are inline function definitions.

+

We have inline functions all over the place in JavaScript. Callback functions, including those in promises, are often declared in JavaScript:

+
${`// Ever written an express routers?
+router.use('/users', (req, res, next) => { .. })
+
+// Ever write a promise?
+fetch("https://www.google.com").then((res) => { .. })`}
+

Like JavaScript, Swift has functions as a first-class citizen. That means they can be passed around like any other variable. That\u2019s pretty cool, and if you come from a pure JS background you might not realise it. You might think it\u2019s pretty annoying. But it\u2019s not. Try filtering a dataframe into a subset in Python using Pandas without the filter-like function syntax (don\u2019t @ me).

+

We use closures in Swift in exactly the same use case: when we need to pass a function as an argument to a function. For example, if we are passing a custom sort, map, or sorted function on an array.

+

In the same mental model that React uses, a SwiftUI View is like a React component: it\u2019s fundamentally a function: f(state) => ui - UI is a function of state.

+

Understanding Closures in swift will help you write, and read, SwiftUI examples.

+

The name\u2019s a little confusing. In JavaScript a closure is the scope at which a function is declared and its relationship to the surrounding variables. Coming from JS, I had a little trouble getting my head around them.

+

Ground 0: Function Declarations

+

Defining inline, full-blooded functions in Swift is pretty standard, and could probably be intuited by any engineer with one or two languages under their hat:

+
${`func multiply(number: Int, by:Int) -> Int {
+	return number * b
+}`}
+

It would be perfectly valid syntax to pass this function around by simply referencing its identifier (multiply).

+

Removing some syntax

+

But what if we don\u2019t want to have to declare named functions everywhere. Especially if we\u2019re literally just going to use it once?

+

In JavaScript you define the function inline with the same syntax as you would anywhere else. BUT NOT IN SWIFT. Why? I don\u2019t know, friend, by let\u2019s explore the what not the why first.

+

Swift comes with a set of syntactical sugar for declaring closures. Syntactical sugar is a way of making code shorter or more readable. Syntactical sugar often replaces boilerplate or verbose code, and results in identical functionality to its un-sugared sibling.

+

This syntactical sugar looks like:

+
${`	{ (parameters) -> ReturnType in
+		// expression
+	}`}
+

Let\u2019s give a real simple example. We\u2019re going to take an array of Int and convert it to an Array<String>:

+
${`let strings: Array<String> = [1,2,3,4,5].map({ (n: Int) -> String in
+	return "The number is (n)"
+})`}
+

The in keyword

+

This syntax looked odd to me. The key (pun intended) to me grokking it was understanding the in keyword. Typically I have only seen this associated with iterators (in languages like python and JS):

+
${`# This is Python code
+for name in list_of_name:
+	print(f"Hello, {name}")`}
+

In Closures, in Swift, the in keyword signifies that we\u2019ve reached the end of our parameter and return type. Everything after the in is the action function expression.

+

Implicit Types for Even Less Syntax

+

You better believe that\u2019s not all the syntactic sugar. There\u2019s still stuff we\u2019re going to get rid of.

+

Once we declare types in one place, e.g. in a variable, generic, parameter, then we don\u2019t need to duplicate that typing. We can but we don\u2019t have to.

+

Swift is able to find the implied types elsewhere in the code, and therefore we can remove them in the closure.

+

In the following example the boastfulString variable is declared as the Array<String> type, so the map function doesn\u2019t need to be told twice:

+
${`let boastfulStrings: Array<String> = [10,20,30,40,50].map( { n in return "I have (n) tacos!"})`}
+

By using implicit types we can get rid of two redundant parts of the closure declaration.

+
  • The surrounding parentheses for the parameters: (n: Int) becomes n). We can do the same with multiple parameters: Say we had an argument that took three parameters: (name: String, age: Int, averageScore: Float) .. could become name, age, averageScore ..

  • +
  • The return type of the closure: We know the function needs to return us a String, it\u2019s in the variable declaration. So (n: Int) -> Int in .. can become n -> ..

+

Swift is super ready for you to give it an Array<String> and will actually get pretty mad if you dont\u2019. You\u2019ll run into compile-time errors with anything else.

+

Implicit Returns

+

Man, talking of redundancies, that return doesn\u2019t look like it\u2019s doing much on that one line there. JS, Ruby, and Rust all have implicit return types - and so does Swift. That means you don\u2019t need to use the return keyword to tell Swift \u201Cthis is the bed that the function should hand back\u201D.

+

This is more syntactic sugar: we\u2019re choosing conciseness and simplicity over explicit and verbose. Having return or omitting it in this example does exactly the same thing. You don\u2019t have to like this, or us it in your code. It\u2019s your choice, but you should definitely know about it. Also it\u2019s probably useful in those scenarios where you just need something to work:

+
${`let boastfulStrings: Array<String> = [100, 150, 200].map( { n in "I have (n) taco!" })`}
+

Look how concise that statement is.

+

Shorthand Argument Names: spend those \\$

+

But we can be more concise.

+

What else can we get rid of?

+

That named parameter, n:

+
${`let regretfulStrings: Array<String> = [2,4,6,8].map( { "I ate ($0) too many tacos ):" })`}
+

These are shorthand arguments. Where $0 refers to the first argument in the function. $1 to the second argument, $2 to the third\u2026

+

Now we\u2019re really favouring conciseness over explicitness.

`; +}); diff --git a/.netlify/server/chunks/2021-02-19-things-i-learned-28-9e389556.js b/.netlify/server/chunks/2021-02-19-things-i-learned-28-9e389556.js new file mode 100644 index 0000000..6c29fbc --- /dev/null +++ b/.netlify/server/chunks/2021-02-19-things-i-learned-28-9e389556.js @@ -0,0 +1,42 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_19_things_i_learned_28, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #28", + "author": "Thomas Wilson", + "date": "2021-02-19T00:00:00.000Z", + "draft": false, + "slug": "2021-02-19-things-i-learned-28", + "tags": ["things-i-learned"] +}; +const _2021_02_19_things_i_learned_28 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This collective noun: If I was to make a list of small-talk and first date conversation topics it would go something like this: food, the tube, podcasts or books, and then collective nouns for animals. How many times have I been told the words \u201Ca parliament of owls\u201D in my life? I don\u2019t know, but I love re-remembering every time. This week I learned a new collective noun, and I\u2019m sorry if you heard this one already: a scurry of squirrels. Of also a \u201Cdray\u201D of squirrels. But I think \u201CScurry\u201D is cuter and definitely deserves the headline. (source)
  • +
  • This early gay selfie: This week I came a picture of some early gay rights activist. Two handsome Victorian looking gentlemen holding a sign which read \u201CNot married but willing to be\u201D. Which is beautiful in sentiment and heartbreaking in reality. I think it popped up on one of my social feeds, and I hunted it down. It looks like the photo re-surfaced last year when Hugh Nini and Neal Treadwell published Loving : A Photographic History of Men in Love 1850s-1950s (buy it on Hive (UK)). The Guardian took some of the photos from this piece and published them with some nice art direction on their website. The two un-named gentlemen I saw were photographed circa 1900s in Provenance, USA. Also of note is a very early selfie, entitled \u201CIn the mirror\u201D - it\u2019s a photograph of two men taken in a mirror with a simply darling 1900s camera on the table between them. In a time when they couldn\u2019t have photos taken or developed by anyone (what with homosexuality being illegal), it makes a lot of sense. (source)
  • +
  • This colour: The browser has some default colours, like black or blue. Some of them are a little odd, like indianred or mediumquamarine, but they\u2019re there. You can use whatever colour you want in the browser (and people do), but you have to define them with computer-readable code like #BD1A0F or rgb(15,189,126). So being a human-readable colour name isn\u2019t the usual or standard approach. CSS comes with rebeccapurple. This colour, which was the colour used in the original branding for Twitch, the online streaming platform, is named in memory of Rebecca Alison Meyer, the six year old daughter of Eric Meyer. Eric is one of the pioneers in standardising CSS, one of the three truly foundational and essential web technologies. This particular shade of purple was Rebecca\u2019s colour. After Rebecca passed away from brain cancer, this colour was added to the CSS standard, and so comes with every browser, as a beautiful little reminder and honorary to Rebecca. (source)
  • +
  • This French translation: You know pie charts? The worst form of data visualisation (@ me you cowards). In French these can be translated to diagramme circulaire (formal) or camembert (informal). Yeah, it\u2019s a funny joke: ha ha the French love cheese they saw a graph and saw cheese *twiddles moustache*. But we looked at exactly the same thing and saw pie. What does that say about us? Would you rather have a pie or some fresh bread with a baked camembert and garlic? Learning this fact made me happy, and then made me sad that my culture just doesn\u2019t love camembert like the French do. (source)
  • +
  • This health advice from Leondardo: One of the most famous figures of the Italian renaissance, Leonardo was one cool guy. He had a pretty varied mental diet: anatomy, fluid dynamics, natural science, art (obviously), inventing underwater breathing gear, optics, engineering, and so on. In one of his notes he detailed a mixture of mental and physical advice for staying healthy. Go and read it. The advice is surprisingly modern, reasonable, and holistic. He advises to remain standing after eating, which is good advice for weight loss. \u201CBeware anger and avoid stuffy air\u201D, the latter of these points is something with a surprisingly detailed history. Similarly he advocates to \u201Crest your head and keep your mind cheerful\u201D. Leonardo understood well that our physical and mental health, our sleep, food, and physical activity all contribute to making us happier. That\u2019s not to say it\u2019s all good advice: he calls medicine \u201Cill advised\u201D, says exercise shouldn\u2019t be \u201Ctoo strenuous\u201D so as with everything, take it with a punch of salt. (source)
+

What I\u2019ve had on Rotation

+
  • Something New: Dark Days by Yard Act (2021, Indie Rock). This is a four track EP from a new-ish band from Leeds, UK. It\u2019s punk, and genuinely quite funny, painting a really rich portraits of characters in sometimes-singing-sometimes-talking tones. It reminds me a little bit of The Streets in the lyric/narrative blurred line. I am really excited to see the band drop an LP! (links)
  • +
  • Something Old: Bits of Naaz by Naaz (2018, Pop). This fresh, clean pop sound sounds like happier times to me. It\u2019s lovely songwriting and and pleasing melodies. I\u2019m always a fan when someone contrasts obviously drum-machine beats over more organic samples and Naaz does that nicely throughout this album. (links)
`; +}); diff --git a/.netlify/server/chunks/2021-02-20-clubhouse-after-48-hours-55ae4f20.js b/.netlify/server/chunks/2021-02-20-clubhouse-after-48-hours-55ae4f20.js new file mode 100644 index 0000000..5463af8 --- /dev/null +++ b/.netlify/server/chunks/2021-02-20-clubhouse-after-48-hours-55ae4f20.js @@ -0,0 +1,50 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_20_clubhouse_after_48_hours, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Opinions from 48hr on Clubhouse", + "author": "Thomas Wilson", + "date": "2021-02-20T00:00:00.000Z", + "draft": false, + "slug": "2020-02-20-opinions-from-48hr-on-clubhouse", + "tags": ["clubhouse", "social-media"] +}; +const _2021_02_20_clubhouse_after_48_hours = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Clubhouse is a new audio social network platform for iOS. It\u2019s basically like having a moderated voice-only Zoom call. The entire network is largely three entities:

+
  1. Users: Human beings who use the app. Clubhouse have taken a pretty hard line on non-human (e.g. business) accounts.
  2. +
  3. Rooms: Pre-scheduled or impromptu virtual rooms that users can go in. Rooms are where the conversation happens. Only users on the stage can speak to the room. One or many people can be speaking in a room at any one time. Rooms are moderated by a user, who can add or remove users from the stage. Their role is to keep the conversation on track and civil. Everyone else in the room can hear the person/people speaking on the stage. If you\u2019re not on the stage, you can\u2019t be heard.
  4. +
  5. Clubs: Are groups of users. They\u2019re like Facebook groups or group DMs.
+

For the past couple of days I\u2019ve been dipping into some clubhouse rooms. I\u2019ve heard discussions on sustainability between small UK businesses, startup advice for new founders, large investors talking about the ecosystem, hiring fairs, language learning, news discussion, and random chats.

+

The audio-only format is interesting and unique. It\u2019s part podcast, part zoom call, part audio-only Twitter thread. I have really enjoyed the relaxed, low-effort format of this. It feels alive and human, but maybe that\u2019s my socially-deprived Covid brain talking. I\u2019ve been very impressed by people\u2019s civility (it is indeed still early days and invite only), and I\u2019ve seen moderators do a good job of keeping people on topic, and stopping spam. I do worry that there\u2019s potential for spam and un-civility.

+

I don\u2019t know where this new audio-only format, or Clubhouse specifically is headed. It may very well be a flash in the pan.

+

I have been so impressed by people\u2019s generosity. People have offered sincere and useful advice to startup founders, posed interesting questions, and disagreed with (at least some) civility and generosity.

+

I wonder how much of this is because the format is new and the audience is self-selecting. I think there is something about the medium:

+
  1. It\u2019s engaging: Humans are social creatures. We\u2019re wired to like the sound of conversations and storytelling. It\u2019s how we learn and remember a lot of information. Having the voice of the person making the statement, and not a plaintext tweet (and maybe gif or emoji) does draw attention, and is just easier to interpret.
  2. +
  3. It\u2019s low activation energy: Having a conversation is the natural and easy thing in the world, so I think people are willing to give more, and more detailed, information. You can\u2019t stop to double-check and research (and you\u2019re not expected to), and you\u2019re not backspacing over your replies to make
  4. +
  5. It\u2019s synchronous: Twitter, Instagram, and Tik Tok will always bet here with content to present you when you\u2019re back. If you miss something on Clubhouse it\u2019s gone. When life returns to not-lockdown, this might be incredibly impractical. For the now, a world without meet-ups and informal gatherings, it does a surprisingly good job of re-creating these feelings.
  6. +
  7. It can be on in the background: If I\u2019m working on something monotonous which requires my attention sometimes but not always (re-plotting plants, inbox clearing, unclogging my shower drain) Clubhouse has been great to have on the background. My previous go-to here would be Podcasts, but I\u2019ve become increasingly selective about what I\u2019m listening to and why. There isn\u2019t that pressure with Clubhouse.
+

I\u2019m interested to see where this goes. It does have the feel of a side hustle. It\u2019s not low maintenance like Tik Tok or Instagram - they\u2019ll put videos in front of you and just ask you to swipe up and down. Will it become like LinkedIn, or will it become something a bit freer? Is it the right time for audio social media, is it even a good idea? Vine failed in the 2010\u2019s but TikTok is bloody huge now.

+

With everything, it comes down the quality of the content. That requires there to be excellent club and room moderation tools. If the team want growth, they\u2019ll need to work on discoverability: finding people, clubs, and rooms with certain areas needs to be easier.

+

I\u2019ve been doing this for two days, so I\u2019m sort of an expert.

`; +}); diff --git a/.netlify/server/chunks/2021-02-26-things-i-learned-29-71d9ce32.js b/.netlify/server/chunks/2021-02-26-things-i-learned-29-71d9ce32.js new file mode 100644 index 0000000..e69d65b --- /dev/null +++ b/.netlify/server/chunks/2021-02-26-things-i-learned-29-71d9ce32.js @@ -0,0 +1,47 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_26_things_i_learned_29, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #29", + "author": "Thomas Wilson", + "date": "2021-02-26T00:00:00.000Z", + "draft": false, + "slug": "2021-02-26-things-i-learned-29", + "imageUrl": "preview-images/29.png", + "tags": ["things-i-learned"] +}; +const _2021_02_26_things_i_learned_29 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This lineage of cats: Chartwell House, in Kent, England, was the home of Winston Churchill. It\u2019s now owned and operated by the National Trust, a British institution, allowing visitors to see the gardens and houses. During Churchill\u2019s life, he had a marmalade (white and ginger) cat, called Jock. A few months after Chartwell House was handed over to the National Trust by the Churchill family, the family made the request that there always be a marmalade cat with a white bib and four ginger paws. Presently, Jock VII (picture) reigns the house, while Jock VI (picture) is living in a peaceful retirement with one of the house\u2019s staff. The public life wasn\u2019t befitting the older gentleman, so the sprightly Jock VII has taken the public-facing duties, allowing his predecessor to take the rest he deserves. (source)
  • +
  • This fact about smartphones: Smartphones are hella distracting, y\u2019all. Over the past couple of weeks, I\u2019ve been making a special effort to reduce how much I allow myself to be distracted during work (and other time). We all know that deep work requires uninterrupted time and concentration but that\u2019s so\u2026 boring. So not fun. And our phones really want our attention. Or to be more accurate, some of the biggest and richest companies in the world are employing some of the cleverest people alive to make us want to spend more of our time, more often, on apps and platforms. And it\u2019s working, Instagram is very relatable. In some research which examined the effect of even being near your phone, the researchers found a 10% reduction on working memory (i.e. how many things can you hold in your immediate attention and memory) and Fluid Intelligence (your ability to solve novel problems, independent of previously acquired skills). This was when the participants left their phone in their bag, and were uninterrupted by it, compared to when they were asked to leave it in another room. (Summary link and DOI: 10.1086/691462)
  • +
  • This board game: CoraQuest is an adorable co-op fantasy tabletop game for up to four people. It was created by a father-and-daughter duo Dan and eight-year-old Cora during the Covid lockdown in the UK. It initially started as a homework project, which allowed Dan to encourage his daughter to do art, creative writing, maths, and computing but evolved into a fully fledged game. If I can step in here a minute and preach the importance of project-based learning\u2026 guys it\u2019s important and it\u2019s practically the only kind of learning we do once we leave school so why is it never really done in school? Dan, who has been a gamer and D&D enthusiast, was able to offer support and guidance to the team, and shared it with other play testers and families during the development. Both families and other game developers ended up pitching in advice, feedback, and even some artistic assets. How encouraging this must have been for Cora! The end result to all this is a Kickstarter campaign which raised \xA3130,000 more than its \xA312k target, being supported from over 5,000 individuals. This is such a wholesome story, my goodness. (source)
  • +
  • This fourteenth century witchcraft accusation: Alice Kyteler was the first person in Ireland to be condemned of Witchcraft. The accusations against Alice ran from spiritual (denying the Christian faith and attempting to overpower the church) to corporal (murdering three husbands) to somewhere in between (having a sexual affair with a demon). I\u2019m actually pretty sad Kyteler didn\u2019t leave a memoire behind. Alice\u2019s only real sin seems to be a particular taste in men, specifically rich money lenders: she just kept marrying them until they died. Which they did, three times with three separate men. And then she\u2019d marry another one (who also died, more likely than not). What I will say is that at some point around the untimely death of your second and very rich husband, people are going to start getting suspicious. Especially in small town Ireland in the the 1320s. By the time her fourth husband started falling ill, people were pretty suspicious and so naturally accused her of witchcraft. Nothing so fortunate may happen to a woman who is not a witch, so the church said. What followed was a protracted and political attempt to convict Kyteler. Given that she had become so socially prominent (and rich, because of those dead husbands), accusing her and taking her in for questioning was a very difficult affair. Like impeaching someone. The bishop in charge of convicting her was waylaid and even imprisoned while he tried to make the formal accusations. Say what you like about Kyteler (like \u201Cthis woman is trying to corrupt good Christian men by selling them love and hate potions\u201D, true story) but she wasn\u2019t a powerless fool. After several months, the church kidnapped and tortured one of Kyteler\u2019s servants (Petronilla de Meath), who confessed to witchcraft and implicated Kyteler in the acts. Let\u2019s not ask how using torture to extract (almost certainly fake) confessions gives you the moral upper hand. It was a simpler time. Kyteler high-tailed it out of the historical records after that, so it was likely that she was never caught. If she was captured and killed the church would have gloated all over the historical record. She may have fled to England, what a story! (source)
+

What I\u2019ve Had on Rotation

+
  • Something New Super Monster by Claud (2021, Pop). I don\u2019t know where this new wave of pop has come from. I\u2019d like to say Covid\u2019s had us all making music in our bedrooms for the past year but I think we\u2019re starting to hear from people who\u2019ve been making music in the bedroom for the last 4-5 years. Gen Z. I\u2019m talking about Gen Z. I\u2019m new to Claud, their music has a fresh light pop vibe, which is great as we\u2019re coming into spring. They\u2019re also signed to Phoebe Bridger\u2019s Saddest Factory record label, which is a good thumbs up for me. (links)
  • +
  • Something Old Poverty\u2019s Paradise by Naughty by Nature (1995, Hip Hop). It\u2019s old school hip hop, and the intro skit track starts with the sound of a live crowd which we all miss. It even gets better from there, which is great too. This is a real \u201990s New York Hip Hop vibe, drum machines, reverb, and Nas-style horn sample sequences. They rhyme \u201Ceverybaaaaady\u201D with \u201Cpaaaaaahrdy\u201D and tell you to clap your hands but still have a gritty quality to them. (links)
+

Cool Articles

+
  • This tweet from weetabix. A light-hearted tweet that I think did the rounds a few weeks ago. Truly horrifying, I\u2019m not okay.
  • +
  • Shit\u2019s Broken: Why we need mindful notification and how to design them by Clo S for This Too Shall Grow. The attention economy is a good way to think about, and make better decisions in, the modern world. It\u2019s easy to forget about because people and companies are designing things to stop you thinking about it. Sorry to get all tinfoil hat here. This article was a nice reminder about understanding what is important when all our apps and platforms are telling us that they alone are important. I particularly like this quote from Clo, which I think summarises the problem nicely: \u201Cthe LinkedIn announcement that someone you don\u2019t know started a new job, are given the same importance as an email from your client saying they accepted your budget\u201D. The author goes on to talk about how you can just go ahead and turn off anything that isn\u2019t important. And if you\u2019re involved in making products, design mindful notifications that align the urgency and prominence of a notification with that of its content.
+

Fun Things

+
  • I Miss my Bar. It\u2019s a dark-noise style machine but with bar sounds. Put it on and pretend you\u2019re outside your own house.
`; +}); diff --git a/.netlify/server/chunks/2021-02-27-github-actions-xcode-tests-b4c7e20c.js b/.netlify/server/chunks/2021-02-27-github-actions-xcode-tests-b4c7e20c.js new file mode 100644 index 0000000..25e3e9f --- /dev/null +++ b/.netlify/server/chunks/2021-02-27-github-actions-xcode-tests-b4c7e20c.js @@ -0,0 +1,148 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_02_27_github_actions_xcode_tests, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "How to run Xcode tests for a SwiftUI iOS codebase with GitHub Actions", + "author": "Thomas Wilson", + "date": "2021-02-27T00:00:00.000Z", + "draft": false, + "slug": "2021-02-27-github-actions-xcode-tests", + "tags": ["swift", "github-actions"] +}; +const _2021_02_27_github_actions_xcode_tests = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Tl;dr

+
  1. Make sure you\u2019ve got a repo on GitHub.
  2. +
  3. Make sure you\u2019ve got at least one set of tests in your Xcode codebase.
  4. +
  5. Create the file below in yourproject/.github/workflows/main.yml:
  6. +
  7. Replace the yourprojects and YourProjects with your file name
  8. +
  9. git add .github/workflows/main.yml && git commit -m "Add test GitHub action" && git push
+
${`# Run My App's tests whenever someone pushes to `main` or creates a PR into `main`
+
+name: CI
+
+on:
+  # Triggers the workflow on push or pull request events but only for the main branch.
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+
+# We're only going to have one job, `test` but you can add this
+jobs:
+  test:
+    runs-on: macOS-latest
+    steps:
+	    # Checkout the code to the working directory
+      - uses: actions/checkout@v2
+      # Install xcbeautify so the logs are human-friendly
+      - name: install xcbeautify
+        run: brew install xcbeautify
+	    # Run the tests
+      - name: Run the xcode tests
+        run: xcodebuild clean test -project YourProject.xcodeproj -scheme YourProject -destination "platform=iOS Simulator,name=iPhone 12" | xcbeautify
+
+`}
+

What are Github Actions

+

They\u2019re bits of code you write which are executed whenever something happens on your GitHub repo. These bits of code can do whatever (they\u2019re just functions that run on a container), like:

+
  1. Run the tests in your repo (what we\u2019ll be doing today)
  2. +
  3. Build an artefact from source code then publish that to a directory
  4. +
  5. Send out an e-mail or hit a web-hook whenever something happens
  6. +
  7. Build your static site and upload it to S3, GitHub pages, or wherever.
+

If you\u2019ve used other tools, GitHub actions are like TeamCity, CircleCI, Jenkins, or any other CI/CD pipeline tool, but built right into GitHub. If you\u2019ve not heard of, or used those tools, I explain a bit more about it below.

+

The working parts

+

We don\u2019t actually write \u201Cactions\u201D, we write workflows, which contain one or more jobs, which contain one or more steps.

+

The details for a single workflow is written in yaml, as common plaintext format used by a lot of DevOps tools.

+

We put the yaml file in yourproject/.github/workflows/workflow-name.yml where yourproject is the root directory of your project and workflow-name is the name you wish to give the workflow.

+

There are three root-level yaml properties we\u2019re going to set:

+
  1. name Is the human-readable name for the entire workflow. Call this \u201CCI\u201D or \u201CRun all tests\u201D or \u201CSend e-mail\u201D.
  2. +
  3. on configures what exactly needs to happen for this workflow to run. By default, every job and step will run on every event.
  4. +
  5. jobs Is a list of the jobs we\u2019ll be doing. In this example there\u2019s just one: running the tests
+
${`name: CI
+on:
+  # Triggers the workflow on push or pull request events but only for the main branch.
+  push:
+    branches: [main]
+  pull_request:
+    branches: [main]
+jobs:
+test:
+runs-on: macOS-latest`}
+

Not how we\u2019re telling the test job that we\u2019re going to run on macOS-latest. Github gets us a container running that environment, which is cool.

+

Checking out the code so we can access it in our tests

+

By default, a job in a GitHub action just gives us an empty container, so we need to tell it to copy the code into our current working directory.

+

There\u2019s an easy way to do that: the checkout action is a third-party GitHub action that checks out our current working branch to the current working directory. Here are the Checkout docs.

+

By adding the following we make sure we have access to our code:

+
${`jobs:
+  test:
+    runs-on: macOS-latest
+    steps:
+	    # Checkout the code to the working directory
+      - uses: actions/checkout@v2`}
+

Installing xcbeautify

+

The default Xcode logs are horrible: they\u2019re verbose and unintelligible. Xcbeautify is a CLI tool that formats them to give us more readable useful information.

+

Luckily the macOS-latest platform comes with homebrew, the MacOS package manager, already installed, so we just need to tell our test job to install it:

+
${`jobs:
+  test:
+    runs-on: macOS-latest
+    steps:
+	    # Checkout the code to the working directory
+      - uses: actions/checkout@v2
+      - name: Install xcbeautify
+	      run: brew install xcbeautify`}
+

This step in our job has two things:

+
  1. name is a human-readable name, useful for us and the UI in GitHub
  2. +
  3. run is the thing you want to type onto the CLI. When that\u2019s done, the job will move on to the next step
+

Run the Test

+

The last step in the job is to run the tests using the xcodebuild CLI tool. This is actually pretty easy and simple, just make sure you clean-up the names and details in the script below.

+

Node how we\u2019re piping (i.e. the | character) the results from xcodebuild through the xcbeautiful command. That\u2019s a unix-ism, it\u2019s pretty powerful (or so I\u2019m told, I\u2019m just a frontend engineer here).

+
${`jobs:
+  test:
+    runs-on: macOS-latest
+    steps:
+	    # Checkout the code to the working directory
+      - uses: actions/checkout@v2
+      # Install xcbeautify so the logs are human-friendly
+      - name: install xcbeautify
+        run: brew install xcbeautify
+	    # Run the tests
+      - name: Run the xcode tests
+        run: xcodebuild clean test -project YourProject.xcodeproj -scheme YourProject -destination "platform=iOS Simulator,name=iPhone 12" | xcbeautify`}
+

Commit, baby

+

You\u2019re good to go, let\u2019s add the file we made to our git repo, make a single commit and push it up git add .github/workflows/main.yml && git commit -m "Add test GitHub action" && git push

+

(We\u2019re assuming the main.yml file is the one you made, if you called it something different, change that).

+

Go check GitHub

+

Go to your GitHub repo, click the \u201CActions\u201D tab, and watch with glee.

+

Why can't I just run these things locally?

+

You can. If you already know why, you can skip this section.

+

I come from a frontend engineering background, where having test coverage has typically been difficult or different to the backend world. So answering this question is as much about learning facts/words as it is about understanding that the software design, development, and deploy process can be different. I know. I\u2019m sure some engineers are tutting or shaking their heads at me. TUT AWAY, FRIENDS I\u2019m standing in my truth here.

+

GitHub\u2019s actions are part of a broader practice of CI/CD (continuous integration and delivery) in software. The idea of CI/CD is to commit code frequently, and have automated processes in place to detect the introduction of errors to the codebase.

+

CI/CD can also automate any other previously manual processes, like building, deploying, or publishing software. The roles of CI/CD and automation can grow and expand as your team or product become more complicated. In this example we\u2019re just using it to run tests because well written tests give you confidence that your code does what you think it does.

+

As teams grow, having actions run automatically means that institutional and team policies (like having all tests pass before anything goes into main, formatting code, running a smoke-test before publish) are adhered to without manual intervention. This reduces the barrier to actually publishing code.

+

Integrating the CI/CD pipeline right where your code is hosted is different to having a third-party service watch your git repo. It\u2019s first-party and also probably cheaper (maybe).

+

GitHub actions are versatile \u201Csomething\u201D that triggers these bits of code to run can be:

+
  1. Someone pushes to your main branch
  2. +
  3. Someone opens, closes, or comments on an issue
  4. +
  5. Someone creates a PR from any branch to any branch
+

For a full list, see Github\u2019s full list of events that can trigger a workflow.

`; +}); diff --git a/.netlify/server/chunks/2021-03-05-things-i-learned-30-8c9e3af2.js b/.netlify/server/chunks/2021-03-05-things-i-learned-30-8c9e3af2.js new file mode 100644 index 0000000..d17e3e3 --- /dev/null +++ b/.netlify/server/chunks/2021-03-05-things-i-learned-30-8c9e3af2.js @@ -0,0 +1,48 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_03_05_things_i_learned_30, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #30", + "author": "Thomas Wilson", + "date": "2021-03-03T00:00:00.000Z", + "draft": false, + "slug": "2021-03-03-things-i-learned-30", + "imageUrl": "preview-images/30.png", + "tags": ["things-i-learned"] +}; +const _2021_03_05_things_i_learned_30 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • These no longer fictional bridges: You know the bridges on the Euro notes? There are seven of them total (notes and bridges) which represent seven different architectural styles. They were originally designed in 2002 and were (at the time) fictitious bridges which didn\u2019t exist anywhere - so that no country felt special or left out. Robin Stam, an architect from the Netherlands, has gone ahead and designed and built them all irl, for cyclists to use. The money willed these bridges into existence, which is cool. source
  • +
  • This mis-attributed quotes on 2021 coins: The Royal Mint is releasing a set of \xA32 and 50 pence pieces in 2021 with quotes from Lewis Carol\u2019s famous Alice in Wonderland. It turns out that the people who chose the quotes didn\u2019t check their sources, and ended up using quotes from adaptations and derived work. They went onto Goodreads and copy-pasted, so from what I can tell The Royal Mint is run by thirteen year olds who left their homework until the last minute. I support the notion that we should never let a fact get in the way of a good story, so I think this is marvellous on one level. Maybe it\u2019ll be like the bridges and a Dutch architect will come and re-write Lewis\u2019 work for us. There you go, there\u2019s your coin trivia and your callback gag - this one\u2019s a twofer. (source)
  • +
  • This Geocache: I know about geocaching, but I don\u2019t know about geocaching. I don\u2019t get it. The idea is simple: hide something somewhere (public or out of the way), then tell a select few people on the internet where to find it. You can also go find the things that people have hidden. It\u2019s like Pok\xE9mon Go but with real things (lame). One of the engineers who worked with the Perseverance rover (who has now landed safely on Mars, which is pretty cool) is into geocaching. As an homage to this, the team have printed a Geocaching tag (like a unique identifier) on the calibrating tools for the rover\u2019s equipment. When Perseverance gets to mars, it will take a picture of this equipment and send it back to earth - and that\u2019s the code people can use to tag/find/achieve (I don\u2019t know the lingo, sorry) the little cache. The question for me is if this is still geocaching, an not marscaching (marcaching?) (source)
  • +
  • This heartening panic fact: Although mass panic and hysteria did define the early reaction to the Covid-19 pandemic, at least in the UK (couldn\u2019t get flour or toilette paper anywhere), panic isn\u2019t actually the common or expected response to disasters. It\u2019s fun to stereotype and be pessimistic but the social normals that have emerged during Covid have been around patience, space, and understanding. The language we use can be direct (there is a pandemic wear a mask) or indirect (things are tough at the moment), but these qualifiers are normally followed with \u201Cso let\u2019s do something good\u201D. Yeah, we all get a bit annoyed sometimes and some people can\u2019t seem to understand making the slighted accommodation for others, but if you think about it - we\u2019ve done an alright job (except for the bit where we caused and then did not contain a pandemic). The interesting question here is actually why people act so generously, cooperatively, and altruistic during a disaster (like a pandemic, fire, or other natural disaster). From a purely game-theory perspective, acting in your own self interest during a crisis or resource shortage does make the most sense. Social creatures that we are, we\u2019re likely to copy these behaviours when we see then, but why are these norms short lived, not sustained? That\u2019s the interesting research angle from this crisis, I think. (source)
+

What I\u2019ve Had on Rotation

+
  • Something New: Bach: The Cello Suites - Recomposed by Peter Gregson by, err Peter Gregson (2018, Classical). Bach wrote some banging cello suites, you definitely recognise Cello Suite 1 (famously in G Major). Gregson takes on the ambitious task of reinterpreting Bach\u2019s cello suites, and I don\u2019t know enough to explain why, but this album is stunning. It feels fuller, more harmonic, and less performative than the originals. Where the originals might be a spectacle, this album is immersive and surrounds me when I\u2019m listening. It\u2019s a good album to write to, and also a wonderful way to justify any expensive headphones or speakers you\u2019ve bought yourself. (links)
  • +
  • Something Old 10 Things I Hate About You Soundtrack various artists (1999, rock?). I recently re-watched 10 Things which is genuinely a really good film and everyone should (re)watch it. I was taken by much I loved the rocky soundtrack. Ugh, Barenaked Ladies, Spiderbait, Letters to Cleo\u2026 it\u2019s nostalgic and grungy. Just listen to it (Spotify playlist and YouTube Playlist)
+

Cool Articles

+
  • Bren\xE9 Brown on Empathy (VIDEO). A really nicely illustrated reminder about empathy. A little ABC but also a good thing to be aware of. Be kind, y\u2019all.
  • +
  • Taste for Makers by Paul Graham (San Francisco and Silicon Valley darling). I\u2019ve been asking the questions \u201Chow do I design a good product\u201D lately. It\u2019s a hard question to answer, and one of the fundamental (but un-actionable) points is about taste. Ira Glass\u2019 famous quote The Gap covers similar ground.
+

Cool Things

+
  • doodad.dev. If you\u2019re a software engineer or web design geek this is a very pleasing collection of utilities. I love the early Mac callback.
  • +
  • iOS Icon Gallery. A collection of iOS App Icons, for design inspiration or general perusing. Some of them are very pleasing.
`; +}); diff --git a/.netlify/server/chunks/2021-03-06-design-workflow-build-components-63b59472.js b/.netlify/server/chunks/2021-03-06-design-workflow-build-components-63b59472.js new file mode 100644 index 0000000..c66a131 --- /dev/null +++ b/.netlify/server/chunks/2021-03-06-design-workflow-build-components-63b59472.js @@ -0,0 +1,62 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_03_06_design_workflow_build_components, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Frustrating Mismatch of Design by User Journey but Build with Components ", + "author": "Thomas Wilson", + "date": "2021-03-06T00:00:00.000Z", + "draft": false, + "slug": "2021-03-06-design-workflow-build-components", + "imageUrl": "preview-images/question-mark-exclamation.png", + "tags": ["design", "ui"] +}; +const _2021_03_06_design_workflow_build_components = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

How do you design a good app?

+

It\u2019s a charmingly amateurish question, but I\u2019ve spent the past five years primarily trying to design and build web apps and I don\u2019t know the answer.

+

I regularly get sick of looking at my current and old designs and ask \u201Cwhy don\u2019t these look like a competent adult made them, and can I make them actually good?\u201C. I\u2019ll typically then do two things:

+
  1. Go to Dribbble and meander around until I find things that look vaguely like what I want and then get frustrated that these mockups are so simplified and informationally un-dense they\u2019re only partly applicable to my current situations, and
  2. +
  3. Do a web search for \u201Chow to design good UI\u201D, then get given countless \u201Cseven tips to improve your UIs\u201D and \u201CUX fundamentals for UI design\u201D that will tell me that a UI is basically just colour, spacing, and typography which, yeah true, but is incredibly unhelpful in the abstract.
+

These are two vastly different types of data: one is a finished product for an often fictional or simplified use case, and the other are abstract design principles. Mushing those things together to understand, critique, and then be able to produce your own design is the skill of becoming a better designer. It\u2019s not intuitive or easy and you can\u2019t just search for the answer on the internet.

+

Build in Components

+

But as an engineer I want to, because that\u2019s how I find a lot of my answers. That and doing it wrong the first time.

+

Being an engineer I build web, and more recently mobile, interfaces. Both of these technologies have been moving towards the component-model: building self-contained little things or widgets that are composed together to make bigger things, like screens and applications. React, Vue, Svelte, and Angular all use this model. SwiftUI introduced it for iOS and Swift, and Jetpack Compose (seems) to do the same for Android and Kotlin.

+

This component model is declarative. I\u2019m not 100% convinced I actually know what declarative means because I am not a clever man, but broadly I think of it as f(state) => ui - which is to say that the UI is a function of state. Given some data, this is what the UI will look like. You get to say \u201Cwhen the data looks like this, do that with it\u201D. For example if an item in a list is selected, make sure this text is underlined, or this string in the cart should be the total cost of every item in the cart with the \xA3 character put in front of it.

+

Components as a first class citizen in building UIs lends itself really well to encapsulation: a component should care only about the data that it needs to present information to the user, and contains the complexities of any internal interactions or logic. It doesn\u2019t need to be aware of anything else.

+

Let\u2019s illustrate this with a button (I\u2019m sorry, I know it\u2019s tired and over-worked, but it\u2019s simple). Imagine we have a Button component that only takes two bits of data (like a prop, or an input, or an argument): a label, the text that goes in the button, and an onClick function to describe what happens when a user presses/clicks the button. The benefits of encapsulation work for everyone:

+
  1. The button only has to do what it needs to do. It doesn\u2019t care if a label comes from an internationalisation (i18n) file, a database, or generated dynamically when the user does something (like added above \xA3100 worth of products to their cart).
  2. +
  3. The page / larger component (like a molecule in Atomic Design) doesn\u2019t need to contain boilerplate code about rendering and event-handling for buttons. If I had four buttons on a screen (which, let\u2019s just be clear, would be madness) the page they\u2019re on doesn\u2019t need to worry about anything but finding a label and an event handler.
+

These are really great benefits for the engineers building UIs and web software. They can make code easier to understand, more consistent throughout the codebase, and more separated. These are not guaranteed (I can make any code into spaghetti, honestly it\u2019s a super power) but they are easier to achieve with this component-first idea of software architecture.

+

Design in User Journeys

+

But that\u2019s not how the user of a UI thinks about buttons at all. Nor is it helpful when you\u2019re trying to design your app. The buttons on a screen let our users, guests, customers, patients, staff, whoever achieve something. And as a designer thinking about the specifics of the button is part of the job, but it can\u2019t be done in isolation to every other part of the web page.

+

It\u2019s so easy to find good advice on building components in code. There are tricky conversations to be had about them, about how to extend them and manage them as the complexity grows, but that advice is pretty specific and concrete. It is so much harder to get someone\u2019s opinion on figuring out how a button integrates with the Sign Up page, a \u201Cbuy now\u201D button on a product card, a \u201Cadd two factor authentication\u201D button, or a \u201Crequest help\u201D button. These are questions about the purpose and intention of the app you are building.

+

We are taught to build at the focused and specific level of components, but to design with with so much more information in our working memory. What screen am I on, how did I get here, and where can I go? How do I know if my data is saved or (in)valid? What does it look like if I\u2019m browsing versus editing? If these questions aren\u2019t answered properly it creates this weird jilted UI and UX experience as I move around a product. Seeing a mocked up screenshot from a single state of a single page on Dribbble is never going to help me answer these questions, no matter how pleasing the curves, shadow, and pastel colours.

+

The Frustration

+

I have experienced (and witnessed) the bike shedding meets deer-in-the-headlights moment of designing a new app or website where you\u2019re terrified to make decisions about the label placement on your forms. It genuinely stops me from making decisions and moving forward, especially at the beginning, when your app is an idea and a mostly blank Figma file.

+

The form inputs aren\u2019t important, but they are when they represent 50% of the screens you have currently designed. I have been terrified to move on from designing my sign up screen until I have perfected the form and form input components. Because I was so aware that they\u2019re components: they\u2019ll be used everywhere. They are perfect lego blocks and if I get them wrong here everything will look terrible.

+

My fixation (or obsession) with designing by components has limited my ability to focus on anything bigger. But as a user, my fixation on the flow through an application will stop me noticing anything smaller. Yeah, the onboarding was confusing, and I can\u2019t figure out how to access my profile page but holy smokes have you seen the border radius on the cards and the top navigation? They match perfectly!

+

No matter how perfect your button is, it\u2019s not going to salvage an app with competing or confusing Calls to Action, with disjointed screen layouts, mixed metaphors, or obscured ideas. Similarly, the UX conventions of colour, spacing, and typography won\u2019t help you answer these questions. Yet if you don\u2019t build a system around these basic elements, the visual clarity and rhythm of your UI as a whole will suffer.

+

Similarly, if you don\u2019t build your codebase with well encapsulated components, you\u2019re going to have a real hard time modifying and extending your app\u2019s code.

+

Designing an app demands that we ask questions about the app, not the components, that we see the entire blueprint. Building components demands we exclude all thoughts about the app at large and focus solely on this little corner, this one detail. This is the titular frustration of having to build in components, but design by user journey and flow.

+

That\u2019s it. That\u2019s the end of the article and I\u2019m sorry I can\u2019t close with a unifying theory, or three step framework to build perfect UIs every time. I just want to build actually good apps, and it\u2019s difficult, ya know? The context switching between design and developer brain is hard.

`; +}); diff --git a/.netlify/server/chunks/2021-03-12-things-i-learned-31-5651ec47.js b/.netlify/server/chunks/2021-03-12-things-i-learned-31-5651ec47.js new file mode 100644 index 0000000..e9342a9 --- /dev/null +++ b/.netlify/server/chunks/2021-03-12-things-i-learned-31-5651ec47.js @@ -0,0 +1,45 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_03_12_things_i_learned_31, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #31", + "author": "Thomas Wilson", + "date": "2021-03-13T00:00:00.000Z", + "draft": false, + "slug": "2021-03-13-things-i-learned-31", + "imageUrl": "preview-images/31.png", + "tags": ["things-i-learned"] +}; +const _2021_03_12_things_i_learned_31 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

This week we celebrated International Women\u2019s Day. My love and support goes out to anyone who identifies with that label. Let\u2019s keep pushing for fair representation and pay, acknowledgement of domestic labour as work, and maybe some systemic government-backed support for domestic abuse victims and sex workers that doesn\u2019t involve the police where it\u2019s not necessary. Anyway, here\u2019s a funny a bit by Iliza Shlesinger that I love.

+
  • This hijab-wearing model: Halima Aden is a Somali-American model who first came into popular attention, aged 19, in 2017 when she walked at an event for Kanye West\u2019s Yeezy brand. She also won Miss Minnesota, and was the first hijab-wearing woman to do so. She was described as a \u201Cdifferent beauty\u201D and honestly, it\u2019s easy to see why. Earlier this year, Aden announced that she would be leaving the fashion industry after feeling like she was compromising her religious beliefs. Aden represented the figure head of \u201CModest Fashion\u201D, a recent movement by western fashion labels to design looser fits and bigger silhouettes, in line with some cultures\u2019 expectations of modesty in the way (mostly women) dress. There\u2019s a pretty difficult conversation to be had here about the western/European/American perception of modesty as oppression, and the religious foundation of modesty. Fundamentally though a woman (and any person) should be able to chose what they wear and how they would like to show/cover their body. That just seems like a human right. Aden is a cool example because she\u2019s standing by her beliefs, despite the success she was seeking and following (almost 1.5m followers on the \u2018gram). As a younger, and newer model, in a famously cut-throat and often problematic industry, it can\u2019t be easy to make those decisions, or to speak out. Good on you, Halima. (source)
  • +
  • This reason to stop talking: I\u2019m sure many other introverts can relate to the scenario: you\u2019re talking with someone you don\u2019t know particularly well, or maybe professionally, and there\u2019s a little voice in your head that\u2019s like \u201Cdude why are you still talking?\u201C. Well I hate to feed your insecurities but that voice has a point, y\u2019all. In some research involving 252 strangers who were paired up randomly to talk (they were given some task to complete but told that they can chat for as long as they want before they started), a Harvard study found that only 2% of couples both agreed that the conversation was the right length. That\u2019s like two of the 126 couples. 69% of participants wanted the conversation to be shorter (preach, sis), and said that the conversation could have been about half the length. My advice from this research: wait until your new conversation partner is half way through a sentence and stand (if you\u2019re standing, try crouching suddenly) and say that it\u2019s been fun chatting but you don\u2019t want to bore them. In earnest though, don\u2019t be afraid to cut a conversation short if you feel it\u2019s dragging: the feeling might be mutual. (source)
  • +
  • This reason to not give anyone any certificates: You can be motivated by two types of influences: internal or external. Internal motivations are ones you make yourself: you want to do something because you enjoy it. External rewards are given to you by others: you want to do something because you\u2019ll get paid, or get an award. Internal motivators are stronger that external ones, the presence or expectation of an external validation (like a certificate) isn\u2019t enough to make us want to do something as much as if we ourselves decided we wanted to do it. The distinction between these two things isn\u2019t clean, in turns out. By providing an external reward for a behaviour, even if it wasn\u2019t expected or explicitly stated, you can reduce someone\u2019s intrinsic motivation for that thing. In one study, children were asked to pick any activity they wished (like colouring in), and were later given a reward for it (a certificate with a gold seal and a bit of ribbon). After doing so, children were less likely to chose that activity freely (i.e. without expectation of an external reward). As one 1999 meta anlysis states, \u201Ceven when tangible rewards are offered as indication of good performance\u201D, they typically decrease intrinsic motivation for interesting activities\u201D. Given how powerful internal motivations are in allowing us to live a fulfilled life, the authors suggest instead focusing on highlighting how completing or performing a task helps us feel fulfilled. Reminding someone of how they felt during, or after a task, for example. This is an almost counter-intuitive way of thinking about things, we\u2019re so keen to give feedback and praise and recognition (and scholarships and grants and jobs), where this could be damaging the processes that actually go into the performance. (source)
+

What I\u2019ve had on rotation

+
  • Something New: Organ by Dimension (EDM, 2021). This is a safe space and I need to not be judged. This is a pretty four-on-the-flour Electronic/House/DnB album which I just love. It\u2019s perfect for running and cycle training at the moment, especially as I\u2019m trying to shed the sludge that comes from winter and my complete inability to resist Christmas chocolates and sweets. It\u2019s got that old 2007 Pendulum vibe that I remember listening to on my first MP3 players. (link)
  • +
  • Something Old: Temple by Matthew And the Atlas (Folk, 2016). Matt Hegarty, the lead singer of this band, has a distinct voice with a lovely tomber. Hearing this album again brings me right back to 2016, and writing my Ph.D. There\u2019s also an unplugged/acoustic rendition of this album available, which I recommend heartily. They\u2019re a great mix of indie rock and folk, and the sister acoustic album means that it can fit every mood. (links)
+

Cool Articles

+
  • Things I Made that Sucked by Jordan Morgan. This little self-critique slash reflection from someone who\u2019s designed and built indie apps for a while is nice. It doesn\u2019t take itself too seriously, and isn\u2019t preachy, it feels honest. If you\u2019re a maker of anything, you too have made things that suck, and I like that articles, like this, can normalise things like that.
  • +
  • Stop Keeping Score by Arthur C Brooks for The Atlantic. A nice short piece by Brooks which reminds us that we don\u2019t have to achieve our \u201C30 things before 30\u201D lists. A fact I find heartening because I\u2019ve only got ten months left before I hit thirty and man this pandemic isn\u2019t going anywhere in that time. Anyway, a nice reminder that we can do our best work, be ourselves, and enjoy what we do without a prescriptive list.
`; +}); diff --git a/.netlify/server/chunks/2021-03-15-magician-9baceb14.js b/.netlify/server/chunks/2021-03-15-magician-9baceb14.js new file mode 100644 index 0000000..1dd7e49 --- /dev/null +++ b/.netlify/server/chunks/2021-03-15-magician-9baceb14.js @@ -0,0 +1,61 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_03_15_magician, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Magician", + "author": "Raymond E. Feist", + "score": 1.5, + "image": "magician", + "slug": "magician", + "book_review": true, + "date": "2021-03-15T00:00:00.000Z", + "finished": "2021-03-10T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "fantasy"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Raymond-E-Feist/Magician/9002112" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/magician-apprentice-9780425286623/9780553564945" + } + ] +}; +const _2021_03_15_magician = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The first in Feist\u2019s Riftwar Saga, Magician has the air of a pulp fantasy novel. First published, abridged, in 1982 and unabridged a decade later, this book oozes nerds in the \u201970s playing D&D and I love that. It has it\u2019s bona fides as a fantasy novel and that\u2019s what made me pick it up in the first place. Unfortunately, I could never find myself truly getting into Magician in a way that I have with more contemporary fantasy series (like Brent Week\u2019s Lightbringer, or Peter V. Brett\u2019s Demon Cycle). The piece was paced oddly, the characters undeveloped and shallow, and as a whole it felt too broad and unfocused. There\u2019s a fine line between telling an epic story with a sense of something larger than what the reader is being shown, and having an author move endlessly along a chain of \u201Cand then\u201Ds. Unfortunately, this series hit the wrong side of that line and I was never given anything good enough to forgive it.

+

The book starts with two boys (one orphaned, naturally) growing up in a medieval-setting fantasy castle. I expected us to stay there a lot longer, a la Robin Hobb\u2019s Assassin\u2019s Apprentice series (a 4\u2B50 series btw). Strong but clich\xE9 start. Almost immediately Feist whisks us off somewhere else, and before long we\u2019ve covered seemingly large spaces of time and personal development in just a few chapters. This might speed up the pacing, but when you\u2019re writing fantasy you have to educate your readers, which is why \u201Cundiscovered genius\u201D is a common and useful trope in fantasy: our protagonist can learn about the world with us, but do all the hard work (like studying for all those pesky magic exams). Instead, Feist introduces Pug and Tomas (our young keep boys) just before they start their apprenticeships and then comes back to them years later in the middle of their studies. We\u2019re not much wiser about their day-to-day lives, their skills, their character development. Later we spend seemingly endless pages on board a boat with characters who phase in-and-out of importance, and then maybe a dozen pages are given to Pug after he has his memory wiped and goes through an entirely new magic training in a parallel world. The pacing was way off - I could never infer importance from length or attention.

+

This isn\u2019t even a review about Feist\u2019s book anymore. I don\u2019t want to spend time dissecting what I don\u2019t like about something if it doesn\u2019t lead to a productive understanding about what I do like, and how it could be better. Unfortunately I just don\u2019t think I like this kind of book. That also means I did not like this book very much, which is a shame because it seems like such a beloved classic.

+

But I do like fantasy. So let me explain to you why both these things are true.

+

There is a feeling that Feist has already go to the end of this book and is relaying it to you, almost haphazardly in the pub when really you\u2019d rather be talking to the cute boy or girl you\u2019ve been making eyes with. Good storytelling is joint discovery, you and the story teller are stumbling across things, surprising things, unexpected things, at the same time. Feist\u2019s writing in this book lacks that feeling, and it\u2019s a shame. A good plot, a rich political ecosystem, an interesting magic system are the core ingredients to a good fantasy epic, but there\u2019s nothing holding them together. Croissants might just be butter, flour, yeast, and milk but so are a lot of things - the art is in the mixing and waiting.

+

As much as I want to love good old pulp fantasy, I don\u2019t know how much I actually enjoy it. A lot of my favourite fantasy series are more modern. It\u2019s only a forty-year gap, in the scheme of writing it\u2019s really not that long. Orwell\u2019s 1984 was published over seventy years ago, Steinbeck\u2019s East of Eden a few years after that, and Atwood\u2019s The Handmaids Tale a few years subsequent. All books that remain remarkably readable and excellently rich for modern readers.

+

Reading this book acted more as a counter point for contemporary fantasy (things published in the last 10-15 years). Fantasy has become less of a distinct entity, separate from fiction. Writing fantasy isn\u2019t a necessarily a decision about niche or genre, it is a stylistic or world-building aspect. Sure, some modern writers are going deep on the epic and high fantasy (see: GRRM), but a lot of others are writing good books, with crafted characters, set in a world that has magic and swords and dragons. And that\u2019s great, I love swords, and magic, and taverns.

+

More people can write and publish their books, and more people can find and access them. The barriers to everyone in this equation have gone down, and the result hasn\u2019t been the dilution of quality we probably feared it would be forty years ago. This means that if I want to read a book about men who make potions or women who can make magical illusions with their art, I don\u2019t have to pick the writer just because they\u2019re a fantasy writer.

+

I like good books first, and fantasy second. I love good books written in a fantasy setting, but I (personally) cannot forgive a bad book because its characters inhabit a world where there is magic. No matter how well explored the consequences, or certain aspects of the political and economic ramifications of there being magicians.

+

With so many new, creative voices in fantasy, many of who are women and People of Colour, I would rather spend my time exploring what\u2019s new in the genre. Our attention and our conversations are two of the best tools that we have to make meaning and change with out brief lives on earth, and I think those things are better spent on emerging and under-represented artists (if I was made to chose, which I am not).

+

I\u2019m glad I read a classic of the genre, but not because of the book itself - rather to get a better lay of the land. I\u2019m glad I read it but I won\u2019t be reading the rest of the series. 1.5\u2B50

`; +}); diff --git a/.netlify/server/chunks/2021-03-20-things-i-learned-32-0b354c4a.js b/.netlify/server/chunks/2021-03-20-things-i-learned-32-0b354c4a.js new file mode 100644 index 0000000..ebadfb2 --- /dev/null +++ b/.netlify/server/chunks/2021-03-20-things-i-learned-32-0b354c4a.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_03_20_things_i_learned_32, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #32", + "author": "Thomas Wilson", + "date": "2021-03-20T00:00:00.000Z", + "draft": false, + "slug": "2021-03-20-things-i-learned-32", + "imageUrl": "preview-images/32.png", + "tags": ["things-i-learned"] +}; +const _2021_03_20_things_i_learned_32 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Following on from International Women\u2019s Day last week, news of Sarah Everard\u2019s body being discovered broke on the 10th of March, a week after she went missing from Clapham, London. There have been subsequent vigils (and protests) to remind us all that violent and sexual crimes against women are under-reported and under-convicted, and that any fair and just society needs to build systems that don\u2019t let people think (let alone know) that they can hurt or sexually assault another person and probably get away with it. It\u2019s a bit of a rough or tone-deaf transition, but let\u2019s look at some things I learned this week:

+
  • This charmingly pre-covid advert: I stumbled across this advert for Choices Hotels, which asked (presumably sometime in 2019) \u201CWhat\u2019s your 2020 Vision\u201D. Imagine giving your 2021 answer to this question to anyone from 2019, it\u2019d sound fifty shades of dystopian. My 2020 vision was mostly the inside of my house, and being genuinely excited when I could eat dinner outside or go for a walk (also outside). Anyway, what\u2019s your 2022 vision? Rats? Locusts? Black Mirror but it\u2019s real life? Personally, I\u2019m hoping the dead rise and consume us all.
  • +
  • This surprise concert: Yo-Yo Ma, the famed American cellist, recently received the second dose of his vaccine (he\u2019s 65, which is pretty cool). He briefly set up shop in the waiting room of the vaccine centre for about 15 minutes, to play for the people waiting for their vaccines. As a classical musician, Ma has probably missed performing live to people, so I imagine this wasn\u2019t just a joy because he had received his vaccine. (Guardian video)
  • +
  • This forbidden confectionary: It\u2019s illegal to buy or sell chewing gum in Singapore. You can buy prescription gum (like nicotine gum), but you have to get it from your doctor. Why is it illegal? Train vandals, that\u2019s why. In 1987, the government in Singapore funded a \\$5b railway system, and people kept vandalising the door sensors of these trains by sticking their gum to them. So the government looked around, at their gum covered pavements and train sensors and thought enough is enough and outlawed the buying and trading of chewing gum. The total ban was lifted, to allow for medical exceptions, in 1992 when Wrigley, of gum manufacturing fame, lobbied the United States government to explicitly name gum in a legal free trade agreement (the USS-FTA) between the two countries. Despite the country of Singapore having a population of some 3.2 million in 1992 (which would have been about half the population of New York City), the company defended their position. Likely because they didn\u2019t want any other country looking over at Singapore\u2019s infamously clean train sensors and asking if they should do the same. (source)
  • +
  • These wine merchant scales: Lord Byron was one of our first celebrities, namely a poet and a scoundrel. Byron as obsessed with his weight and would travel, sometimes multiple times a day, to Berry Bros. & Rudd, a wine merchant in Covent Garden, to use their scales to weigh himself. Berry Bros. & Rudd also happens to be the oldest wine and spirit merchant in the UK, being founded in 1698, by the way. It being the early nineteenth century these scales weren\u2019t the little box that you stand on and look down at, hope in your heart, but rather giant versions of kitchen balancing scales, used for weighing wine barrels. Byron\u2019s weight reportedly varied from around 9st to 13st, and he appeared to have yo-yo\u2019d in weight for most of his adult life, starting at Cambridge University and up until his death (at age 36). With scales being so inaccessible, to know how much you weighed was itself a status symbol - and apparently, various members of the gentry (men and women) had their weights recorded in Berry Bros. ledger, though these records haven\u2019t all survived. (source)
+

What I\u2019ve had on Rotation

+
  • Something New: Evering Road by Tom Grennan (2021). Grennan\u2019s slightly gruff but clear vocals remind me of Dermot Kennedy or James Bay (in his first album). Evering Road is full of poppy ballads and I hope this comes to be one of my albums of Summer 2021. (links)
  • +
  • Something Old: What\u2019s Going On by Marvin Gaye (1971). My father actually recommended this one on his Facebook page and blog. This album is such a beautiful re-discovery, Gaye was just a talented man, the vocals, instrumentals, and production sit just right on this album. Seriously, the sax in Wholy Holy\u2026 my goodness. (link)
+

Cool Articles

+
  • The Future of Group Messaging. This is a really great piece about the UI and UX of modern group messaging. There\u2019s not a lot to distinguish between how we communicate these days, but various platforms bring their own ideas of what is (not) important. Some focus on instant messages (WhatsApp, iMessage), inboxes (e-mail), or group chats (Slack). Most of these paradigms result in a user experience which is either a) a 90\u2019s-style online forum, or b) iMessage/Messenger chat bubbles. These don\u2019t reflect the way we do group messages these days: where four people are having three conversations at the same time but one of them is important. As a persistent de-railer of conversations, I contribute to the chaos this post tries to solve, by arguing for a better (more first-party and actually useful) threading metaphor, to allow these conversations to happen in parallel.
  • +
  • The edge of our existence: A particle physicist examines the architecture of society .
`; +}); diff --git a/.netlify/server/chunks/2021-03-21-dash-cycle-00-7e58c52a.js b/.netlify/server/chunks/2021-03-21-dash-cycle-00-7e58c52a.js new file mode 100644 index 0000000..be97d16 --- /dev/null +++ b/.netlify/server/chunks/2021-03-21-dash-cycle-00-7e58c52a.js @@ -0,0 +1,78 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_03_21_dash_cycle_00, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Dash Cycle #00 - The Beginning", + "author": "Thomas Wilson", + "date": "2021-03-21T00:00:00.000Z", + "slug": "2021-03-21-dash-cycle-00-the-beginning", + "draft": false, + "tags": ["dashdot", "buildinpublic"], + "imageUrl": "preview-images/C00.png" +}; +const _2021_03_21_dash_cycle_00 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Hello. I\u2019m building an app called Dash Dot, it\u2019s a native iOS app for interval training that is a) well-designed, and b) privacy- and utility-focused. This post covers the first (approx.) six weeks in designing and building the app.

+

I\u2019ve never made a truly native app before (I have written things in React Native before, though), nor have I ever successfully released a product to the world. Maybe this will be the time \u{1F937}\u200D\u2640\uFE0F

+

I want to #buildinpublic so this is a proto-changelog for a product that I\u2019m hopeful will exist one day.

+

Cycle? I don\u2019t like the \u201Csprint\u201D terminology that agile practices use to describe how features are developed. Nobody sprints all the time, that\u2019s ridiculous, and building a product is a long slow burn. Also, I don\u2019t have a product to iterate on, I\u2019m currently working forwards from \u201Cwouldn\u2019t this be a good idea\u201D. I need longer than two-week springs to make a difference. In line with Basecamp\u2019s six-week \u201Cbets\u201D and Linear\u2019s \u201Ccycles\u201D, I want to work in cycles, as in lunar cycle or life cycle: longer (six-ish) periods of work where I focus on broader goals.

+

This cycle (#0) lasted seven weeks:

+
  • Started: 2021-02-01
  • +
  • Ended: 2021-03-21
+

What do I have right now ?

+
  • An idea of what I want to build, how it offers value, and a route to monetisation
  • +
  • MVP Features that I want to build before I release (into Test Flight), and a rough shape for the functionality I want to add on after that.
  • +
  • A very messy Figma file that needs tidying up but does contain screens for a lot of the app: dashboards, timers, config pages, profile pages.
  • +
  • A working swift iOS app that lets you configure a timer and do some very primitive navigation
+

What have I done that I\u2019m proud of?

+
  • Decided to make this app, don\u2019t overlook that
  • +
  • Learned a whole lot about Swift and iOS development. I don\u2019t think I\u2019d written any Swift code before 2021, and I\u2019ve spent the past four years building predominately frontend web software in JS/TS, so I\u2019m pretty proud of this.
  • +
  • Visually designed and prototyped the principle workflow for creating a timer, completing it, and viewing your account
  • +
  • Created code that travels the entire vertical stack (i.e. end-to-end) that allows a user to create, save, update, and delete a timer
  • +
  • Toyed with JIRA and Linear for project management
+

What went well?

+
  • I actually built something, I have an idea of the product and I have the first few screens that make this a little bit closer to a reality. That\u2019s a cool feeling
  • +
  • Rapid low and medium fidelity UI prototypes and iteration. I didn\u2019t waste too much time wanting to get the perfect UI done before I started, so I\u2019ve built with a very Spartan UI in Swift, but have worked in parallel in Figma to know what the content (if not the presentation and layout) of my screens will be.
  • +
  • I\u2019m proud to be focusing on UX and UI that actually makes sense for humans. I tried a lot of competitor/existing interval timer apps and wow are they non-intuitive. They just expect you to poke around, do things without confirming them or making clear what they\u2019re about to do, and have unclear iconography and buttons. I\u2019m happy to be building and designing an app that takes these things seriously.
  • +
  • Early validation of the idea from discussing it with friends (which isn\u2019t real validation, I know)
+

What didn\u2019t go well?

+
  • UI Design != software design. Although the two relate closely, I made the mistake of tying my initial software design to the UI/UX design. Although the two should be similar, they shouldn\u2019t be identical. I made my code too strict and tightly linked to the UI implementation. I have been working to combat this in more recent code design.
  • +
  • Better code design I should make more effort to design systems on paper before I start coding, not code > get stuck > design > delete & rewrite code. Obviously, you can\u2019t just plan to the exclusion of coding, but you can spend 10-15 minutes getting your ideas on paper, yeah?
  • +
  • TDD. Related heavily to the above: I tried to use test-driven development (TDD) from day 0, but it made it hard to prototype and change things. Maybe if I was a better engineer I would have designed a better system from the get-go, but my style of doing things is a little more \u201Clet\u2019s see what happens if I do this\u201D. - I ended up designing and building one system, then splitting it out, dividing it, and re-naming parts which made my tests redundant and all fail, so I\u2019m basically going to have to go back and re-write tests for everything - This may not have been the best approach - slowly refactoring code and tests in parallel would probably have been a good idea, but I decided I\u2019d rather just go ahead and write the code instead. If this was an established app in production I would definitely have done code and tests together.
  • +
  • Writing in a new language. I\u2019m having to learn about both Swift and iOS development as I construct the app itself, so there have been several sizable re-shuffles and re-architectures
  • +
  • A messy Figma File that\u2019s hard to navigate. I haven\u2019t settled on a UI/UX design, there\u2019s been a lot of iteration - which means the business components exist but the UI components are very minimalist and industrial (read: bad)
+

What has been most challenging?

+
  • Learning a new language (Swift) for the development
  • +
  • Learning and implementing the architectural patterns for iOS development (e.g. Model-View-View Model)
  • +
  • Having to learn the entire vertical stack before building a feature: persistence, animations, layout & styling, etc. The process feels a lot more like full-stack engineering than frontend, despite thinking otherwise as I went into this.
  • +
  • Shifting from the predominately functional style of building React applications to the more Object-Orientated way in Swift.
+

What do I do next?

+

In order, here are the things I want to do in the next cycle:

+
  1. Finalise the current architecture and add tests: The code that lets you create and configure a timer is functional (it walks), but I can probably do some tidying. In fact I can definitely do some tidying. I absolutely want to have tests in my code, even if TDD didn\u2019t work out this time and I\u2019ve had to write code then tests, that\u2019s still preferable to writing no test.
  2. +
  3. Solidify the design: I\u2019ve got a lot of possible UIs and medium-fidelity prototypes, with various colour schemes and mental/visual metaphors in my current Figma file, I need to settle on the Colour Palette & Design Tokens so that I can build consistent UIs. I need to get rid of old ideas (I\u2019ll probably move them to some kind of \u2018Archive\u2019 part of the file so that I can go back to them later). This should create a consistent UI and UX across the various user journeys.
  4. +
  5. Allow someone to complete a timer: Design the architecture and UI that would allow someone to select a timer they have made, and actually complete it
  6. +
  7. Buy some domain names: I need to start thinking about the keywords and handles I\u2019ll be using online
  8. +
  9. Decide on JIRA vs Linear: How to manage software development? What an ever-turning wheel
+

Note the lack of marketing and advertising here? I\u2019m aware that this should start early but I don\u2019t want to do anything until I\u2019m sure that I\u2019ll have something that I\u2019d be happy letting someone else use.

+

Hopefully, Cycle #1 will last from now until the beginning of May 2021, but I also expect it could last longer. Right now it\u2019s about making ideas solid and building code - and that happens when it happens.

`; +}); diff --git a/.netlify/server/chunks/2021-03-26-things-learned-33-6b144699.js b/.netlify/server/chunks/2021-03-26-things-learned-33-6b144699.js new file mode 100644 index 0000000..fb3a18b --- /dev/null +++ b/.netlify/server/chunks/2021-03-26-things-learned-33-6b144699.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_03_26_things_learned_33, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #33", + "author": "Thomas Wilson", + "date": "2021-03-26T00:00:00.000Z", + "draft": false, + "slug": "2021-03-26-things-i-learned-33", + "imageUrl": "preview-images/33.png", + "tags": ["things-i-learned"] +}; +const _2021_03_26_things_learned_33 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
  • This cassette revival: Last year\u2019s (2020\u2019s) sale of tape cassettes, the 90\u2019s mainstay of car sound systems and OG Walkmans (Walkmen?) were the highest they have been since 2003. An increase of 94% on 2019. Despite having inferior sound quality to CDs and vinyl, the medium is a lot cheaper and easier to produce which means a lower initial investment and potentially higher profits, which is great for indie musicians. Especially given how reluctant modern streaming services are to pay musicians and livable or useful fee for their streams. The global pandemic has made it a lot harder for musicians to tour, and a the related economic recession has made shifting merch a little harder. The sudden demand for cassettes is part of the \u201Cyou can\u2019t hold a digital download\u201D trend which has seen a resurgence in tangible, physical things. It makes sense, if you love music or artists, then you want things that resonate with that belief: band Ts, a vinyl collection, a feeling of belonging, ya know? (link)
  • +
  • This money making chimp: Raven, who is a chimpanzee, is the most successful chimpanzee on Wall Street. In 1999, she created an index fund by throwing darts at a list of 133 internet companies. The fund saw a 213% return on investment, outperforming thousands of professional Wall Street brokers. So here\u2019s your reminder that humans like to construct stories and narratives around what is actually chaos, and like to believe that we have more control than we actually do. Anyway, yeah, Raven the chimpanzee. (link)
  • +
  • This paper computer: Magic: The Gathering is the oldest collectible card game, which had its first set of cards released in 1993. There are literally billions of Magic cards in circulation right not, which is cool. It\u2019s actually a really fun game, you should totally play some time. Anyway, Magic is technically Turing Complete, a term used to describe a machine that can take and perform any arbitrary computer algorithm, i.e. any set of arbitrary instructions. This means that (practicality be damned) Magic: The Gathering can perform anything that most programming languages could. The authors of the cited study acknowledge that using this technique might be possible but in practice \u201Cmay effect an individual\u2019s ability to successfully execute the combo due to concerns about the sheer amount of time it would take to manually move the tokens around to simulate a computation on a Turing machine. This would not be a concern for two agents with sufficiently high computational power\u201D so I guess we should just let the robots play the game for us now. (source).
+

What I\u2019ve had on rotation

+
  • Something New TIME by Jess Gillam (Classical, 2020). Gillam is a classical saxophonist, and this album is a collection of modern classical pieces. It\u2019s all really beautiful. It contains the (rightfully) popular On The Nature of Sunlight (Max Richter) and Dappled Light (Luke Howard) which act almost like the gateway drugs for lesser known composers and arrangers, and the result is an album which really fills the space without ever feeling cramped. I am far from a classical music person, and definitely not a saxophonist, but Gillam comes across as crisp and precise, supported by her ensemble. (links)
  • +
  • Something Old We The Kings by We The Kings (rock, 2007). Oh wow, I didn\u2019t remember this album at all until it started playing and then suddenly it was 2007. This is peak in-ear headphone buds plugged into my MP3 player and walking to or around college. According to Spotify, the band is most popular in Chicago (USA), Jakarta (India), and Singapore (where chewing gum is still illegal btw) - I never would have guessed that combination of cities (and city states) in a million years. (links)
+

Cool articles

+
  • Nothing breaks hearts like A.I by Pamela Mishkin for Pudding. Pudding is pretty much everything I love about the internet: nerdy cool people making nerdy beautiful things. In this piece, Mishkin uses GPT-3, probably the most advance text-generating AI, to generate part of a personal romantic essay-cum-story. It blurs the lines about what\u2019s real: the details or the sentiment. The piece is also incredibly well produced and presented. You can tap to re-generate certain parts of the text, to rotate wheels. For example, half of this sentence was generated by GPT-3: \u201CGPT-3 doesn\u2019t care about my friends. It doesn\u2019t care that I work at a start-up, live in a city, that I am quarantined in a house with two other people. It doesn\u2019t care that Omar and I didn\u2019t have the language to say what we wanted from each other, that we fought about his insecurity and my loneliness, that I felt like I was losing myself. It doesn\u2019t care which of my sentences are tired or stale or cliche.\u201D Could you guess which part? Which of that feels like it wasn\u2019t written by a human?
  • +
  • Why growing mushrooms at home is everyone\u2019s new pandemic hobby by Adrienne Matei for The Guardian. This is such an odd piece, and I can\u2019t explain it but looking at pictures of mushrooms makes me deeply uncomfortable. They\u2019re so alien, and they\u2019re almost in an uncanny valley: my brain can\u2019t decide if they\u2019re alive or not. They\u2019re plants but they\u2019re not. Apparently there\u2019s been a boom in growing them indoors since the beginning of the pandemic, which is cool I guess but not for me. I love when people grow (and then eat) things. Matei also reports that some people have started growing mushrooms to trade for eggs and bread - so we\u2019ve been in the pandemic long enough for an emergent goods-and-barter economy to arise.
`; +}); diff --git a/.netlify/server/chunks/2021-04-02-things-i-learned-34-55e72bfc.js b/.netlify/server/chunks/2021-04-02-things-i-learned-34-55e72bfc.js new file mode 100644 index 0000000..8981ab9 --- /dev/null +++ b/.netlify/server/chunks/2021-04-02-things-i-learned-34-55e72bfc.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_04_02_things_i_learned_34, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #34", + "author": "Thomas Wilson", + "date": "2021-04-02T00:00:00.000Z", + "slug": "2021-04-02-things-i-learned-34", + "draft": false, + "imageUrl": "preview-images/34.png", + "tags": ["things-i-learned"] +}; +const _2021_04_02_things_i_learned_34 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Things I Learned #34

+

We\u2019ve made it to the Easter weekend. Spring has arrived here in London, which is to say it was 20 degrees C earlier this week and this morning it was 0, windy, and overcast. This time a year ago, my mental state was dominated by COVID-19 (something I barely even think about now), but that also lead me to notice the beauty of spring for the first time. I\u2019m normally more of an autumn person. My wildflower seeds have started to come up, my tomatoes have been sown, and I made an asparagus risotto this week (largely so I could drink white wine while cooking, al la my middle-aged housewife dream).

+
  • This product search duopoly: I try and keep things pretty fun and light hearted here. Find some irreverent fact about a victorian butterfly hunter, you know. But I\u2019m also interested in tech and business as a force for good and change (and therefore also as a point of stagnation of source of moral evil). The past couple of years have seen increasing calls for big tech firms, like Amazon and Google, to be disassembled. They have so many resources available to them that they stifle market forces and creativity by being able to undercut any competitor, and subsidise initially unprofitable efforts in some areas (e.g. logistics) through their massive profits in others (e.g. cloud computing and advertising). As a case-in-point, approximately 60-70% of people who need to find a product online will start their search at either Amazon or Google. The problem for small businesses then becomes about discoverability and visibility: how do people find them. So they go to advertisers. Who are the advertisers: Google & Facebook (and most commonly, Amazon). Amazon will allow businesses to advertise on their platform, and compete against their own products. This hardly seems fair or right, but it does sound hella profitable. (source).
  • +
  • This Victorian butterfly collector Margaret Fountaine (1862\u20131940) lived in England and was a wealthy and independent woman who amassed a collection of some twenty-two thousand butterflies, and a million pages of personal journals. Despite her immense contribution to entomology (the study of insects) and lepidopterology (the study of butterflies) her contributions are largely noted as an assistant or amateur. This is, of course, entirely unrelated to the fact that she was a woman, and therefore unable to participate in the meetings of these societies. In 1897 Fontaine became a member of The Royal Society, though her contributions to science remain largely under-appreciated and rarely spoken about, namely because they are neither professional nor amateur. If you get the chance, read about the life Fontaine read: travelling across Europe (and the British Empire) to collect samples and view other butterfly collections. (source)
  • +
  • This imaginary designer Nikolay Ironov is a Russian designer but is also an AI. Ironov had created static and animated logos and logos for various clients (here\u2019s their portfolio of work): they\u2019re a real mix of geometry and typography. I quite like them. The AI was created and maintained internally within the Art. Lebedev Studio, but kept completely isolated. That\u2019s why it was given a human name, and was introduced to the team as a remote employee - even getting its own employee page. It\u2019s quite a cool concept but also a little terrifying - I\u2019m sure all of Ironov\u2019s colleagues weren\u2019t super pleased to find their work has been outsourced to an AI. (source)
+

What I\u2019ve had on rotation

+

-Something New Justice by Justin Bieber (pop, 2021). After 2020\u2019s frankly insulting Changes, this new album from Bieber is a breath of humanity and honesty. The album doesn\u2019t rush but it\u2019s poppy, it\u2019s perhaps a bit laboured in its expression of love and gratitude for his wife but it\u2019s a good album. (links) -Something Old Ocean Avenue by Yellowcard (pop punk, 2003). I went back this week to try and find some good grunge and rock from the \u201890s but ended up getting stuck on this album. I\u2019m not regretful, and Nirvana can wait for me. Probably related to my We The Kings re-listen that I mentioned last week. I\u2019m not even really sorry, early \u201800s emo music is in my bones. (links)

+

Cool articles

+
  • Squark Notes #7 (newsletter) by Susan Fowler Rigetti. Rigetti is a writer and refugee from tech (she\u2019s the woman who ousted allegations of sexual abuse from Uber\u2019s CEO). She posts a newsletter every six-to-eight weeks, and it\u2019s worth a subscribe. This edition contained the advice to write more than one thing at once. Or, if you\u2019re any kind of creative: always have multiple songs, poems, paintings, side hustles, whatever. I can butcher her sentiment, but she does it far more justice: \u201Cwhen someone has one thing and only one thing is that nothing ever happens with it. Sometimes it\u2019s because that one thing simply isn\u2019t good. Sometimes that one thing is really amazing, but it\u2019s not the right time or place and things just don\u2019t come together in the right way\u201D
`; +}); diff --git a/.netlify/server/chunks/2021-04-03-once-upon-a-river-22df99c4.js b/.netlify/server/chunks/2021-04-03-once-upon-a-river-22df99c4.js new file mode 100644 index 0000000..9c9b7e8 --- /dev/null +++ b/.netlify/server/chunks/2021-04-03-once-upon-a-river-22df99c4.js @@ -0,0 +1,63 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_04_03_once_upon_a_river, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Once Upon a River", + "author": "Diane Setterfield", + "score": 3, + "image": "once-upon-a-river", + "slug": "once-upon-a-river", + "book_review": true, + "date": "2021-04-04T00:00:00.000Z", + "finished": "2021-03-25T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "light-fantasy"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Diane-Setterfield/Once-Upon-a-River--The-Sunday-Times-bestseller/24016340" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/once-upon-a-river-8853cf4b-49f2-4c60-995d-d1d16947cbd4/9780743298087" + } + ] +}; +const _2021_04_03_once_upon_a_river = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

This is a lovely book where classically fairy tale things happen. Set on the River Thames in Oxford around the turn of the 20th century, it follows individuals and families as a girl is found not-quite-dead in the river. Everybody sees somebody different in this child, they see the lost daughter they wished they could re-find, or the lost sibling who died some thirty years ago. We follow the people of the village as they attempt to care for, claim stewardship over, and make counter-claims about her. This otherworldly, captivating child precipitates the best and the worst parts of our characters and their pasts.

+

I\u2019ve been describing Setterfield\u2019s book as \u201Cfairytales for grownups\u201D which sounds like a good description to me, but I\u2019m also worried it\u2019s a little dismissive. So please interpret it generously. This book made me feel like stories made me feel when I was younger: something wholly separate from real life. Something that I enjoy living in.

+

The book opens on a pub somewhere along the Thames, near Oxford, where the local townsfolk gather to tell and hear stories. As beginnings go it\u2019s only a few steps over \u201Conce upon a time\u201D but it works. It sets the tone and the expectation: this is a capital-S Story . And by knowing itself, its medium, and its limits, Setterfield gives us permission to get utterly lost and captivated in it.

+

A difference, though, between this book and an actual fairytale is how it weaves in and out of fantastical elements. You can read it most literally as a piece of historical fiction, or more fantastically as a piece of light urban-fantasy set in the past.

+

The core of the story is people: the big cycles of life and death, and the smaller infinite little plots that make up our lives, our families, and our communities. This book never loses focus on the individuals, which reminds me of Ken Follett\u2019s Kingsbridge series of novels. At times, the characters seem villainously evil and heroically chivalrous or noble, but archetypes have a place in stories.

+

Each character seems a little reduced to one trait which dictates everything they do: maternal love, selfish greed, parental guilt, financial gain. It\u2019s a story about people, but those people seem a little simplified at times.

+

Still, I love a character-focused book. I love going page-to-page asking how would people like this react in a situation like that? Like a fairytale, it\u2019s analogous to life: it gives us tools to recognise and understand the actions of people around us, and Setterfield does this well.

+

So I mean it in no belittling way when I say that Once Upon A River is a lovely book.

+

It doesn\u2019t try to introduce new ideas, cunning literary devices, or poetic prose. Sometimes you need this no-nonsense \u201Cimagine these people doing these things\u201D story.

+

There are still moments of gentle beauty and fantastical elements. The language is florally embellished in places, as if it were a well-crafted tale being told aloud to you in a pub in the early 1900s. It\u2019s never self-indulgent, either - the language or words never distract or get in the way.

+

There are certainly a few times where characters seem to transform or shift in a moment. It\u2019s like they were vehicles towards the resolution of the story: for there to be a happy ending they must accept that this child isn\u2019t their daughter, or to be in love one must let their fears go. I did take particular issue with one character who, for very personal and rational reasons, decided that she did not want to have a child - but abandoned those beliefs when she met the right man. A narrative that queer/asexual and anti-children people often face. The \u201Cyou just haven\u2019t met the right man\u201D argument. It maybe would have been nice for the woman to not want children and realise it\u2019s because she wasn\u2019t maternal, or maybe was queer - and resolve the story that way. Setterfield had the chance to break an expectation or convention yet still fulfil a fairytale ending, sort of like a genie, but instead she took the predictable and easy route. But I can\u2019t criticise a book too harshly for wanting to stick to what\u2019s already known, and for sticking to its genre. Still, its a missed chance for more representation.

+

On some deeper level, I think having the characters change so quickly is a nice reminder that sometimes we need to only give ourselves permission to change our beliefs or our action. But I think I\u2019m looking into that a bit too much.

+

It was a nice read, a nice escapism read. It\u2019s a book I\u2019m going to remember because of how it made me feel, not because of the characters or writing. A good solid read for when you need something palatable and easily digestible. 3 \u2B50

`; +}); diff --git a/.netlify/server/chunks/2021-04-08-just-enough-software-design-bb1b6ff1.js b/.netlify/server/chunks/2021-04-08-just-enough-software-design-bb1b6ff1.js new file mode 100644 index 0000000..ae08d23 --- /dev/null +++ b/.netlify/server/chunks/2021-04-08-just-enough-software-design-bb1b6ff1.js @@ -0,0 +1,77 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_04_08_just_enough_software_design, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "How much is just-enough system design for new apps and software?", + "author": "Thomas Wilson", + "date": "2021-04-08T00:00:00.000Z", + "slug": "2021-04-08-just-enough-software-design", + "draft": false, + "tags": ["software", "software-architecture"] +}; +const _2021_04_08_just_enough_software_design = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I wrote this because of a paralysing problem in coding: how much should I design my new app\u2019s architecture before I dive into code if I can only learn about my app\u2019s architecture by coding it?

+

I\u2019m building Dash Dot, an interval timer iOS app from scratch, and this is the problem I\u2019ve been facing this month.

+

The temptation is to answer all possible questions about your app before you start coding it, but you have to resist. It\u2019s good to have an awareness of what parts make up the whole of your system. If you don\u2019t, you\u2019re going to have to refactor and restructure your code frequently, especially at the beginning. But if you wait too long, if you only answer questions, then you\u2019ve got only theoretical answers.

+

The issue is keeping your code and your design in-step with each other. If your code gets ahead of your design, it\u2019s a mess and you\u2019ve got to refactor and wrangle chaos. If your design gets ahead of your code, you\u2019ve got a monotonous boring slog to just implement (potentially over-engineering, or outdated) solutions to changing problems.

+

Code is discovery.

+

Design is discovery.

+

But they\u2019re different kinds of learning, and you need them both. You can split the things you know about your software into two buckets:

+
  • Obvious: These are properties that you can glean, or deduce relatively quickly, just by thinking through your code. Your core business entities need to be persisted, so you need a way of talking to a persistence layer, and you need a way of communicating data from your persistence layer (like a database) to your code\u2019s logic (like an Entity). You need something to manage the publishers in your system, and you need a way for your other components to subscribe to these publishers.

  • +
  • Emergent:: These things become clearer or more important as you start coding. You might notice that your Entity class has reached 400 lines in length, and realise you need a Factory class to take away some of that logic. You realise that you\u2019re passing around data through a lot of initialisers - does it need to be centralised somewhere?

+

As you become a more experienced software engineer and architect, more things are in the Obvious bucket, and less things are in the Emergent.

+

The problem with Emergent Properties is that they are often Unknown Unknowns. Of course, this is a spectrum too. The more you deal with software architectures, the more you know the kinds of boundaries that become problematic.

+

Building the code means we learn more, but not knowing enough means the code we write is less useful. There are some lessons we can learn without coding. My advice? Do just enough design so that you can maximise your learning by building. How do you know how much is \u201Cjust enough\u201D? That\u2019s the whole problem, mate.

+

I\u2019ve been working on the meta skill of asking myself \u201Cis this enough design to get going?\u201D, and then accurately answering myself. That\u2019s what I want to share and talk about.

+

The Takeaways

+

We\u2019re all busy, here\u2019s what I\u2019d recommend:

+
  • Work over dogma: Get the app building and working. Want to list restaurants near you: get that webpage running, that map rendering, and that database queried. It doesn\u2019t matter how beautiful your abstraction if you can\u2019t show your user a list of nearby taco vans.
  • +
  • Design and develop with your brain in mind: I know that I like to do. I like to dive in and get started, so I have to train myself to wait and think things through for a bit before I start. You might be paralysed by the need to perfect the architecture before you even open your text editor. Whatever technique works for you, use that.
  • +
  • Good systems change fast: The code you\u2019re writing at the beginning of an app will either a) live forever, or b) live for the next three days. Make sure new code can be, refactored, renamed, extended, and divided easily. If it\u2019s hard to change, you\u2019ll do bad things or workarounds because it\u2019s easier than doing the right thing.
+

##\xA0Swinging the pendulum

+

My thoughts and approaches to building a new codebase have swung quite a bit over the last two months. I have been developing a la

+
  1. Test-driven development (TDD): build all code from the ground up with tests first. The satisfying red, green, refactor cycle is very rewarding.
  2. +
  3. Interpretive movement development: do what feels right in the moment, just validate with the UI, man.
  4. +
  5. UML-driven development: spent literally hours creating classes, methods, and relationships to understand the system.
+

TDD

+

TDD was my first approach. It\u2019s how I learned Rails back in the day (or at least how I was encouraged to). I have often bemoaned a lack of any testing in a lot of the professional projects I\u2019ve worked on and I thought to myself \u201Cthis app will have flawless testing. I will be the jealousy of the town\u201D.
+Why was I doing TDD? Because I liked the idea of the finished product. I liked having a codebase which I knew worked, it was inarguable. I had green ticks on my CLI, and the knowledge that a particular ticket or branch were complete.

+

I spent a couple of weeks heavily pursuing this goal. However it fell apart. When you\u2019re building early systems and foundational code it is highlly likely that things will change. In fact, I\u2019d say it\u2019s certain. If you\u2019re writing perfect code on day 1 then bully for you but boy am I not that kind of engineer.

+

\u201CBut Thomas, write your tests first to help design your API\u201D. Yeah, actually good criticism. I agree - I think having code and tests consume the API of a class forces you to think about abstraction early. It forces you to decouple things. However, you don\u2019t know everywhere your code is going to be consumed, especially on day 1. You don\u2019t know when certain parts of the codebase are going to grow in complexity and size (and reduce in readability) and need to be split out. And now you\u2019ve doubled the work required in a refactor: you can\u2019t quickly and easily move code about, chop it up, rename it, etc.

+

\u201CBut Thomas, the tests mean that your API surface remains stable so that even when you do that kind of refactoring, the end result still acts as expected\u201D. Right again, in theory. This is great when there is other code in your project which already depends on the stuff you\u2019re refactoring, and you want absolute certainty that what you\u2019re doing won\u2019t break a consumer. But that\u2019s just not what\u2019s happening here. This is the first step of whittling away the wood to let the sculpture emerge, I don\u2019t have to be delicate everywhere. I really wanted TDD to work for me here, and maybe if I was more intelligent and could preemptively know my API it would work. Or, if I was further into the project, it would let me know that I\u2019m doing okay with my refactor.
+As a tool for writing the first bits of a new project, TDD just did not work for me.

+

Interpretive movement design

+

Talk about a kickback reaction. Freed of the expectations of TDD and of the need to really write atomic and comprehensive tests, I just went about doing the thing every engineer loves to do: write code. +I created classes, and modules and methods and functions and utilities and it was lovely. I named things in a way that made sense in the moment and things felt right. I wasn\u2019t constrained by anything and could get my ideas onto the screen quickly.

+

This is a great example of where the \u201Csoftware engineering as a craft\u201D argument gains credibility. This was a swing too far away from discipline and rigour, and towards creativity and reactive-ness. There was no structure to wrangle my code into readable, clear ideas.

+

It didn\u2019t force me to notice similarities in my codebase. It didn\u2019t encourage me to make similar solutions for similar problems, and I ended up writing code which was tightly coupled to its context. Code should be decoupled. The canonical example for this was when I found myself with three Entity classes (the ActiveRecord-like classes which wrapped several persisted entities, like a \u201Ctimer\u201D) and three drastically different approaches to similar behaviours. I had different APIs and implementations for how I validated, persisted, updated/deleted my data - I stored different bits of information about them and under different names.

+

This was a bad approach - I had let myself get too excited with the joy of writing code, and hadn\u2019t taken a step back. \u201CBut Thomas, couldn\u2019t you have exercised a little bit of self-restraint?\u201D. Look. Yes. I have known for a very long time that I, as a person and professional, would much rather learn and discover while and through doing, rather than plan and prepare beforehand. It\u2019s mixed-blessing. Self-knowledge isn\u2019t about trying to change these things but rather putting myself in positions where this isn\u2019t a problem (wisdom to know the difference, and all that).

+

The interpretive-movement style of development was useful. It helped patterns emerged and it also helped me do a lot more than I did with TDD. The result was always on the output: I want to see this data on the screen, I want to be able to have these kinds of interaction. Unlike TDD I was thinking a lot more as a real-life human user of my software, not like a software user of my software. But it needed to be paired with a little more forethought, and something which would help me anticipate similarities before they occurred.

+

UML-driven development:

+

Does anything feel quite so engineer-y as drawing bloody giant UML diagrams. You know the ones, with the boxes and class names and methods and arrows. They\u2019re great. I started drawing these when I came to the next logical part of my app (i.e. how do I, as a user of the app, do a timer).
+I sat down with the fantastic (and free) [diagrams.net] (formerly draw.io) tool to draft up the parts of my system, what they would be called, how they would communicate, what was similar and unifying, and what were the distinct parts.

+

I immediately made the decision to use this diagram as a sketch or an outline. I didn\u2019t want to specify every method, every relationship, every movement. It was about the high-level system design, and not about the specifics. UML diagrams may feel productive, but at the end of the day they\u2019re not code.

+

For me, facing myself to write this broad-outline UML diagrams was just enough design to make the code I was writing feel productive. It guided the direction and structure of the work I was doing, but it was vague enough that I could split things our and change implementation details. For example in a couple of places, I leaned heavily into the Dependency Inversion or Inversion of Control but these didn\u2019t need to be specified in the diagram before hand

+

I knew this approach was just-enough design because before I started writing code I noticed when too much responsibility was being put in one place, and when similarities between components started arising. Just like the frustration of UI/UX design - it was impossible to design a good system by focusing wholly on the components. Components should serve the system and architecture as a whole.

`; +}); diff --git a/.netlify/server/chunks/2021-04-11-things-i-learned-35-34430b12.js b/.netlify/server/chunks/2021-04-11-things-i-learned-35-34430b12.js new file mode 100644 index 0000000..ccbcd92 --- /dev/null +++ b/.netlify/server/chunks/2021-04-11-things-i-learned-35-34430b12.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_04_11_things_i_learned_35, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #35", + "author": "Thomas Wilson", + "date": "2021-04-11T00:00:00.000Z", + "slug": "2021-08-11-things-i-learned-35", + "draft": false, + "imageUrl": "preview-images/35.png", + "tags": ["things-i-learned"] +}; +const _2021_04_11_things_i_learned_35 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The slightly cold-snap here in London continues. The optimistic sewing and sprouting that took place in my garden (such as it is in urban West London) have largely had to retreat to the comfort of the indoors. Covid-related deaths continue to fall in the UK, as we begin optimistically opening up after a very long winter. I\u2019ve started to have more normal moments - more going into a (socially-distanced) office, going to (socially-distanced) gatherings of people outside of my household. With this spirit of early optimism (and copious tree pollen) in the air, let\u2019s begin:

+
  • This fact about parachutes: according to a study published in the British Medical Journal in 2018, the authors found the use of parachutes \u201Cdid not significantly reduce death or major injury\u201D. Rather than a serious study into the efficacy of parachutes for people jumping out of planes (spoiler alert: parachutes will probably stop you from dying, not wearing a parachute almost certainly will not), the authors were taking a tongue-in-teeth approach to the double-blind randomised-trials \u2014 the gold standard in medical research. They argue that sometimes we aren\u2019t able to effectively control, model, or simulate real-life situations for the benefit of experimentation. This is important in fields like medical research, where areas of discussion range from deeply personal experiences (like mental health and trauma) to almost purely biomechanic discussions (like vaccine efficacy). Part of expertise and knowledge is (in my humble opinion) knowing what constitutes \u201Cproof\u201D or evidence in your current area of study. (source)
  • +
  • This (yet) another impact of the pandemic: I like bikes. I think they\u2019re cool. In 2019 I cycled across France on a bike (and I\u2019ve not stopped talking about it since). Since the start of the pandemic, bicycle use in the UK has increased to 120% of its use relative to the year prior. It\u2019s up over 150% on weekends - suggesting that more Brits are getting out for weekend rides. I\u2019ve noticed a much more diverse set of people out on rides during my spring training: it\u2019s not just MAMILs - I\u2019ve seen more women and partners of (presumably) pre-existing cyclists, more amateur groups and also a lot more international riders. The other week I was absorbed by a peloton of six-some Polish (I think) riders on a mix of hybrid and commuter bikes who seemed to be enjoying South London\u2019s cycle superhighways rather a lot. Comparatively, tube and rail use are both down 70%, and cars about 15%. So-called \u201Cactive travel\u201D, like cycling and walking, is an essential part of meeting carbon emission goals. A journey made by bike represents about 30x lower CO2 emissions than a fossil fuel-burning car, and 10x lower than an electric car. (source)
  • +
  • This hat piracy: Benjamin Hornigold was a pirate in the 1700s, and you\u2019ve probably not heard of him. His second in command was Edward Thatch, who went by \u201CBlackbeard\u201D. Hornigold and Thatch ran a thirty gun ship, the most heavily-armed ship in the area at the time, around the Bahamas in the 1700s. Piracy was rife as the Spanish Succession war had come to an end, leaving a lot of sailors and soldiers out of jobs. With no successful re-skilling plan in place, a lot of them too to looting merchant ships around Jamaica and the Bahamas. My favourite story from Hornigold\u2019s time as a pirate is the time he and his crew (about 350 men) got rip-roaringly drunk and threw their hats overboard during the night. The next day they attacked a merchant ship, stole the crew\u2019s hats, left their goods untouched, and carried on. Hornigold later turned pirate-hunter (job title goals), a position at which he was pretty much entirely unsuccessful. (source)
+

What I\u2019ve had on rotation

+
  • Something New The Wind by Balmorhea (2021, Contemporary Classical). A couple of really beautiful classical albums came out this week but this is the one I\u2019ve been drawn to. This is the first album in a while which has been produced largely by just Rob Lowe and Michael A. Muller - the original duet of Balmorhea. This shows - there are moments that are so typically them in their sound and composition. Apparently, it was recorded in the same studio as Nils Frahm records, and it has the same acoustic reverence as Frahms can bring. (links)
  • +
  • Something Old The Resistance by Muse (2009, Rock). I don\u2019t know why I completely ignored Muse while they were pumping out albums like The Resistance, so I\u2019ve gone back to give them some time. The musicality on this album is lovely, the production does feel a little dated in places but there are some real timeless moments. This isn\u2019t so much a rediscovery as a \u201Cgetting round to it\u201D discovery. I\u2019m still very glad that I did. (links)
+

Cool Articles

+
  • How to avoid death by PowerPoint by David JP Phillips for TEDxStockholm. Everybody hates giving presentations. Everybody hates watching presentations. With these things in mind let\u2019s at least work to make them at least a little bit more focused and usable. Phillips focuses on very actionable and psychology-focused tips for improving your PowerPoints. They\u2019re essentially around limiting the number of things you audience has to focus on. That comes from the visual design as well as the overall structure of your presentation. Give it a watch, it\u2019s a little masterclass in giving good presentations, like watching Steve Jobs introduce an iPhone.
`; +}); diff --git a/.netlify/server/chunks/2021-04-12-dash-cycle-01-8d6c6cd5.js b/.netlify/server/chunks/2021-04-12-dash-cycle-01-8d6c6cd5.js new file mode 100644 index 0000000..0ae89ac --- /dev/null +++ b/.netlify/server/chunks/2021-04-12-dash-cycle-01-8d6c6cd5.js @@ -0,0 +1,81 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_04_12_dash_cycle_01, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Dash Cycle #01: (re)organising", + "author": "Thomas Wilson", + "date": "2021-04-12T00:00:00.000Z", + "slug": "2021-04-12-dash-cycle-01-reorganising", + "draft": false, + "tags": ["dashdot", "buildinpublic"], + "imageUrl": "preview-images/C01.png" +}; +const _2021_04_12_dash_cycle_01 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I\u2019m building DashDot: a privacy-focused interval training app that doesn\u2019t suck. The second cycle of development lasted March 15 - April 12. Let\u2019s look at where we are.

+

Goals

+

Here are the things I wanted to achieve in this cycle:

+
  1. \u2705 Finalise the code architecture and restore tests
  2. +
  3. \u2705 Allow someone to complete a (timed) timer
  4. +
  5. \u2705 Focus on the persistence of timers and workouts. Make sure that relationships between these entities are persisted.
  6. +
  7. \u2705 Buy domain names (for app and company)
  8. +
  9. \u2705 Decide on ticketing / management software and method. JIRA vs. Linear
  10. +
  11. \u270D\uFE0F Solidify and scale-back the UI design
  12. +
  13. \u{1F645} Make the UI nice
  14. +
  15. \u{1F645} Continue with TDD and high test coverage
+

Designing Code Architecture

+

This cycle I started running into the limitations and assumptions of my previous software architecture. Four weeks ago I did not have any strong opinions or experience on architecture for a SwiftUI app, but now I do. I wrote about my experience with this pretty extensively elsewhere. In summary, I\u2019ve taken a very Rails-esque approach to the design: splitting my software into models, views, view models, and interfaces. Dividing by function rather than domain model will make some people mad, but it\u2019s actually really helped keep everything clear in my head.

+

I ended up doing a pretty major refactoring of the architecture, which mean that a lot of my previously-written tests were no longer useful, and had to be deleted. I was only attached to them via the sunk-cost fallacy, so away they went.

+

I also got to draw some pretty gnarly, sprawling UML-style diagrams in this process to help me really flesh out my thinking. That was cool.

+

I\u2019ve still not reached the same level of test coverage as I had before, but I do have a much more readable and consistent code architecture so I think the pros outweigh the cons.

+

Allow someone to complete a timer

+

Creating a timer and doing a workout are the two core workflows in DashDot. This cycle I focused on that user journey: letting someone select a timer they wanted to complete and then start doing it.

+

There are a couple of complications here (obviously) but this workflow now functions. In DashDot you can now select a pre-existing timer, and start doing it. The app will persist your progress and process as you go, and progress you through the intervals, etc.

+

So far you can only complete timed intervals (not distance). That\u2019ll be one of two focus points for Cycle#02.

+

Persistence and relationships

+

I spent a good few days really getting into CoreData, managed object contexts, and the ORM-like way of managing relationships between entities.

+

DashDot now persists records of your activities, your workouts, and your timers - all without any fuss. This is an essential feature and I\u2019m glad it\u2019s done

+

I have created an Active Record-like pattern for my business entities, as I didn\u2019t like the idea of manually modifying the generated classes from CoreData. This allows me to have some helper methods on my models to access related data, and to treat what\u2019s in the persisted CoreData layer as DTOs. This is definitely my web influence coming through: treating the data persistence as dumb and largely stateless objects. I\u2019m not sure if this is the best, or most Swifty, way of doing things - but it\u2019s the way that lets me move faster.

+

Purchase domain names

+

I needed domain names for both the app and for the company I\u2019d be publishing it under. I\u2019ve purchased both of those and I\u2019ll share when there\u2019s actually something on them.

+

Project management: JIRA & Linear

+

I had previously been using JIRA to manage my tickets and things to do. I discovered Linear (I think because someone on Under The Radar mentioned it).

+

I\u2019ve completely switched to Linear for managing my tasks. I like it because:

+
  1. It has a native app, even if it\u2019s just an Electron wrapper, it feels surprisingly native
  2. +
  3. It\u2019s free (for me a one-person team)
  4. +
  5. Phenomenal keyboard shortcuts that let you move between tasks and screens, update and create tickets, and do all sorts.
  6. +
  7. Their idea of \u201Ccycles\u201D fits almost perfectly with how I want to think about software development. They\u2019re essentially four-week sprint-like phases. You pick a four week period, acknowledge what you can/not get done during that, and make sure things stay in scope.
  8. +
  9. Nice integration with GitHub - generating branch names for tickets and tracking their progress through PR to merge status. Even working as a one-person team, this helps me focus on \u201Cone things at a time\u201D.
+

Using Linear comes with a lot less friction than JIRA.

+

Scale-back the UI

+

I had a bloody massive Figma file with a whole bunch of screen prototypes and idea exploration. By the time I had spent four weeks doing more code-heavy tasks I had lost track of what was where, what I liked and didn\u2019t like. There was too much in the Figma file and things were too hard to find.

+

So I copy-pasted everything into an \u201Carchive\u201D tab in the file, and largely started from scratch. I used a more simple and iOS-like design. It\u2019s a lot more boring, yes - but it\u2019s also a lot more achievable.

+

Every now and then I go back to the archive and look to see if I had any interesting UI ideas, bits of data, or conventions that I\u2019d like. In general however I am trying to stick to a very simple and limited UI. No fiddly bits or tricky bits, I want to get something out there.

+

I have started this process of redesign, and it\u2019ll continue into Cycle#02. The UI I have in the app at the moment is\u2026 not good or consistent, but it is functional for testing. So I need to improve it.

+

I\u2019ve become a lot more involved and aware of the iOS-specific design scene. Reading a lot of app reviews and listening to podcasts so I can get a better sense of \u201Cwhat makes a well-designed app\u201D.

+

Make the UI Nice

+

I wanted to have a fully redesigned and implemented UI by the end of this cycle. That did not happen, I had other things to do. I\u2019m working on it though.

+

Continue TDD

+

I wanted to continue to develop with tests are the forefront, however the severe refactoring and reorganisation I\u2019ve done have left a lot of my old tests useless, and I decided to move with greater speed by not having as many tests before I commit code.

+

This decision will come back to bite me, I\u2019m sure, but I want to focus on producing something usable and interactable. The code is not the message, the code is the vehicle.

`; +}); diff --git a/.netlify/server/chunks/2021-04-16-things-i-learned-36-aee9efcb.js b/.netlify/server/chunks/2021-04-16-things-i-learned-36-aee9efcb.js new file mode 100644 index 0000000..4af59cd --- /dev/null +++ b/.netlify/server/chunks/2021-04-16-things-i-learned-36-aee9efcb.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_04_16_things_i_learned_36, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Things I learned this week #36", + "author": "Thomas Wilson", + "date": "2021-04-16T00:00:00.000Z", + "slug": "2021-08-11-things-i-learned-36", + "draft": false, + "imageUrl": "preview-images/36.png", + "tags": ["things-i-learned"] +}; +const _2021_04_16_things_i_learned_36 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The cold snap in London is teasing us. Is it over? hopefully. But it will still be ~1C at night so don\u2019t get too complacent. Still, the days already feel long. I can hardly remember it being dark at 4pm but I\u2019m sure I\u2019ll remember as soon as October comes. There\u2019s a lot of spring, summer, and autumn between now and then though. Here\u2019s some things I learned this week

+
  • This Breaking Bad character: Mike Ehrmantraut is one of my top three characters in Breaking Bad (Walter and Gus, in case you\u2019re wondering). He almost wasn\u2019t a significant character at all. Bob Odenkirk, who plays Saul, was needed on set during the filming of season two of Breaking Bad, and so the show writers Brough Mike\u2019s character in to act as a go-between for information in the episode. It\u2019s one of those happy little accidents that remind us that if we roll with an unexpected change or limitation, the we can create something lovely. Maybe it\u2019s different to what we imagined at the beginning, but it can still be good. (source)
  • +
  • This one book: Lord of the Rings, the famous and seminal work for fantasy fiction by JRR Tolkien was written as one book. It was published as three, presumably because someone said to him \u201CJohn, these four hundred and eighty thousand words will not fit in one book, you need three books or we\u2019ll need to sell a magnifying glass to everyone who buys a copy\u201D and then I presume John answered first with a poem or song and then gave his actual answer. Oh, he didn\u2019t? Because that\u2019s not how people speak? Sorry, sometimes I forget myself. Tolkien considered what we now now as \u201Cbooks\u201D as simply \u201Cvolumes\u201D in the story. The crazy part about this fact is that Tolkien wrote every word of Lord of the Rings before he published them, and here I am in 2021 waiting for like a dozen fantasy authors to write book #2 or 3 in their trilogy. (source)
  • +
  • This demographic fact: About a third of new-born babies in the UK have at least one parent from outside the UK. London is a very multi-cultural city, and we\u2019re carrying this figure heavily: 69% of babies are born to at least one parent from outside the UK here, with Newham topping out at 86%. I think that\u2019s cool - the more children that grow up seeing people from different places, seeing different cultures to the one they\u2019re surrounded by immediately\u2026 that\u2019s only a good thing. In a very left-wing-can\u2019t-we-all-just-get-along way: I\u2019m happy to see this. (source)
+

What I\u2019ve had on rotation

+
  • Something New King\u2019s Disease by Nas (2020, Hip Hop). This album won the grammy for best hip hop album and I hadn\u2019t heard that it even existed before. Whoops. Nas, of Illmatic fame, is undoubtedly one of the fathers of modern hip hop. Though, to quote Jay Z on Blueprint: he did put out one good album in ten years. Luckily it was good. Unfortunately I meant I had him written off as a forebear without being an active artist. King\u2019s Disease is good. Like, actually good - not just good because I want it to be good. The beats are slick the vocals and tight, the themes are good. Having two good albums over several decades isn\u2019t a great hit rate. As if I\u2019ve not said enough to crucify myself in the eyes of the real Hip Hop Heads: this album reminds of Common in places, and that\u2019s a good thing to me. (links)
  • +
  • Something Old Summer Suite, Vol 1 by Chad Lawson (2010, Classical). I go through phases of working in silence and to music. I\u2019m emerging from a more silent phase at the moment, but the light and upbeat vibe of this album is a perfect transition piece for that. Pop it on when you don\u2019t think you want sound but silence doesn\u2019t feel right either. (links)
+

Cool Articles

+
  • Greta Thunberg: \u2018It just spiralled out of control\u2019 by Leslie Hook for The Irish Times. A few years ago, Greta was fully in the limelight - very publicly active and outspoken. She\u2019s recently turned eighteen and is back at school in Sweden, studying full time. In this piece, Hook gives a humanising account of Thunberg\u2019s current beliefs and attitudes. I was interested to learn that she doesn\u2019t actively talk about solutions to the climate crisis, seeing that as the job of others with more knowledge and expertise. She\u2019s reluctant to give answers to the big questions, which I have mixed feelings about. Give the article a read, Greta\u2019s a cool person and I think we could all take a bit of her urgency.
`; +}); diff --git a/.netlify/server/chunks/2021-04-17-mrs-death-misses-death-baf54f9b.js b/.netlify/server/chunks/2021-04-17-mrs-death-misses-death-baf54f9b.js new file mode 100644 index 0000000..9e66b48 --- /dev/null +++ b/.netlify/server/chunks/2021-04-17-mrs-death-misses-death-baf54f9b.js @@ -0,0 +1,57 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_04_17_mrs_death_misses_death, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Mrs Death Misses Death", + "author": "Salena Godden ", + "score": 3.5, + "image": "mrs-death-misses-death", + "slug": "mrs-death-misses-death", + "book_review": true, + "date": "2021-04-17T00:00:00.000Z", + "finished": "2021-04-03T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "poetry"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Salena-Godden/Mrs-Death-Misses-Death/25330558" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/mrs-death-misses-death-9781867523253/9781867522959" + } + ] +}; +const _2021_04_17_mrs_death_misses_death = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Godden has been writing and performing poetry since she decided to move to London instead of going to university. \u201CGodden is a poet\u201D headlines my review because it is so evident in every page of this book. Every transition from unknown narrator, to fourth-wall breaking direct address, to poetry, to \u201Cnormal\u201D prose. Godden barely pays attention to consistency when she writes, because she is trying to get across an idea. All books are poor transcriptions of spoken word stories that buoyed humanity through tens of thousands of years, long before we invented written word, paper, and typesetting. This book just acknowledges that more than a lot of other books I have read.

+

Mrs Death Misses Death was written almost entirely in service to an idea. Sometimes you\u2019re not sure what that idea is, and other times you\u2019re frustrated that it is just an idea, without resolution or arc, but most of the time you are spell-bound by how Godden writes. This is \u201Cexactly the sort of thing you expect when a poet writes a novel\u201D, to quote Sara Collins in her review for The Guardian.

+

This is all to say that Mrs Death Misses Death is interesting at a meta level. Perhaps more interesting than it is at the direct substantive level. The characters and story are secondary. The book is written by Wolf, a \u201Cbi-gender\u201D young poet in London who meets death when she sells him some tobacco at a local store. Death, who has always been personified as male, tall, and slender, is shown here by Godden as a young, poor, black woman in London. Because this is the most overlooked, the least seen, kind of person. Wolf is captivated, maddeningly so, by Mrs Death, and Mrs Death is glad of the chance to speak to someone about the endless and laboured process of collecting souls as they leave life. Told in part by Wolf through testimony or flashbacks, sometimes in poems, other times from the perspective of Mrs Death - we explore this idea and the consequences of being or meeting death.

+

The book was written over the past five years, long before anyone could identify a spike protein, face mask, or socially distanced funeral out of a lineup. It was written before death figures filled our every news report for months and months on end. It was written independently of contract, i.e. Godden was writing without obligation to a publisher, and this freedom shows. Humanity and experience, largely unfiltered or unguided, are at the centre of this book, and I don\u2019t think the same result could be achieved if it was rushed or shaped by the need to fulfil or attract external attention. Despite this \u201Cbusiness ruins art\u201D talk, the book has already been snapped up for film or TV by Green Door Productions (a company owned by Idris Elba), as well as receiving generally favourable reviews. It\u2019s not an art-or-money situation.

+

Despite liking the idea of this book, and broadly adoring the language and sentiment, I didn\u2019t find it entirely engaging or sticky. Whenever I was reading it, I enjoyed it, but I did not find myself coming back to it unintentionally. If you can, read this book in as few sittings as possible, I think.

+

It is not a book where things happen, or where particular ideas are explored explicitly. It seems to follow a very brief period of time, a snapshot. We get glimpses of some of the things Mrs Death has to deal with, and the sadness and anger she feels as being seen as a man, and as being the opposite of life \u2014 but we never see that in action. We are with Wolf for the entire book, and Wolf is your classic unreliable narrator, and starving poet. We explore the tension between a childhood trauma caused by the early death of Wolf\u2019s mother and their subsequent upbringing by their bitter and probably cruel grandparents. This idea of intergenerational trauma was something that I loved in Queenie, but here it is not explored in as much length or detail.

+

I am glad I read this book, especially as somebody who loves books and poetry. I love that it wasn\u2019t a \u201Ctraditional\u201D book, and how Godden sees the world, or at least frames the world, in some interesting ways. The sentiment of grief and unresolved trauma runs consistently throughout this book, affecting both Wolf and Mrs Death, a supposedly other-worldly spirit or idea. It normalises the idea that death is a hard thing for those left alive to process. It treats that difficulty with patience and I hope lends sympathy and empathy. But there still weren\u2019t any moments which shone above all others in this book. I would recommend it to you if you love books and reading and language and ideas, but not if you love stories and characters. This from a man who can\u2019t sit easily through a Chekov or Pinter play though, so don\u2019t listen to me. \u2B503.5

`; +}); diff --git a/.netlify/server/chunks/2021-04-24-things-i-learned-37-6d2be3d7.js b/.netlify/server/chunks/2021-04-24-things-i-learned-37-6d2be3d7.js new file mode 100644 index 0000000..1145dfb --- /dev/null +++ b/.netlify/server/chunks/2021-04-24-things-i-learned-37-6d2be3d7.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_04_24_things_i_learned_37 +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const _2021_04_24_things_i_learned_37 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `
+

title: \u201CThings I learned this week #37\u201D +author: \u201CThomas Wilson\u201D +date: 2021-04-24T10:24:00 +slug: \u201C2021-04-24-things-i-learned-37\u201D +draft: false +imageUrl: \u201Cpreview-images/37.png\u201D +tags:

+
  • things-i-learned
+
+

This week I\u2019ve been focusing on perspective and gratitude. It\u2019s harder than it sounds if you feel things are unfair and not in your favour. But, to quote about a million throw cushions on Pinterest: you can\u2019t control life, only how you react to it. So this week I am choosing to react by being grateful. Even if it has to start out feeling like a very pointed lie, or jibe to my less patient self. Anyway here are some things I learned this week:

+
  • This misunderstood emperor: Nero (AD 37-68) was the last roman emperor to be descended directly for Caesar Augustus, the first Roman Emperor. Nero has a reputation for being a little\u2026 callus. He\u2019s the one who \u201Cfiddled while Rome burned\u201D during the Great Fire of Rome in AD 64, and had his mother and (maybe) both of his wives murdered. But apparently much of what we know about him came from biased and vilified accounts of him and his life, which were pushed after he \u201Ccommitted suicide\u201D (if you\u2019re forced to commit suicide it\u2019s more spiritually aligned to murder, I propose) and a new emperor came to power. And then three others after the first, all within the space of a year. When Nero tragically killed himself independent of any political pressures or personal accusations, the power-vacuum left by him had to be filled by other ambitious men. Taking the Roman Empire from stable and long-lasting (normally) emperors into this rocky period required some careful PR work, and a lot of work was done to legitimise and justify the need for his death and the change. Hence much of the accounts and writing left about him are vastly anti-Nero. Our knowledge is largely influenced by the survivorship bias: the things which have survived (like official records and accounts by historians of the time) are obviously walking the party line. However, evidence from graffiti and the common folk, reveal that Nero was actually pretty liked by people, and our image of him as a tyrant is maybe undeserved. He competed in the public games, and acted on stage\u2026 He was probably a well-known and well-liked figure at the time. Scandelous though it may be to have an emperor perform on stage and race a chariot. He did still kill his own mother and wives though, let\u2019s not forget that. (source)
  • +
  • This health benefit of tea: Coffee will forever remain my first love, but as I mature into a young gentleman, I\u2019m looking for any excuse to eat biscuits at about 4pm. Tea is one such excuse, but I ended up catching feelings for tea. Coffee gets a bad wrap for being full of caffein though, and although there are no negative health effects of chronic caffein consumption, I don\u2019t want to be dependent on it. Tea, although containing caffein, is thought to boost our mood and calm us, despite caffein\u2019s tendency to lead us towards jitters if we get a little over-buzzed. For instance, a study on South Korea found that adults who regularly drank tea were 21% less likely to develop depression over their life - the same effect as about 2.5 hours of exercise a week. It\u2019s unclear if this is because of individual or mixed chemicals in tea (like epigallocatechin gallate or l-theanine), or the ritual of preparing and then consuming the tea itself. Don\u2019t underestimate the fact that simply taking 5-10 minutes out of a day to sit down and not be stressed is probably good for us. Nevertheless, it does appear that drinking tea (and not a placebo) does help people a) feel more relaxed, and b) produce less cortisol (the stress chemical) - so in reality, it is likely some combination of the two. (source)
  • +
  • This bee weapon: Bees are cool and really useful. Did you know that they create their own air-circulation system? To keep the temperature in a hive a comfy ~30C, the bees beat their wings to circulate air around the hive. Unfortunately, bees are also under attack sometimes, and not just from cartoon bears with a hunkering for honey. One way that bees can defend themselves from invasive species, like wasps or hornets, is to gather around the invading individual and focus the hot air at the new guest. This essentially cooks them, or overheats them. That\u2019s pretty hardcore, bees. (source)
+

What I\u2019ve had on rotation this week

+
  • Something New Wake by WVNDER (2021, Pop Punk). It feels a little like cheating to call a seven-song twenty-four minute CD an \u201Calbum\u201D but I\u2019ll take it. WVNDER not only have great album artwork (I had a little poke around and couldn\u2019t easily find the credited artist). This is a tight little pop punk/emo pop album with clean vocals and lovely moments. (links)
  • +
  • Something Old Perotin by The Hilliard Ensemble (1989, Choral/Classical). This is one to listen to with headphones, or a good surround-sound. The medieval-era vocals are wonderful to work, walk, and exist to. (links)
+

Cool articles

+
  • Neuroscientist Christof Koch on How the \u201CQualia\u201D of Our Experience Illuminate the Central Mystery of Consciousness by Maria Popova for Brain Pickings. Popova has a gift for merging the scientific and the poetic, though this is slightly easier where the two meet naturally. The study of consciousness is like that: we\u2019re yet to have any functional answers. Instead it\u2019s an area of science where interpretations reign supreme. If I was a cleverer man when I was sixteen years-old and chasing my studies, I would\u2019ve chosen subjects that would let me into neuroscience. In this piece, Popova introduce\u2019s the Romantic Reductionist approach to studying consciousness, adopted by Christof Koch. Koch is a currently-active academic in the realm of consciousness, and his approach merges the reductionist (\u201Cthings can be explained as a system of discrete and interacting parts\u201D) and romantic (\u201Cthings are beautiful and not the sum of their parts\u201D).
`; +}); diff --git a/.netlify/server/chunks/2021-04-27-excommunicate-your-ideas-66e47124.js b/.netlify/server/chunks/2021-04-27-excommunicate-your-ideas-66e47124.js new file mode 100644 index 0000000..bb9f215 --- /dev/null +++ b/.netlify/server/chunks/2021-04-27-excommunicate-your-ideas-66e47124.js @@ -0,0 +1,65 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_04_27_excommunicate_your_ideas, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Excommunicate your ideas", + "author": "Thomas Wilson", + "date": "2021-04-27T20:55:00.000Z", + "slug": "2021-04-27-excommunicate-your-ideas", + "draft": false, + "tags": ["essay", "side-projects"] +}; +const _2021_04_27_excommunicate_your_ideas = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Your side-projects deserve a decisive, merciful death at your hands. You dragged them into this world, you\u2019ll fling them out. And do it quickly.

+

I want to talk about killing our much beloved side-projects, and why this is totally a good idea. Then I want to talk about why this could be a terrible idea. I\u2019m not here for resolutions.

+

There are two parts of my personality, plucked from the universe-scale D&D Players Manual, which make the question \u201Cshould I carry on with this side project?\u201D difficult to answer:

+
  1. \xA0I like to flip-flop - just because you made a decision in the past doesn\u2019t mean it\u2019s the best decision, or that you owe your current time your past self. Your past self was probably dumb and optimistic anyway. What do you know now that you didn\u2019t know when you made the choice? Do you know that you\u2019re not enjoying yourself, that you don\u2019t have the money, that it\u2019s not worth the time or investment? Cool, just put your tools down. This kind of thinking got me out of working freelance, a decision I thought I would love but actually did not. Vive l\u2019empoi.
  2. +
  3. I like to commit - if you\u2019re going to make a decision, act like you\u2019ve made the decision. Sometimes that\u2019s about writing a blog post about random things you learn every week even when you don\u2019t want to. Sometimes it\u2019s about finishing puppy school (with your dog, obviously), or building an MVP of that website you\u2019ve wanted to build since 2014. Inaction is a choice. Relaxation and space are a choice. You can commit to restoring some inner peace and spend every night for four months in silent meditation, or watching Netflix, or going on dinner dates with different friends. Or you can commit to learning a new language, reaching a new fitness goal, whatever. I really don\u2019t care what the goal is, but I like to achieve goals.
+

These two make for often uneasy bed fellows. Not quite sitcom-worthy misanthropes, but the two can make it difficult for me to feel confidently happy or fulfilled. Second guessing? That\u2019s a lot easier.

+

I am a front-end and full-stack software engineer by trade and craft. For the past several months I have been building DashDot, an iOS app for interval training. I started this project because it solves an actual problem I have, and because I wanted to try building something for a different platform.

+

I\u2019m going to stop building that app. I\u2019m not going to caveat that sentiment with \u201Cfor now\u201D or \u201Cat the moment\u201D. I have excommunicated it from my life, and I have no intention to pick it back up, or open that Xcode project. I might do those things, sure. I might try again in the future. I just don\u2019t think I will within the next lunar cycle, and I\u2019m not setting any expectation to myself that I will, either.

+

The minute I made that decision, I felt lighter. I was free from doing something that I had increasingly come to resent. I\u2019m not going to go into all the nerdy details about why I didn\u2019t like iOS development - but the short of it is that I do not want to do it. So I won\u2019t.

+

Maybe I\u2019m weird and this is totally natural to some. Maybe some people love giving things up and can do so without nary a backward glance. You\u2019ll know we\u2019re similar people if hearing that you can do this, that you can simply stop, is a gleeful relief or reminder, not an obvious re-statement. Got a side project that simply isn\u2019t worth the investment any more? Great, kill it. No one\u2019s going to come looking for the body.

+

Though the killing metaphor is satisfyingly dramatic, I think excommunication is the better analogy. The idea of the project isn\u2019t dead, I can still go back to it. You can start building your ideas again whenever you want. Instead, I\u2019ve made the choice to have no interaction with it: I\u2019m not going to design, build, refactor, or plan anything else to do with this project. It\u2019s going to take up no more of my mental time and energy. It has been banished from my kingdom of effort and attention.

+

You might be ready to excommunicate when\u2026

+

You ever catch yourself, mid-activity and think \u201Cwait why am I doing this\u201D. How might you know when it\u2019s time to excommunicate that project from your life? Here are some smells I\u2019ve been looking out for

+
  • Does it spark joy? - 2019 internet meme aside, Marie Kondo has a good point: how does your body respond when you think about, or work on the project? Are you excited by what you\u2019re doing or could be doing? Is it heading in a good direction? Or are you just a little weary?
  • +
  • Is it worth it? - is all this time, money, and mental energy you\u2019re putting into the project actually giving you something back? Investment and returns aren\u2019t just money: does it feel like a good use of your time and attention? If you\u2019re finding it hard to justify to yourself, think about why?
  • +
  • Where is this going? - follow through the thought process for \u201Cwhat happens next\u201D for the next weeks and months. One of the last straws for me and my most recent side project was realising that even if things become wildly successful and people love the app, the thought of having to build, improve, and support an iOS app just did not feel like a good reward. And then if things went badly I\u2019d have to do active work to get more users so that I could support an app I didn\u2019t want to support. Is the project leading me closer to the life I want to live? No?
+

But what if I just keep picking things up and putting them down?

+

I\u2019m worried about being that guys who gets a new personality-defining hobby every other month. I don\u2019t want to be telling my friends how great it is to feel the wet clay between your fingers, and then eight weeks later consider my chances as a professional oboe player. There\u2019s nothing wrong with that, you have to pursue your own happiness in this life, but there\u2019s more than that.

+

I worry sometimes that I jump between things, never finishing them or accomplishing anything with them. But also, massive spoiler alert, no matter how long your streak on Duolingo, you\u2019re still going to die. If you can wring joy from the scarce few hours we have on this giant hunk of space rock then, by all means, flit between things. Flit away. Keep flitting. This is hedonism, which I think gets a bad wrap and has a lot less to do with Roman orgies that you\u2019d think.

+

However, if you only ever get a few steps down a road, or you only do something when it is interesting or enjoyable - we miss out on something.

+

Vasari, the first art historian and also debut biographer of Leonardo, wrote in reference to the famous renaissance artist, architect, natural scientist, and polymath: \u201Cif he had not been so variable and unstable, for he set himself to learn many things, and then, after having begun them, abandoned them\u201D. Leonardo was a flitter.

+

If you\u2019ve got the mental horsepower of Leonardo (which I certainly don\u2019t), then the curiosity does us benefit. Even with his almost mystic mental capacity, and despite working in one of the most productive and talented eras of artistry in European history, Leonardo left behind very few finished paintings. He left behind a lot of notebooks, with questions and observations, and he undoubtedly pushed a thousand tiny journeys forward, but he rarely reached \u201Cdone\u201D in his work.

+

There are no more than eighteen surviving paintings which can be attributed to Leonardo (if you ignore all credible questioning on many of these works). Though to be fair his portfolio includes things like The Last Supper and Mona Lisa, possibly two of the most recognised pieces of western art. This is compared to the literally dozens of paintings by Raphael (who died at 37, a full thirty less life years than Leonardo), or Michelangelo who painted (or supervised) the entire ceiling of the Sistine Chapel\xA0, which accounts for over 500 squared metres and then also he sculpted David. To be fair, Michelangelo was probably a bit too dedicated, and maybe could have loosened up a bit.

+

Unfortunately, no one\u2019s really doing anything comparable to painting the Sistine Chapel anymore. I don\u2019t know why, maybe we\u2019re all too remarkable to be remarkable anymore, or maybe we\u2019ve become numb excellence. You\u2019re not sacrificing an era-defining oeuvre so you can go to an introductory macrame class or get three pages into your bullet journal before never opening it ever again. But I do still think we owe it to ourselves to commit a little before abandoning ship. The process of mastery and craft run deep in us, I think.

+

That\u2019s because new hobbies or side projects are both themselves (i.e. making a clay pot, writing a book), but they are also meta-projects: the process of planning how you will dedicate your time and attention around them. The ability to engage with the terrible, awful imitation you have made and the shining exemplar you were trying to reproduce, and asking yourself \u201Chow did I get this so wrong?\u201D. This is another time to mention The Gap by Ira Glass.

+

If you hang around for long enough, you notice the transition from a project as itself, to a project as a meta-project. I think there\u2019s something inherently valuable in going through that, and I don\u2019t think you can force it.

+

To give an example from my domain, when I dip into a lot of forums for web developers I see piles of novice engineers asking ill-formed, basic questions which either have a one-line answer (\u201Chow do I get data from an API in python?\u201D) or no answer (\u201Cwhich JS framework should I learn?\u201D). But a lot of the conversations I see happening between experienced engineers, or at talks from engineers - these are more philosophical or ideal. Broad, cross-technology approaches, team and inter-discipline management or integration. Once you have reached conversational fluency with the details, you can go one level higher. I really enjoyed learning the basics as an engineer but I am really enjoying the work of a journeyman.

+

Similarly, with writing I deeply enjoy the feeling of having written, I dislike much of the reality of writing consistently. I love having a blog where I\u2019ve written consistently for nearly a year, but I hate the Saturday morning fear that this might be the week I don\u2019t write a blog post about things I have learned. I love organising thoughts after they lay strewn in a text document, having stumbled over each other in a rush to get out of my brain. I love that I nearly always have a conversation starter or something to mention when I\u2019m out at the pub. Or if I was out at the pub and there wasn\u2019t a pandemic.

+

Some of these things are about the actual act of writing but others are, more broadly, because I write. And I think I have only come to enjoy these things, and to even see them in the first place, because I have committed to a regular writing practice. I don\u2019t think I would have got there if I decided to flit between ideas, or if I had committed to only writing when I feel like it or when something comes up. I do not know if I would even think to write something in the first place if I hadn\u2019t.

+

Ultimately, it still doesn\u2019t matter, obviously. I\u2019ll be dust in a hundred years and no one cares if I do or don\u2019t commit to things, so long as I seem happy. But there is hope among all the fatalism. But I think the things you gain, and the muscles you exercise at the beginning of something are different to what\u2019s necessary when the motivation runs out and you\u2019re looking to improve. If those are the muscles you want to build, stop flitting.All this, of course, if you\u2019re able to healthily bare the cost of getting there.

+

Sometimes the answer is a resounding and valid \u201Cno\u201D, \u201CI really don\u2019t want to\u201D or \u201CI hate this\u201D. If it is, excommunicate the project from your life. Put it deep in that freezer.

`; +}); diff --git a/.netlify/server/chunks/2021-05-01-things-i-learned-38-2af7f335.js b/.netlify/server/chunks/2021-05-01-things-i-learned-38-2af7f335.js new file mode 100644 index 0000000..ae6e5a0 --- /dev/null +++ b/.netlify/server/chunks/2021-05-01-things-i-learned-38-2af7f335.js @@ -0,0 +1,44 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_05_01_things_i_learned_38, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "(Not) Things I learned this week #38", + "author": "Thomas Wilson", + "date": "2021-05-01T10:24:00.000Z", + "slug": "2021-05-01-things-i-learned-38", + "draft": false, + "tags": ["things-i-learned"] +}; +const _2021_05_01_things_i_learned_38 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

(Not) Things I learned this week #38

+

This week seems to have really flown by. I\u2019ve decided to take purposeful and intentional time for rest and personal recuperation this week. I\u2019m not feeling burned out, but I could certainly smell some distant smoke on the wind. So here\u2019s to taking evenings to get around to those household repairs I\u2019ve been putting off, to that growing pile of unread books. I said 2021 was my Year of Discourse and as we transition from winter to spring, I\u2019m checking in with myself. I\u2019m observing the change of weather, daylight, and flowers. If you get 15 minutes to just sit in a public park, I would strongly recommend.

+

Because of that I\u2019ve not been browsing the internet as much this week, so instead I\u2019m just popping in with some music and reading recommendations.

+

What I\u2019ve had on rotation

+
  • Something New if I could make it go quiet by girl in red (2021, Pop). I\u2019ve been listening to girl in red\u2019s singles since the algorithm started pushing her to me. The algorithm was right, guys. I love the mellow, low-key sad but energetic vibe of this album. The production makes you want to bop in some places and listen carefully in others. (links)
  • +
  • Something Old Blink-182 by Blink-182 (2003, Pop Punk). I Miss You came on a shared speaker this week and everyone in the room knew all the words, and also how to mimic the winey American grunge accent. I got this album in physical when I was in the last year of primary school, or early secondary school (I can\u2019t remember anything, dude). It\u2019s a great album from a seminal pop punk group who are still influencing the genre. (links)
+

Cool articles

+
  • Breaking Camp by Casey Newton for The Verge. Indie tech darling, Basecamp, really messed up this week. In a company-wide memo they initially banned \u201Csocietal and political\u201D discussions at work, before backtracking a little, and clarifying that they meant \u201Cjust not on the work chat\u201D. To me this strikes of peak tech-bro culture where rich white men believe they can divorce themselves, and exist entirely independent of politics. Unfortunately, running a large, outspoken and (broadly) successful company is inherently a political act. I get the impression that DHH and Jason Fried (the two men at the helm of the company) didn\u2019t see the value in doing the work to create a company which actively combats racism/sexism in the workplace. I mean, I get it, it is work but also for some people simply surviving somewhere where they don\u2019t feel welcome is also work. As I write this, about 25% of Basecamp\u2019s employees (including the heads of marketing and design) have resigned. Unfortunately, I can\u2019t help but shake the feeling that this is what Basecamp wanted, given that they offered a six-month severance package to employees who wished to leave (if they had been there longer than a year). They\u2019ll now be creating an ideological silo with low diversity of opinion and/or representation. What happens now? I honestly don\u2019t know.
  • +
  • A 23-year-old coder kept QAnon online when no one else would by William Turton and Joshua Brustein for Bloomberg. Some of the biggest modern questions, which came to a undeniable and ugly head in January 2021, are about free speech, access to platforms, the responsibility and role of social media platforms in relation to their content. It\u2019s a concern that \u201Cfree speech\u201D is becoming coded language for extreme and polarised speech. It\u2019s worrying that individuals and groups are able to find willing audiences to listen to at-best-grey-area rhetoric, and at worse false and actively damaging speech. The authors of this article look at someone who\u2019s making hundreds of thousands of dollars a year by providing technical services and platform to these damaging figures. Perhaps my favourite quote from the article is:
+

Lim argues that the real political crisis facing the U.S. is not extremist violence but erosion of the First Amendment. He says that restrictions on online speech have already brought the U.S. to the verge of communist tyranny, that \u201Cwe are one foot away from 1984.\u201D After a moment, though, he offers a sizable qualifier: \u201CI never actually read the book, so I don\u2019t know all the themes of the book. But I have heard the concepts, and I\u2019ve seen some things, and I thought, \u2018Whoa! That\u2019s sketchy as f---.\u2019\u200A\u201D

`; +}); diff --git a/.netlify/server/chunks/2021-05-05-after-8ebc5dd7.js b/.netlify/server/chunks/2021-05-05-after-8ebc5dd7.js new file mode 100644 index 0000000..8898232 --- /dev/null +++ b/.netlify/server/chunks/2021-05-05-after-8ebc5dd7.js @@ -0,0 +1,72 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_05_05_after, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "After", + "author": "Dr Bruce Greyson", + "score": 3.5, + "image": "after", + "slug": "after", + "book_review": true, + "date": "2021-05-05T00:00:00.000Z", + "finished": "2021-04-20T00:00:00.000Z", + "draft": false, + "tags": ["non-fiction", "death"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/MD-Dr-Bruce-Greyson/After--A-Doctor-Explores-What-Near-Death-Experiences-Reve/25523446" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/after-a-doctor-explores-what-near-death-experiences-reveal-about-life-and-beyond/9781250263032" + } + ] +}; +const _2021_05_05_after = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Declaration of interest I am a spiritual person. I didn\u2019t come into this book desperately seeking answers, or in need of comfort or certainty. You\u2019re never going to get that from any book, I\u2019m afraid. I believe that we are not just our bodies, and that consciousness exists (at least partially) separately to the brain. I came into this book because I was interested in hearing the experiences of a healthcare and scientific professional, and how they experience / grapple with these questions. And to hear from people who had almost died. That sounds pretty cool.

+

Death, as we know, is the only inevitable thing in our life that isn\u2019t taxes. But people seem to spend a great deal more time and attention trying to cheat or bemoan taxes.

+

After: A Doctor Explores What Near-Death Experiences Reveal About Life and Beyond makes you think about death. Barely two pages pass where Greyson isn\u2019t telling us about a patient they saw who nearly died in some morbidly unique way. All throughout, Greyson approaches the subject of near death experiences (NDEs) as a practiced researcher and medical professional, and in doing so does what all good authors do: places their subject matter bang in the centre of something much larger. Death, living, almost dying, trauma, spirituality, and our relationships with ourselves, our families, and our mortality all come up. And while questions about the experience and impact of NDEs on someone\u2019s life comes relatively answered, these broader questions about how we live are left open.

+

At its core, however, it is a book about NDEs. So let\u2019s talk about that first.

+

Near death experiences are experiences that people have when they almost die. In some cases they do actually clinically die, but they eventually come back. The experiences themselves are vivid, and people who have them can tell them apart from dreams. Apparently they\u2019re not quite like anything else. The term NDE was coined 1975 with Raymond Moody\u2019s Life After Life, though reports of NDE-like events predate this. It has remained active grounds for research by people involved across neuroscience to philosophy and anthropology.

+

Current research suggests that some 10-15% of people who almost die experience NDEs. They are present across cultures, religious/spiritual beliefs, ages, and lifestyles. Greyson takes us through the building block questions like \u201Cwhat is an NDE?\u201D and why they\u2019re worth studying. We get an overview of a few common characteristics: from the relatively innocuous change in time perception and clarity of thought, to seeing one\u2019s body from from outside your self, the \u201Clife review\u201D (the addled phrase \u201Cmy life flashed before my eyes\u201D), and meeting and interacting with deceased people.

+

We are well-guided (though perhaps a little briefly) through the process of an NDE. From its immediate characteristics, to how it changes people in the weeks and years which follow. People who experience NDEs often live a different life after their experience, compared to those who almost died but did not have them. Sometimes they can cause conflict if the experience doesn\u2019t conform to somebody\u2019s pre-existing spiritual beliefs. In general, NDEs seem to be a force for good - leading people to live more patient and compassionate lives.

+

This is a well structured non-fiction book. Any aspiring non-fiction writer would do well to pay attention to Greyson\u2019s ability to plant the seeds of one question in one chapter, and then answer it promptly in the next. In some cases he points at something he\u2019s just said and them tells you he\u2019ll clarify it much later. You\u2019re never left wondering about things - Greyson has clearly guided many a novice down this garden path. This makes for an engaging read, one that you could burn through.

+

At times it is a little frustrating that the evidence seems to be \u201CI met Jane who almost died, and here\u2019s what she reported\u2026 I met Alex who almost died and they said\u2026\u201D. However, this does provide more personable that a table or chart might not. Still, it would have been nice to have a bit more formalisation.

+

In fact the entire book seems to work hard to directly avoid an academic tone. Rigour is very clearly cut off in favour of conversation and engagement. We get glimpses into the fact that Greyson obviously has a wealth of experience in dealing with NDEs and their consequences on others. However, I never got the sense that he had truly mastered the gnarlier corners of the field, or was attempting to push the shape of research forward from a collection of personal testimonies.

+

Depth is sacrificed for breadth in this book, even to the extent where I wonder if Greyson\u2019s success can be attributed more to the impact and consequences of his patients\u2019 experiences than to him as an individual or researcher. I get the sense he might give an excellent hour long seminar, or be lively company at a dinner party, but rather less that he fulfils the detail-oriented academic air. I suspect at least in part that this is because he has less literature to delve through, join together, or refute. He is a story teller, a founding father with a vision of a new nation. He is not a civil servant sorting through the minutia of allocating land and settling legal disputes.

+

At the same time, the only way that you\u2019ll get a sense for the actual experience of an NDE is if you hear them spoken about. You can hear \u201Cout of body experience\u201D and not think about it too much. These are loaded, emotionally- or spiritually-charged terms, for me at least. Having three or four concrete examples, each with undeniably odd situations around them (like noticing the state of someone\u2019s attire while dead and having your eyes covered) does a better job at making you confront these experiences. I don\u2019t think the same could be achieved with the cool, polished marble of figures and numbers.

+

This becomes even more important when people talk about experiences which step past both our every-day lived experience, and the capacity of our language to communicate ideas.

+

It is here that we depart the actual topic of the book, and start talking about the meta aspects. It is here that Greyson is able to throw out half a dozen or observations about medical and scientific research, each fundamental to the way we conduct, review, and communicate research. In short - all very interesting ideas. Certainly they are not ideas to adopt wholesale. This won\u2019t be the book that topples the peer-reviewed, double blind study, but it\u2019s a step towards there.

+

The most interesting question this book raises isn\u2019t \u201Cwhat happens when we die?\u201D it is \u201Cwhat is evidence?\u201D. Greyson works in the gate-kept, largely conforming and heterogeneous landscape of academic research. The focus for many practitioners is on getting enough published research out to justify their positions and move towards promotion and tenure. It is not in their interest, really, to rock the boat too heavily. It is a much wiser choice to make sure your research looks, broadly, as it is meant to look, which means it looks like everybody else\u2019s, and like everything that came before it.

+

This is not the most effective way to study every part of the human experience. If you hold NDE experience to the same standard as a vaccine trial (double-blind gold standard control), you will never get any data or information. From that stand point, NDEs simply do not exist.

+

With the prevailing attitude that NDEs do not exist, if you almost died (especially if you tried to take your own life), and you experienced going someplace else and meeting your deceased grandparents or parents, would you tell the doctors around you what happened? Nope, you\u2019d probably stay quiet and maybe tell one other person in your life. Because NDEs do not exist, and there are no vehicles to get your NDE story outside of yourself.

+

You would be worried the doctors would think you crazy, or judge you, and not listen. There\u2019s a high chance they\u2019d diagnose you with some kind of psychotic episode and maybe keep you in hospital longer. You would have gone through two very impactful events in your life (nearly dying, then having an NDE) and you will have no professional support to guide you through processing these and integrating them into your life.

+

The healthcare professionals made sure the mechanics of your body wouldn\u2019t fail, and then sent you off. This is not the gold standard, end-goal of medical care. The question of \u201Cwhat is data\u201D is not just a philosophical one, it is one which impacts us and our healthcare system.

+

Greyson makes a very convincing case for a human- and experience-centric approach to research. Both in the design of experiments and the consideration of publication. There is no point in doing research if it cannot be effectively conducted, reviewed, and published. If the standards for conducting, reviewing, and publishing research remain narrow, then only some kinds of studies will be published. Or things will be studied with inappropriate methods, because they suit the medium (research) not the subject (NDEs).

+

Research should push our collective understanding forward, and medical research should (eventually) result in better care. To support people who have NDEs, regardless of what you think they actually are, you need to understand them. To understand them, you need to be flexible in how you collect data about them. We need peoples\u2019 testimonies and experiences to be treated as sacredly as though the were field observation or computational data.

+

Even if you don\u2019t care the slightest about the spiritual or moral implications of this book, read it. You might think it all poppycock, but it\u2019s a well told poppycock. Perhaps the strokes are too-broad and the author too American, but this is a good, accessible non-fiction book that raises more insightful points about our (the West\u2019s) approach to healthcare and wellbeing.

`; +}); diff --git a/.netlify/server/chunks/2021-05-05-customer-centric-care-like-a-robot-ad6292bd.js b/.netlify/server/chunks/2021-05-05-customer-centric-care-like-a-robot-ad6292bd.js new file mode 100644 index 0000000..3f7dee1 --- /dev/null +++ b/.netlify/server/chunks/2021-05-05-customer-centric-care-like-a-robot-ad6292bd.js @@ -0,0 +1,43 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_05_05_customer_centric_care_like_a_robot, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "[LinkedIn Post] Being so customer-centric your customers think you\u2019re a robot", + "author": "Thomas Wilson", + "date": "2021-05-05T20:07:00.000Z", + "slug": "2021-05-05-customer-centric-like-a-robot", + "draft": false, + "tags": ["linkedin", "emails", "humans"] +}; +const _2021_05_05_customer_centric_care_like_a_robot = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

(This is a cross-post of a short article I wrote on LinkedIn)

+

Stop me if you\u2019ve heard any of these: \u201Cyour call is valuable to us\u201D\u2026 \u201Con a scale of 1-10 how would you rate our\u2026\u201D, \u201Dat ${(0, import_index_10ac95e2.e)(companyName)} we care deeply about our customer experience\u2026\u201D

+

Have you literally ever believed anybody when you\u2019ve heard or read these things? I have not. Not even once.

+

But we should care. I know Oxwash does. We care a lot that people send us their wedding dresses, bedding, favourite band Ts and home team jerseys. It\u2019s one of the top three reasons I decided to work at Oxwash - everyone genuinely cares \u{1F499} I\u2019m a front-end engineer, I make software that real customers use every day, and I care that they have a good experience. At very least I care that we should know if our software is confusing our new customers.

+

\u{1F447} The good news is, it\u2019s actually really easy to stand out. Literally all you have to do is act like you\u2019re a human being who cares. So I\u2019m bringing four tips on how to talk with your customers like you\u2019re a human who actually cares about them

+
  1. \u{1F575}\uFE0F\u200D\u2642\uFE0F Focus on who you want to talk to: You\u2019re not going to be able to talk to everybody all of the time. You have other things to do. I started talking to first-time Oxwash customers. It\u2019s enough that I\u2019m fielding e-mails every day, but they\u2019re not banging down my door. I think it\u2019s really important your software is understandable to first-time users. If they don\u2019t stick around long enough to learn the\u2026quirks of your system then there\u2019s a problem. You might care about your longest customers, or those in a certain age range or who work in a certain sector. Start small, you can always go bigger.
  2. +
  3. \u{1F916} Automate (but not too much): How many e-mails in your inbox were hand-crafted and delivered by artisanal humans? Probably less than half. Use automation services to send-off e-mails based on database and software events. Use snippets (shoutout to TextExpander and SuperHuman) so that certain thing (like instructions on how to update your version of the app in the App Store) aren\u2019t hand typed every\u2026 single\u2026 time. But always, always put something hand-crafted into a reply, especially when someone\u2019s taken the time to send you useful feedback.
  4. +
  5. \u{1F381} Share your findings: We now run monthly reviews with product, strategic, and technical staff. Every single bit of feedback (critical and complementary), every suggestion, every point of contention is brought up and discussed with real humans so that we can do something with that information.
  6. +
  7. \u23F3 Respect people\u2019s time: Every e-mail I send asking for feedback always gives people the chance to reply with \u201C1\u201D, \u201C2\u201D, or \u201C3\u201D (which stand for \u201Cgood\u201D, \u201Cbad\u201D, \u201CI\u2019m too busy at the moment\u201D). I\u2019d love a considered and detailed response from every customer, but I\u2019ll settle for more data overall, if it means sacrificing a bit of depth. Trust me, people love telling you what could be improved, but rarely care to gush about your software to you.
`; +}); diff --git a/.netlify/server/chunks/2021-05-06-weekly-39-8bc58439.js b/.netlify/server/chunks/2021-05-06-weekly-39-8bc58439.js new file mode 100644 index 0000000..248c25d --- /dev/null +++ b/.netlify/server/chunks/2021-05-06-weekly-39-8bc58439.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_05_06_weekly_39, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Weekly #39 (or #1, whatever)", + "author": "Thomas Wilson", + "date": "2021-05-06T19:44:00.000Z", + "slug": "2021-05-06-weekly-39", + "draft": false, + "tags": ["weekly"] +}; +const _2021_05_06_weekly_39 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I\u2019m going to stop writing my \u201Cthings I learned\u201D blog posts. They don\u2019t serve me in the way that they used to. As I wrote recently: kill your ideas and side projects, gladly and without delay.

+

Death is more of a transition, though. The things I learned this week post is becoming simply _The Weekly.

+

I\u2019m not sure what I\u2019m going to use it to write about, I\u2019m going to take a few weeks to try some new formats out. Starting next week. This week I had to kill an old(-ish) friend.

+

Thirty seven weeks ago (in August of 2020) I started writing a weekly blog post with a collection of random tidbits I had learned that week. I\u2019d also put music recommendations and any cool articles I had come across. It was a great way for me to justify the time I spent on random corners of the internet, and share my love for the world. There\u2019s just so much cool stuff going on. Bees cook their enemies, authors write seminal science fiction books over a summer in an Italian villa with other famous poets, some dudes stop millions of pounds worth of books from Gatwick airport.

+

But I don\u2019t browse the internet as much anymore. If you keep looking at your screen the algorithms will keep serving you up content and it felt a) distracting, and b) like you would never reach the end of it. The algorithms are much less inclined to serve you up random historical facts, and much more inclined to show you snappy videos and hot takes. This is the problem with advertiser-driven models of business. But I digress.

+

I hate homework, and browsing the internet, fighting against the gain of The Feed , started to feel like homework. The knack to a healthy side project is tricking your brain into thinking that it\u2019s not homework (it definitely is though).

+

So I was doing something I didn\u2019t enjoy or want to do because I felt I had to. That\u2019s disingenuous. I don\u2019t want to be disingenuous and I want to spent my time on projects that fulfil me (even if I never do ship them).

+

What now? I want to keep doing weekly posts. I get a lot from it. For the past two weeks I\u2019ve put out a post nearly every 2-3 days. I obviously don\u2019t need the impetuous to write this week. But some weeks I do. As much as I bemoan \u201Cit feels like homework\u201D, sometimes we need that homework. Delayed gratification and all that.

+

So I\u2019m going to continue writing weekly, and call them The Weekly. I\u2019ve got a few ideas about the kinds of thing I\u2019d like to write about, most entirely in the realm of non-fiction, but still distant enough from my day job that I\u2019m not just a software engineer all day every day. But hopefully something with a little more overlap to other areas in my life. Something where the algorithms of content can keep their tentacles away from.

+

I\u2019m uncertain if I would like to write timely or evergreen content. I see the benefit in both. I have written both. Let\u2019s see.

+

This is the The Weekly #39 (or #1 depending on how you count). It\u2019s taken me a few days to decide this was the best idea, and I don\u2019t much fancy trying to whip up something entirely new in the next two days. Accept this apology or don\u2019t.

+

You should write If you are reading this don\u2019t write anything but think you might like to, or would simply like to write more, do it. Weekly. First thing on Saturday morning or last thing on Friday, pull up a chair to your kitchen counter, pour yourself a mug of something hot or a glass of something fun, and start writing. No one\u2019s going to read it anyway.

`; +}); diff --git a/.netlify/server/chunks/2021-05-15-weekly-40-68693d5d.js b/.netlify/server/chunks/2021-05-15-weekly-40-68693d5d.js new file mode 100644 index 0000000..86c4a2e --- /dev/null +++ b/.netlify/server/chunks/2021-05-15-weekly-40-68693d5d.js @@ -0,0 +1,63 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_05_15_weekly_40, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Weekly #40: Garlic & The Ancients", + "author": "Thomas Wilson", + "date": "2021-05-15T10:11:00.000Z", + "slug": "2021-05-15-weekly-40", + "draft": false, + "tags": ["weekly"] +}; +const _2021_05_15_weekly_40 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Okay let\u2019s learn us how over the past 3000 years garlic has been espoused by healers and spiritual leaders to ward off disease and evil. It\u2019ll take you down a rabbit hole of medical advice, social segregation, and spiritual prohibition.

+

Garlic (Allium Sativum, of theAllium genus) has set its roots deep in the human story. And let\u2019s get one thing straight: garlic is bloody great. It\u2019s scientifically categorised in a group of foods called \u201Cplease don\u2019t take these away from me\u201D. Smash it, chop it, then fry it. Or top-and-tail the bulb and put it in camembert. Pop whole cloves in with your salmon, soy sauce, and lemons. It\u2019s versatile. Tell me you\u2019re not drooling a little bit, you liar.

+

The Ancients

+

Records of our obsession with this tiny Allium starts some three thousand years ago, with the Ancient Egyptians, and continue upwards through Europe and Asia.

+

The Egyptians

+

Here\u2019s what we know about Ancient Egypt\u2019s relationship with garlic: i) It made up a massive part of the lower class\u2019 (i.e. slaves\u2019) diet, ii) they recognised it medically, iii) Tutankhamen was buried with some.

+

The Egyptians knew it was an excellent nutritional supplement. It went alongside some probably very bland (but calorific) grains. Porridge and gruel with a side of garlic. Humans will find joy and love near anywhere, but I\u2019m sure it\u2019s a little harder to find when it\u2019s 30+ degrees, you\u2019re building a pyramid, and everyone else around you smells almost exactly like they\u2019ve not bathed for well over a month, and have only eaten porridge and garlic.

+

This wasn\u2019t just random guesswork from the Egyptians to keep their slaves alive longer. The Ebers Papyrus is one of very few surviving full-length (about twenty metres all-in, not a joke) hieratic documents. It\u2019s a medical treatise largely about herbs, dating from some 1550 BC. It recommends garlic as a treatment for abnormal growths. As a fun aside, it also tells us that the Egyptians recognised the heart at the centre of a super important circulatory system.

+

But if garlic was a to medical and nutritional supplement, it\u2019s odd that a couple of bulbs ere found in Tutankhamen\u2019s tomb. It would be like burying the queen with some chia seeds. Of course, it\u2019s always possible that it was left there by a careless labourer on their lunch break, but it could also have been so that the emperor would have something to keep him going in the afterlife. Or it could have been that he just really liked it (my personal favourite theory).

+

Medieval Europe

+

Some two thousand years later, medieval Europe saw garlic as a nutritional or medical plants. It was given to relieve constipation and prevent heat-stroke. Just like the Ancient Egyptians, it was consumed by manual labourers to stave off heat stroke.

+

Medieval healers weren\u2019t messing about: they recognised its medical properties and were bullish on eating it raw. Specifically this advice comes from the writings of Abbess Hildegard of Bingen (1098-1179), who was canonised in 2012. Hildegard was a polymath and advocate for scientific observation and method way before it was cool for anybody (especially a woman) to do those things.

+

To her, our physical and spiritual selves were natural. In general, Hildegard sounds cool: she had prophetic visions of the end-of-days and wrote poetry and composed music. She also left behind medical writings (insofar as medical writings had come in the twelfth century). In these, much as in her spiritual writings, she oriented her attitudes of what was good in terms of viriditas, a Latin word meaning \u201Cgreenness\u201D, as in lushness and growth. Though she didn\u2019t create the term, or really use it consistently, Hildegard saw a lot to be admired and emulated in nature.

+

To medieval doctors, garlic was \u201Chot food\u201D, to be consumed during winter. I don\u2019t mean hot as in heated, I mean hot as in \u201Cthis food will affect your heat humours\u201D. Medieval science understood our body in terms of humours (hot/cold, wet/dry, sweet/bitter). Hildegard recommended we consume garlic in moderation, lest it make our blood too hot.

+

Judaism

+

This idea of garlic as a hot food isn\u2019t unique to Europe. It spread to the middle-east, back to Egypt. The Talmud, the central text of Rabbinic Judaism, refers to Jews who celebrate Shabbat (Sabbath) as \u201CGarlic Eaters\u201D. Despite this culturally-identifying level of garlic love, not all Jewish figures advocated for it.

+

Maimonides (1138-1204) was a Sephardic Jewish philosopher who omitted all favourable mentions of garlic from his texts - advising minimal consumption, especially during the summer months.

+

Garlic is a spiritual force

+

Garlic wards off evil. Although we\u2019ve moved on from understanding garlic as a \u201Chot food\u201D, in many places garlic is seen as a ward against malign spirits.

+

It goes without saying that garlic can ward off a vampires. We use to hand wreathes of it on our house and over doorways to ward off the evil eye. Allegedly King Henry IV was baptised in garlic water.

+

The Ancient Greek goddess Hectate (goddess of crossroads, night, magic, and witchcraft) favoured offerings of garlic. They were seen as a way to ward-off evil.

+

In certain religions (Jainism, Brahman Hinduism, Buddhism) the consumption of garlic is prohibited. Jains believe its harvesting is too harmful for the plants, but other eastern religions see it as too stimulating, and to interfere with our spiritual wellbeing.

+

I don\u2019t think there are many other plants so beloved and feared across the world. To be seen as associated with witchcraft and night, and as worth burying alongside your beloved emperor king. Garlic has touched the collective human story, and it\u2019s cool that so much history lives in something so commonplace

+

Bibliography

+`; +}); diff --git a/.netlify/server/chunks/2021-05-21-weekly-41-311c0739.js b/.netlify/server/chunks/2021-05-21-weekly-41-311c0739.js new file mode 100644 index 0000000..c4f4951 --- /dev/null +++ b/.netlify/server/chunks/2021-05-21-weekly-41-311c0739.js @@ -0,0 +1,62 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_05_21_weekly_41, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Weekly #41: Productivity is a daily ritual", + "author": "Thomas Wilson", + "date": "2021-05-21T20:32:00.000Z", + "slug": "2021-05-21-productivity-is-a-daily-ritual", + "draft": false, + "tags": ["weekly"] +}; +const _2021_05_21_weekly_41 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The Weekly is a 1000-word-or-less essay on something I\u2019ve been thinking this week. Let\u2019s talk about how productivity is (basically) a scam and how daily and weekly rituals are the backbone of any sane person\u2019s productivity.

+

I once had the goal to move to Paris. I didn\u2019t achieve it (there was a pandemic). I had a goal to learn Italian (laziness). We\u2019ve all got visions of our future where we\u2019re cleverer, skinnier, more intelligent, or in my case simply the same person but somewhere else.

+

But we don\u2019t do visions. We reach them. But actually we don\u2019t reach them because the Hedonic Treadmill keeps us all both in motion and stationary at the same time.

+

I\u2019m going to put the tinfoil hat on properly in about 500 words, but I genuinely don\u2019t think productivity people want us to be productive, and \u201Cproductivity\u201D isn\u2019t a thing. It\u2019s a thing only because businesses and organisations need way to quantify the impact they\u2019re having.

+

You are not a business. You are an individual. You do not have to justify yourself economically to anyone. You are whole, you are complete, you are enough.

+

But we all want to be just a little bit\u2026more.

+

The secret to doing that little bit extra is in ritual. Every day you\u2019ve got to wake up and do the hard work of redefining what \u201Cbeing productive\u201D looks like. One day it will be writing a eulogy for a family member, the next it might be six hours of visual design work, or a board meeting. Can you compare these things? Maybe, but what a waste of mental effort you could have spent doing things you actually wanted to do.

+

I\u2019m going to share what that actually looks like.

+

My ritual

+

There are two ways I store my productivity system: in my physical notebook (the Leuchtturm 1917 Hardcover A5 with Dotted Paper) and a digital Second Brain (Obsidian).

+

I use these to do two things:

+
  1. Weekly Note \u2014 Every Sunday I dedicate a double-spread on my physical notebook to a list of things I want to do that week. They\u2019re grouped roughly by work (\u2018ship feature x\u2019), personal (\u20182 x Runs\u2019), side-project (\u2018refactor below-the-fold section of landing page\u2019).
  2. +
  3. Daily Notes \u2014 Every day I have a double spread in my notebook and a daily file in Obsidian. One side of my paper has a list of high-level tasks (\u2018go for run\u2019), and the other has a list of things I might have thought about (\u2018luck is about increasing your surface area\u2019). The digital daily note is infinitely editable. I use it as a scratch pad for writings, or sub-tasks, or links to things I\u2019ve done that day.
+

Every week, before I create the next-weekly note, I review my previous week. I look at what I did during the days, I look at what I wanted to get done, and I index things: thoughts that came up, projects which might be important for long-term use.

+

The entire process is vague and not-specific. But if I go into any more detail it\u2019s not going to be useful to literally anyone else. How many other people are working in a small laundry startup, building language-learning tools, and taking nerdy notes on a small subset of podcasts because one day maybe something will stick and I\u2019ll be able to sound insightful in a conversation. There are none.

+

/Puts on the tinfoil hat/

+

Despite not making it to an apartment in Paris (yet), I like to think that I am a productive person. I got a PhD and once knew a lot of French. A lot of people would like to think they\u2019re productive. Globally, the personal development market is valued at around \\$38b. There\u2019s a lot of money to be made by helping people be more productive.

+

A pessimist would say there\u2019s a lot of money in making people feel unproductive, and that you can make them productive.

+

People will try and sell you a framework, app, or system that will solve all your personal productivity problems. For a long time I was very committed to time-chunking, task managers, and efficient email. I don\u2019t religiously adhere to these anymore.

+

Or worse, there are the Vaynerchuck-esque \u201Chacks\u201D which promise, as Pilta Clark writes in the FT puts it, \u201Cto transform useless, Solitaire-addicted sloths into hard-charging models of efficiency\u201D.

+

Learning the click-baity 14 Must Know Tricks For Productivity From A Wall Street Manager isn\u2019t going to help you.

+

That\u2019s because knowledge isn\u2019t the problem. We don\u2019t have a knowledge deficit. We have abundance. An overwhelming abundance, things we want to do, or should do, or feel like we should want to do. If only we had the time to achieve them.

+

When there\u2019s \\$39b dollars at stake, and you want to keep it there, there are two things you can do:

+
  1. Keep everyone feeling unproductive \u2014 make everyone feel like they\u2019re underperforming and need to keep up. Tell them they are unproductive and that your book or consultation or software are the only way to change that.
  2. +
  3. Keep giving people new goals \u2014 as soon as you\u2019ve achieved one goal, move immediately to the next. Or why even achieve it, just drop it and move on.
+

Most worthwhile goals require sustained effort. Fat comes back, muscles decay, French words disparaissent , and your fingers will forget a G-minor scale very quickly.

+

The modern personal productivity industry is selling you a solution to a problem it created to benefit itself. People started making money off that. Loss aversion keeps that idea alive.

+

Productivity is a daily ritual.

`; +}); diff --git a/.netlify/server/chunks/2021-05-25-hangover-square-baf2a976.js b/.netlify/server/chunks/2021-05-25-hangover-square-baf2a976.js new file mode 100644 index 0000000..a4479cc --- /dev/null +++ b/.netlify/server/chunks/2021-05-25-hangover-square-baf2a976.js @@ -0,0 +1,61 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_05_25_hangover_square, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Hangover Square", + "author": "Patrick Hamilton", + "score": 2.5, + "image": "hangover-square", + "slug": "hangover-square", + "book_review": true, + "date": "2021-05-25T00:00:00.000Z", + "finished": "2021-05-01T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "london", "twentieth-century"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Patrick-Hamilton/Hangover-Square/19065452" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/hangover-square-9781933372068/9781933372068" + } + ] +}; +const _2021_05_25_hangover_square = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I was gifted this book by my mother, so I feel terrible for what I am about to say about it. It was gifted with the best of intentions: someone or other famous reported that it made them feel at home in London, a city I love. But a city that can feel indifferent to you. This book did not make me feel at home in this city. It showed how it is possible for a place to be the centre of art, politics, ambition and still allow anyone to shift un-affixed through their life.

+

Credit where it\u2019s due: Hamilton captures this mood so well in Hangover Square, a book set in London in the winter of 1938. Written between 1939-1941, just as the Second World War loomed and then broke, the backdrop is bleak, and various characters\u2019 enthusiasm for the Nazi regime isn\u2019t particularly endearing.

+

This is a bleak book. There is little in it to broadcast hope. We get a few weak flashes, but we know well enough that they\u2019re faltering and won\u2019t last the evening. Let alone the night. This is thanks to our hapless protagonist, George Harvey Bone: a man who seems rarely to have his own self interest at heart. A man who is in hapless love with Netta, a sometimes actress but always cruel woman who uses Bone for nothing more than social leverage and free drinks.

+

The drudgery of unrequited love apparently runs in Hamilton\u2019s other works, namely Twenty Thousand Streets Under The Sky. He writes it incredibly well. Though I am largely unsympathetic to Bone, Hamilton draws out the sympathy, even when you\u2019re pretty stone-cold on the same narrative arc repeating itself for the fourth-or-fifth time in the book.

+

Netta strings Bone, along with her two other drinking companions (and sometimes lovers) Micky and Peter through the pubs of Euston. Gin and beer and sandwiches appear cycle through this book. Unsurprisingly, Hamilton himself was a drunk. A lonely drunk. But golly can he write.

+

This complete haplessness and lack of control over his whole life makes the book drag. There is little to no change in narrative style or characters throughout the book. We\u2019re introduced to Bone\u2019s \u201Cdead moods\u201D, what we might now recognise as schizophrenic or psychotic/depersonalisation episodes. Times when the illusion of self and consciousness are completely freed from him, and he is overwhelmed by a desire to kill Netta.

+

But these are never explored. He\u2019s had dead moods for his entire life, but he\u2019s not known Netta his entire life. Are they an expression of things he truly wants, or some perfect negative of his \u201Cnormal\u201D self? We\u2019re never given any hint of an answer.

+

At no point do you believe that Bone actually will change, or wants to change. He has no mastery of himself, he is subject to the abandonment of others. Romantically and platonically, people leave Bone. It\u2019s sad, but also I have no sense of who Bone was. He\u2019s taken advantage of by those around him, they see him as nothing more than the taxi fares and gin bottles he can buy. And they\u2019re not wrong. They\u2019re obviously callous and unkind and taking advantage, but\u2026 what else is Bone? Our poetic narrator.

+

If nothing else, read sections of the book, just for the language. It is singularly the largest redeeming feature, making this book worth the (literally groan-inducing) effort that it took from me at other times. It reads as though freshly graduated from the school of Dickens, though with the bone-tired-from-the-effort-of-alcoholism that can\u2019t be bought at eighteen years old. A mature student of the Dickensian school, then.

+

I\u2019m unsure if the prose capture the 1940s accurately, or instead a few decades before. I\u2019m not familiar with literature of the time. The little interactions between characters, or our narrators internal monologue all shine. Simply worth reading. Hamilton was a talented writer, and though I\u2019ll gladly turn my nose up at his choice of subject, the way he wrote it was good.

+

Read it, but don\u2019t expect to be drawn in. 2.5 \u2B50

`; +}); diff --git a/.netlify/server/chunks/2021-05-27-weekly-42-40ad7259.js b/.netlify/server/chunks/2021-05-27-weekly-42-40ad7259.js new file mode 100644 index 0000000..435bde2 --- /dev/null +++ b/.netlify/server/chunks/2021-05-27-weekly-42-40ad7259.js @@ -0,0 +1,65 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_05_27_weekly_42, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Weekly #42: Metaphors for Design - Brutalist Architecture, Gardens, and Video Games", + "author": "Thomas Wilson", + "date": "2021-05-28T18:14:00.000Z", + "slug": "2021-05-28-the-weekly-42-metaphors-for-design", + "draft": false, + "tags": ["weekly"] +}; +const _2021_05_27_weekly_42 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The Weekly is a weekly essay on something I\u2019ve been thinking about in the last seven days. They\u2019re less than a thousand words long. This week I want to talk about the metaphors we use when we talk about designing for the web.

+

I read two (fantastic) pieces on the web this week:

+
  1. What even is a website anyway? by Manuel Moreale, who cited,
  2. +
  3. Brutalist Web Design by Carl Barenbrug
+

Sometimes I have no time for Medium-style self proclaimed \u201Cthink pieces\u201D about the web and technology. They\u2019ll expound self-indulgently on non-actionable points, while the rest of us get on with the mundane tasks of building things. This is a criticism I throw un-ironically from the glass house of my personal website.

+

The above pieces are good. Very good, actually. They remind you it doesn\u2019t have to be like this. We don\u2019t have to design and build websites and web apps against a feature list that never stands still. That we\u2019re building for our audience, not the public.

+

When I started web development, I internally compared what I was doing to Google\u2019s work. Now it\u2019s Stripe\u2019s (their designers are ~ artists ~ though) and a milieu of other web apps. Every user, we tell ourselves, is expecting an experience which rivals AirBNB, and Reddit, and Etsy. Even when they land on our dinky little personal site.

+

I don\u2019t think they are. I think we, the people who design and build things on the internet, are. Not every blog needs a load-balanced Elastic Search instance against it. Heck, not every website needs Card or a Menu component.

+

You can build a feature complete website with maybe a dozen html tags and a single CSS file. Does it even need JavaScript? It\u2019d be heckin\u2019 fast and SEO optimised to boot.

+

It doesn\u2019t matter what other people are doing. Your website probably won\u2019t turn into the next Reddit or Tumblr. A website can be feature complete. A feature list can not grow.

+

Barenbrug\u2019s piece (mentioned at the top) argues that we can see websites like Brutalist Architecture: created and inhabited by humans\u2026

+

Brutalist architecture not only reduces construction to its basic materials, but it also finds beauty in that simplicity.

+

I like being reminded of this. I like the Brutalist Architecture metaphor.

+

There are two other metaphors which I think about a lot when I step back from building.

+

That Garden Metaphor

+

I heard about this quote this from George R R Martin, in the context of writing:

+

I think there are two types of writers, the architects and the gardeners. The architects plan everything ahead of time, like an architect building a house. They know how many rooms are going to be in the house, what kind of roof they\u2019re going to have, where the wires are going to run, what kind of plumbing there\u2019s going to be. They have the whole thing designed and blueprinted out before they even nail the first board up. The gardeners dig a hole, drop in a seed and water it. They kind of know what seed it is, they know if planted a fantasy seed or mystery seed or whatever. But as the plant comes up and they water it, they don\u2019t know how many branches it\u2019s going to have, they find out as it grows.

+

I like this metaphor because it is chaotic and unpredictable. It\u2019s non-committed and it changes. I think these are good qualities to have in technology, and life.

+

Gardening acknowledges the life of a project is out of your control. Something you can guide, and give suggestions to, but eventually something that will thrive best when given good conditions and space.

+

The Video Game Metaphor

+

I can\u2019t remember where I heard this first. I found some good articleson it, though.

+

Video games are expertly and intentionally designed. Everyone who designs things can learn something from them. I like the analogy for two main lessons:

+
  1. Your design needs to get out of the way
  2. +
  3. Design can reduce friction, not make everything easy
+

Get out of the way. No one plays a game for the User Interface (UI) or Heads Up Display (HUD) design. But a bad design will ruin your experience as a player. Because it gets in your way.

+

Nobody goes to QuickBooks because they just want poke around. People go to QuickBooks to make sure their receipts, invoices, and payroll are up to date then they get the hell out of there. Nobody opens the inventory in Diablo II to browse, you open it to check the stats on your fire staff and equip or sell it.

+

I work at a laundry company. I agonise over creating the best user experience and interface elements I can. People don\u2019t go to our website because they want to look at a list of things they could get cleaned. They go there to get their things cleaned then get out. People don\u2019t want to notice my new Receipt component design.

+

Reduce friction. Video games are challenging. It makes them rewarding. Hollow Knight is maybe the most frustrated I have felt in 2021 so far and we are in a pandemic. Hades is so frustrating I could cry at times.

+

If QuickBooks\u2019 goal was to remove all stress and difficulty from a user\u2019s life, they\u2019d just say \u201Cpay us \\$1/mo and we\u2019ll do all your accounting and filing and you\u2019ll never have to worry about it\u201D. The business fails but the customer succeeds.

+

Your website or app is one thing your user will do today. Then, if you\u2019re lucky, they\u2019ll forget about you completely, and move on. They\u2019re okay with the friction of the task at large. Taxes are annoying, bank statements are annoying. But you can\u2019t solve that unless you become a government or bank.

+

Don\u2019t solve the puzzle, be a good puzzle piece.

`; +}); diff --git a/.netlify/server/chunks/2021-06-03-project-hail-mary-b8c7d57d.js b/.netlify/server/chunks/2021-06-03-project-hail-mary-b8c7d57d.js new file mode 100644 index 0000000..9ed486f --- /dev/null +++ b/.netlify/server/chunks/2021-06-03-project-hail-mary-b8c7d57d.js @@ -0,0 +1,64 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_06_03_project_hail_mary, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Project Hail Mary", + "author": "Andy Weir", + "score": 3.5, + "image": "project-hail-mary", + "slug": "project-hail-mary", + "book_review": true, + "date": "2021-06-03T00:00:00.000Z", + "finished": "2021-05-14T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "sci-fi"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Andy-Weir/Project-Hail-Mary--From-the-bestselling-author-of-The-Martian/25683365" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/project-hail-mary-9780593395561/9780593135204" + } + ] +}; +const _2021_06_03_project_hail_mary = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

When you read a Dan Brown book you leave it ready to put on your tin foil har. Andy Weir books make you feel ready to don a lab coat. He writes books that are clearly well researched and very involved, but they\u2019re still readable. Dan Brown gets (at most) one of these two things.

+

Project Hail Mary is inevitably going to be compared to Weir\u2019s 2011 The Martian, a book which received (well deserved) critical and public acclaim. It\u2019s a good book (read it) and an okay movie (watch it with friends, drink if you want). Just like The Martian, we follow a lone human (Ryland Grace) confined in a spaceship in space and faced with a laundry list of life-threatening problems. Grace is there because there\u2019s an existential threat to the human race, and so he\u2019s got to get on a space ship to solve it.

+

Whereas The Martian\u2019s Mark Watney speaks to us through Captain\u2019s Log entries (v. enjoyable), Project Hail Mary has a more traditional narrative. Weir\u2019s 2017 Artemis follows a bigger cast of characters, so the narrative is more traditional. In fact, Artemis suffered a bit too much from bing \u201Cmore traditional\u201D which is why not a lot of people talk about it.

+

The writing in this book is solid. It\u2019s caricatured in places, and rarely (if ever) poetic. I wouldn\u2019t highlight or want to remember any particular part of this book. But I didn\u2019t expect it to be. Weir presents us with some really interesting biological/evolutionary theories and ideas, which challenge what you might think of as \u201Clife\u201D. I don\u2019t need lyrical prose if you\u2019ve good big thinkers like that one. Still, don\u2019t expect to have your morals shifted.

+

Take his book as something to be enjoyed on its own. It\u2019s like a party: good for you to do, but hard for you to explain why.

+

We follow Grace through various engineering and biological challenges, twists and turns, which he dutifully solves as he tries to save a) himself, and b) the rest of humanity. The pacing is textbook. It is predictable and unsurprising, but well-enough written that it never lags, though towards the end you certainly start to predict the rhythms.

+

The other problem is that the stakes never differ, or feel actually on the line. A problem emerges which is a 6/10 emergency, Grace does something to solve it and it goes down to a 0-3/10, and then something unexpected happens and we\u2019re at an 8-9/10 before he solves things and we move on to the next cycle.

+

Even though you might not understand the problems, you always know that Grace is going to solve the problem, because Grace always has solved the problem. Everything is going to be okay in the end,.

+

The content of the problems is what makes them interesting each time, though. Weir brings a level of knowledge and a depth of research that make you feel glad that you\u2019re not on a spaceship and that humanity isn\u2019t depending on you. Weir has the great scientific quality of \u201CX happened\u2026 so therefore Y\u201D. He\u2019s able to set the table rules in physics, chemistry, and biology and then explore problems close enough within those rules.

+

If you\u2019re a practicing research scientists in any of these areas I\u2019m sure you\u2019ll roll your eyes at it. I\u2019m sure it doesn\u2019t withstand informed scrutiny, but I enjoy it.

+

Despite all this heroism and know-how, Grace is a coward. Not an entire coward, not cripplingly. Humans can be many things in many contexts. Grace is a high school teacher in his 30-somethings (before he goes to space). His life has been shaped heavily by a lack of action or boldness in everything other than his academic career. Even in that he doesn\u2019t commit to it.

+

We don\u2019t see any character development or changes in him. At the end of the book you know that he\u2019s the same person he was at the beginning, and I\u2019m unsure if he\u2019s had any level of self-awareness or knowledge. But (low-level spoilers here) he does manage to save the world and humanity, so maybe he\u2019s earned the right to stay a flawed man.

+

It\u2019s a reminder that \u201Ccowardly\u201D people can do good things, and that Andy Weir can write excellent science fiction, just maybe not great character work.

+

I listened to the audiobook of this one, and I would definitely recommend. There are parts of the book which play with sound/language, where having an audio component really made this shine. The production quality added in a few non-vocal aspects which really brought it to life. I would totally recommend picking this up on Audible if you even remotely like audiobooks.

`; +}); diff --git a/.netlify/server/chunks/2021-06-05-weekly-43-a2087a97.js b/.netlify/server/chunks/2021-06-05-weekly-43-a2087a97.js new file mode 100644 index 0000000..a62fb88 --- /dev/null +++ b/.netlify/server/chunks/2021-06-05-weekly-43-a2087a97.js @@ -0,0 +1,69 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_06_05_weekly_43, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Weekly #43: Vision, problem, and action", + "author": "Thomas Wilson", + "date": "2021-06-05T10:16:00.000Z", + "slug": "2021-06-05-weekly-43-vision-problem-action", + "draft": false, + "imageUrl": "preview-images/43.png", + "tags": ["weekly"] +}; +const _2021_06_05_weekly_43 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The Weekly is a weekly essay where I write about something I\u2019ve been thinking about in the last seven days. They\u2019re under 1000 words, and this week I want to talk about vision and problems when you\u2019re building a new product.

+

I\u2019m building the lexicon, where I am (un-ironically) trying to build the world\u2019s most useful language learning resources. I like Duo Lingo, but I don\u2019t think it helps you much in the real world \u2122\uFE0F. It\u2019s born out of my desire (and previous moderate success) to be come proficient in French. The pandemic slashed my French proficiency, though.

+

Over the past few weeks I\u2019ve been thinking more about this product idea. I think there\u2019s enough scope in the vision of \u201Cbest language learning resources in the world\u201D that I can meaningfully do something new. I think I know enough about computers and learning to do something impactful.

+

The first thing I did? Set up a landing page with a sign-up form for a mailing list, and released two (free) sets of flash-cards with the most common words. If you want them, you know where to find them.

+

None of these things (which took real time and energy) solve any of the core problems that I\u2019m trying to solve, though. I\u2019ve got a vision for the company, and these things move me generally in the direction of it. I can\u2019t sell anything if people can\u2019t find where to buy it.

+

But I don\u2019t think I solved the high value problems.

+

In his essay how to get startup ideas Paul Graham says:

+

You should only work on problems that exist. And yet by far the most common mistake startups make is to solve problems no one has\u2026 The verb you want to be using with respect to startup ideas is not \u201Cthink up\u201D but \u201Cnotice\u201D\u2026 The most successful startups almost all begin this way.

+

I created this vision because I noticed a problem: I want to learn a language in an efficient way, that gets me to real-world use quickly. Having a landing page does nothing to solve that particular problem.

+

What Graham says is (probably) true, but I also think they miss out on another dimension of problems: the specificity / uniqueness of them.

+

Getting Specific: Flashcards

+

Let\u2019s get specific.

+

I produced some flashcards sets. These keeps within the vision, but what problems do flashcards solve?

+
  1. Target-language translations of words (\xEAtre \u27A1\uFE0F \u201Cto be\u201D)
  2. +
  3. They decide what word\u2019s you\u2019re learning
  4. +
  5. The can be used in Active Recall
+

This list, broadly, runs from most generic to most opinionated solutions.

+

1. Bilingual translation Could you learn French with resources which just showed you the words in the target language. Verser, manifestation, et vaccin.

+

Have you just learned to pour/contribute, protest (noun), and vaccine ? No. You maybe could have guessed the latter, though.

+

To remove the bilingual elements of language-learning flashcards would be an unexpected feature. Maybe replacing them with image/sound can help (an auditory component for French \u2194\uFE0F English translations would be beneficial) but largely, you need the bilingual text. This isn\u2019t a high-value problem.

+

2. Decide what wordsWhat words should I learn? This is a more interesting problem. It\u2019s actually one of the core problems that lead me to think about the lexicon. I don\u2019t think we teach useful words to new language-learners.

+

The problem of \u201Cwhat words do we learn, and in what order\u201D is a problem worth solving. So I used data-backed findings to decide on the most common verbs. This is a higher-value problem.

+

3. Encourage Active Recall\xA0Active Recall is, almost irrefutably, a core component of any language-learning practice. When you use flashcards, you should see the prompt and guess the answer (actually guess it, like, say it aloud) before viewing the answer. Anything else is passive recall or lying to yourself.

+

Active recall is essential to any effective language learning practice, and I was leaving it as optional. \u201CHere\u201D, I said, \u201Care some flashcards. You know how to use them effectively, right?\u201D.

+

A foolish assumption that was probably false (no one teaches these skills de facto in schools) which essentially let the user determine exactly how effective or useful the language-learning resource was going to be

+

I had a chance to solve an important and unique problem (how to pair the \u201Cright\u201D words with the \u201Cright\u201D learning method) and I delivered it in static flashcards. I moved towards the vision without solving the particular problems: actually increasing your French vocabulary.

+

I left the hard work of solving the problem to the customer. I shifted responsibility.

+

Visions are slopes, problems are places

+

I was guided by a vision, without thinking about the unique and important problems.

+

A vision is like a slope. It\u2019s easy to know when you\u2019re heading up or down hill, and you can conform to a vision by degree: head directly down hill, or go diagonally.

+

If a vision is a slope, a problem is a place. Or a least a region. The further away from the problem you are, the easier it is to head towards it. When you haven\u2019t started, doing almost anything will get you closer. Setting up a landing page and a mailing list, for example.

+

But you get a bit closer and you\u2019ve got to change bearing. You were heading east, but now you\u2019ve got to head north-east. And then north-north-east. Anything other than that and you start veering away your destination. Maybe you\u2019ll find a different problem along the way (the infamous pivot) or maybe you won\u2019t.

+

A mailing list, a landing page, and some static flashcards are not the world\u2019s most useful language learning resources. They\u2019re part of the vision but not the product,

+

Set vision, solve problems.

`; +}); diff --git a/.netlify/server/chunks/2021-06-10-weekly-44-618d9f06.js b/.netlify/server/chunks/2021-06-10-weekly-44-618d9f06.js new file mode 100644 index 0000000..e033533 --- /dev/null +++ b/.netlify/server/chunks/2021-06-10-weekly-44-618d9f06.js @@ -0,0 +1,63 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_06_10_weekly_44, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Weekly #44: Thinking about Conspiracy Theories", + "author": "Thomas Wilson", + "date": "2021-06-10T20:18:00.000Z", + "slug": "2021-06-10-weekly-44-thinking-about-conspiracy-theories", + "draft": false, + "imageUrl": "preview-images/44.png", + "tags": ["weekly"] +}; +const _2021_06_10_weekly_44 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The Weekly is a series of essays under one thousand words where I write about something I\u2019ve been thinking over the last seven days. This week I want to talk about misinformation and conspiracy theories surrounding Covid-19, and why they\u2019re more harmful than previous conspiracy theories. I\u2019ve been a little busier than usual this week, so let\u2019s get into it

+

Alongside the actual pandemic of Covid-19, the World Health Organisation (WHO) has declared an infodemic: the \u201Cfalse or misleading information in digital and physical environments during a disease outbreak\u201D.

+

The consequences of misinformation worsen the effect of a disease on a population (that\u2019s us). They can work directly by encouraging less-safe (i.e. less adherence to preventative measures, like wearing a mask or social distancing), as well as specifically dangerous (intentionally attempting to spread the disease) behaviour.

+

Compassion & Sympathy

+

Before I begin, I also want to add that over the past few weeks I have felt a lot more sympathy for those who believe COVID-19 misinformation. They are typically associated with lower education, lower trust in the government, lower income, and lower scientific trust.

+

An American study which looked at adherence to social distancing measures in American citizens found that those who disregarded social distancing were more likely to to have great \u201Cpseudoscientific beliefs, lower governmental and institutional trust, lower risk perceptions, and [conservative political] affiliation\u201D.

+

I used to think believing the conspiracies was a choice, and now I think it\u2019s much more a consequence of feeling unheard. Of seeing the world as unfair, and seeking a reason other than ignorance or a bureaucracy-over-people government.

+

Believing these conspiracy theories is easier when you don\u2019t want the world to be unfair. When you don\u2019t want there to be a disease that doesn\u2019t threaten you, but does threaten others. So you have to sacrifice something for \u201Cnothing\u201D in return . I\u2019ll touch on cognitive dissonance later, but I think we\u2019re retrofitting what we\u2019re seeing into what we want to believe.

+

\xA0Belief in multiple conspiracy theories

+

I\u2019m near the end of R. Brotherton\u2019s Suspicious minds: why we believe conspiracy theories. In it, they talk about how belief in conspiracy theories are often correlated. If you believe in one, you\u2019re likely to believe in another. Even when they\u2019re unrelated.

+

Previously, this would mean believing that the Kennedy assassination was connected to 9/11. Or that the Freemasons secretly run our governments and plan our wars. But what do you do with that information? Trot it out at parties to a silence nobody feels comfortable filling, or share it among your co-conspirators to nods and disgruntled feelings?

+

You might be (probably) wrong, but you\u2019re also (probably) not hurting anybody with your beliefs.

+

The Wikipedia page for Covid-19 Misinformation runs several thousand words, and details at least ten broad categories of misinformation. These fall into a few groups:

+
  • The disease: e.g. the belief that COVID-19 was created and released by a secretive global organisation or government to control the global population; or that the mortality of the disease is not worth worrying about.
  • +
  • Medical and scientific responses: e.g. the belief that vaccines or medications are not safe or could even be designed to actively harm people
  • +
  • Social responses: e.g. the belief that some government or secret organisation are trying to make us obedient to their commands
+

These are massively different types of arguments. But they all push behaviour in one direction: less adherence to public health policy. Less social distancing, less vaccination, more deaths and suffering.

+

Separate among the conspiracy theories which have emerged are that COVID-19 was a virus invented as a weapon to control global population, as a trigger to get us to inject microchips into our brains for mind control or to impart our ability to reproduce, and as a way to get us used to wearing face-coverings to make us more obedient citizens.

+

If you\u2019ve got brain control, you don\u2019t need to persuade anyone. If you\u2019re trying to control population in a physiological way, why do you need wilfully obedient citizens?

+

It\u2019s possible to hold conflicting beliefs in our head. Our brains will shape them until they\u2019re in-accordance with each other. We call that cognitive dissonance, and it saves us from a lot of distress and time wasted in examining everything we believe and do before we assimilate something new.

+

Now, with COVID-19, even disconnected beliefs are pointing people\u2019s actions in a single direction. Belief a maligned global power set against the free will of the people, or corrupt medical researchers, or an evil foreign state all point towards the belief that adherence to public health behaviours should be ignored because COVID-19 is a) not-existent, b) not dangerous, or c) a weapon to control us, and should be ignored.

+

Belief in one conspiracy theory makes you more likely to believe another, even when they\u2019re not related. Even when they\u2019re directly opposing.

+

Conspiracy theories fill a vacuum

+

We do not know everything about COVID-19. The origin and nature of the virus itself, our governmental and societal response to it. The chance that we, in June of 2021, know everything there is to know about a pandemic which is still happening are very low. We do not know everything. That statement is caution.

+

This need for caution, of not overstepping our boundary or certainty, has left gaps in people\u2019s understanding of the disease.

+

A theory with less evidence than the one it opposes shouldn\u2019t be able to dislodge one with more explanatory power. But they can. When they\u2019re more appealing or more conforming or more sensible to the people hearing them.

+

We\u2019re already susceptible to these beliefs, and we don\u2019t have the infrastructure (legislative, technological) to stop them spreading. So they\u2019re spreading. And they\u2019re changing actions.

+

So they\u2019re causing unnecessary deaths.

`; +}); diff --git a/.netlify/server/chunks/2021-06-13-infinite-coast-of-problem-solving-20326007.js b/.netlify/server/chunks/2021-06-13-infinite-coast-of-problem-solving-20326007.js new file mode 100644 index 0000000..5865a8b --- /dev/null +++ b/.netlify/server/chunks/2021-06-13-infinite-coast-of-problem-solving-20326007.js @@ -0,0 +1,47 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_06_13_infinite_coast_of_problem_solving, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The infinite coast of problem solving", + "author": "Thomas Wilson", + "date": "2021-06-13T19:48:00.000Z", + "slug": "2021-06-13-infinite-coast-of-problem-solving", + "draft": false, + "tags": ["lexicon", "design", "product"] +}; +const _2021_06_13_infinite_coast_of_problem_solving = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I\u2019m currently designing and building the lexicon, ambitiously explained as \u201Cthe most useful language learning resources in the world\u201D.

+

The problem is that there\u2019s a lot involved in that, you know? There\u2019s theoretical questions like \u201Cwhat does most useful mean?\u201D and \u201Chow do humans learn languages\u201D?

+

Then there\u2019s small problems like \u201Cwhat is the shape of the JSON I send to the client?\u201D and \u201Chow do I generate prompts & questions for language learning?\u201D.

+

I\u2019ve been thinking about these problems, in some capacity, for legitimately years. So it\u2019s no wonder that I come to them with so much gusto.

+

A lot of the questions are nebulous. \u201CBest\u201D is subjective, and learning is a spectrum. Proposing theories and ideas is okay, but making something and finding out is even better.

+

The questions are big, and important to me, and so I don\u2019t want an imperfect solution. The tech has to scale, the processes have to be automated, everything has to be just so. I\u2019m building tools for problems I haven\u2019t encountered but know I will encounter. Or would encounter, if I just got on with the work.

+

Problem solving is fractal. Every step you propose to get from A to B has a whole subset of steps if you look at it closely. If you\u2019re not careful it goes from A -> B, to A1 -> A2, to A1.i -> A1.ii.

+

It\u2019s like how [the coastline has theoretically infinite length].

+

What I\u2019m saying is that this week I challenged myself: no code, just design. Just product problems and questions. No infinite coastlines, no cartography.

+

So I made some designs. They\u2019re down below. This is what happens when I ask the question \u201Cwhat could the future of language education actually look like\u201D and then demand a concrete answer from myself.

+

${

+

${

+

${

`; +}); diff --git a/.netlify/server/chunks/2021-06-13-sistersong-b84e41c1.js b/.netlify/server/chunks/2021-06-13-sistersong-b84e41c1.js new file mode 100644 index 0000000..37d5bd1 --- /dev/null +++ b/.netlify/server/chunks/2021-06-13-sistersong-b84e41c1.js @@ -0,0 +1,60 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_06_13_sistersong, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Sistersong", + "author": "Lucy Holland", + "score": 3.5, + "image": "sistersong", + "slug": "sistersong", + "book_review": true, + "date": "2021-06-13T00:00:00.000Z", + "finished": "2021-06-01T00:00:00.000Z", + "draft": false, + "tags": ["fiction", "fantasy", "historical"], + "links": [ + { + "country": "\u{1F1EC}\u{1F1E7}", + "store_name": "Hive", + "link": "https://www.hive.co.uk/Product/Lucy-Holland/Sistersong/25288479" + }, + { + "country": "\u{1F1FA}\u{1F1F8}", + "store_name": "bookshop.org", + "link": "https://bookshop.org/books/sistersong-9780316320771/9780316320771" + } + ] +}; +const _2021_06_13_sistersong = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Sistersong is the debut novel from Lucy Holland. Set in Dumnonia, the Celtic kingdom which lasted between the 4th-8th century in what is now South West England, it follows the three children of the king (introduced as Riva, Synne, and Keyne), as they come of age and start to see the word \u201Cas it is\u201D.

+

The world now is far from the one the siblings grew up in. Threatened by the surrounding Saxons, losing connection to the land\u2019s magic, and waining religious beliefs all give this book an excellent backdrop. The world that Holland constructs (and the people she puts in it) are granular and realised. Holland believes a world into being, almost effortlessly. Dialog never feels forced, and the relationships between the siblings are rendered wonderfully.

+

\u201CFantasy\u201D literature is a broad scope, and books like Sistersong do it justice by creating these complex, real characters. Although the book is set in an historical-fantasy setting, it is just a setting. I don\u2019t think I\u2019ve read a book that gives such, almost casual, voice to figures who might otherwise be voiceless. The prominence of trans, or gender identity, themes in this book came across as far more important than anything else. But still, other elements and people and their relationships come through.

+

Yeah, there\u2019s magic, but even if there\u2019s magic there\u2019s still siblings who argue, and parents who don\u2019t accept when their children grow up, and men who only want one thing (sex). I would have a hard time putting this book into any particular genre

+

Despite this excellent character work and writing, the pacing was off for me. The first and last third of the book felt right: things moved along at the right pace. Though I definitely felt the book swerve after maybe 100 pages. I feel like a certain pathway for the plot was set up, and then we just hopped over to another story. This felt jarring.

+

The middle third felt a little aimless at times, and without more of the world to investigate, or seeing things change, it felt like a slog to get through. The world painted is pretty bleak: the weather isn\u2019t great, there\u2019s a threat of a foreign invasion, and there\u2019s generally a lot of mistrust. I don\u2019t know if Holland is trying to create this feeling of claustrophobia or fear, but it\u2019s all tension with no real consequence. It\u2019s exaggerated by the more focused chapters on either side. For a long time\u2026 nothing happens.

+

Removing content from a creative project is hard. Especially when you spent ages making it. I think this book could have benefited from a bit more even pacing, and more ruthless copy editor.

+

Then again, maybe Holland wanted a book driven entirely by character, where plot is just a thing that happens in the background. That\u2019s a fine aspiration, but it didn\u2019t feel consistent.

+

Despite that, I enjoyed the themes: family, relationships, coming of age, and identity. They\u2019re themes that are strong in our oldest stories and ballads as humans, and they\u2019re as relatable now as they\u2019ve ever been (apparently). Holland his tried to give new depth or new voice to an existing story - and has done so without being preachy, or really without making it a thing.

+

Read this book. 3.5 \u2B50

`; +}); diff --git a/.netlify/server/chunks/2021-06-27-weekly-45-0233ec62.js b/.netlify/server/chunks/2021-06-27-weekly-45-0233ec62.js new file mode 100644 index 0000000..149c864 --- /dev/null +++ b/.netlify/server/chunks/2021-06-27-weekly-45-0233ec62.js @@ -0,0 +1,45 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_06_27_weekly_45, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "The Weekly #45: This is an old story", + "author": "Thomas Wilson", + "date": "2021-06-27T08:40:00.000Z", + "slug": "2021-06-27-weekly-45-this-is-an-old-story", + "draft": false, + "imageUrl": "preview-images/45.png", + "tags": ["weekly"] +}; +const _2021_06_27_weekly_45 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The Weekly is a series of essays where I write on something I\u2019ve been thinking about over the last seven days. They\u2019re under a thousand words. There\u2019s some stuff going on in my professional life (positive stuff, but still stuff, you know?) so it\u2019s going to be a short one this week. It\u2019s better to publish than not.

+

I want to talk about old stories. I mean things that people have been experiencing for thousands or tens or thousands of years. I take a lot of joy from realising when I\u2019m seeing, or involved in, and old story.

+

There are some clich\xE9 old stories: sitting around a campfire, the smell of freshly cooked bread, hearing somebody sing or read a story out loud. There\u2019s a chance that literally everybody in your family tree for the last one hundred (or two hundred) generations has experienced these things. If humanity makes it another one hundred generations, they\u2019ll probably experience them too. These things are old stories.

+

I take a special kind of joy in realising that I\u2019m in the middle on an old story. Let me give an example. A few weeks ago my company held their Christmas/Summer party (lockdown had us delayed). We all got on a boat, and went up and then down the Thames for a bit. While on the boat, some people got a little too familiar with the bar. Some people got too drunk on a boat.

+

People getting a little too drunk on a boat: old story.

+

Watching somebody sweep the dust from their shop floor out on to the street: old story.

+

Picking blackberries off the plant while passing by: old story.

+

Noticing the summer solstice: old story.

+

Old stories make the world feel richer to me. They bring me closer to the human experience, and away from the personal experience. They make me feel like I\u2019m a part of something, and humbled. We\u2019ve come really far in the last one hundred years, but some things have been the same for the past couple of thousand. And they\u2019ll stay the same. We\u2019re all still people.

+

Try and keep an eye out for old stories, they\u2019re fun.

`; +}); diff --git a/.netlify/server/chunks/2021-07-08-out-of-office-2e798a65.js b/.netlify/server/chunks/2021-07-08-out-of-office-2e798a65.js new file mode 100644 index 0000000..ddf88e5 --- /dev/null +++ b/.netlify/server/chunks/2021-07-08-out-of-office-2e798a65.js @@ -0,0 +1,36 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_07_08_out_of_office, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Out of office: summer 2021", + "author": "Thomas Wilson", + "date": "2021-07-08T15:47:00.000Z", + "slug": "2021-07-08-out-of-office", + "draft": false +}; +const _2021_07_08_out_of_office = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Summer has always been a time for doing and living. It doesn\u2019t feel right to force at least one piece of writing out of my brain every week. Discipline and routine are useful tools for living, but so is taking a summer break. I\u2019m going out of office for the next couple of months, so I can focus on the latter. I want long cycles, solitary train rides, food eaten outdoors, and adventure. This is what summer is for.

+

So there will be less writing in public, and more living in private for a little while. It\u2019s been a weird 18 months with a pandemic, but this year I feel I can have a more \u201Cnormal\u201D summer. So I\u2019m going to do that. Shame that I won\u2019t be going to Florence, though.

+

Take care and stay safe, I\u2019ll be back when the days start drawing in \u270C\uFE0F

`; +}); diff --git a/.netlify/server/chunks/2021-10-11-back-in-office-70c65d6c.js b/.netlify/server/chunks/2021-10-11-back-in-office-70c65d6c.js new file mode 100644 index 0000000..1b2f578 --- /dev/null +++ b/.netlify/server/chunks/2021-10-11-back-in-office-70c65d6c.js @@ -0,0 +1,43 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_10_11_back_in_office, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Back in office: summer 2021", + "author": "Thomas Wilson", + "date": "2021-10-11T07:16:00.000Z", + "slug": "2021-10-11-back-in-office", + "draft": false +}; +const _2021_10_11_back_in_office = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

After a year and a half of very new normal, summer 2021 was pretty perfect. I mean, the weather wasn\u2019t summery, being around a lot of strangers (and even friends) felt odd, and there seemed an awful lot of pressure to make this The Best Summer Ever.

+

I\u2019m pretty grateful for a lot of small moments this summer.

+

Here are some of those moments:

+
  • Moved to Oxford and filled a moderate-sized house with an unwise number of plants
  • +
  • Climbed Helvellyn and Haystacks in the Lake District
  • +
  • Ate food outside with friends
  • +
  • Ate food inside with family
  • +
  • Watched campfires
  • +
  • Drank gin on hot evenings and cold nights from between clinking ice and wedges of citrus
  • +
  • Cycled through sunny mornings and afternoons
`; +}); diff --git a/.netlify/server/chunks/2021-10-25-the-handbrake-has-come-off-3c1142af.js b/.netlify/server/chunks/2021-10-25-the-handbrake-has-come-off-3c1142af.js new file mode 100644 index 0000000..77bfe79 --- /dev/null +++ b/.netlify/server/chunks/2021-10-25-the-handbrake-has-come-off-3c1142af.js @@ -0,0 +1,49 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_10_25_the_handbrake_has_come_off, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "It feels like the handbrake has come off", + "author": "Thomas Wilson", + "date": "2021-10-25T18:11:00.000Z", + "slug": "2021-10-25-the-handbrake-has-come-off", + "draft": false +}; +const _2021_10_25_the_handbrake_has_come_off = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Over the past two months I have inherited leadership of an engineering team I have worked in for the last twelve months. In the last two weeks I\u2019ve seen the speed of development go from not-slow, to almost inarguably fast (given current resource constraints).

+

I\u2019ve spent months slowly attempting to unpick the parts of the team and company which were bottlenecks. There\u2019s actually some very interesting conversations around what makes a bottleneck, and how do you spot one. But I want to talk about the feeling of not moving fast, and then all of a sudden moving quickly.

+

The analogy I\u2019ve been giving is that it\u2019s like I\u2019m in a car facing down hill, and then the handbrake came off.

+

At first I was like ahhhhhh!, but now I\u2019m more like ahhhh?. Ya know?

+

For the year before this I had been a member of a very small engineering team, where I had written or reviewed 90% of the code that went into production. I, broadly, knew all of the projects, and what was happening.

+

Now, with a larger team (six) and some well-experienced hands in and incoming, things are starting to happen that I don\u2019t fully understand. Sure, I understand the what and the why, but the how isn\u2019t as in focus. I\u2019m a frontend engineer by trade, dev-ops is\u2026 hand-wavy it works?

+

This is the ahhhhhhh! moment. The fear that things are happening, decisions are being made, changes to passing, and I\u2019ve had full visibility on the result but far less on the process. And that scares me because what if things start going wrong?

+

I trust all the engineers in my team implicitly, you have to, but it\u2019s still scary. Things still go wrong.

+

And the ahhhhh? ? That came when I saw the cadence of our releases going up, the quality and security of our software being cemented (test-driven development and refactoring), and both deeper and wider features being shipped.

+

Yes, it\u2019s terrifying and I feel a little out of control, but it\u2019s been about two years since I\u2019ve felt like I\u2019m part of such a productive engineering organisation. It feels like the value proposition of engineering is apparent, not promised.

+

There are lot of parts to this improvement, including but not limited to:

+
  • Test-driven development at unit, functional, and integration level
  • +
  • A simple git workflow for main -> feature -> PR -> main
  • +
  • Pair programming for 10-50% of my day
  • +
  • Feature-driven tickets, by moving to a monorepo and unifying development & deployment, engineers ship an entire (cross-cutting) feature all at once
+

I\u2019d love to talk in detail on each of these, but for now I\u2019ll just say that I am confident each of these highly correlate to better developer productivity.

`; +}); diff --git a/.netlify/server/chunks/2021-10-28-how-to-onboard-new-software-engineers-89215694.js b/.netlify/server/chunks/2021-10-28-how-to-onboard-new-software-engineers-89215694.js new file mode 100644 index 0000000..b8e727b --- /dev/null +++ b/.netlify/server/chunks/2021-10-28-how-to-onboard-new-software-engineers-89215694.js @@ -0,0 +1,47 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_10_28_how_to_onboard_new_software_engineers, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "How to onboard new software engineers without paying high interest", + "author": "Thomas Wilson", + "date": "2021-10-28T16:03:00.000Z", + "slug": "2021-10-28-how-to-onboard-new-software-engineers", + "draft": false +}; +const _2021_10_28_how_to_onboard_new_software_engineers = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

In the past four months I\u2019ve hired about five software engineers (including interns). So I\u2019ve been thinking about how we onboard new engineers to the team. This has been especially important because over half the engineers have never had an engineering job before, or even a job as a university graduate.

+

This means that onboarding isn\u2019t just about introducing someone to the company or the engineering team, it\u2019s about bringing people into both their first \u201Cproper\u201D job.

+

It feels awesome that I can make someone\u2019s first experience as a software engineer so good. Or at least have the potential to do so.

+

Tell you what doesn\u2019t feel super: the onboarding process. It takes a lot to introduce anyone to the way that professional software engineers plan, do, and think about work. It means that my time is spent teaching, not doing. And while teaching is doing, I definitely notice a loss of momentum and bandwidth in the (already quite small) team.

+

A new engineer will land in your team anywhere between 0-90% ready to start contributing code to production. The goal of an onboarding process is to get that slider to 100%.

+

I argue that slider is tending towards 0% unless you\u2019re effectively onboarding them. That is, if you bring someone onboard and then make cursory efforts to keep them get them up to speed, they\u2019ll slowly grind down to 25-50%.

+

I also suspect it gets harder to move this slides close to 100% over time. Onboarding is like a high interest debt: if you\u2019re going to pay it, you\u2019ll pay less if you pay it quicker.

+

In thinking about onboarding in our team, and in our company, there are a handful of insights that I think are worth sharing explicitly.

+

Cook from chilled not frozen: If someone comes into a new job knowing the bare bones of the job (anything that\u2019s in their contract, who their manager is, and where they\u2019ll be working) ten they\u2019re coming in frozen. There\u2019s been no progression between the end of the interview process, and the start of the working process. I (very purposefully) run a pretty high-touch interview process, and by the time a candidate receives an offer, there\u2019s been some good rapport built between us and them. Making sure that the candidate knows exactly when and where they\u2019re expected in on their first day is table-stakes. Defrost it even further by setting clearer expectations and timeframes. Bonus points if you can CC their colleagues into these emails.

+

Do it in person: we\u2019re a remote-by-default hybrid engineering team. Honestly I think that works great for us[^That\u2019s not to say it\u2019s easy. Remove work comes with its own challenges which are real and can slowly strangle a company or team] but onboarding should be done in-person, or as close to synchronously as possible. There are just so many little things, like using new Browser, using Slack not Teams, MacOS not Windows, that can make \u201Csimple\u201D things deceptively hard. If you\u2019re doing something in person, or synchronously, you can put a real early stop to some rabbit-hole chasing. You also get the best feedback possible for improving your onboarding process.

+

Read from a script: Despite doing it in person, have a really clear (ideally ordered) checklist of things that need to be done on the very first day of onboarding (accounts to create, software to download). New starters should have access to the checklist, but the checklist is not the interface. You, a human being, are the interface. Allow someone to synchronously ask questions, send emails and messages on the new starter\u2019s behalf.

+

Have many checklists: I\u2019ve written three lists for onboarding new engineers: accounts and software, a list of people they need to arrange meetings with, and the code deployment pipeline. Each of these have different time frames and purposes. Break things up, instead of having one big old long list.

+

Complete the checklist ASAP: Focus should be on getting a new starter to the end of all the lists ASAP. Accounts and software should be as as close to complete by the end of the first day. We aim to have an engineer go through the deployment of a bugfix/quickfix ticket in the first two days (sometimes three days), and by the end of their first week I want them to have events in their calendar to meet everyone they need to.

+

Force one-ones with the entire business: We\u2019re an engineering team in a highly ops-focused startup, and we\u2019re hybrid remote as a team, but distributed across three cities as a company. This means that the chance of water cooler chat is pretty low. I think there\u2019s incredible value in having engineers meet as many members of the team as possible, across as many functions as possible. This is especially important where internal staff are also users of the software you\u2019re building.

`; +}); diff --git a/.netlify/server/chunks/2021-12-12-build-the-platform-ship-the-product-aef2df81.js b/.netlify/server/chunks/2021-12-12-build-the-platform-ship-the-product-aef2df81.js new file mode 100644 index 0000000..5b70744 --- /dev/null +++ b/.netlify/server/chunks/2021-12-12-build-the-platform-ship-the-product-aef2df81.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2021_12_12_build_the_platform_ship_the_product, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Ship the product, build the platform", + "author": "Thomas Wilson", + "date": "2021-12-12T17:21:00.000Z", + "slug": "2021-12-12-build-the-platform-ship-the-product", + "draft": false +}; +const _2021_12_12_build_the_platform_ship_the_product = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Imagine you\u2019re part of a new-ish, in-house engineering team working with a legacy codebase. How do you extend this codebase into new features while discovering and fixing Dark Patches on that same codebase\u2019s map? I actually don\u2019t know, and myself and the rest of the engineering team at Oxwash have been working hard to think about solving this.

+

My thinking about shaping and prioritising this work first coalesced around one phrase: Build The Platform. This was shamelessly stolen from Steve Yegge\u2019s Google Platforms Rant. It\u2019s long and very good, and if you\u2019re leading an engineering team I think you should read it.

+

I think engineering teams should be building the platform, or operating system, that runs a business. The platform should account for the objects/entities, and processes that comprise a business. Things like Orders and Users. A Platform can be thought of as a bunch of services, where each service has a single responsibility. Like letting users register and sign up, or like recording revenue.

+

Platforms help company and public users interact with the business. We do laundry at Oxwash, so the platform is about helping us do more laundry, more efficiently. You\u2019ll be shocked to learn running a laundry isn\u2019t as simple as it seems.

+

While I\u2019ve found this a fantastic tool in technical and strategic discussions, it\u2019s not great when you\u2019re talking with end-users, internal or external. Computers and software are a means to an end for 95% of people. To those people you can\u2019t say \u201Cthis sounds like we need to alter our internal scheduling engine\u201D. To these people you have to ask product-focused questions, like \u201Cwhat tools do you need to spread workload so that laundry can be done consistently without being overwhelmed?\u201D

+

This is product-level thinking. Behind the scenes we\u2019re building a platform. When we think about grouping, shaping, and prioritising work it\u2019s about choosing what\u2019s best for the platform. Front-of-stage, we\u2019re shipping a product. Many products, actually: internal and external tools, and even more if you think about tests and environments as features.

+

This way the engineering team can think about adding value to the business by building products which are demonstrably useful to the people who need them. Separately, they can make the engineering team\u2019s life easier by helping more code be shipped faster and with more confidence that it\u2019s not going to go wrong.

+

This addresses two core questions I find myself being asked a lot: the what and the how long. If you\u2019ve got good answers to those questions, you\u2019re doing well (I think).

+

I\u2019m currently having to re-evaluate this beautifully simple distinction. That\u2019s caused where problems in the platform cause problems across products.

+

A platform composed of separate, business-level services means that when something doesn\u2019t behave as expected, you don\u2019t always get clear and obvious signals. You might get reports of minor unexpected behaviour here-and-there, or some weirdness occurring in some edge cases.

+

When these problems are in Platforms, not Products, it can make the what and the how long answers seem wildly disproportionate from a product perspective. How long to fix this tiny bug?

+

And now you\u2019re relying on either a) engineering expertise, or b) trust to communicate the source of the problem. You\u2019re also going to have to use Platform factors in the prioritisation of fixing these problems, which adds another layer of complexity when translating Work In Progress at the engineering-product interface.

+

Engineering is tough, yo.

`; +}); diff --git a/.netlify/server/chunks/2022-02-04-vibe-check-0-c8eb5675.js b/.netlify/server/chunks/2022-02-04-vibe-check-0-c8eb5675.js new file mode 100644 index 0000000..95fccef --- /dev/null +++ b/.netlify/server/chunks/2022-02-04-vibe-check-0-c8eb5675.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2022_02_04_vibe_check_0, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Vibe Check #0", + "author": "Thomas Wilson", + "date": "2022-02-04T18:46:00.000Z", + "slug": "2022-02-04-vibe-check-0", + "draft": false +}; +const _2022_02_04_vibe_check_0 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

January 2022 was a good month. It\u2019s weird how slow the start of the year feels, until it\u2019s over. The days get longer, and it feels like momentum is returning to my life, which is cool.

+

Some highlights from this month include:

+
  • Turning 30, taking the day off work, and sitting in the sun drinking a coffee, reading Marcus Aurelius. I\u2019ve read Meditations a lot, but not for a couple of years. There are parts of it I\u2019m proud to have internalised. There are other parts that are good to hear.
  • +
  • Going for a Christmas dinner nearly five weeks post-fact. Or maybe forty-seven early. It was wonderful, but boy has the pandemic made it easy to forget that some people ironically eat dinner at 22:00. That\u2019s insane to me, I should be in bed.
  • +
  • Taking my first outdoor road cycle of 2022. The days are short and the weather mild (if a little windy), my stamina has legitimately been shot, but it felt good to be out.
  • +
  • The days are getting longer. It\u2019s now not dark when I finish work. I can take an evening stroll or run (so long as it\u2019s immediately after work) and it\u2019s not dark.
  • +
  • I\u2019ve seen a lot of robins.
+

2022 feels as though it\u2019s off to a gentle start to me personally. There have been (good) growing pains at work, as product and engineering leave their infancy, and processes and people start to get put in place. It\u2019s been truly remarkable to return my attention to the design of accessible, clean user interfaces. There\u2019s a lot of dust in those books, or wastage in those muscles (depending on the harshness of your preferred analogy). It\u2019s good though - I love design, and I love some of the engineering conversations we\u2019ve been having recently.

+

This month I\u2019ve been reading:

+
  • A Line To Kill by Anthony Horowitz. This whole series (Hawthorn and Horowitz) is an absolute delight.
  • +
  • Meditations by Marcus Aurelius.
  • +
  • Atomic Habits by James Clear. It\u2019s a clich\xE9 and I\u2019m late to the party, but definitely worth reading.
  • +
  • Under the Whispering Door by TJ Klune. It\u2019s a fiction book about death.
`; +}); diff --git a/.netlify/server/chunks/2022-02-22-atomic-habits-is-a-really-good-book-89593d65.js b/.netlify/server/chunks/2022-02-22-atomic-habits-is-a-really-good-book-89593d65.js new file mode 100644 index 0000000..dd3d06b --- /dev/null +++ b/.netlify/server/chunks/2022-02-22-atomic-habits-is-a-really-good-book-89593d65.js @@ -0,0 +1,90 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2022_02_22_atomic_habits_is_a_really_good_book, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "\u{1F4D6} Atomic Habits is a really good book", + "author": "Thomas Wilson", + "date": "2022-02-22T20:56:00.000Z", + "slug": "2022-02-22-atomic-habits-is-a-really-good-book", + "draft": false +}; +const _2022_02_22_atomic_habits_is_a_really_good_book = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

I spoke to thirty founders, and they all do these three things before breakfast.

+

My nine journaling prompts for other CEOs and founders

+

One rule for flawless interviews.

+

[and so on]

+

Habit hacks are catnip to a certain kind of self-improvement/business-guru people. I actually got pretty involved in these kinds of articles earlier in my career, so it\u2019d be wrong for me to judge.

+

I think these kind of articles (or titles for articles) work because i) they make people feel smarter than other people, and ii) they promise great results with low input.

+

Maybe three weeks ago I\u2019d get snarky about how better results isn\u2019t a knowledge problem. I don\u2019t think knowing more equates simply to more and better work. \u201CKeep running\u201D won\u2019t unconditionally get anybody to the end of a marathon.

+

After reading Atomic Habits (by James Clear), I was reminded of the best of these articles. Clear helped me remember the generous interpretation for why these articles get written, read, and perform so well on social media: little decisions, stacked and reliably repeated, make big changes about who we are and what we can achieve.

+

The platonic ideal of good habits are tools that help us become the version of ourself we want to be, and produce the highest quality work we can.

+

But still, the problem isn\u2019t knowing what three things to do before breakfast, it\u2019s programming yourself to do the activities over and over again.

+

We all want that. And Clear dedicates a whole book to giving us the tools to get there. I want to surface the parts of Atomic Habits that resonated with me:

+
  1. The rules for forging and breaking a habit.
  2. +
  3. Call out your automatic actions / lazy behaviours.
  4. +
  5. Decide what kind of person you want to be.
  6. +
  7. Monkey brain makes decisions but is easy to trick.
+

1. The Rules

+

Clear gives us four rules for making and breaking a habit. To make a habit we must:

+
  1. Make it obvious
  2. +
  3. Make it desirable
  4. +
  5. Make it easy
  6. +
  7. Make it satisfying
+

And to break, we invert:

+
  1. Make it invisible
  2. +
  3. Make it undesirable
  4. +
  5. Make it difficult
  6. +
  7. Make it unsatisfying.
+

The what and why of each of these rules is the whole point of the book. Read the book, you\u2019ll find helpful stuff in there.

+

2. Call out your automatic or lazy behaviours

+

Our laziness (and the purposefully crafted and endlessly revised systems devised by social media and engagement-driven advertising that take advantage of that laziness) mean that we do a lot of things without really thinking. Without even realising.

+

Come home, sit on sofa, reach for the remote, and turn on the TV. Open a new tab, type faceb and have your browser take you to Facebook. Open your phone and check twitter. Walk into the kitchen, fill up the kettle for another pot of tea.

+

Clear introduces the Pointing and Calling method. A process where you literally point at something and say what it is.

+

You might point at your kettle and say \u201CI am turning this on because it is the morning and I drink coffee in the morning\u201D.

+

\u201CI am eating leftovers because they are on the side\u201D

+

\u201CI am checking Hacker News because I don\u2019t want to start my next task\u201D

+

A lot of the time we\u2019re witnesses to our actions, rather than the conductor. I like Pointing and Calling because it can be done from the passenger seat, as a way to move you into the driving seat. \u201CI have let YouTube autoplay into another vide\u201D I say to myself, as my brain beckons in the firehose of intriguing titles and thumbnails.

+

I\u2019ve also been Pointing and Calling before I start doing something intentionally. \u201CI am about to have a meeting with my colleague, I need their help because Y\u201D I say to myself, out loud, alone, in my office, like an insane person. Or \u201CWe are talking about putting some more text on the UI because we think our software is confusing our customers\u201D, I explain to a colleague, as though they are a non-technical colleague and not, in fact, a skilled engineer.

+

Hilarity aside: Pointing and Calling sets the scene. Unspoken mismatch of understanding is a staple for a sitcom, but also the reason for a lot of wasted time. State the problem, do the smallest amount of work to solve it, and move on to the next problem.

+

3. Decide what kind of person you want to be

+

This point is the least actionable, so probably least worthy of discussion.

+

No amount of daily journalling, meditation, calendar apps, or dopamine detoxes is going to make you the person you want to be. Chances are that they\u2019re rain dances.

+

You have finite energy and time, in which you can make finite choices. So make a decision about the direction you want to change in.

+

Think about it and why you want it.

+

The kind of person I want to be is someone more deeply engaged in thoughtful problems. The happiest periods of my life are when I\u2019ve been like that. What are the kind of things people like that do?

+
  • Engage and stay engaged
  • +
  • Prevent disruptions or distractions
  • +
  • Communicate thoughtfully and well
+

What don\u2019t they do?

+
  • Switch contexts or problems before reaching depth
  • +
  • Avoid resistance or friction to difficulty
+

4. Monkey brain is tricky

+

Our brains are dumb, or at very least don\u2019t want the best for use. Very smart people are building enticing platforms that wholly rely on having your attention. Our poor brains are easily persuaded by others, and very persuasive to us - so that makes them a high value target.

+

It\u2019s become weirdly normal to be distracted or give your attention to other things. Our brains rely on sight for information processing. We see a lot of attention-grabbing things every day, and we have to do active work against that.

+

Understanding this is necessary for a) breaking habits around modern media consumption, and b) making habits that use the freed time and space that creates.

+

Clear gave me three very useful reminders in this book:

+
  1. If you want your brain to forget about something, just hide it. Put your phone in the other room, remove the app from your home screen.
  2. +
  3. Friction and perceived effort aren\u2019t proportional: adding a tiny bit of friction can make your brain think something is way harder than it actually is
  4. +
  5. Make something tangible: a lot of difficult or important things don\u2019t have immediate tangible satisfaction. Cross something off, or write it down. Move lego bricks from one jar to another. Tear off a calendar page. Let your brain see or touch something.
`; +}); diff --git a/.netlify/server/chunks/2022-02-28-vibe-check-01-d55a0e2d.js b/.netlify/server/chunks/2022-02-28-vibe-check-01-d55a0e2d.js new file mode 100644 index 0000000..d947e1d --- /dev/null +++ b/.netlify/server/chunks/2022-02-28-vibe-check-01-d55a0e2d.js @@ -0,0 +1,48 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2022_02_28_vibe_check_01, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Vibe Check #1", + "author": "Thomas Wilson", + "date": "2022-02-28T19:58:00.000Z", + "slug": "2022-02-28-vibe-check-1", + "draft": false +}; +const _2022_02_28_vibe_check_01 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

It\u2019s basically March and the days are finally getting longer! On Sunday, the sun was up to greet me as I made coffee. Tiny sweet peas and strawberries bud on the window sill. The flow of spring into winter feels miraculous.

+

It\u2019s getting lighter, but it\u2019s secretly the coldest, wettest month. That\u2019s how it feels, I\u2019ve no idea what the data says.

+

Things I\u2019ve done this month which have brought me joy:

+
  • Consumed a full Christmas dinner for the third month in a row. I cooked some of the best roast potatoes I\u2019ve ever made, and introduced three other people to their first meat-free roast.
  • +
  • Went for a two hour walk in the Chilterns, and discovered a feeling wholly like the green Downs of home. Walk was promptly followed by a Sunday lunch and glass of wine in a prop\u2019r pub, complete with locals, dogs, and an outhouse.
  • +
  • DM\u2019d my first ever game of Dungeons and Dragons, and I loved every minute, baby.
  • +
  • Took a four day weekend, for no reason other than \u201CI had leave to take\u201D. The joy of taking an hour walk to read my book in a cafe, at two in the afternoon, while others worked. Simple joy.
  • +
  • Discovered some excellent Columbian coffee from Newground. Truly, it\u2019s like apple cherry coke.
  • +
  • Made my first Spring meal of the year (Anna Jones\u2019 Spring Onion and Pea Fritters). My favourite Spring meal remains pea risotto, cooked while consuming white wine. Something to look forward to, brightly.
+

We\u2019re now in to 2022. It\u2019s begun, and the peace and hope of New Year\u2019s have fallen away. I find my head more full of ideas and problems, of managing a maturing engineering team in a fast-moving organisation. And also of a semi home-brew D&D campaign. Routine and way-finding are butting heads (I should write horoscopes).

+

To my delight, I find myself still reading. Highlights this month include:

+
  • Shadow of the Gods, by John Gywnne. This is the first Norse-mythology book I\u2019ve read (sorry Neil Gaiman), and right now I\u2019m confused by all the names. I\u2019ve got five hundred and fifty more pages to get familiar with it.
  • +
  • Deep Work, by Cal Newport. Extremely good, tyrannically anti social media in places, though.
  • +
  • The Last Wish, after being somewhat baffled by The Witcher Netflix series, I find myself equally baffled by the odd dialogue in this collection of short stories. Am I supposed to just know what a Bruxa is, Mr Sapkowski?
  • +
  • Meditations, by Marcus Aurelius. It\u2019s not a book to devour.
`; +}); diff --git a/.netlify/server/chunks/2022-03-02-concentrate-on-concentrated-tests-3e42db2f.js b/.netlify/server/chunks/2022-03-02-concentrate-on-concentrated-tests-3e42db2f.js new file mode 100644 index 0000000..ca93be3 --- /dev/null +++ b/.netlify/server/chunks/2022-03-02-concentrate-on-concentrated-tests-3e42db2f.js @@ -0,0 +1,42 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2022_03_02_concentrate_on_concentrated_tests, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Concentrate on Concentrated Tests", + "author": "Thomas Wilson", + "date": "2022-03-02T21:41:00.000Z", + "slug": "2022-03-02-concentrate-on-concentrated-tests", + "draft": false +}; +const _2022_03_02_concentrate_on_concentrated_tests = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

The flavour of a test block lies in the calling of application code, and the assertions on its behaviour. Everything else (set-up, tear down, tidying, and side effects) dilutes a test. Work to prevent tests from being watered down.

+

It should be as obvious to an incoming engineer exactly what part of the codebase is being tested, and exactly which parts of the testing-infrastructure (stubs, mocks, fixtures) are facilitating that.

+

By contrast: a diluted test makes it hard to point to the grain of truth or value. Tests which are hard to understand are hard to change. Code which is hard to change won\u2019t get changed.

+

If it\u2019s easier for an engineer to add a new test, rather than alter an existing one, they will. If it\u2019s unclear that a test already exists for something, that test will be duplicated.

+

Diluted tests risk making your codebase bloated and brittle (too big and hard to change).

+

Ask if you can make a test more concentrated by:

+
  1. Creating multiple unit tests to test previously-grouped functionality
  2. +
  3. Removing tests which make no unique assertions on your application code
  4. +
  5. Herding your testing infrastructure out of individual test files to isolate repeated patterns or necessary magic
`; +}); diff --git a/.netlify/server/chunks/2022-03-13-discover-complexity-56eefb8e.js b/.netlify/server/chunks/2022-03-13-discover-complexity-56eefb8e.js new file mode 100644 index 0000000..a3698bf --- /dev/null +++ b/.netlify/server/chunks/2022-03-13-discover-complexity-56eefb8e.js @@ -0,0 +1,43 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2022_03_13_discover_complexity, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Discover Complexity", + "author": "Thomas Wilson", + "date": "2022-03-13T10:10", + "slug": "2022-03-13-discover-complexity", + "draft": false +}; +const _2022_03_13_discover_complexity = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Code changes frequently, and good code is able to change easily. That means that code must be both simple for other humans to interpret (so that the code is changed, not duplicated or added on to), and anti-brittle (so that changes don\u2019t require rewrites, or re-considerations).

+

An (understandable) response to this need for change is to predict the need for change by forecasting changes to customer, business, or engineering requirements.

+

Discover complexity, do not invent it.

+

Discovered complexity is unearthed in the actual use of the software by the intended user, in the intended use case. Do what you can to gather and distribute this feedback to everyone involved in designing, building, and releasing the product.

+

Alternatively, complexity is invented. It does not come from real-world use. It is a guess. It is speculative. Pay attention to solving problems which could happen, because it dilutes focus on solving the actual problem.

+

Invented complexity takes time and attention away from solving real, demonstrated problems now. It obscures the meaning or focus of the code you\u2019re writing, so you\u2019ll pay another cost when future engineers (inevitable) attempt to understand it.

+

Solving for non-discovered complexity can lead to things like:

+
  • Adding a lot of flexibility to functions, even though they\u2019re only used in one case
  • +
  • Creating a lot of indirection in layers of software, even though there\u2019s only one actual path in use
  • +
  • Naming things with less tangible names to accommodate future siblings, even though you\u2019re building an only child.
`; +}); diff --git a/.netlify/server/chunks/2022-04-03-vibe-check-02-61ea8329.js b/.netlify/server/chunks/2022-04-03-vibe-check-02-61ea8329.js new file mode 100644 index 0000000..721973b --- /dev/null +++ b/.netlify/server/chunks/2022-04-03-vibe-check-02-61ea8329.js @@ -0,0 +1,59 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2022_04_03_vibe_check_02, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Vibe Check #2: GTD in the face of weathering and predators", + "author": "Thomas Wilson", + "date": "2022-04-03T07:37:00.000Z", + "slug": "2022-04-03-vibe-check-02", + "draft": false +}; +const _2022_04_03_vibe_check_02 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

March 2022 has been a good month for me. December-January saw me feeling very mentally strained, in retrospect because we\u2019re seeing the remnants of covid restrictions lift. personal and professional obligations are changing, and as an introvert they\u2019re drawing from an already shallow well of extrovert energy.

+

I\u2019ve not felt drained in this way since the beginning of my professional career. I remember consuming loads of books and podcasts at that time around personal productivity and management, and I think it helped (I\u2019m still in a similar career area now). I spent February-March re-discovering some of the things I\u2019ve learned and since forgot.

+

Early March saw the tentative adoption of a Getting Things Done (GTD) -inspired personal task management system, which I\u2019m running through Todoist.

+

To be a clich\xE9: having a task management system has been liberating. Having a big old list of every actionable thing I need to do, is great. I know I\u2019ve reached adoption because if I can\u2019t jot down a TODO after it popping into my head I get viscerally nervous.

+

GTD has been paired really well with a reading of Deep Work, by Cal Newport. Both Newport and Allen (GTD author) have hammered home that thinking is the highest value work I do, as a knowledge worker.

+

\u201CThinking is important\u201D is taken-for-granted simple. So it doesn\u2019t happen. In the same way we assume that we\u2019re not going to forget pay rent or stop work at five pm. Making sure that thinking happens, and that its quality is high, is work, and should be taken seriously. I\u2019d forgotten that.

+

Instead, I was allowing precious mental CPU cycles process the questions \u201Cis this thing I\u2019m doing right now the thing I should be doing?\u201D (Probably?); and \u201Cis there anything I should be doing but have forgot?\u201D (more than probably).

+

The next thing I need to conquer is some kind of ritualised review of my system. The Weekly Review\u2122\uFE0F in GTD-land.

+

With zero dought, re-upping personal task management has made the single biggest quality of life change to my day-to-day in 2022. Feeling like I\u2019m equipped to capture, prioritise, and then do the things I want to do to live the life I want to live\u2026 That\u2019s one of the load-bearing challenges of life, and also one that face constant weathering from the tiny stream of ordinary life chaos, but also an entire ecosystem of attention predators (Netflix, YouTube). Okay, soap box away, tin foil hat off.

+

March is an unknowable month for weather, at least February is reliably terrible. Eighteen degrees one day, snow flurries three days later. I don\u2019t even think this one\u2019s good for the plants.

+

Anyway, here are some things which happened in March 2022 which I think are worth talking about:

+
  • Saw Come From Away, a fantastic musical. I loved it and you should go see it, it\u2019s a great example of the craft.
  • +
  • Took a glorious Saturday morning cycle in the spring warmth. I saw lambs and sheep.
  • +
  • Saw a university friend and went for a walk and a Wagamama lunch. Wagamama is a true champ among the highstreet food chains.
  • +
  • Travelled first class on a train for the first time, and got complementary snacks for doing so.
  • +
  • Got a tiny shed for the garden, painted it sage-green with white trimmings, and filled it with pots and garden whatnots.
  • +
  • Got grumpy at the loss of an hour\u2019s sunlight in the morning and joyful at the expansive evening light.
  • +
  • Went back to group exercise classes and did enough squats to make stairs a mortal threat.
  • +
  • Saw my first live dance show since the start of the pandemic
  • +
  • DM\u2019d my second Dungeons and Dragons session (a player died lol)
  • +
  • Crossed the 800th test in our CI-process at Oxwash. I think this means we\u2019ve 10x\u2019d the total test count in the last 8-12 months, which feels fantastic.
+

The books I\u2019ve been reading this month are:

+
  • Getting Things Done: The Art of Stress-free Productivity, by David Allen. I told you above how great this book has been to me. If you\u2019re looking to boot-up or freshen a personal task-management system just read this book, it\u2019s classic for a reason.
  • +
  • Pandora, by Susan Stokes-Chapman. A really beautiful, semi-mystical historic London urban fantasy loosely based on the Greek myth. A nice book, but I don\u2019t think one that I\u2019ll remember in a few months.
  • +
  • The Shadow of the Gods, by John Gwynne. I switched from Audiobook to physical book on this one because the names were starting to pass me by a little too fast. I am absolutely smitten with this book, it is everything I love in fantasy: a loosely explained magical world, multi-character narrative, visceral hatred and storytelling.
  • +
  • Leviathan Wakes by James S. A. Corey. I\u2019m too early in this one to pass comment.
`; +}); diff --git a/.netlify/server/chunks/2022-04-10-recognise-and-reduce-risk-023ea1df.js b/.netlify/server/chunks/2022-04-10-recognise-and-reduce-risk-023ea1df.js new file mode 100644 index 0000000..fa3c937 --- /dev/null +++ b/.netlify/server/chunks/2022-04-10-recognise-and-reduce-risk-023ea1df.js @@ -0,0 +1,46 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _2022_04_10_recognise_and_reduce_risk, + metadata: () => metadata +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +const metadata = { + "title": "Recognise and reduce risk", + "author": "Thomas Wilson", + "date": "2022-04-10T21:10", + "slug": "2022-04-10-recognise-and-reduce-risk", + "draft": false +}; +const _2022_04_10_recognise_and_reduce_risk = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `

Answering and executing the question(s) \u201Cwhat do we build and how do we build it?\u201D is an existential challenge for small companies.

+

What you build is probably more important than how you build it. But how you build it changes how well you can change it. And the what is going to change.

+

Uncertainty and risk are the abstract problems here. Will an onboarding email sequence increase the number of customers who convert to a paid membership? Do our users care about keyboard shortcuts? Should we hire someone new?

+

Dan McKinley\u2019s Boring Technology Club introduces the the idea of the Innovation Token, a metaphorical token that we spend on \u201Cour limited capacity to do something creative, or weird, or hard\u201D. A team has very few innovation tokens, and each token spent increases risk.

+

They increase risk because they make it hard to make a good guess about what will happen next. Good guesses are sometimes the only fuel that new companies and small engineering teams have. Longer-lived companies have experience or data to help.

+

The Shape Up methodology gets it right: we\u2019re making bets.

+

If you\u2019re an engineer you can make a bet more risky by building with newer technologies (frameworks or languages) or infrastructure (databases or cloud providers), relying on manual (not automated) testing or deployment, by prematurely optimising, by building in isolation from customers, and a hundred other smells.

+

A product person can increase risk by not knowing or understanding their customers, attempting to solve an over- or under-ambitious problem, by pricing things wrong (or not at all).

+

These types of risk are not separate[^1]

+

If you know your customer is extremely price sensitive, then building a $99/yr subscription model is going to have risk that even the most boring technology stack (IMO: MySQL, Rails, Bootstrap, Digital Ocean) cannot address.

+

Risk is risk. Risk from product (what) and risk from engineering (how) cannot be meaningfully separated once you take more than three steps backwards.

+

Your job is to reduce risk for yourself, your boss, or your company. If you have any interest beyond the pure craft of software, aim to reduce risk for the most number of people possible

+

[^1]: I think we (I) separate the what from the how because they are often solved by a CEO and CTO. Just because a problem is solved by two people does not mean it is two problems.

`; +}); diff --git a/.netlify/server/chunks/Navbar-3e8a1470.js b/.netlify/server/chunks/Navbar-3e8a1470.js new file mode 100644 index 0000000..c6b656c --- /dev/null +++ b/.netlify/server/chunks/Navbar-3e8a1470.js @@ -0,0 +1,35 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + N: () => Navbar +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./index-10ac95e2.js"); +var Navbar_svelte_svelte_type_style_lang = ""; +const css = { + code: "nav.svelte-1g1paqu{display:flex;flex-flow:row;max-width:100vw;overflow:hidden}.left.svelte-1g1paqu{flex:1;flex-grow:0;text-align:left;padding:var(--spacing-base)}.home.svelte-1g1paqu{color:var(--brand-orange);text-decoration:none;font-weight:300;display:flex;width:fit-content;white-space:nowrap;transition:0.3s}.home.svelte-1g1paqu:hover{transform:rotate(11deg)}.right.svelte-1g1paqu{flex:1;text-align:right;padding:var(--spacing-base)}.blog.svelte-1g1paqu:visited{color:var(--brand-blue)}", + map: null +}; +const Navbar = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + $$result.css.add(css); + return ``; +}); diff --git a/.netlify/server/chunks/getPostsFromGlobResult-2e7f393c.js b/.netlify/server/chunks/getPostsFromGlobResult-2e7f393c.js new file mode 100644 index 0000000..66c2143 --- /dev/null +++ b/.netlify/server/chunks/getPostsFromGlobResult-2e7f393c.js @@ -0,0 +1,71 @@ +var __defProp = Object.defineProperty; +var __defProps = Object.defineProperties; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropDescs = Object.getOwnPropertyDescriptors; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getOwnPropSymbols = Object.getOwnPropertySymbols; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __propIsEnum = Object.prototype.propertyIsEnumerable; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __spreadValues = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + if (__getOwnPropSymbols) + for (var prop of __getOwnPropSymbols(b)) { + if (__propIsEnum.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + } + return a; +}; +var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); +var __objRest = (source, exclude) => { + var target = {}; + for (var prop in source) + if (__hasOwnProp.call(source, prop) && exclude.indexOf(prop) < 0) + target[prop] = source[prop]; + if (source != null && __getOwnPropSymbols) + for (var prop of __getOwnPropSymbols(source)) { + if (exclude.indexOf(prop) < 0 && __propIsEnum.call(source, prop)) + target[prop] = source[prop]; + } + return target; +}; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + g: () => getPostsFromGlobResult +}); +module.exports = __toCommonJS(stdin_exports); +async function getPostsFromGlobResult(result) { + const allPosts = await Promise.all(Object.entries(result).map(async ([filename, resolver]) => { + try { + const { + metadata, + default: _a + } = await resolver(), _b = _a, { render, $$render } = _b, rest = __objRest(_b, ["render", "$$render"]); + const { html } = render(); + const _c = metadata, { date } = _c, data = __objRest(_c, ["date"]); + return __spreadProps(__spreadValues({}, data), { + html, + date: new Date(date), + filename + }); + } catch (e) { + return null; + } + })); + return allPosts.filter((post) => post !== null); +} diff --git a/.netlify/server/chunks/hooks-1c45ba0b.js b/.netlify/server/chunks/hooks-1c45ba0b.js new file mode 100644 index 0000000..e69de29 diff --git a/.netlify/server/chunks/index-10ac95e2.js b/.netlify/server/chunks/index-10ac95e2.js new file mode 100644 index 0000000..8d88899 --- /dev/null +++ b/.netlify/server/chunks/index-10ac95e2.js @@ -0,0 +1,122 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + a: () => each, + b: () => add_attribute, + c: () => create_ssr_component, + e: () => escape, + m: () => missing_component, + s: () => setContext, + v: () => validate_component +}); +module.exports = __toCommonJS(stdin_exports); +function run(fn) { + return fn(); +} +function blank_object() { + return /* @__PURE__ */ Object.create(null); +} +function run_all(fns) { + fns.forEach(run); +} +let current_component; +function set_current_component(component) { + current_component = component; +} +function get_current_component() { + if (!current_component) + throw new Error("Function called outside component initialization"); + return current_component; +} +function setContext(key, context) { + get_current_component().$$.context.set(key, context); +} +Promise.resolve(); +const escaped = { + '"': """, + "'": "'", + "&": "&", + "<": "<", + ">": ">" +}; +function escape(html) { + return String(html).replace(/["'&<>]/g, (match) => escaped[match]); +} +function escape_attribute_value(value) { + return typeof value === "string" ? escape(value) : value; +} +function each(items, fn) { + let str = ""; + for (let i = 0; i < items.length; i += 1) { + str += fn(items[i], i); + } + return str; +} +const missing_component = { + $$render: () => "" +}; +function validate_component(component, name) { + if (!component || !component.$$render) { + if (name === "svelte:component") + name += " this={...}"; + throw new Error(`<${name}> is not a valid SSR component. You may need to review your build config to ensure that dependencies are compiled, rather than imported as pre-compiled modules`); + } + return component; +} +let on_destroy; +function create_ssr_component(fn) { + function $$render(result, props, bindings, slots, context) { + const parent_component = current_component; + const $$ = { + on_destroy, + context: new Map(context || (parent_component ? parent_component.$$.context : [])), + on_mount: [], + before_update: [], + after_update: [], + callbacks: blank_object() + }; + set_current_component({ $$ }); + const html = fn(result, props, bindings, slots); + set_current_component(parent_component); + return html; + } + return { + render: (props = {}, { $$slots = {}, context = /* @__PURE__ */ new Map() } = {}) => { + on_destroy = []; + const result = { title: "", head: "", css: /* @__PURE__ */ new Set() }; + const html = $$render(result, props, {}, $$slots, context); + run_all(on_destroy); + return { + html, + css: { + code: Array.from(result.css).map((css) => css.code).join("\n"), + map: null + }, + head: result.title + result.head + }; + }, + $$render + }; +} +function add_attribute(name, value, boolean) { + if (value == null || boolean && !value) + return ""; + const assignment = boolean && value === true ? "" : `="${escape_attribute_value(value.toString())}"`; + return ` ${name}${assignment}`; +} diff --git a/.netlify/server/entries/endpoints/api/blog.json.ts.js b/.netlify/server/entries/endpoints/api/blog.json.ts.js new file mode 100644 index 0000000..de94dd7 --- /dev/null +++ b/.netlify/server/entries/endpoints/api/blog.json.ts.js @@ -0,0 +1,83 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __defProps = Object.defineProperties; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropDescs = Object.getOwnPropertyDescriptors; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getOwnPropSymbols = Object.getOwnPropertySymbols; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __propIsEnum = Object.prototype.propertyIsEnumerable; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __spreadValues = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + if (__getOwnPropSymbols) + for (var prop of __getOwnPropSymbols(b)) { + if (__propIsEnum.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + } + return a; +}; +var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + get: () => get +}); +module.exports = __toCommonJS(stdin_exports); +var import_getPostsFromGlobResult_2e7f393c = require("../../../chunks/getPostsFromGlobResult-2e7f393c.js"); +var import_sanitize_html = __toESM(require("sanitize-html")); +const fetchBlogPosts = async () => { + const files = await { "../content/blog/2016-02-28-eating-disorder-powerful.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2016-02-28-eating-disorder-powerful-0af4a0ee.js"))), "../content/blog/2017-03-03-loss-and-ed.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2017-03-03-loss-and-ed-d4b1c1a5.js"))), "../content/blog/2019-08-15-goodbye-bear.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2019-08-15-goodbye-bear-799aed90.js"))), "../content/blog/2019-09-20-why-use-css-in-js.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2019-09-20-why-use-css-in-js-9fcc7d49.js"))), "../content/blog/2019-10-30-culture-i-devoured-in-september-2019.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2019-10-30-culture-i-devoured-in-september-2019-46f09e61.js"))), "../content/blog/2019-12-20-nuxt-to-gatsby.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2019-12-20-nuxt-to-gatsby-fc2a6097.js"))), "../content/blog/2020-02-20-introducing-eating-disorders.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-02-20-introducing-eating-disorders-d2e86304.js"))), "../content/blog/2020-02-24-hereabouts-devblog-1.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-02-24-hereabouts-devblog-1-18e93c36.js"))), "../content/blog/2020-03-15-ux-with-components-screens-state-and-actions.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-03-15-ux-with-components-screens-state-and-actions-0c39ac14.js"))), "../content/blog/2020-03-22-chosing-react-native-for-hereabouts.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-03-22-chosing-react-native-for-hereabouts-b7863833.js"))), "../content/blog/2020-04-02-hereabouts-devlog-2.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-04-02-hereabouts-devlog-2-264ab07c.js"))), "../content/blog/2020-05-31-unicorns.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-05-31-unicorns-06ff6905.js"))), "../content/blog/2020-06-11-deploy-rails-in-render.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-06-11-deploy-rails-in-render-30f28e2a.js"))), "../content/blog/2020-08-07-where-i-go-for-ui-inspiration.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-08-07-where-i-go-for-ui-inspiration-fc5cd52d.js"))), "../content/blog/2020-08-14-thing-i-learned.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-08-14-thing-i-learned-05e37aa6.js"))), "../content/blog/2020-08-21-things-i-learned.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-08-21-things-i-learned-a798a2f9.js"))), "../content/blog/2020-08-23-why-are-you-like-this-javascript.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-08-23-why-are-you-like-this-javascript-843edfcd.js"))), "../content/blog/2020-08-28-things-i-learned-3.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-08-28-things-i-learned-3-2e553969.js"))), "../content/blog/2020-08-29-apple-what-are-you-doing.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-08-29-apple-what-are-you-doing-a46abe23.js"))), "../content/blog/2020-09-04-things-i-learned-4.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-04-things-i-learned-4-a37f698c.js"))), "../content/blog/2020-09-06-js-promise-introduction.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-06-js-promise-introduction-04a4a7c9.js"))), "../content/blog/2020-09-11-things-i-learned-5.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-11-things-i-learned-5-9ba86116.js"))), "../content/blog/2020-09-18-things-i-learned-6.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-18-things-i-learned-6-43c7d35d.js"))), "../content/blog/2020-09-21-finding-a-job-process.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-21-finding-a-job-process-d482c66d.js"))), "../content/blog/2020-09-25-things-i-learned-7.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-25-things-i-learned-7-3c1e1a8f.js"))), "../content/blog/2020-09-28-software-as-craft.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-28-software-as-craft-24d74267.js"))), "../content/blog/2020-10-02-things-i-learned-8.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-02-things-i-learned-8-b54e3403.js"))), "../content/blog/2020-10-09-things-i-learned-9.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-09-things-i-learned-9-0fa38174.js"))), "../content/blog/2020-10-10-five-questions-for-a-first-week.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-10-five-questions-for-a-first-week-5fec9954.js"))), "../content/blog/2020-10-16-things-i-learned-10.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-16-things-i-learned-10-3f4d1b6f.js"))), "../content/blog/2020-10-21-designing-mental-frameworks.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-21-designing-mental-frameworks-41042d8b.js"))), "../content/blog/2020-10-23-things-i-learned-11.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-23-things-i-learned-11-04dedbc2.js"))), "../content/blog/2020-10-24-writing-for-recipe-cards.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-24-writing-for-recipe-cards-ae8f013d.js"))), "../content/blog/2020-10-31-things-i-learned-12.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-31-things-i-learned-12-8d6c0203.js"))), "../content/blog/2020-11-01-js-runtimes-and-environment.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-11-01-js-runtimes-and-environment-c2ddc8b0.js"))), "../content/blog/2020-11-07-things-i-learned-13.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-11-07-things-i-learned-13-87ae224f.js"))), "../content/blog/2020-11-13-things-i-learned-14.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-11-13-things-i-learned-14-f6c9a803.js"))), "../content/blog/2020-11-19-figma-components.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-11-19-figma-components-9b57977b.js"))), "../content/blog/2020-11-20-things-i-learned-15.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-11-20-things-i-learned-15-fcfff925.js"))), "../content/blog/2020-11-23-tiny-separate-design-engineering.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-11-23-tiny-separate-design-engineering-b8124733.js"))), "../content/blog/2020-11-27-things-i-learned-16.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-11-27-things-i-learned-16-d78b9827.js"))), "../content/blog/2020-12-05-things-i-learned-17.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-12-05-things-i-learned-17-93c9716b.js"))), "../content/blog/2020-12-10-things-i-learned-18.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-12-10-things-i-learned-18-a1af1eed.js"))), "../content/blog/2020-12-18-things-i-learned-19.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-12-18-things-i-learned-19-b5e2eca1.js"))), "../content/blog/2020-12-20-how-are-we-going-to-write-about-this.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-12-20-how-are-we-going-to-write-about-this-d65432ee.js"))), "../content/blog/2020-12-27-things-i-learned-20.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-12-27-things-i-learned-20-deca546e.js"))), "../content/blog/2021-01-01-things-i-learned-21.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-01-things-i-learned-21-a5c9e4ef.js"))), "../content/blog/2021-01-02-yearly-theme-2021.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-02-yearly-theme-2021-03a7be39.js"))), "../content/blog/2021-01-09-things-i-learned-22.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-09-things-i-learned-22-09d66b70.js"))), "../content/blog/2021-01-10-an-ode-to-plaintext-notes.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-10-an-ode-to-plaintext-notes-be3efccb.js"))), "../content/blog/2021-01-15-free-fonts-awwwards.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-15-free-fonts-awwwards-83617597.js"))), "../content/blog/2021-01-15-things-i-learned-23.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-15-things-i-learned-23-bcc7f83d.js"))), "../content/blog/2021-01-23-things-i-learned-24.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-23-things-i-learned-24-1b7b35ce.js"))), "../content/blog/2021-01-27-albums-2020.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-27-albums-2020-5725fa4c.js"))), "../content/blog/2021-01-29-things-i-learned-25.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-29-things-i-learned-25-2a491e4b.js"))), "../content/blog/2021-01-31-tiny-thoughts-frontend-is-fullstack.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-31-tiny-thoughts-frontend-is-fullstack-765d7355.js"))), "../content/blog/2021-02-06-things-i-learned-26.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-06-things-i-learned-26-ae9245db.js"))), "../content/blog/2021-02-12-blog-redesign-changelog.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-12-blog-redesign-changelog-48103e19.js"))), "../content/blog/2021-02-13-things-i-learned-27.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-13-things-i-learned-27-17f83b3f.js"))), "../content/blog/2021-02-17-closures-in-swift.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-17-closures-in-swift-b4cbc2f3.js"))), "../content/blog/2021-02-19-things-i-learned-28.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-19-things-i-learned-28-9e389556.js"))), "../content/blog/2021-02-20-clubhouse-after-48-hours.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-20-clubhouse-after-48-hours-55ae4f20.js"))), "../content/blog/2021-02-26-things-i-learned-29.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-26-things-i-learned-29-71d9ce32.js"))), "../content/blog/2021-02-27-github-actions-xcode-tests.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-27-github-actions-xcode-tests-b4c7e20c.js"))), "../content/blog/2021-03-05-things-i-learned-30.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-03-05-things-i-learned-30-8c9e3af2.js"))), "../content/blog/2021-03-06-design-workflow-build-components.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-03-06-design-workflow-build-components-63b59472.js"))), "../content/blog/2021-03-12-things-i-learned-31.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-03-12-things-i-learned-31-5651ec47.js"))), "../content/blog/2021-03-20-things-i-learned-32.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-03-20-things-i-learned-32-0b354c4a.js"))), "../content/blog/2021-03-21-dash-cycle-00.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-03-21-dash-cycle-00-7e58c52a.js"))), "../content/blog/2021-03-26-things-learned-33.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-03-26-things-learned-33-6b144699.js"))), "../content/blog/2021-04-02-things-i-learned-34.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-04-02-things-i-learned-34-55e72bfc.js"))), "../content/blog/2021-04-08-just-enough-software-design.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-04-08-just-enough-software-design-bb1b6ff1.js"))), "../content/blog/2021-04-11-things-i-learned-35.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-04-11-things-i-learned-35-34430b12.js"))), "../content/blog/2021-04-12-dash-cycle-01.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-04-12-dash-cycle-01-8d6c6cd5.js"))), "../content/blog/2021-04-16-things-i-learned-36.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-04-16-things-i-learned-36-aee9efcb.js"))), "../content/blog/2021-04-24-things-i-learned-37.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-04-24-things-i-learned-37-6d2be3d7.js"))), "../content/blog/2021-04-27-excommunicate-your-ideas.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-04-27-excommunicate-your-ideas-66e47124.js"))), "../content/blog/2021-05-01-things-i-learned-38.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-05-01-things-i-learned-38-2af7f335.js"))), "../content/blog/2021-05-05-customer-centric-care-like-a-robot.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-05-05-customer-centric-care-like-a-robot-ad6292bd.js"))), "../content/blog/2021-05-06-weekly-39.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-05-06-weekly-39-8bc58439.js"))), "../content/blog/2021-05-15-weekly-40.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-05-15-weekly-40-68693d5d.js"))), "../content/blog/2021-05-21-weekly-41.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-05-21-weekly-41-311c0739.js"))), "../content/blog/2021-05-27-weekly-42.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-05-27-weekly-42-40ad7259.js"))), "../content/blog/2021-06-05-weekly-43.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-06-05-weekly-43-a2087a97.js"))), "../content/blog/2021-06-10-weekly-44.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-06-10-weekly-44-618d9f06.js"))), "../content/blog/2021-06-13-infinite-coast-of-problem-solving.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-06-13-infinite-coast-of-problem-solving-20326007.js"))), "../content/blog/2021-06-27-weekly-45.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-06-27-weekly-45-0233ec62.js"))), "../content/blog/2021-07-08-out-of-office.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-07-08-out-of-office-2e798a65.js"))), "../content/blog/2021-10-11-back-in-office.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-10-11-back-in-office-70c65d6c.js"))), "../content/blog/2021-10-25-the-handbrake-has-come-off.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-10-25-the-handbrake-has-come-off-3c1142af.js"))), "../content/blog/2021-10-28-how-to-onboard-new-software-engineers.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-10-28-how-to-onboard-new-software-engineers-89215694.js"))), "../content/blog/2021-12-12-build-the-platform-ship-the-product.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-12-12-build-the-platform-ship-the-product-aef2df81.js"))), "../content/blog/2022-02-04-vibe-check-0.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2022-02-04-vibe-check-0-c8eb5675.js"))), "../content/blog/2022-02-22-atomic-habits-is-a-really-good-book.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2022-02-22-atomic-habits-is-a-really-good-book-89593d65.js"))), "../content/blog/2022-02-28-vibe-check-01.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2022-02-28-vibe-check-01-d55a0e2d.js"))), "../content/blog/2022-03-02-concentrate-on-concentrated-tests.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2022-03-02-concentrate-on-concentrated-tests-3e42db2f.js"))), "../content/blog/2022-03-13-discover-complexity.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2022-03-13-discover-complexity-56eefb8e.js"))), "../content/blog/2022-04-03-vibe-check-02.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2022-04-03-vibe-check-02-61ea8329.js"))), "../content/blog/2022-04-10-recognise-and-reduce-risk.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2022-04-10-recognise-and-reduce-risk-023ea1df.js"))), "../content/book-reviews/2020-09-11-wow-no-thank-you.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-11-wow-no-thank-you-a0ff4136.js"))), "../content/book-reviews/2020-09-20-how-do-we-know-were-doing-it-right.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-20-how-do-we-know-were-doing-it-right-0baa332f.js"))), "../content/book-reviews/2020-09-26-queenie.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-09-26-queenie-d51f811c.js"))), "../content/book-reviews/2020-10-03-cats-cradle.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-03-cats-cradle-317a4017.js"))), "../content/book-reviews/2020-10-18-hamet.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-10-18-hamet-528d07f6.js"))), "../content/book-reviews/2020-11-08-an-absolutely-remarkable-thing.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-11-08-an-absolutely-remarkable-thing-cc424996.js"))), "../content/book-reviews/2020-11-14-on-connection.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-11-14-on-connection-f5179625.js"))), "../content/book-reviews/2020-12-02-the-phoenix-project.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-12-02-the-phoenix-project-3360233b.js"))), "../content/book-reviews/2020-12-13-kings-of-the-wyld.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2020-12-13-kings-of-the-wyld-75a05e60.js"))), "../content/book-reviews/2021-01-23-the-silence-of-the-girls.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-01-23-the-silence-of-the-girls-47091b40.js"))), "../content/book-reviews/2021-02-04-first-you-write-a-sentence.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-04-first-you-write-a-sentence-b830ceb2.js"))), "../content/book-reviews/2021-02-09-utopia-avenue.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-02-09-utopia-avenue-4d3c6168.js"))), "../content/book-reviews/2021-03-15-magician.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-03-15-magician-9baceb14.js"))), "../content/book-reviews/2021-04-03-once-upon-a-river.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-04-03-once-upon-a-river-22df99c4.js"))), "../content/book-reviews/2021-04-17-mrs-death-misses-death.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-04-17-mrs-death-misses-death-baf54f9b.js"))), "../content/book-reviews/2021-05-05-after.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-05-05-after-8ebc5dd7.js"))), "../content/book-reviews/2021-05-25-hangover-square.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-05-25-hangover-square-baf2a976.js"))), "../content/book-reviews/2021-06-03-project-hail-mary.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-06-03-project-hail-mary-b8c7d57d.js"))), "../content/book-reviews/2021-06-13-sistersong.md": () => Promise.resolve().then(() => __toESM(require("../../../chunks/2021-06-13-sistersong-b84e41c1.js"))) }; + return await (0, import_getPostsFromGlobResult_2e7f393c.g)(files); +}; +const get = async ({ url }) => { + try { + const posts = await fetchBlogPosts(); + const sortedBlogPosts = posts.sort((a, b) => { + if (a.date > b.date) { + return -1; + } + if (a.date < b.date) { + return 1; + } + return 0; + }); + const withCleanHtml = sortedBlogPosts.map((post) => { + return __spreadProps(__spreadValues({}, post), { + html: (0, import_sanitize_html.default)(post.html, { + allowedTags: [] + }) + }); + }); + return { + status: 200, + body: { + posts: withCleanHtml + } + }; + } catch (error) { + console.error({ error: JSON.stringify(error) }); + return { + status: 500, + body: { + error: "Could not fetch posts. " + error + } + }; + } +}; diff --git a/.netlify/server/entries/endpoints/api/blog/_slug_.json.ts.js b/.netlify/server/entries/endpoints/api/blog/_slug_.json.ts.js new file mode 100644 index 0000000..91d6493 --- /dev/null +++ b/.netlify/server/entries/endpoints/api/blog/_slug_.json.ts.js @@ -0,0 +1,71 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __defProps = Object.defineProperties; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropDescs = Object.getOwnPropertyDescriptors; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getOwnPropSymbols = Object.getOwnPropertySymbols; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __propIsEnum = Object.prototype.propertyIsEnumerable; +var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; +var __spreadValues = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + if (__getOwnPropSymbols) + for (var prop of __getOwnPropSymbols(b)) { + if (__propIsEnum.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + } + return a; +}; +var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + get: () => get +}); +module.exports = __toCommonJS(stdin_exports); +var import_mdsvex = require("mdsvex"); +var import_getPostsFromGlobResult_2e7f393c = require("../../../../chunks/getPostsFromGlobResult-2e7f393c.js"); +var import_remark_gfm = __toESM(require("remark-gfm")); +const fetchBlogPostBySlug = async (slug) => { + const globResult = await { "../content/blog/2016-02-28-eating-disorder-powerful.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2016-02-28-eating-disorder-powerful-0af4a0ee.js"))), "../content/blog/2017-03-03-loss-and-ed.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2017-03-03-loss-and-ed-d4b1c1a5.js"))), "../content/blog/2019-08-15-goodbye-bear.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2019-08-15-goodbye-bear-799aed90.js"))), "../content/blog/2019-09-20-why-use-css-in-js.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2019-09-20-why-use-css-in-js-9fcc7d49.js"))), "../content/blog/2019-10-30-culture-i-devoured-in-september-2019.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2019-10-30-culture-i-devoured-in-september-2019-46f09e61.js"))), "../content/blog/2019-12-20-nuxt-to-gatsby.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2019-12-20-nuxt-to-gatsby-fc2a6097.js"))), "../content/blog/2020-02-20-introducing-eating-disorders.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-02-20-introducing-eating-disorders-d2e86304.js"))), "../content/blog/2020-02-24-hereabouts-devblog-1.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-02-24-hereabouts-devblog-1-18e93c36.js"))), "../content/blog/2020-03-15-ux-with-components-screens-state-and-actions.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-03-15-ux-with-components-screens-state-and-actions-0c39ac14.js"))), "../content/blog/2020-03-22-chosing-react-native-for-hereabouts.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-03-22-chosing-react-native-for-hereabouts-b7863833.js"))), "../content/blog/2020-04-02-hereabouts-devlog-2.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-04-02-hereabouts-devlog-2-264ab07c.js"))), "../content/blog/2020-05-31-unicorns.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-05-31-unicorns-06ff6905.js"))), "../content/blog/2020-06-11-deploy-rails-in-render.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-06-11-deploy-rails-in-render-30f28e2a.js"))), "../content/blog/2020-08-07-where-i-go-for-ui-inspiration.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-08-07-where-i-go-for-ui-inspiration-fc5cd52d.js"))), "../content/blog/2020-08-14-thing-i-learned.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-08-14-thing-i-learned-05e37aa6.js"))), "../content/blog/2020-08-21-things-i-learned.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-08-21-things-i-learned-a798a2f9.js"))), "../content/blog/2020-08-23-why-are-you-like-this-javascript.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-08-23-why-are-you-like-this-javascript-843edfcd.js"))), "../content/blog/2020-08-28-things-i-learned-3.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-08-28-things-i-learned-3-2e553969.js"))), "../content/blog/2020-08-29-apple-what-are-you-doing.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-08-29-apple-what-are-you-doing-a46abe23.js"))), "../content/blog/2020-09-04-things-i-learned-4.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-04-things-i-learned-4-a37f698c.js"))), "../content/blog/2020-09-06-js-promise-introduction.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-06-js-promise-introduction-04a4a7c9.js"))), "../content/blog/2020-09-11-things-i-learned-5.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-11-things-i-learned-5-9ba86116.js"))), "../content/blog/2020-09-18-things-i-learned-6.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-18-things-i-learned-6-43c7d35d.js"))), "../content/blog/2020-09-21-finding-a-job-process.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-21-finding-a-job-process-d482c66d.js"))), "../content/blog/2020-09-25-things-i-learned-7.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-25-things-i-learned-7-3c1e1a8f.js"))), "../content/blog/2020-09-28-software-as-craft.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-28-software-as-craft-24d74267.js"))), "../content/blog/2020-10-02-things-i-learned-8.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-02-things-i-learned-8-b54e3403.js"))), "../content/blog/2020-10-09-things-i-learned-9.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-09-things-i-learned-9-0fa38174.js"))), "../content/blog/2020-10-10-five-questions-for-a-first-week.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-10-five-questions-for-a-first-week-5fec9954.js"))), "../content/blog/2020-10-16-things-i-learned-10.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-16-things-i-learned-10-3f4d1b6f.js"))), "../content/blog/2020-10-21-designing-mental-frameworks.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-21-designing-mental-frameworks-41042d8b.js"))), "../content/blog/2020-10-23-things-i-learned-11.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-23-things-i-learned-11-04dedbc2.js"))), "../content/blog/2020-10-24-writing-for-recipe-cards.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-24-writing-for-recipe-cards-ae8f013d.js"))), "../content/blog/2020-10-31-things-i-learned-12.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-31-things-i-learned-12-8d6c0203.js"))), "../content/blog/2020-11-01-js-runtimes-and-environment.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-11-01-js-runtimes-and-environment-c2ddc8b0.js"))), "../content/blog/2020-11-07-things-i-learned-13.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-11-07-things-i-learned-13-87ae224f.js"))), "../content/blog/2020-11-13-things-i-learned-14.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-11-13-things-i-learned-14-f6c9a803.js"))), "../content/blog/2020-11-19-figma-components.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-11-19-figma-components-9b57977b.js"))), "../content/blog/2020-11-20-things-i-learned-15.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-11-20-things-i-learned-15-fcfff925.js"))), "../content/blog/2020-11-23-tiny-separate-design-engineering.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-11-23-tiny-separate-design-engineering-b8124733.js"))), "../content/blog/2020-11-27-things-i-learned-16.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-11-27-things-i-learned-16-d78b9827.js"))), "../content/blog/2020-12-05-things-i-learned-17.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-12-05-things-i-learned-17-93c9716b.js"))), "../content/blog/2020-12-10-things-i-learned-18.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-12-10-things-i-learned-18-a1af1eed.js"))), "../content/blog/2020-12-18-things-i-learned-19.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-12-18-things-i-learned-19-b5e2eca1.js"))), "../content/blog/2020-12-20-how-are-we-going-to-write-about-this.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-12-20-how-are-we-going-to-write-about-this-d65432ee.js"))), "../content/blog/2020-12-27-things-i-learned-20.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-12-27-things-i-learned-20-deca546e.js"))), "../content/blog/2021-01-01-things-i-learned-21.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-01-things-i-learned-21-a5c9e4ef.js"))), "../content/blog/2021-01-02-yearly-theme-2021.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-02-yearly-theme-2021-03a7be39.js"))), "../content/blog/2021-01-09-things-i-learned-22.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-09-things-i-learned-22-09d66b70.js"))), "../content/blog/2021-01-10-an-ode-to-plaintext-notes.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-10-an-ode-to-plaintext-notes-be3efccb.js"))), "../content/blog/2021-01-15-free-fonts-awwwards.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-15-free-fonts-awwwards-83617597.js"))), "../content/blog/2021-01-15-things-i-learned-23.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-15-things-i-learned-23-bcc7f83d.js"))), "../content/blog/2021-01-23-things-i-learned-24.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-23-things-i-learned-24-1b7b35ce.js"))), "../content/blog/2021-01-27-albums-2020.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-27-albums-2020-5725fa4c.js"))), "../content/blog/2021-01-29-things-i-learned-25.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-29-things-i-learned-25-2a491e4b.js"))), "../content/blog/2021-01-31-tiny-thoughts-frontend-is-fullstack.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-31-tiny-thoughts-frontend-is-fullstack-765d7355.js"))), "../content/blog/2021-02-06-things-i-learned-26.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-06-things-i-learned-26-ae9245db.js"))), "../content/blog/2021-02-12-blog-redesign-changelog.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-12-blog-redesign-changelog-48103e19.js"))), "../content/blog/2021-02-13-things-i-learned-27.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-13-things-i-learned-27-17f83b3f.js"))), "../content/blog/2021-02-17-closures-in-swift.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-17-closures-in-swift-b4cbc2f3.js"))), "../content/blog/2021-02-19-things-i-learned-28.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-19-things-i-learned-28-9e389556.js"))), "../content/blog/2021-02-20-clubhouse-after-48-hours.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-20-clubhouse-after-48-hours-55ae4f20.js"))), "../content/blog/2021-02-26-things-i-learned-29.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-26-things-i-learned-29-71d9ce32.js"))), "../content/blog/2021-02-27-github-actions-xcode-tests.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-27-github-actions-xcode-tests-b4c7e20c.js"))), "../content/blog/2021-03-05-things-i-learned-30.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-03-05-things-i-learned-30-8c9e3af2.js"))), "../content/blog/2021-03-06-design-workflow-build-components.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-03-06-design-workflow-build-components-63b59472.js"))), "../content/blog/2021-03-12-things-i-learned-31.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-03-12-things-i-learned-31-5651ec47.js"))), "../content/blog/2021-03-20-things-i-learned-32.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-03-20-things-i-learned-32-0b354c4a.js"))), "../content/blog/2021-03-21-dash-cycle-00.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-03-21-dash-cycle-00-7e58c52a.js"))), "../content/blog/2021-03-26-things-learned-33.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-03-26-things-learned-33-6b144699.js"))), "../content/blog/2021-04-02-things-i-learned-34.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-04-02-things-i-learned-34-55e72bfc.js"))), "../content/blog/2021-04-08-just-enough-software-design.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-04-08-just-enough-software-design-bb1b6ff1.js"))), "../content/blog/2021-04-11-things-i-learned-35.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-04-11-things-i-learned-35-34430b12.js"))), "../content/blog/2021-04-12-dash-cycle-01.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-04-12-dash-cycle-01-8d6c6cd5.js"))), "../content/blog/2021-04-16-things-i-learned-36.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-04-16-things-i-learned-36-aee9efcb.js"))), "../content/blog/2021-04-24-things-i-learned-37.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-04-24-things-i-learned-37-6d2be3d7.js"))), "../content/blog/2021-04-27-excommunicate-your-ideas.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-04-27-excommunicate-your-ideas-66e47124.js"))), "../content/blog/2021-05-01-things-i-learned-38.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-05-01-things-i-learned-38-2af7f335.js"))), "../content/blog/2021-05-05-customer-centric-care-like-a-robot.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-05-05-customer-centric-care-like-a-robot-ad6292bd.js"))), "../content/blog/2021-05-06-weekly-39.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-05-06-weekly-39-8bc58439.js"))), "../content/blog/2021-05-15-weekly-40.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-05-15-weekly-40-68693d5d.js"))), "../content/blog/2021-05-21-weekly-41.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-05-21-weekly-41-311c0739.js"))), "../content/blog/2021-05-27-weekly-42.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-05-27-weekly-42-40ad7259.js"))), "../content/blog/2021-06-05-weekly-43.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-06-05-weekly-43-a2087a97.js"))), "../content/blog/2021-06-10-weekly-44.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-06-10-weekly-44-618d9f06.js"))), "../content/blog/2021-06-13-infinite-coast-of-problem-solving.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-06-13-infinite-coast-of-problem-solving-20326007.js"))), "../content/blog/2021-06-27-weekly-45.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-06-27-weekly-45-0233ec62.js"))), "../content/blog/2021-07-08-out-of-office.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-07-08-out-of-office-2e798a65.js"))), "../content/blog/2021-10-11-back-in-office.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-10-11-back-in-office-70c65d6c.js"))), "../content/blog/2021-10-25-the-handbrake-has-come-off.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-10-25-the-handbrake-has-come-off-3c1142af.js"))), "../content/blog/2021-10-28-how-to-onboard-new-software-engineers.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-10-28-how-to-onboard-new-software-engineers-89215694.js"))), "../content/blog/2021-12-12-build-the-platform-ship-the-product.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-12-12-build-the-platform-ship-the-product-aef2df81.js"))), "../content/blog/2022-02-04-vibe-check-0.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2022-02-04-vibe-check-0-c8eb5675.js"))), "../content/blog/2022-02-22-atomic-habits-is-a-really-good-book.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2022-02-22-atomic-habits-is-a-really-good-book-89593d65.js"))), "../content/blog/2022-02-28-vibe-check-01.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2022-02-28-vibe-check-01-d55a0e2d.js"))), "../content/blog/2022-03-02-concentrate-on-concentrated-tests.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2022-03-02-concentrate-on-concentrated-tests-3e42db2f.js"))), "../content/blog/2022-03-13-discover-complexity.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2022-03-13-discover-complexity-56eefb8e.js"))), "../content/blog/2022-04-03-vibe-check-02.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2022-04-03-vibe-check-02-61ea8329.js"))), "../content/blog/2022-04-10-recognise-and-reduce-risk.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2022-04-10-recognise-and-reduce-risk-023ea1df.js"))), "../content/book-reviews/2020-09-11-wow-no-thank-you.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-11-wow-no-thank-you-a0ff4136.js"))), "../content/book-reviews/2020-09-20-how-do-we-know-were-doing-it-right.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-20-how-do-we-know-were-doing-it-right-0baa332f.js"))), "../content/book-reviews/2020-09-26-queenie.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-09-26-queenie-d51f811c.js"))), "../content/book-reviews/2020-10-03-cats-cradle.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-03-cats-cradle-317a4017.js"))), "../content/book-reviews/2020-10-18-hamet.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-10-18-hamet-528d07f6.js"))), "../content/book-reviews/2020-11-08-an-absolutely-remarkable-thing.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-11-08-an-absolutely-remarkable-thing-cc424996.js"))), "../content/book-reviews/2020-11-14-on-connection.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-11-14-on-connection-f5179625.js"))), "../content/book-reviews/2020-12-02-the-phoenix-project.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-12-02-the-phoenix-project-3360233b.js"))), "../content/book-reviews/2020-12-13-kings-of-the-wyld.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2020-12-13-kings-of-the-wyld-75a05e60.js"))), "../content/book-reviews/2021-01-23-the-silence-of-the-girls.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-01-23-the-silence-of-the-girls-47091b40.js"))), "../content/book-reviews/2021-02-04-first-you-write-a-sentence.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-04-first-you-write-a-sentence-b830ceb2.js"))), "../content/book-reviews/2021-02-09-utopia-avenue.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-02-09-utopia-avenue-4d3c6168.js"))), "../content/book-reviews/2021-03-15-magician.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-03-15-magician-9baceb14.js"))), "../content/book-reviews/2021-04-03-once-upon-a-river.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-04-03-once-upon-a-river-22df99c4.js"))), "../content/book-reviews/2021-04-17-mrs-death-misses-death.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-04-17-mrs-death-misses-death-baf54f9b.js"))), "../content/book-reviews/2021-05-05-after.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-05-05-after-8ebc5dd7.js"))), "../content/book-reviews/2021-05-25-hangover-square.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-05-25-hangover-square-baf2a976.js"))), "../content/book-reviews/2021-06-03-project-hail-mary.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-06-03-project-hail-mary-b8c7d57d.js"))), "../content/book-reviews/2021-06-13-sistersong.md": () => Promise.resolve().then(() => __toESM(require("../../../../chunks/2021-06-13-sistersong-b84e41c1.js"))) }; + const allFiles = await (0, import_getPostsFromGlobResult_2e7f393c.g)(globResult); + const post = allFiles.find((post2) => post2.slug === slug); + if (!post) { + return null; + } + const compiles = await (0, import_mdsvex.compile)(post.html, { remarkPlugins: [import_remark_gfm.default] }); + return __spreadProps(__spreadValues({}, post), { + html: compiles.code + }); +}; +const get = async ({ params }) => { + const { slug } = params; + const post = await fetchBlogPostBySlug(slug); + if (!post) { + return { + status: 404, + body: {} + }; + } + return { + status: 200, + body: { post } + }; +}; diff --git a/.netlify/server/entries/fallbacks/error.svelte.js b/.netlify/server/entries/fallbacks/error.svelte.js new file mode 100644 index 0000000..7291920 --- /dev/null +++ b/.netlify/server/entries/fallbacks/error.svelte.js @@ -0,0 +1,43 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => Error2, + load: () => load +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("../../chunks/index-10ac95e2.js"); +function load({ error, status }) { + return { props: { error, status } }; +} +const Error2 = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + let { status } = $$props; + let { error } = $$props; + if ($$props.status === void 0 && $$bindings.status && status !== void 0) + $$bindings.status(status); + if ($$props.error === void 0 && $$bindings.error && error !== void 0) + $$bindings.error(error); + return `

${(0, import_index_10ac95e2.e)(status)}

+ +
${(0, import_index_10ac95e2.e)(error.message)}
+ + + +${error.frame ? `
${(0, import_index_10ac95e2.e)(error.frame)}
` : ``} +${error.stack ? `
${(0, import_index_10ac95e2.e)(error.stack)}
` : ``}`; +}); diff --git a/.netlify/server/entries/fallbacks/layout.svelte.js b/.netlify/server/entries/fallbacks/layout.svelte.js new file mode 100644 index 0000000..dd5494e --- /dev/null +++ b/.netlify/server/entries/fallbacks/layout.svelte.js @@ -0,0 +1,26 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => Layout +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("../../chunks/index-10ac95e2.js"); +const Layout = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + return `${slots.default ? slots.default({}) : ``}`; +}); diff --git a/.netlify/server/entries/pages/blog.svelte.js b/.netlify/server/entries/pages/blog.svelte.js new file mode 100644 index 0000000..1b2fb98 --- /dev/null +++ b/.netlify/server/entries/pages/blog.svelte.js @@ -0,0 +1,68 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => Blog, + load: () => load +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("../../chunks/index-10ac95e2.js"); +var import_date_fns = require("date-fns"); +var import_Navbar_3e8a1470 = require("../../chunks/Navbar-3e8a1470.js"); +var blog_svelte_svelte_type_style_lang = ""; +const css = { + code: ".posts.svelte-1a11qlj.svelte-1a11qlj{list-style:none;margin:0;padding:0;display:grid;grid-template-columns:1fr;gap:var(--spacing-base)}.post.svelte-1a11qlj.svelte-1a11qlj{border:1px solid var(--gray-200);padding:var(--spacing-md);transition:0.2s;border-radius:8px}.post.svelte-1a11qlj.svelte-1a11qlj:hover{color:var(--brand-orange)}.post.svelte-1a11qlj a.svelte-1a11qlj{color:inherit;text-decoration:none}.post-title.svelte-1a11qlj.svelte-1a11qlj{text-decoration:underline;font-family:var(--font-family-title);font-weight:600;padding-bottom:8px}.post-date.svelte-1a11qlj.svelte-1a11qlj{font-size:0.9rem}.post-preview.svelte-1a11qlj.svelte-1a11qlj{font-size:0.9rem;line-height:120%;color:var(--gray-600)}.days-since.svelte-1a11qlj.svelte-1a11qlj{color:var(--brand-orange);font-weight:300;border:1px solid var(--brand-orange);border-radius:4px;padding:8px;font-family:monospace}", + map: null +}; +async function load({ fetch }) { + const posts = await fetch("/api/blog.json").then((res2) => res2.json()).then((res2) => res2.posts); + const mostRecentPost = posts[0]; + const daysSinceLastPublish = (0, import_date_fns.differenceInCalendarDays)(new Date(), new Date(mostRecentPost.date)); + const res = { + status: 200, + props: { posts, daysSinceLastPublish } + }; + return res; +} +const Blog = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + let { posts } = $$props; + let { daysSinceLastPublish } = $$props; + if ($$props.posts === void 0 && $$bindings.posts && posts !== void 0) + $$bindings.posts(posts); + if ($$props.daysSinceLastPublish === void 0 && $$bindings.daysSinceLastPublish && daysSinceLastPublish !== void 0) + $$bindings.daysSinceLastPublish(daysSinceLastPublish); + $$result.css.add(css); + return `${(0, import_index_10ac95e2.v)(import_Navbar_3e8a1470.N, "Navbar").$$render($$result, {}, {}, {})} +

Blog

+

I write about software and I how I should have built it, books I've read, and sometimes other + things. +

+

I like to write at least once a month. It's been ${(0, import_index_10ac95e2.e)(daysSinceLastPublish)} + ${(0, import_index_10ac95e2.e)(daysSinceLastPublish === 1 ? "day" : "days")} since I last published something. +

+ +

All Writing

+
    ${(0, import_index_10ac95e2.a)(posts, (post) => { + return `
  • ${post.book_review ? `\u{1F4DA}` : ``} +
    ${(0, import_index_10ac95e2.e)(post.title)}
    +
    ${(0, import_index_10ac95e2.e)(post.html.slice(0, 140))}...
    +
    ${(0, import_index_10ac95e2.e)((0, import_date_fns.intlFormat)(new Date(post.date)))}
    +
  • `; + })}
+
`; +}); diff --git a/.netlify/server/entries/pages/blog/__error.svelte.js b/.netlify/server/entries/pages/blog/__error.svelte.js new file mode 100644 index 0000000..fb72765 --- /dev/null +++ b/.netlify/server/entries/pages/blog/__error.svelte.js @@ -0,0 +1,37 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => _error +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("../../../chunks/index-10ac95e2.js"); +var import_Navbar_3e8a1470 = require("../../../chunks/Navbar-3e8a1470.js"); +var __error_svelte_svelte_type_style_lang = ""; +const css = { + code: "main.svelte-10gwx6e.svelte-10gwx6e{background-color:var(--gray-100);min-height:100vh;display:grid;grid-template-columns:1fr;grid-template-rows:min-content 1fr}main.svelte-10gwx6e section.svelte-10gwx6e{display:grid;min-width:100vw;height:100%;place-content:center}a.svelte-10gwx6e.svelte-10gwx6e{text-align:center;color:var(--brand-orange);font-size:1.2rem}", + map: null +}; +const _error = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + $$result.css.add(css); + return `
${(0, import_index_10ac95e2.v)(import_Navbar_3e8a1470.N, "Navbar").$$render($$result, {}, {}, {})} +

Erm...

+

Couldn't find that post

+ Go back to the blog
+
`; +}); diff --git a/.netlify/server/entries/pages/blog/_slug_.svelte.js b/.netlify/server/entries/pages/blog/_slug_.svelte.js new file mode 100644 index 0000000..51c4372 --- /dev/null +++ b/.netlify/server/entries/pages/blog/_slug_.svelte.js @@ -0,0 +1,59 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => U5Bslugu5D, + load: () => load +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("../../../chunks/index-10ac95e2.js"); +var import_date_fns = require("date-fns"); +var import_Navbar_3e8a1470 = require("../../../chunks/Navbar-3e8a1470.js"); +var _slug__svelte_svelte_type_style_lang = ""; +const css = { + code: "header.svelte-1dr3guc{padding-top:24px}article.svelte-1dr3guc{max-width:65ch}.post-title.svelte-1dr3guc{text-align:center;padding-bottom:1rem;line-height:125%}.post-author.svelte-1dr3guc{font-size:1rem;text-align:center;line-height:100%}.post-date.svelte-1dr3guc{font-size:1rem;text-align:center;line-height:100%}", + map: null +}; +async function load({ params, fetch }) { + const { slug } = params; + const { post } = await fetch(`/api/blog/${slug}.json`).then((res2) => res2.json()).catch((error) => { + console.error(error); + return { post: null }; + }); + const res = { + status: post ? 200 : 404, + props: { date: new Date(post.date), post } + }; + return res; +} +const U5Bslugu5D = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + let { date } = $$props; + let { post } = $$props; + if ($$props.date === void 0 && $$bindings.date && date !== void 0) + $$bindings.date(date); + if ($$props.post === void 0 && $$bindings.post && post !== void 0) + $$bindings.post(post); + $$result.css.add(css); + return `${(0, import_index_10ac95e2.v)(import_Navbar_3e8a1470.N, "Navbar").$$render($$result, {}, {}, {})} +

${(0, import_index_10ac95e2.e)(post.title)}

+

${(0, import_index_10ac95e2.e)(post.author)}

+

${(0, import_index_10ac95e2.e)((0, import_date_fns.intlFormat)(date))}

+ +
${post.html}
+
`; +}); diff --git a/.netlify/server/entries/pages/index.svelte.js b/.netlify/server/entries/pages/index.svelte.js new file mode 100644 index 0000000..7c85323 --- /dev/null +++ b/.netlify/server/entries/pages/index.svelte.js @@ -0,0 +1,53 @@ +var __defProp = Object.defineProperty; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key) && key !== except) + __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable }); + } + return to; +}; +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + default: () => Routes +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("../../chunks/index-10ac95e2.js"); +var import_Navbar_3e8a1470 = require("../../chunks/Navbar-3e8a1470.js"); +var index_svelte_svelte_type_style_lang = ""; +const css = { + code: "section.svelte-z7n73x.svelte-z7n73x{--link-transition:0.2s;--link-padding:4px;--link-border-radius:8px}section.svelte-z7n73x ul.svelte-z7n73x{margin-top:0;margin-bottom:0}section.svelte-z7n73x p.svelte-z7n73x{padding-bottom:var(--spacing-md)}.oxwash.svelte-z7n73x.svelte-z7n73x{padding:var(--link-padding);transition:var(--link-transition);border-radius:var(--link-border-radius);background:#0256f2;color:white}.oxwash.svelte-z7n73x.svelte-z7n73x:hover{background:#6fbbec;text-decoration:none}.figma.svelte-z7n73x.svelte-z7n73x{padding:var(--link-padding);transition:var(--link-transition);border-radius:var(--link-border-radius);background:#c7b9ff;color:#000000}.figma.svelte-z7n73x.svelte-z7n73x:hover{background:#ffc700;color:#000000;text-decoration:none}.thesis.svelte-z7n73x.svelte-z7n73x{padding:var(--link-padding);transition:var(--link-transition);border-radius:var(--link-border-radius);border:1px solid var(--brand-orange);color:var(--brand-orange)}.thesis.svelte-z7n73x.svelte-z7n73x:hover{background:var(--brand-orange);color:white;text-decoration:none}.links.svelte-z7n73x a.svelte-z7n73x{color:var(--brand-orange)}h1.svelte-z7n73x.svelte-z7n73x{font-size:2.5rem}h2.svelte-z7n73x.svelte-z7n73x{font-family:var(--font-family-title);color:var(--gray-800)}li.svelte-z7n73x.svelte-z7n73x{padding-bottom:0.3rem}", + map: null +}; +const Routes = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + $$result.css.add(css); + return `${(0, import_index_10ac95e2.v)(import_Navbar_3e8a1470.N, "Navbar").$$render($$result, {}, {}, {})} +

Thomas Wilson

+

I'm a software engineer who loves the craft of building reliable and human-friendly software + for the web. I build good things with good people for good companies. +

+ +

My work

+ ${`

I build human-friendly software for the web, and help teams do that with better design.

+ `}
+ +

Me

+ ${`

I like to write on my blog and ride bikes. I'm learning to sew and my French + is terrible +

+ `}
+ +

Links

+
+
`; +}); diff --git a/.netlify/server/index.js b/.netlify/server/index.js new file mode 100644 index 0000000..ea9e002 --- /dev/null +++ b/.netlify/server/index.js @@ -0,0 +1,2039 @@ +var __create = Object.create; +var __defProp = Object.defineProperty; +var __defProps = Object.defineProperties; +var __getOwnPropDesc = Object.getOwnPropertyDescriptor; +var __getOwnPropDescs = Object.getOwnPropertyDescriptors; +var __getOwnPropNames = Object.getOwnPropertyNames; +var __getOwnPropSymbols = Object.getOwnPropertySymbols; +var __getProtoOf = Object.getPrototypeOf; +var __hasOwnProp = Object.prototype.hasOwnProperty; +var __propIsEnum = Object.prototype.propertyIsEnumerable; +var __defNormalProp = (obj, key2, value) => key2 in obj ? __defProp(obj, key2, { enumerable: true, configurable: true, writable: true, value }) : obj[key2] = value; +var __spreadValues = (a, b) => { + for (var prop in b || (b = {})) + if (__hasOwnProp.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + if (__getOwnPropSymbols) + for (var prop of __getOwnPropSymbols(b)) { + if (__propIsEnum.call(b, prop)) + __defNormalProp(a, prop, b[prop]); + } + return a; +}; +var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b)); +var __export = (target, all) => { + for (var name in all) + __defProp(target, name, { get: all[name], enumerable: true }); +}; +var __copyProps = (to, from, except, desc) => { + if (from && typeof from === "object" || typeof from === "function") { + for (let key2 of __getOwnPropNames(from)) + if (!__hasOwnProp.call(to, key2) && key2 !== except) + __defProp(to, key2, { get: () => from[key2], enumerable: !(desc = __getOwnPropDesc(from, key2)) || desc.enumerable }); + } + return to; +}; +var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target, mod)); +var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); +var stdin_exports = {}; +__export(stdin_exports, { + Server: () => Server, + override: () => override +}); +module.exports = __toCommonJS(stdin_exports); +var import_index_10ac95e2 = require("./chunks/index-10ac95e2.js"); +var __accessCheck = (obj, member, msg) => { + if (!member.has(obj)) + throw TypeError("Cannot " + msg); +}; +var __privateGet = (obj, member, getter) => { + __accessCheck(obj, member, "read from private field"); + return getter ? getter.call(obj) : member.get(obj); +}; +var __privateAdd = (obj, member, value) => { + if (member.has(obj)) + throw TypeError("Cannot add the same private member more than once"); + member instanceof WeakSet ? member.add(obj) : member.set(obj, value); +}; +var __privateSet = (obj, member, value, setter) => { + __accessCheck(obj, member, "write to private field"); + setter ? setter.call(obj, value) : member.set(obj, value); + return value; +}; +var _use_hashes, _dev, _script_needs_csp, _style_needs_csp, _directives, _script_src, _style_src; +function afterUpdate() { +} +const Root = (0, import_index_10ac95e2.c)(($$result, $$props, $$bindings, slots) => { + let { stores } = $$props; + let { page } = $$props; + let { components } = $$props; + let { props_0 = null } = $$props; + let { props_1 = null } = $$props; + let { props_2 = null } = $$props; + (0, import_index_10ac95e2.s)("__svelte__", stores); + afterUpdate(stores.page.notify); + if ($$props.stores === void 0 && $$bindings.stores && stores !== void 0) + $$bindings.stores(stores); + if ($$props.page === void 0 && $$bindings.page && page !== void 0) + $$bindings.page(page); + if ($$props.components === void 0 && $$bindings.components && components !== void 0) + $$bindings.components(components); + if ($$props.props_0 === void 0 && $$bindings.props_0 && props_0 !== void 0) + $$bindings.props_0(props_0); + if ($$props.props_1 === void 0 && $$bindings.props_1 && props_1 !== void 0) + $$bindings.props_1(props_1); + if ($$props.props_2 === void 0 && $$bindings.props_2 && props_2 !== void 0) + $$bindings.props_2(props_2); + { + stores.page.set(page); + } + return ` + + +${components[1] ? `${(0, import_index_10ac95e2.v)(components[0] || import_index_10ac95e2.m, "svelte:component").$$render($$result, Object.assign(props_0 || {}), {}, { + default: () => { + return `${components[2] ? `${(0, import_index_10ac95e2.v)(components[1] || import_index_10ac95e2.m, "svelte:component").$$render($$result, Object.assign(props_1 || {}), {}, { + default: () => { + return `${(0, import_index_10ac95e2.v)(components[2] || import_index_10ac95e2.m, "svelte:component").$$render($$result, Object.assign(props_2 || {}), {}, {})}`; + } + })}` : `${(0, import_index_10ac95e2.v)(components[1] || import_index_10ac95e2.m, "svelte:component").$$render($$result, Object.assign(props_1 || {}), {}, {})}`}`; + } + })}` : `${(0, import_index_10ac95e2.v)(components[0] || import_index_10ac95e2.m, "svelte:component").$$render($$result, Object.assign(props_0 || {}), {}, {})}`} + +${``}`; +}); +function to_headers(object) { + const headers = new Headers(); + if (object) { + for (const key2 in object) { + const value = object[key2]; + if (!value) + continue; + if (Array.isArray(value)) { + value.forEach((value2) => { + headers.append(key2, value2); + }); + } else { + headers.set(key2, value); + } + } + } + return headers; +} +function hash(value) { + let hash2 = 5381; + let i = value.length; + if (typeof value === "string") { + while (i) + hash2 = hash2 * 33 ^ value.charCodeAt(--i); + } else { + while (i) + hash2 = hash2 * 33 ^ value[--i]; + } + return (hash2 >>> 0).toString(36); +} +function lowercase_keys(obj) { + const clone = {}; + for (const key2 in obj) { + clone[key2.toLowerCase()] = obj[key2]; + } + return clone; +} +function decode_params(params) { + for (const key2 in params) { + params[key2] = params[key2].replace(/%23/g, "#").replace(/%3[Bb]/g, ";").replace(/%2[Cc]/g, ",").replace(/%2[Ff]/g, "/").replace(/%3[Ff]/g, "?").replace(/%3[Aa]/g, ":").replace(/%40/g, "@").replace(/%26/g, "&").replace(/%3[Dd]/g, "=").replace(/%2[Bb]/g, "+").replace(/%24/g, "$"); + } + return params; +} +function is_pojo(body) { + if (typeof body !== "object") + return false; + if (body) { + if (body instanceof Uint8Array) + return false; + if (body._readableState && typeof body.pipe === "function") + return false; + if (typeof ReadableStream !== "undefined" && body instanceof ReadableStream) + return false; + } + return true; +} +function normalize_request_method(event) { + const method = event.request.method.toLowerCase(); + return method === "delete" ? "del" : method; +} +function error(body) { + return new Response(body, { + status: 500 + }); +} +function is_string(s2) { + return typeof s2 === "string" || s2 instanceof String; +} +const text_types = /* @__PURE__ */ new Set([ + "application/xml", + "application/json", + "application/x-www-form-urlencoded", + "multipart/form-data" +]); +function is_text(content_type) { + if (!content_type) + return true; + const type = content_type.split(";")[0].toLowerCase(); + return type.startsWith("text/") || type.endsWith("+xml") || text_types.has(type); +} +async function render_endpoint(event, mod) { + const method = normalize_request_method(event); + let handler = mod[method]; + if (!handler && method === "head") { + handler = mod.get; + } + if (!handler) { + return event.request.headers.get("x-sveltekit-load") ? new Response(void 0, { + status: 204 + }) : new Response("Method not allowed", { + status: 405 + }); + } + const response = await handler(event); + const preface = `Invalid response from route ${event.url.pathname}`; + if (typeof response !== "object") { + return error(`${preface}: expected an object, got ${typeof response}`); + } + if (response.fallthrough) { + throw new Error("fallthrough is no longer supported. Use matchers instead: https://kit.svelte.dev/docs/routing#advanced-routing-matching"); + } + const { status = 200, body = {} } = response; + const headers = response.headers instanceof Headers ? new Headers(response.headers) : to_headers(response.headers); + const type = headers.get("content-type"); + if (!is_text(type) && !(body instanceof Uint8Array || is_string(body))) { + return error(`${preface}: body must be an instance of string or Uint8Array if content-type is not a supported textual content-type`); + } + let normalized_body; + if (is_pojo(body) && (!type || type.startsWith("application/json"))) { + headers.set("content-type", "application/json; charset=utf-8"); + normalized_body = JSON.stringify(body); + } else { + normalized_body = body; + } + if ((typeof normalized_body === "string" || normalized_body instanceof Uint8Array) && !headers.has("etag")) { + const cache_control = headers.get("cache-control"); + if (!cache_control || !/(no-store|immutable)/.test(cache_control)) { + headers.set("etag", `"${hash(normalized_body)}"`); + } + } + return new Response(method !== "head" ? normalized_body : void 0, { + status, + headers + }); +} +var chars$1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ_$"; +var unsafeChars = /[<>\b\f\n\r\t\0\u2028\u2029]/g; +var reserved = /^(?:do|if|in|for|int|let|new|try|var|byte|case|char|else|enum|goto|long|this|void|with|await|break|catch|class|const|final|float|short|super|throw|while|yield|delete|double|export|import|native|return|switch|throws|typeof|boolean|default|extends|finally|package|private|abstract|continue|debugger|function|volatile|interface|protected|transient|implements|instanceof|synchronized)$/; +var escaped = { + "<": "\\u003C", + ">": "\\u003E", + "/": "\\u002F", + "\\": "\\\\", + "\b": "\\b", + "\f": "\\f", + "\n": "\\n", + "\r": "\\r", + " ": "\\t", + "\0": "\\0", + "\u2028": "\\u2028", + "\u2029": "\\u2029" +}; +var objectProtoOwnPropertyNames = Object.getOwnPropertyNames(Object.prototype).sort().join("\0"); +function devalue(value) { + var counts = /* @__PURE__ */ new Map(); + function walk(thing) { + if (typeof thing === "function") { + throw new Error("Cannot stringify a function"); + } + if (counts.has(thing)) { + counts.set(thing, counts.get(thing) + 1); + return; + } + counts.set(thing, 1); + if (!isPrimitive(thing)) { + var type = getType(thing); + switch (type) { + case "Number": + case "String": + case "Boolean": + case "Date": + case "RegExp": + return; + case "Array": + thing.forEach(walk); + break; + case "Set": + case "Map": + Array.from(thing).forEach(walk); + break; + default: + var proto = Object.getPrototypeOf(thing); + if (proto !== Object.prototype && proto !== null && Object.getOwnPropertyNames(proto).sort().join("\0") !== objectProtoOwnPropertyNames) { + throw new Error("Cannot stringify arbitrary non-POJOs"); + } + if (Object.getOwnPropertySymbols(thing).length > 0) { + throw new Error("Cannot stringify POJOs with symbolic keys"); + } + Object.keys(thing).forEach(function(key2) { + return walk(thing[key2]); + }); + } + } + } + walk(value); + var names = /* @__PURE__ */ new Map(); + Array.from(counts).filter(function(entry) { + return entry[1] > 1; + }).sort(function(a, b) { + return b[1] - a[1]; + }).forEach(function(entry, i) { + names.set(entry[0], getName(i)); + }); + function stringify(thing) { + if (names.has(thing)) { + return names.get(thing); + } + if (isPrimitive(thing)) { + return stringifyPrimitive(thing); + } + var type = getType(thing); + switch (type) { + case "Number": + case "String": + case "Boolean": + return "Object(" + stringify(thing.valueOf()) + ")"; + case "RegExp": + return "new RegExp(" + stringifyString(thing.source) + ', "' + thing.flags + '")'; + case "Date": + return "new Date(" + thing.getTime() + ")"; + case "Array": + var members = thing.map(function(v, i) { + return i in thing ? stringify(v) : ""; + }); + var tail = thing.length === 0 || thing.length - 1 in thing ? "" : ","; + return "[" + members.join(",") + tail + "]"; + case "Set": + case "Map": + return "new " + type + "([" + Array.from(thing).map(stringify).join(",") + "])"; + default: + var obj = "{" + Object.keys(thing).map(function(key2) { + return safeKey(key2) + ":" + stringify(thing[key2]); + }).join(",") + "}"; + var proto = Object.getPrototypeOf(thing); + if (proto === null) { + return Object.keys(thing).length > 0 ? "Object.assign(Object.create(null)," + obj + ")" : "Object.create(null)"; + } + return obj; + } + } + var str = stringify(value); + if (names.size) { + var params_1 = []; + var statements_1 = []; + var values_1 = []; + names.forEach(function(name, thing) { + params_1.push(name); + if (isPrimitive(thing)) { + values_1.push(stringifyPrimitive(thing)); + return; + } + var type = getType(thing); + switch (type) { + case "Number": + case "String": + case "Boolean": + values_1.push("Object(" + stringify(thing.valueOf()) + ")"); + break; + case "RegExp": + values_1.push(thing.toString()); + break; + case "Date": + values_1.push("new Date(" + thing.getTime() + ")"); + break; + case "Array": + values_1.push("Array(" + thing.length + ")"); + thing.forEach(function(v, i) { + statements_1.push(name + "[" + i + "]=" + stringify(v)); + }); + break; + case "Set": + values_1.push("new Set"); + statements_1.push(name + "." + Array.from(thing).map(function(v) { + return "add(" + stringify(v) + ")"; + }).join(".")); + break; + case "Map": + values_1.push("new Map"); + statements_1.push(name + "." + Array.from(thing).map(function(_a) { + var k = _a[0], v = _a[1]; + return "set(" + stringify(k) + ", " + stringify(v) + ")"; + }).join(".")); + break; + default: + values_1.push(Object.getPrototypeOf(thing) === null ? "Object.create(null)" : "{}"); + Object.keys(thing).forEach(function(key2) { + statements_1.push("" + name + safeProp(key2) + "=" + stringify(thing[key2])); + }); + } + }); + statements_1.push("return " + str); + return "(function(" + params_1.join(",") + "){" + statements_1.join(";") + "}(" + values_1.join(",") + "))"; + } else { + return str; + } +} +function getName(num) { + var name = ""; + do { + name = chars$1[num % chars$1.length] + name; + num = ~~(num / chars$1.length) - 1; + } while (num >= 0); + return reserved.test(name) ? name + "_" : name; +} +function isPrimitive(thing) { + return Object(thing) !== thing; +} +function stringifyPrimitive(thing) { + if (typeof thing === "string") + return stringifyString(thing); + if (thing === void 0) + return "void 0"; + if (thing === 0 && 1 / thing < 0) + return "-0"; + var str = String(thing); + if (typeof thing === "number") + return str.replace(/^(-)?0\./, "$1."); + return str; +} +function getType(thing) { + return Object.prototype.toString.call(thing).slice(8, -1); +} +function escapeUnsafeChar(c) { + return escaped[c] || c; +} +function escapeUnsafeChars(str) { + return str.replace(unsafeChars, escapeUnsafeChar); +} +function safeKey(key2) { + return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key2) ? key2 : escapeUnsafeChars(JSON.stringify(key2)); +} +function safeProp(key2) { + return /^[_$a-zA-Z][_$a-zA-Z0-9]*$/.test(key2) ? "." + key2 : "[" + escapeUnsafeChars(JSON.stringify(key2)) + "]"; +} +function stringifyString(str) { + var result = '"'; + for (var i = 0; i < str.length; i += 1) { + var char = str.charAt(i); + var code = char.charCodeAt(0); + if (char === '"') { + result += '\\"'; + } else if (char in escaped) { + result += escaped[char]; + } else if (code >= 55296 && code <= 57343) { + var next = str.charCodeAt(i + 1); + if (code <= 56319 && (next >= 56320 && next <= 57343)) { + result += char + str[++i]; + } else { + result += "\\u" + code.toString(16).toUpperCase(); + } + } else { + result += char; + } + } + result += '"'; + return result; +} +function noop() { +} +function safe_not_equal(a, b) { + return a != a ? b == b : a !== b || (a && typeof a === "object" || typeof a === "function"); +} +Promise.resolve(); +const subscriber_queue = []; +function readable(value, start) { + return { + subscribe: writable(value, start).subscribe + }; +} +function writable(value, start = noop) { + let stop; + const subscribers = /* @__PURE__ */ new Set(); + function set(new_value) { + if (safe_not_equal(value, new_value)) { + value = new_value; + if (stop) { + const run_queue = !subscriber_queue.length; + for (const subscriber of subscribers) { + subscriber[1](); + subscriber_queue.push(subscriber, value); + } + if (run_queue) { + for (let i = 0; i < subscriber_queue.length; i += 2) { + subscriber_queue[i][0](subscriber_queue[i + 1]); + } + subscriber_queue.length = 0; + } + } + } + } + function update(fn) { + set(fn(value)); + } + function subscribe(run, invalidate = noop) { + const subscriber = [run, invalidate]; + subscribers.add(subscriber); + if (subscribers.size === 1) { + stop = start(set) || noop; + } + run(value); + return () => { + subscribers.delete(subscriber); + if (subscribers.size === 0) { + stop(); + stop = null; + } + }; + } + return { set, update, subscribe }; +} +function coalesce_to_error(err) { + return err instanceof Error || err && err.name && err.message ? err : new Error(JSON.stringify(err)); +} +const render_json_payload_script_dict = { + "<": "\\u003C", + "\u2028": "\\u2028", + "\u2029": "\\u2029" +}; +const render_json_payload_script_regex = new RegExp(`[${Object.keys(render_json_payload_script_dict).join("")}]`, "g"); +function render_json_payload_script(attrs, payload) { + const safe_payload = JSON.stringify(payload).replace(render_json_payload_script_regex, (match) => render_json_payload_script_dict[match]); + let safe_attrs = ""; + for (const [key2, value] of Object.entries(attrs)) { + if (value === void 0) + continue; + safe_attrs += ` sveltekit:data-${key2}=${escape_html_attr(value)}`; + } + return `