I don't think it's a coincidence that the multiplatform codebase was cleaner. Very often, things will be written quickly and then you have to clean up a lot of the technical debt as part of porting it.
Your assumptions about the compiler/interpreter, file system and so on often break across platforms, so you have to revisit and repair that code as part of the porting process.
Quoting from "The Practice of Programming" by Brian W. Kernighan & Rob Pike:
Finally, and most important, a portable program is a better program. The effort invested to make a program portable also makes it better designed, better constructed, and more thoroughly tested. The techniques of portable programming are closely related to the techniques of good programming in general.
The major issue with creating clean code is that clean code requires a _lot_ of discpline, at least for me. Of course, if I am fresh and going, creating clean code is easy. Extract a method here, Invert that if, move that around and so on and so on and all becomes nice and cute. But if I am tired and annoyed by the code, I really have to force myself to extract that one convoluted condition, to remove that duplication and such.
Furthermore, I have observed that a lot of my co-students often struggle enough with getting stuff to work, and once they got it to work, uh, it works and no one really pulls himself together in order to get it into a nice, readable form, again, "Because it works, and I have other stuff to do.
So much to say, I had to debug a number of stuff in their code, and just by cleaning up stuff, I found bugs. sigh
It's a shame that most of my Comp Sci peers don't seem to take much pride in actually building readable code. Building something that works is important, of course, but so is how it looks on the inside. Kind of analogous to building a house: sure, you can build something that keeps the rain off and the sun out in a relatively short time, but building it to stand the test of time is at least as important as keeping out the elements, if not more so.
I think coding assignments should also include style check/marking. A university should pick whatever standards out there and follow it for most of the situations. Preferably a standard that is used by the industry (For Java, follow SUN/Checkstyle, for C++ follow Google or some other open source project)
Students should write assignment code as if it's their professional job to do so even if they're not majoring in CS.
They should:
- Write unit-test (doesn't matter if they want to practice TDD or not, as long as when submitted, there should be minimum X unit-tests or so)
- Be given access to source code repository, and they have to write informative logs
- Write decent comments and learn how to use a template license at the top of their code (make all code GPL or BSD, doesn't matter, it's just an assignment and it's just a way to show them the importance of code license).
Yes, it sounds silly for just an assignment, but then again, they are students. Most of them needs to be taught/told.
And yes, sometime these things could be gamed as there is no hard-fast rule especially in terms or marking (i.e. subjectives), but the TA and instructor should mark them based on their effort (for the subjective parts)... even if it's just a checklist.
At least we're forcing a bit of a good habit to them.
For example, ask them to fix bugs in a prepared project with a number of subtle errors without unit tests and comments, then another project with good tests and comments. After that, when you give them a group term project, not only will they be graded by you according to the code standards you set, but their peers will demand and expect that they write the code well.
It is probably because they see it as a one off project that they will not need to look at in a year and they could care less about code readability and reuse.
Granted, you did not have this information from my original post, but this was a 1 year project with 13 people, and it was pretty sure that this project would be continued after the 1 year project.
But oh well. more refactoring fun for me, I guess.
Something that can happen is you keep to the standard of the current code when you start working on it, especially when something is contact freelance, no sense in undoing what is already there, just do the best you can to tack on what you need to.
One project I was working like this for a while, until it got to the point where it seemed I was going to be spending a lot of time on the code base. I was working around maybe 20% of the code that wasn't mine so I finally decided it would be worth the time to rewrite out the old bad practises.
Maybe it was a common utility function called from 4 applications that looked into 40 files to see if you had permissions to do something or to see if an operation was safe to do?
And the first if was copy/pasted across the entire app. So when you have to change the logic of that permission, you don't have a central, official, way of figuring it, instead you have checks all over the app.
Your assumptions about the compiler/interpreter, file system and so on often break across platforms, so you have to revisit and repair that code as part of the porting process.