Michigan Tech



In early 2020 I and a few other students worked on a website that allowed you to easily see courses that are pre-approved for transfer to Michigan Tech since it's a real pain to find them manually. We originally planned to add support for showing Tech-offered courses to the same tool, but not everyone was available.

I ended up building it as a separate project over the next few months. I planned to release it in two parts: first a MVP and then a more feature-rich application.

I launched the initial version in March of 2021. Even though it was fairly basic, the tool still received a very positive reception.

I launched the feature-rich v2 seven months later, again to a very positive reception.

This is my biggest open-source project to date with well over 13k lines of code. I really enjoyed watching it slowly grow to match my original vision and I'm super happy with how it turned out.


Inspired by tools like Spotlight, Alfred, Raycast, and even GitHub Issues, the primary interface to finding courses is a free-form search field. You can enter keywords, and then narrow your search by using filters of the form token:value. For example, intro subject:cs might return Intro to Programming.

The app's UI is primarily designed around reducing the number of clicks required for any particular action. Just compare how long it takes to view a course description on my app vs. Banweb (Tech's course system):

Since this is a mostly STEM school, a not-insignificant portion of the student body uses ultrawide monitors. Owning one myself—and wanting to improve the overall workflow if extra screen space was available—I added a 2-column layout that's activated when the browser window is wide enough:

This works far better than having to hide parts of the interface behind a modal or drawer, as is sadly the case with smaller screens. Because ultrawide users often keep their browser window to half the width of their screen or less in day-to-day use, I also added a tip instructing users to resize their browser that appears if this 2-column layout is supported.


The main goal of this app was to provide both a smoother experience and additional features as compared to Banweb. For example, integrated statistics on pass, fail, drop, and class size data are shown for each course—something that Michigan Tech doesn't expose anywhere (information was retrieved through a FOIA request). Instructor ratings are also synced from Rate My Professors, so students can easily see if a course they're looking at has a particularly good or bad professor.

Of course, the biggest additional value that my app provides are what I call "baskets."

Baskets allow you to save any number of courses to a table for reference. A few features include:

  • Exporting the basket as an image or .csv file
  • Generating an importable calendar
  • Showing a realtime-preview of your schedule with monthly and weekly views
  • Filtering by sections schedule-compatible with your basket with the is:compatible search filter
  • Correctly handling edge cases, like warning you if a section was deleted from Banweb

Problems Encountered

I spent a few days looking at moving much of the core logic to Web Workers to keep the main UI thread responsive, but ultimately the complexity trade-off didn't seem worth it. After some experimentation, I was able to greatly reduce loading time and increase general responsiveness by moving expensive tasks into several requestIdleCallback() calls, which allows for better utilization of the main single thread.

As another example of an optimization necessary for this specific application, I moved from a more elegant comparison of schedules to more of a static analysis approach that makes a few assumptions, shaving several seconds off filtering sections by those schedule-compatible with the current basket.

Besides performance issues, I opened a PR and a few issues with some of the open-source libraries I was using.

I also managed to accidentally DDoS the school's course system during development of the scraper:


Almost 2k unique people have visited the app as of October 2021. Users have caught one or two bugs that slipped through testing, all of which were promptly fixed.

I learned a ton during the development process. In particular, I ended up extensively using MobX and Kubernetes, two major technologies that I had previously never touched. MobX handles all state management in the app, from loading data to handling basket states. And the backend (along with a few supporting services) is deployed automatically upon every push to main using GitHub Actions + Kubernetes.

return to home