Recent Content

Advent of Code Reflections

posted on 2022-01-23 18:00:00

It's been a busy start to 2022. I'm working as an Engineering Manager for the first time and enjoying it but it's been easy for other things to slip through the cracks. For example, I told myself I would write a post on Advent of Code several weeks ago. So I'm sitting down to write about it now before I forget any more details.

Background

This is the second time I've attempted Advent of Code. The first time was in 2020 and I enjoyed it a lot but ran out of gas around day 10. I was pretty distracted with a Flamingo Squad project I can't recall and probably a bit burned out. Both years I've written my solutions in Common Lisp.

Advent is interesting. I get enjoyment from different things on different days. Some problems I just enjoy seeing how much I can optimize Common Lisp, or writing solutions in a few different styles if the problem is simple and seeing the differences in how they are compiled and allocate memory. Other problems I'm much more satisfied by trying to see how "pretty" a solution I can write, either using constraint solving tools like Screamer or a pipeline using threading macros and so on.

I enjoy the social aspect of AoC and having a leaderboard with some mutual friends and coworkers. It's nice to chat about something besides production code with other talented programmers. That said, I have to be pretty careful to avoid judging myself. I have to consciously remind myself that my goal isn't to "win the race" and not worry too much if I struggle to solve a problem elegantly.

Advent 2021

There were two things I wanted to try and do differently this year from last year. The first was just to go as far as I could and not worry about racing. The second was to experiment with literate programming tools and try to do a better job documenting my work.

I think the results were a mixed bag. I got through day 11 so I powered out at around the same point. I mostly worried less about the race but I still cared a lot about finishing each problem on the day it became available and definitely got discouraged once or twice when I didn't like my approach. On the other hand, I had a good time and learned a few things so it's a good investment overall.

Takeaways

  1. MGL-PAX is awesome
  2. My graph traversal foo is weak
  3. I know ways I'd like to evolve my style

MGL-PAX

I have been meaning to play with mgl-pax for a long time. Like ... probably several years? There are blog posts about it as far back as 2014 and it's been on my radar a long time but I just never seemed to make time for it. Advent seemed like a good place to play with it.

I like the idea of an environment where prose about code and code are intermingled, so I have a natural attraction to literate programming. This shouldn't surprise you if you've been here before. In terms of Advent of Code problems, I'd ideally be able to do the following:

  • Keep the prose and code for a given day/problem in a single file
  • Easily export the entire project to an easily navigated and read web page
  • Make it easy to show different versions of the code as well as disassembly or evaluation examples

I think MGL-PAX is excellent on the first two points and struggles a little bit more on the third. It has a feature called transcripts which could plausibly support what I'm talking about. Transcripts allow for including examples that are evaluated when the documentation is generated but there are two issues I have with it:

  1. The results are actually embedded in the source code. The argument for this is that they are parsed and checked to ensure the code and example don't get out of date somehow. However, this will never work with processes that are inconsistent like, say, the memory address of a disassembled function.
  2. The result of a form to evaluate could easily dwarf the function itself whether we're talking about disassembly or just a function that generates a sizable data structure.

In short, I'd love to see MGL-PAX support pretty printing the result of an expression into the docs with a given 3BMD syntax highlighting. If I can motivate, it may be worth me hacking something up.

If I start a large project in common lisp in the future, I'd definitely be interested in trying to use MGL-PAX to document it. The build-site function and deploy script for my advent-of-code project were quite simple to put together. It was more complicated but quite satisfying to hack together something that generated an overview with performance measurements for all the days that had solutions written.

Graph Algorithms

Evolving my style

8 Good Games (since 2013)

posted on 2022-01-01 13:40:00

Since Last Time

A long time ago when Norma and I had just started dating and I hadn't ever taught anyone to program, I wrote a post. In it, I talked about some of my favorite games. It was mostly just a list with a little added color here and there. But it's time for an update, and this time I hope to do just a little more than list some favorites. I'm also a little aware of how I weighted things last time. When I wrote Beloved Games, I wanted to make sure the times in my life with the most gaming (middle school and high school) had the bulk of the entries. I also wanted to show that the gaming experiences that had been managing to pull me back into the fold and affect me at that time were small downloadable indies, a relatively new phenomena. Those games offered new experiences more regularly than AAA titles so I also was careful to not include more than one game from a particular genre or series (which were relegated to honorary mentions).

The List

So, what really struck a chord with me in the last 8 years? I'll just list the titles first and then delve into more detailed thoughts and justifications. These are arbitrarily in order of least to most long-term impact on me personally.

The Last of Us

The Last of Us is an incredibly compelling story and one of the best games of its generation. The value it has to me has less to do with the gameplay though, and more to do with the quality of its presentation, the rapport it builds with its cast, and the more serious themes of its plot. In some ways, The Last of Us reminded me of when I first played "Metal Gear Solid". The themes it dealt with were more mature than what I expected of games at that time and it pushed the envelope of how to tell a story in games compared to its contemporaries.

The interesting thing about such games is that they make a big impact at the time of release but wane later. By pushing the medium forward, if you miss them when they came out it becomes notably harder to appreciate their qualities many years down the line when the lessons they teach are internalized by other works in the medium. (The same thing happens in film, of course.)

The reasons I started disconnecting with games in the late aughts and early tens was two fold. For one, I was really starting to grow up. I had a lot of opportunities to do fun things IRL that weren't available to high school me. I was being social more, studying more, working more. I was living more. That focus made it harder to justify lots of time spent on gaming experiences.

The fact that AAA games increasingly were just rehashes of existing series or well-formed genres was just the nail in the coffin. The Last of Us is an amazing title. But it is a continuation of the established mold of "story-driven 3rd person action adventure". That's not to undersell its accomplishments at all, but I think there are limits to how much that can impact me now.

