I finally got a working starfield and a spaceship to fly around a very large space. Compared to the last milestone’s rather drab technical test of spinning shapes, this is huge! One can start to imagine an actual game!
Also huge is more insight into overcoming my particular brand of procrastination when facing personal projects like this. Or really, any project that requires some measure of uncertainty coupled with the desire for rapid progress. I now see new coping mechanisms that may help me move past the feelings of frustration, which I’ll talk about that right after the jump. After that, I’ll talk a bit more about the technical challenge in detail for those who are interested.
My Brand of Procrastination
I love knowing how things work in operational detail. I love having deep insight into process and what makes one way more effective than another. Conversely, I hate the feeling of when I can’t get a handle on the details or grasp the critical insights behind a process. I also generally hate feeling dumb, ignorant, and incompetent.
I dislike these feelings SO MUCH that in the first few milliseconds of contemplating a new task, I don’t make a practical distinction between BIG UNCERTAINTY and small inconveniences. I have to catch myself and force my mind past that reaction into action, because my immediate natural reaction is to stop and try to find answers to my questions until I feel more certain or not work at all/find something else to do. In other words, I almost immediately lose momentum in the face of the unknown, and if I’m not pushed by some greater force I have a tendency to stop dead in my tracks. Embarrassing but true!
This is a feeling that I think I’ve always had, from the time I was a kid to EVEN NOW as a skilled adult. The one innate power I have is an OCD-like hunger to pursue knowledge and insight itself. If I don’t know how something works and I am curious enough, I will hammer at it from all available angles until I am mentally exhausted or I run out of ideas. In the case where I’m not curious but see the task as a kind of chore, I pretty much run out of gas and take lots of naps. Only a powerful secondary motivator, such as wanting to help someone else or if I’m responsible for making progress, will make me re-engage my willpower and motivation. However, working under this type of motivation extracts higher wear-and-tear than when I’m operating on pure curiosity alone, so it’s not a sustainable operating mode for me. Also, as my personal projects have no secondary motivator, they tend to stall unless I synthesize another purpose (hint: writing about pursuing my big ten-year goals is me putting myself in the role of sacrificial creative noob, so others in the same place feel they aren’t alone in being here in noob-land!).
Anyway, these personal insights have ramifications for tackling my big hairy projects. There are two main ways that they manifest as resistance:
- As most of these projects require learning, not dealing well with my lack of knowledge is a big problem. Interestingly, it’s not my ignorance of facts and procedure that bothers me; I like knowing what I don’t know, because that helps give me direction. It’s when the available learning materials fail to give me the knowledge I want in an efficient and clear manner that I get angry and frustrated. It’s a negatively-charged emotional response that doesn’t help me get anything done.
- I have a pretty good imagination when it comes to visualizing what a finished project looks like. I’m sure that lots of people are good at this, but my imagination also includes EVERY best practice, refinement, and mark of excellence that I’ve ever learned of. This gives me an incredibly discerning eye in a few areas, which helps me do my work. It also raises the threshold of expectation so high that it leads to a kind of paralysis when starting, because the desire for excellence is such a built-in value.
I’ve known about these two aspects of my procrastination for a very long time, and have tried to deal with them by repeating such homilies as, “break the task into little steps” and “don’t let great get in the way of good”. These are useful universal principles of action, but what I dislike about them is that such advice fails to address MY SPECIFIC DESIRE to know how they deliver results on an operational, process-driven level. On milestone 2 of my project, I suddenly realized with some embarrassment what the crux of my performance shortfall has been: I am not a dedicated, experienced, practicing creative.
It may seem obvious to people who naturally “do” without the need for understanding. Such people innately know, I suspect, that practice and repetition lead to improvements in skill. Motions becomes more efficient. Problems are solved as they come up. This is exactly the kind of zen mindset that I tend to lack, even though I know that it’s true. The problem is that I am neurotic about process, not mindful or patient. That clear path to productivity I crave will come from, I suspect, effectively channeling my enormous ability to overthink AWAY from self-defeating analysis. I can analyze-away my desire to do something in milliseconds. That analytic ability is far more useful when channeled into the answering of questions. In other words, the analytic mind focused inward tends to stop the doing from happening. Retraining my mind to focus outward is what I’ve been learning to do, though I wasn’t aware that this is what I’ve been trying to do until just now.
Putting this insight in context with the two resistances I mentioned above, when it comes to doing difficult creative work:
- That one must learn new abilities in the vacuum of bad teaching materials is a universal life truth. The most accessible means of filling in the gaps is to try building your own simple understanding as a bridge to gain enlightenment. Once one spends the time to build the bridge, it’s yours. Then you can save everyone else some time by explaining it your own way.
- Desiring excellence is not the same as pursuing excellence, which by necessity has to take you on a journey through what is bad so you can appreciate what is good. When at the beginning of this endeavor, reaching for the nearest and most obvious approach is likely to not be the one you stick with, but it is also a bridge toward refinements that will be hard-won through testing.
- All this takes lots of time, but don’t focus on that as a metric. In the beginning, focus instead on answering the next obvious question with the nearest obvious answer. This will get you very far until, hopefully, you suddenly see the shape of what you are really doing. Then, more sophisticated approaches will naturally suggest themselves.
- Above all, you must trust yourself that this will happen. It does. Your failures are instrumental to building later successes, and you alone are responsible for seeing your journey through to the glittering results imagined in your dreams. I call failures “data points”, because they point the way to to your ultimate destination.
So, how did this apply to the actual work?
The Milestone in Review
In the 18 days since the last milestone on February 23, I put in 41 hours of work on my video game project. I didn’t count them up until today, because I didn’t want to measure my sense of productivity by “hours spent”.
In hindsight, the pattern of spending a lot of time “thinking before doing” is really obvious. This is how the “resistance to uncertainty” manifests itself. Rather than do, I delayed by finding more certainty or bailing out until I had more energy to deal with it. The bold text in the following table are where I felt the most resistance:
day | time | hours | description |
---|---|---|---|
Wed 25 | 1345‑1545 | 2.00 | Define a way of handling asynchronous loading, feel a sense of satisfaction. |
Wed 25 | 1600‑1645 | 0.75 | Design a async load manager, but then realize that async loader might be handled by Promises, a new Javascript language feature I had been hearing about. |
Fri 27 | 1500‑1900 | 4.00 | Study implementations of Promises, tutorials, writeups. |
Fri 27 | 2200‑3000 | 6.00 | Finally get a handle on how to implement and use Promises, then set it aside. |
Sat 28 | 1245‑1615 | 3.50 | Massive cleanup of SystemLoop, GameLoop |
Sat 28 | 1615‑1815 | 2.00 | Write documentation on Github Wiki |
Wed 04 | 1130‑1245 | 1.25 | Try to work on Starfields, but feeling flustered |
Wed 04 | 1245‑1415 | 1.50 | Slough through ThreeJS point cloud examples |
Wed 04 | 1700‑1830 | 1.50 | Add rotation features, implement Starfield parallax! |
Sat 07 | 0530‑0630 | 1.00 | Pick PhysicsJS and Keypress libraries |
Mon 09 | 0430‑0530 | 1.00 | Get Physics simulation to work, sorta |
Tue 10 | 1000‑1200 | 2.00 | Ship controls, basic, implemented |
Tue 10 | 2000‑2245 | 2.75 | Ship controls, move to own module implemented |
Wed 11 | 2115‑2300 | 1.75 | Convert to 3D camera, figure out fog trickiness, fix camera backoff algorithm. |
Thu 12 | 1030‑1415 | 3.75 | Figure out how Mimosa “web packing” works, debug r.js problems with Durandal and mimosa default configuration |
Thu 12 | 1445‑1630 | 1.75 | Settle on just using package, not optimization or minification. |
Thu 12 | 1630‑2100 | 4.50 | Figure out how Heroku works, deploy! |
41.00 | TOTAL HOURS |
The bolded entries are all situations when I was trying to learn something new. The frustration existed for as long as it took for me to distill a clear mental model of what the unfamiliar concept was, and how it was used in the context of my own code. In several cases, the frustration was exceptionally high because the documentation I found lacked a complete map from concept to implementation. My opinions on what documentation I found fell into the following categories:
- The documenter took basic details for granted, assuming you knew them.
- The example code or description was contrived and did not demonstrate usefulness in itself.
- The example was not syntactically correct or runnable.
- Too much visual separation between code samples, so could not easily compare them.
- The concepts had not yet been experienced by me, so they made no sense to me.
Here’s an example of the first kind of resistance, when I was learning new ways of thinking and feeling dumb. I had to write a bit of code called an “asynchronous load manager”, which is like an assistant that ensures that items you request appear in the order that you need. It’s like ordering food at a restaurant: you want the appetizers to appear first, then the entrees, then the deserts. If they appear out of order, the meal experience is disturbed. I wanted my load manager code to be simple to use with a very clear model of use, without the need for complicated definitions. So I defined what I thought was a reasonable methodology, and was all set to translate my ideas into working code when I realized that a new Javascript featured called “Promises” might be the exact feature I was looking for. As I had heard much about Promises but didn’t understand them, I figured that I owed it to myself to finally find out how they worked. It took ten hours for me to wrap my head around a relatively simple idea, largely because I am not that familiar with the pattern of programming that advanced Javascript tends to follow, and I had to learn a new way of thinking about code. In hindsight, this experience has made me a stronger Javascript programmer, but at the time I was deeply irritated by the hoops. At the end of it all, I understood roughly what Promises do, and I will use them when I’m ready. I probably didn’t need to understand how Promises were actually implemented, but the reason I pursued it was because (1) I am really OCD when it comes to how things work and (2) I didn’t think the tutorials I found on using Promises were comprehensive, good or insightful. When it comes to learning, though, I can’t let my opinion on materials stop me from actually synthesizing my understanding from what is available. That is the big trick I need to get better at.
A second example is grounded in the second kind of resistance, which was wanting to have the whole system complete before I even took the first simple step. Visually, I wanted to have a spaceship flying in a scrolling starfield, which was really easy to imagine because it’s been done a million times before across thousands of games. I even knew how to implement it from past experience, and had outlined a simple approach that I knew should work. What I didn’t know was exactly how or where I would do it, and from that I was concerned about wasting effort (I’m impatient) or write something crappy that other programmers would snicker at. It’s this dread of not being optimal or wasting effort that screws up my momentum. On top of that, there were a bunch of questions I didn’t know the exact answers to yet:
- What is the best way to draw points in WebGL?
- Where should this point-drawing code live in my code structure so it makes logical sense?
- Where would this point-drawing code be invoked during the game’s rendering loop?
- How should the point-drawing code be made accessible to other system components for maximum flexibility, assuming it works?
- How to make the code reusable?
Each of those questions were just the ones I thought of before starting, until I remembered that not thinking beyond one question at a time was the key to getting through it. So, starting with the first question, I reduced it to how do you draw any kind of point in WebGL? and looked it up. I wrote garbage code just to see if I could get the computer to draw anything at all in a predictable way, and hours later I was about to get some dots to appear. They were too big, not showing up quite as expected, and I ended up discovering a flaw in the way I was setting up OTHER parts of the code. I discovered holes in the graphics library documentation that I plugged after searching for people with similar problems, marveling all the while that without the Internet I probably would have been stuck for days. But eventually, all that got sorted out from asking just one question and following the trail down into the rabbit hole. I couldn’t answer the questions easily ahead of time. I had to live them, which gave me the experience to deal with them. I hate the idea of having to do that, but I’m starting to see it’s not so bad.
In an ideal world, the code libraries I am using would be clearly documented as to their intent, its means of modeling the problem it is solving, and be opinionated in its approach with clear supporting arguments as to why it is that way. Why? I tend to lack interest in experimenting before understanding. On the other hand, I think a lot of programmers ENJOY experimenting with code to see what happens, and playing with it. I don’t feel any particular joy in it, though I do like a clearly written piece of code once I’m finished with it, and I also do like knowing that I put it together cleanly. However, I can’t let the negative feelings about documentation that does not meet my criteria for technical writing shake me from my learning path. I am discovering that the experimentation is a useful way for synthesizing and learning with what’s available. And through this code project, I hope to help put out some good documentation that saves other people some time along the way. Because GOOD GRAVY do we need more of that. But I digress.
Time Breakdown
For fun I roughly categorized the time spent in particular tasks:
category | description | hours | % |
---|---|---|---|
study | wrapping my head around libraries, tools, and language features that I don’t yet understand | 19.00 | 46% |
design | coming up with conceptual code structures that achieve desired results in an easy-to-understand way | 2.00 | 5% |
code | actual programming! writing loops! conditions! sculpting elegant data structures! debugging! | 9.00 | 22% |
integrate | managing development tools, adding external code libraries to the project, organizing source code, and deploying test builds | 5.50 | 13% |
refactor | reviewing past code and rewriting it for better clarity | 3.50 | 9% |
document | comment and explain the code in a manner that will help reuse it later with a minimum of confusion | 2.00 | 5% |
Almost half my time was spent being stuck, learning about how something worked so I could actually use it for something. I feel my blood pressure rising just thinking about it, but I am going to embrace that this is what learning is. Interestingly, only 22% of my time was spent in writing what I would consider “new code”. 13% of my time was spent doing “integration”, which is basically finding libraries of other people’s code and gluing them into my own. It also includes figuring out the nuts and bolts of managing code and deploying it somewhere where it can be seen. Very little time was spent designing new approaches, but that’s about to change with the next milestone: artificial intelligence that makes ships fly around by themselves.
Milestone Changes
My original M2 Specifications were this:
starfield… DONE!- simple move-to physics … half-done
- behaviors and state machines
- timers/triggers/filters/events
- stage and level management
- sound manager
- settings manager
Ha ha! So funny! I decided that getting the starfield + spaceship was good enough for a milestone.
While I didn’t get everything I wanted to do, I ended up doing stuff that I didn’t anticipate, like researching “Promises” and rewriting the key code loop objects to make it work better. I also learned how to package the app so I could share it on a free Heroku plan, so for the first time I can have a public build that people can actually play with. The build is at http://1401.davidseah.com, and while it’s not much to look at now, having the ability to share what I’m doing is a huge win! When I have the ability to share my progress, that makes me want to have progress to share! A virtuous cycle, it is! :-)
For the next milestone, I’m going to be a little more realistic and just say it’s all about moving ships exhibiting behaviors. This actually touches the next three things on the list:
- simple move-to physics
- behaviors and state machines
- timers, triggers, filters, and events
That is a big hairy task! They are not entirely new tasks for me to learn how to do, so I’m facing the resistance of wanting the system before I start, and I’ll have to write a lot of test code to refine my approach to make a super-clean, super-easy way of describing how ships can move in interesting and intelligent ways. The first step to breaking that resistance is to implement ANY way of handling any of these challenges. It is entirely OK to learn to do it badly, and then trust myself to learn from it. That’s the major philosophical takeaway from Milestone 2.
4 Comments
Great post! The fact that you’ve come this far, and saw the value in rewriting and exploring promises is a huge thing. We all deal with that hurdle of feeling dumb because we have to research and learn something new, but that’s what makes programming so much fun and rewarding! (Not to mention that this particular concept is also very applicable outside of javascript, so now you have an understanding thats made you a much deeper developer.)
The breakdowns you listed, and approach in general seems hyper productive. I’m definitely going to model this for my own work and bring it up with me team. Plus the game looks pretty awesome so far, so keep it up! Congrats!
Patrick: Thanks for the encouraging comment! It strikes me that having some kind of feedback from others in the same space is really helpful too. I think one factor that adds to my impatience is that I don’t work with other developers, or have a sense of how quickly they work. So I used to assume I was doing it slow and wrong, which probably isn’t true, but who knows??? More uncertainty! More doubt! But I’m learning to let go of that. I’m a decent developer, if a little obsessed about documentation. If documentation was cleaning, then I would be M-O from Wall-E :-)
I’m impressed by your ability to find the blocks. I can spend hours or days avoiding something without realizing it. :-( One thing I do for learning is to start a tiny project on the side to learn a topic without trying to make the code clean. It lets me experiment quickly, learn quickly, and then throw away the code. Ideally these tiny projects happen between main projects, but sometimes I’ll do them on the side.
Amit: I think I’ve learned to recognize the negative pushback in my own head…it’s palpable and feels depressive. I’ve always had a very active meta awareness in my thoughts that acts almost like a tape delay in a live TV show, so that helps me catch the moments. I think I’m also still learning to enjoy learning. I’ve come to think that I don’t really like exploring at all, but I like knowing. I’ll explore so I can know, and learning is like the toxic byproduct :-) If there was a way to know without learning, I probably would be jacking in right now. I guess what keeps me from doing it is the problem of pervasive low quality knowledge.
I do like the idea of starting dirty…that’s generally what I do, but I don’t particularly like it. I’m probably not experienced enough of a developer to have built that into the process as a separate kind of activity. I would guess there’s a certain minimum scaffolding required? 1401 is kind of my attempt to build the minimum scaffolding for maximum expressiveness.