Dashdashforce

On learning

Cover Image for On learning

What follows below are my reflections on the process of learning hard things. There's no code in this post but it all applies to the process of learning computer programming and similarly complex subjects. My learning style will obviously not fit all but I hope this can be a useful road map to many of those trying to learning computer programming on their own, or who are seeking some additions to their learning at university. I don't pretend that any of this is fully original and I stand on the shoulders of a few particularly towering giants who I will mention. Books and resources linked at the bottom.

I am a self taught software engineer, although my ability to learn this trade came from many years of struggle in other fields. I've always had a technical side to me, as even from a young age my hobbies drifted towards things like radio controlled cars and planes, working on my full sized car (nothing like experimenting on your lone source of transportation), building gaming PCs, etc. I also did exceptionally well in chemistry and biology courses and inhaled Carl Sagan documentaries.

Lessons from Music

However my first year in college I was actually a music performance major. This all happened rather by accident as I played an "in demand" instrument (bassoon) and had put enough hours in behind the horn they wanted me to join the music college. Why not try it? I could practice long hours in the practice room, I could focus, and I was very good with my hands which was required for bassoon, as besides being a rather complicated and dexterous instrument, playing it required making the complex double reeds used to produce its sound yourself because pre-made ones were usually crap or obscenely expensive. But I found that the passion for performance really wasn't there for me like it was for the others, and my thoughts quickly drifted back to the world of science and technology.

However, from my time in the music college I learned a few useful things that have served me since:

Sleep is almost as important as the practice itself, and when in doubt, give up and try again in the morning.

I swear sleep is magic. There were countless occasions when practicing a particularly hard section of music late into the night, that after many slow iterations through and still failing to get it right, upon giving up and sleeping a bit, then trying again the next morning the difficult section would flow out of the instrument perfectly. There is significant evidence (besides my hand wavy anecdote) that your brain solves problems while sleeping that it couldn't work out while awake. I've found this to generalize beyond music and absolutely be true with programming. Stop staring at the screen at 1am, you're wasting time. Trade that time for a night on the pillow and come back in the morning. Matthew Walkers "Why We Sleep" is a particularly good book on this subject.

Do not practice until you get it right, practice until you can't get it wrong.

That first moment of getting through a particularly difficult passage of music is extremely satisfying, however it is a trap. The nice controlled environment of a practice room is one thing, but under pressure is a whole other. As such, just getting it right once it not enough to promise success. Keep at it until that difficult thing is engrained in muscle memory. Then test it under mild pressure. Programming has far less of the "live under pressure" moments as music did. My boss has never asked me to live code a feature...but interviews sure have. As such when working through a particularly hard algorithm or design pattern, it's worth bookmarking it for later and revisiting it to make sure that the concept is truly learned and in long term memory, and not just learned once and forgotten.

Learning takes repetition, with each time you relearn a concept taking a bit longer before you forget it. Write a Fibonacci algo once and you'll probably forget it in a few days. Do it twice over the course of a week and it'll probably stick around in memory a good deal longer. Refresh it a few more times and it will start to stick and be easier each time. Feeling pressured and stressed turns this up a notch and requires greater ingraining in memory. You will not raise to the occasion, you will fall to your floor of preparation. Practice everything that must be done under pressure with that in mind.

"Natural talent" is often just a lot of passionate hard work that goes overlooked.

This one may ruffle a few feathers. In music and the arts especially there is a tendency to see someone who performs or creates art at a masterful level and say something along the lines of "my what talent they have!" or "they were born with such a gift!". Having performed along side some true prodigies I assure you this ruffles their feathers. What you don't see is all the hard work. All the time in the practice room and the failed attempts lost to the sound insulation of that room. To assert that it is simply a born talent akin to magic overlooks all that work.

The moment that made me realize I probably wasn't cut out for music performance as a career was reading an interview with Judith LeClair, who is currently Principle Bassoon of the New York Philharmonic and someone I looked up to greatly while in the music college. In this interview she talked about her youth and how she would listen to various symphony works for hours until she fell asleep, and how she spent a truly incredible amount of hours per day, every day behind the instrument practicing. I don't remember the precise number of hours but it was far more than I have ever been able to commit daily without feeling burnt out. Here is where there may be some "natural gift" at work. We all have our passions, our interests, our obsessions. And work stops feeling like work when your heart is truly in it, allowing you to more easily put in the time needed for mastery. But the work still needs to be put in.