Skate

There isn't a ton to say about Skate. It should've been on the original list and it wasn't. I can clearly remember spending the night at a friend's house in 1999 and his insistence at Blockbuster (really dating myself here) that we rent a skateboarding game. I thought it was the dumbest idea I'd ever heard. Why on earth would that be any fun at all?

Tony Hawk's Pro Skater got me into skateboarding in real life. It is the first ~~physical~~ athletic activity I remember really liking. It was also the first hobby I picked up and really enjoyed despite knowing I wasn't particularly talented at it.

Tony Hawk as a series has always been an arcade game rather than a Sim though. I discovered Thrasher's Skate and Destroy in high school and eventually favored it because it was closer to how I would really want to skate than the mindless combo fodder of THPS which was better for playing with friends.

Skate came out in 2009 and was probably the first PS3 game I was really hype about. That or MGS4. Skate took a great budget and the notion of a Sim skateboarding game and nailed it. I loved the whole series and eventually started playing it more than really skateboarding. Whoops.

Breath of the Wild

What was the first "Open World" game? Do we count GTA 3 and Vice City or do we wait until Assassin's Creed and Skyrim? Is 3rd person perspective required? I realize Elite was a thing but I wasn't alive for that. Breath of the Wild is probably the first so-called open world game that I gave a damn about it and that's the least interesting thing about it to me.

Ocarina of Time feels like the first open-world game that I played and was really captivated by. It comes down to the same crucial thing: an insane dedication to compelling world building. There are tons of open world games that just feel like endless content with no soul, no hidden inner workings, just the result of needing to fill a virtual space rather than a thing that has a logic of its own. In a game like GTA where most people play by just causing chaos and trolling authority in a controlled space that's fine. But in a game like Zelda, it makes all the difference.

I don't remember if I played Breath of the Wild in 2017 or 2018. I never finished the story. I just enjoyed exploring a well-crafted world until I'd had my fill. I don't know that it changed how I thought about games or what they could be. It was just the perfect way to relax and enjoy Hyrule.

Persona 5

Final Fantasy convinced me I liked JRPGs but I never managed to break into the genre more broadly. I really enjoyed FFVIII (my first) and FFX. I never played 1-7 (I know, I know) and started but never finished 9 and 12. It mostly came down to an enjoyable world to explore, an interesting (or at least tolerable) cast, and great art and music. Persona 5 was the first JRPG I managed to play outside Final Fantasy and I think the only reason I didn't finish it is my wife got impatient. I enjoyed watching the rest of her playthrough. One day I'll finish my own.

JRPGs often have an adolescent feel to me and I think it's probably essential that they do. I was a shut-in during high school even though I'm pretty extroverted. I had close friends but still managed to doubt that I'd figure out life: jobs, relationships, a future. JRPGs are great providers of "safe freedom" and a coming of age setting. They build faith that you can figure things out and win, often in a style that suits you.

Persona 5 nails this more than any RPG I can think of. It has incredible art and worldbuilding, an engaging story, and genuinely interesting relationships. It is the only RPG where I've been compelled to micro-optimize whether I study, work, build a friendship, or fight demons after school. How they made it both fun and relaxing, I'm not sure.

Hades

You've probably already heard about Hades. (And most of these games, in fairness.) It won Game of the Year from many publications. It is the first roguelike I have loved. Roguelikes are tricky for me. It's interesting to separate the games on my lists between an attraction for worldbuilding/story vs mechanics/gameplay. While there is definitely a spectrum, games are fairly even dividied as to what the big draw is for me but it is exceedingly rare for me to like a game that doesn't have strong art and storyline to rope me in.

Roguelikes as a genre promise variation from randomly generated elements in a playthrough and multiple ways to win but often struggle to have the same draw for me as games with more linear stories and higher production values. It's hard for randomly generated worlds to have a soul. Call me shallow but there are exactly 3 games on my lists that I would say don't matter to me at all in terms of story and characterization: Mega Man 2, Super Stardust, and Melee.

Lots of indie roguelikes (and metroidvanias too) struggle to not just be fun to play but also compel with their characters and sense of place. Hades brokethrough for me by having a very strong sense of meta-progress across runs, a very engaging story, beautiful art, and an amazing capacity to build enjoyment through more options the longer you play. It's hard to explain but it's magic. I remember saying the same thing about Persona 5 at some point, "It just keeps opening up".

Celeste

I love platformers. The last few years have really driven that home for me. Celeste took me a while to get around to because, well, the art didn't quite impress me. And I was fresh off playing Hollow Knight so my bar was probably a little high. It also didn't have combat and I wondered how the gameplay would develop to keep me engaged without it. That was a foolish mistake.

Celeste is one of the best platformers I have ever played, has a memorable and moving soundtrack, and one of the most thoughtful treatments of mental health in video gaming. It is brutally challenging while also encouraging the player to push onwards. For all its difficulty, kindness is somehow in its design. I am not one of the people who completed all the optional B and C-side content and probably won't be. I am immensely happy I took the time to pick it up.

Hollow Knight

We're really getting into the heavy hitters at this point. I loved Hollow Knight. Really loved it. I've been eagerly awaiting their follow-up game Silksong for the better part of 2 years, clinging to any news at all and hoping for a surprise release announcement constantly.

Hollow Knight is the complete package. A new IP from a formerly unknown developer. Just enough story and lore to have you curiously driving forward while retaining an air of mystery. Absolutely stunning artwork and animation combined with a fresh setting. A beautiful soundtrack to accentuate exploring. A sense of perpetual "opening up" as new mechanics and abilities are unlocked. And most important of all, beautifully tight physics and controls. The kind of game where it "just feels right".

