Search This Blog

Practicing Our Craft

The new year is nearly upon us, and you know what that means - New Year's resolutions. I didn't used to put much stock in resolutions, but for 2013 I resolved to start this blog and write a post every week. So far so good. Over that time I've talked a lot about the benefits of learning new things and practicing them to become a better programmer. I've realized that I spend much more time on the former than the latter, so this year I want to remedy that by spending a little less time studying and devoting that time to dedicated practice.

How will I actually do this practice? Software engineering is such a vast and complex field. Deciding what to practice can be paralyzing in and of itself, much less how to do it. When in doubt, head back to the fundamentals. I'll either be pulling out my old college algorithms book, or doing practice problems on different websites. As for how to do dedicated practice, there are a few guidelines that I think will help to get the most out of these practice sessions.

Stick to a routine. Practice won't be too useful if it's done haphazardly or inconsistently, and it certainly won't be dedicated without a routine. Like in weight lifting or playing a musical instrument, practicing consistently is probably the most important way to improve rapidly. Having a routine is a commitment, and with it, the practice is more likely to happen. It has served me well for these blog posts, and I expect it will do the same for programming practice. I'll start with a couple practice sessions a week to see what I can handle, and then see how things settle out.

Pick one thing. The purpose of practice is to learn something so well that it becomes second nature. To do that, you have to focus. That means picking one thing to focus on and practicing that one thing until you don't have to think about it anymore. Practice until you can do it while carrying on a conversation. Practice until you can think a few steps ahead of the code you're writing while doing it. Practice until it becomes harder not to do it. So what is 'it'? 'It' can be anything from a new language feature that you want to learn to a keyboard shortcut in your editor that you're trying to add to your repertoire. Whatever it is, make sure to focus on it exclusively to learn it faster. And exclusively doesn't mean for inordinate amounts of time, either. You can focus for short amounts of time before moving on to something else, but don't try to practice more than one thing at once or you'll slow yourself down.

Get rid of bad habits. We all have them. We should be aware of them. The trick is to get rid of them. The best way to get rid of a bad habit is to realize when you're doing it and stop it right then and there. Don't allow yourself to do it wrong just this time with the excuse that you'll do it better next time. Do it right this time. Check in your code right now before doing that refactoring. Write the test first this time. Take the time to write smaller functions with good names now, not later. These are only examples, but they are probably common examples. The point is to identify your bad habits and fix them right away. Above all, do not practice bad habits. You play like you practice, so practice how you want to play and do it well.

Practice in bursts. This advice is probably not what you think it is. I'm not talking about practicing for ten minutes, then taking a break, and then practicing for another ten minutes. I'm talking about practicing a very small, discrete skill over and over again, and then using it within a larger exercise. I learned this technique from my guitar teacher as 'bursting', and it is used a lot when learning musical instruments, typing, or any skill that requires developing a lot of muscle memory.

When learning to play a new guitar piece, I would practice a difficult measure or even a single chord transition a number of times, maybe ten or even twenty times in a row, and then play through the whole piece without stopping. If the difficult part came out easily, I would move on to practice another part of the piece. If it was still hard, or I hesitated, I would do another burst. You'd be surprised how quickly you can smooth out rough sections of a song with this technique. The same goes for learning difficult skills in programming, and like the principle of picking one thing, it could be any distinct, well-defined skill that needs practicing.

Make it harder to make it easier. Do you remember how hard it was to understand scoping rules for function parameters the first time you were learning them? I remember that being the first thing that really confused me when learning to program. It was all a big muddle at first. I also remember thinking function parameters were so easy by the time I was learning about class member scoping rules and method overloading in C++. Then templates made those things look easy by comparison as well. Doing something harder and pushing yourself beyond your previous limits makes things that used to seem hard now look easy.

Many sports have ways to intentionally make practice harder than the real game to take advantage of this principle. Have you ever tried to downhill ski on one ski? I mean physically remove one ski and then go down, leaving it at the top of the run. Yes, you still have to turn. You can't just bomb the run and hope for the best. This was a standard drill when I was on the ski team in high school, and we did it through slalom gates. Once you could ski on one ski, doing it with two was a piece of cake.

How about swinging a golf club with only your left hand? How about only your right hand? How about playing soccer or tennis with ankle weights? How about swimming laps with three suits on? These are all ways to make these sports more difficult so that real play is easier, and you are subsequently better. So the next time you think the problem you're working on is hard, try making it harder. The real problem might suddenly seem easy by comparison.

So that's the plan for the coming year - real practice to improve at programming faster. This set of principles is a nice, easy to manage regimen that should help make the most of that practice. You don't want to complicate things too much because you need to keep your mind on what you're practicing. Stick to a routine and pick one thing to focus on at a time. Sometimes that one thing will be a bad habit to break. Other times it will be a difficult concept or skill that needs to be practiced with bursting. And if something is not making sense, try moving past it to something harder. Trying to understand things at the next skill level may help everything fall into place.

What You Should Learn In College, But Will Have To (Probably) Do Yourself

Final exams are over, the semester has come to a close, and all of those lucky college students now get a month of R&R during winter break. I remember those times well, and I especially remember the relief after finishing out another set of challenging courses. I loved my college experience, both the mind-expanding scholastic activities and the exciting extracurricular activities. There is no doubt in my mind that I gained an incredible amount of knowledge and understanding from the time I spent in college, but in looking back over that time, I notice that there was one gaping hole in all of the engineering and computer science coursework I completed. Almost none of the courses even came close to teaching us how to effectively manage and execute real projects.

Now, you may be saying to yourself, "Well, duh! College isn't about doing real projects. It's about learning theory and how to apply that theory to contrived textbook problems." And I would agree, to a point. There is certainly a vast quantity of knowledge surrounding software engineering, a significant portion of which a good Computer Science curriculum should teach. But I also think college students should learn how to use that knowledge in the context of actual software projects, because let's face it, most college grads are going to go work for a company where they will be contributing to projects for the rest of their careers. Only a small subset of them will go through PhD programs and cycle back into academia as professors.

Come to think of it, professors spend most of their time on projects, too. They may be research projects instead of commercial projects, but that doesn't mean they wouldn't benefit from learning how to run projects before they need to do it on the job. Not adequately teaching students how to do software development is kind of like building a car without windows or a steering wheel. The car may have lots of nice features. It could have a good, powerful engine. It might be luxuriously comfortable. But without windows you won't be able to see where you're going, and without a steering wheel you'll have no control over how to get there, anyway.

How College Misses The Mark


I can't think of any good reason why colleges couldn't teach good software development practices along with all of the theory they cover on relational databases, algorithms, networks, compilers, and everything else. Development practices are at least as important for efficiently producing high-quality software, and they're certainly not hard concepts to learn. Although they are difficult to master. Maybe it's because the concepts are perceived as easy that colleges don't feel the need to teach them, but that is a terrible disservice to these future programmers.

If students were introduced to good software development practices early in their coursework, they would have a much better chance of developing good habits that will serve them well throughout their professional careers... and their college careers for that matter. From my own experience, university programs don't spend much, if any, time going over the practical aspects of developing software. Even those courses that have you do projects that take more than a couple of days to complete don't introduce good programming practices properly.

Those courses that also expect you to do more significant projects with a group of students aren't any better because the professors still don't give any instruction on how to manage a project within the context of a group. It's as if they expect everyone to either already know how it should be done from high school group work, or they think we'll all pick it up easily on the fly because it's so obvious. And let's face it, your grade depends on it, so that should be incentive enough to spontaneously learn it.

I must admit that I did have one excellent course that involved an extensive project with a team. It was an electrical engineering course, not a computer science course, but it was cross-listed with the computer science department. I don't know of a similar CS-only course for software development. Anyway, this course had the unassuming title of "Digital Engineering Laboratory" and it had the most credits of any lab course, weighing in at a hefty four credits. Most labs were only one or two credits. The goal of this lab was to implement a microprocessor from scratch of the team's own design. The processor could do whatever you wanted it to, but it had to work on a real FPGA for a demo at the end of the semester.

Let me tell you, four credits was not enough for this course. I spent more time on this course than my other three courses that semester, combined. I'm sure my four teammates did the same. Yet, this course was different from all of the other project-based courses. Even though it was a lab, there was a small classroom component to the course, and the professor spent most of the time going over practical design, development, and project management principles. The rest of the classroom time was spent going over progress reports and addressing any logistical issues we came up against.

