Friday, March 14, 2008

There's more to coding than...well.... coding.

Learning how to write software is really a tiny piece of what it means to be a programmer. Let's be honest, writing code is actually pretty easy to do. You spend a few years learning how the basic logic structures work, the looping, function calls, return values, blah blah blah. After that, the most work you put in is studying some new API or learning the nuances of some new language. All in all though, it's not terribly hard to do.

Unfortunately, there's a lot more to it than that. The book series "Effective C++" by Scott Meyers (I've provided links at the end of this entry to all of the items I rave about, so no need to fire up Google) really opened me up to this notion. It was the first book I had read about programming that didn't teach you how to write code, but how to write proper code. Actually, not just proper code, but great code. It was such a breath of fresh air to pick up a book about programming and not have to see the same step-by-step teaching process. Books like this (you should have already gone and checked it out from your library by now...if not, stop reading and go. now. I'm waiting.) focus on things that too many programmers neglect: writing proper, efficient code that does exactly what you intend it to do, and does so very nicely.

But again, that's just another piece of the puzzle. I've been browsing some programming blogs recently and I came across this one: http://www.gamesfromwithin.com/ There is some really great content in there and I encourage you to check it out. The relevance for this discussion is that the author is a big proponent of agile development and test driven development. If you aren't familiar with those concepts, I hear Google works quite well. The basic run down of agile development is that it's a production mechanism of sorts that stresses quick iteration of software based on client feedback (whether the clients are other programmers working on other features or your actual end-users depending on the type of project you have). A main element of agile development tends to be a team oriented approach that involves things like XP (2 programmers working side-by-side on the same piece of code).

For an example of how well these things can work, check out this entry in the above mentioned blog: http://www.gamesfromwithin.com/articles/0602/000104.html You'll be amazed at how much work gets accomplished with this method.

Test driven development follows with the iterative theme in that you essentially reverse the coding process. How? With the use of a unit testing framework, you write your tests before you write your code. Clearly, the test should fail. Then, you write just enough code to make that simple test pass. The key word there is simple. The tests you design should be very small and simple to implement. The author of that blog suggests between 1-2 minutes to design the test, and not much more than 15 to implement the code to pass the test. "Test Driven Development" by Kent Beck seems to be a godsend book on this design methodology. I just picked it up from the library yesterday and it's very helpful in outlining the process, go get it!

These are just 2 examples of design methodologies in software engineering, but there are a ton of other ones. Some work better for certain things, but the point is that this stuff matters. It's vital in a professional software development environment. Without things like this, nothing would get done, and even if it did, the result would be awful. I encourage you to start learning about this stuff while you are still in school, because chances are you won't have too much meaningful class time devoted to things like this. All of it can only serve to make you a better programmer.

This is where the distinction between "Computer Science" and "Software Engineering" comes in. Software engineering is devoted to stuff like this. It's all about the design, the planning, the process. Computer science tends to be focused on the implementation alone. The curriculum in colleges today leaves much to be desired in my book. How can you send CS majors out into the work field with very little knowledge of software engineering principals? To me, they go hand in hand. You can't write any sort of decent code without a design or a planning process. What about a roadmap or schedule for the project? You can't just "wing it" and expect any worthwhile results to come out the other end. Some people think all of this "management" should be the responsibility of the projects "manager". Maybe so, but I don't think it's black and white. The project manager can't write your test cases for you. The project manager (in the sense that most people think of him/her in) can't set realistic and useful code milestones for you. As a programmer, you can't get to where you need/want to be unless you know where that place is before you start.

I encourage you to read as many blogs by professional developers as you can. These people are wise beyond my years, so I could go on and on, but you're better off hearing it out of their mouths (or fingers...) than having me repeat to you what I've learned from them. The "Games From Within" blog above is really outstanding. I learned more about software engineering in a few hours than I have in 3 years of college. In addition, look for some language-specific blogs by some seasoned vets as well. These blogs tend to focus on many similar topics that the "Effective C++" series does. That is to say, the "how to do it right" as opposed to just the "how to do it". I found this site the other day and it has a wealth of information from blogs by over a dozen different professionals, to regular articles: http://www.artima.com/index.jsp

Good luck, and remember: learning how to program is just the first small step in being a software developer.

Resources You Need To Check Out

Websites / Weblogs
Books

