Hacker News new | past | comments | ask | show | jobs | submit login
Ask HN: What is your best advice for a developer to write better code?
146 points by gdaz on June 29, 2016 | hide | past | favorite | 190 comments

When "better" means "fewest bugs":

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.

6) Don't hire or retain sloppy programmers.

Point 6. freaks me out, because I am not sure if I am one of them.

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

You can write buggy code in any language, and good code in any language. If Ruby's what you have to use, write good Ruby code. If the only reason you're not able to use something better is that you don't know anything better, then fix that when you can.

You probably are not sloppy, because you are worried about being sloppy. The sloppy programmers are the ones that don't care about being sloppy. If you're conscientious, you have a huge leg up on a lot of other programmers.

Since 'sloppy' is going to be defined differently by basically everyone, this isn't true.

That someone is worried about being sloppy really only lets you assume they don't write code they consider sloppy.

Not even that. They could believe that they are in a job where they are expected to move at a pace that implies sloppy code.

Of course, that will actually mean they move much more slowly due to bug fixes, but a junior dev in an environment without a good senior dev can easily fall to the "quick and dirty" fallacy.

How exactly do the first five points put Ruby out of the picture? Sure, it isn't statically typed and allows mutable data, but I don't see how any of the remaining points couldn't apply.

True. First 3 points. Corrected.

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?

Remember also that even in 'C', there are strong and static typing ... aspects to most compilers lurking under the surface.

And for 4) - don't be afraid to build instrumentation into the code base to support decisions about correct operation.

Whenever people talk about typing I just think about how C prevents none of the magical solutions they talk about.

This last part is sooo overlooked.

I feel like this answer ignores why you are writing code in the first place.

The question was how to write better code.

It sure is :)

After 25 years of programming I'll give you the lesson my first boss gave me: "Think more, type less".

It's stood the test of time, I've passed it on to many juniors.

"Weeks of programming can save hours of planning" is a favorite quote of mine.

While this is true, the opposite can also be true. That's called "Analysis Paralysis".

Most of the time analysis paralysis is a signal that you lack sufficient understanding of the needs to actually write the right code. There are two ways to break out of it: (1) understand the problem better, and (2) build something, anything, see why it wouldn't work, and then go back to the drawing board.

> "Weeks of programming can save hours of planning" is a favorite quote of mine.

I love this.

My two favorite generalizations are: - Slow down to speed up - Less is more

another variation of "slow down to speed up" is "slow is smooth / smooth is fast"

> 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.


I've found the opposite. Maybe "Ken" could do it, but most programmers who think they can can't. I've had three programmers spend three days thinking about a problem to no avail, and then fired up a debugger and tracked it down in half an hour. Never be too proud to use your tools.

Interesting. That's the opposite of my experience. When I try to think about things I get them wrong. When I just write code it works out.

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.

> "Think more, type less"

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.

My rules for good code:

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)!

Totally agree with this list. I would also add:

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.

>6) Read lots of code. The more of other people's code that you read the faster you'll learn good practices.

How do you get to read "good code" outside of the job? Care to point me to some such java resources.

> > 6) Read lots of code. The more of other people's code that you read the faster you'll learn good practices.

> How do you get to read "good code" outside of the job?

You don't have to read just good code to learn good practices (negative examples are important, too), and there's lots of published code readily available (e.g., open source repositories.)

Though, I'd say you need to work with lots of code to learn good practices; merely reading code may give you misleading ideas of good vs. bad practices.

I usually look at GitHub, Reddit, or just links from HackerNews.

I have to nitpick.

2) You can't prove correctness with tests. You can only state that it ran correctly for that test case(s).

"Proving correctness" is sort of windmill-tilting for today. Just don't despair of this :)

Good test vectors are a great investment, as are constraint checks and supporting instrumentation of said constraint checks.

I don't despair, because I know that to prove correctness of a program you need to use math.

For example proof assistants(like Coq, Agda, Idris, hol) are capable of proving correctness of a program.

Well, usually my code does not run in space. ;)

But you are right, tests are biased. Pair programming can reduce the chance of code/tests being biased in a negative way.

No, I literally mean that you can't prove correctness with tests, because you would need a lot of test cases to prove the simplest function.

For example: int addOne(int input) function would need test cases for every number in the int type, which would be 2,147,483,647 * 2 + 1 test case.

The point of writing tests is to provide information, not prove correctness.

IE, a test is another way to explain what the developer of that test cared about, worried about, needed to verify of the code that is exercised.

Also, tests provide anothing built in consumer of the code, and all code with more consumers is better code, purely by surviving the stress.

It depends on the terms we set for our tests. Usually we infer things to be correct that are out of scope. For instance, my tests usually don't cover to test the runtime or hardware before executing tests. And what if laws of physics change? No seriously, I know what you mean. But I mean correctness in the bounds we set. Those bounds are different if you write software for aviation or biometric devices or an Instagram clone.

It's perfectly possible to write a function with a small enough set of arguments to make it practical to exhaustively test.

Well it's possible, but how many developer would rather make a new type for using the first ten integer instead of just using int?

I think random testing is a good way to get almost exhaustively tests.

A developer that uses a narrower integer data type, or who wants to be clear that the argument is a member of an enumerated set of options, not an integer. What kind of developer represents non-integer data as an integer data type?

> I think random testing is a good way to get almost exhaustively tests.

I think that testing known/predictable edge and corner cases makes more sense (in some cases), but I also think that I was responding to a comment about the impossibility of using tests to prove correctness of a function, not about how to derive practical benefits despite theoretical limitations.

You are right, I didn't think the example through.

You are right, you can use tests to prove a function if - the function has very limited arguments and - the function is pure or does very limited amount of state change(side effect)

Generally speaking tests are not the right tool for proving program correctness.

integers are frequently used to represent fixed point numbers anytime you're doing interesting math in an embedded system

And old PC hardware, where you aren't guaranteed to have an FPU, or where integer operations were a lot quicker than FP ones.

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?"

