You don't usually see people ( including me!) talk about their mistakes openly. But I think it is good to think about the mistakes we made in the past, so that we don't commit the same errors in the future.
I've been a professional programmer for about 5 years now. Like anyone else, I made mistakes along my way. Usually I didn't recognize the wrong thing I did right away; I only knew about the mistakes after being exposed to the correct ways of doing things. Hopefully after reading this post you would draw something useful from it and won't make the mistakes ( and pay the same price) as I did.
- Not using a proper ORM
Data Access Layer code is always messy, tedious and boring. I remembered when I was first doing a simple internal bookkeeping application, I was horrified at the amount of code I had to write just to get the basic plumbing done. So I started to plug away the ADO.NET and manually coded up a home-brewed-with-a-very-specially-customized-to-specific-table-schema ORM to serve my purpose.
A few months later there were some changes in the business requirements, and that cascaded into changes in table schemas, which led to a modification of my ORM, which was so painful that I discarded it all together and opted for strongly typed dataset adapter
For a while this thing actually worked. But still, I wished that I used a proper ORM ( such as NHibernate) for the job. At least I don't have to worry about changing database vendor when my users grow in numbers.
- Not learning generics soon enough.
I started my career as a programmer in .Net 1.1 days. The problem with .Net 1.1 is that it doesn't have generics support. As a result we couldn't have strongly typed list and could only be satisfied with the bland ArrayList. But using Arraylist, with casting and boxing all over your code is just painful to read and write. So we used CodeSmith to generate strongly typed collection list. But as the codebase grew those custom generated lists were becoming a monster on their own. Because I can modify the code easily, I often step in and change a method's behavior to suit my purpose, and that caused confusions and bugs later on.
I should have switched to .Net 2.0 and started to use generics as soon as it is available, instead of creating more and more custom collection lists that are simply unmaintainable.
- Reinvent the wheel
New programmers always like to reinvent the wheel: "The current implementation wasn't good enough for me so I have to rewrite the whole thing from the scratch". I once thought about writing my own UI controls because Windows Forms UI controls were just too unsophisticated for my use.
As we all know there are a lot of excellent .Net UI control tools available; my GUI tools were not as good as those commercial ones, of course. I was just too naive then.
- Too much documentation.
Code documentation is good, because it explains, in plain English, what your code is doing, right?
Wrong.
Documentation is often staled, outdated or downright wrong. I spent a lot of my time documenting my code ( XML documentation, remember?), only to find that I needed to update the documentation when I changed my code. Updating the code is a must, but updating the XML documentation isn't; it's a liability, it sucks time, and it serves no purpose. Eventually I ran out of patient changing the XML documentation and moved on to something else.
- No automated build
Application deployment and packaging are comparatively easier than programming, and so I put a very low priority on that. Soon, I was receiving complains from everyone the build wasn't working. "Prerequisites are missing, how to fix it?";"dlls are not updated, can you please send me a patch?";"Why the icons are running away?" and calls alike were reaching desk like avalanche.
At the end of the day I was worn out, not because of programming, but because of mind-numbing re-deployment and repackaging process. I could really "save" sometime from writing the automation scripts, but the time I wasted on fixing every errors and on supporting other people was many times more than what I could "save". Your software should be built at one click, more than that is a waste.
- Rely on visual inspection and debugging too much
It's so easy to come up a form and display your output. And Visual Studio is so powerful that one can easily step into the code and inspect the value on the fly. But debugger is harmful if you indulge into it too much. Imagine if your method will only get called after the application is up and running for 45 minutes, are you going to wait 45 minutes to reach that point and then only start debugging?
A better way is to break the application into sub-module that can be called independently. In this way you can just prepare the input that produces the faulty output and test it from there onwards.
- No unit test
I used to think that my application is trivial, that it can be easily covered by manual testing. Unit testing is for something big, and sophisticated and not for me. The outcome of this was the application grew into a monster, with no separation of concern, hard-to-refactor and completely unmaintainable code base. There was a point when I was afraid to make even the slightest modification to my code because any changes may or may no result in breaking changes. There were a few times when a mysterious problem suddenly surfaced out of nowhere, and the root cause was a breaking change I introduced a few months ago. Working with this kind of legacy code is not just boring and straining, but mentally stressing as well.
But with unit tests, life improves dramatically. I wish I could have learn the art of unit testing, and practicing unit testing starting from day one. It's a shame that the school doesn't teach unit testing.