Monday, March 10, 2008

There's room for everyone

One of my biggest problems to date has been that I get discouraged when I look at what's already been accomplished in this field. When you are sitting down to work on a trivial idea you've come up with, it's easy to stop and say "Wow, do you have any idea how complex the GCC compiler is? What the hell am I doing with this simple program?!" It's an easy trap to fall into, but a deadly one.

We can't all be John Carmack, Bill Gates, Linus Torvalds, etc etc etc... but that doesn't mean we should find a new profession. Implementing those trivial ideas are essential for growing as a developer, and if you don't go through that process you'll never get to where you want to be. John Carmack didn't roll out of bed one day and write a 3D game engine. He had years of programming experience. Granted, he's a very intelligent man when it comes to math and science, regardless of his programming abilities, but again, he's one of the many exceptions. Most people simply aren't that gifted. However, if programming is the field you want to be in, you can work hard enough at any area of it and become proficient.

The only remedy I've found for this issue is that when you have an idea for a piece of software you'd like to create, don't "Google it". Most ideas that most of us have will be based off of some piece of software that is already in use. Going to Google to check out some of those applications is only going to worsen this issue. I like to get off of my computer, grab a pen and paper and start designing the system "offline". It's actually a lot more productive than sitting in front of your monitor, and you can't get discouraged if you pretend that nobody has ever made this piece of software before.

Going back to the trivial nature of some of the programs we may write... Just as programming books start you off simple before branching into pointers, objects, templates, data structures, etc... you should be doing that with your code. Now, this tends to happen naturally anyways since you can't well write code involving things you don't yet know how to do, but I know I've certainly tried. Not to say that it's always a bad thing to test new waters, but you shouldn't really make a habit of doing something until you understand it. A book progresses rather quickly, but your projects should progress much more slowly in terms of the complexity of the underlying software. This is paralleled by the fact that you cannot simply read a programming book front to back as if it were a novel, it must be an interactive experience in which you are typing the code from the book, doing the examples, doing the projects, etc... The more time you spend building the complexity of your projects up, the better off you'll be in the long run because you'll have an expert-level understanding of everything you've done, which will then make the transition into the really advanced stuff easier.

A great way to do this is to develop your software idea just like a mainstream piece of software. Have iterative releases of your application, adding new features and refactoring code along the way. Make a habit of creating a "TODO" list after each release so that you have specific points to focus on. Ideally you'd have setup some sort of road map at the outset of the project, so you should already have some direction in this regard. Set stern, but reasonable deadlines for your releases, manage a blog documenting the process, invite others to use your applications (friends are fine, as long as they will give honest feedback), etc... Doing all of these things will keep you excited about your project, focused on your project, and you'll absorb a lot more of the techniques than if you just fleshed out your initial idea and say "Meh, that's cool I guess...".

Hope this helps.

Tuesday, March 4, 2008

College Courses

When I transferred to my current school last year, I heard a big buzz about a change in the department from C++ to Java. At my previous school (a very, very good one), Java was the focus of the curriculum. We did a lot of advanced things with Java, and although I don't use Java as my primary language, I learned a lot about programming. C++ was used to teach pointers primarily, but some of the OOP concepts were also presented of course. Now, the difference between that school and the one I'm at now is that this school is on semesters instead of quarters. At my old school, you could ideally finish all of your Java courses in your first year of school, thus opening the door for more specialized courses that didn't force you to use a certain language. The main issue of this post is to discuss the programming curriculum that I think should be in place in most schools, but isn't.

Below is a basic outline of the flow of programming courses that I would prefer be offered:

  1. C - Focus on basic programming logic, functions, recursion, arrays, and introduce structs.
  2. C++ - Pointers and memory management, heavy focus on OOP from novice to expert topics. I would choose to wait until now to deal with memory management because a lot of bad habits get formed when you do this stuff in C without knowing what you're doing.
  3. Java - Heavy focus on interfaces/abstract classes. The most confusing things to most people in Java is having to extend the standard library, override functions, etc...
  4. C# - With this language coming into popularity, it's a must have.
