<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.3.3">Jekyll</generator><link href="/feed.xml" rel="self" type="application/atom+xml" /><link href="/" rel="alternate" type="text/html" /><updated>2024-04-29T19:22:25+00:00</updated><id>/feed.xml</id><title type="html">Thoughts, Rants and Epiphanies.</title><subtitle>thoughts and rants.</subtitle><entry><title type="html">on cobras and database schemas</title><link href="/2024/04/29/on_cobras_and_database_schemas.html" rel="alternate" type="text/html" title="on cobras and database schemas" /><published>2024-04-29T19:05:28+00:00</published><updated>2024-04-29T19:05:28+00:00</updated><id>/2024/04/29/on_cobras_and_database_schemas</id><content type="html" xml:base="/2024/04/29/on_cobras_and_database_schemas.html"><![CDATA[<p>Previously, I was at a company that had a large and somewhat problematic database.  Questionable design decisions and blatant hacks had piled up upon one another to the point where any schema change felt like the penultimate move of a Jenga game.</p>

<p>Despite this, many of the developers would haphazardly slap in a new column, table or index without a second thought. Other devs would willy-nilly deploy code with non-trivial schema migrations, bringing the whole tower crashing down. Hilarity ensued.</p>

<p>Mindful of this, and with a few awkward incidents still raw in his recent memory, our VP of engineering decreed that henceforth ALL schema changes shall be reviewed by an architecture committee.</p>

<p>Unfortunately, the committee took a lot of preparation, only met every other week and often would give you feedback and place additional requests on your proposed changes. Sometimes , they would even have valid reasons for the requests.</p>

<p>Developers are under the whip to make their burn-downs pretty and release features to meet their quarterly OKRs (both of these are rants for another time), and so they find ways to innovate around the blockage: instead of making schema changes, they re-purpose old database fields, stuff JSON into string columns, shove relational data into redis and S3 and do other unmentionable things.</p>

<p>Consequently the schema not only continued to get worse, but in fact got worse a lot more rapidly. More hilarity ensued, culminating in a memorable month where few of the senior engineers got any sleep, the system spent a lot of time choked under load and the cloud services bill was nothing short of spectacular.</p>

<p>Although the superficial form of this tale may be modern, the underlying problem is a classic.  For instance: During the British rule in India, some wise government official decided the cobras were bad, and offered a reward for dead cobras.  Naturally, local  entrepreneurs began breeding cobras for the purpose of killing them and selling the corpses to the Raj.  Good business! Sadly, the government found out about this and abolished the programme, boo! At which point, the entrepreneurs did what any sensible person would do, if they suddenly found themselves with a great oversupply of cobras - they simply set them free. Cobras everywhere!</p>

<p><a href="https://en.wikipedia.org/wiki/Perverse_incentive">There are other, equally amusing examples of this same pattern, well worth the read.</a></p>

<p>Humans are wily, ingenious creatures!</p>

<p>Management is hard!</p>

<p>What can we do?</p>

<p>Well…</p>

<p>Back in my undergraduate years, I learned about the three body problem. I’m talking about the physical model, not the book, although the book is brilliant and should definitely be on your reading list.</p>

<p>Now what makes the three body problem interesting is that (as with system in a chaotic realm) a tiny perturbation will cause the behaviour of the system to <a href="https://en.wikipedia.org/wiki/Lyapunov_exponent">diverge exponentially</a> and unpredictably from it’s current path.  Weather has similar properties, which is apparently why we study butterflies so carefully.</p>

<p>There is a large body of evidence to suggest that groups of humans attempting to collaborate exhibit the same phenomenon: a seemingly tiny change in the boundary conditions will result in large and unpredictable changes in the system behaviour.  And so the principles that I learned from sleepless nights of trying to debug simulations of chaotic systems seem useful to apply:</p>

<ul>
  <li>Make changes one at a time, so that you can observe their effects in isolation.</li>
  <li>Monitor the effect of every change that you introduce carefully and at a high sampling rate.</li>
  <li>Ensure that you are measuring the right thing.  In the case of cobras, the number of cobras seen in the wild may be a better yardstick than the number of dead cobras in the garbage. In the case of the sick database, the number of architecture reports is not a good indicator of progress. APM statistics and database CPU usage would be more useful.</li>
