I agree, I don't think there is much difference in intrinsic ability. I'm absolutely convinced that every healthy person can become a really good programmer.
But becoming a really good programmer requires putting in a lot of time doing programming, and a lot of students don't put in that time.
I've been programming for nearly 40 years. Based on my interactions with others, programming is an intrinsic ability. People that don't have that intrinsic ability can cut'n'paste their way through simple programs, but really struggle to understand what they are doing and why their program works (or not).
Anecdata: My high school got access to a computer (dialup modem). I essentially taught myself programming and then took the official class to teach me programming. Aced it, obviously. My younger sister saw how much I enjoyed programming so she took the class and struggled tremendously. I tutored her... I recall a problem where she had to do an operation repeatedly, an obvious (to me) application of a "for" loop. She struggled with why one problem pattern required a "for" loop and one pattern required an "if" statement.
My sister is very smart and was a straight "A" student in things that she could memorize, graduated from college summa cum laude (IIRC). She became a very good elementary school teacher. Myself, I was very much not an "A" student, especially in things that required me to memorize facts, but I "got" programming instantly.
More anecdata: I am now mentoring FIRST Robotics teams. I continue to see a dichotomy in aptitude for programming... two years ago I walked a student through a program for controlling a robot. She got pretty excited and interrupted my explanations and said "wait, let me think this through"... and she (verbally) worked out the logic of a complex "if" statement. She took over programming that year, is now in college pursuing a Computer Science major, and loving every minute of it.
Still more anecdata: Last year and this year I have a student that loves computers and intends to pursue it as a carrier, but he isn't a "natural." I spent a huge amount of time last year coaching him, but he still struggles to understand what pattern he is looking at and why e.g. he needs a "for" loop to solve the problem.
I could give a lot more anecdata, but I've worked with Robotics students that can program e.g. move sequences once I coached them through the details and I've worked with Robotics students that took off and created complex programs with nothing more than a simple introduction to constants, variables, loops, and conditional statements.
My problem with these theories is that people like me just don't fit into them at all.
I've always been slow. Never did all that well in classes. When I was on a FIRST Robotics team I was phased out by the genius programmer that was already there and barely saw any code. I never really had a problem with for loops or if statements. But never really instantly got the more complex programming concepts, either. My father was a programmer so I was exposed to a lot of the things earlier, maybe that's why I missed the not getting for loops stage. I shouldn't be a programmer if many posts in this thread are to be believed. My father shouldn't be, either.
Worst of all, my programming understanding has went through several key developments in a very jagged fashion. For loops and if statements just didn't give enough to push me over the edge. And it wasn't just programming, but the general theme was that sometimes I would just not get some concept, or miss a simple concept, and after that, I would get stuck, and I could not get unstuck without some unusual event like getting the right help from the right source at the right time. One of my most important degrees of understanding did not develop until I took a certain class in the second-to-last semester of college.
After a while, it seems that enough things clicked all at once, and the problem went away. I don't get stuck anymore, I always know where to go. But that was supposed to happen earlier, so much earlier, but it just didn't.
While this was all happening I was definitely the kid who doesn't get it in the eyes of others. Maybe there's some teacher or mentor out there right now writing a blog post or a comment somewhere else about how they tried, they really tried, but I didn't get it.
And, yet, leaving for another industry would have easily been the worst decision of my life.
This is surprising. I used to be like your second student according to my father. He taught me most everything I know, and my brother used to be like your first student.
I found what personally helped me to overcome the insight bridge/gap was I had to read several different books to find the right analogy that helped achieve the "insight".
There are certain things I definitely did not get in the beginning. But after working very hard I got them.
I am curious what percentage can make the jump as I did. Clearly there are certain "epiphanies" to be had. I almost immediately understood "for" loops, but took several years to get pointers and polymorphism each. I know of people who get some or all of these concepts instantly.
There is clearly the appearance of bimodality here, even in just my experience with just how I learned things.
That's an interesting question. Programming is definitely a skill so study and practice certainly matter. But it's possible the limiting value is the same as g or at least something that includes a set of abilities highly correlated with g (e.g. working memory).
Well, if you enjoy something, it's much easier to put a lot of time in to figure it out.
For example, I became a software entrepreneur about five years ago making money from my own projects. Dealing with a lot of business related "work", I actually discovered I also really like law, in particular tax law.
A friend of mine was a pretty good lawyer (hung up his hat to do more entrepreneurial stuff) and I occasionally ask him to look over contracts I've drafted. He said some of the contracts I put together are better than what some of his colleagues put together. I've also defended myself in a few tax disputes with legal arguments, and always won. If I knew more about it before, I think I would've genuinely enjoyed being a lawyer.
If you enjoy something, it's not that hard to become really good at something. If you don't, it is extremely hard to become better than the guy who loves what he does.
>> Well, if you enjoy something, it's much easier to put a lot of time in to figure it out.
I started programming as a kid because I wanted to make games. It was fun. The problem was that I didn't get the more formal stuff until college, and it made me a much better programmer. But I could also see how boring the data structures class would be to someone with no experience because they really didn't have insight into how applicable some of the concepts could be.
I have always advocated for creating games (and other useful things) to teach programming. Most if not all the major concepts can be applied to games. Why anyone would use the fibonacci sequence to teach recursion is beyond me - it's a stupid solution to a stupid problem. Let's talk about board games and minimax search. Yeah, you have to build a lot of code before that comes into play but you'll learn a hell of a lot more and have way more fun doing it.
Doing simple games like 2D scorched earth really brings home basic vector math and physics. Any 80's arcade game with a thrust button allows you to apply that stuff.
Any kind of 3d graphics goes right along with linear algebra - a topic that is not required by all CS programs even though matrix operations run 24/7 on supercomputers.
Text processing. chat bots anyone?
I used to have an example that used trees but it escapes me right now. Chess doesn't really count because you don't store the tree. We can go back to 3d graphics of course - photon mapping, kd-trees, various BVH structures.
If you start with data structures and algorithms, peoples eyes will glaze over. If you start with simple things that are somewhat interesting you'll get people interested and then you can progress them slowly to more advanced topics by introducing problems they'll want to solve.
I agree with all that, and in my experience, students really react well to courses and coursework based on doing games.
And yet, I will use Fibonacci as introductory example tomorrow when I teach "Intro to
computational complexity" this week. The great advantage of Fibonacci over just about anything else
is that it is so short, so simple, that everybody can immediately understand it. There is no preparation needed. Just about anybody who can breath, can understand Fibonacci.
Despite this simplicity, Fibonacci is so rich:
You can use it to illustrate: Recursion, exponential complexity, going from exponential to linear
complexity by memoisation. Relationship between loops and
recursion. Tail calls. Stack space used by compilers, the limitations of compilers that do not do proper tail
call optimisation,generating functions, recurrences, solving
recurrences.
>> And yet, I will use Fibonacci as introductory example tomorrow when I teach "Intro to computational complexity" this week. The great advantage of Fibonacci over just about anything else is that it is so short, so simple, that everybody can immediately understand it. There is no preparation needed. Just about anybody who can breath, can understand Fibonacci.
Despite this simplicity, Fibonacci is so rich: You can use it to illustrate: Recursion, exponential complexity, going from exponential to linear complexity by memoisation. Relationship between loops and recursion. Tail calls. Stack space used by compilers, the limitations of compilers that do not do proper tail call optimisation,generating functions, recurrences, solving recurrences.
I agree with all you said too ;-)
I would say "Intro to computational complexity" is a more advanced course and the students should already be familiar with recursion from experience prior to learning to analyze time complexity ;-)
IMHO Fibonacci is still a poor example because the most obvious (to me) implementation has always been a loop. Pointing out how a recursive version can be simplified to a loop seems silly, and so does making it more efficient with memoization. But as a first example, sure I suppose. Then you drop the bomb on them and show how it can be done in O(log(n)) by using fast matrix exponentiation.
Thanks for reminding me of the O(log(n)) algorithm. I had forgotten about it. Just added this algorithm to the lecture slides. I <3 the internet.
I start with the recursive algorithm because it follows directly from the definition F(n+2) = F(n) + F(n+1). I also think there's a big schism in programmers: between those that think recursively, and those that are of a more iterative bend. I'm in the former camp, probably owing to the fact that my first programming language was Scheme.
This is a problem in general in math-based education, and sometimes in science also. The solution is problem-based teaching, where the problem is introduced before the solution. By establishing the need for something first, it makes it much more concrete.
It's not really surprising that good programmers are often also good at legal drafting.
When you're a programmer, you understand that the processor is dumb and has to be guided through absolutely everything. If you don't factor in the corner cases, your program is going to screw up somehow.
Legal drafting is the same thing, just replace the processor with a judge and the programming language with English. If, while writing a contract, you precisely define everything and cover all the ins and outs of what can and cannot happen and what should and should not happen in the event that any or all of the above likely or unlikely events shall happen during the lifetime of the contract. Then if you ever need to get the contract enforced by the judge, you can clearly point out exactly how the opposing party already agreed to resolve the situation in some way.
The real reason why you need to hire lawyers has more to do with making sure that the contract you draft is enforceable (considering current law and legal precedent), or else risk having the entire contract thrown out later by the judge. AKA legal system faulting.
A lot of less technical management doesn't understand how important being able to find corner caeses is. This is what separates a good and solid application from one that is routinely failing.
I think the question of whether anybody can get good at programming is very interesting. I often hear "anybody can do it, but you can only become really good if you enjoy it".
So then the question is: why do you enjoy something? Are we born that way, or is it something we do? (I don't know what the answer is)
Edit: also, it is interesting to replace "programmer" with "math professor". Can anybody become a good math professor if they enjoy doing it? If not, what is the difference (assuming it is true for programmers).
For me I think the determining factor of a good programmer is not enjoyment (although that is necessary), it's curiosity. I work with a guy who I'm pretty sure has a photographic memory and would probably run circles around me in an IQ test and with his GPA, but I'm constantly showing him more efficient ways to write code. The difference is I am forever curious about CS-related stuff. I spend hours a day reading HN and other things like it. I'm orders an of magnitude better prgrammer than he is simply because I'm curious.
I think it's a bit of both nurture/nature. In hindsight it was obvious that I would be a programmer even though I didn't have much access to a computer until college. Growing up I gravitated towards math/science, loved any sort of problem solving, and enjoyed things that many would consider tedious (building model WW2 naval ships with my grandfather for example). I did have a Nintendo that was in a constant state of being taken apart, but it did work most of the time :) When I finally had school computer time starting around middle school, they literally had to drag me off of them. Trying commands, tinkering, etc... was just...fun.
None of my friends (or parents for that matter) understood because they were mostly jocks with a few artists types mixed in. But, my friends never cared as long as they could get me out of the house to play whatever sport was in season.
To circle back around, I had a natural inclination with people like my grandfather encouraging it without really knowing.
I'm not sure but I suspect that viewpoint has a massive effect.
It's similar to the old saw about growth vs fixed mindsets.
I often describe programming as "failing 99 times and succeeding the 100th time, and counting that as success". There are a lot of people who are not wired and acculturated to that sort of "success".
That said, I don't (obviously via the growth mindset) think it's a fixed quality, it's more of a learned and acquired routine.
I think our enjoyment of an activity depends on how we see our progress.
If we keep struggling with it, we will hate it, even if we thought we would like it at first.
We could also begin to enjoy an activity if we see ourselves progressing in it. When you see your improvements, your brain probably releases dopamine (or another one of those addiction chemicals) and that makes us want to do it more (to taste that sweet taste of victory/progress).
Some subjects aren't really fun until your good at it though. I used to hate it until I forced to do it and found it was fun after I got the basics down pat.
When I think of somebody who enjoys programing, they usually have a goal or task to compel them. Just solving random CS questions and math is pretty boring to the majority of folks.
It's not fair to call people that find programming difficult lazy. You can work harder and longer, but it only pays off up to a certain point.
There are some tasks which require more intelligence, and some which are easier for more people to do. And thankfully. there's more that can be done to make the former more like the latter.
It's really not about time, it's being able to think flexibly. I have seen several freshman who never coded before where 1/3 of them get it in a few weeks and have an easy 4 years, where the second set either drops out or spends a lot of time trying to keep up.
An assembler class where the high end spent 2-3 hours and come in with 3-5 pages of code vs. the low end that spent 50x as long had 100+ pages of code that did not quite work. At first glance the difference was if you looked up how the math coprocessor worked, but more generally how much you tried to brute force the problem vs. look for a cleaner solution.
I don't think he was refering to time spent on a given program; rather, for people who don't intuit CS concepts time spent staring at the page can make the difference between a person who never gets it and one who eventually does. At that point, there isn't much functional difference that person and a person who got it from the start.
I don't think it's really about the CS concepts as it is being able to link them together flexibly. Suppose you want the median value in an array. Well sorting makes it easy, but you don't need to fully sort the array. A modified quick sort seems like a good compromise, then again using a built in sort is probably fast enough and much less code.
That's the kind of thinking that really works. Because you can look up well known probelms, but you need to start thinking in terms of trade offs instead of going with the first idea.
I would argue that in order to link them together one must first understand the CS concepts and their uses. Once a person has that understanding, it becomes trivial to know when a naive solution is no longer the right approach. Once a normal person has the ability to see problem solving like that, they've pretty much got it.
That's not to say there's not a difference between all possible solutions and the people trying to find them. Some will be able to zip together the objectively most efficient solution right from the start. These are the true "superstars." People for whom doing something once is as good as doing it a million times (ie, they don't forget things). These folks are exceedingly rare and the rest of us will have to settle with kowing enough to know when we need a better way.
I get where your coming from, but many people can get all the individual concepts and still not make the connection.
If they want to double X, they are happy to use X + X, 2 * X, or X << 2 and map them all to the same place. So, if they suddenly can't use * because the CPU does not support it they are happy to use the other 2. And somehow this is the same skill where someone hmm database is to slow, let's do X.
It's probably a learnable skill, but it's just not directly part of CS classes. Someone can learn X XOR 1 is the same as X MOD 2, it's another to use XOR when they can't recall the MOD symbol.
Maybe I'm missing something but in your two examples, what you refer to as skill is just recall. I would argue that in the context of alternative solutions, the skill would be knowing when a better alternative is needed when it isn't immediately obvious. If I knew mod wasn't available yet I neded an analogous operation finding an alternative is trivial even if I don't recall it. I wouldn't call that a skill.
It might seem obvious if A and B do the same thing then you can use A or B to move on to the next step, but many people don't think this way.
For a non programming example, you can use the handle of a shovel as a long stick. This should be more or less obvious when looking at a shovel, but I have seen people ignore shovels when looking for a stick to do something.
But becoming a really good programmer requires putting in a lot of time doing programming, and a lot of students don't put in that time.