This realization is both freeing and damning at once. It frees you from feeling you can't accomplish something just because you're not a master right away (because no one ever does that), but it hammers home the importance of choosing a path of mastery that really does fit your own particular passions. Can anyone become a master musician? Well maybe if they put the work in, but can they do so without feeling contempt or burnout towards their music and stopping as a result? That's the real question. Do they need to become a true master? That's a whole other question. We don't all need to be Judith LeClair, especially those who see their career as purely a means to earn and support themselves, not a burning passion to which they need to be the best. At the end of the day, whatever you're learning, realize that showing up and putting the work in is most of the struggle, and a foundation of daily hard work (even for only a short period each day) will take you further than you might think. Just be sure to keep yourself sane along the way.

Lessons from Chemistry and Math

I later signed on as a Biochemistry major. Back to my science and math roots from high school. Turns out that even though the subject matter was totally different, the mechanisms of learning didn't change much. Who would have thought?

Sleeping on a hard problem after studying? Check. Those derivatives make more sense under a good nights sleep. Practicing until you can't get wrong? Very Check. Many people can probably sympathize with the experience of listening to the professor explain something once, thinking "oh yeah that makes sense, got it" and then looking at an exam question on that same topic and drawing a total blank as to how to even start. The fact that I learned this lesson in music, but didn't realize I needed to apply it for other subjects was rather embarrassing. Hard work fueled by an interest? Oh yeah there it is again, but turns out it's easier this time so I felt like I was on the right track.

However a few new things popped up that I learned the hard way. In the music college I never really struggled conceptually. My struggle was just putting in the time and effort to master it all under pressure. But that all changed when I had to do calculus and thermodynamics.

Ask the "dumb" questions. You're not the only one who doesn't get it, and even if you are, who cares?

I've often struggled with imposter syndrome and not feeling "good enough". This bit me hard during the biochemistry years, as there were many moments (specifically with TAs and such during office hours) where I really didn't get something and should have spoken up instead of nodding along thinking I'd figure it out later. Asking a "dumb" question seemed like an admittance that I didn't belong there or wasn't smart enough. But in the final year courses which got particularly difficult I started noticing a funny thing. The people in the course who did the best on tests where not the ones who sat in the back and didn't engage (the stereotype of the silent genius at the back of the room), they were the ones in office hours grilling the TAs. And I noticed an even funnier thing, looking around the room as the TA answered you'd see a good 50% of the room at least looking surprised and furiously scribbling. THEY DIDN'T KNOW EITHER!

This realization has served me well in the professional world. My previous jobs involved medical data, meta statistics, genetic analysis, and some very intense scientific acronyms, all mixed with computer programming topics. Needless to say no one knew it all. From my experiences in college I was finally able to get over my fear of not feeling smart enough and just asked the damn questions I needed to ask. I started from a place of "yeah I have no clue and there's only way to find out" and a funny thing happened. Almost every time I would speak up asking for clarification, I would get messages on Slack saying things like "oh thank god you asked that I had no idea" or "wow I totally thought I understood that but I had it totally wrong". People were grateful, even admired that I was willing to admit total ignorance on a subject. One particular comment stuck with me from a coworker:

Man, you're brave for asking that in such a big public slack channel. Thank you, that convo explained a lot for me.

Don't be afraid of not knowing. You went through the interview process and were hired. You're smart enough to be there you just need the time and environment to learn whatever it is you need to learn. It's doubtful there is anyone judging you negatively at all for that, and if they are their attitude is not worth wasting your mental power on.

Lessons from Software

All of the previous points have applied in software. Every last one. "Putting in the hard work every day" especially so. After leaving college I realized that a biochemistry undergrad alone wasn't particularly useful on its own in the workplace and I wasn't keen on pursuing it further. I got my first job as a data analyst but soon began work on learning JavaScript and C# (the tech my company at the time used for their web application). I put in time every night after work, a few hours every day. And it turned out I actually liked the stuff. Getting a program running at all was and still is an incredibly satisfying feeling, even with the interim frustrations of the computer not doing what I want it to do but instead doing literally what I told it to do.

I put myself out there and made mistakes in view of others. At the time I was playing a video game called Eve: Online, and a huge amount of the people I was playing with worked in software in one way or another. We had a Slack channel for programming and boy did I ask some dumb questions. I owe a lot of how quickly I learned to the people in that Eve group, without their constant support and feedback on snippets of code I was working on my learning would have been much slower and shallow.

My first "real world" programming project for a company was a very basic web page that did statistical conversions for my fellow data analysts at that job. Things like converting standard error of the mean to standard deviation. I never want to see that "version 1" code every again. It was truly awful to behold. Pretty sure I had some variables named a, b, c, and such. But it worked. It actually worked pretty well and saved people a lot of time and effort, and most important of all it resulted in the COO of that company asking me after work one day the words I had been working towards: "Hey, you wanna get paid for doing that?"

