The Force is Strong with this One:
Iteration 1 was a good launching point for our semester project. Much has been learned, which will force better practices upon my later development. That being said, it was an excellent example of what not to do. First off, leaving the majority of the iteration to the night before it's due is still a terrible idea. Secondly, test cases can be extremely useful in debugging, rather than having to use a multitude of printf() statements. Lastly, bugs can appear in places that you would least expect them, and often the complex answer is not the best one.
My project partner was very helpful in getting the initial code written, I then went through during some of my free time and cleaned it up a bit once we figured out a style that we agreed upon. Fixing a few syntax errors and getting the code to compile and run the test-cases was trivial after that. Implementing all the regex matching took a while, but wasn't overly difficult. It was nice to start developing apart - communicating through comments, code, and text messages - to both get a general idea of what is going on. This forced us to check each other's code to make sure what we were doing was correct. Later on, we paired up for an evening and rolled out most of the rest of the iteration.
As far as code styling goes, I prefer the "emulated pure blocks" method. I find it to be cleaner, more succinct, but still provides an understandable structure. In my own projects, I often mix and match styling depending on who will be reading it, how often I'll need to come back to certain code snippets, and on the language being used. We were required to pick a style, and stick with it for this iteration (and I assume the entire project). I found myself being more verbose - which is not necessarily a bad thing - but also more structured in my thought just because my code was required to be more structured. This lead to some faster edits and debugging, and being able to compare changes between revisions much quicker.
I'm very torn on the idea of pair programming. Studies have been conducted, and shown that people working individually generates more unique ideas, and the stereotype of computer scientists being anti-social creatures often holds true. An article in the New Yorker stated "decades of research have consistently shown that brainstorming groups think of far fewer ideas than the same number of people who work alone and later pool their ideas". This can obviously be proven with statistics, but what cannot be proven, is the quality of each of those ideas. A thousand difficult terrible ideas are worth considerably less than one great idea. Personally, being able to hack away on a project on my own time-frame, without someone "looking over my shoulder" is very enjoyable and very productive. Although, often there are parts that I don't fully understand, and having another person to bounce some ideas and methods off of is extremely helpful! With the work I've done in industry, I've found the trend of having a pair of programmers on a project to be very useful. The idea of a primary or senior developer, with a secondary or junior developer to sanity check them is the method I prefer. Each developer is primary on a feature, and secondary on another. They often start off pair-programming, but as time goes on, they split ways. The primary does large additions, with the secondary checking their code, and adding in small fixes or pieces when necessary. So, I'm not going to write off pair programming, I actually think it's very effective, but like any blind dogma, it's not something that should always be used, just because someone says so.
In response to an earlier remark on test cases, the printf() can often yield very enlightening results, but if we write self-verifying tests, they are often deemed un-necessary. Not always, but often. Is any one practice useless or worth less than the other? Betteridge's Law holds true in this instance, saying that any "headline" that ends in a question mark can be answered with "No!". Both test cases and simple prinft() statements are often enlightening when trying to debug issues. We often wrote parts of our code without writing test cases first though, and ran into issues. Had we just taken a few minutes to figure out what we wanted, rather than diving in headfirst to the code, we probably could have saved a few hours of small, hard to track bugs.
One of the difficulties we had is that we wanted a more dynamic way to match each regex to a token, and late at night, it seemed like a great idea to use a struct with a few pointers. I was totally wrong. It ended up being a hassle to try to debug; I never did get it to work correctly in that form. The benefit of this though, is my logic was correct, my implementation was wrong though. After many hours or debugging, I found a very simple way to include this dynamic method, and eliminate all of the pointers, structs, and object passing. It wasn't necessary to use this method to satisfy the requirements of the iteration, so it wasn't included in Iteration 1, but for Iteration 2, it will be. It saved us about 150 lines of code, which is fantastic. This is a great example of refactoring!
Subversion (SVN) worked very well between us. Very rarely did we have any issues merging our code. The few times we did, the issues were solved with a "use mine" or "use theirs", rather than having to manually check everything. I normally prefer Git over SVN, but that doesn't fit into the requirements of the class, and SVN is more than able to handle anything we will throw at it.
One thing I learned is that a good practice to break the iterations into smaller pieces, with test cases for each piece. Things will go wrong, and you won't see the bugs coming. These will compound themselves with every line of code you write after something breaks. Overall, the iteration was a good experience, it made me realize quite a few things that I need to improve upon, and also motivated me to clean up what I could for the next iteration. Working with my partner was a great experience and I look forward to continuing that in the future iterations.