So, what's my logic here? I believe in starting from the ground up in order to establish good habits and strong skills. I began teaching myself C++ when I was in 8th grade. By the time I was forced into taking a Java class, I had no problem whatsoever picking it up. Take the inverse of that. Nearly everyone I've talked to that started programming in Java has struggled in C++ and/or despised it. Why? Java hides too many details from you that become your responsibility in C++. Basically, if you can code in C++, you can code in anything. I don't think you can honestly say that about Java. This is of course a general statement, this isn't to say that there aren't plenty of intelligent people out there that can program in any language, because of course there are. In fact, any programmer worth his weight can, and should be able to program in any language. The point though is that when you are teaching the material, it would be more beneficial to start with C/C++ and then simply learn the nuances of Java from there. The beauty of the above outline is that it allows you to move on to more specific topics such as data structures, GUI, threading, etc... and by the time you get there, you are armed with knowledge of 4 programming languages. The current trend seems to be to teach a particular course with a particular language in order to kill two birds with one stone. I'm not a big fan of this. I think someone is far better off coming into a data structures course with intimate knowledge of at least 2 programming languages as opposed to being expected to develop that knowledge of a language while at the same time mastering data structures. In addition to the above diagram, I think a school should offer at least 2 scripting languages and require one for a degree. Python, Ruby, Perl all come to mind.

My main concern is that a lot of kids will graduate from school with zero ability to program in anything other than Java. That's more of a reality than you may think, especially when C++ is essentially being removed from the curriculum of some schools. The bottom line on this is that C++ is widely used, and that isn't going to change. In fact, in some areas of Computer Science, namely Game Programming (console/PC), C++ is king.

More and more I'm finding kids in my CS courses that have never done a lick of programming work before coming to college. The market is always good for Computer Science, so they decide to pursue it as a career. These are one of groups of people that I have in mind when I say you can't go from Java and learn any language. The popular argument against this is that C/C++ is too complicated for these people. Maybe so, but I don't agree with that if the course is taught properly. Secondly, think of it as a "weed-out". It seems the popular choice for a "weed-out" course at a number of schools is discrete math. While I understand the concepts presented are important, I don't view them as things that are specific to this course. I think you garner all of the logic you need to in your programming courses/experiences. Secondly, I don't think this course serves as any sort of useful primer for a data structures course, and at a lot of schools that is how they have the pre-reqs set up. The only logical reason to do that is to "weed-out" kids that may not be cut out for this line of work. I think a more useful test would be teaching C/C++ as a first language as opposed to Java. After all, if you can't design and write solid code, you won't have a job very long. Anyone can sit down and work out logic puzzles.

Just my two cents.

Monday, March 3, 2008

Why put a go-kart engine in a Camaro?

I was browsing some projects on Sourceforge yesterday and I came across a basic game of Checkers. I believe they were using GTK and maybe SDL as well. All of the source files were C++. Now, SDL works natively in C++, but as far as I know, you'd need to use GTKMM in order to write GTK code in C++. Nevertheless...

This person usesd absolutely NO features of C++ in his code. It was all straight-C. I really don't understand this at all. Why incur the extra overhead of the standard C++ libraries and then not use them? Secondly, why use C if you don't need to? When I say that, I'm referring to the need to do a lot of low-level memory manipulation, in-line assembly, and other things of the like. Of course, any of that stuff can be done in C++, but usually C is preferred. This application had none of that in it. It was just a bunch of structs, char*'s, and SDL/GTK library calls.

My stance on this particular instance is to just use C++ instead of simply changing the file extension to ".c". std::string is a lifesaver, and the C-style structs just get clumsy and very limited after a while, especially in a game. Those 2 things alone would have made the game more extensible, easier to maintain, and a lot easier to understand.

Just my two cents.

Thursday, June 14, 2007

The Contract Job From Hell

It seemed easy enough. That's what I thought when I received an e-mail from the Computer Science chair at my University advertising a C++ programming opportunity involving a fairly simple API to interface with a radio receiver card. The details weren't great, so I replied and said that I'd like to get some more information. About 2 weeks later I heard a reply from the CS contact person. I was given the contact person for the job, the person actually doing the hiring. I shot off an e-mail asking a few preliminary questions such as the features he'd require, the time span, the pay, etc... The reply this time was fairly quick, and the job was sounding relatively do-able.

