I am currently reading Daniel Kahneman’s pop psych book “Thinking, Fast and Slow”. The basic premise of the book is that humans have two generalized thought processes - one that is reflexive and instinctual (System 1), and another that is more rational and deliberative (System 2). Book smarts are commonly equated to the latter and streets smarts to the former. I often think that coding has a similar thought pattern to it, which is unsurprising given that computers are designed to mimic human thought and communication, in a context-stripped yet efficient manner.
When I’m coding, I often have a large problem that I want to solve. I want to pull all the data from a website, for example. Or I want to create a program that helps me better manage my finances. Conceptually, I can map out the actions and data that these programs will need. However, like most technological advances, coding starts from the bottom-up. Spaceships didn’t immediately follow horses as a means of transportation; first came bicycles, then trains, then cars, then planes, then spaceships. Technology tends to build on the most recent invention, and while large paradigm shifts can transform a communication platform virtually overnight (e.g., the Internet), most innovative products are built on the backs of countless previously innovative products.
In a similar vein, albeit on a much smaller scale, programming is the same way. While I may have a large problem that I want to solve in mind as I start to code, when I actually get down to writing, I have to take it piece by piece, line by line. Otherwise, communicating a large, abstract concept to a computer that doesn’t understand context and has to be explicitly told what to do is pretty difficult. I have to distill my program into its most irreducible component, make sure that runs smoothly, then add another layer, make sure that layer runs smoothly, etc. Rinse and repeat.
For example, if you want to create a Blackjack game, you don’t just create Blackjack. You have to start from the bottom, not just in terms of defining the game attributes, such as deck structure, card values, the number of players, etc., but you also in determining the gameplay. Start by assuming that you only have one player. Master the gameplay for that one player (e.g., what happens when the player stands? What happens if he/she hits?). Map out how a single player would play if he/she were in a bubble. Hold off any sense of betting because that will only make things more complicated at this point. Focus on getting the gameplay for a single player correct, then move on to add a dealer, add more players and introduce betting components.
If I were to create a Blackjack game, I would approach it iteratively - focusing on mastering one small, low-level yet self-sufficient component, then using that as a building block of a larger piece of the game. This means writing one line of code, running the code, debugging it as needed, writing another line of code, running it, debugging, etc. As I’m doing this, I’m using a more instinctive, System 1 approach to coding, in that I’m responding immediately to the output from my IRB shell (Interactive RuBy). I’m not focusing on the larger, bigger-picture problem, which remains pretty abstract early on. Instead, I’m iteratively tackling problems one at a time until I end up with a finished product. Okay, so the System 1 / System 2 analogy isn’t entirely apt as writing a line of code still requires a deliberative, rational thought process, but you get the point. Early on in a project and when actually writing lines of code, I try not to let the larger issue at hand get in the way of progress. If you just focus on the big problem, you’ll often get overwhelmed and lost in the problem instead of progressing toward a solution.
Avi spoke a lot about this concept of programming slowly and shortening the feedback loop in class today. As I mentioned in a previous post, one of the beauties of coding is that you get immediate gratification; I can write a few lines of code and instantly see the results. Beginners (myself included) often get lost in trying to solve a big problem without thinking through the concrete, small steps that a computer can understand. Personally, I tend to jump too quickly into coding and trying to solve the biggest problems first. I’ve realized over the past few days that I need to take my time, write more pseudo-code and start small.
In addition to discussing coding best practices, we worked more on our scrapers and tried to refactor some of our code into more efficient class constructors. In the afternoon, Avi taught us about object orientation, recursion and directory/file access in Ruby. Each day I’m learning new components of my technical skill set, all of which build on top of each other and make what I’ve learned before even more powerful. Coding is a cumulative skill set; what I learned in the first seven days I used today, and what I’ve learned today I’ll use tomorrow, the next day and for the rest of my coding career. This is comforting, as it lessens the pressure to get it 100% right the first time, and its reassuring to know that since practice makes perfect and since we’ll be getting a lot of practice, we stand a solid chance of getting pretty good.