(BTW, "beautiful, modular, maintainable code" is one skillset necessary to be a great programmer, and a relatively minor one at that. Much more important is knowing when to write beautiful, modular, maintainable code, and when to bang out a piece of shit that nobody will ever want to look at again, but will quickly prove or disprove a hypothesis and let you know whether an idea is worth pursuing.)
Preferably one with a formal, rewarded mentoring system in place that is outside the management structure.
I'm sure they have this sort of thing at Google/Facebook/Apple, etc. as well, but at MSFT I spent a bunch of my time finding technical mentors --- mostly outside of my organization --- for my direct reports. Finding them is easy for people with < 7 years of experience, but once you have > 13 years of IC work (as more than five of my directs did!), it takes serious effort to both help you identify a direction that it would be worthwhile to grow in and then find somebody who can actually help with it.
1. Read a ton of (good) books: this will expose you to new (and old) ideas and techniques.
2. Read a lot of code: this will expose you to good, bad and awful code. As you suffer other people's bad ideas, you'll learn to recognize and avoid them.
3. Practice, practice, practice.
About the #1 point, it's very important to read not only fashionable books or things related to your immediate work. Try to be broad: read the classics, even if their ideas seem outdated to you. Read about the history of the field and the old programming languages and systems (you'll notice that things haven't changed that much).
Also, try to learn a couple of languages that are really different from each other. If you know Java, learning C# won't give you anything. Good languages to expand your mind are: Racket/Scheme/CommonLisp/Clojure (DSLs, metaprogramming, FP, OO, almost anything ...), Haskell/Scala/ML ("real" static typing and FP), Smalltalk (like Java but fun!), Factor/Forth ...; explore a couple of them and pick the ones that make you feel "weird": those are the ones you'll learn interesting things from.
And don't rush: becoming a good programmer will take your whole life; but it's fun and extremely rewarding.
- How to design programs (http://htdp.org)
- The Little/Seasoned/Reasoned Schemer.
- Code: The Hidden Language of Computer Hardware and Software by Petzold
- Coders at work by Peter Seibel
- The Pragmatic Programmer by Hunt and Thomas
- Code Complete by McConnell
For intermediate/experienced people:
- Structure and Interpretation of computer programs (http://mitpress.mit.edu/sicp/full-text/book/book.html)
- Software Tools in Pascal by Kernighan and Plauger.
- Programming Pearls by Bentley
- Smalltalk 80: The Language and Its Implementation by Adele Goldberg.
- Paradigms of Artificial Intelligence Programming by Norvig
- A Discipline of Programming by Dijkstra
While I've ommited some important language specific books, and ignored essential areas (algorithms, discrete math, hw arquitecture), I think this is a good starting point.
And if you don't come up with an interesting learning project, you can always learn new programming languages. I've found that the best learning experiences have been the languages that least resemble what I use daily. I'm a C programmer but for learning purposes I recommend learning a Lisp, ML or Haskell and Prolog. An alternative to Prolog is going through the logic programming chapter of SICP and writing your own Lisp-based logic programming language and having fun with that (I actually used Haskell + Parsec to implement a logic language).
It's absolutely impossible to turn an average coder into a great coder. Because the things about code you mention in the question -
All of the four things above do not come by direct learning. They come with experience and a lot of practice.
I agree with the fact that you can make a platform to provide the user with questions that will challenge him but still there will be a part where you will give him some hints. And that will just spoil the entire working.
A bad question is one to which everyone knows the answer to (or everyone knows that no one knows the answer to).
"It's absolutely impossible to turn an average coder into a great coder." - Sorry all great coders were average at some point. No one is born great.
Couldn't agree more. BTW, that's the reason why, contrary to popular belief, old programmers are often better than young programmers.
In other words, grad school will help a good scientist become a great scientist, but it will not help a good programmer become a great programmer. In other fields the same is true -- it will help a good architect become a great architect, but it will not help a good bricklayer become a great bricklayer.
This has two benefits, and the primary one is that it gets you _reading_ good code. The second benefit is that, if the project is any quality, it forces you to write good code, both because of the project's standards and because the software is well-designed enough that the easiest thing to do is to make new features match that good design.
"This is the delegation pattern, we use it to _________"
"This is a singleton method, it's best used for ____"
"Create an MVC structure using the strategies we discussed"
The problem is that until you're faced with a real-world software system with real-world problems - and in particular, faced with the consequences of your misuse - you'll be tempted to use them in places where they're not the best solution. It's one thing to read something in a textbook. It's another thing to wrestle with a million-line codebase and try to make sense of it.
Singletons, for instance, almost always turn out to be an antipattern in the long run. You're better off injecting your dependencies explicitly, even if you only think there is one in the whole program. Delegation is used all the time, but can also be overused, and it's important to know when you're better off modifying the original class rather than trying to wrap it with something else.
I figured that by creating a singleton class responsible for executing requests sequentially, this problem would be fixed (and it did). This singleton class internally uses a FIFO-queue to execute all requests sequentially. I think it was an appropriate solution, especially since this singleton class is used internally, not exposed through interfaces to other classes interacting with my 'framework'.
I was just curious about what 'singleton method' meant, as opposed to 'singleton object'. Sadly, it seems that it would be very hard to implement something similar in Python (my main language at the moment) without creating a metaclass. But I certainly saw this pattern in Smalltalk before, just didn't know how it's called.
static MySingleton *sharedSingleton;
static BOOL initialized = NO;
initialized = YES;
sharedSingleton = [[MySingleton alloc] init];
Not to throw conspiracies out there, but I think they are suspiciously un-emphasized here a lot because they are competitors of codecademy with a better product...
This site is awesome for computing information, its about $10 per month and you can read 5 books per month. Books in general give you a more comprehensive understanding of the subject.
Amazon top sellers lists for programming category's are also
worth looking at:
Peep Code, Destroy All Software, Railscasts... It's like watching over the shoulders of some of the best programmers in the world as they teach you everything they know.