I would agree with (1), but add "Most code is read at least an order of magnitude more times than it is written." Lots of decisions that save you time writing code (or save typing) at the expense of reading the code are bad decisions because of this.

Also, always put a breakpoint on every code branch and step through it at least once in the debugger. Everyone makes mistakes. Fixing mistakes at the point of writing the code is much more efficient than having someone else fix them later. If you haven't done at least this level of testing, just don't check it in. Assume code is broken unless it has been tested.

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.

> Go read open source libraries.

That can be good, but some caution is required I believe. Most developers are writing programs to solve a fairly specific problem operating in a fairly specific domain in a fairly specific environment. They may choose a variety of programming styles to approach the problem (imperative, object oriented, functional, and so on). I'm going to call these kind of programs "normal" program.

Libraries are not normal programs. They are tools or components that are used by those writing normal programs. A good library tries to be accommodating to a wide variety of normal program styles, and tries not to impose too many constraints on how the library is used.

To achieve this, library coders often have to do things that would be poor style or poor design if done in a normal program.

This is an important point. Fully generalized, though, and we find idiosyncrasies in every application domain.

Maybe starting with a project like this would help? https://github.com/aosabook/500lines

This. Just familiarizing yourself with developers of popular/widely-used codebases helps immensely. Make sure to stray outside of your peer group for this, too.

Any suggestions on how to get outside of your peer group?

If you're a WordPress developer, look at some non-WordPress projects.

If you use Angular all the time, check out some React projects.

Use Bootstrap as a starting point for websites? Check out Zurb or any of the new CSS frameworks that are posted here every week.

You don't have to switch... Just become aware of what others are doing.

In addition to the other suggestions, take a personal interest in technologies you may not be able to use professionally. If you write Java at work, maybe go learn Erlang. If you build web pages, go learn database optimization. If you do anything other than security, learn how exploits are discovered.

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?"

The other bit I know, besides this one, is to write comments stating what you're trying to achieve, and why. The how is redundant, but sample data right there may help.

(Someone famously pleaded for documenting the data structures, and leaving aside the processing mechanics.)

Caveat, don't be afraid to use advanced language features if doing so eliminates boilerplate.

Caveat Ruby's advances features seem to be designed to make code less readable sometimes.

Changing the interpreter's behavior is equivalent to creating a new language. The problem with Ruby (and especially rails) programs is that every program is written in a different language, and what that language is is largely defined by external imports.

I have no idea how people have the mental capacity to deal with this.

> Keep your functions to one or two pages.

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.

> Don't get cute

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.

Rule of thumb: Any language feature or library API that is clearly and unambiguously documented, not obsolescent or discouraged, and legitimately the best tool for the job, is fair game.

Readable code > cleaver code

I love Haskell but I feel it attracts the most golfy code. E.g. Yes you apply the dot operator to itself but why would you?

> I love Haskell but I feel it attracts the most golfy code.

I don't feel like most Haskell code is like that and I've read a fair amount.

> E.g. Yes you apply the dot operator to itself but why would you?

I write a fair amount of Haskell and I despise seeing code that applies the dot operator to itself.

Another lambda rather than a double compose is almost always the answer.

> Another lambda rather than a double compose is almost always the answer.

Exactly. I also like to choose between do, >>= and <$>, <*> etc. based on readability. I prefer a slightly more clumsy but readable do {...} in many situations.

Clever is the enemy! Simplicity is key.

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.

A better statement might be: "Don't be clever, let others be clever for you."

Obviously, stdlib functions are going to be highly optimized and the compiler will put hardware-specific performance hacks in for your benefit. Smarter people than you wrote, vetted, and approved that code. Use it, and don't ever try to be that smart yourself.

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.

/9 Work on legacy systems.

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.

I like 10. Massive backlogs of shit you won't do are pointless.

I use sub-TODO lists with thematic stuff (ie. freelancing-related, related to this or that product, etc). Then I get to not see it which is really helpful. A good TODO list doesn't have too many stuff in it, so why not hide parts of it. Then each day wake up and think "I'll do all that very doable backlog today".

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.

Yea, totally ate my share too. For me, I also had an interesting lesson where I returned to a company like 10 years after having been there prior. I picked up some code to fix a defect and was frustrated by it, only to realize I was the "moron" that wrote it prior.

> when it would be better understood by 80% of developers

And yourself, 6 months down the line.

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.

> Think really hard about the problem you are solving.

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.

> Think really hard about the problem you are solving.

How do you know you have thought hard enough?

If your boss hasn't complained about how long you've spent thinking you haven't thought hard enough. /s

This would be a good SO question.

It would be closed for being off-topic ;)

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.

[1] http://www.joelonsoftware.com/items/2007/10/26.html

> 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.

Only if you were using that planning for something. Is the business value of that feature really so marginal that you want to do it if it takes 2 days but not if it takes 1? I find it's more useful to prioritize, limit work in progress, set a cap on how long any one task is allowed to take before you reassess, but explicit estimation isn't worth it.

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.

Become an excellent debugger. It's sorely neglected as a skill that goes along with development, but is not the same thing as being a good coder.

Read this book: https://www.amazon.com/Debugging-Indispensable-Software-Hard...

It's short and sweet and applies to any technology problem.

+1 to this.

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 suggest reading Steve's post [0] on the touch typing and programmers.

[0]: https://steve-yegge.blogspot.com/2008/09/programmings-dirtie...

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!

Read more good code and emulate after you fully understand it.

There are lots of projects that are good examples.


The problem is that good code isn't so obvious that it is good, its just kind of there and understandable (as it should be). Bad code on the other hand is obvious that its bad, as it takes you ages to understand what is going on.

Which is why I usually generalize this advice to "Read code". The majority of what you read should ideally be good code, but seeing both a good way and a bad way of doing the same thing is sometimes necessary.

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.

My main two:

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.

Which subjects would you recommend?

* Programming languages

* Software development methodologies, things like Mythical Man Month

* Computer Science history and basic theories and concepts

* Compiler implementation techniques.

* Anthropology and related subjects. Programs are written by people and for people so understanding people helps a lot.

