Some invaluable tips for you.
Last week I watched some videos and read article from experts in computer science academia and software industry. I have skimmed some great programming wisdom and aggregated them in this article.
Program not Code
When you program, your job is to craftily solve problems, handle errors gracefully, use good component names and document the code. Programming also require programmers to find ways around the limitations of a language or ecosystem and improve them.
When you code, you are simply making things work and getting constantly annoyed by the shortcomings of the language constructs. Coding is a job of applying fixes and patches and disregarding the complexity.
Big Interfaces make weaker Abstractions
A class/object with too many methods make program bloated. Multiple methods for variations of same job is unnecessary. For example, when you create a class that converts a given decimal number to hexadecimal, binary, octal etc. you can write methods for every conversion or just one that accept a base value parameter and perform conversion for that base number. In later case, the interface is small but will lead to more implementations(usefulness) and lesser complexity.
// too many interfaces convert.toBin(10); convert.toHex(10); convert.toOct(10); // just one interface convert.to(10, 2); convert.to(10, 16); convert.to(10, 8);
A little copying is better than a dependency
Programmers move on from their code, its a proven universal fact. When the code base of a dependent package is not maintained regularly it increases the possibility of dependency hell. Sometimes our code does not even utilize a dependency completely. A clever move is to always copy some code to make up for the missing functionality instead of adding an extra node in dependency tree.
Errors are good, treat them like friends
Learning to program is more about learning to make mistake and then correcting them. A naive move that most of us make is to ignore errors. Generally when program throw errors, we fix them and move on. What should be done is to reinforce the occurrence of errors with helpful messages and documentations. Introduce errors to users as you would introduce a friend to your family. A simple
if (err) print(err) should not be the goto practice.
Use good Component Names and Comment the code
Naming is the single most underrated thing while programming. Names should describe the purpose of code. A good name can be sufficient to convey if the named entity was an object, variable, function etc. Naming itself can suffice documentation needs for small programs, but description of code in comments will make source code a heaven for future developers.
Use a style guide for code formatting
Lets get real, we don't like style guides, but they are awesome because they exist. Programmers talk through their code, and a style guide provides convention. Even if you hate them, you should care about future programmers and implement one.
Use a suited Programming Language
A programming language comes with its own ecosystem, which means you can include previously written code in your own, incorporate supported tools and get help from community. Any turing complete language can solve solvable computation problems, hence one language can indeed do the job of other. So, it is not a question of what a language can or cannot do, but how hard it can be to implement for a certain job? For example, when it comes to rapid debugging and human-friendly syntax, python wins but at the same time it is not suitable for game programming. Similarly C++ is a powerful OOP language for writing games but hard to use for front end web apps.
Orders of Ignorance
Our field is one that requires constant touch with on going research and experiments with latest tools and libraries. We can not only enjoy learning new things everyday but also get rewarded for it.
Learning software development is "knowledge acquisition activity". To acquire knowledge, we should know five orders of Ignorance as proposed by Phillip G. Armour.
0th Order Ignorance - Lack of Ignorance, I know how to do something and can display by lack of ignorance with some sort of output.
1st Order Ignorance - Lack of Knowledge, I don't know something but I know that I don't know how to do it and I know what I need to learn in order to be able to do it.
2nd Order Ignorance - Lack of Awareness, I don't know that I don't know something.
3rd Order Ignorance - Lack of Process, I don't know a suitable efficient way to find out I don't know that I don't know something.
4th Order Ignorance - Meta Ignorance, I don't know about the five orders of ignorance.
Once we know our orders of ignorance it becomes easy to work on them. For example, while building a software system 2rd and 3rd order of ignorance are most dominant. Knowledge of these orders also convey how serious can it be for us to solve a problem with programming.
This month I started to learn programming(again) by solving Brian Kernighan's C Programming Book, and I have found some alarming deficiency in my programming skills. I have been coding for past two and a half year. I have had always felt that something was missing in way I program. When my code fail I always look for "help" instead of a "solution". At first I used to think maybe I was lacking proper planning skills, but after through introspection I found that the problems were in my habits. I have learnt a lot by these tips. I hope it would be of help to you some day.
In regards to "Big Interfaces make weaker Abstractions", I disagree with your example - you have to balance it with clean code. "toHex" and "toOct" methods make more sense and is more readable than a signature of "to(value, radix)". The former doesn't require knowledge of the method's signature, the latter does to know that the second value is what base you're converting the number to.
However, I do agree with the point of the section.
Yeah its a terrible example, I agree. I was actually not going to include one because it'll take a separate article to explain what "weaker abstraction" mean. My idea for including that example was this: If you have a simple conversion program, you can make one method to convert a number to multiple bases, and then you can use it to write other methods to do more complex things like converting the converted number to string, long etc which would have then led to more implementations. But I agree, thats a poor example to explain the point, because of poor naming, and unclear code.
Hadn't read about the Five Orders of Ignorance before but it's a really interesting way of thinking. Definitely going to read more about it!
Hey, this was a pretty good read. Could you please elaborate on "Errors are good, treat them like friends" section? How to introduce them to users exactly? What do you mean by introducing them?
Thanks for sharing this. :)
I would like to mention one thing before you read this reply, in that point by user I did not meant "end-user" but the developers who will use our code in future.
Now, by saying that "treat them like friends", I meant that errors produced should themselves be enough to describe the problem. Like throwing a stack trace of error will exactly tell the developer where the problem occurred. When stack traces are reinforced with descriptive and helpful messages, it saves a lot of hassle for the developers to fix it.
For example, take good frameworks, almost all of them explain errors with helpful messages and links to official docs, stackoverflow questions, articles etc. on how users can fix them. Such thing is great but unfortunately not a common practice.
When I and likewise other beginner programmers work on projects, we often miss properly handling errors by just
if (err) throw err;. Specially if its a common issue that future dev working on it may come around, its a great idea to display some helpful messages and fix.