Teaching a Class at Uppsala University

In the first quarter of 2024, I did a short stint as a teacher at Uppsala University. I taught the class “platform-spanning systems” (PSS), which is a fourth-year/masters-level course for engineering and computer science students. It was fun and rewarding to be back at the university, and I probably learnt as much as the my students.

PSS?

Just what IS a platform-spanning system? When I agreed to take on the course, I had only the vaguest idea. The content of the course under this same name appears to have drifted over time. From what I gather, initially the course was about Java programming and programs/code that could run on multiple different platforms. I.e., spanning platforms in the sense of portability.

Today, it is about building an application in the style of a mobile app or web application. I.e., approximately consisting of a least a frontend, backend, and database. The spanning is in the sense of a single application spanning across multiple systems. In any particular case there might be more servers and other types of nodes like sensors or actuators. To give an idea for the possibilities, I showed this slide to the students:

In detail, the way I defined the contents was that the students should build an application that is implemented:

  • Using at least three physical processes (i.e., separate process instances on the same or different hosts)
  • With at least three different implementations or applications (i.e., different code bases)
  • Running on at least three different hosts or platforms
  • Communicating through some kind of network connections.

It would be nice if there was a better name for this, but neither I nor any previous teacher have come up with one.

Initially, it felt like this could be called a “distributed system”, but that does not really fit. Typically, a distributed system would consist of many compute nodes running the same program. So that moniker does not quite capture the essence of the course.

Project Course

The course was a project course, with the students organized into groups to implement an application from scratch. We started by randomly assigning the students into a few “idea groups”, each of which came up with two ideas for the project. Next, all the project ideas were presented to the class, and the students choose which one they wanted to work on. With a small bit of teacher-driven adjustment we ended up with seven groups doing four different projects: there were three projects that had two groups doing them, and one group doing a unique project.

Having multiple groups do the same project was quite instructive. It showed how differently you can solve the same problem and how differences in background knowledge affect planning and emphasis. For example, one group focused on the server side and the backend with a minimalistic approach to the frontend, while the other group doing the same project started from the frontend and put less effort into the backend.

The students self-organized their work within the constraints of the course. Each week they handed in a sprint report and a demo, forcing a one-week sprint rhythm on their work. A one-week sprint is unrealistically short, but it meant they did get to do enough sprints to get a feel for how it works. Doing fewer sprints would have hurt the learning objectives. As can be expected, almost everybody split into sub-groups to handle different parts of the system. With attendant synchronization problems, which is also a learning objective.

For most students, this was the first time they were set free to implement something in any way they liked using (almost) any technology they choose. They also had complete freedom to organize the project groups. Such freedom has the potential to lead to disaster, but all groups got going quickly and the project collaboration worked.

The students were surprised by the fact that there were no hard rules and must-do (except for the weekly reports). I very carefully stuck to the “I do not care how you solve a problem” line for most cases. Just like I prefer it at work – product management is involved in determining the “what” we want to achieve, and leave engineering with the details on just how. As long as the “how” does not impact the “what”, of course.

Architecture and Solutions

The groups all basically came up with the same architecture – one frontend, one backend, and a database. A couple of projects had multiple frontends for different user roles, but they all connected to the same backend. One project had sensors in addition to the user-facing interface. Despite talking about it in early lectures, there were no real attempts to do microservices or more complex setups, which is understandable given the limited time of the course.

All the projects had a significant user-interface component, which made for good demos. However, the backend is also important. To demo the backend, the students used things like REST API entry points or just showing the code. The tools that allow REST APIs to be explored and interactively experimented with make for passable demos of at least the interface to the backend. There was no time to build backend dashboards or other inspection interfaces.

When splitting up the work in the groups, the teams on each side of a certain connection have to agree on the transport and data formats by which they communicate. Once the interface is set, each side can develop their functionality independently and test it using unit tests at the interface level. I did emphasize the importance of agreeing on interfaces and the importance of good interface design. Despite this, the pretty much all groups reported some case of mismatched interfaces being discovered when doing integration. Which is excellent – it is much better that the students make these mistakes in the safe environment of a university course rather than out in the real world.

Testing

Different groups took different approaches to testing. Everyone did manual testing. Automated testing was employed by some teams in some groups (which is understandable since there was not much time and setting up good automated testing is time-consuming).

Since I love testing I talked a bit about it (including the slide shown above). Some groups did take the idea of testing to heart to an extent that almost made me wonder if they thought I had made unit testing a requirement for passing the course. While others just did a little here and a little there.

Everyone did end-to-end testing of the complete application once all the pieces were in place and talking to each other. However, it took until the latter half of the project work before all parts started to talk to each other. In the meantime, each team found some way to run their code without having to interface with other teams. Just like they are supposed to, but typically without actually creating stubs or mocks for the other parts. Rather just injecting data in some ad-hoc way.

Overall, I have sense that interfaces between components and how to apply testing to a multiple-component system were the most novel parts of the class for the students. Obviously, some students had experience in this including from having worked in industry, but for most it seemed new.

Fun!

In general, it was a great experience to teach and run a class like this. Students today have grown up in a very different digital world from my generation. Interacting with students does give you new perspectives, it is not just something people say… There is a real freshness of thought and lack of cynicism that is refreshing.

The students were impressively fearless. When doing the final presentation and demos of their projects, a couple of teams that had implemented an interactive quiz application actually dared to run it live for the class. It worked for one group and the other was close. The second group had tested the application right before the class, but it still broke down. Another pedagogical win, meeting the dread Murphy or demo devil live, but of course I wish it would have worked for them too.

Kids these Days

Looking at what the students managed to build in a few weeks’ time drives home just how far we have some come in frameworks and making it easy to write software since I started as a CS undergrad 30 years ago. Back then, the only way to implement the applications for this course would likely been using C or maybe C++ along with raw TCP/IP sockets talking to hard-coded IP addresses or maybe computer names. Accessing it from outside the university network would have been impossible.

Today, the high-level frameworks and sheer volume of example code and templates available thanks to the Internet makes it possible to throw together a system with multiple graphical user interfaces talking to a server in just a few weeks of part-time work. Amazing. On the other hand, they are far more removed from how things actually work.

Of course, real programmers should use no fancy things like frameworks. See XKCD 378. And XCKD 1755.

On the other hand, the fundamental questions are still there. How do you structure the program? What is the data to process? It is easier to write code to do things, and the net results is much nicer looking on the user end. But at core, it is still programming. Solving problems and encoding the solutions for computers to execute.

Collaboration tools were second nature. They had to use GitHub and pull-request-type flows for their source code, but also deployed a range of other applications. Some had Discord channels for team communication, many used Figma for sketching their designs, Trello boards served as planning tools, and Google docs allowed collective editing of lists of use cases. We had nothing like that in 1992.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.