Ch. Reichenbach wrote:
(1) Re-use, and design for re-use (aka: abstract). Depending on whichever language you use, you might want to ask yourself whether the Skiplist you're implementing really has to be restricted to only containing character strings-- why not allow it to contain any kind of value? Or, when implementing a sort function, why focus on one particular order when you can just allow users to pass in the order they like?
Indeed, generic containers and sorting functions which can be passed arbitary functions to compare with are good examples of useful abstractions. But the art of building useful abstractions is an art of it's own. It's never a good idea to duplicate code, but too often one builds abstractions on top of abstractions, which finally result in a heap of code, which could be done with a few lines instead.
So generally, while abstractions and reuse are definitely good things, I would first write specific cases, and only when I see myself repeating the same pattern over and over again (sometimes twice is enough), I turn it into an abstraction instead.
Quote:
(2) Publish, and get criticised. Everyone's code sucks, but yours might get just a little bit better if you have to worry about being able to defend your particular implementation against other coders of similar experience.
Also be humble, and accept that somebody else might have a better implementation/design/whatever. Unfortunate as it is, it happens all too often. Also, remember that people often expect things to work in certain ways, without having actually tested them. It is not uncommon that simple experiment demonstrates that an "obviously inferior" implementation strategy actually outperforms the better one.
Quote:
(3) Don't be platform-specific unless your life depends on it. I wrote a couple of small games in Turbo Pascal for the 16 bit x86, and I was quite proud of them. Nowadays, not even the DOS/PC emulators can run them for various bizarre reasons. Don't let this happen to you!
It's also a LOT more fun to be able to show your programs to your friends, and when they look at them and say "WOW" you can then give them a version which runs on their favourite OS/platform.
Quote:
(4) Design APIs before writing code. I've found it very useful to force myself to think through the neccessary structure of a module (and to worry about where and how to encapsulate) before writing any code. Java's interfaces, C++' abstract classes, Haskell's type classes, O'Caml's module signatures etc. all allow you to completely separate interface from implementation-- even if you decide to stick with one implementation, trying to figure out the "what" before the "how" can do much good.
This is a double-edged sword. Designing API's is usually a good thing yes, but rarely is the API what you actually want to build. Generally, I think it's usually good to start from the projects real "core" features, experiment a bit with implementing them, try to find what are the interesting aspects, and then design an API that would implement it, then adapt your code to your API. Then add other features, extending your API as you implement more code.
I'd say, plan your API's for extensibility, but don't specify APIs which you aren't going to implement right now. Otherwise you find something related to the problem of too many abstractions.
Quote:
(5) Use meta-programming and/or domain-specific homebrew languages where needed, and there only. Sometimes you're faced with very high-level or meta-programming-ish tasks ("let's find a way to serialise all our C data structures") that the programming language you are using does not allow you to express directly. Try to see whether you can reduce the particular problem to a small set of primitives, and whether you can write a code generator (or a couple of macros) allowing you to express your intentions concisely.
I'd like to add here, that if you are using a code-generator, NEVER modify the generated code manually, always modify the generator (or it's source) instead!
Quote:
(For this, I don't consider templates to be part of the type system; if I'm not mistaken, I'm in agreement with C++ there).
Indeed, C++ templates are a language of their own, last I checked they where turing complete.... avoid them, unless you are fairly comfortable in writing your own Lisp-compilers (or something similar).