Finding out if I've Improved as a Programmer: Part 2

I've been looking into whether or not I've improved as a programmer by dusting off an old shell program I wrote for a college course and seeing if I can make it any better. The exercise has been eye-opening so far. I really have come a long way on my programmer's journey, with much longer to go, I'm sure. To quickly recap, all of the refactorings I'm doing are going up on my GitHub repo so you can follow along with the changes, and I identified these general issues with the code:
  • It doesn't compile
  • Minimal tests
  • Inconsistent indenting and formatting
  • One long function in main()
  • Poor structure and organization
  • Major memory management issues
In the first article, I tackled the first three items, so I now have the last three—breaking up main(), giving the program better structure, and improving memory management—to address before I'll be happy with the revision. Let's jump right in, shall we?

Finding out if I've Improved as a Programmer: Part 1

Do you ever wonder how far you've come as a programmer? Well, I sometimes do, and today, I've decided to take a look and see if I've made any progress. I think that I have. I certainly have spent a lot of time studying and practicing to be a better programmer, not to mention the years of projects I've worked on in my career, making a living of this fascinating endeavor of instructing computers to perform automated tasks. One hopes that all of that effort hasn't gone to waste.

If I look back at one of my early projects, I should be able to easily see ways to improve it to make it clearer and cleaner. If I can't, well, what have I been doing all of these years? I decided to pluck a project from my operating systems course in college, good old CS537 from UW-Madison. It's a simple introductory project that implements a basic shell in C. The shell can execute commands either in an interactive mode from a prompt, or read commands from a file given to the shell as an argument when it starts. It's a small enough project that I can evaluate it in a couple blog posts, but not so small as to be trivial, like FizzBuzz or the Sieve of Eratosthenes.

Let's Refactor Some Bad Code, Part 3

To quickly recap, we're refactoring some code I found that implements a rainflow counting algorithm. I used this code as a model to implement a real time algorithm for use in a data acquisition system, but before I could do that effectively, I needed to basically rewrite the code so that I could understand it better. I started off by making some tests and running it through an auto-formatter. Then I improved the UI so that I could run the model more quickly. Now it's time to work through the main part of the algorithm and make it more clear and understandable. Once again, you can view all of the commits at my GitHub repo to see side-by-side diffs of the changes to the code.

Let's Refactor Some Bad Code, Part 2

One reason to spend time refactoring code is to make it livable. If you think of your code as a workshop—a place where you get work done—you want your workshop to be clean and organized so that you can spend time efficiently getting stuff done. If you have tools and materials haphazardly strewn all over your workshop, it will take longer to find the things you need, and it will be difficult to clear out the space required to do the tasks that need to get done. A messy workshop negatively affects the quality of the workmanship that's done in it. So it is with code.

Last time we did the bare minimum cleaning necessary to get a rainflow counting program in working order by giving it consistent formatting and a small set of tests. Now the goal is to target those parts of the program that make it the most annoying to work with and fix them so that the program is more well-suited for its use cases. I'll show each change to the code as a git commit, and you can follow along with the diffs in my rainflow git repository in addition to the code snippets I'll show here.

Let's Refactor Some Bad Code, Part 1

Unfortunately, we can't always be writing new code when programming. Much of being a programmer involves working with code that already exists because there is so much code out there already. There are mountains and mountains of code, and, as every programmer knows, not all of it is awesome. Sometimes this code has to be refactored to adequately maintain it, sometimes it needs to be done before new features can be shoehorned in, and sometimes it just needs to be done in order to stay sane while working with it. This is not always other people's code, either. Oftentimes it's your own code. I know I've written more than my fair share of bad code, and I may even use it as an example someday. That would be fun.

Tech Book Face Off: The Shallows Vs. Thinking, Fast and Slow