All around, it was an excellent learning experience that came closer to real-world project execution than any other college course I took, and they had the right idea in how they structured the course. Integrating some instruction on managing projects with the execution of a full-scale project provided enough motivation to really pay attention to the design and development practices. If you didn't, it would be much harder to succeed. But there were still problems even with this exceptional course. For one, there wasn't enough time to properly cover everything you need to know to run a project well. For another, since it was a hardware design course, there was no mention of some of the best software design and development practices.

Critical Best Practices


A few weeks ago I wrote out a list of the best software development practices that I keep in mind as I'm writing code. The practices I'm talking about now are not the same as the ones from that list. While those practices were rules of thumb that I picked up over time and use to help guide the process of developing software in a general sense, the practices I'm talking about here are four concrete methods of developing software. They happen to be agile methods, but I'm not advocating them because they're agile. I'm advocating them because they are some of the best practical methods of developing software that I've found. I wish that I had learned them in at least one of my CS courses in college, or at least had been made aware of their existence and encouraged to look into them on my own.

The first method is to define requirements for your software project with user stories. No matter what size project you're working on, user stories provide an exceptionally powerful way to organize the requirements of the software, and they are flexible enough to be useful in an ad-hoc way for more informal single-developer projects or to be extended to meet the more stringent requirements of enterprise or safety-critical projects. If I had known about user stories in college, I would have been using them all the time as an organizational tool, even though most of the time college project requirements are handed to you instead of you coming up with them on your own.

The other three methods are intimately related, and when used together they become an extremely powerful way to develop software. The first is to use version control. Always. You are using version control, right? I don't think I need to justify its use here, what with the wide adoption of Git through GitHub and the general acceptance over the last decade of version control's crucial importance in nearly everything you read about software development. Yet I never heard so much as a whisper about it in college. I can't believe I didn't become aware of it until a couple years after I graduated. Don't make the same mistake. You need to learn this stuff.

The second method is test-driven development (TDD). Writing tests first and then writing the code to make those tests pass results in much cleaner, more well-designed code that has a much better chance of working quickly. Plus, it turns out that it's much easier to write the tests for the code you need to implement and then write the code. It was only recently that I really started to appreciate this benefit of TDD because it's so counter-intuitive. It does work, though. I find myself spending a lot less time staring at the screen contemplating how I'm going to implement the next feature, and more time making good progress because the problem I'm trying to solve is so much more well-defined when the tests are written first.

The combination of version control and TDD allows for the third method, refactoring, to be used with impunity. When you have tests to back up the functionality of your project when making functionally equivalent changes, and you have version control in place to back up every change made to the code base so that you can easily turn back time, cleaning up and optimizing your code becomes so much easier and more likely to actually get done. This trifecta of software development gives you the freedom and confidence to take your programming skills to a whole new level.

Hitting The Mark Yourself


During my university program, I missed out on learning these critical software development practices. It took years after graduating to learn and appreciate the importance of user stories, version control, TDD, and refactoring, and I'll continue learning and improving. I can only speak from my own experience. Other computer science programs, or even my own if taken today, could do a much better job covering these things, but if you are not learning them in college, you should take it upon yourself to learn them on your own.

Two good ways to do this would be to participate in an open source project (or start one) or do an internship at a company that practices them. Working on a project that practices good software development is an invaluable experience, and it will teach you things that college courses will overlook or do a poor job teaching you. Sometimes doing it is the only way to learn, but you also have to be conscious of what you're learning. It's entirely possible to work on a real-world project and not fully appreciate the software practices the rest of the team is using, so don't write off studying those practices, too. There are all kinds of great books, blogs, and online resources out there for learning good development practices. Supplement real-world experience with studying to get the most out of both, and don't assume that college will teach you everything. Take the initiative and make sure you learn what you need to know.

What Can Chess Teach Us About Programming?

Chess board


Similar to how it seems that many programmers play a musical instrument, particularly the guitar, it seems that many programmers love to play chess. Now that may be the case only because people in general like to play the guitar and play chess. But I think programmers especially like playing the guitar because it allows them to express their creativity, and they like playing chess because of their proclivity toward analytical problem solving.

There aren't many problems out there that are more complex and difficult than a game of chess (with Go possibly being one of them). Yet, programming is full of mind-bending problems that we have to overcome everyday, and so there are many parallels between chess and programming. We could certainly learn some things about programming from the strategies involved in playing and getting better at chess.

Phases


For starters, chess has three phases of the game: the opening, the middle game, and the ending. In the opening, both players follow a series of moves that have been played time and time again in thousands of previous games throughout history. Most of the advantages or disadvantages of each move have been studied extensively, and there are accepted lines of play for each side that will lead to slight advantages to one player or the other. If the players have studied openings extensively, the opening may last for twenty moves or more. Similarly in programming, when you start a new project, you will go through a known set of steps to setup the environment and lay the foundation for the rest of the project. Much of the initial setup will build a skeleton for the rest of the code to hang from. It gives the project structure, much like the opening moves in chess will build up a pawn structure to use as the pieces are developed and put into motion.

At some point one of the players will introduce a novelty - a move that takes the game out of established opening play - so that the players now have to rely on their own chess playing skills. This phase is the middle game, where strategy and tactics take over as each player grapples for advantages and attempts to maintain them through the rest of the game for a win. The middle game can be fraught with uncertainty, with countless options available on each move and few certain paths to victory. Tactical strikes can change the balance of the game quickly. The advantage can quickly change hands as attacks succeed or fail and pieces are exchanged.

The long middle game of a software project can have its fair share of uncertainty as well. Every design decision entails tradeoffs and compromises, and the final success of the project is largely unknown, much less what it will actually look like once all is said and done. There will be days where everything seems to be going great, other days where nothing seems to work at all, and that momentum can change in an instant. This is the time to celebrate small victories, attempt to keep morale up, and strive to maintain momentum and positive progress.

Back in the chess game: at some point enough pieces will have been removed from the board, and the position becomes more clear. The transition from the middle game to the ending is not as well defined as from the opening to the middle game, but at some point it becomes obvious that the end of the game is imminent. In this phase every move becomes critical, and the game can be won or lost because of a single pawn move at the wrong time or the precise path that the king takes across the board. Precision of execution is paramount. The same goes for software projects. At some point most of the planned features will have been added, and the bugs are getting progressively cleaned out of the system. It becomes clear that this software will actually ship, but the execution from here on out is critical. Everything has to line up precisely for the best possible outcome on release day, and the slightest mistake could make a huge difference in the success of the product.

Pattern Matching


Okay, the phases of the game showed some similarities to software projects in broad strokes, but there are a number of other more specific things that we can learn from the game of chess. At its heart, chess is a game of pattern matching, and that is how the masters are so good at playing. When they look at a chess board, they don't see two sets of sixteen separate pieces on individual black and white squares. They see combinations of interacting pieces controlling space on the board. They see a pawn structure that defines the game and shows which strategies will be appropriate to pursue. They can instantly memorize any given position and assess the strengths and weaknesses by recognizing common configurations of pieces so that they can spend their mental energy analyzing the best course of action.

If you've ever watched an expert programmer at work, you may be amazed at how quickly he (or she) can determine how a piece of code works and make necessary changes. This ability comes from the same pattern matching skills as the chess master, but the patterns are in the code. I'm not talking only about design patterns here. An expert programmer stops seeing individual keywords, variables, and operators, and instead he sees the structure of the code itself. He can recognize similar blocks of code that he's seen in the past and work with it at a higher level than just reading and manipulating individual symbols.

For the chess master, this pattern matching ability is useful beyond merely assessing a position. Being able to recognize more chess patterns will give you a better ability to calculate the best lines of play, and it will improve your horizon - how many moves ahead you can see. Strengthening this ability to concentrate on the position and calculate deeply in spite of what pressures the player is under is known in chess as developing mental toughness. That concept is perfectly appropriate to programming. As you gain more experience and expand your ability to see software patterns, you will be able to see larger and more complex transformations of code with less mental effort. You will be able to anticipate more potential problems and envision more promising solutions when writing code, all by improving your mental toughness.

To develop this skill in chess, you should do lots and lots of practice drills. There are entire books filled with positions where one player has an immediate tactical advantage over the other, and you are supposed to see the correct lines of play that capitalize on that advantage. You can also do all kinds of different drills with a few pieces to practice essential tactics like pinning, forking, skewering, and discovered attacks. Seeing these tactics will become more automatic as your pattern matching skills improve. There are also all kinds of ways to improve your pattern matching skills in programming. In particular, studying algorithms and data structures, and practicing on programming puzzle websites like Project Euler or Programming Praxis will greatly improve these skills.

Strategy And Tactics