Bravely do it wrong, then do it better.

My first web application was pretty darn rough around the edges but it laid down a foundation that I improved on significantly, and if I had been paralyzed by fear of "doing it wrong" I never would have built it. I also never would have learned first hand why naming a variable a is such a comically bad idea. Do not let obsessive planning and perfection be the enemy of making an attempt and iterating. I think it's pretty natural for software engineers to want to plan things out perfectly and then do it in one go. There is value in planning and strategy no doubt and I'm not saying to totally abandon them, but sometimes systems need to be at least partially built to learn lessons and iterate towards the end goal. On a big scale this is reflected in things like the Agile and Scrum methodologies of project management, but it can be used at a smaller level too for the sake of better learning.

Lets say you're starting a particularly hard algorithm problem for interview prep and you really don't have a good idea of how the whole thing will look when done. There is a temptation to think "well I don't know the whole answer so I should just look it up and then do it myself correctly". You will not learn as much this way. This method does not truly make you think critically about each step of the problem, instead short cutting it all for the "right" answer. Even taking the step of lets say just setting up a for loop and few basic logic gates, and then falling into a common mistake with the problem will allow you to make key connections with the right answer as to why it's done a certain way. Reading about how a certain technique for producing a set of Fibonacci numbers will produce a stack overflow error is NOT the same as writing the algo that way, watching the program crash from an overflow, wondering why, and then fixing it. It will take more time and effort now for the trade of truly understanding it and not having to relearn it so much later.

This is somewhat akin to total immersion learning when learning a foreign language. Reading about how to order a latte in Oslo is one thing, actually trying it, making a common mistake, and realizing that mistake will cement it in your mind far better. Put yourself out there and make mistakes. Oh and don't forget to practice doing it the right way a few more times until you won't make that mistake again.

Putting it All Together

Through all this I've came to notice that there is a process to learning complex thing like math, programming, art, chemistry, and human language that seems to be broken into three main parts. Interestingly, I find there to be a high congruence of learning techniques between techniques for learning a programming language and those for learning a spoken foreign language to the point where using foreign language learning as an analogy is quite useful. All the previous lessons learned apply at every single stage here, but clearly understanding these stages has helped me a lot in improving, as it gives me better targeted ways to fix gaps in my knowledge when I find them.

The Three Pillars of Learning Complex Things

These three pillars do not represent a linear progression. They are all important and support one another in unique ways, and each need strengthening to make you effective at whatever it is you're working on.

Syntax

This where you start but will often come back to. How do you define a for loop? How to do you initialize a variable? What is the consequence of using var vs let vs const? How do you export functions? Does the programming language have an OOP system? It is analogous to the early learning in a spoken language where you learn the words for colors, animals, how verbs are ordered, how questions are structured, etc. Again, this is not some first step that you will never return to. On the contrary, once there is experience with the larger structures at hand (writing a single function program, building a whole application) syntax examples and documentation will become more meaningful.

Sections you glossed over in the docs take on new meaning, like how in Python sort() sorts the list in place and returns nothing, while sorted() returns a new list that is sorted leaving the old one untouched. A subtle difference on first reading that may not even register, but upon trying to get a new list out of sort() and being confused at why it's not working, it will suddenly make sense and even become useful to you. There are a lot of good resources for this pillar for free or behind mild pay walls on the internet. Things like PluralSight, Code Academy, official language docs, endless Reddit and blog posts, etc. These resources alone won't allow you to write useful code though, just as a dictionary won't help you write sentences. This is what the next pillar is for.

Sentences

Of the three, this one seems to be either the most neglected, or the most over emphasized paradoxically enough. On communities like r/learnprogramming there will be many links, resources, and discussions around the first pillar. "Here's how to learn the basics." But naturally people wonder where to go from there, and all too often I see the suggestion to "build a side project" or dive into some other large project. From learning the word for "dog" to writing a children's book about dogs. I believe this is a mistake or at least not for those who value their sanity. This second pillar brings you the ability to order that latte in Oslo without fear. Could you write a love letter to that latte about how good it was? Maybe not yet. Inter sentence structure is a thing not yet explored, but you'll be well on your way soon.