It's been years since I've played it and I regularly entertain thoughts of playing it through again (which I don't really do with games). I'm sure I'll love it for years to come. Here's hoping 2022 is the year for Silksong.

Melee

I ... probably should stop the article now. Melee is a force. I played Super Smash Bros for N64 and Wii in college and really enjoyed it. Few things are better than beating up your friends with Nintendo characters. It's just a fact. But Melee is something else. You can play it the way you play the other smash games. It can be chaos with friends, random items and silly stages full of hazards. Or you can turn off the most chaotic random elements and stages, practice movement with your character, and turn it into possibly the most interesting competitive game I've ever played.

I started playing at the end of 2013 and I haven't stopped. I've traveled out of state with my friend Max to compete in national tournaments. It is the only fighting game I know of that has multiple tournaments with prize pools in the tens of thousands of dollars 20 years after release with no backing from its developer. I am closer to understanding fans of real sports because of how many times, how many seasons, I've watched twitch streams of major tournaments with tens of thousands of other spectators, rooting for pro players I think can break through to the next level of play or conquer their demon.

There are at least three high quality documentaries I can think of off the top of my head chronicling the game's competitive history and the stories of its players. There are countless sets I've loved watching. The melee I see played today has evolved from 2 years ago, which has evolved from 2 years before that, all the way back to when I started playing eight years ago. I have recordings of me playing in 2014 and 2015. I can't express how different they look to when I play now.

When does a game become more than a game? I think it's when the dedicated, long-term efforts of thousands and thousands of people force it to continue to grow and change until it no longer resembles it's humble origins. Every time I think the game has been pushed to its limits and all its secrets have been revealed, I'm proven wrong whether it's at the next tournament or the one after. It won't surprise me if Melee is still being played seriously 20 years from now. And even if it isn't, it's been one hell of a ride. Some good links below if you're interested.

Video Essays:

Documentaries:

Grade A Youtube Content (from entertaining to educational):

One very good recent set:

Compilations and Combo Videos:

Deliberate Action

posted on 2021-12-31 15:15:00

2 years in a blink

I hardly know how to count the time. In the past ~2 years, I left Flatiron after helping start the Atlanta campus, started working at Calendly, been a best man, got married myself, weathered a global pandemic, and recently became an Engineering Manager.

A tremendous amount has happened, but I feel like I've lost the boy I remember from college a little. He was excited about things: video games, music, common lisp, poetry. This blog has also atrophied for nearly a decade, torn between being an outlet for personal interests and reflection and a more serious place to cultivate a professional(-ish) voice.

Focus on Habits

I was talking to my close friend James recently about working in tech. James is probably the sharpest engineer I've had the pleasure to work with and he was discussing getting better. I asked him what it mattered, or more precisely, what he would be able to do if he got better that he couldn't do now. His answer surprised me. He said, "I really don't think about outcomes."

There was a little more to it than that but the short version was, he keeps an eye on how much he's learning and places bets on what will be interesting and provide good opportunities to grow. Then he just walks in that direction.

By contrast, I have an almost total inability to pursue things without thinking about the outcomes in advance and evaluating my progress after every minute step. I doubt I'll ever be able to suppress those urges completely, but picking a direction and moving without so much analysis paralysis is something to work on.

Rather than worrying about the past or where a certain choice will take me, I hope to pick a direction and just walk. I'll form a habit, live with it for a while, and try to feel it out. I'll know soon enough if I want to continue.

Goals for 2022

With that in mind, these are some things I'll pursue in the coming year. There are two overarching themes: allow myself to goof off when needed, and pick just a few things to chip away at instead of debating 100 projects. I.e. Do more, deliberate less.

Waste Time

It's time to pursue the childlike joy I remember that college kid having. I'm not sure exactly what form this will take. One thing I'd like to try is getting back into video gaming again. I haven't allowed myself to play many (single-player) games for the last few years. I make up stories about how they're a waste of time and I "should" do more productive things. But then I waste time in other ways to avoid being productive. Games are good. Maybe also some things like trying to learn Chess or mess with emacs.

Use the Internet Less

Social media is a wasteland and it's all too easy to simply fritter away time. I've read the internet enough and while there are some high quality blogs I enjoy, my time would be better spent reading books, writing code or prose, or goofing off with games or Norma or friends. So, use the internet for work, pushing code and blog posts, getting new music, and chat/slack. The end.

Write More

I used to blog more. I blogged about all kinds of things. I was (and am) a culture nerd. I wanted to talk about Music, Movies, TV, Games. It wasn't just code all the time. I also wanted to talk about code and, in particular, I relished in things that seemed cool but I really knew nothing about. And that is one of the uses of my computer that I've never regretted. Writing somehow always winds up feeling like an at least decent use of time. (I probably just like the sound of my own voice too much. I did teach after all.)

I hope to keep experimenting without aspirations, without outcomes, and writing about what delights me and what I take away from my dabbling. I hope I write more here in general about everything! To preserve a record for future me, or for anyone else who might be interested.

Crafting Interpreters and then other technical reading

I've got such a long list of programming or CS texts I've meant to work through. And it's hard! After working at a software company all day, even though I still want to know more about various aspects of computing, it's just not appealing. However, I'm pretty disappointed that I still haven't written a toy language implementation, finished an emulator, worked with C more, etc etc.

Crafting Interpreters is a great place to start in terms of technical topics I'm interested in and I have a friend who is also interested in working through it. Community always helps. After CI, there are certainly other things I'm interested in. I don't have a strict list of priorities but a proper algorithms book (Vazirani/Dasgupta or Erickson probably) or a good "systems" book like CS:APP would likely be next on my list. I'd also consider a look at Software Design for Flexibility or Lisp in Small Pieces of course. :)

I'd also like to read some non-technical books. The Elegant Puzzle would be good to get a better grasp on engineering management and I've got a few books on Chess that might help improve my play as well. But Crafting Interpreters first, then I can worry about "what's next".