</ul>]]></content><author><name></name></author><summary type="html"><![CDATA[Previously, I was at a company that had a large and somewhat problematic database. Questionable design decisions and blatant hacks had piled up upon one another to the point where any schema change felt like the penultimate move of a Jenga game.]]></summary></entry><entry><title type="html">Xcode devs: try this one wierd trick to reclaim osx diskspace</title><link href="/notes_to_future_self/2024/04/10/one_wierd_trick_to_reclaim_osx_diskspace.html" rel="alternate" type="text/html" title="Xcode devs: try this one wierd trick to reclaim osx diskspace" /><published>2024-04-10T05:27:09+00:00</published><updated>2024-04-10T05:27:09+00:00</updated><id>/notes_to_future_self/2024/04/10/one_wierd_trick_to_reclaim_osx_diskspace</id><content type="html" xml:base="/notes_to_future_self/2024/04/10/one_wierd_trick_to_reclaim_osx_diskspace.html"><![CDATA[<p>Started running low on disk space recently. Did some <code class="language-plaintext highlighter-rouge">du -sh *</code> around my volumes and came across this delight:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>~ du -sh ~/Library/Developer/Xcode/iOS\ DeviceSupport/*
5.0G	15.7.5 (19H332)
5.0G	15.7.6 (19H349)
  0B	15.7.7 (19H349)
5.0G	15.7.7 (19H357)
  0B	15.7.8 (19H357)
5.0G	15.7.8 (19H364)
  0B	15.7.9 (19H364)
648K	15.7.9 (19H365)
  0B	15.8 (19H365)
5.0G	15.8 (19H370)
6.3G	16.6.1 (20G81) arm64e
3.6G	iPhone14,6 17.3.1 (21D61)
</code></pre></div></div>

<p>Turns out, that every time you run an Xcode project on a device, Xcode helpfully downloads debug symbols from the device. So every iOS upgrade on my dev device was creating a 5GB “cache” that just hangs around forever.</p>

<p><a href="https://stackoverflow.com/a/40327522">You can safely delete everything here</a> as well as a few others. I freed up more than 40GB in a few seconds.</p>

<p>If you’re still using one of those caches it’s going to cost you a few seconds next time to debug on that device, so you can be a little bit selective.</p>]]></content><author><name></name></author><category term="notes_to_future_self" /><summary type="html"><![CDATA[Started running low on disk space recently. Did some du -sh * around my volumes and came across this delight:]]></summary></entry><entry><title type="html">Don’t infer intent</title><link href="/posts/2024/03/27/dont_infer_intent.html" rel="alternate" type="text/html" title="Don’t infer intent" /><published>2024-03-27T19:40:36+00:00</published><updated>2024-03-27T19:40:36+00:00</updated><id>/posts/2024/03/27/dont_infer_intent</id><content type="html" xml:base="/posts/2024/03/27/dont_infer_intent.html"><![CDATA[<p>We live our lives in states of highly imperfect information.  We try to make sense of what we observe to be happening around us by relying on a <a href="https://en.wikipedia.org/wiki/Evolution_of_the_eye">series of biological hacks</a> to turn stimuli into electrical impulses. This is flawed in numerous and interesting ways.</p>

<p>A large part of what we observe revolves around the actions and words of the people around us. And based on what we observe, we react.  But we don’t react directly to the observation. Instead we build a mental model of the emotional and mental state of the person when they said or did the thing.  We infer their intent.</p>

<p>So a typical interaction looks a bit like this:</p>

<ol>
  <li>You have an intention (A)</li>
  <li>You say or do something based on this intention</li>
  <li>I see you say or do that thing</li>
  <li>I filter this observation through my own special set of biases and preconceptions.</li>
  <li>Based on what remains, I construct an interpretation of your intent (B)</li>
  <li>I react to  my interpretation of your intent.</li>
  <li>Hilarity ensues</li>
</ol>

<p>My reaction to your action is based on my own construction, rather than what you actually meant.  And the world is a worse place.</p>

<p>There are some heuristics that I find useful to alleviate this issue:</p>

<p>The first is from a former manager, who was fond of saying “MRI - most respectful interpretation”. Accept that what you observe is ambiguous and consciously choose the meaning that puts the other person in the best possible light.</p>

<p>The second is from <a href="https://www.youtube.com/watch?v=3S16b-x5mRA">one of my favourite film scenes of all time</a>: As the man with the moustache points out, <strong>be curious, not judgemental</strong>.  Ask “what did you mean when you said that?” or “why did you do that?” and listen carefully to the answer.</p>

<p>And finally, <a href="https://www.tiktok.com/@motivationstop19/video/7214070475914431790?lang=en">choose discomfort over resentment</a>. Now I know the context of the video was slightly different, but bear with me.  When someone says something that you don’t like, it’s often easy to just brush over it and walk away resentful. Instead, front-load your pain and ask or tell them: “hey, when you said that thing, it made me cranky, what gives?”.</p>

<p>Also: Shut the fuck up and listen. You have one mouth and two ears for good reason.</p>]]></content><author><name></name></author><category term="posts" /><summary type="html"><![CDATA[We live our lives in states of highly imperfect information.  We try to make sense of what we observe to be happening around us by relying on a series of biological hacks to turn stimuli into electrical impulses. This is flawed in numerous and interesting ways.]]></summary></entry><entry><title type="html">The elves are leaving an immoral maze</title><link href="/rants/2024/03/21/the_elves_are_leaving.html" rel="alternate" type="text/html" title="The elves are leaving an immoral maze" /><published>2024-03-21T13:46:48+00:00</published><updated>2024-03-21T13:46:48+00:00</updated><id>/rants/2024/03/21/the_elves_are_leaving</id><content type="html" xml:base="/rants/2024/03/21/the_elves_are_leaving.html"><![CDATA[<p>Steve Blank wrote <a href="https://steveblank.com/2009/12/21/the-elves-leave-middle-earth-%E2%80%93-soda%E2%80%99s-are-no-longer-free/">a brilliant essay</a> way back in 2009 about the metamorphoses that companies undergo as they grow.  I’m not sure if it’s entirely attributable to this article, but the idea of free food has completely ingrained itself in our cultural zeitgeist to the point where every job ad for every aspiring scale-up boasts about how they spend their VC money on keeping the fridges well-stocked with artisanal blueberries.</p>

<p>For fuck sakes. Do you not understand the idea of a metaphor?</p>

<p>Paying for soft drinks is not the reason why people leave a job.  I know that it’s convenient to pretend that software engineers are just a bunch of childlike savants, but we’re not completely stupid. We are, in fact, able to perform the long division required to calculate how many cold drinks you can buy for a million rand, or whatever the median software engineering salary is these days.</p>

<p>The real reason why people leave jobs is because the change in the cold drink situation is a bellwether for a more general enshittification that sometimes sets in as a company grows.</p>

<p>This change is a hydra:  <a href="http://wovenminutia.blogspot.com/2010/06/carroll-quigley-and-institutions.html">Instruments become institutions</a>. Politics<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup> becomes a reality of everyday life. Organisational sclerosis sets in, precipitated by a <a href="https://www.slideshare.net/reed2001/culture-1798664">cambrian explosion of process and procedure</a>. Meetings multiply without bounds. Slowly and then suddenly, you’re working in an <a href="https://thezvi.wordpress.com/2020/01/12/how-to-identify-an-immoral-maze/">immoral maze</a>.</p>

<blockquote>
  <p>a toxic organisation which puts tremendous pressure on you to prioritize getting ahead in the organization over everything else</p>
</blockquote>

<p>The consensus seems to be that this is the <a href="https://slatestarcodex.com/2014/07/30/meditations-on-moloch/">inevitable consequence</a> of growing an organisation, that every successful business will gravitate to this unhappiness as it falls victim to its own success.</p>

<p>This is generally true, but not necessarily. And whether it happens is entirely dependent on the morality of the individuals in your team.</p>

<blockquote>
  <p>Moloch always and everywhere offers the same deal: throw what you love most into the flames, and I can grant you power.</p>
</blockquote>

<p>Although everyone finds Moloch’s deal tempting, some people will resist it while others will grab at it with both hands.  And that latter group is not only going to be extremely attracted to the immoral maze, they will very actively work to deepen it.</p>

<p>It is exactly these people who trigger the rapid collapse of the kind of environment where the elves want to work.</p>

<p>Consequently these people have a useful function in the world: they act as signals for toxic culture. Never mind looking at org structure, incentives, skin or soul in the game or other signs of a toxic organisation. Just look for this kind of person.</p>

<p>Handily, they have a few common traits that make them easy to spot:</p>

<ol>
  <li><strong>Referring to humans as “resources”</strong> - these people appear to have a Dunbar’s number of approximately 0, so everyone around them is just something to be manipulated to maximise personal gains</li>
  <li><strong>Bragging about the number of their reports</strong> Using an internally focused yardstick of success rather than value created.</li>
  <li><strong>Name-dropping about who they report to or how the CxO knows who they are</strong> - because they are focused on an internal zero sum game, their currency is internal recognition.</li>
  <li><strong>Insisting on being invited to meetings where they have nothing to contribute</strong> while humble-bragging about how many meetings they need to attend. Every meeting is an opportunity to display their influence, even if only by sitting in it with their camera off.</li>
  <li><strong>Empire building</strong> - they look for any excuse to increase the head-count they have under them, or entrench their unit or department into seemingly unrelated functions.  Efficient solutions to business problems are shunned because these detract from the opportunity to hire more “resources”.</li>
  <li><strong>Avoiding creative work</strong> - creative work generally implies the possibility of failure. These people will avoid getting into those situations at all costs, so the way that they phrase their output is necessarily going to revolve around completion of tasks, attendance of meetings or busywork (Jira subtasks for the win).</li>
  <li><strong>Almost inevitably, they gravitate to middle-management positions</strong>, where they are comfortably insulated against the intolerable hardships of either having skin in the game or dealing with object-level reality.</li>
</ol>

<p>Avoiding the maze is as simple as detecting and avoiding or removing these people.   If you are in a position to fire them, do it before they entrench themselves. If you meet them when you’re interviewing at a company, bolt. If you interview them, submit a hard no. If they start multiplying in your company like maggots, and you’re not in a position to clean them out, update your resume.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>The most apt definition I have heard for politics is “Saying something because of how you think people will react, rather than based on what you believe to be true”. I wish I could remember where I heard this. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name></name></author><category term="rants" /><summary type="html"><![CDATA[Steve Blank wrote a brilliant essay way back in 2009 about the metamorphoses that companies undergo as they grow. I’m not sure if it’s entirely attributable to this article, but the idea of free food has completely ingrained itself in our cultural zeitgeist to the point where every job ad for every aspiring scale-up boasts about how they spend their VC money on keeping the fridges well-stocked with artisanal blueberries.]]></summary></entry><entry><title type="html">Don’t build it (yet)</title><link href="/ramblings/2024/03/14/dont_build_it.html" rel="alternate" type="text/html" title="Don’t build it (yet)" /><published>2024-03-14T11:18:39+00:00</published><updated>2024-03-14T11:18:39+00:00</updated><id>/ramblings/2024/03/14/dont_build_it</id><content type="html" xml:base="/ramblings/2024/03/14/dont_build_it.html"><![CDATA[<p>As someone who nominally earns the majority of their income from writing code and building software, I spend an alarming amount of time telling people not to build software and/or not ask me to build software for them.</p>

<p>To my detriment, I encourage people to use google docs, Zapier, sticky notes, a telephone, interns or in fact just about anything that doesn’t involve writing code of any form. Failing that, I typically encourage them to build <a href="https://www.outseta.com/posts/growth-by-elimination">less</a>, <a href="https://moxie.org/2012/11/27/the-worst.html">worse</a> software and build it faster.</p>

<p>Some of this may be related to the idea of <a href="https://paulgraham.com/ds.html">doing things that don’t scale</a>, and some of this is just me being a luddite.  And some of this is related to the idea that often the building of things is one of the more predictable part of creating a business.  But all of those factors combined still don’t fully explain my reluctance to build things and get money for doing so.</p>

<p>So why do I spend so much time telling people not to pay me money to build things for them?</p>

<p>The typical “person-with-idea” that asks me to build something for them, has a picture in their head of how using their idea to serve customers will translate into money.  They have a view on what the end state will look like where this autonomous “product” is making money for them like a sort of Rube Goldberg machine (no disrespect to them, any new business is going to have spit and baling wire holding it together).</p>

<p><img src="/assets/images/rube.gif" alt="image" /></p>

<p>In the mind of person-with-idea, there is generally an even spread of complexity and risk throughout the implementation of this machine: the difficulty of assembling each component is roughly equivalent to that of every other component, so the logical approach is to work from right to left, or in parallel and assemble the whole damn thing before you fire it up.</p>

<p>Christopher Hitchens said something along the lines of: “the job of a public intellectual is to say that I think you’ll find its a bit more complicated than that”. I’m not an intellectual, and certainly not a public one.  But the more general case of this statement seems to be that the role of any <a href="https://www.youtube.com/watch?v=BKorP55Aqvg">expert</a> in any situation is to say that “I think you’ll find it’s a bit more complicated than that”.</p>

<p>So we look closer, and with more nuance, and we find that the different parts of the machine have vastly different attributes: some are simple steel cogs while others are Penrose stairs made of unobtainium.  Randall Munroe once <a href="https://xkcd.com/1425/">pointed out</a> how hard these two are to distinguish. <sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></p>

<p>Being able to distinguish these differences up-front makes for a completely different approach to machine-building. “Well, if we can replace this vintage bird-cage with a simple weight, then it makes it so much cheaper to build, so let’s try that first and see if it works”.</p>

<p>And so a few years of tinkering with different technologies starts to add value: you develop a set of heuristics and patterns that give you quick estimates on viability, feasibility and potential tradeoffs: where will things break, how quickly could we build something to replace a manual process, and what are the main areas of risk.</p>

<p>Most often this results in the conclusion that “all this is going to be reasonably easy (if tedious and costly) to build, just start by testing the value proposition with a google form and then we can build it later”.</p>

<p>Sometimes it results in the conclusion that “this is not possible on current hardware, unless P=NP”.</p>

<p>Very, very infrequently, it results in the conclusion that “hmm, it would be pretty hard to build that, but if we did <a href="https://bitcoin.org/bitcoin.pdf">it could be interesting</a>”.</p>

<p>If it was uniformly true that “the tech is the easy part”, then life would be much simpler.  Unfortunately, the tech is the easy part, unless it’s the hard part or the impossible part. And it’s important to <a href="https://www.reddit.com/r/Jokes/comments/zsmy4/knowing_the_difference/">be able to tell the difference</a>.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>It occurred to me that this cartoon suddenly aged dramatically in the past couple of years. Well, the specifics did, but the principle is still standing tall. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name></name></author><category term="ramblings" /><summary type="html"><![CDATA[As someone who nominally earns the majority of their income from writing code and building software, I spend an alarming amount of time telling people not to build software and/or not ask me to build software for them.]]></summary></entry><entry><title type="html">The Mind is a Wild Elephant</title><link href="/notes/2024/03/09/the_mind_is_a_wild_elephant.html" rel="alternate" type="text/html" title="The Mind is a Wild Elephant" /><published>2024-03-09T11:18:39+00:00</published><updated>2024-03-09T11:18:39+00:00</updated><id>/notes/2024/03/09/the_mind_is_a_wild_elephant</id><content type="html" xml:base="/notes/2024/03/09/the_mind_is_a_wild_elephant.html"><![CDATA[<p>Recently, I went on a <a href="https://pataka.dhamma.africa/course-information/">10-day Vipassana course</a>. My reasons for going we re complex and out of scope for this post. Likewise, the personal outcomes and the details of the journey are for another time and post.  This post is really just to focus on some of the more mundane and practical aspects of the course, because there were a few things that I wish I had known or thought about before going.</p>

<h2 id="dont-panic">Don’t panic</h2>

<p>As it got closer to the start of the course, I found myself worrying about it quite a lot. This was entirely unnecessary. Yes, the course isn’t easy and it’s not something to be taken too lightly, but there is no way to “fail” at it, other than to decide to quit.  So although it’s going to be challenging, there is absolutely nothing that’s going to prevent you from completing the course, unless you decide to stop.</p>

<p>Some of the worrying things that a few people mentioned to me beforehand are:</p>

<ul>
  <li>Pain and discomfort</li>
  <li>Food</li>
  <li>Sleep</li>
  <li>Not being able to exercise</li>
</ul>

<h3 id="physical-discomfort">Physical Discomfort</h3>
<p>Yes, at times things are going to get uncomfortable, both physically and mentally.  That seems obvious.  But the intent of the course is not at all to be torture of any form and this is emphasised repeatedly.  If you manage your mind and body with a degree of common sense, the discomfort is minimal. I’ll talk about that management a bit later on.  One thing that I can say without hesitation is that any discomfort that I had was totally self-inflicted. There is never any real pressure to do anything that you don’t want to.</p>

<h3 id="food">Food</h3>
<p>For some reason, a few people I know seemed to be worried about whether they would get enough to eat. My experience was that the food was simply delicious, and there was more than enough of it. The meal schedule was different from what I’m used to, but I didn’t ever feel hungry (other than the 10 minutes before meals) or deprived.  It’s incredible how quickly your body gets used to eating at a specific time.</p>

<h3 id="sleep">Sleep</h3>
<p>When I looked at the schedule beforehand, I worried a bit about the early mornings and relatively late nights - it looks as though you might end up sleep deprived.  I found quite the opposite: in the absence of stress and with all the time spent quietly relaxing, my sleep needs dropped dramatically, and I was always awake a few minutes before the morning wakeup call. In fact, I think the end of the course was the most rested that I’ve been in years</p>

<h3 id="exercise">Exercise</h3>
<p>I’ve had a number of people say they could not go so long without exercise. And this was one of my biggest concerns too - I’m deeply dependent on exercise to manage my stress and overall mood.  Turns out this was a lot less of an issue than I thought it would be: when I have no stress and spend most of my day in quiet contemplation then the need to go out and sweat is massively reduced.  You’re also going to walk a lot more than you think you will - it’s a few hundred meters from the meditation hall to your room, and a few more hundred meters from your room to the dining hall and you will make these trips multiple times per day. I generally took roundabout routes, and sometimes walked a few laps and this seemed to be more than enough exercise to sustain me.  In fact, it felt as though I had not even lost much fitness at the end of the 10 days.</p>

<h2 id="but-be-prepared">But Be Prepared</h2>

<p>Although you don’t need to panic, there seem to be a few things that you can do to get more out of the experience, and make it a more pleasant experience overall.</p>

<h3 id="meditate">Meditate</h3>
<p>I’d been meditating on and off for some time before going on the course, and I think I found this helpful: my brain was already somewhat accustomed to sit quietly and behave itself by the time I started, so I just needed to dial up the intensity and duration of my practice. Anecdotally (from speaking to a few people who did the course with me as well as a few others I know), it seems that the people who had some experience with meditation both had an easier time on the course, and also seemed to get more out of it (probably those two aspects are related). So in the weeks leading up to the course, try to find 10 or 15 minutes a day to practice if you can. I’m specifically thinking of unguided, silent meditation - I’m not sure how helpful the Headspace/Calm type guided meditations are going to be to prepare yourself.</p>

<h3 id="sit">Sit</h3>
<p>Sitting for 10 hours a day is unusual and anything you can do to help your body prepare will be useful. Obviously, if you’re meditating already then you’re also sitting and helping your body to prepare. But either way, working on finding a comfortable position, understanding what cushions or props you need to get comfortable and getting used to sitting up straight but relaxed will definitely help.</p>

<h3 id="stretch-and-roll">Stretch and roll</h3>

<p>It’s useful to get rid of as many aches and pains as you can before you start. I didn’t, but what saved me was doing three sessions a day of about 20 minutes each of stretching, rolling and self-massage during the course.</p>

<h3 id="make-a-list">Make a list</h3>
<p>I had a lot of things that I needed to wrap up and put in place before going, and I found it really useful to make a list and tick everything off. Once I got to the course, knowing that I had ticked off everything on my list was definitely comforting - otherwise I would have probably spent considerably energy either worrying about what I might have forgotten or forcing myself not to worry.</p>

<h2 id="some-things-to-take">Some things to take</h2>
<p>In addition to what was on the packing list, I was either glad I had packed, or wished I had packed the following:</p>

<ul>
  <li>Anything you need to sit on. I took along my old memory-foam cushion and it was a life-saver. There are lots of cushions available, and you can even sit on a chair if you need to, but it can take some time to find the right thing, so doing it before you’re there is helpful.</li>
  <li>A water bottle.</li>
  <li>At least 2 sets of long, comfortable pants. You’re basically not going to be able to wear anything else, except when you’re alone in your room, so bring pants that you’re happy to wear all day, every day.</li>
  <li>A cake of laundry soap. There is a basin where you can hand-wash your clothes.</li>
  <li>Bedding (pillow, single fitted sheet, duvet). There is some available but it’s not great. I took a sleeping bag, but sleeping in a sleeping bag for 10 nights isn’t ideal, especially if it’s warm.</li>
  <li>Bug spray: There were some mozzies and it was warm, so being able to sleep with the window open was a huge benefit.  I think a mozzie net would have been good, but I can’t remember that there was anywhere in the bedroom where you would be able to hang it up</li>
  <li>A clock: You can’t and don’t want to wear a watch, but it’s often useful to know what time it is when you’re in your room. There is a gong or a bell whenever you need to be somewhere often it’s useful to know if (for example) you have time to take a shower before the gong.</li>
  <li>Yoga mat, foam roller, thera-cane, massage ball, so that you can help your body to recover after sitting for so long.</li>
  <li>Anti-inflammatories: If you get back or neck pain, you will be happy you brought them.</li>
  <li>Aspirin: Trying to meditate with a headache isn’t fun</li>
  <li>Broad-brim hat / sunscreen / umbrella. You’re going to be outside and in the sun or rain quite a lot so one of these is going to be a life saver (depending on the weather).</li>
  <li>Spare flip-flops.  My flip-flops broke on the last day. Luckily I was able to repair them well enough to get through the last day, but if I had not and this had happened early on, it would have been a real pain in the … feet.  Personally, I would not want to wear closed shoes - you’re going to be putting them on and taking them off about 10 times a day.</li>
</ul>

<h2 id="at-the-course">At the Course</h2>

<h3 id="stretch-and-roll-1">Stretch and roll</h3>

<p>I mentioned this earlier, but I think it’s worth repeating. I spent 20 minutes stretching, rolling and self-massaging three times a day. I’m generally prone to back and neck pain, so I was pretty worried about the effect of sitting so much. I think this routine saved me a lot of discomfort over the course - I was one of the few people who didn’t have much back or neck pain.  I also think that it helped me to sit more comfortably and for longer periods.</p>

<h3 id="appreciate-the-place">Appreciate the place</h3>

<p>The courses are generally held in beautiful, peaceful places, certainly the Worcester venue where I was, was spectacular. I found it really helpful to take time to appreciate the surroundings every day. I think it helped me to relax and be happy and to appreciate the opportunity that I had to be there. Some people say that this is a distraction from the meditation, you’ll have to make up your own mind about that.</p>

<h2 id="other-notes">Other Notes</h2>

<ul>
  <li>I had a pretty bad dopamine withdrawal on the 2nd day.  Or at least that’s how I can best explain the restlessness and anxiety I experienced on that day - a sense that I should be doing something or that there was something I needed to attend to.  My list helped a lot for this. Once I realised that the feeling was very likely because I had gone 2 days without my usual dopamine triggers (email, social media, etc), it was easier to manage. Apparently many people have a hard time around day 4 or 5, I didn’t have this as much.</li>
  <li>Some days were easy, some days were quite tough. On these days I found it best to adopt a “just keep swimming” approach - taking things one meditation at a time. At one point I had to tell myself that “if you get through the next meditation and still want to quit, you can”. Got through the next meditation, didn’t want to quit any more.</li>
  <li>Your car is going to be standing in the sun for 10 days. Take a sunshade and think about disconnecting the battery if you can. And don’t leave anything in the car that you don’t want to be slow-cooked.</li>
  <li>This was one of the most interesting and meaningful experiences in my life. I’m quite sorry that I didn’t do it sooner, and I have a strong determination to go again as life allows.  I hope that this post is helpful to someone who is considering going on a course.  If you have any questions, feel free to drop me a mail. I’ll do my best to help.</li>
</ul>]]></content><author><name></name></author><category term="notes" /><summary type="html"><![CDATA[Recently, I went on a 10-day Vipassana course. My reasons for going we re complex and out of scope for this post. Likewise, the personal outcomes and the details of the journey are for another time and post. This post is really just to focus on some of the more mundane and practical aspects of the course, because there were a few things that I wish I had known or thought about before going.]]></summary></entry><entry><title type="html">The power of constraints</title><link href="/2024/02/29/the_power_of_constraints.html" rel="alternate" type="text/html" title="The power of constraints" /><published>2024-02-29T11:55:50+00:00</published><updated>2024-02-29T11:55:50+00:00</updated><id>/2024/02/29/the_power_of_constraints</id><content type="html" xml:base="/2024/02/29/the_power_of_constraints.html"><![CDATA[<p>In <a href="https://www.amazon.com/Beautiful-Constraint-Transform-Limitations-Advantages/dp/B08DG8DK9Q">A Beautiful Constraint</a>, the authors make a compelling case that constraints can be a source of creativity and innovation. In my case, very tight constraints were the only thing that got me to finally publish a blog.</p>

<p>I’ve had many false starts on this. Mostly, I have an idea for something that I want to write, or a notion that I really should be blogging, or I take a look at the list of my notes and feel like I should really start turning some of these into long-form content.</p>

<p>And then I go down the rabbit hole of thinking about what the ideal blog setup would be. I start researching different frameworks and templates, different hosting providers, what would be a great code formatter.  Eventually the analysis paralysis bogs me down to the point where I give up, or need to go do real work.</p>

<p>I could just give up and use Medium, but ultimately <a href="https://startafuckingblog.com/">I want to own my content</a>, I believe in open platforms and communities and I think the world has lost a great deal by moving to a <a href="https://www.theverge.com/23513418/bring-back-personal-blogging">small number of walled gardens and platforms</a>.</p>

<p>This last time, I had a very hard deadline. I had promised the Powersync team that I would finish up the damn blog post this month, I had a ton of other work to do and I could simply not afford to bugger around.  So, I gave myself 2 hours to get something live. And resolved that if I didn’t have a blog post up by then, I would just use Medium. Which would make me sad.</p>

<p>The process then went like this:</p>

<ol>
  <li>Identify the tool to use (Jekyll) by googling “best static site generator 2024” and going with the recommendation of a random Hacker News commenter that “<a href="https://news.ycombinator.com/item?id=20797170">if you like ruby, use Jekyll</a>”. Also, the name is familiar, and I have actually used it before back in the distant past.</li>
  <li><del>Find a template</del> Fuckit, just use the Jekyll default, spend 10 minutes figuring out how to edit the basic layour to get rid of cruft I don’t want.</li>
  <li>Host it on the easiest platform I can find. Achieved this by running <code class="language-plaintext highlighter-rouge">jekyll new</code> and trying to deploy the result.  Github pages failed, because it had issues with the newer Jekyll versions and didn’t serve the assets correctly. Vercel failed in some obscure way, and I didn’t have time to debug it.  Netlify worked first time.</li>
</ol>

<p>After about 90 minutes, i had a blog. Yay me. I could spend the last half hour tweaking content and still make my self-imposed cutoff.</p>

<p>And wierdly, I’m now 3 posts deep a few days later o_O - let’s see if it sticks.  But due to the complete absence of friction (write, <code class="language-plaintext highlighter-rouge">git commit &amp;&amp; git push</code>, done), and the fact that <a href="https://kadavy.net/blog/posts/permission-to-suck/">my blog kinda sucks</a>, I don’t feel too pained about putting up sub-standard content. This is incredibly liberating.</p>

<p>My main self-indulgence has been to spend 20 minutes crafting <a href="https://github.com/ckritzinger/intuitably/blob/master/new_post.sh">a bash script that generates a new post</a> for me. Why Jekyll doesn’t do this out of the box is truly a mystery.</p>

<p>Why did this work so well? Maybe because I’m lazy and have no grit.</p>

<p>The other plausible explanation is that the constraints themselves made it feasible. Their reframing of constraints into the form “I can do $GOAL if $SHORTCUT” is a powerful one. In my case “I can get a blog up if I don’t care what it looks like and I just take the easiest possible approach” worked like a charm. Maybe one day I’ll even pick a nicer template.</p>]]></content><author><name></name></author><summary type="html"><![CDATA[In A Beautiful Constraint, the authors make a compelling case that constraints can be a source of creativity and innovation. In my case, very tight constraints were the only thing that got me to finally publish a blog.]]></summary></entry><entry><title type="html">Apple, export regulations and toil</title><link href="/epiphanies/2024/02/28/encryption.html" rel="alternate" type="text/html" title="Apple, export regulations and toil" /><published>2024-02-28T11:10:12+00:00</published><updated>2024-02-28T11:10:12+00:00</updated><id>/epiphanies/2024/02/28/encryption</id><content type="html" xml:base="/epiphanies/2024/02/28/encryption.html"><![CDATA[<p>In my early forays into app store submissions, I found myself clicking through the same “Provide Export Compliance” questions every time I uploaded a new build.</p>

<p>According to Apple:</p>

<blockquote>
  <p>When you submit your app to TestFlight or the App Store, you upload your app to a server in the United States. If you distribute your app outside the U.S. or Canada, your app is subject to U.S. export laws, regardless of where your legal entity is based. If your app uses, accesses, contains, implements, or incorporates encryption, this is considered an export of encryption software, which means your app is subject to U.S. export compliance requirements, as well as the import compliance requirements of the countries where you distribute your app.</p>
</blockquote>

<p>Are you wasting your life complying with <a href="https://en.wikipedia.org/wiki/Export_of_cryptography_from_the_United_States">cold-war era export regulations</a>?</p>

<p>There’s a two-line fix. Add the following to your <code class="language-plaintext highlighter-rouge">Info.plist</code>:</p>

<div class="language-xml highlighter-rouge"><div class="highlight"><pre class="highlight"><code>	<span class="nt">&lt;key&gt;</span>ITSAppUsesNonExemptEncryption<span class="nt">&lt;/key&gt;</span>
	<span class="nt">&lt;false/&gt;</span>
</code></pre></div></div>

<p>Go forth and toil a little bit less.</p>]]></content><author><name></name></author><category term="epiphanies" /><summary type="html"><![CDATA[In my early forays into app store submissions, I found myself clicking through the same “Provide Export Compliance” questions every time I uploaded a new build.]]></summary></entry><entry><title type="html">The real reason for an offline-first architecture: Developer Experience</title><link href="/epiphanies/2024/02/23/flutter.html" rel="alternate" type="text/html" title="The real reason for an offline-first architecture: Developer Experience" /><published>2024-02-23T11:10:12+00:00</published><updated>2024-02-23T11:10:12+00:00</updated><id>/epiphanies/2024/02/23/flutter</id><content type="html" xml:base="/epiphanies/2024/02/23/flutter.html"><![CDATA[<p>I’ve been curious about <a href="https://www.powersync.com/">PowerSync</a> for a while now, but after seeing it <a href="https://news.ycombinator.com/item?id=38473743">blow up on HackerNews</a> I had to try it. Moreso because it gave me the excuse to start on a side project that has been percolating in the back of my mind. You can see a full repo with my code (mobile and backend) <a href="https://github.com/ckritzinger/gotofun">here</a>.</p>

<p>The hype is true: once you have PowerSync running, it’s pretty darn magical. Run an INSERT or UPDATE and see the data instantly pop up in the front-end of your app.  Even more impressive is how little code you actually need to accomplish that magic.</p>

<p>But the thing that will make PowerSync my go-to tool in future was not the offline-first magic. It’s that PowerSync helps me to sidestep my two worst favourite Flutter pain points: state management and API integration.</p>

<p>Don’t get me wrong. Flutter is one of the nicest frameworks that I’ve worked with: The underlying language is solid and really well designed. The community is great. The UI code is declarative, but still just code, not an entirely new syntax (talking to you, JSX). And the batteries are mostly included, from flutter new to app store.</p>

<p>But there are two aspects of Flutter that grind my gears:</p>

<h2 id="state---the-final-frontier">State - the final frontier</h2>

<p>Flutter state management is an unsolved problem. Or perhaps unsolved is the wrong word: <a href="https://docs.flutter.dev/data-and-backend/state-mgmt/options">there are plenty of solutions</a>, but none of them are great.  So every Flutter dev I know has gone through a painful learning curve of:</p>

<ul>
  <li><code class="language-plaintext highlighter-rouge">setState</code> and callbacks</li>
  <li>Spaghetti hell</li>
  <li>Rewrite in bloc, because that’s what all the cool kids are using</li>
  <li>Boilerplate hell</li>
  <li>…</li>
  <li>More hell</li>
  <li>…</li>
  <li>Find some tolerable steady state</li>
</ul>

<p>For me, the steady state heavily relies on singletons that are <code class="language-plaintext highlighter-rouge">ChangeNotifier</code>s. It’s horrible, inefficient, and probably an indication that I’m a bad programmer. But, it seems to be the least worst solution for most of my use cases.</p>

<h2 id="hand-rolled-api-client-code">Hand-rolled API client code</h2>

<p>Not for lack of trying, but I’ve never managed to successfully generate a dart REST client from a swagger spec.  OK, actually I have, but the result was so much worse than my own boilerplate that I just threw it away.</p>

<p>GraphQL support seems to be a bit better, but still a hassle.</p>

<p>And so most people seem to use Dio (or the http package, if they have high pain thresholds) and a lot of boilerplate. Copilot may be great at helping you churn out this boilerplate. However, it’s not nearly as good at helping you maintain it. And as for fixing the inevitable, subtle bugs in the boilerplate, well…</p>

<h2 id="who-moved-my-setstate">Who moved my setState?</h2>

<p>So what does that rant have to do with offline-first architecture? Well, here’s the thing I noticed while building the app:</p>

<p>Using PowerSync meant that I didn’t have to write ANY state management code.<sup id="fnref:1" role="doc-noteref"><a href="#fn:1" class="footnote" rel="footnote">1</a></sup></p>

<p>Once you’ve configured your PowerSyncDatabase and .connect-ed it, generating reactive UI is as simple as:</p>

<div class="language-dart highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">StreamBuilder</span><span class="p">(</span>
  <span class="c1">// you can watch any SQL query</span>
  <span class="nl">stream:</span> <span class="k">return</span> <span class="n">db</span><span class="o">.</span><span class="na">watch</span><span class="p">(</span><span class="s">'SELECT * FROM customers order by id asc'</span><span class="p">),</span>
  <span class="nl">builder:</span> <span class="p">(</span><span class="n">context</span><span class="p">,</span> <span class="n">snapshot</span><span class="p">)</span> <span class="p">{</span>
    <span class="k">if</span> <span class="p">(</span><span class="n">snapshot</span><span class="o">.</span><span class="na">hasData</span><span class="p">)</span> <span class="p">{</span>
      <span class="c1">// TODO: implement your own UI here based on the result set</span>
      <span class="k">return</span> <span class="p">...;</span>
    <span class="p">}</span> <span class="k">else</span> <span class="p">{</span>
      <span class="k">return</span> <span class="kd">const</span> <span class="n">Center</span><span class="p">(</span><span class="nl">child:</span> <span class="n">CircularProgressIndicator</span><span class="p">());</span>
    <span class="p">}</span>
  <span class="p">},</span>
<span class="p">)</span>
</code></pre></div></div>

<p>All the mutable state in your app is now in a transactional DB. It seems like a much more natural place to put mutable state than cramming it into some singleton object, scattering it throughout your stateful widgets, or evolving it into a cambrian explosion of blocs and cubits.</p>

<p>Because, y’know, ACID.</p>

<h2 id="api-boilerplate---poof-gone">API boilerplate - poof, gone!</h2>

<p>And API client boilerplate?  Well as the PowerSync docs explain, you still need to implement back-end operations to push data back to your service. So don’t rip Dio out of your dependencies just yet.</p>

<p>But if (like me) you’re lazy and/or you prefer to write server-side code, you can get away with a single API call.</p>

<div class="language-dart highlighter-rouge"><div class="highlight"><pre class="highlight"><code>   <span class="k">await</span> <span class="n">_dio</span><span class="o">.</span><span class="na">post</span><span class="p">&lt;</span><span class="kd">dynamic</span><span class="p">&gt;(</span>
     <span class="s">'sync.json'</span><span class="p">,</span>
     <span class="nl">data:</span> <span class="p">{</span>
       <span class="s">"update_type"</span><span class="o">:</span> <span class="n">update_type</span><span class="p">,</span>
       <span class="s">"table"</span><span class="o">:</span> <span class="n">table</span><span class="p">,</span>
       <span class="s">"props"</span><span class="o">:</span> <span class="n">props</span><span class="p">,</span>
     <span class="p">},</span>
   <span class="p">);</span>
</code></pre></div></div>

<p>That’s it. That’s all the client-side code you’ll need. Yes, it’s not RESTful 🤷‍♂️. But you’re going to have to write server-side marshalling validation and authorisation anyway. So you might as well avoid having to duplicate half of that on the client.</p>

<h2 id="a-surprise-to-be-sure-but-a-welcome-one">A surprise, to be sure, but a welcome one</h2>

<p>It was fairly predictable that as a user, I would really like the way offline-first apps work. Startup is instant, no waiting for a loading spinner as the app bootstraps initial state from the server. Edits don’t force you to wait as they post back and reload data.  Pull to refresh is a thing of the past.</p>

<p>But as a developer, this feels like a game-changer:  I get incredibly robust data sync with LESS code. I don’t need to think about edge cases, race conditions, network failures, and retries. All of that is handled for me, and to be honest, in a much more robust fashion than I would bother implementing myself. Since all local state is in a transactional DB (once again with almost no effort), I get rock-solid state management. With a bit of luck, I’ll never have to care about the difference between a Bloc and a Cubit again.</p>

<p>As mentioned, <a href="https://github.com/ckritzinger/gotofun">here</a> is a reasonably complete example of how to use PowerSync with Flutter and Rails.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1" role="doc-endnote">
      <p>It turns out that <a href="https://news.ycombinator.com/item?id=37494175">I’m not the first</a> to make this observation.  <a href="https://www.powersync.com/blog/how-local-first-simplifies-flutter-state-management">Or even the second</a> <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name></name></author><category term="epiphanies" /><summary type="html"><![CDATA[I’ve been curious about PowerSync for a while now, but after seeing it blow up on HackerNews I had to try it. Moreso because it gave me the excuse to start on a side project that has been percolating in the back of my mind. You can see a full repo with my code (mobile and backend) here.]]></summary></entry><entry><title type="html">git init .</title><link href="/meta/2024/02/22/git-init.html" rel="alternate" type="text/html" title="git init ." /><published>2024-02-22T11:10:12+00:00</published><updated>2024-02-22T11:10:12+00:00</updated><id>/meta/2024/02/22/git-init</id><content type="html" xml:base="/meta/2024/02/22/git-init.html"><![CDATA[<p>Testing, 1, 2, 3. Hello world.</p>]]></content><author><name></name></author><category term="meta" /><summary type="html"><![CDATA[Testing, 1, 2, 3. Hello world.]]></summary></entry></feed>