The biggest thing is to approach things from all perspectives and an open mind. Learning programming languages of different types is great because the different language families highlight different techniques, concepts, and ways of thinking. No one approach or language is the perfect solution to everything. Try to aim for the largest perspective: functional, homioconic, machine like, pure OO, strict, lose, etc. You can look at the lineage of programming languages and what developed and derived from what and learn one from each group to get the broadest perspective.

Learning CS history and basic theories might not be directly applicable to your life but the knowledge that comes from it will show up in everything you do and knowing how to leverage it makes a big difference.

The value in learning about compilers, GCs, etc comes from being forced to learn, in depth, languages themselves and concepts behind them. If there was anything you didn't learn in depth in other areas they will probably show up here.

Everything you learn about programming and CS is ultimately dependent on humans and how we interact with computers. Understanding how we think will help you develop long lasting programs that are easier to understand and use.

Depending on your goals it may be useful to learn about the basics of how the hardware works, although that is more related to performance optimization than good design and good code.


Learning about so much is a long process and never ends but if you want to write solid code long term, and not just do what's popular at the time, it's the best way to go. Just take it slow and do it at whatever pace works. It works best if you have toy (and not toy) programs to make in each language as you go. After you've started getting a broader perspective, in things like programming languages, it all becomes a lot easier and faster. You'll be able to learn completely new languages in a matter of days and be better at them than people that have been doing it for years, because you can break it down in to its fundamental concepts and all you have to do is learn the language libraries and syntax, which also starts coming quickly after awhile.

I think I take a lot of the above for granted. It all sounds like a solid CS education to me, something which many students already have.

So I think your point about being open minded is the strongest. Additionally, you bring up some excellent summaries of what each discipline is about. A lot of the time the failure here is lack of comprehensiveness, or coverage; coverage in space (what's out there) and coverage in time (what's been done historically). Current favorite example is APL: http://isomorphism.es/post/146379365169/unlike-many-language...

But as far as material goes, I suspect pure, bare metaphysics is underrated. Bearing with me, this talk by Hickey quotes a lot of Whitehead: https://www.infoq.com/presentations/Are-We-There-Yet-Rich-Hi...

Whitehead spearheaded Process philosophy: https://en.wikipedia.org/wiki/Process_philosophy

Most metaphysics is crap, but there are a few gems. Whitehead, Russell, Quentin Meillassoux, Wittgenstein, Northrop, Peirce, Kripke. Dealing with fundamental conceptions of space, material, time, cause, and uncertainty can go a long way when it comes to modeling code and understanding when it will correspond to reality. Programming languages give you enough flexibility to reach your ass and fuck yourself over. That needs to be constrained.


We're in agreement, I just like hearing myself talk.

Write a lot of it, and keep a critical eye. Try to find the issues that tend to come back to bite you and avoid them in the future.

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?

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.

When you refer to style what sorts of aspects are you looking at? Simple things like bracket placement, naming conventions?

It's all kinds of things. I recently read a suggestion that you should be able to remove everything from a function's source except the declaration and the comments, and still know exactly what it does. I'm thinking about adopting that stylistic choice, and after a few weeks/months come back to reevaluate if it's worthwhile or overwrought. Or it will just be so obviously great that it becomes a permanent part of my stylekit.

By style I mean it closer to writing style. How you express your thoughts. For example checking preconditions and returning an error in a block up front instead of mixed in with the computation, or nesting your computation in a bunch of precondition if checks.

Bracket placement is trivial and can be formatted with a tool in a second or two so play around with that all you like.

It's not only about formatting or naming. It's about how you break down the problem. I sometimes write functions for a certain problem and later realize that I have written the same thing 3 years before. When I compare the code it's almost the same. Almost same function name, same parameters, same result type.

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.

Depends on what your weaknesses are.

For me, pair programming has been the by far best way to improve my coding.

Test your code, every which way. Think of edge cases, security holes, do research on how code fails and internalize those lessons, and constantly test - test test test. Manual tests, unit tests, etc.

Code that works reliably is (IMHO) better than beautiful code that doesn't work at all, or falls apart under strain.

Study the source code of major open source projects & try to contribute - you will see techniques for better code in their natural habitat, and through code review.

Go back to code you wrote 5 years ago or even 3 years ago and refactor it. You will most likely cringe but it will force you to write it better.

Also - write code that would be easy to understand for a jr developer. I see so many developers trying to be creative with their code but it's hard to understand.

1) Learn the limits of your own brain and of the average human brain. On average someone can remember about 7 items. So do not write functions with more variables. Cut problems in many stupid little problems which are easy to reason about and debug. So whenever you see a function gets to 25 lines cut it up in to pieces. Because of your own/average brain limits large functions are garanteed (95% sure) to have bugs. 2) Test all your assumptions you make about code and build on those assumptions and build tests to check them. So you keep building on a solid code base that does not "surprise" you. 3) Be crazy about Good variable names and clear functions names and avoid abreviations because those costs brain cycles.

1. Try to understand the problem you want to solve and only solve this one in the shortest and cleanest way you can.

1.1. Write tests for this problem you solve.

1.2. Do not over-engineer on that problem.

1.3. Optimize later. If the code is clean the performance is usually good enough. If the code is clean you can easily optimize on it.

2. The choice of the language does not matter so much, as long you know the caveats of it. If you use dynamically typed languages you should write more tests covering possible input and output or use asserts to validate it.

3. Know your tools. Try to understand each tool you are using first before using it for your production code.

4. Learn to communicate your thoughts clearly. Honestly it is one of the biggest advantages for any developer. You will write better code as a result.

Write a "how this piece of incredibly complicated software works" document for a piece of software you have no idea of the workings.

I have never actually published any, but have done this several times. The process is unlike any other form of writing; you are constantly rewriting all parts to reflect your incremental gains in understanding.

P.S. I believe there is an inversely proportional documentation to complexity rule, where at some point the adequate amount of documentation to describe the complexities becomes unmaintainable. In this case, the code becomes a better descriptor of the code than any amount of documentation ever could.

