Awesome FOSS Logo
Discover awesome open source software
Launched 🚀🧑‍🚀

Software Sessions: Yak-shaving interview (2022)

Software Sessions logo

tl;dr - I hopped on the Software Sessions podcast to talk about yak shaving and some projects I’ve been working on. Take a Listen (it’s kinda long so consider the transcript as well)

I was contacted a while ago by Jeremy who runs the Software Sessions podcast. I’d actually come across his Podcast in the past so I was super excited to get a chance to interview and talk about some of the projects I’ve done in the past.

Before the podcast, I got some general ideas on where the conversation could go with Jeremy, so I was able to do some thinking and compile my thoughts, which is what I want to share here.

This might serve as a nice book-end to the podcast (or quick summary of my thoughts).

Pre-Podcast notes

Ongoing Projects


Based on the rough examples that were provided by Jeremy

Context (Team of One, Generalist, Consulting, CRUD apps? What scale?)

I’m basically all of these things – A team-of-one generalist who also consults while building sometimes CRUD-y apps but more so services.

The CRUD is almost never the goal, unless you’re a CRM company (?) – the goal is a service that saves people time and makes people money. I operate on the small scale – very much an indie hacker though I wish I’d gotten to that community earlier in my career.

What do you optimize for? (Fun to write? Minimal operations work? Docs / Community?)

Early on, I optimized for learning, correctness (type systems – “the Haskell years”), then fun, these days I optimize for speed and not doing the same work twice.

I’ve spent a lot of time yak shaving and I think what gets me to act the most or go on a yak shave is the idea of doing the same work multiple times when arguably the entire point of the kind fo programming most people do these days is automation.

A note on optimizing for speed – as I launch more things it’s clear – some times it’s just not worth spending an extra 5 days to build out some automation to do that thing. It’s better to do it manually the first 10/20/30 times, and worry about other things.

That said, I do still take time to try and iron out patterns I see springing up when I’m writing software – I get too excited about the imagined gains from automation. I guess I’m delusional in that way.

Funny because everyone seemed to be yelling this into the void (twitter) repeatedly, and by gosh they were right. Time to market is important. Who knew.

What’s your approach to testing? (unit level? integration? testing environments?)

It depends on the project. The really crucial bits of my infrastructure (I’ve got a project I reuse a lot that I call “ReadySetSaaS”) are heavily tested. The most important tests are the E2E tests, then there’s integration and fairly few unit tests.

It’s certainly a hot take and basically justification for arguably bad habits, but if your type system isn’t at least capable of making most unit tests

(RANT) dynamic languages are great, but it feels like they’ve both progressed the programming world and set it back like 10 years. People spent a lot of time getting excited about being smart enough to check for -1 for a function that was supposed to take natural numbers (1-Infinity)

What’s your git workflow? (commit to master? PRs? How detailed are your messages?)

I use a form of loose git flow. If I’m on a roll or want to make smaller changes or just don’t care, I commit to main/master. BUT, for actual focused project development, I normally have a list of some sort which means I generally have a goal for some part of the day, which means I generally start a branch.

It’s obvious/common sense at this point. Doesn’t mean it always happens, but it feels like common sense to me at this point.

Every once in a while there are tools that are transformative to my workflow though:

  • Embracing Makefiles for disparate contexts
  • Light standards like Conventional Commits
  • Tools like git-cliff are amazing for building changelogs
  • Squashing and merging (I believe I first cut my teeth on this at one of my first jobs out of college – learning what the heck git rebase did and having to do it manually absolutely changed my life)
  • emacs + magit til.

How do you track what you’re working on and prioritize things? (kanban? github issues?)

I’ve found what works for me is TODO lists. I make issues but I mostly make issues for things that aren’t top of mind that I want to remember for the future. I know if I go to any project I’ve worked on and don’t know what I want to do first, I can always look in the issues. But for day to day issues on active projects, I have a TODO list going that have at least 5-10 top of mind things that should be done.

