In the course of over ten years of hacking on so many varied types of things it is hard to truly grasp, even for me, I have come to learn many important lessons about programming. Most of these things are specific to given problems types, but there are a few which have more to do with how you look at problems than anything else. So to kick start this series here are some things I learned the hard way, and had I known sooner, would have saved me many many headaches and pointless tail chasing.
On learning a new API
- Documentation is your friend, but should never be considered the sole authority.
- Other people can sometimes be of use, but should never be relied on to know more than you.
- When you don’t know, and the documentation is incomplete, the first stop should be the source itself.
- Even when the documentation is fairly complete, the source should still be a primary resource
- Bite Size Chunks – don’t try to learn everything at once.
- Further – Don’t wait until you know the whole system before you start using it.
- But – don’t avoid large code bases just because they are large.
- Google is Your Friend.
- Wikipedia is too.
- When dealing with an open source API – it is not the maintainers job to answer all the questions of any programmer who happens to use it. Nor should you expect them too. Their job is to maintain the source, not explain it.
- Assume any problem is your fault.
- or – Don’t blame the system, the developer, the maintainer, or the guy next door for every problem you face, until you know the API so well you can be sure you are right – and still keep the option that you are wrong open for consideration.
- It will always take longer than you want/expect
To really expand these, the biggest most frustrating thing for anyone learning a new API is lack of knowledge. In a large number of the cases, no matter what problem you run into at least some of it is simply your lack of understanding of the system. If you are learning a new system you are facing all manner of seemingly insurmountable odds, and the only way you can be sure you will surmount them is by taking things one step at a time, looking first at the documentation, then examples, trying to code with what little you know, using the source/headers, documentation, and google/wikipedia as your constantly open companions.
Some people try to keep their learning nice and clean, look at one API, one example, and sequentially build examples one at a time. This can be useful, but ultimately you aren’t learning the api, so much as learning how to ape it – which means when problems come up they are that much more obscure, because you don’t really understand what you are doing in the first place or why it works when it does, much less why it doesn’t when it doesn’t. In my experience, the absolute best way to learn an API is to dive in and USE it, and have every possible resource you can find open and on hand for you to switch between them all as you go. And when you have a problem you try and solve it. In most cases you need to understand the API to use it, aping the motions isn’t enough, because you will hit bugs, and you can’t safely debug a system you don’t understand.
But ultimately – don’t expect to be spoon fed, and don’t run away from large systems. You want to know how an API really works? If you are dealing with a public API, find a big open source source code base and really look at it, try and understand how it is using the API. Will it be daunting at first? Probably. Will it be far more than your needs? Almost certainly. But any problem you might face, the big projects already have. And if you aren’t willing to look in the dictionary for the definition of a word just because there are so many other words in it you don’t need, you are never going to learn anything at all.
On Writing new Systems and APIs -
- Documentation is your friend, and should not be considered a problem for someone else.
- If you don’t document it now you will be the confused developer in a few years (or tomorrow) wondering what idiot wrote this code.
- Always use comments – they help you keep track of the code, and make it easier to read.
- But avoid excessive comments – they clutter the code, and make it harder to read.
- Don’t obsessive over private/internal frameworks/classes/functions, etc – you can, and will, change your mind later anyway
- Consistency is key, but it can’t come first.
- Don’t be afraid to change a bad api,
- If you change a public API, make sure you maintain a backwards compatibility wrapper.
- Avoid breaking ABI if at all possible – and it usually is
- Don’t try and rewrite every bad api in your system all at once - Iterative improvements when possible, will always be safer, and keep you saner.
- Plan ahead.
- Don’t try and plan for every contingency.
- Always plan for the possibility you forgot/overlooked something
- You will always overlook something.
- Don’t duplicate something someone else has already done if at all possible.
- Don’t avoid writing something just because someone else has already done something similar.
- Naming should be obvious within the context of the system – obscurely named classes/functions/parameters/variables don’t help anyone - least of all you.
I could keep going, but expanding on these. Writing a good api, should reflect the problems of learning one, and that means even when documentation is incomplete, the API itself should be semi-self documenting, if it isn’t you yourself will be stuck with a system you probably don’t remember, and thus can’t even easily change. Similarly, comments are good – but too many is bad. For an example of this, when your comment ratio starts to approach one or more per line of code, you probably are going overboard. More, if you need that many, your code isn’t self-documenting enough.
Realistically a good api should read kind of like prose, maybe ugly prose, but still self-describing. For this reason, when possible, methods should avoid unnamed or less than self-describing – think foo(true, false, false, true, 1) – parameters. In systems like Cocoa, this is easy, because you can literally provide the name as part of the signature. you require the argument names to call the function. For other systems it isn’t always so easy, Carl Worth of cairo for example, has made a strong stance in api development for C, to always use named enum’s whenever possible, instead of bitmasks, or boolean flags – this makes for bulkier calls, but they will be far easier to understand and use from a self-documenting standpoint.
When it comes to duplicate/not duplicating code, this is a hard issue – you should try to use a common system API whenever one is available. But when and when not to use third party api’s is always a lot more challenging, because -
- what about future compatibility with the system
- what about feature completeness for your code
- what about future maintenance of the third party system.
In general you shouldn’t be afraid to use any third party api – but you shouldn’t be afraid to make your own even if one exists either, so long as you keep in mind that you shouldn’t try and duplicate just for the sake of doing it yourself, and remembering that if it is a linked api, it is now a hard dependency of your stack.
There are many times you only need a fraction of what an api provides, and it doesn’t make sense to depend on the whole stack. Sometimes it does. But don’t be afraid to go either direction, just be logical about it. Be sure why you pick the route you do – and don’t let laziness, or ego, be the driving factor.
In General
- Frustration is inversely proportional to your ability to think rationally
- Frustration usually comes from impatience when faced with a non-obvious problem
- Impatience is the bane of all coding – be it your impatience, or someone else’s
- Learn to walk away, both physically and mentally
- You will spend most of your time debugging – no matter how well your know the system
- Debugging involves logical process, as much as intuitive leaps
- When something goes wrong, scan the code, and iteratively check everything
- No really - everything
- Always Test every single thing until you find the problem, or you intuit it
- Sometimes the hardest problems to find, are ones you miss because you are so certain it can’t be there
- Never rely on the compiler/framework to prevent your mistakes
- A compiler can’t prevent you from being an idiot. No matter how strict the typing, or fancy the GC
- Creativity involves both logical consistent boundaries and the willingness to to ignore them
- Anything is possible – whether or not it is a good idea.
- Be willing to adapt to new paradigms, and coding styles – even if your way is better. There is a lot of code in the world, and very little of it is yours. Even if you wrote all of mozilla by hand, from scratch.
- Sometimes your way isn’t so much “better” as “obscurely clever” – and obscurely clever isn’t always better. Sometimes it is just obscure.
- Obfuscation can be fun, but is never a good idea for serious projects
- If it is “clever” or “elegant” code – it is probably completely indecipherable and/or unmaintainable
- Short simple code, is always easier to read, and maintain, than large complex functions
- Divide and Conquer. Both in learning, and in coding
- Just because you can do it with a single RegExp, doesn’t mean you should. In fact it probably means you shouldn’t
- Common advice but always good – don’t optimize until your system is already functional. No really. Not even then. NEVER. not then either. seriously. you will always regret it. Or whoever has to clean up after you will.
- Sleep on it .
- Sometimes an all night hack session results in amazingly brilliant code. But more often it results in an amazingly brilliant, obscurely clever, simply elegant pile of useless that you will spend most of the next week recovering from.
- Some form of Version Control is your BFF. Seriously. Even… No, especially for private code you never ever share.
I have more, but I think that is enough for now, and since I don’t think I need to summarize most of these. I think I shall end this now.
Coming up next – No idea! But the next set of entries will probably be more specifically about problems I faced, than a general list like this.