<?xml version="1.0" encoding="utf-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:content="http://purl.org/rss/1.0/modules/content/" >
    <channel>
        <title>Jesse Ditson RSS Feed</title>
        <link>https://jesseditson.com/</link>
        <description>The online home of Jesse Ditson — essays on technology, work, and the world.</description>
        <lastBuildDate>Fri, 26 Jun 2026 20:41:21 +0000</lastBuildDate>
        <atom:link href="https://jesseditson.com/feed.xml" rel="self" type="application/rss+xml" />
        
        
        <item>
            <title><![CDATA[ "Vibe Coding" ]]></title>
            <link>https://jesseditson.com/stories/vibe-coding.html</link>
            <guid>https://jesseditson.com/stories/vibe-coding.html</guid>
            
            
            
            <category><![CDATA[ Technology ]]></category>
            
            
            <content:encoded><![CDATA[ <p>I’ve been using LLMs a lot lately, and in the last few weeks have been intentionally exploring their utility in a software engineering context. My conclusion is that I believe that “Vibe Coding” is actually the exact opposite of the correct way to use LLMs:</p>
<p>LLMs thrive on context, which allows them to do a much better job the more precise and verbose the prompt is. They’re also always going to reference additional context that you didn’t include, just by way of the way they’re trained - instructions are only overlaid on top of existing probabilities, which include exclusively things you <em>didn’t</em> ask for. So it makes sense that large amounts of context are helpful/required for getting good results.</p>
<p>Which brings us to “Vibe Coding” - the idea here is that verbose product specs are dead because you can just fiddle your way into something that works rather than thinking through exactly how it should work first. The LLM will trial and error with you until you get the result you’re looking for.</p>
<p>This is a bizarre thing to use LLMs for, as they will invariably just make a bad version of something that already exists unless you are quite precise with your instructions. But beyond that, the culture of letting the LLM do the initial experimentation, and then leaving the “hard work” to humans leaves engineers with nothing but messes to clean up. And often, those messes could have been avoided or circumvented by writing a good spec first.</p>
<p>Ironically, the LLM then could do a much much better job reviewing, adjusting, writing tests for, and otherwise truly pairing on a problem if you had written the spec to begin with, and made a best effort at writing the first version yourself. This also results in clear style references and test examples that the LLM can follow, allowing it to truly help instead of being relegated to creating throwaway code that over promises to a product manager and creates a pile of technical debt in its wake.</p>
<p>I suspect that these shortcomings in the use cases that appear to be most heavily encouraged by vibe code boosters are just the tip of the iceberg. Something that a human can do is be told “don’t abstract things in this part of the codebase” or “we have a style guide for readability that includes X”, and generally they only need to be told once. In my short experiment I have encountered many things that would be easy to tell a junior engineer one time and never have to worry about again, which to get an LLM to “remember” would require a tedious list of dos and don’ts in the LLM context file, along with infinitely subtle variations as it finds new and creative ways to attempt to write code that matches the token probabilities instead of code that matches your internal culture.</p>
<p>For me, one of the bright spots of the latest rounds of models is that in a sufficiently tested codebase, it can do a decent job of writing tests around functionality - I often find this helpful for counter-factual tests, when I’m trying to fix something and I need a test to fail when I fix it. I can then manually update the test to verify that I changed what I expected to change. LLM-written tests are often extremely pedantic and corner-case oriented, which is very helpful when changing large systems. The long-term value of these tests is certainly up for debate, but at least for the exercise of “I know it doesn’t work now, but how do I know I didn’t regress with a fix”, LLMs are looking like a powerful tool for existence proofs today.</p>
<p>However, I will caveat that I have had little success even with very high context with asking agentic LLM to fix bugs or write tests for unknown states — which probably is about what you should expect, it is just predicting what the code would look like when the bug was fixed, but unlike a human, “context” here has absolutely no impact on the most important parts of the UX of your application, it’s just a pedantic list of commands and explanations.</p>
<p>I think this last note is very helpful for setting expectations about when LLMs can be useful in a coding context, and once again highlights the etymological damage that OpenAI and others have done when it comes to helping us use these new tools. Under no circumstances should you think of these tools as “thinking” or “helpers”, but rather “very accurate predictors” - if you give it a really nicely shaped problem and have it predict what fits inside, they’re incredibly powerful, and will certainly have a meaningful impact on my life. But the moment that I ask it to do something that isn’t obvious and constrained, it (predictably) generates reams of trash.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>09 Dec 2025 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ Pandora’s Overton Window ]]></title>
            <link>https://jesseditson.com/stories/pandoras-overton-window.html</link>
            <guid>https://jesseditson.com/stories/pandoras-overton-window.html</guid>
            
            
            
            <category><![CDATA[ Politics ]]></category>
            
            <category><![CDATA[ Philosophy ]]></category>
            
            
            <content:encoded><![CDATA[ <p>The ongoing debate within the Democratic party about voting for this week’s budget package is a fascinating case study to me - I think it may demonstrate a disagreement on the philosophy of change, and was inspiration for me to try to write some thoughts on the subject:</p>
<h3>The Overton Window and Friends</h3>
<p>For the uninitiated, the Overton Window (<a href="https://en.wikipedia.org/wiki/Overton_window">wikipedia</a>) describes a theory of change which is extremely relevant to modern politics and social dynamics: the more radical an argument is, the more normal it makes less radical versions of the same argument seem. This is a well-studied phenomenon, and almost certainly one that will define modern politics.</p>
<p>I think there’s also a secondary resultant effect of intentional Overton Window abuse (subliminal or not - I don’t think JD Vance is smart enough to wield this power should he become aware of it, for instance): it creates a cascade of logical fallacies related to defending positions that are <a href="https://en.wikipedia.org/wiki/Red_herring">Red Herrings</a> or <a href="https://en.wikipedia.org/wiki/Straw_man">Strawmen</a>. An example would be when someone makes an obviously false statement like “immigrants are criminals” - to debate this on the merits would be foolish - but it achieves both the Overton Window shift <em>and</em> multiple logical fallacies that are difficult to ignore even for the most rational people. If you started in the position “Immigration is literally the foundation of our country, and is one of our greatest strengths”, you could get to “Maybe immigration policy should be reconsidered” without necessarily changing your political stance.</p>
<h3>Self-Owns for Everyone</h3>
<p>It’s reasonable to imagine that the best way to combat an Overton Window is simply to advocate for polar-opposite extremist ideas. You could start intentionally pointing out the merits of Communism, Primitivism, or other unpopular leftist ideas in the hopes that popular ideas among the folks in which you influence would take a leftward shift that does not result in any of the “extreme” ideologies becoming popular, but results in the more pragmatic ideas from them becoming normalized.</p>
<p>I hope that the risks involved in this approach are obvious, but let me say some out loud:</p>
<ul>
<li>Some people will believe you are being earnest, and become extremists.</li>
<li>Some people will not believe you are being earnest, and the window will not move.</li>
<li>This is a paradox, which will result in internal debate among those you influence.</li>
<li>If you are advocating for extremism, you cannot, by definition, also advocate for a more popular/pragmatic/achievable policy.</li>
</ul>
<p>These are pretty big issues, which in my opinion make it quite clear why pretty much all American policy is currently in chaos. I find myself almost daily asking myself (about the approach of American elected officials and those who voted for them) “why would you do something so obviously counter productive and stupid, especially when you very likely stand to personally suffer from the results?” I think the bullet points above go a long way towards explaining a lot of this behavior, if you imagine that nobody considered them while they were reaping the short-term rewards of Overton Window abuse.</p>
<p>Beyond just being divisive, Overton Window abuse also makes it literally impossible to create specific policy:</p>
<ul>
<li>Some of your supporters are happy that you’re moving the window but don’t believe you’re an extremist. If you actually propose extremist policies, they will abandon you.</li>
<li>Some of your supporters are happy that you’re finally supporting their extremist ideas in a popular platform. If you don’t propose extremist policies, you’ll be seen as a traitor to the cause.</li>
</ul>
<p>So, the only thing you can gain by abusing the window is a tenuous popularity. But you better be vague! Or alternatively, you can do everything at once, contradicting yourself. This is the path the current administration chose - promise prosperity and sign orders enacting austerity, while everyone else attempts to debate logical fallacies.</p>
<p>This sadly brings us to an unfortunate reality: an equal-and-opposite approach to right wing extremist ideas is probably not left wing extremist ideas. Both will likely combine to create <em>more</em> chaos, not less. Infighting is a direct result of the contradiction of proposing extreme ideas in service of incremental movement; if nobody believes you, the window doesn’t move. If some people believe you, you can only create chaos, because your policy cannot be clearly defined. If everyone believes you, you’re <a href="https://en.wikipedia.org/wiki/Ted_Kaczynski">Ted Kaczynski</a>, and the window either moves very little or not at all.</p>
<h3>The Left Is Fucked</h3>
<p>It seems to me that this is what is currently disturbing the left:</p>
<ul>
<li>Gavin Newsom clearly admires the right’s exploitation of the Overton Window, but amazingly doesn’t even understand how to do it for the left and so has inexplicably decided to help exploit it further towards the right. Ideally this is political suicide but I assume he’ll just run as a Republican or try a party flip.</li>
<li>Chuck Schumer is unaware of the window, or perhaps anything outside of congress, and still believes compromise and status quo is on the table. Members of his party will likely use him as an excuse to defy their constituents.</li>
<li>AOC &amp; Bernie believe they can ride the lightning and want to open the leftist Overton Window Pandora’s box. It’s possible Bernie already did? Maybe that’s what 2016 was about?</li>
<li>Warren as always is attempting to prioritize logic &amp; economics, which will result in an anti-authoritarian obstructionist vote, but it’s unclear how long she’ll be willing to break eggs if she knows the omelette is going to be shit anyway.</li>
</ul>
<p>My opinions based on the above:</p>
<ul>
<li>I don’t think we can shut Pandora’s Overton Window, but I do think that we can prepare to rebuild once it has run its course.</li>
<li>I’m not optimistic that we can get anywhere without the system destroying somewhat important parts of itself.</li>
<li>I am focused on local empathy and trying to make sure that we are prepared for damage control when the chaos reaches us.</li>
</ul>
<h3>Helpful Tips For Living in a Post-Pandora’s Overton Window Hellscape</h3>
<p>I do not believe that policy will save either party right now, but irrefutable mission statements may. What if we held politicians to a simple standard when it comes to commenting on policy:</p>
<blockquote>
<p>Statements about policy should include clear goals (and optionally methods), which are not possible to understand by both sides of an Overton Window as beneficial.</p>
</blockquote>
<p>Here are some statements that do not pass the test:</p>
<ul>
<li>“We will create American prosperity”</li>
<li>“We will be business friendly”</li>
<li>”We will defend American families”</li>
<li>“We will uphold the constitution”</li>
</ul>
<p>Here are the same statements, made in a way that passes the test:</p>
<ul>
<li>“We will declare war on Canada”</li>
<li>“We will raise taxes on the middle class and cut taxes for billionaires”</li>
<li>“We will ban gay marriage”</li>
<li>“We will pack the supreme court with unqualified partisan judges to intentionally mis-interpret the constitution towards our goals”</li>
</ul>
<p>These ones also pass the test:</p>
<ul>
<li>“We will cancel student loan debt”</li>
<li>“We will prevent &amp; prosecute monopolies”</li>
<li>“We will prevent and/or reverse legislation that encroaches on the personal liberties of Americans”</li>
<li>“We will amend the constitution if necessary to prevent consolidation of power in any branch of government”</li>
</ul>
<p>It’s hard to know when to believe people, which makes it easy to act against your own interests - this is a problem that will get worse as we explore this window, unless we can start to understand when our leaders are acting in good faith and when they’re playing a game. It’s important to believe people when they say what they mean, and equally important to refuse to interpret statements optimistically.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>14 Mar 2025 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ Jesse's Hi Desert Voting Guide 2024 ]]></title>
            <link>https://jesseditson.com/stories/voter-guide-2024.html</link>
            <guid>https://jesseditson.com/stories/voter-guide-2024.html</guid>
            
            
            
            <category><![CDATA[ Politics ]]></category>
            
            
            <content:encoded><![CDATA[ <p>This election year, there are a bunch of things on my local ballot in San Bernardino County, which is where Joshua Tree is, that were a challenge for me to understand. This post is my attempt to make sense of it - and to share my research, and my opinions.</p>
<h1>Offices</h1>
<h2>President &amp; Vice President</h2>
<h3>Kamala Harris &amp; Tim Walz</h3>
<p>There are tons of problems with this ticket - but at the end of the day, the presidential office shouldn't be as important as it has seemed lately. A vote for Kamala, for me, is a vote against giving more power to the highest offices, as her opponent has made it clear that he would attempt to turn the US into an authoritarian state with him as dictator, which is an undesirable power concentration, and we know the Supreme Court will not offer resistance. In my opinion, regardless of your politics, this one is mandatory.</p>
<h2>US Senate</h2>
<h3>Adam B. Schiff</h3>
<p>This one is harder. Adam is a genuine asshole and worked extremely hard to boot a better democratic candidate (Katie Porter) off the ballot during a primary. I think he jeopardized CA's seat in doing so, but the seat becoming red would be a reliable vote for some especially unsavory shit, so this douchebag gets my vote. It's likely going to be close, otherwise I'd be leaving this one empty.</p>
<h2>Representative District 23</h2>
<h3>Derek Marshall</h3>
<p>Derek doesn't strike me as a career politician, or even a particularly intelligent person - his policies appear to mostly be wide-eyed plans about adding economic opportunities and jobs via water parks and high speed rail that feel too ambitious for the seat and tenure - but he does seem to represent a fairly centrist, liberty-oriented, opportunity-focused sentiment that feels representative of the folks who live up here. His opponent is a boring republican &quot;businessman&quot; who sold software in the 90s (which would make any idiot rich), and who now sends me emails about what he's doing for law enforcement and border security. I think voting Derek in is a pretty big win for the demographic shift in the Hi Dez and would be meaningful outside of policy (which I doubt would change much).</p>
<h2>Senator District 19</h2>
<h3>Lisa Middleton</h3>
<p>As far as I can tell, this race is a matter of the candidates trying to talk about policy, while the media talks about identity. Both are important - Lisa is a trans woman, the first of which to be mayor of Palm Springs, and would make history as such on the senate. Rosilicie is the first Republican Latina elected to the senate, which is its own sort of depressing history given the party's current rhetoric related to latinx folks. For me, the identity is probably enough for my vote to go to Lisa - I'm a strong believer that trans folks have had to live much more life than most of us and as such usually have deeply developed political theory. However, policy makes this one obvious. Ochoa supports vaguely republican coded policy like &quot;parental rights&quot; in schools and &quot;lowering gas taxes&quot; which I think can both be easily translated into anti-trans and anti-climate sentiments.</p>
<h2>State Assembly District 47</h2>
<h3>Christy Holstege</h3>
<p>This one, to be honest, is more about Christy's opponent than what I expect her to get done personally. Greg Wallis has been an annoying douchebag in the California assembly his entire tenure. His politics are extremely tired (and oddly focused on opposing universal health care, which I was fairly certain was an all-but-dead issue outside of ultra-geriatric demographics), and he is the type of &quot;assholes live forever&quot; redpiller which appears to most enjoy being a pariah but has no constructive policy. As soon as he stopped having something to agitate, he'd be impotent. So... let's put Christy in office to get this little speed bump out of Sacramento.</p>
<h1>Nonpartisan Offices</h1>
<h2>Member, Board of Education Area E, SB County</h2>
<h3><em>No Endorsement</em></h3>
<p>This race is hard to find any substance on, but I personally voted for Neal Alfred Waner, based on his long history of non profit work in the Big Bear area. I genuinely couldn't find anything about him that didn't seem positive. On the flip side, the incumbent Andrea De Leon is endorsed by the republican party of SB county, and sadly, this decade that's a tough pill to swallow. I'm usually hesitant to vote out an incumbent (because project timelines don't respect term limits), but I do think there should be consequences for blind alignment with the facists this year. That said, I doubt there are any wrong answers on this ticket.</p>
<h2>Member, Governing Board Area 3, Copper Mountain College</h2>
<h3><em>No Endorsement</em></h3>
<p>It was hard finding info on these candidates, and I'm not totally clear on what the office entails. I'm split on the candidates as well - the incumbent is Mary E. Lombardo, who now has 12 years in this role - I believe that experience is critical to action, and I'm generally supportive of incumbents in these types of roles.
The challenger, Terrence C. Latimer, runs a local co-working space, and is a black man who worked in IT/tech. I know that his experience as a minority in this industry would be very valuable in the context of creating opportunities, but I'm skeptical of his optimistic views about the impact and importance of tech. That said, I find <a href="https://www.linkedin.com/pulse/why-im-running-seat-copper-mountain-colleges-board-terence-latimer--cbzmf/">his arguments</a> related to helping rural communities with digital literacy compelling. I'm not sure that a shift towards techno-determinism at a community college is the ideal outcome though. I think it's worth reading his &quot;why I'm running post&quot;:</p>
<p><a href="https://www.linkedin.com/pulse/why-im-running-seat-copper-mountain-colleges-board-terence-latimer--cbzmf/">https://www.linkedin.com/pulse/why-im-running-seat-copper-mountain-colleges-board-terence-latimer--cbzmf/</a></p>
<p>And an interview by Mary given last election, which I assume still represents her values:</p>
<p><a href="https://z1077fm.com/we-meet-the-candidates-for-copper-mountain-college-board/">https://z1077fm.com/we-meet-the-candidates-for-copper-mountain-college-board/</a></p>
<h1>San Bernardino County Offices</h1>
<h2>Assessor/Recorder (Short Term)</h2>
<h3>Dara Smith</h3>
<p><em>Mystery! Intrigue! Addiction &amp; Death!</em> Strap in, this short-term assessor/recorder seat has it all.</p>
<p>I had no opinions when I opened my ballot so I googled around until I found <a href="https://www.msn.com/en-us/news/other/4-compete-for-san-bernardino-county-assessor-s-seat-in-november-election/ar-AA1sx28g">this gripper of a story</a>. Apparently we're doing this election for this allegedly important seat because of the untimely death of Bob Dutton, who died in 2022, one month into his fourth term. His assistant was appointed through January, so these 4 candidates are all vying for a half-term to finish up Bob's 4 years.</p>
<p><strong>First off, what the fuck is an assessor/recorder?</strong></p>
<p>They appraise value of property in SB county for tax purposes. I think a layperson could imagine how you might abuse this power, but if you've ever had your house appraised, you'd know it's pretty banal and straightforward, and that property values are quite disconnected from it. It's mostly property tax that is impacted by this position, which doesn't set or collect taxes, just, uh, assess, but not directly (an appraiser does this, the assessor assumedly gives them guidelines), properties. Ok now that that is super clear, let's dig into the candidates.</p>
<p><strong><em>Blanca Azucena Gomez</em></strong></p>
<p>This firecracker apparently has been kicked out of a few Victorville City Council meetings (2 in fact, although she was convicted of 4 charges, so she must have really caused a ruckus). She also has been arrested for sneaking into a part of Hisperia City Hall that is off limits to the public and then refusing to leave. The good news is that she's already an elected official, serving her second (and actively running for a third) term on the Victorville City Council. She recently ran unsuccessfully for state Senate in D23.</p>
<p>Do we think we should support her hunger for power?</p>
<p><strong><em>Josie Gonzales</em></strong></p>
<p>This is her second time seeking Bob's vacated seat, and is also a seasoned politician, serving on various supervisory and city council seats in the (somewhat distant) past. Not to be outdone by Blanca though, she also appears to be an agitator, more interested in anecdote than fact. Here are some fun quotes: <em>&quot;This position is the most important office, in my opinion, in any county,&quot;</em> Gonzales said. <em>&quot;It is the revenue generator for, I would say, probably 85% of the general fund that comes in that then goes to pay for all the services.&quot;</em>.</p>
<p>If you're unconvinced by those numbers, get this: She's running on the platform that lots of people are over-assessed - but when pressed about <em>who</em> she feels was over-assessed, she did not have any examples, and said despite not having any experience for the role, she reassured her constituents with this statement: <em>&quot;I claim to have the experience of knowing the individuals that are in the right places that will make things happen.&quot;</em>. Compelling!</p>
<p>Who could she be talking about? Well, turns out her campaign advisor is none other than Bill Postmus, who served with her on a board of supervisors before narrowly winning the role of Assessor/Recorder in 2006. This would seem like an important ally, but before he could complete his term as Assessor/Recorder, he was arrested for felony possession of meth during a corruption investigation!</p>
<p>Gonzales, to her credit, has stayed loyal through these trials.</p>
<blockquote>
<p>&quot;I told him that after he served his time, if he stayed clean, and he did everything he was supposed to do to find his way back through life and to be able to serve, then I would let him run my first campaign for assessor,&quot; she said. &quot;It's not so much about him helping me, it's about me helping him.&quot;</p>
</blockquote>
<p>Does this help or hurt her campaign? What does this seat do again?</p>
<p><strong><em>Dara Smith</em></strong></p>
<p>At this point during my investigation, I was desperately hoping to find a viable candidate to vote for. Unfortunately, Dara's bio starts as such:</p>
<blockquote>
<p>Smith is the only candidate in the race who has not previously held elected office.
&quot;This is one of those offices that you definitely want to have qualified people in it,&quot; Smith said.</p>
</blockquote>
<p>Ok, well at least she knows what she's up against.</p>
<p>In all seriousness, she doesn't appear to be aligned with any ex-methhead corrupt seatholders of the office, and has no record of being arrested at city council meetings, and she has a 100 day transition plan which includes some attractive accountability and public education metrics. In general, she feels that the office could do more for outreach to folks who can, for instance, get public benefits for disability or natural disasters.</p>
<p><strong><em>Donald Willamson</em></strong></p>
<p>The sole male in this race, Don seems like a simple but likeable man. His main campaign stump is to point out that one time while working as county assessor (1994-2006) he fired an employee for not helping an elderly woman. Seriously, here's the quote:</p>
<blockquote>
<p>&quot;He wouldn't help her. He said she'd been in before and there was no point to it,&quot; Williamson recalled. &quot;And I said 'Yeah, but I'm asking you to come in here and help me help her.' And he said again he wouldn't do it. So I said, 'OK, just go home then.' &quot;</p>
</blockquote>
<p>I'd hate to get on his bad side! He made this vow if returned to office:</p>
<blockquote>
<p>&quot;That's me, I like to help people,&quot; he said. &quot;Got a problem, come to me.&quot;</p>
</blockquote>
<p>He also believes that it would be important to reopen the Fontana office that was closed in 2006, mostly so old people, who &quot;like to come in&quot;, don't have to drive as far. Sounds reasonable to me!</p>
<p>For what it's worth, it seems like Donald is doing a lot from outside of political office, so maybe he's fine where he's at. Again from the linked article:</p>
<blockquote>
<p>&quot;I like helping people. People knew who I was and they always asked me 'Hey, I got this problem, what do I do about it?' I just got a call the other day.&quot;</p>
</blockquote>
<p>Is this an important race? Who knows. But I sure enjoyed reading about it.</p>
<h1>District Offices</h1>
<h2>Member, Board of Directors Division 5, Joshua Basin Water District</h2>
<h3>Stacy Doolittle</h3>
<p>When I moved to this area in 2020, Stacy came to my house to ask for my vote. Now, she's an incumbent. I could find absolutely nothing of substance on either of these candidates, including <a href="https://z1077fm.com/joshua-basin-water-district-candidates-forum-recap/">this interview</a> which was entirely unhelpful. I don't even know what this person is responsible for, and so I'm going with the lady who showed up at my house.</p>
<h1>State Measures</h1>
<h2><a href="https://voterguide.sos.ca.gov/propositions/2/index.htm">Proposition 2</a></h2>
<h3>Yes</h3>
<p>This authorizes a $10B public school bond. This obviously includes charters, and between that and the general modern incompetence in government, it's unclear if this impressive number will result in the impact that it should. However, this one is only opposed by Howard Jarvis Taxpayers association which would oppose a fractional cent increase in property tax - and generally, $500/mm a year to fill up some coffers with more to help our stressed education system feels like a good gamble.</p>
<h2><a href="https://voterguide.sos.ca.gov/propositions/3/index.htm">Proposition 3</a></h2>
<h3><strong>Yes</strong></h3>
<p>This one is obvious. Prop 8 was passed in 2008 and overturned by the Supreme Court in 2012; it was a constitutional amendment aimed at banning same-sex marriage in California. However, despite being nullified, it's still shamefully sitting in our constitution. This prop adds an amendment to finally clean up the mess and guarantee the right to marriage among all couples in CA regardless of gender or race.</p>
<h2><a href="https://voterguide.sos.ca.gov/propositions/4/index.htm">Proposition 4</a></h2>
<h3><strong>Yes</strong></h3>
<p>Prop 4 authorizes bonds for &quot;various activities aimed at conserving natural resources&quot;. In general, I am frustrated when a proposition like this ends up as a voter issue rather than resolved in legislature. We elect our officials for a reason, and when opaque props end up on my ballot, I blame my elected officials for failing to do their jobs. That said - this is a 10B bond with no opponents other than our friend Howard Jarvis. I suspect this will mostly end up being fire fighting, and while I'm depressed that this is still a topic resulting in any controversy whatsoever, if this is how the money is allocated for it, so be it. Take my yes vote and get your heads out of your asses.</p>
<h2><a href="https://voterguide.sos.ca.gov/propositions/5/index.htm">Proposition 5</a></h2>
<h3><strong>No-ish???</strong></h3>
<p>If the last proposition was annoying, this one is enraging. The wording is incredibly challenging, and attempts to present this as a proposition in support of affordable housing. However, in my reading, any impact on housing is somewhat bolted on, and this prop is a constitutional amendment lowering the approval of infrastructure bonds with a 55% majority. Historically, CA has required a 2/3 supermajority for bond spending. To add to the confusion, this appears to be a partial referendum on <a href="https://en.wikipedia.org/wiki/1978_California_Proposition_13">prop 13</a> (passed in 1978), which was intended to cap property tax increases.</p>
<p>My personal opinion is that prop 13 redistributes wealth upwards by putting tax pressures on sales tax instead of property tax, which is effectively a subsidy for the rich. I'd absolutely support a repeal. However, prop 5 feels like a back door, and ultimately I don't think it has the checks in place to prevent it from modern political abuse. &quot;Infrastructure&quot; is vaguely defined in the measure and it's obvious how this could result in the type of &quot;affordable housing&quot; funding that we saw in San Francisco that ultimately ended up entrenching developer monopolies and doing nothing for the actual housing crisis. I ended up as a <strong>No</strong> on this, purely due to the fact that I feel we can be more specific with our solutions, or we could vote to repeal 13 - but opening the door to less-popular spending bills to support infrastructure that will probably be built by billionares feels sketchy at best.</p>
<h2><a href="https://voterguide.sos.ca.gov/propositions/6/index.htm">Proposition 6</a></h2>
<h3><strong>Yes</strong></h3>
<p>Do you like slavery? No? Ok this should be easy then! This prop eliminates a constitutional provision that allows us to force our prisoners into &quot;involuntary servitude&quot;. I think everyone should be a slavery absolutist. Especially with a measure to incarcerate the homeless on the ballot (more on that later!)</p>
<h2><a href="https://voterguide.sos.ca.gov/propositions/32/index.htm">Proposition 32</a></h2>
<p><strong>Yes</strong></p>
<p>This is a minimum wage increase to $17 (and $18 in 2026) for companies with &gt;25 employees in California. If you believe that raising minimum wage does anything other than improve economic opportunity for everyone except assholes, call me. My number is 415-656-7383. I will happily have a chat about how economics work, and who will benefit from wage increases.</p>
<h2><a href="https://voterguide.sos.ca.gov/propositions/33/index.htm">Proposition 33</a></h2>
<h3><strong>Yes</strong></h3>
<p>This measure, which was (importantly!) put on the ballot by the AIDS
Healthcare Foundation allows local governments to implement rent control.</p>
<p>I lived in San Francisco for a decade, and can't say enough good things about rent control. Anyone who tells you that this puts undue pressure on landlords is confused about how economics works. There are definitely edge cases here but in general, rent control allows communities to stay together, and gives greedy landlords any reason at all to not be assholes and to think twice before building extractive empires.</p>
<p>Perhaps someday if there's more rent control, houses won't be bought up by people looking to leverage them for passive income, and property values will drop enough that houses will be affordable to (gasp!) people who want to live in them.</p>
<h2><a href="https://voterguide.sos.ca.gov/propositions/34/index.htm">Proposition 34</a></h2>
<h3><strong>No</strong></h3>
<p>Holy shit this one is a doozy. Read the measure as written, and then come back.</p>
<p>Here's the rub: <em>THE ONLY FEDERAL DISCOUNT PRESCRIPTION DRUG PROGRAM THAT MEETS THE QUALIFICATIONS TO BE REGULATED BY THIS MEASURE IS...</em></p>
<p><strong>The AIDS Healthcare Foundation</strong>!!!</p>
<p>This measure is worded like it's some public good, but this literally is just a revenge measure put on the ballot to get back at the AIDS Healthcare Foundation, for putting prop 33 on the ballot. These are the evil landlords I mentioned in the prior paragraph, literally using the ballot to try to harm a healthcare organization that exclusively helps people with AIDS! Are you fucking kidding me!!!</p>
<h2><a href="https://voterguide.sos.ca.gov/propositions/35/index.htm">Proposition 35</a></h2>
<h3><strong>Yes</strong></h3>
<p>There doesn't appear to be any reason to oppose this. No opposition was even filed against this - it basically just codifies Medi-Cal, which otherwise would expire in 2027. Why are we even voting on this? Who knows. I'm sure Greg Wallis would oppose this prop.</p>
<h2><a href="https://voterguide.sos.ca.gov/propositions/36/index.htm">Proposition 36</a></h2>
<h3><strong>No</strong></h3>
<p>What the fuck is this shit. This measure basically adds mandatory jail time for certain petty crimes like smash and grabs and minor possession. This is an absurd idea which is expensive to taxpayers, will contribute to systemic crime, clog the courts, and fund private prisons. Maybe easiest nope on the ballot other than getting rid of slavery - although if you're pro prison slavery, I could see the symbiosis here. Maybe that's why this obviously stupid idea is on the ballot?</p>
<h1>Morongo Unified School District Measures</h1>
<h2>Measure C</h2>
<h3><strong>Yes</strong></h3>
<p>This is our second time trying to pass this bond, which seems pretty obvious. There are a lot of libertarian tax nuts out here, so it probably will fail again - but all this does is give money to our small district who could use it. It will cost $36/yr to fund per 100k, which we all know would mostly be paid by out-of-county AirBnBs anyway. I will give any local who votes yes on this a $1/drink discount when our bar opens, up to 36 drinks per year. I'm dead serious. Fund the damn schools.</p>
<h1>San Bernardino County Measures</h1>
<h2>Measure K</h2>
<h3><strong>Yes</strong></h3>
<p>This increases transient occupancy tax (Hotels &amp; Vacation Rentals) to 11%. Don't tempt me with a good time, let's do 30%! I'd vote for 50%! Obviously this is reasonable and fair. Yes yes yes.</p>
<h2>Measure L</h2>
<h3><strong>No</strong></h3>
<p>This is a bizarre measure put on the ballot as a pre-emptive anti-defund-the-police move that will lock the salaries of local law enforcement to within 4% of the average of surrounding counties. It's unclear who is trying to defund the police (well I am, but not succeeding) out here, but this seems like the most pandering way to get a tiny raise. Let's talk about the fiscal impact of this if we're gonna argue about minimum wage... In any case, I don't see any need to support this. In fact, I'm not even support of the fact that someone wasted my tax dollars putting it on the ballot.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>29 Oct 2024 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ Redpilling: the myth of lazy success ]]></title>
            <link>https://jesseditson.com/stories/redpilling.html</link>
            <guid>https://jesseditson.com/stories/redpilling.html</guid>
            
            
            
            <category><![CDATA[ Politics ]]></category>
            
            <category><![CDATA[ Philosophy ]]></category>
            
            
            <content:encoded><![CDATA[ <p>It seems to me that a specific definition of “redpilling” would be something like:</p>
<ul>
<li>A mediocre person in a competitive field consumes social media or news that focuses their attention on a cherry-picked set of successes by people who are statistical anomalies. Most billionaires fit this category, so it’s not a media transparency issue, just a normal human curiosity/interest.
<ul>
<li>Almost all of these successes were possible due to advantages that the beneficiaries did not influence or manufacture - either familial or otherwise external subsidies, accidental success, cheating, or just plain luck. By definition, this level of outsized success is not possible via work (compensated labor) alone, but it is in their interests to claim that it is. Obscuring the subsidy creates a dissonance for the observer - these people did not work for it, but were successful anyway, so they must have a “secret shortcut” [^1].</li>
</ul>
</li>
<li>It makes the person question the necessity of doing things the “hard way”, e.g. learning about things before attempting to do them, acquiring academic credentials, etc.</li>
<li>They vocalize or act on those observations, and either are rejected by whatever community they have that believes in the value of expertise, or get lucky and manage to create a short-term shortcut in their field (e.g. lucky timing in a market, shortcutting safety or hedges for near term gains at the cost of long term value/risk, exploiting normally shared or finite resources for short-term personal gain, etc.) - or both.</li>
<li>Even if they don’t succeed, since they are abandoned by peers with expertise, their new peer group confirms via discourse their suspicion that expertise was unimportant. An “echo chamber” effect helps them focus only on rare and atypical successes by non-experts, which makes them feel as if they were wrong to pursue expertise.</li>
<li>The rare people who are successful in this approach are incentivized to continue the mythology. And in most cases, they can create a confirmation loop by selling things to the people who believe in the myth of lazy success, thereby resulting in nearly irrefutable success.</li>
</ul>
<blockquote>
<p><em>Put more succinctly; if most billionaires are stupid assholes, the blue pill is to try to be a billionaire, and the red pill is to try to be a stupid asshole.</em></p>
</blockquote>
<p>I can see why this is so attractive. The idea that working hard is for suckers and that you don’t need to account for risk if the disaster never happens has always been a fairly effective strategy to scam people, but usually didn’t hold up to scrutiny. What changed to make it so that being scammed actually makes you the smart one?</p>
<p>Three compounding dynamics seem to have caused the shift in the mainstream percieved legitimacy of these cons:</p>
<ol>
<li><strong>Shorter term media focus</strong> - there are genuine positives to focusing on smaller and smaller trends (which IMO help to drive systemic changes thought impossible in prior decades), but the main negative is that it’s very easy to over-ascribe value to things that smooth out in the macro trends. This sadly causes short-term success to be easily confused with long-term success.</li>
<li><strong>The ability to turn support into capital</strong>, e.g. giving fame, and infamy, value - financial engineering products, meme stocks, and token markets all are good examples of how someone who has no actual social value could convert notoriety into money. This results in a feedback loop where you can become “traditionally successful” without any accountability to a product or service. Why sell Trump Steaks and worry about having to pivot when people realize that they are very low quality, when you can just sell tokens and no steaks? There have always been ways to generate margin from notoriety, but we now have a few ways of skipping the product and just getting people to hand you their money.</li>
<li><strong>More people, more outliers</strong> - as media and people move onto the internet, we lose the curatorial voice and it becomes much easier to find outliers that are isolated examples of things that should normally be extremely improbable. The fact that there are more of them every day feels trend-y to a non-critical mind, despite being not actually being a trend after normalizing growth.</li>
</ol>
<p>It’s easy to see how if you were struggling in mediocrity how you’d prefer to imagine that <strong>you</strong> could be the outlier - or that perhaps the outliers aren’t outliers at all, but a trend you could join - if you keep seeing other mediocre people buying the dip and selling the peak. (I mean, someone always has to, why not you?)</p>
<p>In reality, there’s no shift in the percentages, just a consistent growth in total numbers. In the jealous mediocre brain, the focus is on the fact that are more rich assholes every day. This is true, but not representative of the percentage of rich assholes as compared to the number of other visible people, so while there <strong>are</strong> more rich assholes every day, your chances of becoming one haven’t changed.</p>
<p>I am a little concerned about the power of this phenomenon to convert enough people into willful idiots that it will start impacting politics and culture. However, I have to take my own advice and trust that these are not the majority of thinkers, just the loud mediocre ones, and that their moment will pass. After all, they have time and they’re spending it yelling about DEI on the internet instead of pursuing their passions. And from a competitive standpoint, I welcome it. Less mediocre hustlers in the professional environment and more short-term focus in investment &amp; business means more room in the market for deep thought and long-term strategies, as long as we don’t collapse the whole thing first.</p>
<p>[^1]: <em><!-- raw HTML omitted -->Nassim Nicholas Taleb built his career on selling jealous observers of accidental success a special form of logic tailored to help them believe that these successes were not randomly anointed, but based on “social alpha” or otherwise manipulable events. The Incerto series is very interesting, but reading it doesn’t appear to correlate with success.<!-- raw HTML omitted --></em></p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>17 Oct 2024 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ Rust Singletons in a ServiceWorker ]]></title>
            <link>https://jesseditson.com/stories/rust-singletons-in-a-service-worker.html</link>
            <guid>https://jesseditson.com/stories/rust-singletons-in-a-service-worker.html</guid>
            
            
            
            <category><![CDATA[ Technology ]]></category>
            
            
            <content:encoded><![CDATA[ <h2>Background</h2>
<p>Recently I was working on the archival editor (https://editor.archival.dev), which is an application in which all the business logic happens in a Rust library. This setup is nice because the UI is a pure function of the state produced by Rust, which is infinitely more reliable than javascript and much faster than round trips to a server.</p>
<p>One of the things that causes a bit of friction when working in this environment is that the singleton pattern isn’t really friendly with Rust’s memory model.</p>
<p>Rust’s design includes the concept of “Fearless Concurrency”, which in practice means that unless any type is marked as <code>Send</code>, the compiler will disallow storing references to it in structures that could potentially be used across threads. For the most part, when working in Rust you'll use types from the <code>stdlib</code> (e.g. <code>Mutex</code> or <code>RwLock</code>) which implement <code>Send</code> and <code>Sync</code> - usually, you won't need to implement these traits yourself. And importantly, implementing these traits must be done outside of the borrow checker (in an <code>unsafe</code> block) because the checker can't guarantee ownership across threads.</p>
<p>This sometimes bumps up against the reality that a service worker is always a single thread. You could go to all the work to make sure every one of your data structures are thread safe, but this would ratchet up the already quite high friction in working with a WASM codebase up to 11 (and in my opinion push it beyond what is reasonable for a web application in terms of complexity). In addition, multithreading doesn't work out of the box in a WASM environment - subthreads will silently not spawn which will often result in an effective deadlock. It makes a lot more sense to build some tooling around helping rust with the single threaded assumption, and then handling any necessary parallel execution via spawning workers.</p>
<h2>Why Use Rust At All?</h2>
<p>In modern frontend application architecture, a common goal is to make the frontend entirely stateless. This is a strategy long explored in the frontend community, and a big reason why React and other reactive patterns are so popular. However, when working in real javascript applications, the abstraction always leaks. React and other libraries explicitly support storing state in components, and the lines often blur when using patterns like context. Ideally, the only memory that needs to be preserved should be entirely outside of the rendering code.</p>
<p>In my app, this is achieved via using a long-lived service worker to hold all stateful memory - even the javascript code running in this service worker is stateless outside of holding a reference to an instance of my rust library. When it receives a message from the frontend or when the rust lib calls a FFI in the worker, it sends those along to the correct receiver. (It also manages caching &amp; proxying but that’s for a different post).</p>
<p>The Rust application on the other hand becomes extremely stateful. It manages worker lifecycle by caching any long-lived application data (using web APIs and/or FFIs to invoke <a href="https://developer.mozilla.org/en-US/docs/Web/API/Cache">native Cache APIs</a>).</p>
<p>This gives you the safety of Rust where it matters - in the process of producing a <code>State</code> object - but doesn’t require you to do anything fancy when it comes to rendering the UI. In fact, I just use DOM apis via <a href="https://github.com/jesseditson/upd8"><code>upd8</code></a> and skip a reactive javascript library entirely.</p>
<h2>Managing State With a Singleton</h2>
<p>Ok, so we want to put our state in Rust. But Rust doesn’t have any stdlib singleton pattern, so we’ll need to use some static memory to track our main library code.</p>
<p>My first attempt was to just write a huge comment warning the reader and to bail out memory safety via <code>unsafe impl Sync/Send</code> on a <code>newType</code> struct:</p>
<pre><code class="language-rust">// HERE BE DRAGONS

/*
 * Editor is &quot;effectively&quot; single threaded, in that it makes heavy use of
 * interior mutability and locking to deal with event orchestration. These
 * locks are generally achieved through RefCells, which are not threadsafe
 * but faster than mutexes. Similarly, ref counting is achieved via Rc
 * instead of Arc for performance. While it may be possible to make Editor
 * threadsafe, the use of stored callbacks make it an even larger challenge,
 * and due to the statefulness of it, there are little upsides. Instead,
 * it is the implementors responsibility to make sure that there is only one
 * Editor instance. In FFI contexts, the implementor can just hold a pointer.
 * But in WASM, it is non-trivial and already unsafe to send a pointer in and
 * out of javascript. So instead, we use a singleton in the WASM thread, which
 * is (as of 2023) already guaranteed to be single threaded.
 */

use crate::editor::Editor;
use once_cell::sync::OnceCell;
use std::ops::{Deref, DerefMut};
use std::sync::{Mutex, MutexGuard};
use tracing::{debug, trace_span, warn};
use wasm_bindgen::JsValue;

pub struct NotActuallyThreadSafeEditor(Editor);
unsafe impl Sync for NotActuallyThreadSafeEditor {}
unsafe impl Send for NotActuallyThreadSafeEditor {}
impl&lt;'a&gt; Deref for NotActuallyThreadSafeEditor {
    type Target = Editor;
    fn deref(&amp;self) -&gt; &amp;Self::Target {
        &amp;self.0
    }
}
impl DerefMut for NotActuallyThreadSafeEditor {
    fn deref_mut(&amp;mut self) -&gt; &amp;mut Self::Target {
        &amp;mut self.0
    }
}
fn wrapped_editor&lt;'a&gt;() -&gt; &amp;'static Mutex&lt;NotActuallyThreadSafeEditor&gt; {
    static INSTANCE: OnceCell&lt;Mutex&lt;NotActuallyThreadSafeEditor&gt;&gt; = OnceCell::new();
    INSTANCE.get_or_init(|| {
        debug!(&quot;♻️ Create Editor Singleton&quot;);
        Mutex::new(NotActuallyThreadSafeEditor(Editor::init()))
    })
}

pub static LOCK_DESC: Mutex&lt;String&gt; = Mutex::new(String::new());

pub fn editor_guard(
    name: &amp;str,
) -&gt; Result&lt;MutexGuard&lt;'static, NotActuallyThreadSafeEditor&gt;, JsValue&gt; {
    if let Ok(editor) = wrapped_editor().try_lock() {
        debug!(&quot;locking: {}&quot;, name);
        let s = trace_span!(&quot;locking&quot;, operation = name);
        let _lt = s.enter();
        *LOCK_DESC.lock().expect(&amp;format!(&quot;double lock: {}&quot;, name)) = String::from(name);
        Ok(editor)
    } else {
        {
            let current_lock = LOCK_DESC.lock().unwrap();
            warn!(
                &quot;conflict: attempted to lock ({}) while locked ({})&quot;,
                name, current_lock
            );
        }
        Err(JsValue::from_str(&quot;locked&quot;))
    }
}
</code></pre>
<h2>Mutexes, RwLock, Panics - oh my!</h2>
<p>This all brings me to the main issue - I generate bindings from Rust to JS using <a href="https://rustwasm.github.io/wasm-bindgen/">wasm-bindgen</a> - this saves me a lot of headache around instantiation and types, and works out of the box. However something that wasn’t immediately clear to me when getting started with this toolkit is that while Rust applications usually terminate when they panic, this environment has no “crash mode” - exceptions can be thrown, but that just ends the current tick and prints something to the console. The next tick, the event loop will continue, with your memory intact. This totally breaks a core assumption in Rust that memory will be dropped after a panic, and often results in <code>unreachable</code> statements being hit as Rust code is not expected to continue running after a panic.</p>
<p>What does this have to do with singletons? Because, when the above code panics, the locks are never poisoned. Instead, wasm-bindgen wraps panics and throws exceptions. In addition, the guard isn’t dropped - which makes sense, JS can’t guarantee that we won’t reuse that memory.
This results in a permanently locked Mutex which isn't marked as poisoned. The result for end users is an infinite load, or otherwise non-modifiable state, since the Mutex will never unlock.</p>
<h2>One Solution</h2>
<p>I initially looked at “manual poisoning”, but this reasonably doesn't exist, the implementation details of poisoning and unlocking are private. So instead I wrote my own manually tracked lock, which would allow me to poison it in a panic hook. Then, I used a static variable to track a global instance that is lazily initialized. When the lock is poisoned, we just recreate the instance the next time it is asked for. The result looks roughly like this:</p>
<pre><code class="language-rust">
use crate::editor::Editor;
use std::fmt::Debug;
use std::ops::{Deref, DerefMut};
use tracing::{debug, warn};
use wasm_bindgen::JsValue;

pub static mut INSTANCE: Option&lt;UnsafeAssumedSingleThreadLock&lt;Editor&gt;&gt; = None;

unsafe fn guarantee_instance() {
    if INSTANCE.is_none() {
        debug!(&quot;♻️ Create Editor Singleton&quot;);
        INSTANCE = Some(UnsafeAssumedSingleThreadLock::new(Editor::init()));
    }
}

pub fn set_panicked() {
    unsafe {
        if let Some(inst) = INSTANCE.as_mut() {
            inst.poison();
        }
    }
}

pub fn editor_guard(name: &amp;str) -&gt; Result&lt;UASTGuard&lt;Editor&gt;, JsValue&gt; {
    unsafe {
        guarantee_instance();
        match INSTANCE.as_mut().unwrap().lock(name) {
            UnsafeAssumedSingleThreadResult::Locked(existing) =&gt; Err(format!(
                &quot;lock conflict: Attempted to acquire editor lock for {} while it was already locked for {}&quot;,
                name, existing
            )
            .into()),
            UnsafeAssumedSingleThreadResult::Poisoned =&gt; {
                INSTANCE = None;
                editor_guard(name)
            }
            UnsafeAssumedSingleThreadResult::Unlocked(guard) =&gt; Ok(guard),
        }
    }
}

pub fn read_editor() -&gt; &amp;'static Editor {
    unsafe {
        guarantee_instance();
        INSTANCE.as_ref().unwrap()
    }
}

#[derive(Clone, Debug)]
enum UnsafeAssumedSingleThreadLockStatus {
    Unlocked,
    Locked(String),
    Poisoned,
}

#[derive(Clone, Debug)]
struct UnsafeAssumedSingleThreadLock&lt;T&gt; {
    status: UnsafeAssumedSingleThreadLockStatus,
    value: T,
}

enum UnsafeAssumedSingleThreadResult&lt;'a, T&gt; {
    Unlocked(UASTGuard&lt;'a, T&gt;),
    Locked(&amp;'a str),
    Poisoned,
}

pub struct UASTGuard&lt;'a, T&gt; {
    lock: &amp;'a mut UnsafeAssumedSingleThreadLock&lt;T&gt;,
}
impl&lt;'a, T&gt; UASTGuard&lt;'a, T&gt; {
    fn new(lock: &amp;'a mut UnsafeAssumedSingleThreadLock&lt;T&gt;) -&gt; Self {
        Self { lock }
    }
}
impl&lt;'a, T&gt; Drop for UASTGuard&lt;'a, T&gt; {
    fn drop(&amp;mut self) {
        self.lock.status = UnsafeAssumedSingleThreadLockStatus::Unlocked;
    }
}
impl&lt;'a, T&gt; Deref for UASTGuard&lt;'a, T&gt; {
    type Target = T;
    fn deref(&amp;self) -&gt; &amp;Self::Target {
        &amp;self.lock
    }
}
impl&lt;'a, T&gt; DerefMut for UASTGuard&lt;'a, T&gt; {
    fn deref_mut(&amp;mut self) -&gt; &amp;mut Self::Target {
        &amp;mut self.lock.value
    }
}

impl&lt;T&gt; UnsafeAssumedSingleThreadLock&lt;T&gt; {
    pub fn new(thing: T) -&gt; Self {
        Self {
            status: UnsafeAssumedSingleThreadLockStatus::Unlocked,
            value: thing,
        }
    }
    pub fn lock(&amp;mut self, description: &amp;str) -&gt; UnsafeAssumedSingleThreadResult&lt;T&gt; {
        match &amp;self.status.clone() {
            UnsafeAssumedSingleThreadLockStatus::Locked(_) =&gt; {
                if let UnsafeAssumedSingleThreadLockStatus::Locked(name) = &amp;self.status {
                    UnsafeAssumedSingleThreadResult::Locked(name)
                } else {
                    panic!(&quot;invariant&quot;)
                }
            }
            UnsafeAssumedSingleThreadLockStatus::Poisoned =&gt; {
                UnsafeAssumedSingleThreadResult::Poisoned
            }
            UnsafeAssumedSingleThreadLockStatus::Unlocked =&gt; {
                self.status = UnsafeAssumedSingleThreadLockStatus::Locked(description.to_string());
                UnsafeAssumedSingleThreadResult::Unlocked(UASTGuard::new(self))
            }
        }
    }
    pub fn poison(&amp;mut self) {
        self.status = UnsafeAssumedSingleThreadLockStatus::Poisoned;
    }
}

impl&lt;'a, T&gt; Deref for UnsafeAssumedSingleThreadLock&lt;T&gt; {
    type Target = T;
    fn deref(&amp;self) -&gt; &amp;Self::Target {
        &amp;self.value
    }
}
</code></pre>
<p>Now, in <code>lib.rs</code> I can implement the panic hook:</p>
<pre><code class="language-rust">#[wasm_bindgen(start)]
pub fn start() -&gt; Result&lt;(), JsValue&gt; {
    panic::set_hook(Box::new(|info| {
        editor_singleton::set_panicked();
        // Also give ourselves some readable stack traces, of course.
        console_error_panic_hook::hook(info);
    }));
    Ok(())
}
</code></pre>
<p>All together, this results in what I want - our instance is lazily initialized whenever accessed, allowed to be read without locking, and allowed to be written by obtaining a <code>UASTGuard</code>, which when dropped will release the lock. If <code>set_panicked()</code> is called, then the next time the instance is accessed, it will be recreated.</p>
<p>Now our WASM code can run statelessly, and if a panic happens, the editor will be transparently recreated without the user noticing more than the cost of initialization, which in Rust is rarely noticeable.</p>
<h2>Conclusion</h2>
<p>After working through this, I thought it was a pretty good test case for understanding some of the subtleties when bridging the assumptions in Rust and the assumptions in ServiceWorkers and Javascript threads. This solution feels so far like the best of both worlds. I may at some point publish some library code related to this, but in its current state it feels best managed inside application codebases, especially due to the dangerous nature of the <code>unsafe</code> blocks - you really must only use this type of pattern when you can guarantee a single threaded environment - something I can’t do from inside a crate.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>16 Aug 2024 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ cf-doh: look up DNS records from your frontend javascript ]]></title>
            <link>https://jesseditson.com/stories/cf-doh.html</link>
            <guid>https://jesseditson.com/stories/cf-doh.html</guid>
            
            
            
            <category><![CDATA[ Technology ]]></category>
            
            <category><![CDATA[ Announcements ]]></category>
            
            
            <content:encoded><![CDATA[ <p>Recently when working on <a href="archival.dev">Archival</a>, I found myself needing to check the DNS records of a domain.</p>
<h2>Background</h2>
<p>Archival Pro allows users to point custom domains at Archival sites. To enable https for these sites, we use a TXT-record based domain verifier to verify ownership before issuing an SSL. To make this process simpler, I needed to query the records to check if the CNAME and TXT records are configured correctly and show some helpful messages if not.</p>
<p>In a node.js or C-like environment this is quite simple, as each OS has a local DNS cache and lookup tools. However, I was running this in a cloudflare worker, which is actually a v8 isolate and therefore doesn't have access to the OS's dns system. In fact, even with <code>nodejs_compat</code> turned on, the <code>dns</code> library from node's stdlib will just return an empty object.</p>
<h2>DNS-over-HTTPS</h2>
<p>After doing a bit of research, I realized that the modern DNS-over-HTTPS would be a good fit for this problem, and has uses outside of my narrow case. However I didn't love any of the libraries on npm for this use case - what I wanted was something more similar to node's DNS library, which abstracts away the lookup servers.</p>
<p>Cloudflare offers a DNS-over-HTTPs solution, which you can read about here: https://developers.cloudflare.com/1.1.1.1/encryption/dns-over-https/</p>
<p>The primary downside to this API is that it can be a bit opaque to average users - the status codes are returned as numbers that map to a spec, and the response format is in Question and Answer format and includes granular data that, while useful, is overkill for most casual use.</p>
<h3>A simple package</h3>
<p>To make this easy for myself and others, I published <a href="https://www.npmjs.com/package/cf-doh">cf-doh</a>.</p>
<p>This is a simple library that makes it super simple to query records from the browser, cloudflare workers, or anywhere else that javascript runs. It depends on a native <code>fetch</code> implementation, and allows setting one if you don't already have one, so if you desire you can even run in node with a polyfilled whatwg fetch implementation - however if you're in node, you'll also have <code>node:dns</code> which is likely what you want.</p>
<p>In addition to wrapping the fetch calls, this library provides full types for the entire spec, handles quoted string responses, and converts http errors and status responses into exceptions.</p>
<p>Usage is simple:</p>
<pre><code class="language-typescript">import { queryDNS } from &quot;cf-doh&quot;;

const records = await queryDNS(&quot;_verification.jesseditson.com&quot;, &quot;TXT&quot;);

records.forEach((r) =&gt; console.log(r));
</code></pre>
<p>If you prefer a typed value, you can even import all valid record types and use them instead of strings:</p>
<pre><code class="language-typescript">import { queryDNS, DNSRecordType } from &quot;cf-doh&quot;;

const records = await queryDNS(&quot;_verification.jesseditson.com&quot;, DNSRecordType.TXT);
</code></pre>
<p>If you want to handle statuses other than <code>NoError</code>, you can instead use a lower level API:</p>
<pre><code class="language-typescript">import { queryDNSRecords, DNSRecordType, DOHStatus, DOHStatusMessage } from &quot;cf-doh&quot;;

const response = await queryDNSRecords(&quot;_verification.jesseditson.com&quot;, DNSRecordType.TXT);

switch (response.status) {
  case DOHStatus.NoError:
    console.log(&quot;This record exists!&quot;);
    break;
  case DOHStatus.NXDomain:
    console.log(&quot;Domain wasn't found&quot;);
    break;
  default:
    console.log(DOHStatusMessage[response.status]);
    break;
}
</code></pre>
<p>To add this to your project, just run <code>npm install --save cf-doh</code>. If you're curious about the source or full API surface, check out the repo:</p>
<p><a href="https://github.com/jesseditson/cf-doh">https://github.com/jesseditson/cf-doh</a></p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>18 Jun 2024 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ Life After the Con ]]></title>
            <link>https://jesseditson.com/stories/life-after-the-con.html</link>
            <guid>https://jesseditson.com/stories/life-after-the-con.html</guid>
            
            
            
            <category><![CDATA[ Politics ]]></category>
            
            <category><![CDATA[ Philosophy ]]></category>
            
            
            <content:encoded><![CDATA[ <p>SBF story arc is interesting and enlightening, despite being extremely depressing. I see him as the least sophisticated pattern matcher of this new capitalist villain we’ve seen, notably demonstrated by Trump, and Musk.</p>
<p>The pattern is:</p>
<ul>
<li>Gain trust by doing something that people will like, and avoid denying that you’re doing it for the same reasons they want you to:
<ul>
<li>Run for office (because politicians are corrupt? Sure.)</li>
<li>Start an electric car company (because you want to help reduce carbon emissions? Sure.)</li>
</ul>
</li>
<li>Do that thing disingenuously for as long as possible, making a lot of money, for instance:
<ul>
<li>Get elected and hire a bunch of obvious mid level scammers, so they can make a big mess while you do your best to siphon as much money as possible out of the position.</li>
<li>Use your position to attempt to create an equally ecologically destructive energy monopoly, this time by <a href="https://dailyenergyinsider.com/news/8079-teslas-solarcity-settles-alleged-fraud-claims-federal-government/#:~:text=SolarCity%20Corp.%20has%20decided%20to,pay%20the%20government%20%2429.5%20million.">scamming individuals directly via solar city</a> and moving the industry from oil rigs to <a href="https://www.forbes.com/sites/isabeltogoh/2019/12/17/apple-and-tesla-among-tech-giants-being-sued-over-the-deaths-and-injuries-of-child-cobalt-miners-in-drc/?sh=953a97e31079">child labor</a> and <a href="https://www.wired.co.uk/article/lithium-batteries-environment-impact">poisoning wildlife</a>. Much easier than a regulated monopoly.</li>
</ul>
</li>
</ul>
<p>The reason this works so much better than actually having a plan or doing a good thing, is that the ambiguity allows optimists from all areas of the spectrum believe that your weird behavior benefits them, so they let you continue just in case. Nobody will get what they want, but you’ll be rich and popular for a while because everyone will care about what you do.</p>
<p>In reality, you’re just running a con, but you’re also a folk hero. This is the part of the movie where the con artist hops on a train with the suitcase of money, never to be seen again, or is caught, and goes to jail forever or something.</p>
<p>However, what if you ran this con on the internet? What if you narrated the whole thing on Twitter, so you don’t really have anywhere to go? What if you felt appreciated for the first time as a folk hero, and didn’t want to shrink back into obscurity?</p>
<p>In theory, an interesting approach to staying popular after the con might be to say “I was trying to do the right thing, but the environment I was doing it in made me do the bad thing, let’s change the system” - I bet this would work well, but has the unfortunate side effect of obligating you do do anything other than run off with the money.</p>
<p>In any case, if you’re not very creative, the best you can do is to say “actually, you’re all the real idiots, I never meant to do the good thing, you just optimistically hoped that I would, but my plan this whole time has been to do the bad thing, and now you’re the suckers and should let me walk away with my winnings”.
So far, it’s unclear if this scam works in the long run, but it has been very successful so far for those two men. So much so that Elon decided to run it back and double his Tesla winnings down on a Twitter scam that looks pretty similar to his existing playbook.</p>
<p>I think you could see FTX/Alameda as a far less sophisticated version of this same con, in that Bankman-Fried was explicit about doing the good thing, and probably never even planned on doing the bad thing. So, he was able to run the con for quite a long time, because unlike Trump and Musk, nobody had a super good reason to say “look this is obviously a scam, stop being so optimistic and look at the reality” - it looked like he was doing the right thing, and he said he was, and it was making him very rich. Why would he do a bad thing when the incentives prefer a good thing?
Well, it turns out, known or not known to him, he ran an extremely over-engineered Ponzi scheme, that’s why.</p>
<p><a href="https://www.vox.com/future-perfect/23462333/sam-bankman-fried-ftx-cryptocurrency-effective-altruism-crypto-bahamas-philanthropy">This week, SBF reached out to a journalist</a> in what I can only assume is an attempt to retroactively change the narrative to become a Trump or Musk-style capitalist anti-hero. This is distinctly a different version of the post-con tactic, but I think it makes sense given his options, and probably points to him attempting to find a way to hold on to some of the cash he owes his customers. The real story here is likely:</p>
<ul>
<li>He thought he was doing the good thing, but he was not smart enough to actually understand much of anything that he was doing, which was in fact the bad thing</li>
<li>He got caught, because in this case, the bad thing was a Ponzi scheme and you pretty much always get caught when you do a Ponzi scheme, especially if you do it by accident</li>
<li>He exfiltrated some money (this is conjecture, but the only possible reason he wouldn’t do this is if he didn’t have the ability to. And I’m pretty sure he had the ability).</li>
<li>He wants to keep that money, so he’s looking for a way to put himself in the villain position now, because a large following of people saying “ooh look he’s actually very smart and planned this scam the whole time” has a higher probability of letting him keep his cash than just saying “look I fucked up”, which implies that he should be just as broke as his customers.</li>
</ul>
<p>Is it a 4D chess move? Probably not. The world of finance is pretty regulated and this scam is far too similar to a Ponzi for him to claim some bad-faith-but-very-smart credit here. I think he’ll either go to jail or he’ll go on an Assange-esque tiresome Carmen Sandiego tour of totalitarian countries until he finds a place that will give him asylum, just to troll US politicians. But in this context, the act of setting your own reputation on fire on your way down <strong>almost</strong> makes sense.</p>
<p>I’m sure the other post-con villains will have plenty to say about it too.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>18 Nov 2022 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ Don't be a 10xer! ]]></title>
            <link>https://jesseditson.com/stories/dont-be-a-10x-er.html</link>
            <guid>https://jesseditson.com/stories/dont-be-a-10x-er.html</guid>
            
            
            
            <category><![CDATA[ Technology ]]></category>
            
            <category><![CDATA[ Philosophy ]]></category>
            
            <category><![CDATA[ Economics ]]></category>
            
            
            <content:encoded><![CDATA[ <p>In software, engineers are sometimes referred to as &quot;10xers&quot; - implying that they're capable of producing 10x the productivity of a comparable person. When I was getting started in the industry, this was a bit of a goal for me. I'd like to be perceived as superhuman, and this is a pretty explicit endorsement of that. I'd sometimes work a little (or a lot) extra just to prove that I could do more than my peers. One guaranteed way to 10x is to work 10x the hours.</p>
<p>Over time, I did end up being what I call a &quot;feature 10xer&quot;. I could often produce, measurably, 10x the amount of code or features than other people on my team. I wouldn't often produce 10x the reliability, but I'd certainly make the CEO and PMs happy, which was my goal. This also meant sometimes hacking through systemic problems (getting to the root of issues isn't fast). At early stage startups, this seemed desirable, but came with many drawbacks.</p>
<p>At startups with older codebases, this attitude still prevailed, although it usually takes a different form: the &quot;intuition 10xer&quot; is the person who knows the codebase and hacks well enough to deftly navigate through it far faster than (otherwise extremely competent) peers. This means they're the &quot;debugger of last resort&quot;, and that they can design features in their head and then implement them without needing to change the design, since they knew all the caveats and patterns before reading code. These people also often have been entrenched in their own decisions for so long that they bear little empathy for new team members. Their intuition is so dialed into the history of this specific codebase that they can't even imagine what it would feel like not to know where everything is - everything is where it belongs, after all!</p>
<p>Both of these roles break down at critical times in the business: when you need to react to growth -- either engineering headcount, or scaling pressure from customer growth. I've observed the following common patterns:</p>
<ul>
<li>The &quot;feature 10xer&quot; creates debt faster than everyone, creating a positive feedback loop of debt. To sustain their relationships and pace, they don't have bandwidth to refine shipped work. As a result, a minimum of 10 people are needed to focus on the reactive work they leave behind. If you're lucky, those 10 people won't need to consult the 10xer to fix things, but eventually this will slow the 10xer down, which is extremely frustrating. I've observed that this is when the feature 10xer transitions into an intuition 10xer, or they leave out of frustration.</li>
<li>The &quot;intuition 10xer&quot; becomes a blocker for design and review, bottlenecking all work. You grow the team, the performance issues start coming up, and the system's complexity belongs to an individual. They get frustrated when it takes others 10x the time to fix things, but their desire to &quot;just do it themselves&quot; and fix things faster also slows the team down because they're responsible for reviewing nearly everything, and they're busy fixing things. Everyone sits around waiting for this person, contribuiting to a feedback loop of slowness.</li>
</ul>
<p>At the end of the day, if one team member is dramatically outperforming the others, you have a huge scaling issue, visible or not. If you manage to survive this phase of your company, pain is on the horizon. <strong>All a 10xer does is create 10x the work for others, either now or later</strong>. That doesn't mean that having senior people on your team is bad. But it does mean that continuing to have them &quot;go back to the dopamine dispenser&quot; for years after they've become a load-bearing decision maker results in the code becoming less and less understandable to new people as more and more decisions are made in a vacuum by someone with less and less exposure to the outside world. Inevitably, these codebases are extremely expensive to onboard and frustrating to work on, making it difficult to hire and retain new employees, contributing to the bottleneck of these individuals.</p>
<p>Instead, teams should aspire to see (roughly) equal distribution of work, with the senior people spending the &quot;other 9x&quot; on technical debt, documentation, mentorship, developer productivity, and proactive issue/complexity resolution. Arguably the most beneficial side-effect of this arrangement is that the example set by your 10x citizens are that new hires are empowered to begin their journey emulating these activities. You'll occasionally need to encourage newer people to ship imperfect things, but you won't have your 10xers shipping imperfection and your new hires cleaning up their mess - an arrangement that feels good today, but hurts your hiring and SLOs in the long run.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>16 Jun 2022 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ Software Isn't Ever Necessarily Good, No Matter How Old It Is. ]]></title>
            <link>https://jesseditson.com/stories/software-isnt-ever-necessarily-good-no-matter-how-old-it-is.html</link>
            <guid>https://jesseditson.com/stories/software-isnt-ever-necessarily-good-no-matter-how-old-it-is.html</guid>
            
            
            
            <category><![CDATA[ Technology ]]></category>
            
            
            <content:encoded><![CDATA[ <p>I was reading a delightful <a href="https://www.joelonsoftware.com/2001/07/21/good-software-takes-ten-years-get-used-to-it/">Joel Spolsky article</a> that was posted to my company Slack today - it was originally published in 2001, and I had read it many years ago. As with most of Joel's articles, I assume I nodded along and filed it away to think about. This time though, I found myself wishing it had included a bit more information.</p>
<p>The article is great, but needs some augmentation. The title of the article is &quot;Good Software Takes Ten Years, Get Used To It&quot; - a summary of the article could be:</p>
<ul>
<li>Historically, software takes a long time (years) to get to 1.0</li>
<li>Historically, software growth/adoption is exponential.</li>
<li>Historically, software is pretty low quality until it has doubled in size many times, which historically does not happen quickly.</li>
<li>Despite a lot of press, software doesn't really become good until 10 years from when someone started working on it.</li>
</ul>
<p>There's some cause/effect muddling here - for instance it's unclear to me if there's a relationship between growth and quality being implied here, but he does have a large section of helpful advice explaining some counter-productive myths and debunking them (&quot;Business Mistakes&quot;), which is certainly welcome.</p>
<p>However, the premise of the article appears to be that at a certain point in time (10 years, apparently), a piece of software is complete, and no longer can be improved. While I wish that were true, I've never seen it in the wild. So I'd like to propose an alternate theory of software completion:</p>
<h2>Software Isn't Ever Necessarily Good No Matter How Old It Is, And In Fact Most Software Shouldn't Even Try To Be Good</h2>
<p>Some definitions are in order. When I say Good, I mean (and believe Joel to mean) that <strong><em>it is software that is serving a useful, necessary, and economically self-sufficient purpose, and that the users of said software are satisfied in the software's performance and functionality such that a large majority of the users would prefer that it did not change dramatically.</em></strong></p>
<p>I believe that then the time it takes to write &quot;Good&quot; software is porportional to how complex the software is in a &quot;Good&quot; state.</p>
<p>Joel worked on Excel, and I think 10 years is a very reasonable timeline for how long I'd expect Excel to take. And I actually think that if a team of engineers were given Excel in 2001, it may have kept its feature set -- maybe adding a few parity features to take advantage of fast internet speeds and processors -- but generally people would know what it's good at and customer expectations and value could continue to be satisfied.</p>
<p>You may know that with the benefit of history, that isn't really what happened. I suspect that excel's feature list looks a lot like the chart at the beginning of Joel's article, infinitely exponentially exploding in the 20 years since the article was published. In fact, I've worked directly on an excel competitor, and even as a small part of a larger whole of features, it was always the bear when it came to complexity, and many PMs had the opportunity to make it worse by imagining what might be possible with it.</p>
<p>Perhaps this is an issue with Excel as a product (it is, after all, effectively a programming language and computer all rolled into one). But I suspect that we can extrapolate some useful lessons here.</p>
<p>A counter point may be a simple Linux program, which likely could achieve the reliability of Excel 2001 in a much shorter time period. Given the resource consumption of 0, it also is economically self-sufficient. Adoption wise, it would trend with Linux adoption, so on the same curve. I don't have a study for this, but I think our intuition can tell us that outside of <em>how much</em> more money it made than cost, a program like <code>ls</code> or <code>tar</code> roughly follows the same pattern as Lotus Notes, in a fraction of the time - as a result of it being a fraction of the complexity.</p>
<h2>Business Mistakes</h2>
<p>All this to say - to refine Joel's thesis, the temporal boundary of 10 years probably isn't that useful. In fact, a math equation probably isn't useful at all, given that the languages, features, and implementations, among other things like the backgrounds of the authors, will impact the raw values when answering &quot;how long will it take to be good&quot;. However, there are likely some much more addressible targets to help make good software, that will help answer the &quot;how long&quot; question:</p>
<h3>Is your software even capable of being good</h3>
<p>Much software I've seen built in the last 21 years doesn't even have a chance of clearing the bar I set above. It's just there to make money, and is an arbitrage tool - imagine a high frequency trading robot or the Uber app - these pieces of software are entirely bound by the markets they exist in, and cannot possibly be good for any duration of time, given that the markets they participate in are adversarial and changing. There is no feature in uber that would make drivers want to be paid the amount that uber wants to pay them. The competing forces meant the software is in a perpetual state of being bad software. To write software in this context, you'd be wasting your time if you took the time and care on every feature to refine it to being Good. The harsh reality is that more than likely, you'll just be making it harder for the business to succeed by writing Good code. I strongly suspect that a management style of &quot;plan to throw out the codebase every 2 years&quot; would be far more effective in these environments. In observing these types of companies, that often is the result regardless of the plan.</p>
<h3>When is your software good</h3>
<p>How will you know if your software is good? Who will decide? What is the last feature you will build? These are hard questions to answer in an exponential growth based economy, but I'd argue that most software these days starts out with ambitions that are not possible on a 10 year time scale. PMs are pretty liberal and young engineers are hungry to ship. As Joel noted, the myth of &quot;<a href="https://www.joelonsoftware.com/2001/07/21/good-software-takes-ten-years-get-used-to-it/#:~:text=3.%20Believing%20in-,Internet%20Time,-.%20Around%201996%2C%20the">Internet Time</a>&quot; has long been propagated - the idea that shipping more often is the same as shipping more/better software is long debunked. Slack ships hundreds of times a day and still barely works. A potential tonic for this problem is to create clear understanding of the goals across the company, which is far harder than it sounds. In fact, if you work in software, what would you consider the &quot;end state&quot; of your software if you could stop time and finish it up? If you can even answer that question, ask your PM or a coworker - did they say the same thing?</p>
<hr />
<p>In summary - after writing software the entire 21 years this article has existed on the internet, I'd offer this guide on how to write good software:</p>
<p>Determine if your software can even be Good. If so, agree on a simple feature set and improve your software for 2-5 years. At this point, you may have customers. If you do, seek to implement the minimum amount of improvement possible to make them as happy as possible. In an additional 5 or so years, it is possible that your software will be as good as Lotus Notes, one of the best pieces of software written.</p>
<p>However, I don't think most people should even aspire to write software this way. Instead, I'd offer a few alternative paths:</p>
<ol>
<li>
<p>Write less software, or software with less economic requirements. Lotus Notes is extremely complicated, and at its peak was capable of supporting a large number of employees and customers. Find somewhere on the spectrum between Lotus Notes and a simple linux utility that will satisfy your economic requirements and your timeline requirements. Or perhaps just work on something that doesn't need to make as much money. Do you really aspire to work on a team of thousands? You can't, however, build something with high complexity quickly. I suspect this was Joel's original point. Most startups fail because they fundamentally attempt to do more than they possibly can with their runway. Why not do something well instead, and fail because you were wrong that people would like it? At least that way you can write Good software before you fail.</p>
</li>
<li>
<p>Don't write good software. It's not very profitable compared to imperfect-yet-functional software and if your company is going to scale to hundreds of engineers anyway, your good sofware will drown in features. You'd need 100 years to write Uber with Good software, and in 100 years nobody is going to drive their personal car for 90 hours a week for less than minimum wage, so the software won't be able to make enough money for you to keep it running anyway. This doesn't mean you shouldn't write readable software, or that it's acceptable to not care about the quality of the software you write -- but it does mean that you probably don't need to strive for perfection, and you definitely don't need to write a platform. You can have classes that are thousands of lines long. Optimize for velocity, not quality. Maybe, if you get lucky, people will like your software enough that you can think about spending the next 10 years rewriting your software, this time writing it well.</p>
</li>
</ol>
<p>Your software is temporal, make it fit the team and customers it has now, not an aspirational target in the future. If there's demand for Good software in your space, you'll have 10 years lead time to get started.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>14 Jun 2022 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ Chesterton's Junkyard ]]></title>
            <link>https://jesseditson.com/stories/chestertons-junkyard.html</link>
            <guid>https://jesseditson.com/stories/chestertons-junkyard.html</guid>
            
            
            
            <category><![CDATA[ Technology ]]></category>
            
            <category><![CDATA[ Philosophy ]]></category>
            
            
            <content:encoded><![CDATA[ <p>Throughout my career, I've seen a lot of old code. Almost every company in Silicon Valley is started by writing some mediocre software and attempting to validate a business model without spending too much time or money on something that works well.</p>
<p>This is fine, and the amount of code that survives usually is relative to how &quot;good&quot; the code was originally - if you have the good fortune of working somewhere with no &quot;founder code&quot;, either your founder was on the lower side of the ego spectrum, or their code was especially atrocious. Which is to say, if the product survived at all and you're not in the first cohort of employees, you have probably experienced a phenomenon called &quot;Chesterton's Fence&quot;.</p>
<p>The origin of the quote is a passage in <a href="https://en.wikipedia.org/wiki/G._K._Chesterton">Gilbert Keith Chesterton</a>'s 1929 book &quot;The Thing&quot;. In a chapter called &quot;The Drift to Domesticity&quot;, he writes:</p>
<blockquote>
<p>In the matter of reforming things, as distinct from deforming them, there is one plain and simple principle; a principle which will probably be called a paradox. There exists in such a case a certain institution or law; let us say, for the sake of simplicity, a fence or gate erected across a road. The more modern type of reformer goes gaily up to it and says, “I don’t see the use of this; let us clear it away.” To which the more intelligent type of reformer will do well to answer: “If you don’t see the use of it, I certainly won’t let you clear it away. Go away and think. Then, when you can come back and tell me that you do see the use of it, I may allow you to destroy it.</p>
</blockquote>
<p>This &quot;fence&quot; comes up a lot in software, especially old or poorly factored software - and often it gets translated to &quot;if you can't or don't want to dig in to find the original purpose for something, it probably was put there for a good reason, so you should leave it alone&quot;. In large and/or high velocity codebases, this gets reduced to &quot;don't delete things you didn't write&quot;.</p>
<h2>Piles of fences</h2>
<p>Lately, I've been feeling like while I understand the intention behind this quote and find it helpful, I also find it over-applied to the point of becoming a fallacy.</p>
<p>When taken without subtlety, you could extend it to mean:</p>
<blockquote>
<p>A person, encountering a thing that actually has no use, will never be able to destroy that thing. In following this, we inevitably retain only the objects that truly have no purpose.</p>
</blockquote>
<p>I've been calling the areas afflicted by this symptom &quot;Chesterton's Junkyards&quot; - piles of old, un-owned code, that nobody is empowered to change or refactor, and that arguably at least some of it literally has no purpose.</p>
<h2>Cleaning up Junkyards</h2>
<p>The point of this blog post isn't just to complain, but also to propose a reasonable solution: If you encounter one of these junkyards, consider only the contract, and ignore the junk.</p>
<p>If you cannot reduce the offending code to a contract (e.g. it has too many side-effects, or you lack the knowledge to safely distill and replace the contract), at minimum you should file a bug to the effect of &quot;this area of code is a junkyard, and it needs to be cleaned up before it is changed&quot; – effectively encircling the area with caution tape.</p>
<p>In most cases however, these types of haphazard and unplanned pieces of code are not load-bearing. When considering the contract of a given piece of code, you will likely find that the contract is simpler than the code, and possibly even unnecessary or redundant.</p>
<p>The key difference here is that while Chesterton suggests &quot;seeing the use&quot; of something, I'd propose that many things, especially in code, truly have no use; leading us to a true paradox. But if we instead &quot;define the contract&quot; of said fence – which is to say, we just observe its current functionality instead of attempting to understand its purpose – we can much more easily evaluate if it aligns with our design goals (which likely have changed since we erected the fence), and instead of having to dig in and understand something that may not make sense in the first place, just clean up the junkyard.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>17 Dec 2021 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ What Do You Owe Your Boss? ]]></title>
            <link>https://jesseditson.com/stories/dont-let-them-tell-you-what-to-do.html</link>
            <guid>https://jesseditson.com/stories/dont-let-them-tell-you-what-to-do.html</guid>
            
            
            
            <category><![CDATA[ Economics ]]></category>
            
            <category><![CDATA[ Philosophy ]]></category>
            
            
            <content:encoded><![CDATA[ <p>Modern labor, as described by employers, is a paradox.</p>
<p>On the one hand, employers attempt to tell you that labor is a purely transactional interaction; you're on <em>their</em> time, and they get to tell you how to spend it. The product of your labor is not your concern. Leave your identity politics at home. If you're leaning, you could be cleaning. <em>These</em> hours have been bought, and no longer belong to you.</p>
<p>On the other, employers attempt to capitalize on your personality and intuition. There is an emphasis on growth in the workplace, and interviews don't measure only for current abilities, they predict how you may be a value-add to the <em>culture</em> of the workplace. Companies spend huge amounts of advertising budget attempting to prove to you that, yes, black people work at Amazon. That the workplace is a family. That the company's success is dependent on you, and therefore, you share in the company's success.</p>
<p>At the end of the day, neither is true. The work relationship in the extreme majority of workplaces is simple. You work there becuase you working there makes them more money than you not working there. Labor is the source of all value, and ironically, especially so in tech work. There are some values driven workplaces, and they are a wonderful compromise - but ultimately, if you clearly are not generating more money for the company than you are being paid, you will have a hard time working there for very long.</p>
<p>A theoretical view of tech is that it is a passive machine. That you build something somewhat analogous to a book that can print itself forever. And then, people buy that book, on a monthly recurring basis, until you have enough money to shoot yourself into space. The reality is that tech, like nearly every other thing humans create, degrades at a shocking speed, and requires a huge amount of labor just to keep functioning at a flat rate, to mention nothing of scaling or growing.</p>
<p>Labor touches everything in tech - the initial designs have downstream effects on the maintainability and scalability of a product, sales staff set expectations, preferences and intuition shape the product, and all of <em>that</em> work only puts you in a position in which bugfixes, oncall response, customer support, and directional leadership can have a chance of generating more income than they cost. If the staff of any website or app, simple or complex, walked away from it, it would cease to exist in a shockingly small period of time.</p>
<p>Folks who are early in their career can easily, as I did, believe that their job is to build a building that will stand forever, and that the value generated by these high-leverage actions will grow over time exponentially. But the reality is that exponential software growth is tightly coupled with exponential labor growth. Some of this is linked to application complexity, a topic for <a href="/application-complexity">another post</a>. There are outliers, but this trend is unavoidable.</p>
<p>What does this mean for the labor? It means that despite how much your employer may try to convince you that they know what is best for you, your peers, and the codebase, they always <em>must</em> weigh their ideas in this area against the equation of labor to value - so no mandate by an employer is made entirely in good faith, unless your sole goal at the company is to make your employer a lot more money than you make. I know few if any people who fit that description.</p>
<p>Tech workplaces (along with a growing number of other industries), despite needing to make money, have an interesting secondary effect of being wonderful places to grow your skills, because labor makes all the important decisions. I've certainly watched managers attempt to design software, but at the end of the day, every single decision that directly impacts the functionality of a product is made by someone working at an individual contributor level. This means that quality directly correlates with intuition - even the most hands-on micromanager cannot attempt to control every line of code you write. And as all software programmers know, every line makes a difference in maintainability, scalability, and functionality.</p>
<p>How does this effect your job? It means that if your company is being run correctly (which it likely isn't), you and your employer can form complimentary incentives: your employer wants you to cost less than you make them, and you want your intuition and decision making skills to be better (and worth more) than when you were hired. There is, however, a catch.</p>
<p>The catch is that to make your intuition and decision making skills improve, you have to use them. There are no pure problems in consumer software, everything you do must be both guided by computer science principles <em>and</em> an intuition and awareness of the problems you are solving at work.</p>
<p>Therefore, <strong>if you work from a list of JIRA tickets that you don't necessarily understand, if you execute against an OKR that you can't explain why it is important, or if you don't know why the thing you're doing is important to the company, you are being taken advantage of. You are generating more value than you are being paid, and you are not receiving any additional benefit</strong> (beyond your salary, which we've already shown, will only be paid to you if it is less than your value).</p>
<p>This type of abuse is both rampant and fairly easy to avoid. Simply, don't let anyone tell you what to do. If presented with a task, ask yourself: &quot;do I agree with the goals of this task? Do I want to do this task? Does this task contribute to my growth and the success of the company?&quot; If the answer is no, politely decline and ask for more information. It's possible you misunderstood the task and just need clarity, but more likely that you're the first person to ask this question about the task, and in doing so you will both improve your personal prospects, and contribute immense value to your employer.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>28 Oct 2021 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ The Simplest CMS, Part 1 ]]></title>
            <link>https://jesseditson.com/stories/simplest-cms-part-1.html</link>
            <guid>https://jesseditson.com/stories/simplest-cms-part-1.html</guid>
            
            
            
            <category><![CDATA[ Technology ]]></category>
            
            
            <content:encoded><![CDATA[ <h3>What is the simplest &amp; cheapest CMS possible?</h3>
<p>As someone who works in tech, I'm often asked to &quot;build a website&quot;.</p>
<p>When asked this question, I always try to learn a bit about what they expect the website to do.</p>
<p>What a non-tech person means when they ask this question is usually:</p>
<ul>
<li>Someone types a url into a browser, and sees something special that works as well as other websites but looks more unique and personal than something like a template.</li>
<li>The content on this website follows some common patterns. There's an about page or similar, a listing page containing a potentially infinite, but realistically quite small, list of objects. Maybe they're posts, photographs, or items for sale.</li>
<li>Search, if it exists, is quite small. It's not often that someone asks for their content to be globally full-text searchable.</li>
<li>Being able to update the content whenever they like is imperative. They don't want to learn a complicated system, they would prefer that it were as easy as posting to Facebook.</li>
</ul>
<p>I've spent a lot of time, in short durations but over a long period of time, trying to build a system that satisfies these requirements, but is neither expensive to maintain nor complex to use.</p>
<p>This blog is one of the attempts - and in this case, I attempted to delegate as much as possible to an existing, maintained system (docusaurus). However, the approach I used here requires fairly strong familiarity with github and markdown, but passes the cost and simplicity requirements with flying colors.</p>
<h3>Over Engineering</h3>
<p>One approach I took to this was quite involved, and used the following setup:</p>
<ul>
<li><a href="https://parceljs.org/">Parcel</a> to build the frontend</li>
<li><a href="https://hasura.io/">Hasura</a> (running on <a href="https://heroku.com/">Heroku</a>) for the database (which is <a href="https://www.postgresql.org/">Postgres</a> under the hood), API, and authentication layer</li>
<li><a href="https://graphql.org/">GraphQL</a> queries for CRUD between the frontend and the database</li>
<li><a href="https://docs.docker.com/compose/">Docker Compose</a> for running Hasura &amp; Postgres locally</li>
<li><a href="https://netlify.com/">Netlify</a> as a CDN, for DNS management, and for serveless functions, which are primarily used for generating JWTs.</li>
</ul>
<p>The goal here was to leverage a shared db to scale this model fairly cheaply, but still has the downside of authenticated transactions on every load. Scaling this could be potentially problematic at the DB level (although realistically, I'd expect the audience of this product to be relatively small). But most of all, it just felt very heavy weight for something that was supposed to be small. It's an interesting idea for something maximally complex, but I realized that the core interaction needed by the person adding content to the website is just the ability to organize lists, add objects to the list, and update content on static pages.</p>
<p>This blog has nearly the same interaction, but since it's built on docusaurus, has a bunch of unrelated and difficult to modify features.</p>
<h3>A Project</h3>
<p>After deciding the above approach was too complex for the problem it was solving, I started thinking about a much simpler CMS that follows some common yet new patterns in the industry. It would be composed of the following pieces:</p>
<ul>
<li>The website would be entirely contained in a git repo. All content would be represented by static files in a human-readable format.</li>
<li>When the content changes, a CI job (<a href="https://github.com/features/actions">Github Actions</a>) would compile it to a static website.</li>
<li><a href="https://netlify.com/">Netlify</a> would act as a CDN, and handle DNS.</li>
</ul>
<p>This is how this blog works, for the most part. The DSL is markdown, and this site isn't very flexible in terms of object types. Pretty much only blocks of text are supported. And it still has some problems:</p>
<ul>
<li>You have to know how to use Docusaurus to modify the layout, which leaks to React, Babel, and Webpack knowledge.</li>
<li>You have to be able to confidently edit the content in a git repo (alongside the source) and generally understand git to update it.</li>
</ul>
<p>So, I think the simplest CMS would add two personas to the stack:</p>
<h4>1: Setup</h4>
<ul>
<li>The site would define one or more editable schemas that define an object type.</li>
<li>The site would define one or more simple html layouts and a page layout. The simplest and/or most common templating language should be used here.</li>
</ul>
<h4>2: Update</h4>
<ul>
<li>The site would provide a dedicated interface for adding new files to folders corresponding with the schemas defined at the site level. These would produce the listed objects that the above talked about.</li>
<li>The site would provide a dedicated interface for editing page-level content.</li>
</ul>
<h3>Proposal</h3>
<p>When complete, the goal of this project would be to allow a person with mid-level knowledge of html and git to create a website that was completely custom, with simple schemas. This allows for maximal flexibility while still keeping things relatively simple.</p>
<p>If the site is set up in a standard way, a single desktop/mobile client or website will be able to connect to this git repo using Github OAuth or standard ssh/https git authentication, and edit any website built this way. It would simply edit the schemas defined by each website, and central documentation would track the available scalar types for each of the schemas.</p>
<p>The HTML would simply layout and render the content of the schemas based on their scalar types, but the scalar types can expand to be quite complex, for instance media players or observable notebooks could be embedded using simple definitions.</p>
<p>The build step could be centrally developed and versioned, allowing the boilerplate for this type of website to be very cheap.</p>
<p>Finally, since this repo will be a simple static website, it can be deployed to any of the myriad static website hosts that are available, making administration of some of the harder parts of DNS and CDN quite manageable to someone with little knowledge of the underlying systems.</p>
<h3>Next Steps</h3>
<p>It's possible that I won't build this. But if I do, I'll need to choose some initial parameters:</p>
<ul>
<li>Which static site host to target first (probably Netlify)</li>
<li>Where to run the shared generation code (probably Github Actions)</li>
<li>Which html templating language to use (unsure)</li>
<li>How to build the client (Web tech with WASM bindings for shared business logic if it gets complex)</li>
<li>What scalar values to support</li>
<li>Where/how to build the docs (probably just use the same tech as the CMS)</li>
</ul>
<p>If and when I make progess, I'll update this blog.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>17 Oct 2021 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ About this Blog ]]></title>
            <link>https://jesseditson.com/stories/about.html</link>
            <guid>https://jesseditson.com/stories/about.html</guid>
            
            
            
            <category><![CDATA[ Announcements ]]></category>
            
            
            <content:encoded><![CDATA[ <p>This collection of articles is written by me, Jesse Ditson.</p>
<p>I live in Joshua Tree, California, in the United States.</p>
<p>I spend my time making music, reading, writing, building and growing things, and taking care of my home and the earth around me the best I can.</p>
<p>I can be reached at <a href="mailto:jesse.ditson@gmail.com">jesse.ditson@gmail.com</a>, if for any reason you desire to speak with me.</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>06 Jan 2021 00:00:00 +0000</pubDate>
        </item>
        
        <item>
            <title><![CDATA[ Making A Demogorgon ]]></title>
            <link>https://jesseditson.com/stories/making-a-demogorgon.html</link>
            <guid>https://jesseditson.com/stories/making-a-demogorgon.html</guid>
            
            
            
            <category><![CDATA[ Projects ]]></category>
            
            
            <content:encoded><![CDATA[ <p>[originally published on Medium in 2016]</p>
<p>This halloween we decided to stick with pop culture and try a Stranger things costume.
I started it the same way I start every year, by taking screen caps, measuring everything, and scaling everything to my height.</p>
<p><img src="../img/demogorgon/sketch.jpg" alt="Sketch and reference image" /></p>
<p>For this costume, I wasn't too worried about the proportions, since I was going to be just painting a morphsuit for the body. I figured I'd draw up a slightly more human-like version to play with some ideas too.</p>
<p>The most difficult part was obviously the mask, so I did some searching around for inspiration and found a great tutorial that I stole most of the techniques from: http://ellimacs.com/stranger-things-demogorgon-halloween-costume-tutorial/</p>
<p>However, I wanted a mask that I could take on and off, didn't want a long application process (if any), and I wanted to do a better job matching the proportions on the show.</p>
<p>First, using my measurements and screenshots as a guide, I made an armature for the mask and covered it in masking tape, a layer on each side.</p>
<p><img src="../img/demogorgon/armature-wire.jpg" alt="Mask Armature Wire" />
<img src="../img/demogorgon/armature-tape.jpg" alt="Mask Armature with Tape" /></p>
<p>I used the technique in the tutorial to make the teeth. In my case, it took pretty much exactly a whole bag (6 oz) of Instamorph Moldable Pellets when it was all said and done.</p>
<p>I found that microwaving the plastic and visually watching for them to become clear wound up yielding more easily moldable blobs than dropping the dots in water like the instructions on the bag says.</p>
<p>Be careful and keep the temperature as low as possible while still making the plastic completely transparent. Watch out for superheating the water, which could cause a rapid boil when disturbed. Basically, never heat for over 90 seconds or so.</p>
<p><img src="../img/demogorgon/teeth.jpg" alt="Teeth" /></p>
<p>The teeth pretty much form themselves when you cut them off a strip of plastic, a pretty neat technique.</p>
<p><img src="../img/demogorgon/painting-1.jpg" alt="Painted Morphsuit Leg" />
<img src="../img/demogorgon/painting-2.jpg" alt="Partially Painted Morphsuit" />
<img src="../img/demogorgon/painting-3.jpg" alt="Finished Painted Morphsuit" /></p>
<p>The body was just a grey morphsuit, painted with acrylic. I alternated back and forth between making teeth and painting coats on the morphsuit.</p>
<p>I used a large wide brush and thin layers of dry brushing to get a nice &quot;burned&quot; kind of look to match the monster in the last episode, when we get the best look at it. On the shoulderblades and chest, I left some negative space as highlights to give it a bit more of a textural feel.</p>
<p><img src="../img/demogorgon/face-hole.jpg" alt="Face Hole" /></p>
<p>Next, I moved on to the mask. I used an exacto to cut out a face-sized hole, after measuring right around my eyebrows to just below my mouth.</p>
<p><img src="../img/demogorgon/tape-hood.jpg" alt="Tape Hood on Mask" /></p>
<p>I then folded the flaps inside, and created a duct tape flared ring on the inside of the mask. I then laid tape sticky-side out around a head-sized balloon to create a helmet-like attachment to the back of the mask so I could wear it like a hat.</p>
<p><img src="../img/demogorgon/latex-1.jpg" alt="Latex painted on mask" /></p>
<p>I mixed some latex with flour and food coloring, which on the first try was a cottage-cheese-like mess. The latex I used had been around since last year, so I think it was a bit thicker than I'm used to. I spread it on the mask anyway, and after waiting a few minutes for it to firm up, planted the teeth directly in the latex.</p>
<p><img src="../img/demogorgon/latex-2.jpg" alt="Latex painted on mask" /></p>
<p>The second batch of latex was with a different, much thinner latex and flour, which I mixed to a predictably over-compensated thin paste. It ended up being a bit difficult to work with, and the teeth had a hard time getting purchase on the thin coat of latex.</p>
<p>Lesson: it's worth it to focus on pancake-batter consistency before pouring that shit on the mask.</p>
<p>I intentionally saved the big &quot;wings&quot; for last, as I figured I'd get better with practice, and I wanted the wings to be really solid. I finally nailed the latex consistency and got some really nice, scary looking teeth on both sides:</p>
<p><img src="../img/demogorgon/latex-3.jpg" alt="Latex painted on mask" /></p>
<p>A lot of guides that I've read seem to be convinced that latex dries a lot faster than it does. All said and done, each piece with more than ~1/4&quot; or so of latex took a minimum of 48 hours, and up to 4 days to dry completely, so plan accordingly or go with thinner layers (and expect to have to reinforce the teeth…)</p>
<p>I then set up a cast for the inner face part by using an old face cast that I made years ago, (originally used in a Dr. Doom costume, hence the silver + rivets) which I re-use pretty much every year for anything that needs to form to my face decently.</p>
<p><img src="../img/demogorgon/face-cast.jpg" alt="Face Cast without plastic" /></p>
<p>I generally just used a lot of tape and cardboard to make a decent little bowl, then lined it in saran wrap, and covered the whole mess with a bunch of vaseline so I could pull the saran wrap off when finished.</p>
<p><img src="../img/demogorgon/face-cast-2.jpg" alt="Face Cast with plastic" /></p>
<p>I then made up another batch of latex, but added both red and black for a darker color.</p>
<p>I smashed it in there, leaving some rough eye and mouth areas, added some teeth for good measure, and let it dry, which took a solid 48 hours at least.</p>
<p><img src="../img/demogorgon/face-cast-3.jpg" alt="Face Cast with latex" /></p>
<p>Your mileage may vary, but ultimately I think I prefer using acrylic to color the latex rather than food coloring, which all ended up being a bit brighter and more pink than red and more blue than black. I ended up having to touch up the mask quite a lot with acrylic when finished cause the colors kind of sucked.</p>
<p>By this time the front of the mask had dried, so I did some touch ups. Some of the teeth weren't staying in great on the too thin or thick areas, so I super glued some of them, and painted on a bunch of mod podge, which had the added benefit of giving the mask some wet-like shininess.</p>
<p><img src="../img/demogorgon/fix-teeth.jpg" alt="Fix Teeth" /></p>
<p>I painted the back of the mask with a thin latex coat. You can see the &quot;black&quot; food color is a complete joke.
After that was dry, I painted the back with acrylic, then glued in the center part of the mask with mod podge on both sides after a test fit to make sure I could see well.</p>
<p><img src="../img/demogorgon/back-1.jpg" alt="Back of Mask without paint" />
<img src="../img/demogorgon/back-2.jpg" alt="Back of Mask with paint" />
<img src="../img/demogorgon/front-dry.jpg" alt="Front of Mask" /></p>
<p>I also chopped off the ends of the fingers and made eye &amp; mouth holes in the morphsuit so I could drink and see. I rarely am able to on halloween, so it was nice to make something that I could leave on for extended periods of time.</p>
<p>To get the creepy hands, I just grabbed some finger extensions and painted them black. I tried using some shitty paint on my mouth and exposed fingers, but it rubbed off pretty much immediately. I'll explore other options tonight for better hiding my mouth &amp; fingers, but out on the dark street it was very convincing even without eyeblack.</p>
<p><img src="../img/demogorgon/full-body-1.jpg" alt="Full costume with arms crossed" /></p>
<p><img src="../img/demogorgon/full-body-2.jpg" alt="Full costume" /></p>
<p>As a final step, I bought a bunch of K-Y Jelly and fake blood as well, which I'll use to make the face a bit more drippy/gross.
I'll be wearing it around SF this weekend, say hi if you see me!</p>
 ]]></content:encoded>
            
            
            
            
            
            
            
            <pubDate>26 Oct 2016 00:00:00 +0000</pubDate>
        </item>
        
    </channel>
</rss>
