<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet href="pretty-atom-feed.xsl" type="text/xsl"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
  <title>Zach Kehs</title>
  <subtitle>A game developer that writes about stuff.</subtitle>
  <link href="https://zachkehs.com/feed/feed.xml" rel="self" />
  <link href="https://zachkehs.com/" />
  <updated>2026-09-04T00:00:00Z</updated>
  <id>https://zachkehs.com/</id>
  <author>
    <name>Zach Kehs</name>
  </author>
  <entry>
    <title>There&#39;s No Limit to How Bad Code Can Get</title>
    <link href="https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/" />
    <updated>2026-09-04T00:00:00Z</updated>
    <id>https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/</id>
    <content type="html">&lt;p&gt;TL;DR: Metaphors like &amp;quot;a sinking ship&amp;quot; are often used to describe codebases, but are misleading.
A &lt;em&gt;business&lt;/em&gt; will sink long before code quality reaches a hypothetical floor. Technical debt has
no bankruptcy, no clean reset, so metaphors that imply an end provide a false sense of security.&lt;/p&gt;
&lt;blockquote class=&quot;pull-quote&quot; id=&quot;pull-quote&quot;&gt;
&lt;p&gt;&lt;a href=&quot;#pull-quote-source&quot;&gt;Software is in the domain of the abstract. It is not like a building, or a bridge, that is in
the physical realm where you can see and feel the nature of the thing. If you continue to add
floors and rooms to a building forever, it will collapse. Software faces no such constraint.
The code can &lt;strong&gt;always&lt;/strong&gt; get worse. There can &lt;strong&gt;always&lt;/strong&gt; be a new layer of indirection
or a reduction in performance.&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2 id=&quot;1-boarding-a-sinking-ship&quot;&gt;1: Boarding a sinking ship&lt;/h2&gt;
&lt;p&gt;Over a decade ago I had my first encounter with an &lt;em&gt;ugly&lt;/em&gt; legacy codebase. I had just joined Amazon
as a &amp;quot;Software Development Engineer&amp;quot;, fresh out of university, and worked on a team that owned code
related to &lt;a class=&quot;Footnotes__ref&quot; href=&quot;https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/#1-note&quot; id=&quot;1-ref&quot; aria-describedby=&quot;footnotes-label&quot; role=&quot;doc-noteref&quot;&gt;processing orders&lt;/a&gt;. On the surface, what our code had to
do seemed simple. Processing an order involved writing some things to a database and calling into
services owned by other teams, either to ask validity questions or to update bookkeeping on their
end. My colleagues and I estimated that a sufficient implementation of this system shouldn&#39;t need
more than two dozen strong engineers to maintain and evolve. Yet, our organization was
hundreds of people, and the system had grown so large and complex that it had become impossible to
learn how it all worked.&lt;/p&gt;
&lt;p&gt;It was rare to stay longer than a few years in this org, and institutional knowledge had eroded. This
resulted in code that was full of &lt;a class=&quot;Footnotes__ref&quot; href=&quot;https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/#2-note&quot; id=&quot;2-ref&quot; aria-describedby=&quot;footnotes-label&quot; role=&quot;doc-noteref&quot;&gt;&amp;quot;haunted graveyards&amp;quot;&lt;/a&gt;. Fear suppressed any (under-rewarded) efforts to
simplify existing systems. The business rules for what had to be done for each type of order were
decided by people long ago who weren&#39;t around anymore. These rules could sometimes be found in a
hopelessly out of date file proudly calling itself a &#39;living document&#39;, but often the rules simply
were not written anywhere we could find. Tracing behavior yourself wasn&#39;t easy either because much
of the system lived across team boundaries where the code was not easy to access.&lt;/p&gt;
&lt;p&gt;When some obscure process wasn&#39;t happening with an order that should have been happening, our pagers
would angrily notify us that someone in our tangled web of service dependencies was unhappy. As a
result of this feedback mechanism, the system stayed afloat, but remained difficult to change
and had &lt;a class=&quot;Footnotes__ref&quot; href=&quot;https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/#3-note&quot; id=&quot;3-ref&quot; aria-describedby=&quot;footnotes-label&quot; role=&quot;doc-noteref&quot;&gt;abysmal performance&lt;/a&gt;. Despite this, new layers were constantly added to support the latest
Amazon products and features. This felt unsustainable, and this feeling is what makes me and others
reach for a &amp;quot;sinking ship&amp;quot; as a metaphor to describe an organization that doesn&#39;t pay down their
technical debt.&lt;/p&gt;
&lt;p&gt;To their credit, there were always &lt;a class=&quot;Footnotes__ref&quot; href=&quot;https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/#4-note&quot; id=&quot;4-ref&quot; aria-describedby=&quot;footnotes-label&quot; role=&quot;doc-noteref&quot;&gt;ongoing attempts&lt;/a&gt; to fix the architecture, and these usually
went as follows: A new manager or senior engineer joins the organization and observes that &amp;quot;things are bad&amp;quot;.
Leadership at the organization agrees and &lt;em&gt;wants&lt;/em&gt; to make things better, but there are no engineers
available, so each fix attempt includes adding new engineers and &lt;a class=&quot;Footnotes__ref&quot; href=&quot;https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/#5-note&quot; id=&quot;5-ref&quot; aria-describedby=&quot;footnotes-label&quot; role=&quot;doc-noteref&quot;&gt;teams&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The re-architectures were always a failure: The system required &lt;em&gt;years&lt;/em&gt; of study to properly
understand and was constantly changing. It&#39;s not politically viable to take so long to design a
fix for the system, so naturally everyone attempting to fix things must work with
incomplete information. Some of this impatience is from within: If you are trying to
design a grand fix for such a prominently painful architecture, you are doing it in part because
you want a promotion (and you don&#39;t want to wait too long for a promotion).&lt;/p&gt;
&lt;p&gt;Each cycle would end with the remains of the new attempt permanently grafted onto our architecture
and the leading engineer having departed with their requisite promotion. The increased headcount
stays because the migration plans are too painful and unpopular to actually finish. &lt;a class=&quot;Footnotes__ref&quot; href=&quot;https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/#6-note&quot; id=&quot;6-ref&quot; aria-describedby=&quot;footnotes-label&quot; role=&quot;doc-noteref&quot;&gt;The cycle
continued&lt;/a&gt; as it had long before I had arrived. The sinking ship seemed to have no end.&lt;/p&gt;
&lt;h2 id=&quot;2-where-does-it-end&quot;&gt;2: Where &lt;em&gt;does&lt;/em&gt; it end?&lt;/h2&gt;
&lt;p&gt;About three years after I had left, I was chatting on the phone with a former colleague from that
team. He had recently left the company after an impressive 6-year tenure and had witnessed the
cycle complete again.  We were commiserating, and both of us reached for the sinking ship metaphor
to describe the org, despite us having left years apart.&lt;/p&gt;
&lt;p&gt;&amp;quot;Where does it end? How does it end?&amp;quot; he asked me, curious to hear my take on what would happen to
that org in the future.&lt;/p&gt;
&lt;p&gt;The question and metaphor didn&#39;t sit right with me, and I realized the question conflated two
things. Are we talking about the code, or are we talking about the company?&lt;/p&gt;
&lt;p&gt;A &lt;em&gt;business&lt;/em&gt; can sink. Bad software is a real drag on the business, but how much that actually
matters depends on a lot of factors. For a company with plenty of cash flow like Amazon, they
can tolerate some bouts of internal rot here and there before it has any meaningful impact on their
bottom line. For another company whose business model is more sensitive to software quality, bad
software may be a latent invitation to a competitor to deliver the metaphorical hull breach (and no,
&lt;a class=&quot;Footnotes__ref&quot; href=&quot;https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/#7-note&quot; id=&quot;7-ref&quot; aria-describedby=&quot;footnotes-label&quot; role=&quot;doc-noteref&quot;&gt;LLMs don&#39;t change this&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;For the code, the sinking doesn&#39;t end. It&#39;s an &lt;em&gt;infinitely&lt;/em&gt; sinking ship, because there is no limit
to how bad code can be. You didn&#39;t escape a building that was about to collapse. It is in a constant,
neverending state of collapse. There&#39;s something wrong with using words that imply there&#39;s an end.&lt;/p&gt;
&lt;p id=&quot;pull-quote-source&quot; class=&quot;pull-quote-source&quot;&gt;Software is in the domain of the abstract. It is not like a building, or a bridge, that is in the
physical realm where you can see and feel the nature of the thing. If you continue
to add floors and rooms to a building forever, it will collapse. Software faces no such constraint.
The code can &lt;em&gt;always&lt;/em&gt; get worse. There can &lt;em&gt;always&lt;/em&gt; be a new layer of indirection or a
reduction in performance. &lt;a href=&quot;#pull-quote&quot; class=&quot;pull-quote-back&quot; aria-label=&quot;Back to pull quote&quot; role=&quot;doc-backlink&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The pedants will rightfully point out that software can completely fail to function if it gets bad enough.
In practice, such breaking changes are quickly reverted. The thousands of changes that came before
to make the code worse are not. The software &lt;a class=&quot;Footnotes__ref&quot; href=&quot;https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/#8-note&quot; id=&quot;8-ref&quot; aria-describedby=&quot;footnotes-label&quot; role=&quot;doc-noteref&quot;&gt;continues to &#39;work&#39;&lt;/a&gt;. Other cases without a single
breaking change to revert are where the ballooning costs of the bad software eclipse its benefit,
or if development velocity approaches zero because nothing can be shipped without a breakage. In all
of these cases, it is the business that dies long before the code hits any hypothetical floor (so
don&#39;t act like there&#39;s a floor!).&lt;/p&gt;
&lt;h2 id=&quot;3-technical-debt-has-no-bankruptcy&quot;&gt;3: Technical debt has no bankruptcy&lt;/h2&gt;
&lt;p&gt;The drag of bad software on the business is a real threat and the reason why good organizations
pay attention to code quality. Since there is no abrupt failure threshold associated with software
quality, it&#39;s often described as &amp;quot;technical debt&amp;quot;, which can be a better metaphor (debt can
compound forever) but is also imperfect.&lt;/p&gt;
&lt;p&gt;Debt has an &#39;ending&#39; point because bankruptcy is a forced reset, and the equivalent
in software is a full rewrite, which is &lt;a href=&quot;https://www.joelonsoftware.com/2000/04/06/things-you-should-never-do-part-i/&quot;&gt;rarely an option&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The closest option that a mega-corp such as
Amazon has is what I call a side-channel, where they split off a team that builds a new, completely
disconnected system with only the minimal set of features needed for some new use case. Moving
forward they then have the option to direct more new use-cases at this simplified, separate
system. Importantly, the old system must remain and be maintained (it&#39;s not an &#39;end&#39;), because all
the old use-cases still exist, and new organizational-level pain is felt whenever &lt;a class=&quot;Footnotes__ref&quot; href=&quot;https://zachkehs.com/blog/theres_no_limit_to_how_bad_code_can_get/#9-note&quot; id=&quot;9-ref&quot; aria-describedby=&quot;footnotes-label&quot; role=&quot;doc-noteref&quot;&gt;deciding which to
use in the future&lt;/a&gt;. That&#39;s not exactly slate-clearing like we think of a bankruptcy.&lt;/p&gt;
&lt;p&gt;The wrong mental models about software lead to bad decisions. If a &#39;hard reset&#39; escape hatch exists,
then punting technical debt doesn&#39;t seem so bad. The belief that a rewrite around the corner could
fix things results in worse decisions today, because the decision-maker today doesn&#39;t understand
that there is no escape hatch.&lt;/p&gt;
&lt;p&gt;Metaphors like a &amp;quot;collapsing building&amp;quot; or a &amp;quot;sinking ship&amp;quot; are not appropriate for software, yet we
can embrace them anyway to emphasize what makes software different. The building is infinitely
collapsing. The ship is infinitely sinking. There is no natural constraint that will wake your
project manager up and force them to deal with technical debt. Software will only stay high quality
if we put in the effort to stop the sinking. Grab a bucket.&lt;/p&gt;
</content>
  </entry>
  <entry>
    <title>Zach&#39;s GameDev Story</title>
    <link href="https://zachkehs.com/blog/zachs_gamedev_story/" />
    <updated>2025-12-26T00:00:00Z</updated>
    <id>https://zachkehs.com/blog/zachs_gamedev_story/</id>
    <content type="html">&lt;p&gt;This post started by me trying to write my &lt;a href=&quot;https://zachkehs.com/about/&quot;&gt;about&lt;/a&gt; page, but I got carried away and wrote way too much. Therefore, I&#39;m dumping it here as a dedicated post.&lt;/p&gt;
&lt;h2 id=&quot;1-early-childhood-pen-and-paper&quot;&gt;1. Early childhood: pen-and-paper&lt;/h2&gt;
&lt;p&gt;I have loved games for as long as I can remember, and by that I mean both playing games and making them. I loved to draw as well, so much of my earliest games were pen-and-paper. Some were designed as reusable board games, but this was less common.&lt;/p&gt;
&lt;!-- TODO: Get other pictures that show some of your crappier board games to show here too. --&gt;
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/ptdUtLz8y2-400.avif&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/ptdUtLz8y2-400.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zachkehs.com/blog/zachs_gamedev_story/ptdUtLz8y2-400.jpeg&quot; alt=&quot;Here&#39;s part of one of the board games I made. (This is NOT the pen-and-paper role-playing game I reference elsewhere)&quot; width=&quot;400&quot; height=&quot;264&quot;&gt;&lt;/picture&gt;
&lt;p&gt;My favorite was a pen-and-paper role-playing game that sort of started by me just drawing medieval warriors running around and fighting. Over time I added rules to how the drawing would progress, but those rules were loose because playing the game itself was a creative expression. If I were introduced to Dungeons &amp;amp; Dragons during these years, I would have loved it. However, I didn&#39;t actually learn about Dungeons &amp;amp; Dragons until my late teenage years, and by then I had long since been playing my own sort of version that had evolved from this pen-and-paper game.&lt;/p&gt;
&lt;p&gt;My first introduction to digital creation media was &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Print_Shop&quot;&gt;The Print Shop&lt;/a&gt; on our computer (I don&#39;t remember the version of The Print Shop, but I think we were using Windows 98 at the time). With this, I made little local websites (as groups of HTML pages) where you would navigate around by clicking images I had placed, which would take you to a new page. Somehow I was very entertained and made many &#39;games&#39; that were effectively mazes you would navigate by clicking images to denote your choices.&lt;/p&gt;
&lt;!-- Note: CSS rules will ignore you overriding the height. Overriding width instead just so the image doesn&#39;t take up too much space. --&gt;
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/9l9fdNf4Wq-450.avif&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/9l9fdNf4Wq-450.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zachkehs.com/blog/zachs_gamedev_story/9l9fdNf4Wq-450.jpeg&quot; alt=&quot;Here I am enjoying what appears to be Excel on Windows XP.&quot; width=&quot;450&quot; height=&quot;359&quot;&gt;&lt;/picture&gt;
&lt;p&gt;Later, I dabbled a little bit with some products from &lt;a href=&quot;https://en.wikipedia.org/wiki/The_Game_Creators&quot;&gt;The Game Creators&lt;/a&gt;. I remember trying and failing to wrap my little brain around DarkBasic, but I had fun with FPS Creator. I hung around on the forums and tried to absorb knowledge from the other, more experienced game developers there. Mostly, this time was just spent being an annoying kid.&lt;/p&gt;
&lt;h3 id=&quot;side-note-other-childhood-inspirations&quot;&gt;Side Note: Other childhood inspirations&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Final_Fantasy_Tactics&quot;&gt;Final Fantasy Tactics&lt;/a&gt;: My favorite game of my childhood and responsible for me falling in love with the turn-based genre. The combat system of this game was the primary direction I ended up choosing to head when I later tried to adapt my pen-and-paper RPG into digital form.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Mage_Knight&quot;&gt;Mage Knight&lt;/a&gt; (&lt;em&gt;NOT&lt;/em&gt; the board game!): This was a miniatures game that I got into in elementary school. Building custom armies and situations gave me countless hours of entertainment. I still think the early editions of this game were really well designed. Unfortunately, I think the gameplay and unit design went downhill later in the life of the series before it ultimately died and had its IP revived in the form of a board game that plays nothing like the original.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Dynasty_Warriors&quot;&gt;Dynasty Warriors&lt;/a&gt;: This is blending into the teenage years, but I think I started with a demo-disk of Dynasty Warriors 3 on the PlayStation 2, and then later bought Dynasty Warriors 4, which I played a lot of over the following years.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;2-teenage-years-learning-to-code&quot;&gt;2. Teenage years - learning to code&lt;/h2&gt;
&lt;p&gt;Around the same time I was trying to build a shooter with FPSC, I also tried &lt;a href=&quot;https://en.wikipedia.org/wiki/GameMaker&quot;&gt;GameMaker 6&lt;/a&gt; and had started a few small projects with it using the graphical drag-and-drop programming. I wasn&#39;t particularly convinced that I could make something advanced in it until I had played some games by &lt;a href=&quot;https://archive.org/details/The_Cleaner&quot;&gt;Darthlupi&lt;/a&gt;. This guy was a real inspiration for me, both in terms of what was possible with the tool but also in that I credit him as my starting point for learning to code.&lt;/p&gt;
&lt;p&gt;Darthlupi had posted an open-source tutorial or example game on a web forum for GameMaker users that used GML (GameMaker Language). GML was a pseudo-JavaScript language used by GameMaker instead of the graphical drag-and-drop programming I had been using up until that point. Starting from this example, I taught myself programming at age 13 by digging through the (generally quite good!) documentation of GameMaker.&lt;/p&gt;
&lt;p&gt;I had printed hundreds of pages of documentation out using my parents&#39; printer (sorry!) that I downloaded over our dial-up internet, which I would consult when I got stuck and couldn&#39;t access the internet outside of times it was available. I spent the next couple of years building games with this, 3 of which I completed and maybe 6-10 at various stages of production that I abandoned.&lt;/p&gt;
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/YlT8-T8ObK-1786.avif&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/YlT8-T8ObK-1786.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zachkehs.com/blog/zachs_gamedev_story/YlT8-T8ObK-1786.png&quot; alt=&quot;Three bad freeware games I actually finished. Left: &#39;Elimod &amp; Dagros&#39; (Aug 2008), Center: &#39;The River&#39; (Mar 2008), Right: &#39;Fluffum War&#39; (2007)&quot; width=&quot;1786&quot; height=&quot;395&quot;&gt;&lt;/picture&gt;
&lt;p&gt;Two of the games I made were for these multi-month competitions hosted by &lt;a href=&quot;https://en.wikipedia.org/wiki/YoYo_Games&quot;&gt;YoYo Games&lt;/a&gt; (who had acquired GameMaker a year or two after I had started using it). I didn&#39;t win anything (my games were bad), but they were a valuable learning experience, especially learning how to finish games and how to scope your games properly. If it weren&#39;t for the competition deadline, those projects would have ended up abandoned too. Finishing games is something a lot of game developers really struggle with, so I am happy that I got those repetitions in by making a few small, finished games.&lt;/p&gt;
&lt;h2 id=&quot;3-my-first-big-game&quot;&gt;3. My first &#39;big&#39; game&lt;/h2&gt;
&lt;p&gt;After the freeware games, at 16 I was over-confident in my coding abilities and believed I could build anything I imagined. I felt that I was ready to build a &#39;big&#39; game, which would be a digital version of my pen-and-paper role-playing game from my earlier childhood. This I will refer to as ✨The Dream Game✨ (It will come up again). I was still using GameMaker at this point, but the past several games of mine including this one were 100% using code (GML).&lt;/p&gt;
&lt;p&gt;This game was effectively going to have a strategic world map layer like &lt;a href=&quot;https://en.wikipedia.org/wiki/Mount_%26_Blade_(series)&quot;&gt;Mount &amp;amp; Blade&lt;/a&gt; (a game I was really enjoying at the time), but with tactical battles like Final Fantasy Tactics, and with a bunch of world-simulation fanciness sprinkled in as well. This was way over-scoped relative to my current skill level and what I had completed in the past. About 1 year into the project, I realized I was in over my head and that I needed to build up my skills more to be able to properly take on something this complex.&lt;/p&gt;
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/PQ5tQxNHLa-450.avif&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/PQ5tQxNHLa-450.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zachkehs.com/blog/zachs_gamedev_story/PQ5tQxNHLa-450.png&quot; alt=&quot;This was the final state of V1 of the dream game. Not bad!&quot; width=&quot;450&quot; height=&quot;345&quot;&gt;&lt;/picture&gt;
&lt;p&gt;I started a new, unrelated project instead with a smaller scope. I was freshly inspired by the 2009 hit &lt;a href=&quot;https://en.wikipedia.org/wiki/Borderlands_(video_game)&quot;&gt;Borderlands&lt;/a&gt;. The main inspiration from that game was the idea for procedurally-generated guns - I combined this with the idea of procedurally-generated caves from &lt;a href=&quot;https://en.wikipedia.org/wiki/Spelunky&quot;&gt;Spelunky&lt;/a&gt;, another favorite of mine, to make a shooter-roguelike.&lt;/p&gt;
&lt;p&gt;This project started at the age of 17 and finished at the age of 18 (I think ~1.5 years of work total), and &lt;a href=&quot;https://store.steampowered.com/app/328990/Koya_Rift/&quot;&gt;Koya Rift&lt;/a&gt; was the result! I sold it through my website for a few years, until I eventually got on Steam through their &amp;quot;Greenlight&amp;quot; program. This game isn&#39;t very good - I am still proud of what I accomplished though, because I stayed on schedule and released a bigger game. It was a valuable learning experience.&lt;/p&gt;
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/85heQO0pb3-908.avif&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/85heQO0pb3-908.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zachkehs.com/blog/zachs_gamedev_story/85heQO0pb3-908.png&quot; alt=&quot;screenshot of Koya Rift&quot; width=&quot;908&quot; height=&quot;324&quot;&gt;&lt;/picture&gt;
&lt;p&gt;The deadline for Koya Rift was real, in that I had plans to study Computer Science at a university after I was finished with high school. I wanted to get the game finished and released so I didn&#39;t have to juggle that plus my university schoolwork because I was worried if that happened the game would never get done.&lt;/p&gt;
&lt;p&gt;If I were doing this game over again, and had more time, I would have let it sit &#39;in the oven&#39; for another year or so with a public demo, gathering feedback and making tweaks. I think in the end the content was a little too shallow and there were various usability issues that hampered it. Oh well!&lt;/p&gt;
&lt;h2 id=&quot;4-university&quot;&gt;4. University&lt;/h2&gt;
&lt;p&gt;Despite how it may seem, I never seriously considered studying game design or game programming, or otherwise trying to get a job in the games industry. Games were a passion of mine, and I didn&#39;t want to turn them into a job. I had also done research about the career prospects and projected salary for working in games, vs. just getting a regular software/programming job. This made it more clear to me that I should study computer science and have a normal software engineering career, which is what I chose to pursue. The closest candidate for a second choice was actually graphic design, since I loved art and working on computers. Career prospect research killed that idea.&lt;/p&gt;
&lt;p&gt;So, I went to university to study Computer Science shortly after shipping Koya Rift. My gamedev journey continued - the first year or so there was spent working on and eventually releasing an update for the game. The entire time, I kept the ✨Dream Game✨ in the back of my mind. Now that I had gained much valuable experience from shipping Koya Rift, I knew I could do a better job. I started over, still using GML, even though I was becoming reasonably competent in C++ through my job at the robotics lab and my coursework. At the time, the current owners of GameMaker were trying to rebrand it as a more serious development tool and appeared to be putting in lots of effort to improve it, so that provided a sense of confidence that the situation would improve regarding &#39;serious&#39; things I wanted out of it, like testing and debugging tools.&lt;/p&gt;
&lt;p&gt;We will call this restart of the project the &#39;V2&#39; of the ✨Dream Game✨. Conceptually it&#39;s the same game as before, with some changes. Gameplay-wise, the biggest change is that it&#39;s now grid-based instead of free-movement. I also tried to start my campaign world layer at the same time as my battle layer, so that I could build up the interface between the two over time. This was a mistake the first go-around, where I worked only on the battle system and so I made many architectural errors in not thinking about how that mode would interact with all the other systems. Speaking of architecture, another change this time around was that V2 is now more data-driven in that I wanted players to be able to create and share mods with each other to change the content of the game.&lt;/p&gt;
&lt;p&gt;I met two friends during this time that wanted to help with the project. We all worked together on it for a year or so, and that was really fun. I remember telling myself I would never work alone on a project again because of how miserable it was compared to working with people (spoiler alert: that didn&#39;t happen!). We had good fun, but ultimately other priorities competed and the other two dropped off of the project.&lt;/p&gt;
&lt;!--TODO: Screenshot of dream game v2 !--&gt;
&lt;h2 id=&quot;5-being-a-real-adult&quot;&gt;5. Being a real adult&lt;/h2&gt;
&lt;p&gt;After my collaborators dropped off of V2 of the ✨Dream Game✨, I continued working on it for maybe 3 or 4 more years. In that time, I had graduated from my university and got my first real adult job as a software engineer in Seattle, WA. I was still working on the ✨Dream Game✨ on nights and weekends, though not quite as briskly as I was during my university years.&lt;/p&gt;
&lt;p&gt;During this time of my first real software engineering job, I was learning things at the fastest pace I ever had in my life. Quickly I became frustrated with my old code and old decisions, but even more so I became frustrated with the limitations of the tools and language I was using. At my day job at this point, I was writing backend Java. In particular, one thing I noticed was that in the real world, we used automated tests to make sure that the software worked the way we thought it did. As my ✨Dream Game✨ project continued to grow in complexity, and without any automated test framework available for GML, I slowly became more convinced over time that I was permanently handicapping the scope of the project by not having all the tools available that using a real programming language would have. My motivation waned.&lt;/p&gt;
&lt;p&gt;The project spent a few years in limbo here, where I worked on it a tiny bit, but I mostly experimented with other programming languages and tools. I tried out &lt;a href=&quot;https://en.wikipedia.org/wiki/Unreal_Engine_4&quot;&gt;Unreal Engine 4&lt;/a&gt;, which was the new hotness at the time. However, trying full-fledged &#39;engines&#39; didn&#39;t really stick for me; I preferred the &#39;pure code&#39; approach I had used for my previous several games. I think my feelings here come down to control - I&#39;m a bit of a control freak, and I want to be able to understand and change every aspect of the game.&lt;/p&gt;
&lt;p&gt;Craving more code-first solutions, I played around some with &lt;a href=&quot;https://libgdx.com/&quot;&gt;LibGDX&lt;/a&gt;, since it used Java, which I was using at work. At work at the time, I was working on a high-availability backend service that was mostly doing business logic. Naturally, I spent a lot of my time thinking about problems in that domain, namely, how to avoid bugs and how to make it easier for software to &#39;just work&#39;. I watched a bunch of tech talks where others opined on these issues. Over time, I found myself adopting more of a &#39;functional&#39; programming pattern in my code. The defaults of Java really annoyed me - references were mutable by default, collections were mutable by default, and over time I saw how many bugs were caused by these. In particular I was &lt;s&gt;radicalized&lt;/s&gt; &lt;em&gt;influenced&lt;/em&gt; by &lt;a href=&quot;https://www.youtube.com/watch?v=SxdOUGdseq4&quot;&gt;&amp;quot;Simple Made Easy&amp;quot;&lt;/a&gt;, a talk by &lt;a href=&quot;https://en.wikipedia.org/wiki/Rich_Hickey&quot;&gt;Rich Hickey&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This line of thinking, along with talks/arguments with coworkers, led me to try out various frameworks and alt-JVM languages (JVM is the Java Virtual Machine, many other programming languages emerged over time that could compile to run alongside Java code and utilize the same ecosystem). I spent time building prototype side projects with &lt;a href=&quot;https://www.scala-lang.org/&quot;&gt;Scala&lt;/a&gt;, and I spent a bit of time trying out &lt;a href=&quot;https://clojure.org/&quot;&gt;Clojure&lt;/a&gt;, but neither of them stuck as much as &lt;a href=&quot;https://kotlinlang.org/&quot;&gt;Kotlin&lt;/a&gt;, which I tried pre-1.0 in late 2015.&lt;/p&gt;
&lt;p&gt;I really, really liked Kotlin. I built a few small libraries and prototypes with Kotlin and found that it really resonated with the more functional-style of programming that I had come to love through work. This led me to continue to favor Kotlin for side projects even after I had started my second job which was writing C++.&lt;/p&gt;
&lt;p&gt;During this time I had slowly convinced myself to restart the ✨Dream Game✨ yet again, but in Kotlin this time. I was bouncing between my side projects, and every time I went back to work on the ✨Dream Game✨ in GML it became more and more painful, as I couldn&#39;t help but notice how much of my time was spent fixing bugs that a real static type system and automated tests would have prevented in the first place.&lt;/p&gt;
&lt;p&gt;So, the ✨Dream Game✨ was again started from scratch, with Kotlin as the language of choice (we will call this V3). V3 is the current version of the game, actually. Conceptually, this started out as the same game as V2, but over the years it has slowly evolved into being different (I will explain further in a future blog post).&lt;/p&gt;
&lt;h3 id=&quot;side-note-staying-motivated-and-productive-while-moonlighting&quot;&gt;Side Note: Staying Motivated &amp;amp; Productive While Moonlighting&lt;/h3&gt;
&lt;p&gt;While I was working full-time, my game development schedule consisted, on average, of Saturday afternoons and at least one night during the week sometime. During high-motivational phases, this would be both days of the weekend and multiple nights per week. During low-motivational phases, this would just be one day a week, Saturday. I have a lot of thoughts about how I managed my motivation and productivity over time, and I want to make a separate blog post to write about them. When I eventually do that, I&#39;ll link it here.&lt;/p&gt;
&lt;h3 id=&quot;side-note-local-community&quot;&gt;Side Note: Local Community&lt;/h3&gt;
&lt;p&gt;During my full-time working years while I was moonlighting as a game developer, I typically spent every Saturday afternoon at an in-person coworking session for game developers. In Seattle, these were called &amp;quot;Indie Support Group&amp;quot; (colloquially called ISG, organized by &lt;a href=&quot;https://www.seattleindies.org/events/&quot;&gt;Seattle Indies&lt;/a&gt;). During 2018-2021, I lived in Pittsburgh, PA, and I set about finding my local game development community there. I helped convince the organizer of &lt;a href=&quot;https://www.meetup.com/pgh-game-makers/&quot;&gt;Pittsburgh Game Makers&lt;/a&gt; to start hosting Saturday coworking sessions as well, which they continued for years after I left.&lt;/p&gt;
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/Vpkd45vRZo-1000.avif&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/Vpkd45vRZo-1000.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zachkehs.com/blog/zachs_gamedev_story/Vpkd45vRZo-1000.jpeg&quot; alt=&quot;Seattle&#39;s ISG circa 2015. The second floor of this coffee shop was completely taken over by nerds making games.&quot; width=&quot;1000&quot; height=&quot;442&quot;&gt;&lt;/picture&gt;
&lt;p&gt;Above: Seattle ISG in 2015. Below: Pittsburgh Game Makers&#39; coworking in 2018.&lt;/p&gt;
&lt;!-- Making this one a little less wide or else it&#39;s too tall. --&gt;
&lt;picture&gt;&lt;source type=&quot;image/avif&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/en_R30WaKo-450.avif&quot;&gt;&lt;source type=&quot;image/webp&quot; srcset=&quot;https://zachkehs.com/blog/zachs_gamedev_story/en_R30WaKo-450.webp&quot;&gt;&lt;img loading=&quot;lazy&quot; decoding=&quot;async&quot; src=&quot;https://zachkehs.com/blog/zachs_gamedev_story/en_R30WaKo-450.jpeg&quot; alt=&quot;Pittsburgh&#39;s Saturday coworking circa 2018. Much smaller than Seattle, but closely knit!&quot; width=&quot;450&quot; height=&quot;279&quot;&gt;&lt;/picture&gt;
&lt;p&gt;Community is important to me - when working on the game alone, it&#39;s good to chat with other game developers on a regular basis. I think this was good for my motivation, my social health, and also my game design skills because I was just having regular conversations about gameplay problems. This is especially true if you are working on a game by yourself, since you don&#39;t get to have regular discussions about your game with anyone.&lt;/p&gt;
&lt;p&gt;If you&#39;re reading this and you are interested in game development, I &lt;em&gt;highly&lt;/em&gt; recommend connecting with your local game development community. This is a more popular hobby these days, so you may be surprised by how many people that live near you share this hobby!&lt;/p&gt;
&lt;h2 id=&quot;6-the-modern-era-going-full-time-indie&quot;&gt;6. The modern era - going full time indie&lt;/h2&gt;
&lt;p&gt;During the later years of my career working full-time, I had a goal in mind. I wanted to eventually work on my game full-time, to build my dream project. I never once felt motivated to work in the games industry, in general, or to seek publishing to try and turn the dream project into a &#39;real job&#39;. Instead I viewed it as a sort of artistic magnum opus, where I wanted full control at all times (regardless of how long it took).&lt;/p&gt;
&lt;p&gt;I saved up money with the plan on building a big enough runway to be able to complete the game project (at a reasonably relaxed pace over several years). Over time, the fire within me to do the project never went out, and eventually the urge to quit my job was unbearable, and so I stepped away from the corporate life in 2024. Maybe this will come to be seen as a huge mistake. At the time of writing this, I&#39;m a little over one year in, and I&#39;m having a lot of fun and I have no regrets. Hopefully it stays that way.&lt;/p&gt;
&lt;p&gt;Even though I&#39;ve been working on the game for a while, it&#39;s still the early days, believe it or not. I have a very long-term mindset with this project, where I want to take my time experimenting with the systems to make them fit together in the best way possible. Therefore, I don&#39;t have much to show yet. When I do, I&#39;ll post about it on this website. Consider subscribing to my mailing list to stay up to date. :)&lt;/p&gt;
&lt;p&gt;-Zach&lt;/p&gt;
&lt;!--EmailOctopus Signup --&gt;
&lt;script async=&quot;&quot; src=&quot;https://eocampaign1.com/form/991a64dc-e033-11f0-acd8-e16c0801f9d0.js&quot; data-form=&quot;991a64dc-e033-11f0-acd8-e16c0801f9d0&quot;&gt;&lt;/script&gt;
</content>
  </entry>
</feed>