Much of master level chess revolves around the tension between strategy and tactics. Strategy involves the long term advantage you can leverage from things like the pawn structure and the control of space and critical squares on the board. Tactics instead consist of the short term execution of maneuvers that result in a decisive material advantage. Skewering your opponent's king to trade a rook for a queen or forking the king and bishop with your knight could lead to an overwhelming advantage of force, if you can hold on to it.

The opening is where strategies are first put into place, and most of the opening theory is based on gaining a strategic advantage, assuming the opening lines are played correctly by both players. The middle game is the land of tactics, and this is partly why the balance of the game can change so quickly during this phase. Most novice players make the mistake of focusing too heavily on memorizing different openings, when they should really be studying tactics. Even though strategy depends on deep chess knowledge, most games at the amateur and even the master level are primarily determined by tactics.

When amateurs look at grandmaster games, they will read an awful lot of discussion about subtle positional advantages and strategic play. What amateurs seem to forget is that to reach that level of play, grandmasters had to be absolutely excellent at tactics. They have gotten so good at tactics that for the most part, they have taken tactics out of the game. At least, that's what it looks like on the surface. If you look at the alternate lines of play in a grandmaster game, they are littered with devastating tactics narrowly avoided on both sides. The point is that grandmasters are exceptionally skilled in both strategy and tactics, no matter whether they are described as positional players or tacticians.

In programming creating new code can be thought of as strategic play and working with legacy code can be equated with tactical play. When writing new code, you must think longer term about all of the implications of the design you implement. How you structure the code could have an impact on the project for years down the road because it establishes a way of doing something that can become hard to change as more code is added to the original architecture. On the other hand, working with legacy code entails making surgical changes to existing code, and small changes can be decisive in fixing broken code or adding new features. Refactoring in particular can be thought of as a known set of tactics that can improve legacy code with small, well-defined code changes.

As with strategic or tactical grandmasters, expert programmers may have a preference of creating new code or working with legacy code, but they are excellent at both tasks. The defining characteristic of experts is not whether they are better at building something new or fixing something old, but that they have exceedingly good judgement about programming in general. Just as a grandmaster will have a better idea of when to develop her position and when to go on the attack, an expert programmer will know when it is better to write their own code or use a library and what the best way to debug a particular piece of code would be. Experts have a general sense of good judgement that comes from years of practice, experience, and hard work developing all of their skills. Their preferences for one particular way of doing things tend to show only when the trade-offs of choosing one way or the other are insignificant.

Beauty


It only takes a short time learning chess before you begin to realize that the game is filled with beauty. You can hardly find any book on chess that doesn't mention it in one way or another, and commentary on famous chess games is filled with acknowledgements of beautiful positions or exchanges or checkmates. The more you learn about the game, the more you can appreciate the beauty that unfolds from the interaction of the pieces and how they can work together when the game is played well. One of my favorite types of checkmates is the pure mate, where every square around the mated king is either attacked or occupied only once. Being able to achieve something so perfect in the course of a game with nearly endless possibilities certainly elevates the game to a work of art in the hands of the masters.

The best programmers strive for beauty in code as well. For them it is not enough to merely create functional, productive software. They strive to transcend normal, everyday code to create masterpieces that solve complex problems in clear and elegant ways. For them programming is not a job or a hobby, but a labor of love that they pursue with a deep passion. Of all the things chess can teach us about programming, this one becomes the most obvious with time. Bringing order to complexity is a thing of beauty that is deeply satisfying to achieve.

Oh, How To Learn The Things A Software Engineer Can Know

Last week I wrote up a list of an overwhelming number of things that a software engineer could learn to become more effective at designing and developing software. Some things were more important than others, and you don't have to learn everything to be good at what you do. It was a buffet of choices where every new thing you tried had the potential to expand your tastes and satisfy your hunger for helpful skills.

With such a huge array of potential knowledge, how do we go about capturing it, becoming proficient in it, and putting it to good use? Every programmer has their own preferred method of gaining new programming knowledge, and different things work better for different people, so I'm not going to push one particular method. Well, not too much anyway. Instead, I'm going to attempt to show the plethora of options available for improving your 1337 programming skillz. Once again, this is probably not a complete list.

The Old Fashioned Way


You could start off learning a broad spectrum of software engineering knowledge by going to college. Coupling a Computer Science degree with a Mathematics degree will cover a lot of ground in four or five years. You can also continue on for a Masters or PhD to go deeper and deeper into the fields that you're interested in. College can be great for providing direction and focus in learning, if you have the motivation and don't let too much partying go to your head. Being surrounded by a large group of other smart, motivated people can be encouraging and stimulating. College courses also have the advantage of a fairly well-packaged set of resources and a discernible learning path for the subject areas you decide to pursue.

There are trade-offs, though. College programs are often short on experience, and unless you go for internships, (recommended) you won't have a very good idea of how software engineering is done in the real world. It's also expensive, both in time and money, and it isn't for everyone. Even for those that do go to college, and go on to Master's and PhD programs, it will (or at least should) eventually end. Then staying up on current technology becomes an individual enterprise. Even right out of college, grads don't know everything, so what else can we do to keep learning?

There's always books ... lots of books. If you haven't noticed, this is my currently preferred and primary method of learning more about pretty much anything. I love books. They give an in depth treatment of any given subject in a nice, manageable package that can be easily reviewed, referenced, and now with ebooks, searched for vast quantities of information. There are books on nearly any subject you can think of, and I've had good luck finding high quality books ever since Amazon reviews became ubiquitous.

Even in college I quite often relied on the textbooks as much or more than the professors, but books can't teach you everything. They are an individual pastime that is distinctly lacking in connections to the programming community as well as being short on giving you real-world experience. Beyond that, most programming books can quickly become obsolete as the software they cover continues its eternal progression, so books at least need to be supplemented with more up-to-date and connected ways of learning.

The Newfangled Way


To get connected with a programming community and learn new things at the same time, you can participate in online communities like Hacker News, reddit.com/r/programming, IRC, and LinkedIn groups. You'll be aware of current trends, see new developments as they happen, and be able to join discussions and debates with other programmers. You'll also get a better idea of who's who in the programming world and be able to see first hand how trends are developed and promoted.

You can also participate in communities that focus on teaching and learning in a more permanent format, like Stackoverflow.com or Quora.com. Like most other online communities, they have a gamification aspect where you gain reputation as you ask good questions and provide good answers. But unlike HN, reddit, etc., the questions and answers are easily searchable and available to newcomers so that your contributions will potentially have a larger impact over time, and you can find information on specific topics that was already covered months or years in the past.

Once you've spent some time in some of these communities, you'll likely find some interesting blogs to follow. That's another great way to learn more about different areas of programming, and if you read some blogs from their early beginnings to the present, you'll be able to see how other programmers have developed throughout their careers.

You may even get the urge to start your own blog, and put your own experiences online. Then, instead of only receiving new knowledge, you can develop an ability to teach others what you know. In addition to contributing more to the community, you also gain a much deeper understanding of the topics you're trying to write about. Knowing something is one thing, doing it is another, and teaching it is still another. To effectively teach anything, you have to organize your thoughts in new ways and spend more time wringing out the misconceptions and uncertainty that you may have on the subject. It's harder than you think, and you'd be surprised how much you don't know about things that you thought you could do in your sleep.

However, reading and writing about software engineering can only get you so far. At some point you're going to want to get your hands dirty and do some real programming. Well, there's plenty of resources for that, too.

The Hands-On Way


To get some real programming practice in, you could go to some of the excellent programming puzzle sites for ideas. There's sites like Project Euler, Programming Praxis, Prolog Problems, Code Golf on StackExchange, Python Challenge, and Ruby Quiz to name just a few. Solving programming puzzles is a great way to practice and get better at the fundamentals of programming, or to get ideas for small exercises that you can do to get more familiar with a new language you're learning.

Speaking of new languages, learning another language is an excellent way to learn a lot about new areas of software engineering, especially if that language lives primarily in an environment that you're not familiar with. To learn C#, you'll have to learn a lot about the Windows programming environment. Learning Objective-C will lead you into MacOS and iOS programming. Learning Prolog would be a useless undertaking without also learning a lot about AI. Erlang will provide the impetus to learn more about concurrency and parallel computing. And Lisp will most likely bring you up close and personal with Emacs.

If you're starting out with a new language, there are also a number of online resources out there to help you with the basics, especially if you're fairly new to programming and it's a popular language. Sites like RubyMonk.com, Scratch.mit.edu, and W3Schools.com can get you up and running with a new language through a fun, interactive experience.