Wrapping Up

I can always list plenty more I'm interested in but if I can focus on these three things, I think I'll have a lovely year ahead. Here's wishing for a return to normalcy from the hell years of COVID and joyous new discoveries for us all.

Reboot

posted on 2021-08-30 16:07

This has been an incredibly full and difficult year. Norma and I got vaccinated. Her mother had a serious and ongoing health crisis for several months. During that period, we both had unusually busy quarters at work. I applied for a promotion at the encouragement of both managers and peers and narrowly missed it. My product manager got hired away to be a CPO and several engineers left the product section I work in. As a result, the squad I started is being re-absorbed into the other squads in our product group. Management hopes to restart it at a later date. Finally, the long discussed garage renovation on our home is completed. Now it functions as a climate controlled office and synth dungeon.

At the end of all this, I'm deeply exhausted. I'm very thankful that lately I have been able to enjoy much more human contact thanks to being vaccinated. Seeing friends in person and giving them hugs goes a long, long way. I'm trying to get back in the groove on pursuing creative projects but it's very hard.

Lately I've been thinking about how if I don't choose to enjoy my days, then I am likely to stress myself out. Work can't make me happy, relationships can't make me happy. I care deeply about relationships and community but I have to choose to enjoy my own experience. I have to choose to validate who and where I am. I deserve to feel good. If I don't choose to let myself feel good, and pursue the things that excite me without judgement, then I will find a reason to be hard on myself or stress myself out.

I've been having to remind myself that neither money nor work nor relationships are inhibiting my ability to lead the life I want. It's all me at this point. I just have to start living more fearlessly and letting myself be me in the way that feels right. Damn the consequences. Something to keep working on. Step by step.

Feeling Stuck

posted on 2021-03-07 22:15:00

It's been a year and I'm still thinking about Halt and Catch Fire. I haven't started my 3rd rewatch but it'll probably happen soon. I wrote a bunch of toots about it recently but it may not capture how I feel as well as this infovore article.

The reality is, I love the show because it's about people learning to have healthy relationships with work and to love themselves. I tend to form great bonds with coworkers but my relationship with the work itself and my ability to love myself is just damned fraught.

I feel unbelievably drained lately. I'm in a weird place at Calendly where I'm sort of in between being an IC and a Manager. I'm convinced I'm doing less work than ever while receiving good reviews and "Top Performer" recognition. I just find it insanely hard to praise myself. I've thought a lot about it and one reason I've struggled so much (and sought a Team Lead position) is that I don't know how to praise myself for writing software.

I had to think really hard about that to realize that I don't like much software. People use computers in all these ways that just don't make sense to me. The software I get the most excited about is small and personal. An emacs configuration. A 1000 line blog engine in Lisp. A handcrafted website conveying intimacy and joy.

It's okay that professional software isn't about that. But I have a very hard time figuring out what the "best way" to architect large systems is because I don't want them to exist in the first place. I can speak up when I see an obvious way to improve what we deliver but I actively avoid ownership because it's not the software I want to see in the world. Or at least that I want to use.

That's left me in a tough place trying to figure out what I want to do next professionally but it's been an important step. Maybe moving to a more managerial side will be good. I'm also aware that I am much more able to praise myself for my efforts as a teacher than as an engineer. Teaching is, in many ways, more congruent with my values. For better or worse, teaching examples are usually small applications that can eschew most of the thorny aspects of production software.

It also hasn't helped that I've struggled to commit to hobby coding. I've struggled with depression a lot throughout the pandemic. I get a ton of my energy from my sense of community and sharing experiences with close friends. It's been very difficult to keep a good perspective stuck in the house all the time. I'm also aware that coding all day has taken a lot of the desire to joyfully explore a computer in the evenings away from me even if I did have collaborators handy. I turned a hobby into a career and I definitely have some regrets about it lately.

One thing I have enjoyed in the last few years is listening to a lot of electronic music and starting to dabble with synthesizers myself. With Norma and I both working from home though, the former pseudo-studio space has become a home office. We started remodeling the garage to be a hobby/office space last November, but that work still isn't done.

So here I am. Coming up on the 12 year anniversary of Dad's death, the 10 year anniversary of my entry into the workforce, and my 35th birthday. I'm having a hard time forming healthy habits for managing my stress and not sure what I want to do next. I don't feel I can complain because, well, I'm extremely well off! Calendly is doing well and treating me quite well, I'm safe and at home, in a supportive relationship, my family and friends are safe.

And yet, the urge to pull the plug and change my circumstances is so powerful. I might consider it if only I was certain about what I thought should come next.

Heaven is a Place

posted on 2020-04-14 14:35:00

NIM

Songs of the Day:

  • Pixies - Velouria
  • The Sea and Cake - Four Corners
  • Blood Orange - You're Not Good Enough
  • Soccer Mommy - Circle the Drain
  • Wild Nothing - Midnight Song

It's been a bit of a week. I'm on vacation from work, thank goodness. I had really run out of steam on my projects. It was difficult to focus and I was berating myself a lot which only makes things more exhausting.

There's so much I want to work on.

I have a really, really hard time making myself happy. In a lot of ways, I think I don't know how to play by myself. You would think as an only child that it would come naturally, but it really doesn't. I mean, I can list things I think I'd like to do: read books, play video games, write code, etc. I just struggle to do any of those things or feel good when I actually do them. I think this is why the quarantine has reminded me of what summer break felt like as a kid. There was an initial elation at this sudden freedom in your schedule ... and then a gradual despair as nothing seems to matter without someone to witness it.

