Lessons learned from coding solo for two years

Tyler Neylon
6 min readJun 15, 2016

--

I worked alone building an ambitious game called Apanga for most of 2014 and 2015. I accomplished a lot, but ultimately decided to let go of those efforts as the project would have taken several more years to complete. My last post was about parts of that project that went well; this post is about the lessons I’ve learned from the most critical mistakes I made along the way.

Start with the core

If you only remember one thing from this post, this is it. When you build anything, get to the differentiator as soon as you can. This might mean starting with a paper mock or a shallow prototype, and growing it from there. For technically deep projects, it may mean putting together a bit of scaffolding first. In all cases, though, I strongly recommend putting the core of your project as close to the start of your serious work as possible.

My biggest mistake was to design an original game and then build the unoriginal features first. I’ve heard from experienced makers, and seen first-hand, that often the only step you complete in a multi-step project is the first. You really, really want that first step to be something intrinsically interesting.

This has been a hard lesson for me to learn. I’ve had many previous chances to absorb it. Perhaps human nature is inclined to think along the lines of: “Yeah, everyone else makes that mistake. But not me.” I suspect that this perspective will be a deeper part of how I think from now on.

Connect to your community

Interestingly, I didn’t find working alone to be a huge liability. I was a bit lonely, but I found it sustainable. I suspect everyone has a threshold for comfort in isolation, and mine seems to be higher than average.

I was surprised, however, to realize that working with other people is not just about the work that gets done. Immense value is added by having a variety of points of view and of mental lexicons. I missed that by working alone.

Another community is the group of people who may use your product when it’s done. Most successful projects I’ve seen have had or built upon a pre-existing connection with their potential users. I didn’t do a great job of connecting with potential users, although I put serious effort into it. I wish I could give better advice on this, but I think that when someone doesn’t know how to do something, it’s better to be honest about their weakness than to say something that sounds good but isn’t backed up with experience. So: Connecting with users early on appears to be important, but I don’t know the best way to do that.

Design around the resources you have

Another mistake I made was to design as if I could build my dream game, rather than the best game given one engineer, my personal funds, and about a year of dev time. I also made the classic error of underestimating my required engineering time. It seems like a silly mistake in retrospect. I started out thinking of ambition as good. Ambitious ideas are good, but I let that principle override the reality of limited resources.

Also keep in mind that developers always underestimate how long anything will take to build. I recommend multiplying a time estimate by 4 to avoid disappointment. Maybe it will only take 1.5 times as long, and you’ll be happy.

Build a cage around technical beasts

Some days, OpenGL trounced my will to live. It’s a horrible API. Horrible. Developing device drivers is easier. Typing hex codes for cpu-level instructions directly into executable memory is easier. Literally. Not fake literally. Actual literally. I’ve done those things and I suspect you will think I’m exaggerating about how bad OpenGL is, but I’m not. At all.

Anyway. This post is not about OpenGL. So I will generalize this lesson to be about “technical beasts.” There are probably others. I’ve heard bluetooth can be painful. Debugging memory allocation errors in distributed multithreaded code can be painful.

Building a cage to contain a technical beast means to build the interface you want, and then treat it as a separate problem to get that interface working. You may run into performance issues because your initial interface wasn’t designed with a full appreciation of some tricky details. That’s ok — just iterate on the interface. It’s not fun, but it’s a world better than the situation where this interface doesn’t exist and the malignant technical beast you’re wrestling slithers its bug-ridden, poorly-designed tentacles throughout your previously pristine code base. No one likes it when that happens.

Non-lessons

Those were my lessons. Now for the non-lessons, which are the things I suspect other people would tell me to do, but which I think are significantly less important than those listed above.

I’m not saying I disagree with the lessons below — just that they are not critical. Specifically, if a critical lesson ever disagrees with a non-critical lesson, then prefer the critical lesson.

For context, I’m basing these non-lessons off of many game dev advice articles I read while avoiding doing real work.

Not critical: Choose a game engine first

Many people told me not to build a game engine. The useful tidbit that I missed was that you either use a game engine or you build one. So I did kind of accidentally end up building one.

That was a liability, but I see it as a second-level liability. The more important lesson is to plan everything, not just your game engine, around existing resources. I also think that, depending on your game goals, building the subset of a game engine that you personally need may not be too crazy. But, yeah, if you can use an engine, it can save a lot of time.

Not critical: Avoid multiplayer

I’ve heard a number of game devs say that multiplayer games take much, much more time than single-player games. I did not find the multiplayer aspect of my work to be a huge time sink. I estimate that I spent about 15% of my dev time focused on server code and the corresponding network code on the client side.

Not critical: Avoid cross-platform

I’ve also heard some recommendations to focus on a single platform. It did cost me upfront time to begin the code base across platforms. I’m not sure exactly how long, but maybe around 6–8 weeks. After that, I think I spent around 5% more time on keeping things working across platforms versus the time I’d have needed on a single platform. This percentage was probably kept low because I minimized which libraries I used and worked with C and Lua — both highly portable languages.

Not critical: Never code when you can use a library

Most developers I’ve worked with prefer using an existing library to writing a new one. If a nice interface already exists, then it is great to use a third-party library because it’s already tested and has community support. Those are huge values.

However, many libraries are so poorly designed that building a replacement can be worthwhile in the following ways: You can completely understand every aspect of your own library because it’s small. The interface is a great fit for your needs. If your library doesn’t do exactly what you want, you don’t have to learn a new code base to understand why or to officially fix it.

As an example to illustrate some advantages of building your own libraries, consider the OpenMP library which supports cross-platform shared-memory threading. The API spec for OpenMP is a 320-page pdf file. I believe it is an excellent library that is well-suited for large-scale tasks or for user groups who are invested in deep, detailed applications of this domain. I wanted to fully understand my threading library and to keep the overall code base small, so I created the thready library which has a 5-function API.

The most painful part of this experience has been knowing that, at some level, I probably could have made more sacrifices to keep working on Apanga. I might have been able to find funding. I might have been able to convince someone to work with me, to kickstart the game, or to save up more money and get back to the game. But none of those feel right to me anymore. I still love the vision, but sometimes love isn’t enough. Walking away from so much work, I suspect the greatest long-term lesson I can learn is to maintain a healthy perspective. To be honest with myself about both the good and the bad. To integrate my missteps not in terms of hopes lost to the past, but in terms of wisdom gained for the future.

--

--

Tyler Neylon

Founder of Unbox Research. Machine learning engineer. Previously at Primer, Medium, Google.