While solving puzzles and learning new languages will help you a lot, we still haven't covered great ways to get real-world experience doing larger projects. For that experience, one of the best ways to learn outside of having a job in software engineering, is to contribute to an open source project. Joining an open source project will not only help you learn how to work within a larger software team on a more significant project, but you will also be making a meaningful contribution to the community by helping out on a software project that may be used by thousands of people.

Working on open source software will also give you a better idea of how to write good, high quality code, at least if you happen to be reading good, high quality code. But there's a good chance that you will be, especially if you're looking at the standard libraries for your favorite language or the more popular frameworks and projects on GitHub - the go-to site for finding good open source projects to contribute to.

If you don't want to join an already active project, you can always start one of your own. Coming up with an idea for a new software project and following it through design, development, and release is a great way to develop your programming knowledge, and there are plenty of important problems out there yet to be solved with a good piece of software. You're guaranteed to learn a lot, and the project may even take on a life of its own and take you to places you never imagined you could go.

These projects can range from web design to mobile apps, games, and even embedded products. No matter what kind of programming you want to learn, there's an affordable way to do what you want to do. The barriers to entry have never been lower. Whether its free web hosting at sites like Heroku, or inexpensive embedded kits like Arduino, Raspberry Pi, and Tiva Launchpads, There are all kinds of interesting options for pursuing your DIY urges. I'm especially interested in checking out Make: magazine for all kinds of embedded software project ideas, although I'm afraid I wouldn't be able to resist overdoing it and it would consume all of my time. Maybe I need to wait until my kids are old enough to enjoy those projects with me, and we can learn together. It shouldn't be long now.

Oh, Is That All?


With so many options available, how does one choose what to do? Like the options for what to learn to improve as a software engineer, the options for how to learn it can be overwhelming. It is largely a personal choice, and what works well for some people will be tedious or ineffective for others. For example, I am quite happy reading books and working out programming puzzles, but I can't stand watching instructional videos or screen casts. Another programmer may have trouble concentrating on a book but gets a lot out of video lectures or debating in online forums. The point is to figure out how you are most effective at learning and focus on that. Make the most of the time you have.

I have one piece of advice, though. Try to find a good balance between studying, practicing, and participating. If you spend too much time on any one of those things, it can start to become an end unto itself. That's okay if your goal is to read tons of books or build up a lot of reputation on Hacker News or solve as many puzzles as you can. If you enjoy what you're doing, that's great, but be honest with yourself about what your goals are. If your end goal is to improve as a programmer, or more specifically, learn what you need to learn to accomplish whatever it is you want to do with programming, you're going to make faster progress if you strike the right balance. I'd love to tell you what that is, but you're going to have to discover it on your own.

Oh, The Things You'll Learn As A Software Engineer


The field of software engineering is vast. The amount of knowledge that can prove useful for any given problem is immense. And the paths to attaining enlightenment are numerous. Looking up at this towering mountain of knowledge and deciding how to scale it can be more than a little bit overwhelming. Whether you've recently begun the journey with only the basics behind you, or you've been trekking along for decades with a deep store of accumulated knowledge, you still have an incredible amount of stuff that you could learn ahead of you.

That is the beauty of software engineering. There is never a shortage of new and challenging things to learn, and that new-found knowledge can be applied to interesting problems. Sometimes you won't even know that a particular field of study holds the solution to your problem until you've cracked it open and explored its depths.

It can be useful to have a broad overview of all of the subjects that contribute to software engineering, to have some idea of what could be beneficial to study next. I'll attempt to split things up into coherent categories, but the progression of these categories does not imply a sequential order in which these subjects should be learned. In fact, I don't even claim that all of these things must be learned to be a successful programmer, or that this set of topics is complete. Such is the nature of the constantly changing field of software engineering. This set of topics couldn't possibly be either necessary or sufficient, but it should give a good idea of overall scope. With that in mind, let's survey the landscape of this mountain of knowledge we call software engineering, starting with the foundation.

The Foundation


Surprisingly, the basic knowledge for learning to program well does not come from learning programming languages or theory. It comes, like so many things, from the fundamentals of reading, writing, and mathematics that we all learn as children. They provide the foundation on which to build all the other programming knowledge, both directly and indirectly.

Reading is an integral part of learning everything about programming, from textbooks to technical manuals to documentation, but learning to read well provides deeper and more valuable skills. Knowing how to understand and follow instructions, how to analyze and think critically, and how to research topics that you don't understand are all important skills in programming that improve as your reading ability increases.

Writing is also an invaluable skill for programming. You will not only be writing code, but also documentation, requirements in one form or another, and more informal reports and explanations of software features, bugs, static, planning, etc. Writing is crucial because a lot of communication is done through the written word, and the better you can write, the better you will be understood. You will also be better able to express your ideas in writing, and at a deeper level, that is exactly what you are doing when writing code that will be executed by a compiler or interpreter, but read and understood by fellow programmers.

Mathematics is most directly applicable to programming in the form of algebra, and for certain types of programming, geometry. I think a lot of people mistakenly leave the connection between programming and mathematics at this shallow level and either enthusiastically agree with it or vehemently oppose it, depending on how good they feel they are at math. But the connection runs much deeper than whether programs tend to look like algebraic equations. Learning mathematics will teach you logic, reasoning, abstract thinking, and problem solving skills that will be incredibly useful in programming. After all, a large part of programming is solving problems in a logical way as efficiently as possible.

More Mathematics


Beyond the basic mathematics of algebra and geometry, many other fields of mathematics can prove quite useful for programmers. Probability and Statistics play an important role in all kinds of data analysis as well as helping you understand your users in the aggregate. Numerical Methods will provide plenty of ways to do complex calculations, approximations, and estimations on a computer with attention to both accuracy and efficiency. Graph Theory is probably the most important higher level mathematics field because so many problems in programming can be understood and solved with graphs. And Discrete Mathematics encompasses a whole set of topics that are directly applicable to programming, including Logic Theory, Number Theory, Set Theory, Algorithmic Complexity Analysis, and Finite-State Automata.

Then we start transitioning from more Mathematics-centric topics to more Computer Science-centric topics. DSP (Digital Signal Processing) deals with the handling and analysis of time-domain and frequency-domain data. Control Systems deals with how to provide stimulus to some target based on feedback measured from that target in order to make it do something useful. Neural Networks deals with how to setup a system of small interconnected memory units that you can then train to respond in a certain way to different kinds of stimuli.

Now we're getting firmly into Computer Science territory, and that means I should bring up Data Structures and Algorithms - the basic programming tools that every programmer should know. You won't get far as a programmer without knowing about arrays and hashes, or understanding sorting and searching. Even though the basics are required knowledge, these topics go way beyond that, and there is a wealth of knowledge for programmers of every level here.

The more advanced topics of Artificial Intelligence and Machine Learning round out the set of Mathematics and Computer Science topics that are useful for a programmer to know, but are not directly about writing programs. Before we do get to programming itself, there is one more area to examine.

Under The Hood


Every good craftsman understands his tools, and programming is no different. A great programmer will have a deep knowledge of the central tool of his trade - the processor executing the code. Having a working knowledge of computer architecture will give you great insights into how code is actually executed on the metal. Microprocessor designers have all kinds of tricks that they use in a valiant attempt to make your code run faster: pipelining, branch prediction, out-of-order execution, register renaming, caching, trace buffers, prefetching, virtual memory, and many others.

You could also go even deeper into digital logic design and semiconductor devices, but that would be purely to satisfy your own curiosity. At that depth, you'll be pretty far removed from code execution. However, you should learn the language of the processor, or at least the closest reasonable thing to it - assembly language. Knowing some assembly language will give you a greater appreciation for what code actually looks like when it's executed by a processor, and it might even help you fix some especially elusive bugs if you find yourself in a situation where you don't have the source code and have to step through assembly instead.

While the processor is critically important, it doesn't live in a vacuum. The surrounding system is also important to understand. The memory hierarchy, disk subsystems, and peripheral buses all play a role in programming, and even though programming languages do their best to abstract these things away, knowing that they exist and how they impact performance will help you become a better programmer.

Now that multi-core processors are pretty much standard, it is also becoming more important than ever to understand parallel processor systems and concurrency. Part of that involves learning about memory models, and even though they quickly become mind-numbingly complex, you should at least be aware of the basics for parallel programming.

Other topics that make up the infrastructure of programming include a lot of intricate software that lies between the processor and high level software applications. This software includes the operating system, compilers and interpreters, databases, and networking. These are all deep subjects, and all worth knowing better than you do.