I've been rewatching Halt and Catch Fire and very emotionally attached to it. I think one of the reasons is that it's about these characters who obsess and get fixated on projects but really struggle in their relationships. I feel like I'm pretty happy with my relationships but hate myself for not moving forward on the projects I fixate on. I identify with multiple characters on the show and I think I struggle emotionally because they wind up alone, both romantically and in terms of collaborators. In many ways, the show is about failure and how the characters deal with it. And after seeing them grow as people, work so hard, and love so fervently, it's heartbreaking to me to see that failure.

I've been struggling with a need for external validation my whole life. I think there are a few components to that:

  1. I don't really trust my own evaluation of myself and my contributions. This is mirrored in HCF when Joe asks Cameron "What is it that I do?". He honestly can't convince himself that his contributions make people's lives better rather than worse.
  2. Because I get very fixated on what interests me or how I think things should be done, I need to have a fair amount of autonomy or executive function to be happy and have fun. But if I'm doing anything (project or recreation) purely alone I lose steam and belief that it's worthwhile. The need for both structure and validation from collaborators while choosing not only the activity but also most of how it's carried out makes it really hard for me to find people that will come along on adventures with me.

Two different relationships in my life stand out as being unusually good for me by playing to these challenges.

  1. The Iron Yard was probably the happiest I've been at a job ever. I had a tremendous amount of freedom and responsbility in how I ran my classroom. But thanks to the other staff and the students, I never really felt like I was "on my own". I rarely got into that crazy "does it matter, is it really worth anything" headspace. I had external validation (mostly students), collaboration and friendship (staff), and autonomy in how goals were pursued. There was some tension because I sometimes wished I could change the broader educational goals or thought we weren't honest enough with our students about the challenges they would face, but this was dwarfed by the rest.

    I think this is one of the reasons teaching has often been a good job fit for me. Quoth the showrunners from Halt, "I think teaching is a way to spread your love of a thing without needing to be the victor in that particular arena." In a lot of ways, I struggle to to be an engineer instead of a teacher because I either genuinely don't think the technical problems at the company are interesting or because I think I need to be the victor to prove my worth. In teaching, the problems aren't the important thing, getting people to connect with themselves and their curiosity is most important. Tech is just the setting. That feels almost perfect to me.

  2. Ben Minor was my roommate both in college and after and is one of my dearest friends. Ben is a very easygoing guy and happy to do most whatever you want to do all the time. It helps that we have some overlapping interests (aside from code) but in 15 years of friendship, he's rarely not been open to doing whatever I feel interested in doing.

    I often have a hard time working on things on my own. Even if I'm legitimately interested in them, I struggle to make myself believe that they matter or generate forward motion pursuing them. I desperately want collaborators. But frankly, I'm pretty difficult to collaborate with because I have both pretty specific ideas about what we should do and how we should go about it. This makes me relate to Cameron from Halt and Catch Fire because she is genuinely terrible at working with others even though she would love to. She needs to be the special brilliant child a bit too much.

    But this also extends to how I relax and have fun. In an interview with the actor who plays Joe Macmillan, he said: "He wants his friends to play his game. I guess that's his flaw. He wants to be in the sandbox with his friends, but he wants his friends to be building the same sandcastle."

I don't know how to fix this, or even how to work on it really. Norma mentioned recently that when something makes me unhappy my reaction is to stare at it until I feel I understand or can move past it rather than to be avoidant. It results in a lot of unhealthy feeling "stuck time" where I feel anxious and spiral into my unhappiness. Hopefully one day I can find a little more peace, knowing that I'm valued in the world for loving people in spite of being a little hard to work with. I'm still a bit worried that I'm not a great software engineer because I'm more interested in studying, learning, and sharing, than building things. But one thing at a time.

So sure, this week I would love to:

  • Work through Crafting Interpreters
  • Rewrite the graphics layer in Clones
  • Work through more On Lisp, SICP, CS:APP, or Algorithms
  • Investigate tools for literate programming / publishing programs
  • Start using org-mode
  • Make a great mixtape

But I have to take care of myself first. And today, that might just mean doing laundry, missing dad (and wishing I could listen to music with him), cuddling the dogs, and writing. Maybe I'll spend some time in the hammock. All for now...

In Praise of Unfocus

posted on 2020-02-01 22:45:00

De-emphasizing output

I often tend to judge myself, at work and outside of it, on my output. Old habits are hard to escape. But there are a lot of reasons this is an instinct to be resisted. First of all, if you're tackling suitably interesting projects it may be hard to predict progress or even define good stopgap goals. Many people experience cultural pressure to measure themselves in terms of their output or to be efficient in all things they pursue. That distortion in what we value often leads to a lopsidedness in our goals and pursuits. There are two defenses that have stuck with me lately against such ideas. So I want to tell you about them in the context of last Sunday when I was unfocused and then anxious about having spent my time that way.

Breadth over Depth

In a single Sunday I got excited about: 90s techno (Tri Repetae, Hard Normal Daddy), new techno (Djrum, HVL, John Talabot), Smash Bros Melee both for its depth to competitors and my choice to be only a semi-serious player, a study group I started at work to go through Crafting Interpreters, making music with Modular synths, making music with Renoise instead, Open hardware efforts like Pine Phone and MNT Reform, Grammatech's open source SEL project for doing Binary Analysis and modification with Common Lisp, InterimOS, and a slew of other odds and ends.

Even if these cluster around nerdy themes, that's an awful lot to enjoy in a single day. It's easy to lament that nothing was produced, that there is no output to share, but that ignores the fact that being plugged in to so many things often means forgoing total immersion in a single piece of subject matter. And there are network externalities at work too. Discovering music means I can play it next time I co-host The Mobius on GA Tech radio with my buddy Matt. Being aware of software and hardware projects means I can share resources with other hackers.

People over Performance

