Friday 21 March 2014

Woes and lessons in programming

Assignment 2 (both parts of it) is done now, thankfully. Which means I now have time to reflect on it - on the process, what went wrong, what could have been done better and what went very well.

One thing this assignment clearly illustrated to me was the importance of planning. Since I started programming, I've developed the bad habit of jumping right into writing code rather than thoroughly reading the problem and drawing up a plan, against the insistence of all my instructors. In high school we were forced to handwrite "pseudocode" before we were allowed access to the computer. I remember that I felt it to be an absolute waste of time. After all, I could solve the problem easily, I already had the solution visualized in my head, why bother transcribing it to a piece of paper? Any unforeseen kinks or problems could be smoothed out easily later by trial and error.

And for a while, this worked for me. In fact it worked spectacularly - until this last assignment. The major difference with this assignment was the complexity of the problem, in particular with the function regex_match to compare strings to RegexTrees. In essence this function interprets a set of rules to produce its result. So I took the same approach I always have - I read the rules, I translated them into code and then I repeated the cycle of hitting run and making changes until it worked. Eventually I produced a function that worked rather nicely. Satisfied, I moved on to the next function. Then on Thursday just prior to submitting the assignment, I went to test it against different test cases posted on Piazza. And I found that while my code worked most of the time, there were some instances, using inputs I had not anticipated, where it failed. No problem I thought, I'll just have to modify the code a bit. To my dismay, after some experimentation and frustration, I found that because of the structure of my solution there was no way to accommodate the failed cases short of rewriting the function. Because I hadn't properly planned out the function and taken care to understand the problem fully, I had failed to anticipate several edge cases. So I proceeded to design a function with an incomplete picture of the problem, and so unsurprisingly produced an incomplete solution. As a result, I had to submit a regex_match that I know will fail for several different inputs, and I'm sure there are more similar cases that I did not encounter.

(I suppose this experience also highlights the importance of thorough testing and troubleshooting. Had I been more thorough, I may have noticed the problems earlier and would have had time to make the necessary changes, even if that meant rewriting the function. Of course, this could all still have been avoided had I taken more care with the initial design and planning.)

I'm an optimist so I'll end on a more upbeat note. I'm in third year and taking six courses this semester so I'm always short on time, but I was very happy with how I managed my time for this assignment. Maybe I could have started earlier, but otherwise I was able to steadily work on the problem and finish most of it well in advance of the due date. This is a nice change from pulling an all-nighter to finish Assignment 2 in CSC108 from last spring. I noticed that besides the obvious decrease in stress, giving myself longer to work on the problem had several other advantags. I found myself discovering solutions to problems I'd been having at the most random moments - while commuting to work in the morning, while brushing my teeth, while lying in bed and waiting for sleep to come. It's almost as if my brain needs time for the problem to fully soak in - and when it does, it works on it almost subconsciously.

Friday 28 February 2014

Week 7 - Recursion

Over the past few weeks, this class has focused heavily on recursion and recursive solutions to problems. I've been exposed to this idea previously in high school computer science classes, but we had never really done an in-depth examination of the topic. I do remember thinking upon first encountering recursion that it really seemed quite trivial. The idea, it seemed, was simple; you have a function, and you call the same function within that function. At the time, the whole idea seemed to be purely academic in nature and of no practical purpose.

Using recursion in class and for the first assignment has necessitated developing a much more intimate acquaintance with the concept, and this has shattered many of those naive high school prejudices. First and foremost, I have been rudely awakened to the fact that, despite its deceptively simple definition, recursion is not at all a simple concept. Never have I had such difficulty wrapping my head around an idea, and what is most aggravating is that the code, on the face of it, seems so simple. Just a few lines of seemingly innocent, straightforward Python proves to be an utter headache to decipher. Honestly, even at this point, several weeks after the introduction to the topic, I still find it difficult to trace the path of the program, and I've learned there's rarely any point in doing so anymore. It seems best to take a mental leap of faith instead of troubling myself with the details, trusting the program will execute as I intend it to without fully comprehending exactly how it does that.

What has been most striking is the sheer usefulness of recursion. One of the mantras of computer science classes seems to be "there are many ways to solve a problem" - and yet many of the problems encountered in this course have no apparent solution besides a recursive one. It's difficult to accept that what appears to be such a complex problem (such as the Towers of Hanoi game given in class) can be solved with only a few lines of recursive code. I suppose this speaks to the immense usefulness of recursion to computer science. I would definitely be interested in seeing a more practical, real-world example of recursion in play.

Wednesday 22 January 2014

Getting back into the groove

    It's been a year since I've taken CSC108, so as I expected, my computer science skills were very, very rusty. What I didn't expect was being completely unable to follow the lecture on the first day of class. Naturally, this set off a whole set of alarm bells in my head, so I was relieved to hear that the course had scheduled ramp-up sessions for those who needed a python refresher. I went into the second ramp-up session feeling incompetent, but left enthusiastic and itching to write some code. It was truly surprising how effective the session was, and how quickly I was able to pick up programming again. I guess it's kind of like riding a bike?

    Object oriented programming is new to me. I took a little bit of basic programming in high school, so CSC108 wasn't entirely new, but I never got far enough to start dealing with objects. And admittedly, I never really understood objects, nor what they were useful for. Classes were covered briefly in CSC108 towards the tail end of the course, but up until then I hadn't yet encountered a problem for which I felt that I should be using objects and classes. Everything seemed to be doable without them. However, after covering abstract data types such as stacks and queues, I'm starting to see how they can be useful (and I'm sure I'll see much more as the course goes on). I found the idea of creating a specific data type really interesting, so I decided to play around with it a bit. Last semester I took linear algebra, so I decided to create a Matrix class, which would store integer values in a matrix. So far I've managed to create the class, including random generation, addition, subtraction and matrix multiplication methods. I'm hoping I'll be able to figure out how to implement row reduction and determinant methods as well. This little exercise has been really helpful in getting more acquainted with classes and objects, and understanding their purpose and what they're useful for.