Ask HN: I feel like an 'expert beginner' and I don't know how to get better
I really want to improve at programming but I feel I'm kinda of stuck
in this 'expert beginner' phase. I'm familiar with basic data structures
and their complexity (linked lists, arrays, hash tables, queues,
trees), some basic theory (DFA, NFA, CFGs, TMs, lambda calculus etc),
and elementary math (calc I, II, III, linear algebra, ODEs, discrete).
I don't feel particularly confident in any of these areas of study, knowing the minimum amount to get me by. Sure I know what a NFA is, but ask me convert it to a DFA and I'm lost. I lack 'deep', real knowledge and am desperate to acquire this mythical stuff before it's too late.
In terms of areas of interest, I am interested in type theory, FP, compilers, machine learning, expert systems and AI.
So knowing this, how would I best use say 8-12 hours a day, every day, to learn this stuff? Should I be reading papers all day? Should I be writing code? Should I be doing exercises in books? There's just so much material I need to get through that I am lost on how to actually spend my time getting better.
55 comments
[ 2.6 ms ] story [ 119 ms ] threadHonestly though that set of interests doesn't seem like the sort of thing that lends itself to real problems; it sounds to me like you've already got more than enough CS theory. If you're looking to learn the kind of programming that will make you better at doing it professionally, you need to start making practical things. Find a hobby that could do with a website/app or something else in your life that can be automated.
2. Books and papers are great, but you should also try to find a mentor / guide / teacher / expert to talk about the issues you're facing and what you're thinking about. Schools are organized the way they are for a reason, even if they often fail at their intended purpose.
Above all, always have fun!
NEXT YEAR!! woohoo, I can't even imagine how good I'll be - this year will seem like crap.
Basically don't fret kid, we're all learning - chill and do your best.
Forget about trying to learn EVERYTHING. Pick one thing, learn it well, repeat with the next thing.
As mentioned, the more you can do this within the confines of projects you feel passionately about, the easier it will be.
Take a break from focusing on the strategies and tactics of programming. No single algorithm, framework or language is going to unlock the panacea of potential inside of you. Most problems simply aren't that complex in the beginning.
Having the mindset of an innocent beginner always is the toughest thing to maintain to remain a problem-based thinker instead of a solution-based thinker.
The best way I've found is simply to solve problems the best I can, and when I learn what I could have done better, if the need is there, go and refactor it. No matter how great you are, or aren't today, what you write may look bad in 5 years because you have more experience.
Most things we build as developers become obsolete. It's a separate discussion but I'm not sure what you're trying to optimize, your skills, or a result in a project?
No developer is a a factory of churning out code or results at the same speed. Be less focused on the practice of programming alone and look at the results you're creating.
Software is as much a craft, an art, as much as a technical skill, and maybe it's something for you to explore the other fronts.
When you build stuff for the purpose of practice also make sure you build it incrementally. For example, design a file format, build a parser/generator for it. After that, add networking, so two apps can communicate the contents of the file. After that add encryption (nothing fancy, just use a library), then add some TLS, and then, and then, and then.
I found this approach best because:
1) You learn new things (because you research best way to do stuff, experiment with code, etc), and 2) you learn from your mistakes, because as you add you might notice that certain things don't play with your new features, and you will be forced to improve them.
P.S: I know my example might seem a bit lame, but I couldn't think of anything else at the moment.
Whatever you do, as long as there is a minimum amount of fun in it, you'll get better. And the more you know, the better you can identify what areas you have and/or want to improve in.
Unlike for athletes or musicians, practice in a knowledge field (like CS), seems a little ill defined..
Lose your first 50 games of Go as FAST as possible! Don't worry about winning or losing or finding the "right" move, just put some stones down, get used to looking at the shapes that come up, and get a good feeling for how the rules work. Of course, a consequence of that attitude is that you will lose most of those games, but it doesn't matter. Once you have a bit of experience under your belt, then you are ready to begin
“I have not failed. I’ve just found 10,000 ways that won’t work.” - Thomas A. Edison
Also, I see a pattern that more you are used to studying more quickly you tend to understand something new. I believe its something do with reading habits. So don't leave theory completely, but keep a balance b/w theory and practical.
Also you don't sound line an expert beginner, you sound like a beginning expert, I'm programming for 10 years for a living, built a couple of money making startups, and doing my MSc at the moment, I can't say I know half of all that at an expert level ;)
Finally, accept that you don't really have to know everything, and more so, you can't really be an expert in everything, it's really hard but CS is a very wide field. You can't help but being a beginner expert on a wide area of topics, and only a "real" expert in a very narrow subject. Not all CS Phds are expert in everything, actually they are most likely expert in a very narrow set of topics relevant for their research.
Bottom line, either learn for learning and do it in a place that honors it (academy or independent / commercial research) Or build something that makes money, and the subset of human knowledge needed to make it work will be defining itself (you'll have to fight the urge to learn things that "you'll probably need later", and make it more "on demand" learning)
Do your own thing. Build something you want to see built and you will learn oh so much. Programming isn't about how you implement something so much as it is for what reason. Think of something you want to see built and figure it out from there.
For example, I learned Python by trying to write an app that would take my Shazam tags and convert them to a Google Music playlist so I could more easily remember songs to listen to later.
Notice that I didn't write anything about SQLite or how slow Python's HTTP was when making the queries, because in learning Python, that wasn't important; those things were just implementation details that I only started thinking about after my application was demonstrably "slow." And more than that, I really didn't consider anything about lambda calculus and I don't know a single thing about NFAs or DFAs. I just wrote an app.
And I learned something, enough to get the job done. If you really want to learn about how to apply functional programming, learn Haskell. If you want to learn about compilers, write a compiler. You'll learn enough, because there's no way you can learn "everything" on a topic in Computer Science.
The field is much too broad, and you'll be way better off lazy-evaluating it than calculating it wholesale.
Tl;dr: If you want to be a better programmer (as opposed to being a better computer scientist) build and the knowledge will follow.
Don't go straight for an open source project unless you're really into it. Honestly - debugging other people's code is hell, I hate doing it (but frequently have to). By all means dig through other people's code to work out how something is achieved, but for people starting out, bug-fixing is a bore.
Make your own damn open source project! Pick something you love that has a problem and have a bash at fixing it. An here's the best bit: you'll still get to solve bugs, lots and lots and lots of them. Some of them will be easy to solve, some will take you a week before you realise you missed out a bracket.
You have to enjoy what you do or it won't stick. And don't be fooled into thinking you like something until you actually try to build something with it.
Download the code, figure out how to build/install it, and start to find your way around the codebase to try and figure out which bit of code is at fault/needs extending. When you get stuck, ask on the dev mailing list or IRC or whatever comms channels the core dev(s) have.
A lot of programming is not about designing something elegant and new. It's maintenance work, fixing bugs, extending functionality, adding new features. Sometimes adding exciting new features is a chance to design something elegant and new, but other times it's a bunch of repurposing and refactoring some features that are mostly-there under the hood, but need a couple of tweaks, and a small amount of really new stuff (but in the same idiom as the rest of the system) and exposing in a new way.
You'll really find out how to properly spelunk into a codebase (which is a complementary skill to just reading code), how code is used, and how it solves real-world problems.
If another dev solves the bug before you do, that's not a problem. The real purpose of the exercise was for you to learn, and only perhipherally to help the project. As a bonus, you can see how the other dev solved the problem, and how their solution differs from yours. Did they solve the bug at the "same level" as you? Was their fix a bigger or smaller change than yours?
If you get there first, great! Submit a patch to their mailing list, or a pull request to their git page, or whatever they use. Do not take their criticisms of your work as a personal insult. (If they do insult you personally - which almost certainly won't happen, but very occasionally does - that's another matter. Drop it and find another project. Life's too short to waste on asshats.) Rather, listen to exactly what they don't like about the way you solved the problem, use that to fix the problem in a way they will like, and re-submit.
Repeat.
A couple books that are worthwhile: "Refactoring" and "Rapid Development". That will teach you a lot of basic skills in terms of development process and how to improve the design of real systems (warts and all). Also, take a look at the Architecture of Open Source Systems, it'll acquaint you with how applications fit together.
Also, take on some projects. Pick something interesting and work on it. Pick some small stuff then move up from there. I'd suggest in your case eventually building a compiler. If you're interested in AI, build some simple games and work on building AI for them. There is nothing more important than actually writing code.
Do other people do this too? It would be interesting to hear how other's solve this problem?
Also, there's a disconnect between academia and the workforce. You might invent a fancy new data structure that blows up in real use because it ignores caches. Or you might invent something that's cache-aware, but everybody's using scripting languages or the JVM and doesn't have that level of access to the hardware. And so on. If you're strictly speaking about becoming better at the work of programming (rather than CS), that stuff isn't that important. You will spend way more time, especially as you move up in seniority, interacting with people - whether it's designing your system to be understandable by humans, persuading others of your ideas, getting funding, etc.
2 build, then rebuild, your own systems
After 10,000 hours of this, assuming you keep climbing rather than just doing the same thing over and over, you will be competent.
My advise would be to look at your own network (friends, family, etc) and find those who are in business and ask them about their pain; and there is always some pain that a business has. Then figure out a solution to their problem and program that. This serves 3 purposes: 1) It has a definable goal and purpose (solving the pain) as it's a real-life project. 2) You will learn tons about yourself, programming, and the business. 3) It could lead to either employment or a program you could sell to others and start a business.
As always, make sure you write-up a contract which states that the IP is yours. Hope for the best; plan for the worst.
imho, if you work on an open source project and you find it (or your relation to it) being "without purpose," you're doing it wrong. You've picked the wrong open source project, the project is an undead zombie, whatever. If you do it right, it will most certainly (edit: "usually, at least") not feel "without purpose."
Perhaps consider looking at open source projects and your possible personal relation to any particular one from a kind of two-layer perspective:
1. General idea behind the project; its general goals; and how you feel about them. It's probably a fruitless thing to work on something you don't believe in. On the other hand, finding something that shares your values to a great extent can bring out actual passion.
2. This is (usually, sometimes) not enough: hence find particular lower-level goals (these are the "ideological<->technical interfaces" so to speak, or, purely technical particulars (think of some very particular problem or proposed enhancement on a bug tracker.)) In my experience, the lack of attainable (to you) lower level "what do i do" things (which you can use to deduce "how do i do", and then end up with a todo list of particulars, which always helps to curb general laziness (well, sometimes)) might run you into trouble (and maybe this was something the parent was actually commenting on, so we probably disagree on details only.) You have to also keep re-evaluating these lower-level particulars, and set out new ones, etc. (and this is not always easy, of course.)
A good combination of the two can be quite a powerful thing indeed. And if the project is lead by good people with lotsa experience, and if a wider community of smart folk is involved, you can learn a lot.
> My advise would be to look at your own network (friends, family, etc) and find those who are in business and ask them about their pain; and there is always some pain that a business has.
But I agree that this is probably also a great idea, and sometimes more practical, etc. (also, learning to translate business (and sometimes it is an actual business) needs into solutions / technical designs is a very practical skill indeed)
(1) Start committing to Github daily. Make your own project and just go with it until you it's finished and learn what you need too.
My example project: http://austingwalters.com/openbkz/
(2) You can go through online courses in an attempt to learn more and become an expert, many courses are online. You could also start following blogs, read papers and replicate results.
If you are interested in maximizing learning: http://www.scotthyoung.com/blog/
(3) The past month I have been writing a blog a day, it increased my productivity and forced me to really master topics:
My explanation on blogging: http://austingwalters.com/learning-through-blogging/
I recommend blogging, videos, or writing stuff down for "teaching" others because it really helps you master a subject and helps you think of ways to use those concepts.
However: it sounds like your interests are actually more in the realm of Computer Science than Programming, though: type theory, theory of computation, compilers, AI, etc. are less in the realm of programming and much more in the realm of computer science. You don't really need to know how an NFA or DFA works in most day to day programming, frankly. For learning Computer Science, I would suggest finding an advanced course with all of its material online (MIT OpenCourseware is a good place to start, or any of the other free online courses places), and working through a course on the topic. If it has prerequisites that you don't know any/most of the material from, then find a course on those. In my opinion, the other common options (reading through a textbook, reading papers, working on a project related and just learning what you need for that) all have flaws: textbooks are usually designed to accompany a course, which means they usually have much more than you need to learn a lot about the subject (and, in my experience, many are unbelievably boring and poorly written; if you want to go that route, make sure you find ones that are appropriate for self study). Reading papers is really interesting (and a lot more fun than reading textbooks), but without context or knowledge about the area, it's hard to evaluate the paper's meaningfulness/claims/etc., and hard to decide which papers are important to read. Working on just a project (e.x. just writing a compiler) leads to learning just enough to make that project, and not more. If you want to improve at programming: follow the advice about either making a personal project or working on an open source project. The fastest way to get better at programming is to program more.
Frankly: it sounds like you are decidedly not as much of an 'expert beginner' as you think you are. Familiarity with basic data structures+complexity, an understanding of theory, and an understanding of math through linear, ODEs, and discrete already puts you on a very firm grounding. (Outside of certain very specific parts of CS, you /do not/ need more math than that. If you're going into graphics research, knowing differential topology+geometry might be handy. I'm having a hard time thinking of things other than that, though.) From your description, you have more or less finished the 'beginner' stage, moved well beyond the 'novice' stage, and are moving towards becoming someone with a lot of advanced knowledge. Just knowing that you're interested in things like type theory+compilers/machine learning+expert systems+AI already puts you /way/ beyond being a beginner.
Shameless plug of someone else's stuff: if you're not sure where to start on the courses front, and want to start on the programming languages side of things (compilers, etc.), this course might be a good place to start: https://www.udacity.com/course/cs262 I haven't worked through this course in particular, and I don't know its exact difficulty, but I took undergraduate programming languages from this professor and he's an /amazing/ teacher.
Edit: don't know why I had two copies of that written, but now there should only be one. Also, cryptography is another part of CS that you need more math (in this case, abstract algebra). (More multiple copies? I seem to be pretty bad at this "say things once" thing, and need to make some preference changes.)
Get used to it, the field is huge. You will only every have a surface level overview of "everything".
https://class.coursera.org/compilers-004