But all that wasn't enough to keep me from worrying that I don't focus enough. Or I focus on the wrong things. I had a performance review coming up at work so that might have had something to do with it. Even though the company has a relaxed culture, I'm a worryer and a catastrophizer by nature. I was getting worked up over the fact that I don't ship as much as some other members of my team. I was trying to imagine exactly where the bar was and what objective, quantitative measures would be used to evaluate my performance. I was thinking about how I had never felt like I was the developer doing the most challenging or glamorous work at my past jobs and I still had a slower rate of shipping tickets than those taking on that challenging work.

After a little while, I thought especially about Emcien. Emcien was a great opportunity for me and a cool Ruby/Rails shop to work at. I was there from early 2013 to late 2014. More so than other jobs I've held, I think of things at Emcien as having gone sour even though I left in decent terms. I got into a negative headspace about the value of my work and its perception in early 2014 and that re-inforced until I was dragging my feet constantly. I wound up putting in my notice because I was unhappy, but the work environment didn't do it, I did it to myself. So, did it end in failure?

Here's the really interesting part. After I left that job, where I assumed I was a waste of money and possibly resented for not being a bigger contributor, I wound up becoming the best man of one of the engineers and a good friend and confidant of another. There were 5 devs total, including me. The 2 jobs I got immediately following Emcien were working with those two individuals and they both had positive things to say about me during the interview process.

Probing for Answers

How do we explain this? There are a few possibilities I can think of. One is that I actually was just as productive as everyone else. Another is that even if I was less productive I was working on things others were not excited to work on and that freed them to do what they were passionate about. But the explanation I like is that while I shipped less code than my peers, I made sure they felt great every day. As much as I was able, I shared energy with them and supported them in their efforts while still making progress on my own tasks, even if a bit slowly. I just loved on them.

It's easy in software to get fixated on people working on the most impressive or high profile projects. I can get tunnel vision thinking about career growth as only coming through huge expertise. But even as a software engineer you can be as valuable for how you support others as for your individual efforts. It could be more important to your career goal to be energizing and well liked than productive. Which isn't to say you should go be popular and ignore your work, just that focusing only on output distracts from a more realistic view of how people function as part of a team.

I sometimes struggle with my instinct to be unfocused, or am ashamed I'll be thought of as a dilettante or dabbler, as if the only respectable option is to be myopically focused on one area of knowledge. To have one project of grand scope. I need to remember, and I imagine I'm not alone, that embracing my varied interests both nourishes me and is a valid choice that can enrich the communities I particpate in.

And that's enough of my soapbox for one day. Happy Hacking.

Five, Seven, and Ten

posted on 2020-01-05 14:30:00

10 years ago, I was studying CompSci at SPSU. I had just gotten my first smartphone, a Nexus One. I had started contributing to my first open source project, Paktahn. Dad had died about a half year earlier.

7 years ago, I had just met a woman I would fall in love with, Norma Nyhoff. I was living on my own for the first time at Arts Center Tower in Midtown. I was a Senior Engineer at Rentpath and not very happy about it. I had written and open sourced Coleslaw.

5 years ago, I taught my first class at The Iron Yard, a bootcamp where I helped over 100 people become programmers. I was living with Norma and our two dogs. We were about to rent a house in East Atlanta.

Last year, I got married. I taught another 100 people to program at the Flatiron School. I joined Calendly as a Senior Engineer. I made substantial progress on rawbones, an NES emulator written in ReasonML with one of my best friends, James Dabbs.

Somewhere I read that "Unattainable Earth", the title of my favorite Milosz book, is most closely translated as "Earth too huge to be grasped". In a similar way, these events feel like they surpass my understanding. In the last decade, a life has grown. I foolishly tend to think of my life as something that is planned or designed, but that is not what happens to us. We take a step and a new world blooms as our feet land.

I hope I can be excited and curious more than fearful in 2020. I hope to write more here and perhaps listen to myself again, the way I used to.

I came up with some resolutions but won't share them. The important thing is the shift in focus. I want to pursue programming for artistic purposes, generative graphics and sound. And maybe learn to solder and build a keyboard. Hardware seems fun, graphics and audio seem fun. The web is powerful but not exciting. So I'll work, spend time with the people I love, and see where my passions lead me.

Research Goals

posted on 2018-08-22 12:59:00

A Recent Dilemma

Lately, I've been thinking about what I want my next job to be and I've been strongly tempted to pursue grad school. I only fell further down the rabbit hole when I read this tweet by Tony Garnock-Jones:

This problem is very close to my heart. Yet I'm ill equipped at present to tackle it. That suggests I should pursue a PhD to get better tools but I have some serious concerns about that (above and beyond selling my house). Let me explain.

The State of CS Research

Thinking about CS academics, it seems that most research aims to support building larger systems by improving software:

  1. Correctness, or
  2. Performance

I feel really weird because neither of those things interest me. Sure, modern software has plenty of bugs and it could always be faster. But software is eating the world anyway.

My Concern

Software is the fastest growing store of "how to" knowledge on earth and is mostly inaccessible, not only to the general population but programmers too.

What do I mean? Well...

There's no such thing as code being "readable", not only because being readable implies assumptions about the context of the reader but also because most programs cannot present a linear narrative! As a consequence code cannot be self-documenting. We should strive to write clear code but suggesting that code is its own documentation is untenable.

I started working on a Nintendo Emulator in Lisp to explore the idea of readable code and see if I could make the emulator source a good pedagogical example of what a computer does. I failed.

My Goals

Now my primary motivation working on the emulator is finding ways to generate an explanation of binaries without just recovering the disassembly. It's the intent and constraints that matter, the shape of the problem, not necessarily the solution the developers wound up with.

Indeed, if we could recover disassembly or even get the original source out of binaries (compilation being an inherently lossy process) that would only get us more code that we would need to comprehend. I.e. More how-to knowledge that isn't readily accessible. Legacy code and software preservation only makes this need more urgent.

