Then my father asked me if I could write a simple app that talked through the serial port to control a project of his. Having a goal, and external motivators, is what turns something you learn into something you use.
Have a well defined goal, and unless you're one of those with great internal motivation, share the goal with someone else.
Somewhere along the line I conceptualized functions as a mapping from their inputs to their outputs, much like in mathematics, and I would later come to learn this is what's known as referential transparency[1]. Eventually, during a foray into functional programming, I discovered Lambda Bubble Pop[2] and thought it was brilliant because it was exactly how I had been resolving function invocations inside my own head pretty much for forever, and poof, higher-order functions just made sense. I recently showed it to a developer colleague of mine, though, and he had a very different reaction. In discussing with him, I gathered "replacing a function with its output" was rather alien as a concept; this was not at all how he thought about functions. I'm still trying to figure out how he does conceptualize functions, but I gather they're more lists of instructions than they are term replacements.
Perhaps the closest to an epiphany that I had was in an AI course, realizing that building machines that don't take instructions but rather examples of what to do is a full paradigm in its own right. But arguably that's separate from programming (and imho underscores why understanding the fundamentals is more important). When it comes to memorizing syntax, that's just a function of how long and how recently I've been using that particular tool, it builds up and also decays fairly quickly, that aspect doesn't feel fundamental at all.
What made it click? There wasn't a specific point, but I think it was when I started to seriously branch out into multiple languages. I've dabbled in other languages before, but when I seriously started working with other languages and made larger projects in them did I understand how to structre the code so it's not terrible.
Several months later, perhaps a year, I sat down to try it again. For some reason it wasn't so hard this time. I was able to get it to work.
I don't remember what my other projects were, but I remember struggling to design some more software. I couldn't tell where to begin or how stuff should work. So I'd just jump in somewhere and start somehow. I'd flesh out one component, and then when I'd go to write a component that integrated with it, I found my first design was wrong. I ended up throwing out drafts and restarting.
Through a grueling repetition of this I learned to have a better intuition. I increased my capacity to hold a large and complex program in my head, and to reason about it. I remember a job interview at 18 years old, when someone told me, "you write decent Python." I was quite proud.
I don't think they're was a single moment where it clicked. It was a painful teething process of repeatedly painting myself into a corner, throwing everything out, and starting again. I was very lucky to have supportive adults in my life who helped me out, along with kind strangers on the internet who looked at my broken code.
I'll tell you about one small moment of realization. Once I was asking for help online with a problem relating to my masking an import with a local variable, or something like that. After this was explained to me, Ned Batchelder gave me a command; "now, realize that importing is just a special case of assignment."
It legit blew my mind. It felt like a zen master had imparted special wisdom to me. It was a magical pedagogical moment I've never experienced again. Thanks again, nedbat.
A big part of todays programming work is spent on understanding what others have come up with about how the environment your app runs in is modelled and how it talks to your app and expects your app to talk and behave. This includes data models, process models, event handling etc.
So while there might be a big click when you discover that you need a place to store your data and have algorithms/code operating on that data, in common programming tasks it has to click again an again about others' ways of doing things and adjusting your code to fit that model.
And yes that can be fun and enlighting. Again and again.
One was Visual Basic. VB helped me go from writing fun abstract play things to amuse myself to actually writing something that solved a real world problem for people at a real world company. This taught me that focusing on boring, simple and 'ugly' programs that actually end up in front of people and save them time (and money) is far more valuable than writing really clever programs that don't, and that's what programming as a profession (as opposed to a hobby) is all about.
The second was learning Haskell. The way Haskell forced me to think about everything connected to programming completely changed how I saw things and helped my build up a mental model of the programming 'world' that really made sense to me and made solving programming problems much easier.
Specifically, I learned to program in elementary school (2nd generation programmer), but when I was in 6th grade my school system had its first programming class. Unfortunately, the teacher didn't know how to program so I taught everybody including him. (It was the 90s in a rural school system). Having to explain things to others made me a.) think about my own thought processes and b.) think about why I was taught/learning to do things the way I was. It made me aware of the meta aspect of programming: It isn't enough to know how to program: It's also necessary to be able to think about one's own process.
However a couple things stand out:
- learning to use a debugger
- test driven development
- static typing
- learning a systems language (stack, heap, memory management, pointers etc.)
Nothing earth shattering but once I became familiar with umpteen languages and paradigms, it because a lot easier to express myself when working in a new language as it's just figuring out a new take on a familiar structure.
Actually clicking that I can build my own tools and everything I can imagine: processing ( https://processing.org/ ). Yet another language with a lot of visuals, but I actually started to do some simple data processing with it. Too bad the js copy's website seems down: https://p5js.org
Maybe I’m still meandering around in the pre-click phase though and don’t know. Maybe one day it will click for me!
Any time I hit something new, it only "clicked" when I had an application for the topic/concept
Take tree traversal
I wrote a working ~400 line linear octree traverser in high school in C++
Learned about recursion my second year in college, and rewrote that traversal code in about half a page
I had seen/heard of recursion before (even before I wrote the tree traversal code), but hadn't seen it applied to the type of problem I was working on
Once I saw an application of recursive tree traversal (on a binary tree, fwiw), using it in my other setting was a 100% no brainer :)
That's still true today - though I "program" notably less now (scripting, tool-specific languages, etc), all the whizbang features of whatever mean precisely nothing until I have a use case/application for them
But, once I started using Python, and specifically the ipython interpreter, I realized that programming didn't always have to be statically typed and compiled and work with a Makefile. It could work like a bash prompt!
Eventually, I did branch out into Rust for compiled languages, but my REPL realization gave me the ability to experiment and "fail fast" in a more familiar environment.
But it wasn't until I took a statistics class, which involved programming in R, that I began to realize the purpose of functions: to handle inputs, and return outputs.
The class involved data engineering, so I created functions to deal specifically with data.
And it was then that I realized "Ohhh... functions in any language just operate on data... so... with this knowledge, now I see the purpose of application routes in web frameworks like ExpressJS, Python Flask, etc."
A course on relational databases helped me understand how to store data.
And from there, I finally realized the purpose of a REST API, and how browsers connect to servers.
At that point, I realized "Wow, I finally understand how to create a full stack app (including database design)"
Then, during my pre-teen years, I couldn’t understand how games had several moving objects all at the same time even though it was sequential execution. Then the update-render loop clicked in as I discovered it. Together with that, all kinds of event handling, interrupts, context switching etc.
Then, with WPF, databinding really clicked in with any sort of retained-mode rendering. So then Angular, React etc as well.
But the first time, I was typing some very simple BASIC code on C64 from the user guide and a question popped in my brain: is it possible to change a program when it's running?
I was already a kid like to tinkering with basic electronics and mechanics but after this significant moment they started to decline steadily day by day and I put most of my time and energy to the programming.
Software development, another story...
I use PowerShell for a lot of my scripting needs and have found it to be pretty intuitive, but am wondering what other languages I might enjoy solving problems in.
https://archive.org/download/bitsavers_borlandturVersion3.0R...
Rereading the Wirth's book 20 year later, I finally realize it. Every product I have been working on was a data structure indexed by a key, then processed to transform the data into other data.
TL;DR - when I taught someone and did all her homework as well.