Scaling down native dev
In short: I want to build low-road applications for myself. They will have a very narrow function. I may use them for as little as a week or so, finish the task at hand, and move on to the next thing. Think about it like Simon Willison’s work using Claude to generate tools.
This feels like it demands something besides my usual full-stack web app (i.e., Rails) approach1:
- I would like to launch these apps instantly and operate on local data.
- In particular, files and folders; not database rows.
- I would rather not dig up a folder or terminal to run these applications; they should launch like I’d run anything else (i.e., via Raycast).
Tauri seems like it fits the bill here. It wraps a native web view in a small platform-specific host application. The “host” application is a Rust program that wraps a platform-specific web view, e.g., Safari on macOS. You can write native code in Rust, web/front-end code in HTML/CSS/JS, and easily call functions between them. In other words, a better Electron.
Strengths become weaknesses. In theory, “JavaScript everywhere” is a lovely concept. One language across the web, backend services, command-line scripts, embedded systems, even desktop applications. In practice: it’s a thousand cuts, especially if you’re trying to avoid accepting the whole JS build system/framework ecosystem into your life. Which I was, in this case.
It’d be extremely great to have Deno save the day here. Write backend/host-native or front-end code in JS and very little need to drop to Rust. In practice, it doesn’t seem like anyone is doing that. 🤷🏻♂️
What I want to build for myself is a gizmo for re-categorizing my old blog posts. These are all hosted on Micro.blog as of this year. Because of idiosyncrasies in the Micro.blog API, interacting with all posts seems to require using XML-RPC. The REST+JSON APIs don’t provide access to more than one page of posts, so they’re unsuited to working with one’s entire blog archive2.
Doing this from JavaScript, running in the web view, is where I ran into troubles. All the libraries I found assumed the code is hosted in Node, which maybe would have been fine. Node isn’t drastically different from browsers in this regard, if I understand correctly. Except that loading the actual library used the Node require
mechanism instead of the browser-based import
mechanism. And, it’s been a minute since I cared about the details of code loading in JS (did I ever really care?). It wasn’t really the problem I wanted to solve, so I “just tried things”, despite this being one of my pet peeves about how intermediate-level developers work.
Reader: I was not feeling like a badass user at this point.
I wanted to write some tests with Jest. But, Jest deeply assumes you’re using some kind of code transformation (webpack, Babel, etc.) scheme. Which I was trying pretty hard to avoid. I did get a very basic test working, but I didn’t feel good about it.
I might consider using QUnit and live with in-browser tests if I choose “no build step” as a tent pole principle on a real project.
Long story short, I did manage to get an XML-RPC call working from a test in Jest. I never tried integrating it into the web-view code. I fought the module system enough for the week. Maybe if I revisit this approach, I’ll get my story straight here. 🤷🏻♂️
My next foray was attempting to write the networking calls to Micro.blog in Rust. I’ve previously struggled with Rust in the form of extended arguments with the compiler. I like the idea of the language, type system, and lifetime/borrowing scheme. But taken together, I haven’t yet reached a place of confidence working with it. My last serious attempt at using Rust, several years ago, was stymied by a combination of generics, number towers, and getting lifetimes right.
I did not run into those particular challenges this time around. Armed with an LLM, it feels better than several years ago! I didn’t spend the whole time arguing with the compiler. With Claude 3.5 Sonnet (IIRC), I was able to get a rudimentary XML-RPC call working.
I’m in favor of writing the backend/host-executed stuff in Rust. The jury’s still out on whether this is a plausible approach. I’ve never argued with the Haskell compiler about, e.g., JSON and walked away with a successful compilation.
pico.css
is perfect for my needs. I included it with a link tag and mostly used classless HTML tags. That’s about it. No scheme of semantic, functional, or utility class names to learn. No build step. It’s good enough that looks aren’t the weakest link or distracting. That’s a good tool.
Similarly, I tried using Alpine to layer some interaction logic into the UI. I got hung up on declaring a data structure and then using it from any old element. I think this was a load order issue or misunderstanding on my part. Instead, I should have tried starting with basic interactions and then gone for the fancy stuff.
The verdict, after a few hours of hacking:
- Tauri has a lot of promise for problems shaped like “I want to build a quasi-native desktop app, but I would rather not get caught up in native ecosystems”.
- Rust, in combination with LLM copilots, is easier to navigate than it was without them and I spent less time arguing with the compiler than I’d feared I would.
- Small, low-customization CSS libraries: they’re good for me!
-
Previously: I learn new tricks. ↩︎
-
I’ve explored this a few times and come up with the same answer. I’d love to be wrong about this! ↩︎
A bag of vignettes
From that point on, well, there’s only one, maybe two great nail salons in Amsterdam.
I was rewatching Ocean’s Twelve, because empty calories and fantastic faces. Having watched it a dozen times, I was struck by how it doesn’t fit together like a Major Motion Picture.
Many of the scenes are vignettes. They’re structured around one as little as one laugh or minor plot beat, like I’d expect from an unscripted show. Especially in the back half of the movie, many of the scenes watch like they’re built around a single punchline, often with background action advancing or distracting from the heist-puzzle.
I know this isn’t High Art or Cinema™️, but I love it.
Throw more books
Simon Sarris, Reading Well:
You should start many books and complete few. You should never feel beholden to completing them, there are simply too many worthwhile works to read.
I’m a completionist. I don’t like leaving books, let alone series of books, unfinished. But, endorsements from Sarris (and Austin Kleon) on leaving books unfinished, possibly by throwing them across the room, is a strong-enough signal. 🙃
🔥I wish I’d heard this advice when I was reading The Black Swan.
Hot-takes on web browsers
- Safari is (on macOS) the only good application and web browser. Chrome is a remarkable feat of engineering but a mediocre application.
- Arc is extremely promising. Reimagining the shape, function, and purpose of a web browser for our current computational surplus is a worthwhile endeavor. On the flip-side, I hope that grassroots efforts like the Ladybird browser and browser jams will produce more diversity in how browser engines operate and what it means to construct a browser engine in the first place.
- Web browsers, as application platforms and as document viewers, are an incredible technological accomplishment. Trillions of renders per day, things mostly work, and the security/sandboxing model works without embarrassing flaws. Viewed over years and decades, progress in web browsers has been remarkable.
To paraphrase Winston Churchill, web browsers are the worst cross-platform application framework except for all the other ones that have been tried.
Six one-liners on meetings
- Make a better meeting when you can, and the best of a meeting when you can’t.
- The choice to avoid holding a meeting may snowball into problems that require even more meetings.
- Ensure every meeting worth the person-time, assuming organizational dynamics allow for it.
- Recurring meetings have to earn their continued existence.
- Steer meetings away from sidebars, confusions, digressions, and distractions.
- Meeting are an opportunity to go deeper than documents and chats allow.
Bonus: meetings are the work.
Pen, paper, and a problem
Ben Brooks, Thinking Analog:
The way this works is simple: use a notebook and a pen when you need to work through a problem of any kind.
Not a tablet with a stylus. Not a notetaking app. Not a pencil. Paper and pen.
…
I typically juice the cycle by writing a heading, a date, or any one liner associated with what I want to think about to get things moving. From there the mess happens, scribbles and words. They are disjointed but reconfigured with arrows. In all of that, my thinking solidifies, and the idea takes hold.
(via Patrick Rhone)
Endorsed! Apps, “tools for thought”, etc. are great – don’t get me wrong. But, we all contain multitudes.
Some issues are well-defined and suited to computer-thinking. Other problems are wily and demand a hands-on approach. These thrive on “offline” thinking, gesturing to ourselves, thinking aloud, feeling the texture of paper, and engaged limited interaction modes (🤓).
Previously, taking notes on paper vs. glass:
The sensation & constraint of paper still beats glass. There is something about the resistance, the scratch, of a good pen across a finite sheet of paper. It’s easier for me to write “well” (opinions on my penmanship vary) on paper than on glass; something about the permanence of the ink or that my eyes are considerably higher resolution than glass displays. Filling notebook after notebook over the years and decades is vastly fulfilling in a way digital notes and writing aren’t.
Every day counts (even edits)
George Saunders, A Swim in a Pond in the Rain:
“What does an artist do, mostly? She tweaks that which she’s already done. There are those moments when we sit before a blank page, but mostly we’re adjusting what’s already there. The writer revises, the painter touches up, the director edits, the musician overdubs.”
I’m filing this one away for future reference when I’m feeling less-productive. Even if the day’s toil was tweaks, edits, rewrites, or failed rewrites, it checks the box.
Austin Kleon, A Few Notes on Daily Blogging:
“With blogging, I’m not so sure it’s about quantity as much as it’s about frequency: for me, there’s something kind of magical about posting once a day. Good things happen. Something small every day leads to something big.”
But also this! Frequency generates as much quality as does quantity. Show up, every day!
Jam session
At its best, social media is like jazz — there’s an improvisational, multi-player quality to it. Following threads, riffing, and quipping creates a collaborative rhythm all its own. I love that!
Then, add in the “threaded style” of social media writing and thinking. There’s a give-and-take, a call-and-response. Ideas build on each other, it’s even more like jazz.
Sometimes, riffs are refined via “collaborating with the network” to the point they become coherent, standalone ideas. And, like an improvisation becoming a composition unto itself, they become standalone essays. Fantastic.
Related: I miss Layer Tennis.
Related: jazz as cinematic universe.
All roads lead me to maximalism
Within me are two musical opinions, constantly at tension.
😇 “You can make pretty dang good music with only a few, excellent musicians. Sometimes, even pretty dang good and loud music.”
🤵🏻♂️ “Look, if you want to make dang good and loud music, you’re gonna need a twenty-person band or a Mahler-sized orchestra, at least. Amplifiers and drum kits are crutches. The true path to volume of sound is volume of performers.”
Lukewarm water on a hot day
Henrik Karlsson, Swimming in July:
There is something so frivolous about water. It makes you float like you are in outer space! And no matter what you do—whatever shape you make of yourself—it will instantly fit itself around you!
Water didn’t have to be this good.
You forgot it for years while you lived in the city. But here it is: that one day in July when it storms but the water is lukewarm and you tumble inside the waves. You lose yourself in the sensation of being a body submerged in another body. Your back against the concrete pillar under the pier; the waves cresting, crashing over you—you can do this for hours.
Nothing beats a soak, in a pool or otherwise, in the heat of July (and August).
“Try jumping from the cliff over there,” the guard would say. “And then you shape yourself like a cannonball before you hit the surface.”
Mind the attention traps
Alan Jacobs, The Homebound Symphony:
Station Eleven had the Traveling Symphony: I’m trying to be the Homebound Symphony. Just one person sitting in my study with a computer on my lap, reading and listening and viewing, and recording and sifting and transmitting – sharing the good, the true, and the beautiful, with added commentary. The initial purpose of this work is to repair, not the whole culture, but just my own attention. On a daily basis I retrain my mind to attend to what is worthy. It is the task of a lifetime, especially in an environment which strives constantly to commandeer my attention, to remove it from my control, to make me a passive consumer of what others wish me to look at or listen to.
Take care to monitor your attention, especially regarding social media. It’s easy to get lost in nostalgia and repetitive feedback loops. Make sure that at least some of your influences – be they people, feeds, or algorithms — encourage a forward-looking, forward-thinking mindset. Otherwise, you risk stagnation, cycling through the same thoughts and experiences.
Jazz as cinematic universe
I love when jazz album covers list all the players. Herbie Hancock! Your favorite drummer. A couple of sax players you think are pretty good. A bassist you’ve never heard of!
It’s a bit like Marvel comic book covers: “Iron Man, okay I’m interested. With Thor? Okay that works. Wolverine? And introducing an ‘Ant Man’? Okay what’s going on here – I gotta know!”
Jazz and comic books are more alike than you’d expect. Both revolve around a densely connected cast of characters, epic story arcs, a few cash grabs, and some amazing cross-over events.
Wherein this old dog learns new tricks
I’m dabbling in building, again. I felt the energy of XOXO for nostalgia of a web of the past, making one’s own thing, and indulging in (socially good) weird whilst doing it.
It’s been a while since I built a Rails app from scratch, and I don’t have a big, ambitious business plan to go with. So a blog seems like a fine place to start. 🙃🤷🏻♂️
Vibes and observations follow.
Document-style editing in browsers is a reality
I’m tinkering with ProseMirror as an editor. I’m curious what setting a Very High-Quality bar looks like for an individual developer in late 2024. In short, it seems like document-style editing in web browsers (i.e., not Markdown or hobbled “click-to-style” editors) are close to table stakes for high-quality applications. There are many options out there, it’s probably time to get good (at one of them).
The default for new Rails app is to use import maps for managing JavaScript dependencies. However, ProseMirror’s docs assume you’re using a bundler like esbuild
. In particular, ProseMirror wants to import stylesheets into scope via JS imports
and not CSS @import
. AFAICT, importmap doesn’t gracefully bridge this gap. I’d love to be wrong about this!
I considered using TipTap as a wrapper around ProseMirror. A few things put me off:
- I’m generally wary of open source and component systems with a pricing page. I want to build, not decipher plan structures. I’m not opposed to the phenomenon entirely, but I would rather not join the vanguard of using it either.
- I like the idea of going back to less build tooling for JS. But most of these component libraries, TipTap included, are React-centric. I’m not sure how to win here.
- Some component libraries support React and Vue. My understanding is the latter doesn’t always require a build step. Again, I don’t know how to win here.
Data narratives
I like the idea behind Oaken as an object mother/fixtures replacement. In particular:
- Telling stories instead of describing isolated data is a winning pitch.
- Building upon Rails’ idea of seeds and using it for development and testing is worth trying!
- I don’t have any beefs with FactoryBot, but Oaken imposes less syntax and only a slightly different mental model, which seems like progress.
Kasper is building a track record as a Rails developer with a good sense of taste!
I like class-less CSS frameworks
My CSS skills are “barely good enough”. I’d like to master Tailwind or CSS, in an ideal world. I like that idea better than carefully coding up a UI via Swift, in theory. In practice, I’m the ideal audience/user for mvp.css. Write HTML that mostly makes sense, get on with the building. 🤷🏻♂️
Markup
I have forgotten so much about using ERB, Rails form helpers, and HTML together. 🤷🏻♂️
That’s it, for now.
On Founder Mode
Founder Mode. The discourse (algorithm) demands we discuss it.
My hot-take: the original article is, honestly, not PG’s best work and is best viewed as a jargon land-grab. That said, pointing to a blank space (fancy word: lacuna) and saying “there’s something missing here, and I have a name for whatever it is” is slightly productive. 🤷🏻♂️
I’m a relieved that, so far, the discussion is about execution and thinking. It’s not about power dynamics and executive victimhood (🙄). Excessive org flattening, overloading managers with dozens of reports, and “efficiency” aren’t central to the discussion. Hopefully, those are forgotten trends of late 2022. 🤞🏻
Kent Beck points out that all leadership interventions on work-in-progress, from higher-status individuals in particular, yield a new mindset in which the team/startup operates. Neglect this tradeoff at your own peril. 👍🏻
Rands in Repose focuses on the philosophy that leadership comes from everywhere in a startup. Everyone is accountable for improving the product and company__. The org chart and hierarchy are, to some extent, guidelines and not rules. 💪🏻
How I write on the web, in 2024
My approach to writing on the web in 2024:
- Write (to think, riff, share, or publish) every day.
- Post anything over about one hundred words to my blog. Don’t worry about scheduling, publish when it’s done.
- Every couple weeks, schedule up a bunch of social posts. Some of these are links to the blog posts from the past couple weeks. Many are ideas I haven’t figured out how to turn into longer posts yet.
- Every month or so, roll up all the stuff that went out to socials and blogs in a newsletter.
Robin Sloan, Stock and Flow:
You can tell that I want you to stop and think about stock here. I feel like we all got really good at flow, really fast. But flow is ephemeral, while stock sticks around. Stock is capital. Stock is protein.
And the real magic trick is to put them both together. To keep the ball bouncing with your flow—to maintain that open channel of communication—while you work on some kick-ass stock in the background. Sacrifice neither. The hybrid strategy.
Jim Nielsen, Blog Posts vs. Social Posts:
Generally speaking, the attention you get with a good post on social media is like a firework: it can light up fast and burn bright, but just as fast it disappears.
On the other hand, the attention you get from a good blog posts can be like a forest fire: it starts small but when it catches fire it rages for some time, burning longer and more intense than any firework.
Matt Webb, 15 rules for blogging:
Give up on trying to be popular. I try not to filter myself based on what I believe will be popular. Some of my favourite posts get ignored. Some posts get popular and I have no idea why. Besides, terrible posts get buried fast if I’m posting three times a week. So post with abandon.
Give up on trying to be interesting. Readers will come to my site for what’s interesting to me, or not, it’s fine, just say what I think about whatever I’m thinking about.
Less waste, equal haste
If you waste less time, you’ll make more stuff without increasing time outlays.
- Find more leverage, you’ll make more stuff in the same amount of time
- Get better & faster at a task, it will cost less, you can do more of it (see below)
- Figure out where anxiety, dawdling, etc. happen and how to bypass it; less wasted time, more fruitful time
But don’t eliminate waste. Or, deity forbid, margin.
This isn’t about optimization and efficiency. There’s plenty of time to recapture from outright mis-use of time and space.
Nor is it about reducing waste to zero. It’s difficult to tell the difference between waste, play, and escaping local maximums in the moment.
Note to self: next time I’m tempted to get up just a little earlier or stick with work just a little later, ask myself what I did that was obviously a foolish use of resources.
Squeeze shortcomings before squeezing schedules.
James Somer, Speed Matters: Why Working Quickly Is More Important Than It Seems
“The obvious benefit to working quickly is that you’ll finish more stuff per unit time. But there’s more to it than that. If you work quickly, the cost of doing something new will seem lower in your mind. So you’ll be inclined to do more." (James Somers, Speed Matters: Why Working Quickly Is More Important Than It Seems)
Dan Luu, Some reasons to work on productivity and velocity:
It’s true that the gains from picking the right problem can be greater than the gains from having better tactical execution because the gains from picking the right problem can be unbounded, but it’s also much easier to improve tactical execution and doing so also helps with picking the right problem because having faster execution lets you experiment more quickly, which helps you find the right problem.
Author’s commentary track: this post started because the title was too great of a rhyme to go to waste. I would say that I did not write this with haste. Probably several weeks passed from writing down the turn of phrase to trying to make this a short post suitable for social media to deciding it was really a blog post and wrapping it up.
Letterbird, lovely
Recently, I found myself in need of a contact form for my website. Luckily, I didn’t let myself fall to the temptation of rolling my own! 🙃
My good enough pals at Good Enough have built a modest little app just for this occasion, Letterbird. It was super easy to sign up, set up my form, and embed it on my website. It does the one thing nicely and is delightful to use.
I can’t emphasize this enough: it does the one thing and is delightful. It didn’t immediately encourage me to onboard my team, click through a guided tour, or immediately ask me to consider the generous discount of signing up for twelve months instead of one month.
I just used the thing, solved my problem, and kept going. Recommended!
Unrelated: I had to work really hard to write this so it doesn’t sound entirely like a podcast ad read. 🙃
Decision and context flows
Commonly shared/held wisdom: leadership is flowing decisions down and information up. What if this is (slightly) untrue? Or at least, in need of contextualizing.
Strategy, direction, and context are set by leadership teams based on intuitions, abstractions, and trailing and leading numbers.
The bottom of the org chart has a far better idea of how to get things done than the top. And possibly, what to get done such that customers can succeed. This information _should_be passed up, but it’s not not decision-making.
Seems to me there’s a disconnect and opportunity here for tactics to meet strategy. When things are going well, decisions are guided and informed, but rarely does the middle layer take decisions on its own, instead delegating to the team or below or leadership above. When ambiguity is ascendent and clarity or confidence wane, decisions could flow down.
Contrary: information up, context down is the central conceptual model of middle management. The Fundamental Purpose of Middle Management: Context Down, Information Up:
This brings us back to the fundamental job of middle management: push context down, and information up. The job of a middle manager is to gather as much information from your reports as possible, synthesize it, and pass it up to their manager. At the same time, they should be collecting as much context from their management chain and peers, and passing that important context back down the chain. If you’re a middle manager this should be your guiding principle.
Context-down should provide a coherent backdrop for whatever steering of execution a manager does.
Associated objects are promising
Garrett Dimon, Organizing Rails Code with ActiveRecord Associated Objects:
At the simplest level, associated objects come in handy mostly by helping organize and compartmentalize related logic so we can better avoid the junk drawer or God object “patterns.” But that’s an over-simplification because the benefits can be almost invisible–it just disappears into the background and does its job.
Associated objects have an excellent effort-to-benefit ratio. The implementation is less than a few hundred lines of code. The docs, which fit entirely in the readme, may outweigh the actual code! From that, you get a multipurpose and surprisingly deep tool for designing and modeling your system.
I’m excited to tinker more with this one.
Write a lot
Nat Bennett, How to write:
- Write a lot
- Just Write
- Read a lot
- Write every day
- Walk
- Have a time and a place for writing
- Take it less seriously
- Have an audience
At least as good as any advice I’ve ever given!
There’s lots of reasons that this works but I personally believe that writing is a mechanical skill as much as it is a mental one. Sometimes you just need to run a bunch of words through your writing engine — practice the whole process, from forming a sentence in your brain down to driving the motion of your fingers — to reduce the friction to a point where you can do “real” writing.
As above for writing, so goes for any iterative, world-building creative activity. p.s. coding is an iterative activity wherein a world of thought-stuff is created (and sometimes checked against a computer by executing it and seeing if it all blows up.)