I should note that I don't think all software needs to be preserved. I just think it's a travesty that we're 60 years into the project of programming and our tools for asking computers about how programs behave are so poor and so specialized.

Computers could be much greater tools for knowledge dissemination than they presently are because they can execute models. We currently use them to disseminate static knowledge (web pages, PDFs, videos) instead of executable knowledge.

I continue to want to find a way explain code without relying on static methods like documentation, the code itself, or even types and tests. I dream of better tools for communicating and reasoning about the work software systems do than source code.

Putting it in the simplest terms possible:

When I was 8, I desperately wished I could ask my family computer, "Wow! How did you do that?" I still can't today and I spend a lot of time thinking about what a solution should look like.

Footnotes

see also: Peter Seibel and Akkartik, though Luke Gorrie may be a counterpoint

Things I learned writing Clones

posted on 2018-07-29 12:08:00

wip

I'm turning 32 in a week so thank goodness I'm finally making progress on clones. After my last post, I didn't work on clones for 7 months. Then in May, I just sat down and started hacking. Despite some gaps, there has been steady progress.

There's still a lot I want to do and audio isn't implemented so that's next, but for now I'm going to try to summarize the current status and some of the lessons I've learned thus far.

Current Status

Clones, At Present

The Clones CPU emulation is finished and tested and there is support for input handling and basic graphics support (backgrounds and sprites, scrolling is next). A lot of what determines compatibility for a NES emulator comes down to mapper (cartridge) support and the accuracy of the PPU support. In that regard, clones supports NROM, UNROM, and MMC1 though UNROM and MMC1 have some issues that need ironing out once scrolling is finished.

The circuit board used in NES cartridges actually varied and added additional capabilities to the console, primarily a paging system for switching banks in and out of memory to allow for larger levels, more artwork, more game code, etc. The different cartridge types were called mappers. Thankfully, 6 different mappers accounted for something like 80% of all games commercially available in the US. As a result, mapper support is a big deal since you can't play a game without the matching cartridge support.

Clones, In the Future

The first priority is fixing some sprite glitches and getting scrolling implemented. Once that's done, fixing up the lingering issues with UNROM and MMC1 will take precedence. Once Mega Man 2 is booting, then I'll start work on the audio.

After that's done the real fun begins. I have all sorts of ideas and ambitions for how to build a Control Flow Graph of the game dynamically while it executes and then let the player annotate the structure and save it for later revision. I want to be able to reverse engineer old games interactively and am wondering how much the computer can help in the process with the use of Constraint Logic Programming tools like screamer. In general, I'm interested in how we can examine shipped binaries at runtime as a teaching tool for how the software and hardware work.

More on this soon, I hope. 🙏

Lessons Learned

Test ROMs == Joy

There are many test roms for ensuring that various components in your NES behave accurately. I found it particularly useful to write the memory interface, addressing modes, disassembler, and a stepper for the CPU with no instructions implemented. Then I had a unit test which looped over a verified correct log for a ROM called "nestest" which exhaustively checks the operation of all legal CPU instructions. After I could run the test until it failed, implement a single instruction, and re-run. I had all 56 instructions with their various opcodes written in a day. Super pleasant!

It helped that I'd written a CPU emulator before, of course. This process required having a good idea up front about how I wanted to interact with memory, represent addressing modes, and execute instructions. If you don't understand those pieces though, you'll run headlong into them while trying to implement an emulator anyhow so start there. Spend some time reading nesdev wiki or asking questions online if you need to. 🤘

A Good Macro-Friendly Decomposition for Instructions

There is a bit of a Gordian Knot in the CPU in how the addressing modes and different opcodes interact if you want to define each instruction exactly one time without a mess of switch statements for the different variations. In short:

  1. Addressing modes should only access CPU and Memory to compute an address. Any cycle counting (e.g. for crossing pages) can be done at the call site with macros!

  2. Your opcode-defining macro should set up address and argument variables, or an update function as needed based on the access pattern of the instruction.
    This has bitten me on previous attempts as I assumed the access pattern came from the addressing mode rather than the instruction itself. Instructions can be implied and use no argument, or only use the address and jump to it, or read an argument from the address, or write a value to an address, or read a value, modify it and write it back. It was very worthwhile to split these cases out and handle them independently. It meant a little extra work while writing up the metadata but kept concerns separated later.

  3. Separating the opcode metadata from the actual instruction definition. This is more arbitrary than the earlier recommendations but it felt very clean while hacking the opcode definitions and I think I only found myself going back to edit the instruction metadata one time from making a typo.

PPUs == Pain

PPU stands for Picture Processing Unit and it was the graphics card in the original NES. The central innovation of the PPU was that it supported pixel-level scrolling of levels.

I have no experience in graphics or game programming so this was a big challenge for me. Four other factors contributed to the difficulty of writing the PPU:

  1. There isn't really a suggested ordering of tasks like there is for writing a CPU emulator and subtasks are hard to test in isolation.
  2. The data layout of the PPU is complex: OAM, nametables, pattern tables, attribute tables, etc.
  3. The test ROMs that exist generally assume you have the basics working.
  4. While many working open source emulators exist, the control flow was difficult to follow without getting lost in the weeds and it was unclear why different calculations were used.

I'll try to tackle these briefly and write up more details at a later date.

A Suggested PPU Ordering

First, you need an object to represent the hardware state. It'll need to access the currently loaded game ROM for graphics data so remember to give it a slot for storing the cartridge object.

Second, you'll need to implement the PPU memory map. There's no operating system on the NES so there are no video card drivers and you'll do everything yourself via Memory Mapped I/O. If you've never heard of memory mapped I/O, the idea is that reading and writing to specific addresses in memory directly manipulates the PPU so write those methods and wire it up!