After my book review on Pragmatic Thinking and Learning and How the Brain Learns, I received a recommendation to read another book, The Shallows by Nicholas Carr. I decided to go with it (thanks +Helton Moraes), and I ended up pairing this book with another popular book on how the brain works and how we humans think, Thinking, Fast and Slow by Daniel Kahneman. Through these books I have a personal goal (it's good to have a goal when reading) of finding ways to regain control of my mind and hopefully improve my thought processes. Do these books help clear a path to that goal? Let's see.

Design Patterns in Ruby front coverVS.Practical Object-Oriented Design in Ruby front cover

Practice Programming Through Play

I'm a big fan of puzzle games for exercising your mental muscles while having some fun at the same time. Solving puzzles through your own powers of thought gives a certain kind of satisfaction that is especially rewarding. Games like Sudoku, Tetris, and Rubik's Cube are great for strengthening mathematical thinking and visual-spacial intelligence.

Nowadays we seem to have an endless supply of puzzle games on mobile devices to keep our minds occupied during all of the spare moments of the day. It's fine to use puzzle games to fill up the empty spaces of time, but I've found some games that entice me to go much deeper. Lately I've been getting into games geared towards introducing kids to programming concepts. Lightbot and Cargo-Bot are games that teach young kids the basics of programming by setting up sequences of simple instructions for on-screen robots to carry out in pursuit of a goal. While these are kids' games, and quite good ones at that, I've also found them to be excellent practice tools for me.

Tech Book Face Off: Design Patterns in Ruby Vs. Practical Object-Oriented Design in Ruby

I've been in a good book-reading mood lately, so I'm writing up yet another Tech Book Face Off. This time I wanted to dig into some more Ruby books, since I've felt like I still have much to learn about this wonderful programming language. I also wanted to work on writing better organized programs, so I targeted some books on program design. The books on deck are Design Patterns in Ruby by Russ Olsen and Practical Object-Oriented Design in Ruby by Sandi Metz. Let's see how they compare with each other and with some of the other books I've read on design.

Design Patterns in Ruby front coverVS.Practical Object-Oriented Design in Ruby front cover

Tech Book Face Off: Pragmatic Thinking and Learning Vs. How the Brain Learns

To work and succeed as a programmer, it is necessary to constantly learn new things. The faster and better you can learn new tools, new technologies, and new techniques, the more effective you can be as a programmer. On a personal level, I also have a fascination with learning. What are the best ways to learn new things? What can I do in a practical sense to learn more efficiently? How does the brain process, store, and recall new experiences, anyway? I've felt like I've always been a fairly adept learner, but I've never done any amount of research into how I could do even better. These are the questions I set out to answer while reading through two books on how to learn: Pragmatic Thinking and Learning by Andy Hunt and How the Brain Learns by David A. Sousa. Let's see what secrets these books reveal about how to learn better… faster… smarter.

Pragmatic Thinking and Learning front coverVS.How the Brain Learns front cover

Tech Book Face Off: JavaScript: The Good Parts Vs. JavaScript Patterns

After learning a new language and getting comfortable with its syntax and feature set, it's a good practice to explore how to write well in that language. Each language has its own quirks, and writing well in a programming language means learning how to write in it idiomatically—how to structure statements, functions, and the entire program in a way that is most efficient for that language, and how other programmers expect things to be expressed in that language. I figured it was high time that I learn more idiomatic JavaScript, so I picked up a couple of books on the subject: JavaScript: The Good Parts by Douglas Crockford and JavaScript Patterns by Stoyan Stefanov. Both books are fairly slim, easy reads, but there's no need to read both. Let's see which one comes out on top.

JavaScript: The Good Parts front coverVS.JavaScript Patterns front cover

Learning Without Understanding

It's funny what you can do without knowing what you're doing. For instance, I started programming in Lisp over a decade ago without even knowing it. I realized this, when a few months ago, I started learning the Scheme dialect of Lisp and things felt oddly familiar. I had seen function names like car, cdr, and cons before, along with all of those parentheses. It turns out that I had already learned another dialect of Lisp called SKILL, and I had had no idea what I was learning at the time. I wonder if I would have learned more and gained a wider understanding of the development environment I was working in had I understood what I was doing those many years ago.

Tech Book Face Off: The C Programming Language Vs. The Little Schemer

I decided it was time to take a look at two of the oldest books on my tech book list, the famed The C Programming Language from 1988 by Brian Kernighan and Dennis Ritchie (a.k.a K&R) and the not quite as old The Little Schemer from 1995 by Daniel Friedman and Mathias Felleisen. In the world of programming, these books are ancient, but I still hoped to gain something from reading them because new (or at least forgotten) insights can often be gleaned from old books.

I have been programming in C and C++ for nearly two decades now, so picking up a few insights was my main goal with K&R. I didn't expect to learn a ton of new stuff about the language since it's such a small language and I've been using it for so long. As for The Little Schemer, I have heard so many good things about this book and the Scheme programming language (a dialect of Lisp) that I was excited to see what it was all about. I was surprised by both books, and probably not in ways that you would expect. Let's take a look at both books in more detail.

The C Programming Language front coverVS.The Little Schemer front cover

In Search of the Best Code Editor

I have used quite a few code editors over the years, and since I spent the last four posts explaining how to use my current favorite editor, I thought I would take a step back and go through a broader overview of some of the editors I've used recently. Some are specific to certain languages or platforms, and some can easily be used with almost any language on multiple platforms. Each editor has its strengths and weaknesses, its cool features and warts.

I'll briefly cover what makes each editor special and why I do or don't like it. Choosing an editor ends up being a very personal choice, and different programmers will gravitate to wildly different editors. That makes this review necessarily opinionated, so if you don't agree with me, that's expected. The important thing is to try out different editors for yourself to figure out what works best for you. When you find your best editor, you'll know.

Learn Vim Fast: Useful Plug-ins

Now that we've learned quite a bit about Vim, from the basics to movement and editing, it's time to really put Vim to work for us by extending it with some very useful plug-ins. Vim is an extensible editor, and a vast array of plug-ins are available to make Vim even more powerful for editing code quickly and efficiently. We'll take a look at some of the most useful plug-ins and how they can accelerate your coding even further, but first we need a way to efficiently manage all of these new plug-ins. Not surprisingly, a plug-in manager is available for just this purpose.

Learn Vim Fast: Editing at Speed

So far we've learned some absolute basics of using Vim, customized Vim to make it a little better for everyday coding, and gotten comfortable moving around quickly in a file. If you've stuck it out and practiced the movement and editing commands we've covered so far, you are probably starting to get a sense of the potential that Vim has. With a small set of one letter commands, you can get an awful lot done, and if you've practiced enough to make your use of the commands automatic, you can get stuff done wickedly fast.

It's time to shift into high gear and round out our Vim skills with a more complete set of editing functions. We don't want to always have to enter Insert Mode to make changes to our code. Sometimes we need to move large chunks of code around, change a bunch of variable names, or delete irrelevant code. These code editing tasks would be painful if we had to do them all in Insert Mode, but they can be positively trivial with Vim's powerful editing commands.

Learn Vim Fast: Moving In and Getting Around

If you started learning Vim with my last post, and you've been practicing the handful of commands we covered, then you're probably pretty tired of how you have to move around and edit things with only those rudimentary commands. It's time to expand our command set and crank up our efficiency in getting things done with Vim, but before we do that, let's take a look at how to make Vim a bit more comfortable to look at.

Learn Vim Fast: Quick Start Guide

I use a lot of different text editors for the various programming languages I write in. When doing embedded C/C++ programming, the IDE is almost always Eclipse based. When doing Python scripting, Python(x,y) with Spyder is a solid choice. When doing C# Windows programming, Visual Studio is almost a must. But my default editor when I need to knock out a quick little program, bring up some code for a second to check something, or work in Ruby or Javascript for any amount of time is Vim.

Every editor has its strengths, its weaknesses, and its warts. Vim is no exception. Its spartan interface is nearly impenetrable to the beginner, and it has a killer learning curve. I remember the first time I encountered Vim while in college. I was an intern at a small integrated circuit design company, and I was looking over someone's shoulder as he quickly jumped in and out of files from a Linux shell, darting around the files and making crazy edits without ever lifting his hands from the keyboard to reach for the mouse.

"What the hell kind of editor is that?!" I asked in awe.
"Oh, that's vi," he responded. "You don't want to use it. It's archaic and has a killer learning curve. You'll be happier with a modern editor."

Reflections on Programming

My perspective on programming has changed quite a bit over the years. Even in the few years since I started this blog I've noticed that I look at programming differently than I used to. If there's anything people who work with technology need to get used to, it's change, and I expect that my perspective will continue to evolve in the years to come. This is an attempt to take a snapshot of how I look at programming right now and how it's different from the recent past. As for the future, I'm not capable of speculating. We'll have to see what I think when it gets here.

Tech Book Face Off: Practical Node.js Vs. Node.js the Right Way

I've recently gotten into some server-side JavaScript development at work, and I needed to take a crash course in Node.js to make better progress, so I did what I always do. I picked up a couple of books on the subject and dug in. I did some perusing of reviews on Amazon.com and settled on a couple of books that appeared to be solid: Practical Node.js by Azat Mardan and Node.js the Right Way by Jim R. Wilson.

The funny thing about Node.js (I'll refer to it as Node from now on) is that there's not that much to talk about, so you quickly move on to talking about all of the libraries that you can plug into Node to get stuff done. That's because Node isn't a framework like Ruby on Rails or ASP.NET MVC. Node is a runtime that runs on the Chrome V8 engine, and all it does is allow you to run JavaScript directly on any machine outside of a browser. It includes a small, tight collection of APIs for working with file systems, operating systems, and networking interfaces, and it establishes an asynchronous paradigm for writing and executing code.

This asynchronous paradigm takes a little getting used to. Basically, any function call that could block, be it a file system access, database access, or HTTP request, will take a callback function as its last parameter and return immediately. When the slower operation finally finishes, the callback will be executed with the response from the operation as its parameters. If you forget about this behavior, you'll very quickly run into situations where you're trying to read things out of a database that haven't been written into it yet, or getting empty responses from HTTP requests. Basically, all dependent code needs to be executed inside callbacks, and that leads to the well-known Node existence of Callback Hell. We'll talk more about how to deal with that in a minute, but that pretty much is Node in a nutshell. Let's take a look at the books.

Practical Node.js front coverVS.Node.js the Right Way front cover

What Would Happen If We Created AGI?

This is the big question surrounding AI. In reality, nobody knows, and I'm not going to claim that I do either. I'm merely going to speculate, hopefully coherently, as to what I think could happen and what I think won't happen if we create AGI (Artificial General Intelligence). The predictions flying around out there are all over the map, so it's likely at least some people will be at least partially right, but things will likely go differently than anyone can possibly imagine simply due to the nature of what we're trying to predict.

This is the third post in this mini-series on AI, inspired by the excellent book Gödel, Escher, Bach by Douglas Hofstadter. In the first post, we defined what intelligence means in the context of developing an artificial intelligence and listed the traits of general intelligence. In the second post, we explored how the characteristics of intelligence enumerated in the first post might develop or emerge in an AGI. In this post we're going to dream. We're going to let our imaginations run a bit wild and try to think about what possibilities would arise with AGI. But first, let's get a little more context.

Is Artificial General Intelligence Possible?

We all know that general intelligence is possible. We have living, breathing proof right in front of the mirror. Humans ask wide-ranging questions, solve general problems, and pursue knowledge with an unending passion. While billions of years of evolution has developed at least one instance of general intelligence, is it possible for that intelligence to create an artificial general intelligence (AGI) capable of similar feats of thought? Until now that is a problem that we have not proven to be solvable, but I am convinced that it is.

In my last post, I listed what I thought was a complete set of traits that defined intelligence. Without any one of these traits, intelligence would be questionable. With all of these traits present, we would almost certainly have intelligence. Now we'll explore these characteristics in more depth to see if and how it would be possible to develop them in an artificial intelligence. We'll start with what the AGI would use as input.

The Nature of Intelligence

In my last post I wrote an epic review of two books that delved into the nature of intelligence and the limits of computation: Gödel, Escher, Bach and The Annotated Turing. Both books sparked all kinds of new ideas about artificial intelligence (AI), especially GEB. I tried to stick to the material in the books for the review, but now it's time to dig in and explore some of the ideas those books spawned in my mind about AI. These ideas boil down to three main questions that define the scope of issues surrounding AI.
  1. What is the nature of intelligence?
  2. Is artificial general intelligence possible?
  3. What could happen if we create AGI?
These are big, complex questions that plenty of smart people are trying to answer for various applications. The specific reference to artificial general intelligence is there to distinguish it from the numerous examples of artificial narrow intelligence that we already have, such as chess programs, simulations, equation solvers, and search algorithms that do things better than us humans, but only in a narrowly defined task. AGI is a type of intelligence that we have not yet achieved with computers as of yet.

The implications of these questions are fascinating. The answers to the first question will define how we would recognize intelligence and what we're aiming for with AGI. The answer to the second question is almost certainly yes, but much more is behind it than a simple yes/no answer. The emergence of an AGI that meets the answers to the first question would show the positive result of the second question. The answer to the third question is extremely hard to foresee, and the possibilities get extremely gnarly when coupled with the property of exponential growth. The actual result will most likely determine our future as a species. Heavy thoughts. We'll dig into the first question in this post and cover the other two in subsequent posts.

Tech Book Face Off: Gödel, Escher, Bach Vs. The Annotated Turing

Quite a while ago, I made a list of the best Steve Yegge posts, and one of those posts was his Ten Challenges post on ten recommended books that required thought and dedication to get everything out of them. One of those books was Gödel, Escher, Bach (henceforth referred to as GEB) by Douglas Hofstadter. It wouldn't be the last time Yegge talked about GEB, and it seems that this book had a big influence on his thinking. He certainly gave it glowing praise, and that convinced me to give it a go myself. It is not a book to be read lightly, so I finally made some time to read it and give it my full attention. I was not disappointed.

I tried to pair GEB with a book that attempted to tackle similar topics. You may think that would mean some other book that addresses the nature of intelligence, but I went for a different angle. A significant amount of GEB deals with Gödel's Incompleteness Theorem, and that theorem is closely related to the Church-Turing thesis on computability. I'm not sure where I heard about The Annotated Turing by Charles Petzold, but I thought it would be a good match for GEB. It turns out that Alan Turing's paper also has much to do with intelligence, both human and artificial, and both books stirred up all kinds of thoughts about the limits and extent of what intelligence is. With that, let's dig in to two incredibly ambitious books.


Gödel, Escher, Bach front coverVS.The Annotated Turing front cover