Examples I've worked with include the go compiler and Scala's slick library.

It's not as difficult as people tend to imagine. Most of the time people fall into the trap of thinking that experts in any given field are experts because they know some secret way of doing things that is difficult to learn. The reality is that most experts (whether it's in rock climbing, bread baking, or coding) have a superior mastery of the fundamentals. In code the best thing to concentrate on is writing clear code that works correctly. The clearer the code the easier it is to figure out whether or not it works as it's supposed to, which is win/win.

In general I'd recommend every developer read the book "Refactoring", because the lessons in there are so fundamentally important to development everyone should have them in front of mind as often as possible. Learning about "code smells" and how to transform code from one way of working to another cleanly is hugely important, and that's the "bread and butter" of what good coding is like day to day. Specifically I'd say learn to use extract method and use it incessantly. Don't worry about creating small methods that only get called once (the compiler will optimize for you). Don't worry about creating "too many methods". Don't fret about having "meaty methods" that do "meaningful work" instead of just "trivial stuff", break down your code into components that have semantic meaning, even if they are small components. And if you end up with too many methods it likely means you're mixing up functionality for different things in one spot and need to split it out or you have a more fundamental design problem that needs to be addressed through simplification.

Overall, strive to make code readable and understandable. Learn the magic of well named variables and methods and pretty soon your code will start reading like an open book. Above all else, remember to be kind to your future self and others who might come along your code in the future. It's always tempting to leave a mess because it's "just temporary" or "you'll get back to fix it up later" but try to develop some basic levels of code sanitation so that you're not dumping garbage in the codebase all the time.

It depends on your experience. When you're starting out you want to write as much and as often as you can. Practice solving the same problems using different solutions and adding constraints.

If you're an intermediate developer you need to turn to predicate calculus, logic, and formal mathematics. Learn a specification language and a theorem prover. Learn to think above the code. Learn to identify what the invariants are and then see what you can cut away from your code. Know what pre-and-post conditions must be held strongly and which can be relaxed. Etc.

Fully understand what each line of the code does.

Third party libraries, copy & pasted code from Internet, helper functions from a framework, and more often hides critical information the coder needs to be aware. Many inexperienced coders simply put together code and produces working code without good understanding of why/how their code works.

I found that deeper understanding of the code not on the first level but all the underlying libraries and functions, lets me write more concise, bug resistant, and easy to understand/maintainable code.

Keep asking yourself constantly: does this code make sense?

I think that's actually a very high bar and most code I've seen doesn't "make sense" in that if some non-developing stakeholder looks at it they won't go "oh, ok, I see what this is about" but instead "ok this is a bunch of technobabble that I couldn't possibly understand."

And read or at least skim the "Domain Driven Design" book by Eric Evans. His concept of a "ubiquitous language" is necessary for code that makes sense.

Expose yourself to criticism.

This one is tricky, because (implicitly) it means surrounding yourself with people who are better than you. Which means getting hired on such teams, which is tricky if you can't bring the skills to the table (or mind-hack their interviewing process)... leading to a vicious circle.

But if you can find a way to "quantum-tunnel" through that barrier, and always try to wind up on teams better than those you've worked with up until then -- that's a big step in the right direction, at least.

How I guide my development teams:

1. Write code that does something correctly. Let it do that thing for a while, keep an eye on it.

2. Then come back to it with fresh eyes a few weeks/months later and refactor it. Maybe just a critical chunk, maybe top-down.

3. Repeat.

By revisiting your own code and iterating on it, you also update the design patterns you intuitively apply when faced with a problem. And importantly, you upgrade your ability to a better version of yourself.

I've tried giving examples, setting coding standards, etc; but it's really hard to code in someone else's style. We can't all be Jeff Dean or Salvatore Sanfilippo, and their styles/languages/approaches don't suit every intuition. Also, that "great" code is rarely where the project began, so it's like comparing a beginner's first draft with Hemmingway.

Code reviews are difficult for the opposite reason. Even feedback from a much more senior developer usually lacks the contextual knowledge to really know what's going on, so they're just shooting from the hip. Code reviews catch edge cases well precisely because they take the reader out of the "expected" control flow; and they generate lots of "cute trick" advice at a tiny tactical level. They're good correctness & social tools, but not so helpful for self-improvement.

> keep an eye on it.

Yup! Also, I would really like the computer to keep an eye on itself by simulating running the program a billion times or something like that.

I would say a developer who writes good code is one who:

1.) Uses comments & documentation as a last resort.

2.) Tailors the complexity of their code to the intended audience. There's nothing inherently wrong with 'being cute' or utilising the full feature set of a language if this will make future developers' lives easier. Conversely, if the project is to be maintained by someone that is fresh out of college, KISS is best.

3.) Prefers tried-and-true over bleeding-edge for production-level projects (it's called bleeding edge for a reason, 9/10 times you'll bleed).

4.) Produces code that conforms to what-is rather than what-should-be. Blindly sticking to ideology will perhaps produce more 'beautiful', but not necessarily more maintainable, code.

5.) Is aware of the expected lifetime of the project. No need for defensive programming if this is an MVP that you know will be scrapped in six months time. If this is the backbone of a major banking system then extra checks and being paranoid makes sense.

6.) Follows the conventions of the project and ecosystem. Consistent code is more important than personal style.

7.) Perhaps I'm in the minority here but: is not over-reliant on IDEs. Tools like IntelliSense encourage you to offload part of your mental model to a program; I feel like this inhibits your reasoning abilities.

Learn how to write good tests.

This includes writing tests for code that doesn't have tests (often requires refactoring or some careful engineering)

