The Tragedy of AP Computer Science Principles at My School
I took AP CSP in 2020, which may have made it a little different than usual on account of the virtual lessons (very fitting for a CS class). I am still disappointed and frustrated in how much the poor curriculum and teaching has failed the students.
First Thoughts
The class was not useful. All I could think while attending it is how the spirit of exploration had been removed in order to make way for AP test preparations. A sad fate for such an interesting field of study.
They used code.org for lessons, which was at best good, usually questionable, and at worst abysmal. I heard they used to use something different, but they switched to cut costs on the previous provider.
When they taught about "App Design" (using a tool exclusive to that site), they taught about event handlers that used callbacks before even mentioning functions. Most of the JS you would use in this "App Lab" was not valid JavaScript, but they didn't make that obvious to the students. They should have at least had some notion of importing a library to use the functions, but no - all of this was hidden. Great way to have students tripped up when they get to writing valid JS away from code.org!
All of the functions you would use to interface with the GUI from the tool were not valid JS either, even though they could have made the GUI designer create an HTML page and interface with it like JS was made to! Why they chose not to implement the interaction in this natural way that existed already is beyond me.
Teaching how to Do without Teaching how to Think
Despite callbacks being the main method of interface between GUI components and code, they never once even mentioned how functions are first-class citizens in JS.
The accepted method of writing your event handlers is like so:
onEvent(id, event, callback);
Where id: string
was the ID of your GUI element, event: string
could be one of a number of interactions that could happen between the user and the element that should call the callback, and callback: event => ()
was the function that would execute whenever the event happened on the ID.
This is the format you would see:
onEvent("myButton", "click", function () {
console.log("myButton was clicked.");
});
This was beyond dumb. Although one learns early about how to do a thing when some event occurs, one never learns about why that code worked.
Learning about why is especially important here, because already this introduced at least three important but foreign concepts:
- Functions as first-class citizens
- Higher-Order Functions
- Anonymous Functions (Lambdas)
None of which were discussed later. We were essentially taught to go in blind and know that if we write that, it will work. If we had learned why this worked, I forecast we would see less of this:
onEvent("myButton", "click", function () {
doSomething();
});
and more of this:
onEvent("myButton", "click", doSomething);
After all, it works the same way. That's only the surface as well. If they taught why this works, students may use closures, curried functions, and other such tools to make readable, concise, and maintainable code.
Lesson (Dis)order
This class has some very strange ideas about the order of learning. We learned about onEvent
, a higher-order function, before we learned about functions at all (That was in the next unit). When we did learn about functions, we were taught about them just as procedures - those that receive no arguments and are void (type signature () => ()
), whose existence is only to alter the program state based on the current program state!
They even said that functions are also called procedures, when functions are so much more. I've skipped to the time where they say that. I guess they are one in the same when you limit yourself to the () => ()
type, but you shouldn't do that, so why did they teach it that way?
It's unfortunate, this curriculum had us learn about arrays separately from variables! We learned about variables one unit before.
"Maintainability? Extensibility? Design? Man, I just code!"
The unit where you learn about lists is called "Lists, Loops, and Traversals". You do not learn any data structure other than the list. This led to very shoehorned code from others (I saw a lot of traversing multiple lists in parallel to solve what could have been solved far better with an object ("dictionary")). General problem-solving with shoehorning also made it virtually impossible for people to collaborate on projects if they both weren't familiar with the project and its "design" (always the lack thereof) from the start.
Because of this lack of design philosophies, when the students made programs, everyone made their own distinct rules and reasonings, even if they didn't know what they were. Everyone had their own "Big Ball of Mud". Almost all the time, one student's ideas were incompatible with other student's ideas, hence why students had great difficulty helping each other. Worse, still, they couldn't figure out why, because they hadn't been taught to figure things out.
JavaScript didn't help with reasoning because of the weak typing discipline, but that wasn't the big issue. The big issue, was that not only had nobody been taught about design, no one (at the time, I'm not even sure I did!) had the slightest idea that a computer program is more than its functionality. It was only in the very last unit before the final project preparation that they taught us a "radical" new method to write your functions, and by extension, your programs. The unit name should say everything about that: "Parameters, Return, and Libraries". At our school, for some reason, we didn't do the libraries part.
God only knows why they did this. Only near the end of the school year did they teach you how you can write functions that receive arguments and return output! This is shameful and they should have taught it this way from the start.
Pathetic "Patterns"
The most ridiculous thing from there, I think, is found when looking in the lessons on "traversals" (only on lists here), where they mention "traversal patterns". They wrote these in the worst way possible. Not extensible, with extremely poor maintainability, long-winded, and completely set in stone (our dear "friend" () => ()
is back with these).
There are the "List Filter Pattern" and the "List Reduce Pattern" - neither of which use Array.prototype.filter
or Array.prototype.reduce
, as you might reasonably expect, nor do they at least talk about a good method to write these general functions yourself, no.
They hardcode everything! The list they read from, the list they write to, the validation / combination logic, all of it set in stone like I said.
Honestly, there are the dumbest "solutions" they could have come up with. They write out, in real, valid code, their suggestion for what to do when you need to do one of these:
Make a void, zero parameter function (
() => ()
) that reads your list from the outer scope.Inside there, do some transformation, some computation (they all use loops) and then write to another variable from the outer scope with the result.
Yes. Because god forbid you learn about return
early.
A Little More on the Order of Lessons
They should be teaching functions, proper functions, none of this () => ()
crap, before teaching about arrays. I would go so far as to say that they should teach about functions before teaching about variables.
A function returns a value, you can't (maybe you can, but you shouldn't) change the function implementation once you've defined it. You invented the constant, now how about the variable?
The order of the things you learn matters a lot. They messed it up in my class. Even with something as fundamental as functions and lists, the order is poor.
The Teacher Travesty
My teacher was not great.
Everyone I've talked to about her seems to agree - she's a nice lady but not a great teacher (at least, not a great Computer Science teacher). She doesn't stray from curriculum, doesn't go out of her way to introduce, encourage, or discourage certain practices. She says she just does what's there to prepare students for the test. I don't think she really knows about programming, and the reason she won't question the curriculum for the better of the students is because she is paid to parrot it.
I got a hint at why this may be from this video. This is what they said:
Our CS Principles course also has been designed for teachers who don't have any background in teaching Computer Science.
That sounds like a recipe for disaster, or at least mediocrity. I get the feeling that a "teacher" who doesn't have experience teaching Computer Science also most likely doesn't have much experience in the field in general. Why should you have a teacher teach a class for a field they have little to no experience in?
The Students Do Not Need Coddled
I have seen, too many times, students being treated as children in this class.
This helps nobody.
No High Schooler wants to be treated as though they are a child.
I've seen students in the class who do not care about Computer Science at all. I asked them why, and they all said that their guidance counsellor put them in the class and they don't care about it. With the class in the state it is now, no wonder. I bet if they actually tried to engage the students with things that were new to them, this wouldn't happen. No student ought to need more than a class period to learn what an if
statement is and what it does, more a day to learn about why functions (that take arguments and return a value) are useful and how to use them, and more than a week to understand something like higher-order functions or currying. So what are they waiting for, and why do they drag on and on with things everyone already knows (or at least ought to).
No High Schooler needs to start with blocks to learn about programming. No High Schooler needs to be shielded from programming paradigms other than imperative procedural (with a smattering of event-driven). No High Schooler needs to be protected from functions with parameters and return values until nearly the end of the fucking year!
There are so many other ways the class could go. We could learn C or C++, and gain a deeper, more fundamental insight on how computers work, closer to how they really work. We could learn Scheme or Clojure (or some other LISP), and gain an appreciation for the simplicity of the language design and an understanding of programs made of proper, mostly pure, functions, composed with each other. We could learn Haskell or F# for the same functional programming insight with a more common syntax, and we could learn Java or C# for a solid (pun intended) understanding of Object-Oriented Programming and OO design principles.
But no. We were left with JavaScript, and taught to write code in bad, inelegant ways that made sense, instead of being taught the good, elegant, maintainable ways and having the curriculum make them make sense!
Final Thoughts
This whole class, the teaching, the curriculum, the lessons - it's all malformed at the moment. I hope that someone will step up to make changes for the benefit of the students.
Maybe this class will prepare students for the AP CSP test, but it won't prepare them for actual programming.
That is why when people ask me if they should take AP CSP, I tell them this:
It's an easy A, but don't expect to learn how to program.