The Core


After all of that, we finally get to actually programming. You'll need to learn at least one programming language, of course. The more languages you learn, the better you'll understand the world of programming. To become more effective, you'll also learn other libraries, especially the standard library for your programming language of choice, as well as frameworks for building applications on different platforms. You will likely also pick up knowledge on APIs (Application Programming Interfaces) for various software services available on the internet.

To be a more efficient programmer, you'll need to become proficient in a number of other tools such as a text editor or IDE (Integrated Development Environment), bug tracker, version control system, web browser, and search engine (for finding all of the information you've forgotten). Those are just the basic programmer's tools, though. There are as many programming tools as there are programmers, and you'll pick up a bunch more and maybe even build your own over time.

As you get deeper into the bowels of programming, you'll find that you need to learn more about the surrounding environment. Security quickly becomes an issue that you need to learn well. Practical operating system knowledge, not just the theory of memory management and file systems, but the actual functional knowledge of the operating system you're developing on and developing for, will become increasingly important. System administration and server maintenance will likely come into play as well.

Beyond Coding


The learning doesn't stop with programming languages and coding tools. There are all kinds of methods and processes that you can learn to assist in building software, and some are more helpful than others. There's UML (Unified Modeling Language) diagramming, unit testing, TDD (Test-Driven Development), agile methods, refactoring, code construction advice, user interface design, and various forms of requirements definition. Of those I would put unit testing and refactoring near the top of the list, but your circumstances may dictate a different ranking. And then there's project management, which is another field entirely with many philosophies and strongly held opinions.

Finally, there is the domain specific knowledge that you'll acquire for the specific type of programming that you find yourself doing. This type of knowledge is so unique and varied that it defies enumeration, but examples include web design, embedded programming, scientific programming, modeling, tool building, mobile application development, and game programming.

Stepping Back To Take It All In


Now that is certainly an incredible amount of knowledge to try to acquire. Most of these topics could take years of study in and of themselves to even begin to master. If you are feeling a bit overwhelmed, you are surely in good company. Rest assured that no one could maintain a deep and lasting knowledge of all of these things.

The good news is that you don't have to. Part of being an effective programmer is knowing what you need to learn now and what can be put off until later, sometimes indefinitely. And once you have a good foundation, a programming language or two under your belt, and productive habits in at least one programming environment, you can pick off other topics as they become necessary (or desirable) to learn. The important thing is to keep chipping away at new things. You can gain a cursory understanding of any of these topics in a matter of days or sometimes hours, and then decide whether it's worth it to plunge deeper into the topic.

That still leaves the question of how to crack into the knowledge that you decide to pursue, but I'll leave that until next week. Regardless of how the knowledge is attained, it's amazing that there is so much to be had, and it's all intertwined under the canopy of software engineering. I, for one, can't wait to learn something new. The only real problem is choosing what to do next.

The Quandary of Working With Legacy Code

I have a dilemma. That dilemma involves choosing what to do with the legacy code I'm working on. I have a pretty loose definition of legacy code - basically any code that has been checked into the repository qualifies. If it's been committed, then it becomes someone's responsibility to maintain it, and that makes it legacy code for all intents and purposes. In my case, that maintainer is me alone. At the company I work for code gets split pretty cleanly along microprocessor and microcontroller boundaries, and the code communicates through a variety of serial interfaces. That's not what defines this situation, though, and since dealings with legacy code has as many contexts as there are code bases, knowing the particulars of this situation is important for understanding the dilemma.

This particular code is a small web server that sits on an embedded processor and uses an on-board WiFi chip to connect to a client and serve a small set of dynamic web pages. Since the code base is only about 6 KLOC, it's easily manageable as a side project for one person. Most of the original C code came from TI's example web server app, and I tore out the functionality we didn't need and added other functionality that we did need. The issue I'm having now is deciding whether or not to do a more extensive refactoring of this code, and possibly convert it to a C++ class architecture in the process.

What, Exactly, Is The Problem Here?


There are a number of problems with the code at a number of levels that make me want to do this refactoring, so let's run through them briefly. First, there is no consistent naming convention. Sometimes Hungarian Notation is used, and sometimes not. When it is used, it's not the good kind of Apps Hungarian Notation, but the obnoxious kind of Systems Hungarian Notation. And even then it's only used partially, with numerous variables prefixed only with a 'u' for unsigned, but no other type definition. Function names are ridiculously long, like HttpDynamicHandler_GetBasicUnitInfo(). Many variable names are nearly as long, and end up being longer after the huge chains of struct member accesses are written out.

Then the code and comment formatting is haphazard with many variations of tabs and spaces and block comments and line comments with most commenting restating what the code does. Type declarations are totally inconsistent with such things as int, uint32, and unsigned long used for the same variable at different levels of function calls, or sometimes using typedef struct {...} <name> and other times using struct <name> {...} for struct definitions. This makes the variable typing look more than a little disorganized.

On top of the long names, the functions themselves are mostly long, untestable messes of for loops, while loops, and if-else chains running on for hundreds of lines. It is readily apparent that most of those useless comments are marking suitable places to break the code up into shorter, more manageable functions. Unit testing is further complicated by many static functions that restrict access to calling those functions from outside their compilation unit.

Finally, the overall architecture of the code is somewhat disorganized. After drawing up a quick UML class diagram and substituting structs and files for what would otherwise be classes, it became pretty obvious that some files should be broken up into smaller, more focused units, and some reorganization would make the architecture much cleaner and more maintainable. If the code was also converted to C++, it would easily transfer to classes and many of the long names that were carrying the responsibility for defining the purpose of functions would be cleaned up in the process. I'm not saying that a conversion to C++ is necessary to make this code clean, but it was clearly written in a way that is more in line with the class structure of C++ instead of the procedural structure of C. The conversion would be quite natural.

Well, Then, What To Do About It?


For any programmer that's worked with legacy code, these problems are very familiar. Maintaining consistency is hard, and over time functions seem to accrete more and more logic until they become unbearable rat's nests of code. Even though I try to leave things better than I found them, and every time I add features or fix bugs in this code I try to make it a little bit better, that won't be enough to even begin to address the problems with this code.

To put things in perspective, the main code base that I'm responsible for was another example of code with all of these problems, and it's about five times more code. I didn't hesitate to refactor all of that code and convert it to C++, so why would I be second guessing that choice this time around when it amounts to a much smaller task?

Every situation is different, and it is important to weigh the pros and cons of such an arduous decision as transforming a code base, no matter how small. From my ranting about the poor quality of the code, you may think that only good things could come from paying down this technical debt, but I'm not so sure.

The Pros And Cons of Refactoring


The biggest thing this code base has going for it right now is that it is working. By that I don't mean that I'm afraid to break something. Quite the opposite, in fact. Even though there are currently no unit tests, or automated tests of any kind really, the system is so focused and self-contained in what it does that a simple manual test is all that's needed to see if it's working. All I have to do is access the embedded device's IP address from a browser and make sure the web page graphs the real-time data it's acquiring correctly.

No, the advantage of the code already working is that nothing else has to be done to get it working. Most of the code hardly changed while I was adding and removing features, and the areas that need to change to add more features are well defined and quarantined. Even though the code is a mess, and it offends me to my programmer's soul when I have to look at it, it is fairly easy to change what I need to and move on.

But I have had to look at that dirty code a lot lately, and every time I try to ignore the mess, the pro-refactoring part of my brain cries out in agony. Cleaning up the code would make it so much more liveable, and that is worth something. I have a couple of young kids at home, and some days it seems like they make it their mission to destroy the house Tasmanian Devil-style. After my wife and I have finally gotten them to bed, we rarely have the energy to clean the house, too, and the mess will live on until the weekend. It shifts and changes like some slow-moving monster that's consuming every square inch of floor space in the house.

Looking at that kind of mess is mentally taxing, and it quite literally exhausts you. When the weekend finally rolls around, and if we happen to be home for a couple hours, we can buckle down and put everything back in its place. The feeling of a clean house after all of that chaos is like a dark cloud has been lifted from my mind, and it becomes much easier to think and more pleasant to be in the house. Cleaning up a mess of a code base can give you much the same feeling with the added benefit that it doesn't so easily revert to its chaotic state after another rousing day of playing princesses and soldiers (don't ask, kids are creative).

Another benefit of refactoring the code is that it would become much more testable, so unit testing could be drastically improved for much better peace-of-mind. This benefit is slightly circular because it would be a good idea to implement some amount of automated testing before doing the more extensive refactoring to make sure that all is still well with the code. The first tests would likely be integration tests because unit tests are currently so difficult to implement, but some amount of testing should be put in place to enable safer refactoring. Then more testing could be added in the form of unit tests as functions were split up and put into classes with the relevant data.