And possibly writing tests before you even have the code aka TDD (although I'm not on that bandwagon I have done it at times with great results).

If your code is easy to test it is probably better code than otherwise.

Also depending on the organization a-careful-not-very-productive programmer can be worse than a loose-prolific-code-cowboy but generally that is not the case.

I read something, somewhere, a while back that really stuck with me.

> It is impossible to make your code faster, you can only make it do less. The only way to 'speed-up' a process is to achieve the same result with less code (or really, less cpu cycles).

This is along the lines of less is more, but it is also something that really helped drive home the need to reduce, refactor and refine code instead of just piling more code on top of what you already have.

Your quote makes me feel like you are targeting code lines/chars.

Less cpu cycles != less lines of code.

For example, bubble sort would be little more than 10 lines where merge sort would be twice as that.

What I was really trying to express is the fact that you cannot make code run faster (on the same machine), but this is something we all say - we made xyz faster. Every line of code you write has a price, both in performance and in security/bugs. Security issues and bugs typically are tied to lines of code, but performance is definitely not.

To really understand this, you have to understand how machines work. Merge sort is faster because the processor does less work for the same input compared to the bubble sort. How many lines of code you have is rarely a good mapping of how much work your processor is doing. You have to take into account the complexity (i.e. O(n) or O(N^2)), the framework your are using (just because you have 3 lines of code in a Rails controller, doesn't mean you are executing 3 lines of code, etc.

Spend a lot of planning time breaking up the design into separate components/modules/packages/whatever, where each piece exposes a small, well-documented interface. Naturally these pieces will have inter-dependencies, but try to keep that to a minimum. You don't want to have a single module that every other module directly imports. It takes a lot of thought, but this makes it a lot easier to fix bugs and make improvements with minimal fuss.

Another thing that is really helpful is keeping a dev journal: a sort of stream-of-consciousness record of what you're thinking/doing. Include things you thought about trying but decided against, links to blog posts/stack overflow questions, frustrations or pain points with the design, code snippets, just anything really. This can serve as a rough draft for documentation, and forces you to articulate your thought process into words. It takes discipline to keep adding to the journal, and I've fallen out of the habit recently, but it is super helpful.

Maintain it over time and changes. Writing "working" code isn't that hard, but we've all had the pains of bad code:

* Hard to extend/modify

* Confusing to understand

* Full of exceptions and not-quite-repetitions

That last point is what accumulates due to the first two. The best way to learn how not to do the first two is to actually maintain your own code over changes. That teaches you how to make code that you can return to with less confusion and how to code for changes. ( A lot of code patterns are extensible, but grow cumbersome if break a fundamental assumption )

Ultimately, once you learn to avoid universally "bad" practices, you are left with a lot of conditionally good/bad ones. The same practice that makes a solid, extensible structure for one use case is what gives you a monolithic inflexible mess in another EVEN WITH THE SAME CODE QUALITY.

So I'd say focus on that: too often we feel like it if works and is "pretty" it's good, but that's not always the case. Some seeds bear fruit, others eventually give you weeds.

Be nice to 'future you' - if in 6 months you open up the code and can't figure out whats going on right away, you've done something wrong. Just because you understand everything now, you won't when it comes time to refactor down the road. Make sure that you don't screw future you over by trying to be cute, take shortcuts, or rush something.

Here's what Rob Pike has to say about the best advice he got from his fellow developer Ken Thompson. Build the mental model of the software before touching code: http://www.informit.com/articles/article.aspx?p=1941206

> Build the mental model of the software before touching code

This x1000.

This goes for starting fresh, and coming back to existing code. Too many times I have seen horror that was the result of developers diving right in to coding without spending any time at all having a complete mental model of what they're doing.

For JavaScript in particular.

1) TDD. Since JS offers so few static guarantees, unit testing your components and utilities as you build is important; arguably more so even than in other languages. Besides test-as-you-go, this includes building things to be testable in the first place. "How would I test this?" should be an up-front question that heavily informs the approach you end up taking. Even if you write no tests, this approach will improve your code.

2) Linting. This goes beyond just enforcing code style preferences. It turns out there are lots of potential bugs you can prevent from a simple static analysis—despite JS's lack of static guarantees—and catching them early will avoid errors and make you more productive.

Good code isn't obvious that it is good. Bad code is obvious that it is bad. (Its like TV presenters - you notice a bad one, but good ones are the norm, so it just seems "average").

Get a job maintenance programming on someone else's crappy code. Every time you think "WFT!", ask what would have made it easier.

Likewise, if you are working on a long term project that you have written, then a month or two later revisiting the code you should be able to understand the code you wrote quickly. If you don't understand your own code straight away, ask yourself what it would have looked like to make it easier to understand. Refactor it and try to improve it.

- Add the occasional expositive comment to help clarify intent (in places where it might be ambiguous).

- If writing in a language with weak ability to do this through its syntax, establish critical runtime invariants. This can also make intentions and system constraints obvious to the reader. I recommend invariant.js for javascript.

- Write your tests so they can all run by themselves, and do not depend on state created by other tests.

- If something is hard to name this usually means the design needs work.

- If you realize something was incorrectly named, take the time to fix it and refactor, rather than imposing the burden of working with an incorrectly named thing on other readers of the code.

Mild digression, but my 2 cents would be to document as much as you can. Some people say, Good code should be self explanatory. Building something on top of existing code, debugging can be a real pain in the butt with that attitude.

No (useful) code lives in a vacuum. What you write WILL need to be maintained if it is of any value to someone other than yourself.

Write code so that others can read, understand and maintain.

Don't be a code 'Magician'. Few people other than yourself will appreciate your 'Magic'.

Its ok to be a 'Code Ninja' (whatever that means). In fact I think its demanded that you call yourself that so that you can bypass the recruiting/HR firewalls. Also make sure you note down that you have 10 more years of experience than the age of the technology itself. After all thats what the job posting said is the minimum experience needed.

1.) Comment! Not only does it make the code easier to interpret, but it can also bring logic errors to light as you think through why you implemented something in a specific fashion.

2.) If the language supports error handling (try catch/except) learn it and use it.

3.) Use descriptive variable and function names. Even if it means more typing, the readability is worth the effort.

4.) Use proper code style. Most languages have conventions for style that include what should be capitalized, whether to use camel case or underscores etc.. Learn them and use them.

5.) Write a lot of code. I don't think that there is any real substitute for experience.