Resources like PluralSight's quizzes and exam system, LeetCode, Hacker Rank, and CodeWars are by far the next best steps. These websites (especially ones like CodeWars) take the syntax learning and make you start putting it together in very small controlled ways without having to worry about bigger project level stuff like how to setup a dev environment or compile code. You are instead presented with small puzzles of varying difficulty. Things like "here's a list of numbers, remove all the duplicates". These problems are PROFOUNDLY valuable to learning. They allow lots of practice and repetition with the small things like declaring variables and functions, scoping, pointers and references. This is much like the first sentences you learn when learning a spoken language, which gradually grow in complexity with time and skill and allow for rapid, specific feedback about your knowledge gaps. Knocking out 10 CodeWars problems in a night is far more valuable for learning the fundamentals of a programing language than fighting your Python installation and PATH issues all night. From here, go back to the docs and references as much as needed. Bounce between the two, as like I said before parts of the docs will take on new meaning as you do real problems. This pillar is much like the service DuoLingo for spoken language learning as it is comprised of many problems from individual word quizzes to complex sentences and a few paragraph size problems depending on language.

I've mentioned CodeWars explicitly a few times as I think it currently does the best job of fostering a learning environment. It has a huge number of languages supported and an extensive library of problems, with an open community that allows you to add on or improve them if you want. It is structured in a way that doesn't let you view discussions and solutions before trying the problem, forcing you to bravely do it wrong first and only give up and view answers when really stuck. It also doesn't punish you for doing so. You don't earn points for skipping to the answers but you aren't "de-ranked" like some other services which is more of a competitive programming feature. Same goes for submissions that fail the tests. I truly despise services like these that take points away when you make mistakes as it actively encourages looking up the "right" answer before submitting. You should be allowed to iterate.

CodeWars also has the most granular control of difficulty I've ever seen, from rank 8 (the easiest) to rank 1 (incredibly difficult and probably not encountered much in the real world). Some other services feel like they have a massive chasm of difficulty between "easy" "medium" and "hard". Best of all it also has unique voting system for best solutions in different catagories, from creative but hard to read one-line solutions, to best practice solutions you'd probably use one the job, to solutions that are the most performance optimized but again maybe not so readable. These different solutions have value and separating them out is great. Seeing the top LeetCode solution be some abomination that I'd reject a PR for in the real world is not helpful for people who are learning.

I mentioned this pillar is sometimes over emphasized. Some communities give the advice to new people to do nothing but grind LeetCode problems all day for job interviews. Realize that this is advice only really useful to interviews and not so much learning. I obviously believe there is value in doing many of these problems, but the risk of burn out is severe, and if this is truly done at the sacrifice of being able to do large practical projects then it will come at a cost. Spend some time here, but when confidence begins to grow and you no longer need to look up the basics anymore, move on to the larger things at least for a while.

Novels

This category can best be described as things like side projects and hobby projects, actual job work, and even some of the "Projects" on PluralSight, though I find those a little too easy and handheld to be as useful as a free form side project. The possibilities for this one are endless. Many Reddit posts and communities are overflowing with ideas for small projects, things like making a calculator, clocks, web scrapers, or even open source projects on Github asking for help. My first project was the statistical converter for a previous job remember? It contained many small functions each like a CodeWars problem, but all assembled into a whole. This pillar teaches many things, from environment setup and deployments, to code organizations and design patterns, to the importance of testing and documentation. It gives new insight into just how important it is that individual functions are layed out in meaningful and concise ways, things that when working on one CodeWars problem may not be an issue but that rear their ugly head when working with a multi thousand line application. Maybe find a problem in your life that can be solved or automated with code and do that.

Again, it's worth bouncing between the other two pillars once you spend time here. As well, put these projects up on a Github or similar page as something proud to show off and talk about. Even as time goes on and you look back and think "man I could have done that better" they can stand as a road marker to how much better you've gotten. It represents a body of work, much like a blacksmith hanging previous work on the walls for clients to see. They are also often a good target for rewriting in new languages or technologies in the future.

Closing thoughts

On top of getting a better handle on the process of learning, a book that has helped me tremendously in the last few years has been Atomic Habits by James Clear. Briefly, the book is about methods and processes by which you can build life long habits. He places a strong emphasis on small actionable goals that can be built overtime, and working with rather than against your own psychology and natural tendencies to make to make these things really stick without extreme willpower. It's truly one of the best books I've read in the last 10 years and will serve you well.

Best of luck in all your learnings.

Resources and Links

https://www.goodreads.com/book/show/34466963-why-we-sleep

https://nyphil.org/about-us/artists/judith-leclair

https://www.codewars.com/

https://developer.mozilla.org/en-US/

https://www.pluralsight.com/

https://www.goodreads.com/book/show/40121378-atomic-habits

https://jamesclear.com/