That sounds like a lot of work, and it probably is. That begs the question of whether or not those benefits are worth the cost, and that is not at all clear to me in this case. With the other code base I maintain, it was obvious that I would be living with it for a long time since I started with it on a previous product, was able to migrate it to the current product we're working on, and plan to use it again on the next major product we do. I'm getting a lot of mileage out of the work I put into that code to clean it up, and I knew that I would so it was clearly worth it before I started.

With this embedded web server code, it's possible that it will be a one-off application. I'm not sure yet, but if it is, then it may not be worth putting in all of that extra work for it to only sit in a microcontroller on the daughter board of this one product. That time and effort may be better spent elsewhere.

Now You See My Dilemma


This quandary of working with legacy code must be as common as sand on a beach. The code is a disorganized mess that could be easily improved with some concerted effort, but it's currently working. If the code still has a long life ahead of it, it may be worth it to clean it up and make it more liveable. Making it testable and adding automated tests has clear benefits, but what if all of that infrastructure and testing was put in place and never used? And then there's always the intangible benefit of having a well-engineered piece of software, the practice and learning that took place while building it, and the satisfaction that comes with finishing it.

Do the benefits of refactoring outweigh the costs in this situation? Can you even know with any certainty? I'm not at all sure, and I don't have to worry about the impact on other developers in this case. But I'm itching to rename that HttpDynamicHandler_GetBasicUnitInfo() function to CDynamicRequest::GetBasicUnitInfo() anyway.

Tech Book Face Off: The Ruby Programming Language Vs. Eloquent Ruby

I feel like I'm coming a little late to this party. The excitement over Ruby seems to have peaked years ago, and now all the talk is about things like Scala and Node.js. I don't mind, though. I figure it's never too late to learn a new language, especially one as beautiful as Ruby. Besides, Ruby is in very active development, with the 2.0 version of the language having been released this February, and a lively and helpful community to support it. I would say that if you've been putting off learning Ruby, now is a great time to finally take the plunge, and here are two books to help you on your way.

The Ruby Programming Language front cover VS. Eloquent Ruby front cover

The Ruby Programming Language


This book was written by the same David Flanagan that wrote the excellent JavaScript: The Definitive Guide that I reviewed months ago, and it was co-authored by the inventor of Ruby, Yukihiro "Matz" Matsumoto. It was written in a similar no-frills, straight-to-the-point style that I once again enjoyed and appreciated immensely. When learning the ropes in a new programming language, I want to see a well organized presentation of the features with clear, concise examples and crisp, direct explanations of those features. No games or gimics, please; just the facts. This book delivers exactly to those expectations.

Overall, I would say the book was very easy to read and understand. That could just as easily be said about the Ruby language itself, of course. The flexible syntax and the ability to write programs that read more like natural language than most other programming languages is really appealing. While playing around with solving some basic algorithmic problems in Ruby, I was impressed with how easy it was to express the solutions in the language in nearly the same way that I was thinking about solving them in my head. And Flanagan and Matz did a good job of showing all of the language features in a way that I could pick up quickly and use right away. They methodically explained all of the features and concepts in a nice, logical order.

That is not to say that there weren't a few rough spots. Things got a bit hairy with enumerators and external iterators, and then again with class variables and class instance variables. This was only partially because these concepts didn't click for me right away. After backing up and reviewing those sections, I understood the syntax and what was going on well enough. The main issue with enumerators is that I don't really see when you would want to use them, but I suppose being aware that they exist is the important thing at this point. Beyond that it's a case of "you'll know it when you need it."

With class variables and class instance variables the problem was more of knowing when to use one instead of the other, and Flanagan and Matz didn't get into that much at all. It would have been out of character with the rest of the book, but that's alright because the subject of when and how to use Ruby's language features was pretty much the next book's reason for being. As for The Ruby Programming Language, it was a great introduction and overview of Ruby for an experienced programmer. I highly recommend it to any programmer ready to learn a new and fun language.

Eloquent Ruby


Russ Olsen goes in a completely different direction with Eloquent Ruby. I'm not sure if you would be able to learn Ruby if this book was your only resource. At the very least you would need to refer to the documentation quite a bit when you were starting out. But this book will teach you how to use Ruby to solve real problems and why you would write programs certain ways to be more effective. In short Olsen teaches you how to write idiomatic Ruby.

I thoroughly enjoyed reading this book. I don't think I've had this much fun reading a programming language book since, well, ever. It was like reading The Pragmatic Programmer, but for a programming language instead of general programming practices and processes. Olsen was conversational and engaging, and he really helped me understand how to write good Ruby code. He covered everything from the use of different control structures to writing specs, the use of class instance variables, the various uses of method_missing, creating self-modifying classes, and implementing DSLs (domain-specific languages).

The book is packed with all kinds of useful information in a nice, readable format. Olsen starts out with more basic, general concepts like code formatting and comment style and moves progressively into more complex topics, culminating in a series of excellent chapters on metaprogramming and DSLs. Each chapter addresses one self-contained topic about Ruby programming and includes sections on how to avoid common errors and pitfalls, and what real implementations of the topic under discussion look like "in the wild." This format ends up working really well, and I found the pace extremely easy to follow. It was very understandable, and I learned a ton.

I do have a few quibbles about parts of the book, though. Sometimes his reasons for things like commenting lightly or writing short methods seemed a little weak. It's not that I disagreed with his recommendations. In fact, I mostly agree with him, especially about restricting comments and letting the code speak for itself. But I thought he drew out his arguments a bit too long and included points that ended up sounding like, "You should do it this way because that's the way the Ruby community does it." I found myself disagreeing with some these minor points even though I agreed with the overall premise, and that was distracting. His arguments would have been stronger if he had tightened them up a bit and left out the weaker claims.

Another minor annoyance was the footnotes. I really don't understand why he felt the need to include these when they were nearly entirely useless to the reader. Every time I jumped to a footnote hoping for a little extra insight, and instead was confronted with flippant comments like "Try as we might" or "Yet," (seriously!) I was reminded that I really shouldn't be wasting my time with these footnotes. I still read them all because I couldn't help myself, but I guarantee that none of them were essential. Sure, there were a few clarifying points, but if they were so important to include, they should have been integrated into the text instead of cordoned off as footnotes. However, I didn't see any of them as critical, and you're really not missing anything by skipping them. Trust me, I read them so you don't have to.

Thankfully, those two minor drawbacks can be easily ignored, and the book doesn't really suffer for them. There is so much good material in there that I highly recommend Eloquent Ruby to every Rubyist. It will help take your programming to the next level, and give you plenty of ideas for how to write better Ruby code.

Ruby: The Language


So what about the Ruby language itself? I have to say that it is great fun to program in it. For someone who has spent more than a decade writing mostly in C++, writing in Ruby gave me the distinct feeling of being set free. It also pleasantly reminded me of my early programming experiences with Logo with many moments of youthful excitement and awe - as in, "wow, you mean you can really do that? Awesome!"