There were a few catches though. First, the programming would need to be done on a Windows computer and he would require some TCP communication with the data I'd be working with. I'd never programmed under Windows, and I'd certainly never done anything with Windows sockets. The other problem? They needed the entire project done in 3 weeks and they were only able to pay for 10 hours of work per-week at the University minimum wage of $5.50. Dealing with that insulting pay is one thing, but actually expecting someone to come in and write code for an arbitrary API in very little time is something completely different. On the other hand, I was a poor college student, and the actual programming didn't seem like it would be much of an issue at all so I figured I'd give it a shot.

I shot back an e-mail stating my concerns about completing the project in such a short amount of time, stating that it would probably require a number of hours that they weren't able to pay for in order to do it. About 2 weeks went by and I heard nothing. I assumed some other student had also responded to the e-mail and opted to sell their soul for $165. Then, 1 week before the original 3 week "deadline" I receive an e-mail from him saying that they can raise the hours to 15 per-week, but they need it done in 3 weeks (again). By this time, mid-terms are in full swing and I've got major programming projects for school to complete. I tell him flat out that I just don't have time now, but talk to me in May when school ends, I'll be available for the entire month. Again, I heard no reply from this message.

Fast forward an entire month. They inform me that they "finally have time to get the card programmed" and wanted to know if I was still available until June. I thought long and hard about this. I had just finished a demanding year of school, and 2 very advanced programming projects. I was burned out. I needed a break. I also needed money. By my math I'd make around $300. I took a deep breath and sent off an e-mail stating that yes, I was available until June. As was par for the course, it took him a week to reply to me. Just how important is it to get this thing done?! Honestly, their deadlines came and went as I waited around for e-mail replies from this guy.

Anyways, we got everything arranged and I met with him to pick up the equipment. This consisted of a really old piece of junk computer (the card used an ISA slot), a matching really old piece of junk monitor, and 2 antennas (high and low frequencies). Being of rational mind, I decided I'd do all of the core programming on my Linux box, use boost for the TCP communication, and then move over to my high-end Windows XP machine to add in the API-specific code. I wanted no part of using the computer they gave me for anything more than trying out the final code. I encountered a pretty serious problem right off the bat: The card had 2 inputs, a BNC and a SMA. The problem? Both antennas had BNC connectors. The project description as given would not be possible with this setup as both antennas needed to be used at once. I sent off another e-mail informing him of the issue and he promptly replied asking ME what he needed to buy, and to let him know and he'd get it. Reality check: I'm a programmer. I don't know anything about this stuff! I was brought in to write code that performs the task at hand. Troubleshooting BNC/SMA antenna connectors doesn't really fit in there anywhere. Nonetheless, I did a quick Google search and located 2 links that offered some adapters. I sent them to him and told him he needed to check into the matter further, and to let me know when he had acquired them.

One week goes by. Two weeks go by. I send him a status update on the project, pose a few other questions to him regarding his desired requirements. A third week goes by. A month goes by. At this point I'm convinced he's at the bottom of a lake somewhere. I see no other reason to ignore e-mails that only serve to accomplish a task that he needs completed. I keep chugging away at the code, making my own decisions about the questions I'd posed to him. I got to a point in which I was ready to test the code on the old crappy machine. I shit you not, the video card would not kick in. That's right, I'm given improper equipment, the contractor goes "Amelia Earhart" on me as soon as I get started, and the computer I'm supposed to develop for doesn't even WORK!

I send out a 3rd e-mail stating that I've finished the code as much as possible, and that I can't test the API-specific code due to the computer not working. I finally get a response stating that he was finishing up a trip in New York and that he'd be in town in a few days. At that point we were to meet and try to get another video card working. A few more days went by, and finally, we were set to meet. 9am, Thursday.

I arrive at about 10 till 9 and head upstairs where we met the first time. He works in a musical instruction type of building. Due to all of the expensive equipment, you can only access part of the second floor, the rest is locked off by 2 doors at opposite sides of a winding hallway. My process for handling this in the past was to knock at one door, wait, walk to the other end and knock, wait, then repeat. With each trip, my knocks get louder and louder. Now, you may be shocked as I was, but it was 9:30am and he STILL WASN'T THERE. I really should have known. Being relatively amused by the whole situation, I decided I'd get creative.

