I'm continuing my reflections on the courses I've taken at Yale.
This time I turn to my programming certificate, which is Yale's way of saying a CS minor. In total, I've taken 7 CS courses. 5 of them count towards the certificate, while the other two are used for my S&DS major. This maneuver was entirely operational and there's really nothing fundamentally statistical about those two courses, so I'll just treat all of these as a single curriculum.
I must first and foremost say that I enjoyed telling everyone "no I'm not a CS major" because everything I do is so CS major. A major reason why I did not do that is because I love statistics and linguistics much more than CS, so given I only have two major slots I would absolutely prioritize them. The second is simply don't have time to take more CS courses than I already do (though I already come remarkably close—a CS BA only requires 9 courses besides the senior project). The third is Yale doesn't offer enough CS courses I would enjoy: my interest is narrowly focused on programming languages and compilers, but we only have a few professors who occasionally teach them, and the resources are not getting ampler with time. I didn't even take these classes for the goal of obtaining the certificate; I took CS classes that I liked, and by my senior year, I worked out a combination that gave me 5 CS classes uncounted towards any major, which I lumped together and got a certificate. Anyway, I think I've saturated the CS classes I absolutely have got to take, though there are probably more that are interesting enough for me.
Half of the courses I took were either because CS people all need to take them (I LARP as a CS major and take courses that actually aren't required for my certificate) or because I need to satisfy some distributional requirements: CPSC 223 Data Structures and Programming Techniques (semester 3), CPSC 323 Introduction to Systems Programming and Computer Organization (semester 4), CPSC 365 Algorithms (semester 4), CPSC 447 Introduction to Quantum Computing (semester 7).
CPSC 201 Introduction to Computer Science: I didn't take this course, but I feel obligated to mention it. This was nominally the first course in the Yale CS curriculum, whether you are BS, BA, or certificate. Many (me included) skipped it because (1) it's easy (2) it's poorly taught (3) it's useless for what most people are interested in: software engineering. But the CS department, in their infinite wisdom, decided to make it a hard requirement and the registrar will literally drop you from CPSC 223 if you haven't taken CPSC 201. I know every single bit of information in this course and they want me to waste a precious credit on it, which I would have to have done if I started just one semester late with CPSC 223. Absolutely outrageous. Course-content wise I actually think it's a rare kind of good: it teaches Racket, functional programming, recursion, Turing machines, etc., things that the average person who "just want a SWE job" would never have touched, and it was challenging for some people, so when many people call for the course to be completely reformed, I actually want it to stay as-is. I just want to give it a negative number because of the idiotic CS department policy, not anything to do with the course in particular.
Usefulness: 3/10; Difficulty: 1/10; Recommendation: -1/10.
CPSC 223 Data Structures and Programming Techniques: This, at my time, was the first course of the major for those who opted to skip 201. I could have skipped it too and gone to higher-level electives, but I decided to sit through just for FOMO. Turned out to be pretty much useless other than properly learning pointers and malloc and using valgrind. I finished every 2-week project in a few hours and finished every 75-minute exam in 30 minutes. However I did develop a special relationship with the course: I came back to serve as the ULA (like TA, but for undergrads) for 4 semesters. I had helped countless people debug their programs and walk through tricky data structure problems. I designed and maintained the automated grading infrastructure. in Through these experiences I knew more CS students than many actual CS majors, and certain more than the S&DS majors I knew. So I certainly would have been worse off if I didn't take it, but it didn't come the way I expected. I do think there are a lot of ways the course can be changed, which I've written down in my opinion on C and my opinion on using AI in classes.
Usefulness: 5/10; Difficulty: 2/10; Recommendation: 6/10.
CPSC 323 Introduction to Systems Programming and Computer Organization: This has the reputation of being one of the hardest courses at Yale. I didn't have to take it to pursue my certificate, but I took it anyway because I want to take the fun stuff which all require 323 as a prerequisite, and again, I don't want to miss out. Like all the other CS classes, I didn't feel any particular stress or workload. I finished all my projects with ease and spent the rest of my time optimizing the heck out of them. Fun anecdote: our first project was a TeX macro processor involving lots of string operations, and I implemented a zero-copy string buffer using a linked list of tokens, thinking this would be much more performant than others' naïve index-shifting approach; turned out I performed 2x worse than the reference solution, for one simple reason: I used fgetc() instead of buffering ahead, and the frequent system calls tanked the performance. I learned my lesson the hard way about how system calls work. The class also motivated me to finally learn Rust properly, which was really useful for the later electives (we were the first class with which they started experimenting with Rust projects instead of C). Theory-wise, I now know page tables, CPU cache, x86 assembly, virtual memory; I can't see myself needing them in the near term but they sound like important things to learn. Here's an analysis from a fellow CS student (forgot who that was): there are two types of "hard courses"—those that are intellectually challenging, and those that are tedious and time-consuming. You basically always get a weighted mix of both and rarely a course that truly stands out in both. I wholeheartedly agree with them that 323 lies very far to the end of being "time-consuming but in fact not very intellectually demanding". I even consider it to be small potatoes when compared to LING 231 Neurolinguistics.
Usefulness: 7/10; Difficulty: 6/10; Recommendation: 8/10.
CPSC 365 Algorithms: I took it because CS students all do (and eventually it was listed as required for the certificate anyway). After doing competitive programming for 4 years before college, I finally conceptually understood what Dynamic Programming does. (This is like my revelation about what "marginal probability" actually means, which, should it have come a few years earlier, could have made me literal statistics superman.) It also gave me a somewhat deeper understanding about graphs (max-flow, cliques, etc.), divide-and-conquer, and NP-complexity. I guess this class would be more useful for the LeetCoders who actually need to write these algorithms a few times in their lives for job interviews? I certainly liked writing mathy proofs and solving arcane problems but I can't see them being a daily staple for my job.
Usefulness: 5/10; Difficulty: 5/10; Recommendation: 7/10.
CPSC 447 Introduction to Quantum Computing: I took it for the science credit, and also I thought "oh maybe I would use them in production one day if they actually have good compute!". Let me tell you this: I got nearly 100% on every single exam and problem set, and I still can't "see" quantum computers. I understand superposition, quantum gates, error correction, etc., but they were never embodied with any hardware description or engineering practices. I guess those would be far out of scope for an intro class, but it effectively made this class just glorified linear algebra all along. I was soullessly computing eigenvectors, doing matrix multiplication, and applying existing quantum circuits for all exams while reading off my cheat sheets. It was a pretty demoralizing voyage because you didn't know at which point sh*t would explode and you realize you have no prerequisite knowledge whatsoever to understand today's material. Luckily that day never came in this semester-long course.
Usefulness: 1/10; Difficulty: 7/10; Recommendation: 3/10.
The other half of the courses, I actually took them because I wanted to. All of them are compilers / programming language related: CPSC 421 Compilers and Interpreters (semester 5), CPSC 454 Software Analysis and Verification (semester 5), CPSC 430 Formal Semantics (semester 6).
CPSC 421 Compilers and Interpreters: This is like the compilers course at Yale so obviously I took it at my earliest convenience. I was also tinkering with my own programming language, so perhaps I could use some systematic learning about how lexer, parsers, semantic analysis, etc. work. Well I don't think it taught me anything beyond what I already knew from working on the typescript-eslint and TypeScript codebases. I understood on a theoretical level how LR(1) parsers work and how you read type inference rules. The toy compiler we built in the final project was comparable to the one I already built myself and it used libraries for lexing/parsing anyway. Learning OCaml was very useful, though—taught me that not every functional programming language is as beautiful as Haskell and sometimes people can commit blasphemy because they want to "make it work bro".
Usefulness: 7/10; Difficulty: 5/10; Recommendation: 7/10.
CPSC 454 Software Analysis and Verification: This is perhaps my favorite CS class of the few I've taken. I thought it would be about linting and type checking, but it was actually about formal verification, something I didn't know I didn't know! (Quelle horreur !) I learned about pre-/post-conditions, SMT solvers, decision procedures, etc. We wrote 4 projects, 2 of which were Haskell (because they implemented a mini language and the parser/lexer were distributed in Haskell Alex/Happy); the other 2 were free-form and I chose Rust. Although this sounds like a niche subject, it actually is super relevant to both my projects, my work today, and the industry as a whole. I hope more people can reason about their programs in a mathematically-informed way.
Usefulness: 9/10; Difficulty: 7/10; Recommendation: 9/10.
CPSC 430 Formal Semantics: I personally admire Professor Zhong Shao (trivia: the Zsh shell is named after him) and the work he does, this course itself sits right in the center of my interest, and it's offered about once every 3 years, so it seemed like the stars were aligned and it was now or never. I thought it would have significant overlay with CPSC 454, but this one was actually much more mathy and proof-based. I did not write a single line of code nor did we see any real code; we talked abstractly about if...else, while, etc., without any of the language-specific constructs like classes (I know they are syntax sugar but only offering an essential core made it pretty disconnected from real software). I wrote Rocq proofs to validate the predicate-logic-based semantics of a program. Rocq was extremely useful though, because it was my first time seriously using a theorem prover, and I learned a lot about proof techniques, all of which is especially relevant today with AI math.
Usefulness: 7/10; Difficulty: 8/10; Recommendation: 8/10.