Last year, I quit my job to work full-time on a chess app I created. It’s my first time working full-time on a project of my own, and it’s been both terrifying and gratifying. To close out my first year, I’m sharing an honest account of the mistakes I’ve made as a founder as well as the the things I felt I did well. Marketing 2/5 Ugh. I’ve tried paid ads virtually everywhere (Meta, X/Twitter, Reddit, Google), I’ve tried affiliate programs, word-of-mouth stuff like free merch to pe...| Posts on Marcus' Blog
Here are some lesser-known books I’ve loved, that you won’t find in typical recommendation lists – the deep-cuts. Replacing Guilt: Minding Our Way This book is all about the role of guilt. When is it useful, when is it not, what can be done about it. This could have easily been packaged like a best-selling pop-psychology book – padded to 200 pages with a sampling of the same anecdotes we’ve all read 100 times, fitting a narrative to the life of a celebrity or two to lend credibility...| Posts on Marcus' Blog
One of the biggest realizations I’ve had when building Chessbook is that onboarding a user is really hard. A user that’s coming in from some generic marketing, or from a blog post they found, or from organic search… well, the closest mental model is that they’re precocious toddlers. They won’t read more than a couple sentences of explanation. Usually they’ll skip that entirely and just hit the shiniest button. You have to keep snapping your fingers in front of their face every 10 ...| Posts on Marcus' Blog
I have a chronic problem of committing debug code to production. I often adjust code while testing out assumptions, reproducing issues, or trying alternative ways of implementing a feature or fixing a bug. When I’m committing thousands of lines per week, and with no-one reviewing my commits, occasionally some of this code slips through. A couple months ago I had one particularly annoying piece of debugging code make it to production. We ended up in a loop of fetching user’s data when they...| Posts on Marcus' Blog
Bob: This is where I keep all the notes I wrote in red pen, and likewise for all my blue notes, my green notes, and my purple notes Alice: Doesn’t this split your chemistry notes up into 3 different piles? Why not keep those together? Bob: gasp – and break the Single Color Principle? Disclaimer The shitty part of becoming a more senior engineer is your opinions become a mystifying web of “it depends” – a pile of vague intuitions and bag of exceptions, the kind that drove proponents ...| Posts on Marcus' Blog
In working on Chessbook recently, I often found myself referring to (position, move) pairs. Specifically positions that are stored as EPDs, and moves that are stored in San notation. let difficulty_by_epd_san =//...; let existing_epd_sans =//...; let unique_moves_by_epd_san =//...; fnepd_san_plus_to_condition((epd, san_plus): &(String, String)) -> _//...; I got so used to thinking of these things together as pairs, and wished I had a name for it. I couldn’t think of an existing name that wo...| Posts on Marcus' Blog
Ever seen this keyboard? This was called the Datahand, it was a radical new approach to keyboards that mostly only existed within a small community of RSI sufferers. It cost $2,000 in 1993, which is north of $4,000 today, so you really had to need this thing to justify the price. Even now there’s a small community that continues to use these. For a long time after Datahand shut down production, there was no real replacement. Then Morgan Venable, alias Claussen, created Svalboard. It’s a m...| Posts on Marcus' Blog
Welcome to the end-of-year update for the Rust language. 2030 has been a huge year for us, with some huge wins but also a couple setbacks. We’d like to highlight some of these moments and look back on the past year of work on Rust. Async woes Despite our best efforts, there are still some large issues with async rust. Async traits come with significant limitations, async closures aren’t supported, error messages can be cryptic, it’s easy to accidentally block the executor, and many crat...| Posts on Marcus' Blog
I finally have the feeling that I’m a decent programmer, so I thought it would be fun to write some advice with the idea of “what would have gotten me to this point faster?” I’m not claiming this is great advice for everyone, just that it would have been good advice for me. If you (or your team) are shooting yourselves in the foot constantly, fix the gun I can’t tell you how many times I’ve been on a team and there’s something about the system that’s very easy to screw up, but...| Posts on Marcus' Blog
Abstractions are the best Your code will be safer and more readable. It will prevent entire classes of bugs. It will be easier to add new features. You can inject dependencies at runtime to make testing easy. You can swap out your third party dependencies. You can adapt quicker to business logic changes. You can treat X and Y as the same thing. They’re both forms of Z, after all.| Posts on Marcus' Blog
I wrote a post yesterday about how to compress chess moves. I was pretty happy with my hand-rolled compression scheme, which achieved a per-move size of 9.5 bits. I almost just rolled with it, but I’ve been thoroughly nerd-sniped here, so I took another crack at it. To know the board state or not One of the main considerations in compressing chess moves is how much chess-specific computation you want to do. One of the most optimal forms of compression is actually to evaluate the position, u...| Posts on Marcus' Blog
I recently downloaded Lichess’ database of all December ‘21 games. After using it to generate puzzles for my chess training site, I realized I could also use it to find out something I’ve been wondering a long time: how useless, exactly, is it for me to memorize chess openings? I’m ~1700 on Lichess, so I chose the ELO range of games for these statistics as 1600-1900. The generated database has 10 million games, and 26 million opening lines, at a max depth of 12 half-moves. Along with ...| Posts on Marcus' Blog
Generally, chess puzzles will present you with a position and ask you to find the best move. There’s only one, and all other moves are losing. These are great, but I’ve been thinking of a different style of puzzle that I’d like to practice with. What I want is a chess position, then two moves presented as options; one is a blunder, and one is the best move. The idea is to train my ability to spot blunders, like regular puzzles train your ability to find forcing lines.| Posts on Marcus' Blog
The annual book review, 2021 edition. Ratings are solely about how much I enjoyed the book. I’m not reviewing these books like a critic, if the book has a bunch of tropes or something, but it kept me hooked from start to finish, I’m not going to mark it down. For example, I actually love reading books with a Mary Sue main character, so my rating is going to be divorced from a book critics review there.| Posts on Marcus' Blog
I spend way too much time on reddit, hacker news, twitter, feedly, coinbase, robinhood, email, etc. I’d like to spend time on things that are more meaningful - chess, digital painting, side projects, reading, video games, exercising, meditating, etc. This has been a problem for years. This post is only slightly adapted from my personal notes, so excuse the lack of structure; I didn’t want to try to twist this jumble of thoughts into a narrative.| Posts on Marcus' Blog
Recently I’ve been working on a project to surface census data via a GraphQL API, mostly as a way to learn GraphQL. I did end up learning GraphQL, but I also ended up learning a lot about proc macros. I was using Juniper, which creates a GraphQL schema using structs like this: #[derive(GraphQLObject, Copy, Clone, Debug)]structDemographics { female: Option<i32>, male: Option<i32>, } The problem, is that the census data I was looking to surface had way too many variables, I would have had to ...| Posts on Marcus' Blog
I’ve been dealing with QR codes recently, as one of my side projects generates them, and I got curious about how much data you can really fit in a QR code. Specifically, I wondered how much of my favorite book I could fit on one QR code. QR Code versions QR Codes have different versions, but they’re not versions as you’d generally think about them, version in this case just means a particular size. Version 1 has 21 rows of “modules”, or dots, and 21 columns of modules. Version 2 is ...| Posts on Marcus' Blog
There’s no shortage of posts like “Let’s use Kubernetes!” Now you have 8 problems, or Do I Really Need Kubernetes?, which tend to argue that unless you’re orchestrating 1000 containers, you’re good without Kubernetes. Also, I thought this tweet was hilarious: So… Hi, I’m the guy using Kubernetes for my blog and small side projects, here’s why I love it (to the extent one can love a deploy tool). “You don’t need all that complexity” Undoubtedly, Kubernetes is doing a lo...| Posts on Marcus' Blog
Just some quick thoughts on Gatsby and Next.js, after trying both for a project I worked on recently (this one). I’ve been a Next.js user for about a year, and for this project I tried to use Gatsby, with limited success. Hot-reloading Hot-reloading started out pretty shaky for me when I first tried Next.js about a year ago. But since 9.4 it’s been spot-on. Gatsby hot-reloading mostly worked well, although if there was an error, the page wouldn’t reload after fixing the code. Since erro...| Posts on Marcus' Blog
In my last project I used Sled and Rocket. I had to piece together how to use the two from a few different places so I put together this quick guide in case it helps others. The full code for this walkthrough is availabe here, if you want to fast-forward to the finished product. A lot of this ends up being about error handling, so that using sled in endpoints is more ergonomic. If you don’t care to dive into error handling, you may want to skip those sections.| Posts on Marcus' Blog
Bevy has seen rapid adoption recently, but the learning resources are still fairly scarce. This is an attempt to provide a next step after the Bevy book. The final product looks like this: It’s about 300 lines of Rust, so buckle in; this is a lengthy walkthrough. If you want to fast-forward to the finished code, the code lives here. For each section there’s a diff at the top, which should make it easier to determine where to place snippets of code, when it’s not clear.| Posts on Marcus' Blog
I was aimlessly browsing Github and came across sapling, a very early-stage structured editor. It was inspired by this blog post, which talks about structured editing. Structured editing has had my interest for a while. I’ve put a lot of time and effort into getting really good at text editing, but I’m holding out hope that in 10 years plaintext editing will be outdated. The idea behind structured editing is to edit code instead of text, so instead of “move cursor to next parentheses, d...| Posts on Marcus' Blog
Recently I migrated my side-project from Redux, which I’ve used in every React project for the past four years, to pullstate, here is my tale. Problems with Redux Feel free to skip this part if you already know the pain points of Redux, there’s nothing in here that hasn’t been discussed a million times before. These are the problems as I see them, most important first: The boilerplate. Oh man, the boilerplate. Want to add a counter? First, add the field to your interface (I’m assuming...| Posts on Marcus' Blog
I saw the call for blog posts in the 2021 rust roadmap, so I figured I’d throw in my 2 cents, since I’ve been working on a project recently that uses rust on the backend. As the title suggests, I’ve been finding myself spending too much time on error handling. I want to preface this by saying I’m just using rust for hobby projects. If I were writing rust in production or for a larger project I probably wouldn’t care that error handling takes some work to get right, I’d be more wil...| Posts on Marcus' Blog
I’ve developed an unusual approach to styling in my React code. It’s sort of a functional, atomic css approach. Other methods I’ve used are BEM + separate css files, styled components, and tailwind. By far this is the one that lets me move fastest on my personal projects (I haven’t yet subjected anybody at work to dealing with it). Without further ado. Element Styling constbuttonStyles=s(caps, px(s6), py(s5), clickable); constactiveStyles=s(buttonStyles, bg("green"), fg(light0)); cons...| Posts on Marcus' Blog
The Commonplace blog has been writing a lot on tacit knowledge recently. As someone who’s been programming for a long time (8ish years), these articles resonated deeply. I won’t go into too much detail what tacit knowledge is about, since the above posts do such a good job with it. If you’re not familiar, check them out. Explicit knowledge vs tacit knowledge Essentially, explicit knowledge is that which can be transferred verbally. For example, I could tell someone the method name for p...| Posts on Marcus' Blog
Recently I made the switch to self-hosted analytics, after being a long-term Google Analytics user. Almost every website you visit will have a Google Analytics tracker on it. I think there are idealogical and technical reasons to opt for self-hosted analytics instead. Tracking efficacy This one’s quick. You’re more likely to get analytics for a given user if you’re using self-hosted analytics, than if you’re using Google Analytics. About 26% of people are running adblockers now, a lar...| Posts on Marcus' Blog
ngrok is a tool that proxies traffic from a subdomain (like http://2fb551c6b2fd.ngrok.io) to a port on your localhost. I’ve been using it off and on for years. There’s a couple use cases I’ve used it for: Forward web traffic to a local next.js / webpack server, to show a website in progress without having to deploy it. This way I can send an ngrok link to a friend/coworker and they can see the latest. Forward api traffic from a device (ex. an iPhone if I’m working on an iOS app) to my...| Posts on Marcus' Blog
I’ve been working on a web project for a few months now and thought I’d take stock of the tools I’ve been using. So I went through my zsh_history (fun fact, since March I’ve run 3,950 commands for this project). These are only the “generic” tools, I’ve excluded any stack-specific tools, like ghci, pgcli, docker, spago, etc. I’ve also excluded obvious tools and built-ins, like ssh, scp, and git. {html,js,css}-beautify When I’m on the frontend, it’s not uncommon to deal with...| Posts on Marcus' Blog
I’ve been using kitty and tmux together for years and recently realized my setup for true colors was broken, thanks to neovim’s :checkhealth command. After some searching and trial and error, the setup I ended up at was this: Remove any export TERM lines from .zshrc, .bashrc, etc. Set these options in tmux: set -g default-terminal "screen-256color" set-option -sa terminal-overrides ",xterm-kitty:RGB" Kill tmux, close kitty, reopen and true color support should be enabled| Posts on Marcus' Blog
This is just a rapid-fire summary of the books I’ve read this year and what I thought about them. Note that the links in here are affiliate links. Any profit will be donated to the Amazon Conservation Association, in the rare event people read this and buy a book. Without further ado. The Name of the Wind by Patrick Rothfuss Became one of my favorite fantasy books. Very interesting magic system, world, and narration style. If Mary Sues bother you, then maybe steer clear.| Posts on Marcus' Blog
Recently I acquired a project, Now What Do I Read?. One of the steps in acquiring the data was to scrape the sitemaps of Goodreads. The project was written in Go, and I decided to rewrite it in Haskell, mostly to mix it up a bit. Writing everything in Python and JavaScript gets old eventually, quick as it may be. This will probably turn into a series in which I go through the rest of the process of rewriting the project in Haskell. The intended audience is those with a passing familiarity wit...| Posts on Marcus' Blog
I started a Haskell rewrite of a project, and after not having used Haskell for a long time, found the process of setting up my Vim environment to be a pain. There’s nothing exciting here, but by the end of this quick guide you should have: Haskell + Stack installed Autocompletion, go to definition, type lookups, and more via HIE and CoC GHCi via Intero (it does more, but overlaps with HIE a bit) Local hoogle For vim packages, I’m going to assume you’re using vim-plug, replace Plug with...| mbuffett.com
One of the biggest sticking points of being a solo dev is maintaining motivation. I’ve been keeping a journal entry about how to hack my motivation, what works and what doesn’t. Here are the things that have worked. Convert external sources to motivation I’ve always known that I’m more extrinsically than intrinsically motivated, so I have a couple systems that help to give me bursts of external motivation. For example, the Money Bots, which pop up every time someone subscribes.| mbuffett.com
Background I run a chess site, https://chessbook.com. We ingest a ton of games, nearly 6 billion, to power our various statistics. Our current database has about 900 million lines. We’re working on our next evolution of this database, and that entails re-ingesting all these games, but going much deeper on each game. Our existing solution was already pretty optimized, you can’t get through 1.6 terabytes of data in a reasonable timeframe without some optimization, but we needed to really sq...| mbuffett.com
I played chess briefly with my friends in high school, where I had a rating of around 1100 online. I gave up the game for about 10 years, then picked it back up again recently, in May. I’ve tried a ton of different approaches in the past 6 months, switching things up whenever I stopped seeing results. I’ve improved from 1238 to 1802, and based on my win rate currently I think I’ve got another 50 points in me before I plateau again.| mbuffett.com
Recently, I made a chess program in Python and published the source on github here. The code is just under 1000 lines, about 20% of which is dedicated to the AI. In this post I’ll cover how the AI works, what each part does. and why it works like that. You can just read through, or download the code and mess around with it as you read. The AI is all in the AI.| mbuffett.com
UPDATE: I’ve written a new post with a new technique which is about 2.5x more efficient than this approach Chess notation has come a long way since descriptive notation, now we have nice and decipherable Standard Algebraic Notation, like Qxf7 (queen takes on f7) or Nf3 (knight takes on f3). This is a great text format, but a massive waste of space if you’re trying to store a lot of these. Qxf7 takes 4 bytes, or 32 bits. Let’s do some rough back-of-the-envelope math of how much informati...| mbuffett.com