I'd caution not to use commenting as a crutch, though. Code really ought to be readable and easy to follow all on its own. I don't think code should be littered with comments just narrating what's going on, since those can get out of sync easily when code is modified. The code itself ought to be descriptive enough to "tell its own story", so to speak. Comments ought to explain why something is happening if the author feels the code may be unclear.

Agreed. If I find myself typing a detailed comment past TODO FIX THIS TOMORROW, I refactor. It is rare code should need a comment. Pulling a clever trick to trick the JIT into inlining a function call? Cool add a comment. Just loading junk form a database to show a user? Should not use a comment.

In re: comments, I've found that any time I would write a comment, I try and see if I could re-write the code to make the comment redundant. It is possible to do this in a surprisingly large number of cases.

As for #5, practice makes permanent. Writing lots of poorly thought out code just ingrains bad habits.

Sure self explanatory code is the goal. But in the real world this is never entirely possible. File parsing for example. Without seeing the file being parsed it can be very hard to interpret the code parsing it. Or maybe you are interacting with other software that doesn't always respond predictably to your code and you need to explain why these calls are made in this order.

I agree that practicing bad habits is unhelpful, but I still maintain that the best way to get better at programming is to program, particularly by writing and contributing to open source projects in your spare time.

I like to think about cohesion and coupling for non-trivial projects https://en.wikipedia.org/wiki/Cohesion_(computer_science)

Recently, I've been using a tool to show the dependency graph of my program and I've found it to be quite helpful. Perhaps a bigger point is to find and use tools for your environment that really help!

