1) Use the best language you can get away with. This means using a language that eliminates entire classes of run-time errors via some or all of:
a) Strong typing
b) Static typing
c) Managed memory
d) Immutable data
2) Assume that your code will be maintained by somebody who doesn't know your programming language as well as you do.
3) Use static and dynamic assertions liberally.
4) Ease debugging. Have great formatted dumps of your internal data structures, great internal consistency checking, and great logging. Automate problem isolation, too: for example, in an optimizing compiler, at each point where a discretionary change is about to be made, call a function that logs the change, increments a counter, and returns false if the counter is past a limit that you can set in the environment; this allows an automated bisection analysis to immediately find the change that broke a test program.
5) Regression tests. Once you fix a bug, make sure that your test suite will notice recrudescence.
I'd add
7) Try not to make the same bug/mistake twice.
One of the most important things I learned from chess was to go back over your previous games and look for what mistakes you made, why you made them, and how you can avoid them next time.
Do this same analysis with every BUG you see a bug in your code(whether you wrote it or not). Ask yourself why you or someone else make this mistake? What is because they a assumed a method did something it didn't? Was it because the domain logic wasn't in a single easy to find place so they reinvted the wheel and did it incorrectly?
> When something went wrong, I'd reflexively start to dig in to the problem, examining stack traces, sticking in print statements, invoking a debugger, and so on. But Ken would just stand and think, ignoring me and the code we'd just written. After a while I noticed a pattern: Ken would often understand the problem before I would, and would suddenly announce, "I know what's wrong." He was usually correct. I realized that Ken was building a mental model of the code and when something broke it was an error in the model. By thinking about how that problem could happen, he'd intuit where the model was wrong or where our code must not be satisfying the model.
This was my first thought, as well. It's hard to think when you're staring at the blinking cursor. Spending a little bit of time with a pen and a napkin works wonders for design and reduces the number of times you'll have to hack in fixes for cases you didn't consider.
I agree. While still learning to code, I discovered this aphorism myself when the thought dawned on me that contrary to my previous practice, the programmer thinks for the computer and not the the other way round.
1) Always write code for someone else. And you don't know who it is.
2) Write tests not only to prove correctness, but also to test whether code as an interface makes sense.
3) Be defensive as much as possible. Each additional check / assertion helps to avoid accidental bugs or can help to find them early.
4) Speak about code as much as possible. If you can explain code in your own words and discuss it with someone else, code gets raised on a philosophical level and may end up to be elegant and logical for others.
6) Read lots of code. The more of other people's code that you read the faster you'll learn good practices.
7) Work with other people that are better/more experienced than you.
8) Code reviews are your friend. When I was at Google, the best way to learn and teach good coding practices and libraries were through the code reviews that we had. Get in the practice of reviewing other people's code and having others review your code.
9) Test, test, test! It may sound counter intuitive, but if you want to increase coding velocity, write tests. Tests upfront will save so much time in debugging later on.
1) Always write code for someone else. And you don't know who it is.
-- similarly: "When I come back to this in a few years after not touching this code, will I understand it?"
Go read open source libraries. I started out barely knowing anything in Javascript and I had terrible code, as almost any dev could say. However, I was never afraid to follow the debugger through the code of the libraries I used. At the time these were things like Backbone and Marionette, which have incredibly clean and well documented code.
Find a library you use and have a feel for how it works, and read through their code. If you run into questions about why something is done a certain way, they'll tell you! Use git blame and see what the commit message was for those lines! Often there will be a description or issue tied to it and you can figure out the thought process they used. Then just start applying similar thinking to problems you encounter.
Don't get cute. Code golf is for competitions, not production code. Even if something takes 10 lines that you can do in 1, if 10 lines is clearer, do it that way (you'll thank yourself in 6 months when you have to figure out what you were doing).
Keep your functions to one or two pages.
Keep your nesting to three levels, preferably two. If you have multiple nested if/while/for sections, break them up. (See: "cyclomatic complexity").
Follow the coding conventions of the project you're working on, even if you disagree with them, consistency is more important.
> Don't get cute. Code golf is for competitions, not production code. Even if something takes 10 lines that you can do in 1, if 10 lines is clearer, do it that way (you'll thank yourself in 6 months when you have to figure out what you were doing).
Brian Kernighan put it well: "Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?"
When I encounter functions that large, where the body isn't almost entirely declarative, they tend to be doing way too much. A function longer than 10 lines is a smell, IMO.
I struggle with this. I don't necessarily write a lot of one-liners, but recently I solved a document parsing problem using regex, list comprehensions, zips, etc; generally what are considered "clever" language features to my peers.
The problem-solving approach seemed straightforward enough: match labels, slice document, destruct into keys and values into separate list, transform into proper formats and eliminate errors, combine into list of tuples. I could repeat this pattern because the document was structured hierarchically.
On one hand, I believe that by using these methods I've written code that is maintainable and less sloppy, and reflects the strongest understanding of the problem. I personally find these language features empowering when I solve the problem.
On the other hand, because these features are not the simplest features, the learning curve for interpreting the code is higher. I didn't use any obfuscation methods to compress the code, but neither did I apologize for the usage of the above.
What I wonder is: if we don't try to leverage higher-level language features, do we end up defaulting to a brute-force approach with is less contained and raise technical debt?
You could hedge around this through liberal commenting, but I find it difficult to believe that avoiding thinking about the problem as being too "clever" is much better. Somewhere there must be a compromise.
You have to be clever sometimes, take strlen in C you could do byte at a time which a compiler will vectorize or you could do SWAR with some fancy bit hacks and get a large perf boost.
I see study open source code and read good code, but what I think is more effective is contribute more to open source. Coding is one of the few professions in the world where some of the leading experts give away great samples and advice on a regular basis in the form of open source. Start an open source project for a need you have or submit a PR for something you've always wanted in a project you've used. Generally the comments on PR's are a great place to learn about ways people think through problems and how they're implemented.
My best piece of advice if you take this road though is that you need to check your ego at the door. The only way to truly learn to be better is to take criticism learn from it and keep moving forward.
Don't be afraid to submit PR's because of scrutiny because it will only prevent you from learning.
In my experience as a dev the solutions that you think are so simple and maybe even hacky sometimes turn out to be just steps away from a far more elegant solution than anyone else has thought of and you're hurting yourself and in many cases others by not sharing or by being too timid to share and willing to open yourself up and put yourself out there
0/ Work with other developers, ideally next to them, on the same project. Learn from them no matter you think them "good" or "bad".
1/ When given the choice between making something exist and making it not exist, lean toward the latter. ie. Minimize Everything. Remove everything that can be. Things must earn their right to exist.
2/ Choose the best names you can come up with. If you can't find a good name for something, there is a chance it shouldn't exist. There are books about this.
3/ Code should enable things, not be a problem itself. Make it the easiest to maintain and understand above all other criterion. Code like you have an audience that will be reading that code while not really caring regardless. You can't expect the maintainer to care as much as the writer, it would be impolite to do so.
4/ Think a lot about what things should be splitted in two concepts, and what concepts should be merged into one. Iterate designs until they seem impossible to enhance. If it feels wrong it is probably wrong.
5/ Recognize your weak parts and improve them, not only those that are good already.
6/ Don't confuse input errors and bugs.
7/ Create the right abstractions if necessary and at the right level. Lean toward "no abstraction" if you're unsure of the best design yet.
8/ Forget everything systematically. If you need to remember something, find a way not to have to. You need all your neurons to learn new things constantly.
9/ For the hasty: work on legacy systems. This is the "hardcore difficulty" level of programming. Do some parsers.
10/ Don't give a name and reify everything, in fear it would become a topic of mental activity. Example: since users will report the biggest problems the most, maybe there is no need to record every last user wish. If a task is faster than to record it in the todo-list, make it right away, etc.
This was definitely the most influential experience of my software career. Being one of 5 devs that maintained a 5 million LOC montrosity was a hell of an education.
Less is more -- Keep the lines of code down to a minimum in a single function/method. Its name should say what it does and it should only do that one thing. Also, you should always look for code to remove/refactor to minimize its function to singular actions.
Avoid complex statements or crazy one liners when it would be better understood by 80% of developers if you just put it in a simple if statement or broke it up into 2-3 lines. Break up algorithms this way with good comments too.
Experiment with small pieces of code before committing to a specific design if you are unsure. I have quite a bit of experience and will still write small test programs all the time to test out an idea before I try it in my main code base. This lets me make sure I got my idea (and implementation) correct in the simplest form before trying to put it into a larger more complex codebase.
Don't start optimizing in places you don't know you have an issue. Write it out like you want first, then optimize later when you find it is an issue.
Don't try to "future proof" your code, no one can predict the future and writing extra code to handle what might happen is basically torture, both to yourself and the person that has to remove it all later cause your assumptions were wrong. Not to mention, this is where I find the most errors in code.
Learn data structures well, and use them properly. It drives me nuts to see how badly people abuse data structures and misunderstand their benefits and drawbacks. But see my last point too.
My personal pet peeve, don't assume the person before you did it wrong or was an idiot until you can prove it. Generally devs do something, even if it is not ideal, for a reason. Be it, business changing requirements at the last minute, or schedule crunch or a lack of domain knowledge. But before you call them an idiot or assume they were wrong, try to figure out what they did and understand why they might have done it. I have seen a lot of code get changed by new comers only to find out it was written that way for a specific use case that they just didn't understand yet. Then shit breaks, people get upset and the whole team gets frustrated.
I generally agree with this comment, but wanted to pull out one nugget in particular:
> don't assume the person before you did it wrong or was an idiot until you can prove it.
Heh, I don't want to count the number of times I've looked at a line of code and snarled about how stupid it was... just to git-blame and find out that I wrote it. Nothing will break you of the habit faster than maintaining your own code.
I agree with you on the last point. Humility and assuming best intentions works very well in all settings, but especially in legacy code. I withhold judgement on everything I see now. It took a bit of time and a few instances of eating crow to get there.
Think really hard about the problem you are solving.
First question to ask is always: Do I need to write some code or I can solve this problem using tools already here?
If you decide to write code, then start to think really hard.
What interface should I provide? The smallest the interface the better; and be aware that any kind of configuration your interface use increase exponentially the size of the interface itself.
Now you should experiment, take your time and be sure that the interface you are providing is the smallest possible, try to see the problem from another point of view, don't be afraid to throw away code (don't write test yet if not for experimental purpose, you don't even have the interface to test) and try to keep everything stateless and pure.
During this process is important to gather feedback from your peers, they may see problem that you don't.
Once you have decided what you are going to code, write it down.
Try to keep everything so simple that test will seems pointless, write those anyway.
Be slow, take your time for thinking, don't be afraid to throw code away.
Deliver real, end-to-end working functionality, at least every two weeks and ideally more frequently. Unless and until the code is used it's all meaningless. This more than anything will protect you from overengineering or building the wrong thing, which are the biggest dangers.
Delay design decisions as late as possible. Unless and until you need to make a decision to allow you to deliver some real functionality, don't make it. Avoid any planning of things like code structure. This will give you the chance to make better decisions, since you'll have more knowledge at the point when you make them.
Reduce the number of lines of code. People will say that other things are more important, that making the code longer can sometimes make it more readable. That's an intuitive view, but in my experience it's wrong. Reduce the number of lines of code, and everything else - good design, good code structure, good language choice - will follow.
Not writing code until it was _absolutely_ needed would have saved literally months of my working life, and I haven't been working all that long. Business requirements change constantly, so what you think will be needed probably won't be by the time you ship the code.
Continuously refactor your code to remove duplication (See Don't Repeat Yourself / DRY). If you find yourself copying and pasting boilerplate code over and over, it's probably time to refactor, otherwise you find one bug and have to fix it 20 times. Good testing helps you to refactor fearlessly because the tests will tell you if you screw up.
Whatever happens you'll always cringe reading old code - but see the positive, it just shows that learning is a continuous process and that you are now older and hopefully wiser than you once were.
One thing that's been on my mind lately is an old article by Joel Spolsky [1] about accurate estimating. I'm absolutely terrible at estimating but I'm using Joel's method to improve that. Better estimates mean better code. Why? Because if you estimate 1 day for a task that really takes 2 days, you'll be rushing, stressed and tempted to cut corners by the start of day 2. If you've planned 2 days for it, you can use the time more effectively.
This is the most important thing: "Unless and until the code is used it's all meaningless."
The risk of writing perfect unused code is significant, and the consequences are pretty grave. I think worrying about how "good" your code is should be secondary to worrying how usable your code is.
Yes, maintenance & debugging can really suck. But optimizing to make maintenance & debugging better won't serve your users well if your code never launches.
Learn how to type well (>30wpm). Literally everything else is secondary. You don't have to be the fastest or most accurate typist, but not having to look at the keyboard while typing pretty quickly and accurately is foundational.
Not having to use the mouse for common tasks (closing a window, switching applications, etc...) is another core skill.
Everybody else's comments focus on important stuff but I've seen programmers absolutely hobbled by not having these basic skills.
I'm still fairly green to the trade (1 yr in as a jr dev) but as best as I've been able to determine the best thing I have done is simply read a lot of code.
Reading code from people who are just getting started gives you perspective of how far you've come (hopefully). You can also use this to help people out fairly effectively.
Reading code from people who are more experienced is good for getting styles down while maintaining the context of where certain practices are acceptable.
Switching languages is also advantageous in that you can (hopefully) identify why different languages have different stylistic practices. This works better if the syntax of the language is pretty distinct - so C# to Java wouldn't be excellent at this. But C# to Python is great at it.
Of course writing code helps - especially if you can convince someone else to read that code and give some meaningful feedback!
Stick around on a codebase that's used by real people.
Most of the lessons about programming I learned by designing and coding sets of features, shipping them, and then being the one handling all the bug reports and feature requests. Performance tuning, defensive coding, debugging technique, ui design, codebase architecture, developer team coordination, ... the list of things to be learned by sticking around for the long haul is endless and hard to replace with book smarts.
1) "Overview and Zoom" is a common UI technique where you give an overview and then let a user click on stuff for more detail. In programming, this means writing the "intention" as a method that's very easy to read, then have a bunch of helper functions with the details. This also forces you to only use one level of abstraction per method.
2) Only have one thing happen per line. This forces you to give what you're doing a proper name (as a variable assignment before you use it). This makes it easier to read, but makes all text processing tools work much better with your code. Nothing is more annoying than seeing a diff in a pull request where one line changes, but there are 10 things happening in that line and only one changed.
Don't waste time trying to learn and develop style. Don't waste time studying other code just for the sake of learning how to write better code. Don't waste time reading generic things on how to write better code.
Put the effort in to learning new concepts, programming languages, methodologies, programming language history, computer science, and even broader subjects dealing with humans and how we think and form ideas. There are countless ways to write code and without having a broad knowledge of them you will only at best reach a local optimum and rarely choose the most effective solutions and designs. The worst thing you can do is stop learning and seeing other perspectives.
Intentionally build a style. Keep it stable for a period of time. Finally critique and improve it.
You often hear "The worst code I have ever seen is code I wrote six months ago" While on the one hand that may be true, on the other hand it is trite bullshit. If the depth of your introspection and reflection on past code is "Wow what a pile of shit!". Guess what you are going to be saying about your code in six months?
With a real honest critique you will see flaws and things that you did well. Don't just dwell on what doesn't work. When you see things in your code that work well try to figure out why they work well so that it can guide your deliberate changes to what doesn't work. Also if you don't keep your style constant for a period of time you won't have enough experience with it, nor a large enough body of code to review to have a full view of what works and what doesn't.
Last but most important read the code of others to pick up ideas on how to improve your style of coding. Some of the best bits of my coding style I have picked up from others.
Write a lot of code, continually rewrite it for the dumbest version of yourself.
Writing code should be highly iterative, and learning to code is as well. The more you write the better you get, and the more you will realize how crappy your old code is. Refactoring should be constant to keep the complexity and amount of code to a feasible minimum.
So, now and again, look over the code you've written, does it seem a bit overwhelming complex, are methods starting to feel bloated? Does some new feature or concept feel artificially grafted on? Then sit down and try to figure out the best way to refactor it into something more streamlined and manageable.
A good way to realize how bad one's code is to take a few weeks break from it, and if when you return you have trouble understanding the full scope of it it's time for a rewrite :)
Be sure to dedicate some time to sharpening your saw, researching new tools, technologies etc. It's easy to do something just because it's the "way I know to do it" rather than putting in the time to learn a better way.
[+] [-] pklausler|9 years ago|reply
1) Use the best language you can get away with. This means using a language that eliminates entire classes of run-time errors via some or all of:
2) Assume that your code will be maintained by somebody who doesn't know your programming language as well as you do.3) Use static and dynamic assertions liberally.
4) Ease debugging. Have great formatted dumps of your internal data structures, great internal consistency checking, and great logging. Automate problem isolation, too: for example, in an optimizing compiler, at each point where a discretionary change is about to be made, call a function that logs the change, increments a counter, and returns false if the counter is past a limit that you can set in the environment; this allows an automated bisection analysis to immediately find the change that broke a test program.
5) Regression tests. Once you fix a bug, make sure that your test suite will notice recrudescence.
6) Don't hire or retain sloppy programmers.
[+] [-] sidcool|9 years ago|reply
Also, your first three points puts Ruby pretty much out of the picture.
EDIT: Mentioned Ruby because that's what I am working on right now, after Java and Scala
[+] [-] JamesBarney|9 years ago|reply
One of the most important things I learned from chess was to go back over your previous games and look for what mistakes you made, why you made them, and how you can avoid them next time.
Do this same analysis with every BUG you see a bug in your code(whether you wrote it or not). Ask yourself why you or someone else make this mistake? What is because they a assumed a method did something it didn't? Was it because the domain logic wasn't in a single easy to find place so they reinvted the wheel and did it incorrectly?
[+] [-] ArkyBeagle|9 years ago|reply
And for 4) - don't be afraid to build instrumentation into the code base to support decisions about correct operation.
[+] [-] dazzawazza|9 years ago|reply
It's stood the test of time, I've passed it on to many juniors.
[+] [-] collyw|9 years ago|reply
[+] [-] 0xfaded|9 years ago|reply
http://www.informit.com/articles/article.aspx?p=1941206
[+] [-] lmm|9 years ago|reply
[+] [-] mbauman|9 years ago|reply
[+] [-] Lordarminius|9 years ago|reply
I agree. While still learning to code, I discovered this aphorism myself when the thought dawned on me that contrary to my previous practice, the programmer thinks for the computer and not the the other way round.
It may seem banal but it has helped me a lot.
[+] [-] einrealist|9 years ago|reply
1) Always write code for someone else. And you don't know who it is.
2) Write tests not only to prove correctness, but also to test whether code as an interface makes sense.
3) Be defensive as much as possible. Each additional check / assertion helps to avoid accidental bugs or can help to find them early.
4) Speak about code as much as possible. If you can explain code in your own words and discuss it with someone else, code gets raised on a philosophical level and may end up to be elegant and logical for others.
5) RTFM & RTFS(pecs)!
[+] [-] Johnie|9 years ago|reply
6) Read lots of code. The more of other people's code that you read the faster you'll learn good practices.
7) Work with other people that are better/more experienced than you.
8) Code reviews are your friend. When I was at Google, the best way to learn and teach good coding practices and libraries were through the code reviews that we had. Get in the practice of reviewing other people's code and having others review your code.
9) Test, test, test! It may sound counter intuitive, but if you want to increase coding velocity, write tests. Tests upfront will save so much time in debugging later on.
[+] [-] StrykerKKD|9 years ago|reply
2) You can't prove correctness with tests. You can only state that it ran correctly for that test case(s).
[+] [-] voiper1|9 years ago|reply
[+] [-] mpolichette|9 years ago|reply
Find a library you use and have a feel for how it works, and read through their code. If you run into questions about why something is done a certain way, they'll tell you! Use git blame and see what the commit message was for those lines! Often there will be a description or issue tied to it and you can figure out the thought process they used. Then just start applying similar thinking to problems you encounter.
[+] [-] hvs|9 years ago|reply
Keep your functions to one or two pages.
Keep your nesting to three levels, preferably two. If you have multiple nested if/while/for sections, break them up. (See: "cyclomatic complexity").
Follow the coding conventions of the project you're working on, even if you disagree with them, consistency is more important.
[+] [-] tzs|9 years ago|reply
Brian Kernighan put it well: "Everyone knows that debugging is twice as hard as writing a program in the first place. So if you're as clever as you can be when you write it, how will you ever debug it?"
[+] [-] 0xfaded|9 years ago|reply
[+] [-] eyelidlessness|9 years ago|reply
When I encounter functions that large, where the body isn't almost entirely declarative, they tend to be doing way too much. A function longer than 10 lines is a smell, IMO.
[+] [-] bordercases|9 years ago|reply
I struggle with this. I don't necessarily write a lot of one-liners, but recently I solved a document parsing problem using regex, list comprehensions, zips, etc; generally what are considered "clever" language features to my peers.
The problem-solving approach seemed straightforward enough: match labels, slice document, destruct into keys and values into separate list, transform into proper formats and eliminate errors, combine into list of tuples. I could repeat this pattern because the document was structured hierarchically.
On one hand, I believe that by using these methods I've written code that is maintainable and less sloppy, and reflects the strongest understanding of the problem. I personally find these language features empowering when I solve the problem.
On the other hand, because these features are not the simplest features, the learning curve for interpreting the code is higher. I didn't use any obfuscation methods to compress the code, but neither did I apologize for the usage of the above.
What I wonder is: if we don't try to leverage higher-level language features, do we end up defaulting to a brute-force approach with is less contained and raise technical debt?
You could hedge around this through liberal commenting, but I find it difficult to believe that avoiding thinking about the problem as being too "clever" is much better. Somewhere there must be a compromise.
[+] [-] ScaryRacoon|9 years ago|reply
[+] [-] bbcbasic|9 years ago|reply
[+] [-] heurist|9 years ago|reply
[+] [-] nwmcsween|9 years ago|reply
[+] [-] zbruhnke|9 years ago|reply
My best piece of advice if you take this road though is that you need to check your ego at the door. The only way to truly learn to be better is to take criticism learn from it and keep moving forward.
Don't be afraid to submit PR's because of scrutiny because it will only prevent you from learning.
In my experience as a dev the solutions that you think are so simple and maybe even hacky sometimes turn out to be just steps away from a far more elegant solution than anyone else has thought of and you're hurting yourself and in many cases others by not sharing or by being too timid to share and willing to open yourself up and put yourself out there
[+] [-] p0nce|9 years ago|reply
1/ When given the choice between making something exist and making it not exist, lean toward the latter. ie. Minimize Everything. Remove everything that can be. Things must earn their right to exist.
2/ Choose the best names you can come up with. If you can't find a good name for something, there is a chance it shouldn't exist. There are books about this.
3/ Code should enable things, not be a problem itself. Make it the easiest to maintain and understand above all other criterion. Code like you have an audience that will be reading that code while not really caring regardless. You can't expect the maintainer to care as much as the writer, it would be impolite to do so.
4/ Think a lot about what things should be splitted in two concepts, and what concepts should be merged into one. Iterate designs until they seem impossible to enhance. If it feels wrong it is probably wrong.
5/ Recognize your weak parts and improve them, not only those that are good already.
6/ Don't confuse input errors and bugs.
7/ Create the right abstractions if necessary and at the right level. Lean toward "no abstraction" if you're unsure of the best design yet.
8/ Forget everything systematically. If you need to remember something, find a way not to have to. You need all your neurons to learn new things constantly.
9/ For the hasty: work on legacy systems. This is the "hardcore difficulty" level of programming. Do some parsers.
10/ Don't give a name and reify everything, in fear it would become a topic of mental activity. Example: since users will report the biggest problems the most, maybe there is no need to record every last user wish. If a task is faster than to record it in the todo-list, make it right away, etc.
[+] [-] JamesBarney|9 years ago|reply
This was definitely the most influential experience of my software career. Being one of 5 devs that maintained a 5 million LOC montrosity was a hell of an education.
[+] [-] bbcbasic|9 years ago|reply
[+] [-] davismwfl|9 years ago|reply
Avoid complex statements or crazy one liners when it would be better understood by 80% of developers if you just put it in a simple if statement or broke it up into 2-3 lines. Break up algorithms this way with good comments too.
Experiment with small pieces of code before committing to a specific design if you are unsure. I have quite a bit of experience and will still write small test programs all the time to test out an idea before I try it in my main code base. This lets me make sure I got my idea (and implementation) correct in the simplest form before trying to put it into a larger more complex codebase.
Don't start optimizing in places you don't know you have an issue. Write it out like you want first, then optimize later when you find it is an issue.
Don't try to "future proof" your code, no one can predict the future and writing extra code to handle what might happen is basically torture, both to yourself and the person that has to remove it all later cause your assumptions were wrong. Not to mention, this is where I find the most errors in code.
Learn data structures well, and use them properly. It drives me nuts to see how badly people abuse data structures and misunderstand their benefits and drawbacks. But see my last point too.
My personal pet peeve, don't assume the person before you did it wrong or was an idiot until you can prove it. Generally devs do something, even if it is not ideal, for a reason. Be it, business changing requirements at the last minute, or schedule crunch or a lack of domain knowledge. But before you call them an idiot or assume they were wrong, try to figure out what they did and understand why they might have done it. I have seen a lot of code get changed by new comers only to find out it was written that way for a specific use case that they just didn't understand yet. Then shit breaks, people get upset and the whole team gets frustrated.
[+] [-] falcolas|9 years ago|reply
> don't assume the person before you did it wrong or was an idiot until you can prove it.
Heh, I don't want to count the number of times I've looked at a line of code and snarled about how stupid it was... just to git-blame and find out that I wrote it. Nothing will break you of the habit faster than maintaining your own code.
[+] [-] ctvo|9 years ago|reply
[+] [-] jacquesm|9 years ago|reply
And yourself, 6 months down the line.
[+] [-] siscia|9 years ago|reply
First question to ask is always: Do I need to write some code or I can solve this problem using tools already here?
If you decide to write code, then start to think really hard.
What interface should I provide? The smallest the interface the better; and be aware that any kind of configuration your interface use increase exponentially the size of the interface itself.
Now you should experiment, take your time and be sure that the interface you are providing is the smallest possible, try to see the problem from another point of view, don't be afraid to throw away code (don't write test yet if not for experimental purpose, you don't even have the interface to test) and try to keep everything stateless and pure.
During this process is important to gather feedback from your peers, they may see problem that you don't.
Once you have decided what you are going to code, write it down.
Try to keep everything so simple that test will seems pointless, write those anyway.
Be slow, take your time for thinking, don't be afraid to throw code away.
[+] [-] yitchelle|9 years ago|reply
This is really good advice. Also think really hard about what is the real problem you are trying to solve and only write code to solve that problem.
The oxymoron is the best code you write is the code that you did not write.
[+] [-] lmm|9 years ago|reply
Delay design decisions as late as possible. Unless and until you need to make a decision to allow you to deliver some real functionality, don't make it. Avoid any planning of things like code structure. This will give you the chance to make better decisions, since you'll have more knowledge at the point when you make them.
Reduce the number of lines of code. People will say that other things are more important, that making the code longer can sometimes make it more readable. That's an intuitive view, but in my experience it's wrong. Reduce the number of lines of code, and everything else - good design, good code structure, good language choice - will follow.
[+] [-] mjmasn|9 years ago|reply
Continuously refactor your code to remove duplication (See Don't Repeat Yourself / DRY). If you find yourself copying and pasting boilerplate code over and over, it's probably time to refactor, otherwise you find one bug and have to fix it 20 times. Good testing helps you to refactor fearlessly because the tests will tell you if you screw up.
Whatever happens you'll always cringe reading old code - but see the positive, it just shows that learning is a continuous process and that you are now older and hopefully wiser than you once were.
One thing that's been on my mind lately is an old article by Joel Spolsky [1] about accurate estimating. I'm absolutely terrible at estimating but I'm using Joel's method to improve that. Better estimates mean better code. Why? Because if you estimate 1 day for a task that really takes 2 days, you'll be rushing, stressed and tempted to cut corners by the start of day 2. If you've planned 2 days for it, you can use the time more effectively.
[1] http://www.joelonsoftware.com/items/2007/10/26.html
[+] [-] gsylvie|9 years ago|reply
The risk of writing perfect unused code is significant, and the consequences are pretty grave. I think worrying about how "good" your code is should be secondary to worrying how usable your code is.
Yes, maintenance & debugging can really suck. But optimizing to make maintenance & debugging better won't serve your users well if your code never launches.
[+] [-] ikeellis|9 years ago|reply
Read this book: https://www.amazon.com/Debugging-Indispensable-Software-Hard...
It's short and sweet and applies to any technology problem.
[+] [-] swagtricker|9 years ago|reply
[+] [-] AdamN|9 years ago|reply
Not having to use the mouse for common tasks (closing a window, switching applications, etc...) is another core skill.
Everybody else's comments focus on important stuff but I've seen programmers absolutely hobbled by not having these basic skills.
[+] [-] n3t|9 years ago|reply
[0]: https://steve-yegge.blogspot.com/2008/09/programmings-dirtie...
[+] [-] artimaeis|9 years ago|reply
Reading code from people who are just getting started gives you perspective of how far you've come (hopefully). You can also use this to help people out fairly effectively.
Reading code from people who are more experienced is good for getting styles down while maintaining the context of where certain practices are acceptable.
Switching languages is also advantageous in that you can (hopefully) identify why different languages have different stylistic practices. This works better if the syntax of the language is pretty distinct - so C# to Java wouldn't be excellent at this. But C# to Python is great at it.
Of course writing code helps - especially if you can convince someone else to read that code and give some meaningful feedback!
[+] [-] jacquesm|9 years ago|reply
There are lots of projects that are good examples.
https://news.ycombinator.com/item?id=4331688
[+] [-] Joeri|9 years ago|reply
Most of the lessons about programming I learned by designing and coding sets of features, shipping them, and then being the one handling all the bug reports and feature requests. Performance tuning, defensive coding, debugging technique, ui design, codebase architecture, developer team coordination, ... the list of things to be learned by sticking around for the long haul is endless and hard to replace with book smarts.
[+] [-] pgroves|9 years ago|reply
1) "Overview and Zoom" is a common UI technique where you give an overview and then let a user click on stuff for more detail. In programming, this means writing the "intention" as a method that's very easy to read, then have a bunch of helper functions with the details. This also forces you to only use one level of abstraction per method.
2) Only have one thing happen per line. This forces you to give what you're doing a proper name (as a variable assignment before you use it). This makes it easier to read, but makes all text processing tools work much better with your code. Nothing is more annoying than seeing a diff in a pull request where one line changes, but there are 10 things happening in that line and only one changed.
[+] [-] thecombjelly|9 years ago|reply
Put the effort in to learning new concepts, programming languages, methodologies, programming language history, computer science, and even broader subjects dealing with humans and how we think and form ideas. There are countless ways to write code and without having a broad knowledge of them you will only at best reach a local optimum and rarely choose the most effective solutions and designs. The worst thing you can do is stop learning and seeing other perspectives.
[+] [-] bordercases|9 years ago|reply
[+] [-] phn|9 years ago|reply
Dealing with the consequences of bad code is a very good teacher :D
EDIT: Also take notice when other people's code cause you trouble, what can you do to save trouble to a future colleague?
[+] [-] stonemetal|9 years ago|reply
You often hear "The worst code I have ever seen is code I wrote six months ago" While on the one hand that may be true, on the other hand it is trite bullshit. If the depth of your introspection and reflection on past code is "Wow what a pile of shit!". Guess what you are going to be saying about your code in six months?
With a real honest critique you will see flaws and things that you did well. Don't just dwell on what doesn't work. When you see things in your code that work well try to figure out why they work well so that it can guide your deliberate changes to what doesn't work. Also if you don't keep your style constant for a period of time you won't have enough experience with it, nor a large enough body of code to review to have a full view of what works and what doesn't.
Last but most important read the code of others to pick up ideas on how to improve your style of coding. Some of the best bits of my coding style I have picked up from others.
[+] [-] mhomde|9 years ago|reply
Writing code should be highly iterative, and learning to code is as well. The more you write the better you get, and the more you will realize how crappy your old code is. Refactoring should be constant to keep the complexity and amount of code to a feasible minimum.
So, now and again, look over the code you've written, does it seem a bit overwhelming complex, are methods starting to feel bloated? Does some new feature or concept feel artificially grafted on? Then sit down and try to figure out the best way to refactor it into something more streamlined and manageable.
A good way to realize how bad one's code is to take a few weeks break from it, and if when you return you have trouble understanding the full scope of it it's time for a rewrite :)
Be sure to dedicate some time to sharpening your saw, researching new tools, technologies etc. It's easy to do something just because it's the "way I know to do it" rather than putting in the time to learn a better way.