I'd like to do a rundown of some of the basic features of Ruby compared to C++, similar to what I did in my JavaScript book review, to show you how Ruby compresses code. Let's start out again with a few simple variable declarations in C++:
int samples[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
int sum = 0;
double mean = 0.0;
And the same declarations in Ruby:
samples = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
sum = 0;
mean = 0.0;
Nice! Ruby doesn't even need the 'var' keyword in its variable declarations, like JavaScript does. On a variable assignment, it searches for the variable symbol, and if it doesn't find it, Ruby conjures it into existence right there. So easy.

Now let's go a bit further and do the calculations hinted at by those variable names. First in C++:
sz = sizeof(samples)/sizeof(samples[0]);
for(int i = 0; i < sz; i++) {
  sum += samples[i];
}
mean = sum/static_cast<float>(sz);
And then in Ruby:
sum = samples.inject(:+)
mean = sum/samples.size.to_f
Seriously, that is not even funny. Look at how clean that is! You can actually inject an operator into a collection and it just works. 

Alright, let's say you want to create a quick object to hold some data on your pets. In C++ you'd have to at least create a struct and instantiate it. That would look something like this:
struct Pet {
  string name;
  string type;
  string breed;
  int age;
  double weight;
}

Pet myPet = {"Twitch", "cat", "Siamese", 10, 8.4};
And then there's Ruby:
myPet = {
  name: "Twitch", 
  type: "cat", 
  breed: "Siamese", 
  age: 10, 
  weight: 8.4
}
This isn't an object literal like it is in JavaScript. It's actually a hash, but since objects are implemented as hashes in JavaScript, this is basically the same thing in Ruby. Now let's say we wanted to make the pet more permanent as a class. In C++ you might do this:
class Pet {
private:
  string _name;
  string _type;
  string _breed;
  int _age;
  double _weight;
public:
  Pet(string name, string type, string breed, 
      int age, double weight) {
    _name = name;
    _type = type;
    _breed = breed;
    _age = age;
    _weight = weight;
  }
}

Pet myPet = new Pet("Twitch", "cat", "Siamese", 10, 8.4);
You might want to include setter and getter methods for any of the members (class variables) that you'd want to change later, but I'll omit those for brevity's sake. I'm also not including any error checking code that would be required, like making sure the age and weight are within reasonable bounds. Now here's the equivalent Ruby:

class Pet
  def initialize(name, type, breed, age, weight)
    @name = name
    @type = type

    @breed = breed
    @age = age
    @weight = weight
  end
end
myPet = Pet.new("Twitch", "cat", "Siamese", 10, 8.4);
The '@' symbol marks a variable as an instance variable, and they come into being on the spot, just like other variables do. The admittedly small amount of Ruby I have shown here is fairly comparable to JavaScript, but as you get further into Ruby, you find that it goes well beyond JavaScript in its ability to express programs cleanly and compactly, and C++ is left in the dust. Yes, C++ definitely has its uses, and dynamic languages can't hope to compete with it on speed. But Ruby has an enjoyment factor in its expressiveness that clearly outshines C++.

So About Those Books


It's difficult to say whether The Ruby Programming Language or Eloquent Ruby is a better book. They are both excellent and serve distinctly different purposes. If you want to get started in Ruby quickly, and you already have a programming background, then you can read the first half of The Ruby Programming Language and be good to go. If you're already familiar with Ruby, but you're unsure of the best way to use certain language features or want to learn more idiomatic ways of solving problems in Ruby, then Eloquent Ruby is the book for you.

The Ruby Programming Language makes an excellent reference when you need to look something up, and Eloquent Ruby is a great read for when you want to improve your programming style. They each have their strengths and are targeted for different audiences, or the same audience at different points on the Ruby learning curve. They make a great combination, but one thing neither of them is good for is the novice programmer. If you're starting out learning to program, I think Ruby is a great first language to learn because it is so clean, flexible, and accessible, but these two books are not going to introduce Ruby in a way that a beginner can use. For the aspiring programmer, you'll have to find resources that introduce things at a slower and more careful pace.

For the rest of you programmers out there with a desire to learn or improve programming in Ruby, these two books are definitely worth checking out. They've certainly earned a spot in my library.

What Can Golf Teach Us About Programming?

Golf ball teed up with driver

Golf is a game of accuracy and patience. You start with a little ball slightly bigger than one and a half inches in diameter, and you have to sink that ball into a hole barely more than two and a half times its size that lies hundreds of yards away using only a set of clubs. The less strokes you can do it in, the better, and once you've done it, you get to do it all over again on the next hole. That sounds like an apt metaphor for software projects if there ever was one.

On a software project, you start out far from your goal, the finished product. You may not be able to see the goal when you start, but there are markers and flags along the way leading you in the right direction. Mistakes can send you off in the rough (or worse), and it takes extra time to get back on the right path. There are also plenty of obstacles, traps, and hazards to deal with. In golf, when you get into trouble, the best thing you can do is get back to the fairway. Taking risky shots from bad positions can make a bad situation much worse, and you may never recover, so get to safety first instead of trying to be a hero.

Another place to keep it calm and not try to be a hero is on the tee. We all love grabbing our big driver and taking a monster swing to crush that ball into oblivion, but we're more likely to put the ball much closer to the hole and on the fairway if we take a nice, smooth, easy swing. Have you ever noticed how professional golfer's swings look so effortless, yet they can hit the ball a country mile while maintaining accuracy? That ability comes from great technique and control, not from brute strength. When you try to kill the ball, you're only succeeding in killing your swing with a loss of control. The ball may very well go far ... into the woods. Save the monster swing for the driving range where you have the ability to experiment and hopefully gain some control over it with practice.

The same can be said for software projects. If you try to hammer out hundreds of lines of code in one shot, you may feel like you're making great progress, but you could end up far off course and no closer to your goal. Take it easy. Code a little, test a little. Talk to your customers frequently. Get some feedback so that you know when you're veering off into the trees and can make corrections early.

While you're making those corrections, you can think about your approach. In golf you start out with long shots that cover plenty of distance to the hole, but as you get closer, you use shorter clubs and the shots get shorter and more accurate. More than half of your shots in a game of golf will be taken on and around the green. That means that 90% of the distance to the hole is covered by half of your strokes, and the last 10% of the distance takes the other half. That characteristic should sound very familiar to software engineers, where projects are estimated to be 90% done when you're only halfway through the schedule. Amazingly, that last 10% takes the other half of the time.

Because of this 90/10 property, you can improve your golf game more dramatically by shaving strokes off of your chipping and putting game than you can by adding 50 yards to your drive. Being 100 yards from the green isn't that much better than being 150 yards from the green, but if you can easily sink 10-foot puts, you're going to have lots more opportunities for a lower score. Could the same be true in software projects? If you improve the testing, bug fixing, and tweaking that goes on before releasing a product, that could have as much if not more of an impact on schedule than improving on the initial prototyping and coding at the beginning of the project. Of course, like teeing off, initial prototyping is the fun part. Who wants to spend all of their time practicing putting, am I right? Well, the golfer that nails more puts generally wins more games.

Another aspect of golf is the wide variety of clubs at your disposal. Every club has a job that it performs best, and sometimes the choice of club can make or break a shot. The driver is made specifically for hitting long shots off of a tee. The woods are good for long shots off of the fairway, but don't work well in the rough. The irons can get the ball up and out of the rough better, but can't hit the ball as far as the woods. Hybrids attempt to combine the best parts of the woods and irons, but they have their own compromises. The wedges work well when you get closer to the green, and they can help get you out of bunkers and tight spots. The putter, of course, is the club of choice on the green.

To master the game, you have to become proficient in all of these clubs and know when to use each one. Likewise in software engineering, you will become a much more productive programmer if you learn more tools and learn them well. Every programming language, library, API, or utility is another club in your bag. Take the time to learn their strengths and weaknesses and in which situations to use them to the best advantage. No tool is perfect for every situation, and using them in the right context will make you much more effective as a programmer.

As you're trying to improve as a programmer, you can keep a golfing practice tip in mind. Consider how much there is to think about when trying to improve your golf swing. There's your posture, your grip, your stance, and your line-up to the target for starters. Then during the swing there's the backswing, the downswing, ball contact, and follow-through. The whole swing involves timing, tempo, and rhythm. And for heaven's sake, make sure you keep your head down and your eye on the ball while you make contact with the club face. There is no way that you can be thinking about all of those things during the two seconds that it takes to swing the club.

So don't. Focus on one thing at a time. During your swing, you should be thinking about only one aspect of your swing. If you try to practice even two things at once, you're going to do both of them badly, and you won't get anything out of your practice. If you stay focused and improve on one thing until it becomes second nature, then you won't have to think about it anymore, and you can move on to something else. The same strategy works well in software engineering. Pick one thing to learn and then learn it. Don't split your time and attention over too many things or you won't make progress on any of them. If you concentrate on one thing at a time, you'll learn it faster and actually make use of it more often because you'll know it better.

Here's one last thing that becomes painfully obvious in golf. No matter how good you are, there will be things about almost every shot that you wish you could have done better. Sure, there will be the occasional shot that feels and looks awesome, but it's those great shots that make you believe that you can do better on all of the others. You are not alone. I've read about professional golfers - golfers that have won Master's Tournaments - that say they think 80% of their shots are crap. They thought they could do better than they did on that many of their shots, and they are the best golfers in the world. I'm sure they practice every day to improve on those shots where they felt they came up short. Remember that - there's always room for improvement.

Software Practices to Develop By

Software development is hard. The amount of information you need to know to be effective in any area of software engineering is staggering. And the amount of new information coming down the pipe can be overwhelming. Whether you're doing web services programming in the cloud or embedded software programming for micro-controllers, you should know at least one programming language well, and probably more than one to be really effective. There will be some set of libraries and frameworks to know, and the more you know, the better choices you'll be able to make regarding which ones to use for a given design.

You should know a good software development process, likely something agile. Then there's your development environment: the OS, an IDE or text editor, compilers, build automation, bug tracking, version control, unit testing, etc. You should have deep knowledge of all of these things. Depending on your application domain, you'll need to know about digital signal processing, power management, statistics, probability, user interfaces, user experience, networking, databases, control systems, discrete mathematics, graph theory, and the list goes on. Believe me, that's only a very small, partial list, and don't forget the actual domain-specific knowledge for the field in which you're writing software.

The set of knowledge that a software engineer uses is vast and unique to each programmer, and if you're keeping up on personal development, you're adding new layers to it all the time. However, I've found that there's a short list of development practices that stays fairly constant throughout the years, even with new languages and frameworks and tools appearing every week. This list may be different for you. Heck, in the future it may be different for me, although probably not by much. Up to this point in my career these practices have served me quite well. They're the concepts I think about every day while I'm designing and programming, and while tools and frameworks continue to change, these have largely stayed the same. They are the stalwart knights of my programming days.

DRY: This principle comes from The Pragmatic Programmer, and it stands for Don't Repeat Yourself. I'm sure I don't have to go into too much detail here because any programmer worth his salt already knows it. For anyone that doesn't, stop reading this right now and go get a copy of The Pragmatic Programmer. Read it. DRY is the essence of programming. It's deceptively simple to understand in theory, and wickedly hard to implement in practice. I am constantly thinking up and trying new ways to achieve the ideals of this principle.

KISS: Software engineering is hard enough as it is without us over-complicating our designs and our code. I always aim to Keep It Simple, Stupid. Another way to keep this idea in mind is to aim to do the simplest thing that could possibly work. Don't try to dress up a simple solution in a big, frilly frock of design patterns and UML diagrams that it doesn't need. Do only what is necessary to solve the problem at hand, and no more. Over-design is a house of cards, and if you can barely understand it when you're building it, it will all come crashing down when you're trying to maintain it six months from now. Do yourself, or the next programmer that has to look at your code, a favor and write it as cleanly and concisely as possible, and keep it simple. You'll get more done, you're more likely to get it right, and you're more likely to understand it later.

YAGNI: Closely related to KISS, YAGNI is the principle of You Aren't Gonna Need It. That multi-level inheritance hierarchy for implementing unspecified future features? You aren't gonna need it. That quadruple redundant, auto-recovery, exponential hold-off protocol for messaging between micro-controllers? You aren't gonna need it. That SaaS API for your new meeting software in the cloud? Seriously, you aren't gonna need it! At least, you don't need it yet. Get the stuff working now that needs to be working now, and save the stuff that you could need later for later. Sure, you can think a bit about how you would add future features if you really think you're going to need them, so you don't completely paint yourself into a corner from the beginning. But there's a big difference between planning for future expansion and actually erecting all of the scaffolding and roughing in the architecture. Do the former, not the latter.

Occam's Razor: There are many formulations of this principle, many coming from philosophers and scientists other than the one for whom it is attributed to, William of Ockham. The one that I learned and prefer, but cannot find a reference to is, "in the absence of contradiction, the simplest explanation is best." I use this principle mostly as a guide in troubleshooting and debugging, but also in general problem solving during design. "Best" can mean everything from most correct to most useful to most desirable. If you're trying to figure out why a build is broken, it's much more likely that it was due to some recently added code with a bug in it than a latent bug that happened to surface now. It's still possible that it could be the latent bug, but I definitely wouldn't start looking there. I would start with the most recently checked in code. Occam's Razor is surprisingly versatile, and I find myself using it constantly.

Amdahl's Law: Formally, Amdahl's Law states that "the speedup of a program using multiple processors in parallel computing is limited by the time needed for the sequential fraction of the program." That's quite a mouthful, but basically it means that your program can only be as fast as its slowest component. Another way to think about it in the context of optimizing a program for performance is that you're going to get the greatest speedup from the part of the program that takes the longest to execute. Sounds obvious, right? So don't spend your time optimizing esoteric features of a program that only rarely execute or processes that happen in parallel with long-running IO or database operations. If your program is spending 40% of its time doing something that the user is waiting for, focus on that instead.

"select" Isn't Broken: Here's another one from The Pragmatic Programmer. This time the authors relate a story about "a senior engineer [who] was convinced that the select system call was broken on Solaris." Don't fall into this trap. Sure, it really looks like you're using that library function correctly. You've looked over your code dozens of times and you are positively convinced that it is doing what it's supposed to do. It must be a bug in the library. No, the compiler is making a mistake when optimizing this code section. No, there's a bug in the processor that I have to work around. Stop, just stop already. Do you really think any of those systems that have seen orders of magnitude more use and abuse than your code are all that bug-ridden? Take another look at your own code. The bug is almost certainly there. In a milder form of this practice, you should always assume the bug you are seeing is your own fault. Inspect your own code as thoroughly as you can before trying to blame it on a coworker's code. You might save yourself some embarrassment.

Don't Let Standards Make You Stupid: I don't have a link for this one because I haven't seen this idea wrapped up into a pithy phrase, yet. Instead, I made up my own. The idea is that while standards are generally a good thing, they should not preclude you from thinking about the problem at hand and solving it in the best way possible. Standards can add some uniformity and consistency to programming and offer known solutions to common problems, but standards can also go to far. They can become rigid structures that mask over issues that are unique to particular problems that require their own creative thinking. Make sure to balance out a hefty set of standards with an eye for exceptional circumstances where those standards don't apply. And then use your brain.

Do Not Reinvent the Wheel: A good way to avoid this problem is to watch out for its main symptom - NIH. If you find yourself implementing basic string processing algorithms or building your own data structures, you could be reinventing the wheel. Try spending a few minutes looking around public code repositories or even your language's standard library to make sure you're not wasting your time writing code that's already been written hundreds of times before, and will likely perform better than yours because it's already been extensively tested and optimized. There is some need for balance here because if your problem can be solved quickly with a few short methods or a small class or two, it may take longer to find, adapt, and verify someone else's code instead of rolling your own. On the other hand, if the solution comes from a well maintained framework with a good API and documentation, you can benefit from future updates to the framework. And now that you know it exists, you can reuse it in other projects. In any case, try to find the best way to solve your problems without blindly resorting to writing more code.

Rubber Duck Debugging: This is a method of debugging where, when you get completely stuck, you turn to the rubber duck sitting on your desk, and ask it for help. You have to explain your problem with enough detail that the duck will be able to understand the problem and offer a solution. Quite often the act of constructing a well-formulated question will reveal the solution, all on its own, and that is the point of the exercise. If not, then perhaps the duck will miraculously tell you the answer after all. I wouldn't depend on that, though. For more information on this excellent problem solving method, I'll point you to Jeff Atwood.

Bedtime Debugging: Here is another practice that hasn't been phrased as such, but is very commonly recommended in various ways. It could also be called shower debugging, or brushing-your-teeth debugging, or go-for-a-walk debugging. The idea is to work on the problem as much as you can. Give it a good effort, and if you get stuck, tuck it away in the back of your mind and go do something mindless. You're subconscious will continue mulling over the problem, and then when you least expect it, the solution will pop into your head. When I use this technique, I normally don't immediately turn to doing something mindless when I get stuck. I'll put my current problem aside and work on something else. Because my mind is otherwise occupied, those latent solutions normally don't come to me right away. They turn up as I'm falling asleep at night. This happens so frequently that I've learned to task switch as soon as I run out of ideas for my current problem, instead of staring blankly at the computer screen for hours. It can be frustrating to leave a problem unsolved, but I could also waste a lot of time fighting for new ideas without making any progress. I know I'll figure it out when my mind is calm and relaxed that night, and I'll make more progress the next day.

Leave It Better Than You Found It: My last software practice comes from many years in the Boy Scouts. My scoutmaster was an adamant proponent of Robert Baden-Powell's advice to "leave this world a little better than you found it." In scouts that meant cleaning up trash when you saw it, leaving campsites in better shape than when you arrived, and generally being a good caretaker for mother nature. That lesson has stuck with me in software engineering, and when I'm working on a piece of code, I try to leave it better than I found it, too. I take the time to refactor when I'm changing code so that variable names are more self-explanatory, methods are shorter and more understandable, and code formatting is more consistent. I don't go hog-wild, rewriting every file I touch, but if I see something that looks out of place, I'll take the time to make it a little bit better for the next programmer.

That brings my list of good software practices up to eleven. Maybe that's not such a short list, but they are things I use everyday. I've found them all immensely valuable, and maybe you will, too.