What was my Computer Science degree good for?
The 11th of September marked the 4th years I completed my Bachelor degree in Computer Science at University Geneva (unige).
I got this degree after 5 years at unige, a first year in the Sciences of Education and Psychology department, and four years at the department of informatics.
To be real quick, here is my professional life:
- 2018-09-11: Got my bachelor degree
- 2018-09-11 to 2019-06-01: job hunting
- 2019-06-01 to 2021-06-01: Work at Lombard Odier Investment Managers (LOIM) as Scala developer
- 2021-06-01 to 2021-10-01 Chill it out
- 2021-10-01 to 2022-09-01 Devil dahu (game dev studio)
More details are handed out in my 4 years retrospective post.
What was the degree good for?
Not C knowledge
The way we were “taught” C at unige was absolutely miserable, it mostly involved a link to a tutorial. C is not a trifle language to learn. This resulted in a half-arsed understanding of the dangers of the language.
The one thing you must know when starting to use C is that it’s not just about fixing the SEGFAULTs, but at uni, no one told me that.
It’s a few things outside of uni that taught me that:
- Horror stories blog posts shared on hackernews.
- The Gameboy advance game I made for the systems programming course completely breaking when trying to run it with a different emulator
- Independently buying and reading the K&R and “Expert C programming” that I still see stated as excellent references today.
Programming and Functional programming concepts
The introductory language at unige was Scheme. It is such a neat language to learn programming with. Scheme being pure functional untyped lisp dialect.
I knew a bit of Python before uni too, but scheme’s purity did require a new way of thinking about programming.
The other languages taught at unige were horrendous. Not that Java or Pascal are bad, but the way they were taught didn’t light them in the most compelling form. A major advantage of Scheme, is that we were recommended to use the Dr. Racket IDE, which works remarkably well and doesn’t require much setup. Pascal and Python are also pretty good in that respect (although as soon as you need a dependecy beyond the standard library, it goes apeshit).
But C, Java and matlab are very hard, not as programming languages per se (although Java and C have so many footguns it’s a wonder anyone who knows C can still walk) but to setup and actually use. Sure Java has a bunch of IDEs, and so does C, but as soon as there is an irregularity and your IDE fails with a cryptic error (if you are lucky), you are left to guess with absolutely no clue what went wrong. You actually need some understanding of compilers, linkers and concepts of binary executable to be able to fix issues with your C toolchain. While Java requires some understanding of javac and jars although compared to C, it’s trivial) to be able to generate bytecode and fixup IDE hiccups. This is especially true when you are not that familiar with programming tools, as an undergraduate wont to be. Matlab obviously has its proprietary plateform, but we didn’t have a license to use it, so it was either yarr-ing it or using Octave, which definitively doesn’t have all the features used during the various lectures that relied on matlab.
As a demonstration of what I’m saying. The build system for our system programming project used a monstrous template Makefile that came with the devkitArm toolchain. To me those looked like chtonic incantation, as palpable as an eldritch prayer (2016). Any issue with the build process couldn’t be fixed without the help of someone knowledgeable, and there were a few. Fast-forward to today (2022) and reading back this Makefile, I just understand it. Not that I used C very much (or even at all) between 2016 and 2022, but after learning rust, I have a much deeper understanding of linkers and compiler processes, and the Makefile is fairly readable with this context.
I randomly came across Hackernews and discovered there was more than what we learned at uni, and I was curious enough to try to learn more. This is when I tried out Go, Rust, Elm and Haskell.
I did fall in love with the clear syntax of elm. The lack of delimiter sigils and other character noises make elm and haskell stand out. I’m very surprised no more language have similar syntax.
This is when I turned into a pure functional proselytist. I’m less of a proselytist now, but I still believe that
list.map(f) is a better way of expressing “apply f on all elements of list” than
for elem in list: f(elem).
It would be disingenuous to say that elm was the language that introduced me to functional programming, because of Scheme, so I’d say the degree was in part responsible for this.
Functional programming is definitively what landed me my first job, and what led me to be such an active bevy user. So that’s a plus.
On top, the design process of elm apps (that I transposed later to design of my rust code) structured the way I write code. Now I feel confident from the get go how I would write and architect any application. Starting with guessing the flow, then defining the data types and then defining relations between them.
The unige CompSci curricullum is heavy on math, I even got taught by a now Fields medalist (!) and I consider myself privileged to have learned math at unige. I found math to not be compelling, but apparently I was good enough at it.
The maths I was taught wasn’t really the most useful. I loved inductive logic and made it my Bachelor thesis, but beside it, I’ve not used much math in my limited career. That was until I made games. Games require a lot of algebra at all layers. I don’t quite remember what I did in Algebra I, but the ease with which I wield math to solve my game problems today is definitively due to those lectures.
The parallelism course was definitively useful, the theoretical concepts I learned such as Amdahl’s law is still useful today to understand the behavior of software I write.
This course is also why I started using Linux. The parallelism lectures required MPI, which was impossible to get working on Windows or in a VM, so I installed a Linux partition on my system, and after installing Linux only being coerced into it, I more or less never booted on Windows ever again.
Knowing about complexity and theoretical limits of common problems help a lot knowing if you are doing something absolutely wrong, you should know the theoretical complexity of your problems and should know when your solutions are not just unoptimal but disastrously unoptimal.
Having a constant watch on the complexity of your apps is a necessity for developers. This is an important thing that I learned.
Even if my professional coding was in a higher-level language, understanding the underlying architecture of the processor helps tremendously write efficient software. Cache locality is always a worry of mine, and I generally avoid pointer chains. I understand how inefficient scala code is.
For writing game, this is actually fundamental, and I’m very glad I was extremely attentive during those lectures, while everyone else seemingly were so comatose that they didn’t even have the energy to browse casually Facebook as they did in other lectures.
The content of the course could be learned by following:
- The Azeria Lab ARM tutorial.
- The Tonc GBA tutorial.
I hated the database courses, mostly because the seminary assistant had a constant halitosis and always leaned in front of me when I asked questions, and seemingly I was the only one asking questions (now I realize I might see why it might be)
But SQL, I’ve no idea how I picked up, just clicks with me. I understand the query language as if I was fluent in it, despite not using it at all.
All of this considering that I never really used an SQL database or even SQLite. At LOIM, we mostly used MongoDB, and the little use I did of Microsoft SQL, was quickly replaced by a custom in-house database that would be better described as non-relational.
Statistics and machine learning
I never used machine learning outside of uni assignments. And I now forgot enough about statistics that I know that I don’t know enough to use it responsibly, compelling myself to avoid using statistics.
I recognize machine learning as something important today, and it’s just the contingency of my career that pushed me away from it.
After a re-try I got a perfect grade at my Networking lectures.
I think this is the lecture I forgot the most readily after completing the examination. It’s a shame, because a lot of the games I make could be improved with online multiplayer.
That course sucked and taught actively harmful concepts, I wish everyone that they forget what they learned during that lecture.
Agile is an important thing to teach, the Kanban (continuous improvement) philosophy is an important driver of excellence and high quality software. But learning it by rot is the opposite of what it’s supposed to be!
I think a better approach would be motivationally based. Pointing out anecdotes of disastrous software failure, and how it could have been fixed avoided through common practices today.
The course taught by Thierry Pun. He taught basic concepts like Phong shading and human visual capacity. The latter was mostly a watered-down version of the anatomy course I followed in psychology.
Human anatomy underly the motivation of a lot of the common compression algorithms used today, and it’s also an opportunity to talk about color space. Color space management is an absolutely mess in all parts of image processing software today, so knowing the underlying concepts helps knowing what you don’t know, rather than assuming it’s impenetrable.
However, physics is a major part of computer-generated graphics, and the approach to Phong used in the lectures failed to capture the motivations and justifications behind it. Furthermore, today’s CGI pipeline is even more physics-oriented, so that failing is amplified by modern advances.
The other limitation of the lecture was usage of matlab. Matlab is as far removed from actual CGI as anything can be! On top of it, it is proprietary and requires student to either spend an inordinate amount of money or using unoptimal workarounds (eg: Octave)
A more practical approach would have been usage of a GPU language such as OpenGL.
An approach, that I believe should still be complementary to the one used by Pr. Pun would look like ryg’s graphic pipeline series. However, such a practical hardware-based approach can really only exist in combination with a more historical and motivational approach, such as the one used by Pun.
Independently learning to use Blender in college and during my psychology years did help me more with graphic programming today than that lecture, which is a shame.
Practical software project
A semester was dedicated to develop as a team a software project. I volunteered to develop the CI for it, learning to setup jenkins, opening ports and setting up firewalls to let my teammate consult it, creating a discord bot for chat-ops (of my own initiative), setting up a wonky under-documented pile of java code called Wildfly 11
updating log4j. Fixing the setup of my teammates etc.
I even introduced someone to VSCode when it was the hot new thing! (though I never used it myself)
Ahah, it was a great introduction to my future job, and I wouldn’t exchange it for anything else.
What is missing in the education I had?
- Software Correctness
- Teaching the limitations of C
- Dangers of lousy programming such as common antipatterns (magic numbers, Null, magic strings, ex-nihili architecture, surprise mutations (aka spooky action at a distance), etc.)
- Modern software development practices
- Very basic introduction to compiler, linker, virtual machines (jvm) and generally give an idea of how fucked up and potentially bizantinely complex dev tooling is (android APK and Gradle ahah). This should be a very early course, after introductory programming, but before teaching C or other programming languages (also contrast to modern tooling like cargo and poetry, to demonstrate not all is lost).
- Proper code review (basic human decency, why it exists)
- Limitations of OOP (composition over inheritance, pointer-chasing, leakiness of GC, lack of referential transparency, why it’s a problem with concurrency)
- CI (what tools exist, what are the trade off in terms of velocity correctness (btw I think this should be softeng courses))
- Actual graphic programming (glsl or even a watered down education-oriented language like futhark, a major downside of matlab is that it doesn’t run on GPU)
- Practice in network programming (unix sockets, Nagle’s algorithm)