Sometimes I make a -business repository and actually keep TODOs (along with other resources – social media stuff, marketing copy, blog posts, etc) in there and iterate on/update that instead of anything else.

I used to use Gitlab’s kanban view a LOT. There is a metric ton of value locked in Gitlab and I’ve been a heavy user. RIP the Bronze plan. GitHub is catching up a bit these days though – they got Kanban and list views all at once and now have quite the compelling product. It’s crazy.

Do you collaborate with others or primarily work on your own? If you collaborate, how? (PRs, issues, chat, email, etc)

I primarily work on my own when it’s projects I’ve started/dreamed up. When I need to collaborate I lean on email a lot, and get on calls or cowork with people, but that’s relatively rare.

If I’m working with someone else, it’s probably because I’m being paid to, which to be fair is a lot of the work I’ve done.

If someone comes to you with a project, what tech do you reach for and why? (frontend, backend, email, authentication, css, etc)

We could probably fill the podcast up with just this section. I’m a consultant for my “day job” (though honestly my day job at this point is building Nimbus Web Services – I once again apologize to the wait list, it has been quite the wait!), so this is my bread and butter.

The answer to this question is “it depends”.

From a code-first standpoint:

  • If I want to be fast, I pick Typescript (note I did not say Javascript, I said Typescript – big heavy opinions there).
  • If I want to be correct, I pick Haskell
  • If I want to be fast, I pick Rust

In the real world:

  • It all depends on what the client is comfortable with. For a long time the world just seemed like Java shops and Rails shops.
  • Infrastructure wise AWS is going to be the answer they want to hear 90% of the time
  • Pulumi > Terraform (but most of the time people just aren’t ready to hear this. I’ve been saying this for what feels like forever)
  • Authentication 90% is best done with OAuth2, but you can roll your own in a pinch
  • None of that SASS/SCSS nonsense. CSS + variables is great these days if you can get isolation from your component lib

What I’m actually doing (most recent first):

  • Front (Web/UI)
    • Svelte
    • Vue
    • Lit
    • Plain HTML
    • Tauri for desktop apps
  • Middle (API tier)
    • SvelteKit
    • NodeJS (tsoa, NestJS, Fastify, good ol’ Express – the (req, res) => void pattern is undefeated)
    • Rust (Axum – I’ve tried actix-web, tide, warp, tower-web up until now)
    • Haskell - Servant, it is the way.
  • Back (DB)
    • Postgres
    • SQLite and I almost always regret it when I want to do a rolling deployment or scale out.
  • Infra
    • Kubernetes. Kubernetes. Kubernetes.
    • Ansible
    • Pulumi
    • Shout out to dnscontrol (a bit niche but excellent it’s quite good)

Big believer in the 3 tier architecture, but have recently mashed the front two together when I can force myself to and really think about time to market. I think seperate repos for front and back are optimal, but it’s just faster to have them be one codebase.

How do you handle application performance monitoring, error tracking, and general logging?

Performance usually just… isn’t that much of an issue.

Early on I used to just make sure to set up emailing to myself on error points of important flows. I saw Graylog for the first time in like… 2016/2017 and it was amazing to me. Shame about their mongo dependency. Jaeger and Zipkin are revelations I got a bit trendier and started doing more log aggregation ELK, EFKK. It always felt like overkill to me.

Logging stuff landed on Loki + Fluent Bit which outputs to a Grafana dashboard I never look at.

Shout out to Statping and statping-ng – statping is abandoned now but it is/was a fantastic tool. Super robust, did most of my basic monitoring for a long time.

The most effective O11y I do these days comes from adopting GlitchTip – it’s self-hosted Sentry and I really like it. Usable with the Sentry libs and easy to self host, though I had to definitely do some deconstruction on the architecture to figure out exactly how to host it on kubernetes.

Examples of professional projects you’ve had, the tech you chose, and reflections on them

I’ve been… at a lot of companies. I wasn’t always leading projects but when I was the choice is always Typescript and Postgres It’s a devastatingly effective combo. It doesn’t beat Rails but I’m not a ruby/rails fan so…

What tech have you not liked and why?

I literally just don’t do .NET anymore. I did two contract projects a long time ago – one was in NodeJS which was an absolute breeze, fit in well with the existing systems, etc.

The next project was in .NET – I was initially excited since it would be one of my first forays into writing C#/.NET ASP.NET since way back in my first internship when I was doing VB/.NET 4. I was excited to see what changed, if it really was the “better Java” that everyone claimed it to be (basically Java made a bunch of mistakes that supposedly C# and the .NET ecosystem learned from)

It was terrible. The project went terribly, C# itself was in the middle of some drawn out transition to Core and Standard (?). Entity Framework (4?) was being reworked at the same time (tied somewhat to the larger core/standard migration), so a bunch of stuff didn’t work. I generally don’t even use ORMs but that was obviously not a good idea when the rest of the team (and the ecosystem in general) was quiet invested in EF.

Async behavior was weird… I don’t remember all the specifics now, but Async things weren’t directly await-able, they had inner task objects… but then when you got the result you had to do some digging or awaiting or something. I just remember thinking to myself “why would anyone design it this way”. I think I wrote a screed about it then deleted it because I just didn’t have enough time in the ecosystem – no one wants to hear a noob complain about an ecosystem they barely use and came to hate.

I couldn’t run any of it on linux (mono wasn’t far enough along yet) so I had to get a Windows VM. I dreaded working on that project. I resolved that I would never touch C# again. It just isn’t worth it.

Even F# is just weird Haskell (Scala is ugly java-fied haskell). I can’t do anything in the MS ecosystem. It’s just weird to me to write software in Windows these days. Who does that? (I fully realize that most of the world probably does, especially with VS Code reigning supreme these days)

How do you approach side projects differently than your professional work?

I have to do so much more of the “business” that it’s really interesting. There are so many skill sets that just a simple architect or senior engineer doesn’t have. There are completely different ball games out there. I have to approach side projects as a lot more of a novice and learn more – I didn’t know anything about paid ads years ago (i.e. how many of the FAANGs make their insane revenue numbers), but the internet makes so much more sense when you do.

It’s like being introduced to Indie Hackers for the first time – what they think about is very different from the average FTE. Not better or worse, but different and usually with wider breadth – they have to, because there’s no one else.

There’s also usually a much higher need for me to mentor or manage colleagues when doing professional work. While I do enjoy helping teammates and leading teams, I’m usually brought in to fix a big technical problem in the first place.

During the yak shaving process how do you compare options and come to a decision?

I think it’s become one of my super powers/skills at this point. It’s certainly something I charge for and one of the reasons people come to me for consulting. I spend an unreasonable amount of time seeing, evaluating, placing and trying to categorize software and infrastructure projects.

I started Awesome F/OSS because I thought my list of what I thought was amazing self-hosted and F/OSS software was too big and needed to be shared.

For me it’s all about finding differentiation. One secret is that the mark of quality in a project is when people have good documentation (obviously), but more importantly put that little X vs Y section in there. It shows that they’ve gone around and looked at the surrounding ecosystem and know why you should use their thing and not something else. If they don’t have that section, you have to find that yourself.

What I love to do when I get the chance is double back and do benchmarks/try out experiments. I have a humongous list of outlines for blog posts and experimentation that I want to get to try some day, and recently I’ve been getting that done by taking on entrepreneur-in-residence/developer advocate role/writing roles at various companies – recently the most famous being a string of article for Supabase.

I have to admit I’m not that data driven, but there is a certain joy in being able to go back and see just how much you’re paying in memory efficiency for project X versus project Y. Or just how much faster project Z will serve requests than project A.

For lots of projects you just need to get down and dirty and feel them out. That’s the thing about yak shaving – it takes patience and time and most people just don’t have that these days. There’s a flip side though, it literally cannot matter how good you get at yak shaving if no one ever asks you to shave a yak – so I consult and I try to share my knowledge for my own ends and others.