Third, you'll want to get the timing synchronized between the CPU and PPU. You'll want to do this before trying to render graphics probably as many games wait for an interrupt called vblank from the PPU that the graphics card is ready before even reaching the title. Many games will infinite loop until the PPU wakes them up with this interrupt, then do the work needed to render the next frame and return to the infinite loop. This is part of why it's so important to get the timing right.

Fourth, you'll want to make sure the address computations are right. This was the single hardest bit of code for me to get right in the PPU. It's also the code I'm happiest with and hoping to figure out how to test in an automated way for next time.

Fifth, try to just render the backgrounds using the addressing logic you arrived at ealier. If you can get backgrounds rendering correctly, you should be well on your way to getting sprites and scrolling working. With any luck, the PPU operation should start becoming clearer.

PPU Data Flow

Internally the graphics are represented as 8x8 tiles that are either sprites or backgrounds. Crucially, the information needed to render those tiles is divided up into the different areas inside the PPU: nametables, attribute tables, the palette, and pattern tables (in the ROM).

Nametables represent the background and are 960 byte long arrays where each byte is an index into the pattern table for an 8x8 tile. Why 960 bytes you ask? Because the NES resolution is 256 by 240 and if you divide that by 8 (pixels in a tile) you get 32 x 30. 32 * 30 = 960.

So nametables point to the "pattern" or texture that will be used for a given tile but for space reasons that pattern doesn't actually store all the information about what color it should be. The pattern table is 4kb and holds 256 tiles with each 8x8 tile taking 16 bytes to store. Those 16 bytes are enough for each pixel to get two bits to represent a color ... so 4 options.

The PPU has a 64 byte palette table to select 32 colors for the background and 32 colors for the sprites. But why bother when each pixel in a pattern can only count from 0-3? Well, did it seem a little odd that the Nametable was 960 bytes? That's because the last 64 bytes in that kilobyte are used to store something called an attribute table. Every 16 tiles share a single attribute byte which determines the top 2 bits of the palette index for tiles in groups of 4. There are implications from this about how many colors can be represented in a 16x16 pixel area of the screen, on a scanline, etc.

It's pretty confusing until you sit down and draw it all out. A lot of the calculations for the PPU are exactly this sort of thing. You can just imagine the hardware designers saying: "But how do we do it with less RAM to bring the price down?"

This has been written up well elsewhere, Scott Ferguson's blog comes to mind. But I still never found a high level description of how the PPU renders that wasn't based on perfectly emulating the state of a bunch of internal shift registers and latches and running the PPU cycle by cycle. And, pardon my french, but that's fucking gross. Not because it's inaccurate or slow or anything like that but just because it's hard to see the forest for the trees.

Here's something like how I think of background rendering now. Sprites are more complicated but follow the same basic framework:

  1. For each scanline, you have to draw 32 tiles.
  2. For a (background) tile, you have to get the nametable byte and attribute byte.
  3. The pattern table has 16 bytes for a tile but we only need two for the 8 pixels on a scanline.
  4. Go ahead and extract the two high bits of the palette index from the attribute byte.
  5. Now loop for pixels 0 to 7 and combine those bits with the bits in the pattern to get a color.
  6. Show the backdrop color if it's zero (transparent), otherwise show the background color.

I know this is inaccurate, but it's clear to follow at a high level and if you then pointed out the various address computations in the substeps it ought to be pretty straightforward.

A lot of my remaining questions concern how to support scrolling at least kinda correctly without basing everything off internal registers and how to render things tile by tile instead of pixel by pixel. But I may abandon that because it was mostly to avoid repeated fetches of the same data and I recently made a RENDER-CONTEXT object that can help with that. Maybe down the road at some point I'll make a cycle-accurate PPU. :)

Test ROMs

There aren't really good test ROMs because the ROMs that exist mostly assume you have the basics working and are testing tricky details. While I don't think a test ROM could be written since a lot of what needs testing are internal details of the PPU that weren't exposed to NES programmers, I do think a ROM coupled with some JSON dumps of what internal data should be visible after rendering for a frame or two would be incredibly useful. Because at some point I spent 3 days on a single bug because I wasn't incrementing a counter appropriately.

I'd like to think on this some more but I have some basic ideas. A lot of the difficulty is that in the 90s there were working emulators that did more abstract high level emulation both because PCs were less powerful and because less was known about the underlying hardware. That required workarounds of various sorts for accuracy and so they're frowned upon now. But as a result, I haven't found much high-level documentation of the rendering algorithm in the PPU. Everyone seems to point back to a frame timing diagram on the nesdev wiki. Which is great but I was hoping to write a 2500 lines of code readable NES implementation that doesn't require a solid understanding of latches and assembly to get a basic idea of how the thing worked.

But I believe the address calculations, among other things, can be expressed clearly (and tested!) in terms of the X,Y coordinates to be rendered as opposed to internal registers. More soon...

Hard to Follow Implementations

I'm still unsatisfied with my PPU implementation but it also isn't completely finished. I hope to have more to show here after scrolling is working and some refactoring is done.

A Word On Performance

The output resolution of the Nintendo was 256x240. At a high level, all the PPU is doing is looping from left to right (0-255), top to bottom (0-240) and deciding on a color for the current pixel, then outputting it once per frame. Of course, it has to do that 60 times a second and 256 * 240 * 60 is 3.6 million so pixel rendering needs to be pretty fast. I didn't have to do any optimizing to hit 60 frames per second but I was careful to write code that didn't allocate as I went and we're still using 50% CPU which is definitely more than I'd like.

Til Next Time

Wish me luck, lispers. Cheers. <3


Unless otherwise credited all material Creative Commons License by Brit Butler