As I said, I was in a musical instruction building. This meant there were practice rooms all along the hallway, wide open. With pianos in them. There was never anyone on this floor of the building, either. I figured what better way to get someones attention in another part of the building than to start playing piano? So, I did just that. I sat down, and I just played. My basic line of thinking was that anyone that would be important enough to notice me playing piano and arrive to yell at me would also be important enough to have keys to unlock the door I needed to get into. I gave up after 5 minutes and decided to just leave. As I walked out the front door, I see the contractor walking up the sidewalk. Just a simple "Hi how are you?". I spent the rest of the day explaining all of the code and documentation to him, and never once did he mention being nearly an hour late.

The job is done now, and I feel very relived, to say the least. I accomplished a lot, I learned a lot, and I ended up making close to $500. Despite everything, I made sure that I wrote the best code I could, and gave the most informative and helpful documentation possible. At the end of the day, I even like the guy, he's very intelligent, and I'd be "more than happy" to do some future development on this project for him. Of course, if he reads this, he'll immediately know it's about him, but I suppose that's fine. He got the best $500 custom software package imaginable.

Thursday, June 7, 2007

Careful with those stubs, mister!

This is just a tiny snippet which ties into my last post about compiler warnings.

Frequently when I'm building a class, I'll stub out a lot of the functions just to get an idea of how things will work. "Stubbing" simply means adding the function declaration/definitions, but instead of having the function actually perform it's task, it's usually either left blank, or does a print statement to show where the control is currently at. That's all fine and well...until you do something like I did.

In order to complete my stubbing, I went as far as to assign one of my class data members, an std::vector<>, to the return of the function that would be used to populate this vector. The problem? While stubbing that said function, I forgot to add a return value! This, coupled with lack of any compiler warning flags, caused a segfault when I ran some testing code.

Now, to the heart of the matter: Why was this so hard for me to track down, aside from improper (absent) warning flags? I was doing my debug print statements with std::cout. The problem? std::cout is buffered, which means things get printed when the OS decides they get printed, not exactly when you tell it to print. After I tried to initialize my vector from the function (of which returned nothing), I made a call to some other class functions, and due to the buffering of my debug statements, it seemed the segfault happened AFTER that other class function returned, but BEFORE control was given back to the constructor that called it. This clearly made no sense, and all of the code looked fine.

Using std::cerr is the optimal choice for debugging output because it gets printed exactly when you tell it to. More importantly, a simple -Wall flag to g++ would have informed me right away that: "control reaches end of non-void function" and immediately I'd know why my program was segfaulting.

So, lessons learned?

1. Enable. Compiler. Warnings.
2. Use std::cerr for debugging output
3. Complete your stubbed functions with return values and proper parameters

Note: I've been told that using std::endl will force std::cout to be printed, but for whatever reason that just wasn't happening for me. *shrug*

Attention: This is only a warning.

I tend to be pretty lazy when it comes to compiling my code. After I'm done knocking out the source, I want to make sure it compiles right away, and start testing it. However, taking the 10 seconds to add warning flags to the compile command could save me, and you, countless headaches trying to track down a bug that the compiler would have been able to point out right away if given the proper flags. The following example, unfortunately, is immune to compiler warnings, but it illustrates a basic error that compiler warnings would try to prevent you from making.

I was writing an application that dealt with unsigned integers throughout the entire program. At some point, I needed to convert those unsigned integer values into std::strings via a helper-function that I created. The values were read in via a binary file, and stored in unsigned integers. The deadline was approaching, and I didn't think about what would happen if there was a negative value in the binary file (perfectly legal, though) The result? The compiler silently converted the int that I retrieved from file to the unsigned int it was being stored in, thus mangling the sign value on my data. Luckily for me, I had been programming on a daily basis for many hours for about the past 5 days, so my brain was warmed up and I caught the error rather quickly. However, it isn't hard to imagine how something as minute as this could remain hidden for a long time, delaying the completion of your project, and driving you farther into insanity. Again, this particular mishap is unfortunately immune to warnings, but from this you can see how something of this sort could be avoided by enabling proper warnings.

There are many other error flags, please check the docs for your compiler to see what they are, but it should be a goal to not only use these flags at all times, but also to have your code compile with the strictest of warning flags in use. If you are receiving a compiler warning, there is a good bet you have a problem with your design, implementation, or maybe both. The above scenario would really be classified as design/implementation, depending on how you look at it, but really it was just a case of carelessness.

Enable compiler warnings with the needed flags. Get rid of them with better code.