I like others also favor minimizing changing global state, unit testing (increases odds your code's interface is more well designed), code reviews..

Just code a lot and do it daily. If there is nothing to code on your day job or just old legacy cruft to maintain then try code golfing.

Code Golf is about programming as short as possible and it's also a section on StackExchange [1] where you find daily tasks and many people solving them in many languages. You learn so much because...

- You code really every day and you code new stuff

- Motivation is at its max and you want to be faster than the others and have the shortest piece of code; so you still keep coding after your submission to shave every byte away

- And you learn tons of stuff; reason: you spent thinking hours about your solution, how to tweak it etc and suddenly, you see somebody popping in the answers who did it way better than you, so you analyze and study their implementation for hours like you would never read others' source code, adapt their algorithm and learn; especially when it's about array or bit manipulation StackExchange's Code Golf has a vast selection of tasks and some many awesome programmers there; it's just insane, some guys deliver 10 byte long solutions within minutes while I need 2 hours and 150 bytes

- I want to stress–and this might be the most important topic—writing code is one part of coding but there at Code Golf, you learn that the approach, the core algorithm is more important, and can vary so much, so coding is not just writing commands in a text editor, no it's thinking about the right approach and second about writing it down.

- And you see and learn how same problems are solved in different languages

- One thing which you need to get used to are all these golfing languages which are indeed esoteric but every task is solved in all the mainstream languages as well; at the beginning I didn't like all these golfing languages like Jelly, Pyth, MATL but they grew on me and now I understand them better but find them still a bit awkward; so I like more the JS, Java, C, Python solutions; but again you find everything there, lots of solutions in Haskell, Brainf*, PowerShell, TIBasic, x86 assembler, Vimsrcipt, Mathematica and so on

Compared to standard day routine coding where you glue one API to another Code Golf is ultra refreshing and I'd never had so much fun when programming and learned that much at the same time.

I think there are other code golf communities but I think the one on StackExchange is the biggest.

[1] http://codegolf.stackexchange.com/

The number one thing you can do to write better code is get together a group of people and do code reviews on each other's code constantly. Have people in the group point out things they like and dislike about the code, along with why. Then create a "cheat sheet" where you try to summarize the principles behind all the suggestions people make for your code.

Beyond that, try to find "good" code look at how it is structured. Then try to emulate the practices in regards to language feature use, layout, etc.

Work it work best in a work setting or a friends settings?

It can work anywhere. If your work isn't doing peer code review, they should be - I read somewhere that code reviews are the single biggest driver of high quality software. It is also easy to start up a code review session at hackathons.

Take some turns doing tech supp, test, QA. Especially for your own products (code). The embarrassment from fixing your own stuff will condition you to do better work upfront.

Communicate about it. Whether it's writing internal documentation, user documentation, discussing things with another developer, or just talking to a rubber duck, just forcing the concepts into sentences can really help you think about them. Several times I've been like "this code seems ok" but then when I had to think through it and explain what it does I thought "no, that's too embarrassing, I need to improve that."

What do you mean by better code? Good design is totally different than small tweaks and style changes. I'd argue putting in the effort to learn how to create good designs is the best way to write better code but it takes a lot more time and effort but more than pays off in the long run.

And there is no silver bullet. Advice like "Strong typing" or "functional programming" are not always going to be the best code for the task at hand.

Read and learn from ruby code, because it clarifies intention and is expressive. Express intention, instead of code. Name variables, functions, logically in the problem domain where you are coding for. If you write your code in such a way that you can read the intention of the developer, such the contract/api, the future you, or your colleague can rewrite the guts of your methods but the signature would still communicate the intent.

7 things I live by:

1. "Appear weak when you are strong, and strong when you are weak."

2. “The supreme art of war is to subdue the enemy without fighting.”

3. “If you know the enemy and know yourself, you need not fear the result of a hundred battles.

4. "When cold revenge is served, the dish is always very good"

5. "One man can cut four thousand throats in a single night, if he is continually running."

6. "Only a fool fights in a house that continues to burn."

7. "Pity the warrior that kills all his enemies!"

Practice, you cannot get better at coding by just reading blogs or books.

You have to get your hands dirty trying things.

Always try to keep things simple and short and choose good names. You may have to come back to your code months later, and being able to quickly grok what you wrote pays dividends.

Pick a side project working on something you enjoy. If you work at a corporate job during the day, you may not always have a good opportunity to grow and try new technologies.

Contribute to a FOSS project that has great reviewing system, for instance Servo. See this paragraph at http://nikkisquared.github.io/2016/02/22/things-ive-learned....

> ... In contrast to either of those, everything I write for Servo receives in-depth review and feedback ...

Give a . I've seen so much bad code that's a result of just simply being sloppy. If you care, your code will be that much better.

Porting and maintenance. Take an existing code base (your own, open source, etc) and make it run on another platform. Go fix some of the bugs in the code base.

Then you'll start deeply appreciating what good and bad code looks like. You'll see how helpful comments actually are, how layers of indirection help or not, and all sorts of little details that help or hinder your efforts.

Study Design patterns, follow the SOLID principles while working on some pet projects or even while solving a simple problem may be.

You will be amazed on the benefits you get out of these principles. You will be able to describe your entire design in few English words.

Speak to senior developers and get your class design reviewed, a little bit of "why do it this way" questions will help you a understand a lot of things.

Make a habit of reading the code you're calling, easier if you're building on an os where you have access to the source. This will give you exposure to other coding styles, likely other languages, and deeper knowledge of your platform. You can do this occasionally -- if the documentation is unclear for something, check the source instead of the internet, for example.

Imagine you will have to go back to the code and work with it, after not having spent a single thought on the project for 12 months.

...and possibly during those 12 months have 12 people try to murder your code, i.e. expand its functionality. If the overall architecture, layout is clear, there is a chance that they will expand, improve your code in the way that you originally intended. If it is messy and unclear, it will get more messy. (I'm currently doing a re-write of a huge project that grew over time, using these principles, trying to learn from what was not so nice in the old codebase)

Don't be afraid to throw away code. I just decommissioned a home grown middleware routing system today. I cut my Java teeth on it 5 years ago and it was time to go. Replaced it with an apache camel program that is so much better. I did the happy dance when we turned my code off for good.

Here are slides from a talk I gave on just that subject: http://diiq.org/5questions.pdf

tl/dr: Some useful vocab for phrasing questions you can ask yourself about your code, as you write it, in order to improve it.

- Analyze, design and coding.

- static typing programming language is not verbose, if you know how much comments and unnecessary unit tests you have to write.

- focus on conceptual and system level evolve, stop argue and jump between different programming languages for your work just because some of them are cool.

At the very beginning I think the advice I want to give is to check out standard library codebase. All the design patterns or classical methods are found everywhere in the exemplary codebase. Just steal them and apply to your own code.

Read The book Code Complete 2.

Learn the tools and languages you hate the most.

That's my cheap advice. It's terribly annoying but you always come out on the other side having learned something valuable from the perspective you didn't want. Always.

Study programming languages in different paradigms than you're used to

Always think for the next developer who will maintain your code.

Avoid writing code to begin with by leveraging existing tools, or build better tools so you don't have to write better code (and share with the rest of the world :).

Doesn't that lead you into a place where you can't modify the constraints of your application without sending the patches upstream (for example we hit limits with the mysql connector for C++ all the time, but they are our application specific).

Also, how do you mitigate another leftpad disaster?

My highest benefit/cost habit is viewing the diff immediately before each commit.

It's simple, concrete, and not onerous. The benefits are amazing.

Read at least two style guides for the lang of choice. Adopt the good ideas. Personally, I like the style guides published by Google.

try to do as much as junk code and as many possibilities of coding for a solution. Don't try with one solution and remove it if not working. just comment it and try with some other solution. so that once the code is working fine then clean the code before making it to production.

Don't try to use every feature of a language.

A two-liner is sometimes more efficient and readable than a one-liner.

Pair up, review code, you will be amazed how much you can learn from others both novices and experts.

I'm self taught, and have been doing this professionally for 20 years. I started by learning the fundamentals, and then I started implementing RFC's myself (for things like web servers, ftp servers, SMTP, etc...). Then I went, and compared my solutions to the open source solutions, and tried to see what concepts I was missing. A reason I think this definitely helped me is because when I was creating my own projects, it's easy to decide not to implement a feature if you get stuck trying to figure out how to implement it, and becomes self limiting. Following a spec is going to be a lot closer to how you will work in the real world, and you aren't allowed to decide to just not include a feature because you get stuck.

The comments about writing lots of code are absolutely true, the more you write, the more mistakes you make, the more bugs you have will increase your experience with edge cases and common issues. It's invaluable.

When it comes to actual tips for the code quality itself, a good aim is to make the code readable, as opposed to understandable. Use longer variable names, and avoid single letter variable names. The goal is to make it obvious what your code is doing, you want to limit the comments to sections of the code that NEED them. Far too many developers get the "Comment all the things" dogma, and this just creates a mess. I see this far far too often:

    class Person {

        // Returns the first name of the person
        function FirstName() {...}

This is beyond useless. And remember code will begin to smell, but comments will begin to stink, so you want to make them only when clarification or additional information is required. If you find you have to comment all the time, then you need to work on your code composition and naming.

For flow, you want to make your code work, then refactor it to clean it up. Refactoring should be something you allow time for on any feature implementation. Never move onto another features saying "I'll clean that up later", you won't, or you will eventually because you've created a brittle mess.

Read other peoples code, and run it through a debugger. While I normally eschew debuggers except in fairly rare occasions, they can be invaluable about learning about patterns that you're not familiar with.

Try ditching the IDE. IDE's make your life easy, and they also often make you ignorant as to how your application actually works. Heavy handed namespacing languages like C# and Java are a little trickier to work with this way, but you will learn so much more about your application than you will being spoon fed everything. The reason this is important is something will eventually break, and it's far better to understand those underpinnings when building the app than when something breaks when you're staring down a deadline.

Read books about patterns, languages, etc..., and re-read them after you have been using the techniques for a while. Become familiar with the GoF design patterns, so you understand them, and understand when they're useful. Do not use them as a gospel. Pigeonholing in patterns where they don't belong will create worse code than if you hack together your own more appropriate method. But definitely use them when they fit.

Create an open source side project, and put it up on github. Good code involves interacting with other developers, and even if only 10 people are using your repo, you will learn all about pull-requests and merging, etc...

Teach what you know. You will be amazed at how much better you will understand a lot of concepts once you have to explain how they work. Even if it's just to a rubber duck.

Speaking of rubber ducks, when you get stuck on a problem, or you have a bug that seems illogical and you don't have someone handy to ask for help, explain the issue to a rubber duck. On our team, we'll often call another developer over, and while we explain the problem to them, before we're done explaining, we've already figured out what's wrong. Language uses a different area of the brain, and I suspect that by talking things out, your brain will approach the problem in a way different from the state we use for coding. (this is pure blatant speculation on my part).

Unit test, unit test, unit test. However, ignore coverage metrics, that's a huge waste of time. When you're starting out, write all the tests, but be sure to observe all the instances where the unit test actually identified an issue in the application. You'll always want to unit test your business logic, but avoid testing everything and never test for things that are impossible to occur. Also never test anything but your own code, I've seen fat too many instances of unit tests that simply add a suite of tests to jQuery or some other library. But do assure that you are able to handle bad input, regardless of here it comes from.

Don't be clever. Sure, you can make an easily readable 7 lines of code into a clever one liner that only you understand because you're oh so smart. But don't do it. When you're writing code, you're doing it at the height of your understanding of the system at the time. So even if you're the only eyes that see it, as you move on to other projects, you will no longer be as 'smart' in that codebase. This is especially true when you switch between languages frequently. Beyond that, you probably won't be the only person looking at your code, so write the code (as much as possible) to allow a non-developer to be able to get a sense of what's going on.

Avoid magic strings. What this means is that a string generally shouldn't be used to determine the execution path of code. A simple spelling mistake can be very difficult to detect, and there aren't any tools that can assist. Enums, constants, or named integers are far safer.

Take breaks, get exercise, and don't try to code for every waking hour. If you're in flow, and making real progress this is fine, but if you're just working the hours and aren't making a lot of headway, a good nights sleep will go a lot further than another 4 hours of a fatigued brain. Seriously, sleep at least 8 hours, your ability to learn and remember is entirely based on your REM cycles, when the brain essentially writes from it's cache to permanent storage and cleans up the toxins from the day. Without sufficient sleep, you will not remember what you did, and you will not learn from the mistakes you made and new understandings you would have otherwise acquired.

Never copy and paste from SO or other snippet that you find to solve your problem. Read the example and understand what is going on in the snippet. Then hide the browser and type it in as you understand it to work. I came up with a rule for my first team 15 years ago, and that was to never insert code into a project that you don't understand. If you don't understand it when you add it, you won't understand it any better when that code breaks.

Write cross-platform code

Always think of the next developer who will maintain your code

Work on larger projects and make mistakes to learn from them.

Always trust absolutes, and assume all input is good.

Never reassign a variable with a different value.

try to come up with more than one solution to a problem. don't marry the first idea.

My three pieces of advice to developers aren't specifically about code, but they will eventually lead to better code:

First, slow down. Slow, slow, slow, slow down. Take the time to test and to write tests. Take the time to think about your code. Do it as right as you can the first time. Don't let anyone tell you you don't have time to do it -- you always have time to do it.

Your boss might say "deadline is 5pm", but push back if you can't do it right. It's always, always worth it to slow down. Build testing into your timeline estimates. (My rule of thumb: double the estimate. 1x for writing code, 1x for testing).

Second, don't overwork yourself for no reason. I used to be the support engineer for a startup. Half of my job entailed fixing all the bug reports that came in each day. I would reproduce the bug, add a test, and push a fix as quickly as possible. I used to come in at 9 and stay until 7 or 8pm. One day I cleared out the queue. No more bugs in the list. The next day I came in and had 10 more items. Realization #1 happened there.

I sent an email to a colleague at one point, and he didn't respond until 11am the next day, but I barely noticed. And realization #2 happend then.

The realizations were simple: 1) there will always be more work tomorrow, and 2) nobody realistically expects a response within minutes. In fact, if you send an email after 4pm, you probably don't expect a response until the following morning.

Both of those realizations caused an attitude shift: I leave work at 5, 5:30 every day. I spend more time at home with my fiancee and friends. When I come in, if I have a few more emails than I did the day before, that's fine. They're not expecting instantaneous responses -- and if they are, that's their problem, not mine.

Each support ticket got resolved in 24 hours or less -- far exceeding our customers' expectations -- but I went from working 60 hour weeks to 40 hour weeks. Much happier, much more productive, much less stressed out, and our customers will still exceedingly happy.

A friend of mine works 60+ hour weeks and checks his email constantly, even when he's not at the office. I told him to just wait until morning and email them then. He says, "If I do that, I'll never get anything done, because I'll have 100 emails from my boss in the morning." Well, that's not his problem -- that's his boss's problem. He should go back to his boss and say "If you want me to get X, Y, and Z done, then you need to either email me much less frequently, or get more headcount on the project."

Don't overwork yourself. Don't work more than 40 hours a week without extra compensation. Don't stress out about work -- I guarantee they're not stressing out about you.

Finally, eliminate the phrase "it works for me" from your vocabulary. When someone sends you a bug report, whether it's a customer, a manager, or a fellow developer, your first action should be to confirm that it is, indeed, broken. They would not send you a bug report if there wasn't something wrong. It might be your code, or it might be them, but you owe it to yourself to make sure you have bug-free code, and you owe it to that person to give them the benefit of the doubt.

And one thing you do NOT want to do is go back to someone and tell them THEY were wrong, and then have it turn out that it actually was a bug.

Do your due diligence and rule out a bug. If you can't recreate it, go back and say "Hey, I'm having trouble recreating this. Can you give me more information?" Only when you have ruled out a bug by reproducing the behavior, do you go back to your customer and explain that they made a mistake or something.

Those are the three biggest mistakes I see with new developers (and even people that aren't developers). Slow down, don't work too hard, and start off with the assumption that the customer is right.

My two cents.

Write better tests.

Write less of it.

Take your time.


Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact