Hi! I'm Feifan.

I've started and stopped many blogging efforts over the year, but it's a medium that constantly draws me back. I like long-form writing as a way to gather, sequence, and sharpen my thoughts — and publicly publishing my pieces nudges me to clarify my ideas and understand their implications beyond my head.

These days, I'll most likely write about uncommonly interesting ideas I come across, frameworks for thinking and seeing the world, and my tinkering into ways to improve the experience of using computers.

  1. Tanagram Roadmap: March 2024

    Tanagram remains a nights-and-weekends project. My progress pace during December averaged about 1.5 workdays per week.

    Continue reading →
  2. Tanagram Roadmap: February 2024

    Tanagram remains a nights-and-weekends project. My progress pace during December averaged about 1.0 workdays per week.

    Continue reading →
  3. Tanagram Roadmap: January 2024

    Tanagram remains a nights-and-weekends project. My progress pace during December averaged a bit under 1.0 workdays per week; I was on vacation for much of the month

    Continue reading →
  4. Tanagram Roadmap: December 2023

    This is my 23rd monthly public roadmap update for Tanagram development (I'll stop counting after this one; see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1.0 workdays per week; some personal errands and day-job projects have kept me busier than usual.

    Continue reading →
  5. Tanagram Roadmap: November 2023

    This is my 22nd monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1.0 workdays per week; some personal errands and day-job projects have kept me busier than usual.

    Continue reading →
  6. Tanagram Roadmap: October 2023

    This is my 21st monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1.5 workdays per week.

    Continue reading →
  7. Tanagram Roadmap: September 2023

    This is my twentieth monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1 workdays per week, maybe a little more.

    Continue reading →
  8. Tanagram Roadmap: August 2023

    This is my nineteenth monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1.5 workdays per week, maybe a little more. I was on vacation in the beginning of the month and came back to Tanagram in mid-July.

    Continue reading →
  9. Tanagram Roadmap: July 2023

    This is my eighteenth monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1.5 workdays per week. This month's update is out early because I'm going on vacation for the next few weeks, possibly with limited internet. I'll be back in mid-July.

    Continue reading →
  10. Tanagram Roadmap: June 2023

    This is my seventeenth monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1.5 workdays per week, minus about a week for vacation.

    Continue reading →
  11. Tanagram Roadmap: May 2023

    This is my sixteenth monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1.5 workdays per week, minus about a week for vacation.

    Continue reading →
  12. Tanagram Roadmap: April 2023

    This is my fifteenth monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1.5 workdays per week.

    Continue reading →
  13. How to Use SourceKit-LSP

    Background: I'm building Tanagram, a tool to browse and edit code like a relational database (instead of text files). I'm using SourceKit-LSP to implement code-understanding for Swift. There was very little documentation on how to actually use SourceKit-LSP when I started, and it took a lot of trial-and-error to get it working. This post is the "how-to" guide I wish I had. This is current as-of macOS Ventura 13.1, Xcode 14.2, and SourceKit-LSP commit 99bae51.

    Continue reading →
  14. Tanagram Roadmap: March 2023

    This is my fourteenth monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged a bit less than 1 workday per week.

    Continue reading →
  15. Tanagram Roadmap: February 2023

    This is my thirteenth monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1.5 workday per week.

    Continue reading →
  16. Tanagram Roadmap: January 2023

    This is my twelfth monthly public roadmap update for Tanagram development (see previous updates here). Tanagram remains a nights-and-weekends project. My progress pace over the past month has averaged about 1 workday per week for two weeks; the rest of my time was spent on vacation, packing, and resting over the holidays.

    Continue reading →
  17. Tanagram Roadmap: December 2022

    This is my eleventh monthly public roadmap update for Tanagram development (see previous updates here). I'm publishing this update to document my progress and hold myself accountable, and also provide a place to share some thoughts about what I plan to work on next.

    Continue reading →
  18. Tanagram Roadmap: November 2022

    This is my tenth monthly public roadmap update for Tanagram development (see previous updates here). I'm publishing this update to document my progress and hold myself accountable, and also provide a place to share some thoughts about what I plan to work on next.

    Continue reading →
  19. Tanagram Roadmap: October 2022

    This is my ninth monthly public roadmap update for Tanagram development (see previous updates here). I'm publishing this update to document my progress and hold myself accountable, and also provide a place to share some thoughts about what I plan to work on next.

    Continue reading →
  20. Tanagram Roadmap: September 2022

    This is my eighth monthly public roadmap update for Tanagram development (see previous updates here). I'm publishing this update to document my progress and hold myself accountable, and also provide a place to share some thoughts about what I plan to work on next.

    Continue reading →
  21. Tanagram Roadmap: August 2022

    This is my seventh monthly public roadmap update for for Tanagram development (see previous updates here). I'm publishing this update to document my progress and hold myself accountable, and also provide a place to share some thoughts about what I plan to work on next.

    Continue reading →
  22. Tanagram Roadmap: July 2022

    This is my sixth monthly public roadmap update for for Tanagram development (see previous updates here). I'm publishing this update to document my progress and hold myself accountable, and also provide a place to share some thoughts about what I plan to work on next.

    Continue reading →
  23. Tanagram Roadmap: June 2022

    This is my fifth monthly public roadmap update for for Tanagram development (see previous updates here). I'm publishing this update to document my progress and hold myself accountable, and also provide a place to share some thoughts about what I plan to work on next.

    Continue reading →
  24. Tanagram Roadmap: May 2022 + Demo #3

    This is my fourth monthly public roadmap update for Tanagram development (see previous updates here). I'm publishing this update to document my progress and hold myself accountable, and also provide a place to share some thoughts about what I plan to work on next.

    Continue reading →
  25. Feature-Less Software

    Most software is feature-ful: built from an amalgamation of individual features, which are usually atomic ways to do something specific, arranged in a singular interface that has to work for every user of that piece of software. Each feature is usually built with a small number of end-to-end user experiences in mind (often in the form of "user stories"). Each feature has to live somewhere in the UI; sometimes they're put in unexpected or awkward places, and every so often the whole UI gets shuffled up in a redesign.

    Continue reading →
  26. Tanagram Roadmap: March 2022

    This is my third monthly public roadmap update for Tanagram development (see previous updates here). I'm publishing this update to document my progress and hold myself accountable, and also provide a place to share some thoughts about what I plan to work on next.

    Continue reading →
  27. Tanagram Roadmap: February 2022

    This is my second monthly public roadmap for Tanagram development (see January's here). As with last time, I'm publishing this roadmap because I believe doing so will increase my accountability for progress. It also gives me a place to write a paragraph or two about the mildly-to-moderately interesting bits I'm building away from the terseness of Twitter or the temptation to add more padding for a full-length blog post.

    Continue reading →
  28. Tanagram Roadmap: January 2022

    I've been writing monthly roadmaps for Tanagram development in private for a few months. For 2022 I've decided to publish them, in part because I believe doing so will increase accountability for progress, and also because writing these for an audience will force me to be more precise with what I have in mind and enable clearer did-I-or-didn't-I comparisons.

    Continue reading →
  29. Tanagram: Creating a Database-Based Codebase

    I've been working on Tanagram, a programming environment that's trying to make it easier to browse codebases and build programs by turning code into data. This post is a refinement of previous ideas (see previous posts here), and although it doesn't look much different from demo 2, a lot of changes have gone in under the hood. Until this past week, my blog has been a standard Phoenix site — most of the URL routes were standard Phoenix paths, rendered by Phoenix controllers and views. Making a change to these routes required a code change and a deploy. But no longer: I've implemented my blog routes using building blocks provided by Tanagram, and adding or removing routes now just requires a few clicks:

    Continue reading →
  30. Tanagram Demo #2

    I've been working on a new way of writing and working with software. This is the second demo (demo #1 here), and although this, too, looks like a toy, I think it's a good encapsulation of what I'm trying to solve with Tanagram. In short, Tanagram is a programming environment that's trying to make it easier to browse codebases and write glue code (i.e. boilerplate code; code where remembering the exact syntax is harder than the logic itself) by putting codebase concepts into a database and replacing some typing with a GUI.

    Continue reading →
  31. Tanagram Demo #1

    I've been working on a new way of writing and working with software. Although it's still very early along[^3] and looks very much like a toy, I'd like to share a demo:

    Continue reading →
  32. The Database Inside Your Codebase

    Navigating codebases of any meaningful size is difficult. Most of a programmer's time is spent jumping through the codebase, reading or skimming to build a mental model of the constructs and conventions within it. These constructs — among them: the DSLs, interfaces, and taxonomy of types that exist — are arguably the most important precursor to understanding where and how to make changes. But these constructs only exist in programmers' heads. It's difficult or impossible to navigate most codebases through the lens of those constructs; programmers lack "code browsers" that present the underlying code independently of files and the filesystem hierarchy. Yet code browsers that can do so — and we'll look at some examples below — would be incredibly useful. This is because instances of these constructs can be thought of as records in a database, albeit an ad-hoc, poorly-specified database that can only be queried through carefully-crafted regexes[^10].

    Continue reading →
  33. Computers Have Gone Wrong (And It's All Software's Fault)

  34. Teaching Mental Models

    I was recently trying to explain the concept of mental models to my younger brother — how to build them, and how they could be useful. Ironically, I didn't really have a good idea of how they worked, or how to explain them to someone else, until fairly recently. Maybe I still don't. But my brother found this explanation useful, and maybe you will too.

    Continue reading →
  35. Photography

  36. Building A New Blog

    I've moved my blog off of Wordpress — in part because of limitations with Wordpress.com's hosted offering[^0] — and onto a custom-built site[^1].

    Continue reading →
  37. The Dream Machine: A Story of Creativity, Tinkering, and Cross-Pollination

    "Creativity is a function of freedom" – George Pake

    The advent of computers and the internet is a story of human creativity and organizations that brought myriad dreams to come to life. From the 1950s through the end of the 1970s, during which a scientific community tinkered with and established fundamental ideas in computing, and up through the explosion of personal computers and early internet in the subsequent decades, the story is rife with characters and environments that allowed creativity to flourish, along with those that undermined it. The Dream Machine tells this story by following the life of J.C.R. Licklider, a central figure and instigator of much of the creative accomplishment by virtue of his personality and career.

    Continue reading →
  38. Computers Aren't Fun Anymore

    Throughout The Dream Machine, a history of the early days of computing, tinkering and having fun was a recurring theme throughout the decades. I wasn't around to experience the early days of computers myself, but they seemed to be genuinely exciting and rewarding. In the words of MIT sociologist Sherry Turkle: computers empowered their users, making them feel smart[er], "in control", and "more fully participant in the future".

    Continue reading →
  39. No One Cares About Software Quality

    No one cares about software quality anymore. I mean, yes technically that is untrue and there are demonstrably some people who do, but for the most part, quality software has become a niche luxury[^3] while the most commonly-used software has become a slow, laborious cesspool.

    Continue reading →
  40. Inadequate Equilibria: A Summarized Remix

    In late 2017, Inadequate Equilibria spread like wildfire across my Twitter feed. Having worked through it, I’d now easily rank this book as one of the most impactful I’ve ever read on the way I see the world and think about my career. It is quite a bit of work though — my first read-through was near-incomprehensibility, alongside fragments of ideas that I found tremendously insightful and hinted at a very different way of interpreting the world than I was used to. That held my interest long enough that I reread this book several times; each time resolving the intent and ideas to a finer degree, like a developing Polaroid. Nevertheless, with each reading, I felt that the abstruse writing made the book hard to understand and share with other people. That’s really unfortunate. So, as a way to pay that forward, I’ve decided to remix it — these are my notes, presented in complete sentences, using friendlier terms and assuming fewer conceptual prerequisites so that it reaches a wider audience. I’m sure I’ll lose some technical precision around the edges, but hopefully I’ve got it mostly right.

    Continue reading →
  41. Never Waste a Good Crisis

    The past few weeks, indefinitely isolated at home, has given me time to think about the civilizational optimizations and limitations that COVID-19 has revealed and the stunning interconnectedness of it all. We live in world of long supply chains that magnify rather than mollify shocks and minimally-provision capacity where headroom has been optimized away in service of efficiency. Elsewhere, rules and regulations are being loosened, raising the question of why they're necessary in the first place. And the heterogeneity of government effectiveness is on full display.

    Continue reading →
  42. Remove the Middle Option

    Recently I was talking to a friend who’s thinking about getting a car and wanted to get my thoughts on leasing for 3–5 years vs buying/financing. As it happened, I have also been thinking about getting a car, and I’d already decided that I wanted to lease because for the car I wanted to get, I didn’t want to own it for the long-term.

    Continue reading →
  43. An Eighty-Year Career

    When I was a kid living at home, I remember my dad, from time to time, wistfully looking forward to retiring. I would often ask him why, since retirement sounded so boring, but I don't remember ever getting a clear answer. In the years since, as my sense of how big — how interesting! — the world can be, retirement has come to seem like a strange idea. As the default ending for the conventional career narrative, we've canonized deferred living en mass. That seems unfortunate. What's more, retirement appears to discard a career's worth of experience for decades at a time for millions of people. That seems like a lot of collective human potential going to waste.

    Continue reading →
  44. How To Do My Job

    Recently, I was talking to a future coworker (who didn’t work as a software engineer), and I found myself indelibly curious about what exactly his job was like and what I would need to know if I wanted to competently perform his job. I didn’t get to fully find out at the time, but I later came up with a possible framework for how I’d like to explore the topic. For illustrative purposes, I’ll go first:

    Continue reading →
  45. Documenting Some Thoughts Around Tanagram

    Tanagram is the name of a project idea I’ve been thinking about for a while. I trace the idea’s lineage back to a little prototype I built in late 2013. I didn’t think much of it at the time, but I’ve revisited this idea (or at least something directionally-related) countless times in intervening years.

    Continue reading →
  46. Introducing LeetcodeSolutions

    On a Saturday afternoon last fall, I found myself in front of an expansive whiteboard covered in diagrams, tables, and somewhat legible hand-writing. I was there with a new coworker, and we had just finished going through the data models she’d be working with. Along the way, we’d taken a long digression into database design, and I’d explained the differences between SQL databases and Mongo and when it made sense to use one or the other; our codebase worked with both. At the end, she looked up from her notes and exclaimed, “That makes sense! Wow, why didn’t anyone explain it this way?”

    Continue reading →
  47. Next Steps

    Last week was officially my final week with Trustwork, a seed-stage startup where I joined about two years ago as the second engineer. It’s an equitable conclusion to a personal journey that began when I decided to leave three months ago. I’ll be joining the Issuing team at Stripe in a month, a relatively new team with a really audacious charter.

    Continue reading →
  48. Learn Harder Things

    When you take the time to learn something new on your own time, it’s better to learn things that are conceptually harder than, or paradigmatically different from, what you already know, rather than something that’s adjacent. For example, in software engineering, if you already know Ruby, learn a functional language like Elixir, or a lisp like Clojure — doing so will expand your abilities much more than learning, say, Python, which is conceptually very similar. In the gym, if you’ve been training traditional weight lifting, learn functional strength exercises rather than yet another movement with barbells and plates.

    Continue reading →
  49. Decisions ≠ Outcomes

    While reflecting on how well I make decisions, I realized that it’s possible, and in fact important, to separate the evaluation of the decision-making from its outcome. In other words, the process of making a decision is not the same thing as the outcome of the decision — it’s possible to have a well-made decision that results in a bad outcome, or to have a poorly-made decision that results in a good outcome.

    Continue reading →
  50. Apple Watch: Not-a-Review

    There seems to be an inverse correlation between how much I pay for an Apple product and how much I enjoy using it. My Macbook Pro (2016, Touchbar) is functional at best, and unusably glitchy uncomfortably frequently. My iPhone (XS) is wicked fast and a pleasure to use, although my iPad Pro (Pro, 10.5) is more delightful and practical to use because of ProMotion and the larger display. But after living with the Apple Watch (Series 4) for the past month, it’s become my favorite computing device.

    Continue reading →
  51. On Frustration and Anger

    When I was younger, I used to be easily frustrated when things weren’t going my way. I would feel a surge of emotion wash over me, and I would indulge in that burning warmth while it lasted. The sensation was a strange combination of feeling powerful — a wave of pent-up energy coursing through me, looking for an outlet — as well as a profound powerlessness, the inability to do something which had brought about the frustration in the first place. I knew that it wasn’t healthy or productive to rail against the world in the long term, but each indulgence brought a sense of gilded satisfaction that was hard to forget.

    Continue reading →
  52. Aphantasia and the Speed of Thought

    A recent Twitter exchange reminded me that we all perceive the world differently. For me, one of these differences is that I’m not really able to visualize anything in my mind.

    Continue reading →
  53. An Introduction to jscodeshift

    Recently, I had to make a straightforward change over dozens of files spread across our entire frontend codebase. I didn’t like the idea of finding all the files and manually make the change; in the spirit of laziness-driven-development, I decided to figure out a way to script it. I’d discovered jscodeshift a few months ago as an interesting tool to explore and bookmarked it for “later”, and this was a perfect opportunity to actually do that.

    Continue reading →
  54. So-what-ness

    I’ve noticed a sense of so-what-ness that permeates a lot of the conversations I’ve had or observed. It’s a sense of mild cynicism that hangs over a conversation or idea, where it feels like every sentence has to justify its significance against an unspoken “so what?”. It’s skepticism as a default; an indulgence in intellectual incredulity.

    Continue reading →
  55. Notes on Fasting

    The hardest part of not eating for 120 hours and 11 minutes was the boredom. From the afternoon of May 17th until a late lunch on May 22nd, it was as if I found myself living in a boundless void. Time stretched out forever. I’m not sure if it’s a psychological thing — not having meals to break up the day or look forward to — or if it’s a physiological response, a dilation of time designed to give the primal senses a better chance of finding the next meal. It might be a combination of both.

    Continue reading →
  56. Thoughts on Personalizing Software

    I’ve been obsessed with productivity software for most of my life. I’ve sampled dozens, from simple personal tools (like Apple Notes) to full-featured productions complete with the kitchen sink (like Phabricator and JIRA). None of them ever felt comfortable — many were too simplistic, some were too prescriptive, and some were overwhelmingly customizable (although not necessarily in the ways that I would’ve liked).

    Continue reading →
  57. Work on Good Ideas

    Despite what some people might want to believe, there is such a thing as bad ideas. In the context of building valuable ventures, bad ideas are typically bad in a few ways:

    Continue reading →
  58. Tech Stacks Are Overrated

    In the process of interviewing dozens of junior and intermediate engineers, the questions candidates ask implicitly say as much about them as the rest of the interview. One question that comes up occasionally is some variation of “what tech stack are you using”? List some of the myriad Javascript libraries-du-jour and I get a murmur of approval; mention something mature and be met with silence or a disappointed “oh”. In fact, many outright say that they want to be working with the latest or “bleeding edge” technologies.

    Continue reading →
  59. Service Objects As Test Fixtures

    In our Rails codebase at work, we often have tests that begin with many lines of setup code — declaring relevant variables, creating and updating models — to setup the database so we actually test what we intend.

    Continue reading →
  60. How I Think About Salary

  61. Evaluating Work Opportunities

    Recently, I spoke with a friend about job opportunities. I briefly shared with him my framework for deciding between companies, which I developed during my job search last summer. I want to expand on the questions and the thinking behind them — as far as I can tell, this isn’t common knowledge, and perhaps someone else will find it useful.

    Continue reading →
  62. There’s More to Coding than Just Writing Code

    For most of my life I firmly believed that a Computer Science degree wasn’t necessary to work as a software engineer; there exists a massive amount of resources and practice opportunities to learn outside of the context and cost of a university degree. I maintained this perspective even after I ended up getting a CS degree, partly because of the lack of practical skills in a typical CS program.

    Continue reading →
  63. Behavioral Observations From Taking Over SXSW

    I just got back from taking over SXSW with Trustwork. We ran a scavenger hunt with multiple stations giving out free stuff in exchange for user signups. This post is the second of two posts on learnings and observations from that week. Part 1 is here.

    Continue reading →
  64. Personal Lessons From Taking Over SXSW

    I just got back from taking over SXSW with Trustwork. It was an exhausting eight-day marathon, complete with an air mattress in the office, questionable food, and hundreds of rejections a day. I wouldn’t want to do it again. Despite all that, it was a fantastic experience, and I’m really glad it happened.

    Continue reading →
  65. Mind-mapping

    For many years, I dogmatically resisted using mind maps to take notes or organize my thoughts. I was always afraid I’d get “stuck” if I used pen and paper — that my map would end up too cramped (or too sparse, which seemed wasteful), and the software always seemed too expensive and a bit clunky. I would always fall back to verbose, linear notes (written out top-to-bottom, left-to-right), often ending up with walls of text that I would then have to decipher.

    Continue reading →
  66. ROI: In-Unit Laundry

    I walked past a fancy laundromat + café place today. As a business, I think it’s a great idea (although somewhat indulgent as well), but it got me thinking (as one does) about the economics of laundry, especially in apartments that have laundry on-site. My current apartment has a washer and dryer in every unit. It’s an amazing amenity, and makes doing laundry tolerable. My previous apartment had a laundry room on each floor. Turns out, based on some rough numbers, the former is a better setup for everyone. Here’s how it breaks down (at least in the San Francisco rental market):

    Continue reading →
  67. Viewing iMessage History on a Computer

    I occasionally want to go back and browse conversations I’ve had, either to lookup some detail or to revisit a discussion (many of which might become future blog posts 🙃). Aside from work Slack, the vast majority of my conversations are through iMessages, but Apple’s apps don’t make it easy to scroll through history. I figured it would be fun to write my own. The first version is the equivalent of one day’s work, and everything is available on Github.

    Continue reading →
  68. Falcon Heavy

    I didn’t expect to get chills racing down my spine, but I did. Even now, after the initial excitement has worn off, I still think the Falcon Heavy launch and booster landing is one of the coolest things I’ve ever seen.

    Continue reading →
  69. Deleting Facebook

    A week ago I deactivated my Facebook. It’s tempting to indulge in hyperbole and say that it’s the best thing I’ve done for my life, but I don’t feel any different. And I think that’s the point.

    Continue reading →
  70. Breakfast: Eggs

    I didn’t know how to make eggs for a very long time. That’s mostly because I was squeamish about touching raw eggs. It might’ve also been related to my inability to crack an egg without making a mess or shattering the shell and making a different sort of hopeless mess (I’m still just barely adequate at cracking eggs).

    Continue reading →
  71. Start With Why

    This is my blog. There are many like it, but this one is mine.

    For the past year or so, I’ve flirted with the idea of having a blog — a place where I can think out loud, share cool tools/tips/books, and explore ideas at length. I kept coming back to this idea while planning my 2018 (a topic for a future post), and knew I had to give it a shot. Currently, this blog is a year-long experiment for myself; I’m committing to writing 50 longish-form pieces this year (although, since I’m making up the rules, this count can include posts on my company’s blog).

    Continue reading →