Course Planning
2023–24 Yearlong Spark Project
Introduction
Currently, UC Davis offers students many different tools for planning out courses for future years, including OASIS, Schedule Builder, MyDegree, and General Catalog. It is a complicated and tedious process to research into courses to plan out schedules and future quarters.
Some student pains include:
- Not knowing what courses to take
- Certain tools provide incomplete information (e.g. not displaying correct degree progress)
- No easy way to understand prerequisites / quarter offerings for courses
Proposed Solution
CodeLab has partnered with a UC Davis SWE, Matt Steinwachs, to work on a new Course Tool system that would improve the student and administrative experience of degree progress and planning out courses for future quarters.
The Course Planning Team is developing a new, intuitive UI for managing courses and academic plans for future quarters, including a new algorithm that recommends the student a set of courses to take that meets requirements based on their major and specifications.
The Team
Leads
Jacob Marinas — Project Manager
Thea Mccallie — Project Mentor
Designers
Caitlyn Wong
Developers
Taha Abdullah
Eric Wang
Sauvikesh Lal
Akash Seelam
Reeti Bandyopadhyay
Tools
- Project Planning / Communication: Notion, Jira, Slack, Google Meet, Calendly
- Design: Figma, draw.io
- Software: VSCode, Repl.it, Git / GitHub, MongoDB, Insomnia
Timeframe
Fall Session: October 2023 to December 2023–6 weeks
Winter / Spring Session: January 2024 to May 2024–16 weeks
Design
Fall Recap
Back in Fall Quarter, we initially worked on the first few steps of the design process: UX Research / Competitive Research, User Stories, and creating the Lo-Fis / Mid-Fis.
Research: For Course Tool, we wanted to better understand the current tools used to plan our degrees and schedules, so our designer surveyed UC Davis students — through clubs, professors, and faculty — to get their experiences with the course planning process. Our findings were:
Students have trouble:
- Knowing what courses to prioritize taking over others — placing them on which quarters
- Knowing what quarters courses are offered (and visually understanding this in the academic plan)
- Understanding degree progress (inaccurate, especially for transfer students)
Students want:
- Ability to drag and drop courses into the academic plan
- Course recommendations for the academic plan — courses that satisfy the most requirements, what order to take courses
- Better ways of visualizing the academic plan — prerequisites, class times, different course options
User Stories: From the findings in research, it began to shape a model for how students would interact with an ideal Course Tool in the form of User Stories and what our pages should look like.
Lo-Fis / Mid-Fis: The designs from the sketches were then explored further in Figma. Different pages were designed to build and manage academic plan sheets.
What’s New: Design System
To clarify, we are the Course Planning Team for the Course Tool project — we have this distinction as we have a sister team, Course Visualization, that we work alongside with. In spite of us both working under Course Tool, the designs for Fall Quarter between Course Planning and Course Visualization were separate and inconsistent. Moving forward to 2024, we wanted to unify the designs. And, this is a tool for UC Davis students after all — it should feel like a UC Davis website as well.
Hi-Fis
Many of the pages previously designed in Figma were revamped with the new design system, which leads us to our Hi-Fis — the final designs that best suited a student’s needs for Course Tool. The developers also worked with the designer to ensure that these designs were technically feasible once imported into frontend and backend specs.
Our designer was able to turn these designs into prototypes in Figma, a feature that allows us to sample the functionality of some elements such as page navigation and course selection, without actual code. Very cool!
Software
In Fall Quarter, we spent a lot of time handling the major and course data given to us by the client, and building the foundation of our algorithm. Going into 2024, as designs were reaching into hi-fis, developers went straight to work into building the backend, algorithm, and frontend.
Architecture: MongoDB, NextJS, Express
Database
Back in Fall, our client gave us a lot of data to work with from UC Davis — about majors and courses — in the form of .csv
and .json
files. Analyzing these further, we found:
- A
.csv
containing all the GE courses, where each course includes a quarter offered, subject its under, and the GE requirements they meet - A list of
.jsons
, each representing a major. In a major.json
, it contains a list of condition objects, which each outline a set of courses and some criteria to meet - either taking a number of courses, or taking a minimum number of units.
In Winter, we parsed through this data through Python scripts to better format the data for us to use in our algorithm and in our frontend. For example, we were able to turn the .csv
GE course file into a cleaner .json
file, removing duplicate courses which had the same course code but different quarter offerings.
Then in Spring, we were able to populate our course and major database MongoDB with clean data, including everything we need to know about a course, including quarter offerings and GE reqs fulfilled, in new schemas outlined below.
Creating these collections in MongoDB allowed us to easily provide input to our algorithm. Once a user selects a major, we retrieve the courses required for that major from MongoDB using allMajors. Then, we topologically sort the courses based on the prerequisites provided for each course and check which general education requirements are met, using the data in newMasterCourses.
Backend
In Winter, we created routes to get needed major / courses data from the MongoDB database. A MongoDB function that was particularly useful was findOne()
, which allowed us to search the database by an attribute of an object.
The utils/
directory contains many useful functions that help with checking requirements, ordering courses, and placing courses in a worksheet.
algo.ts
is a special endpoint that starts the course recommendation algorithm process. It strings together a lot of the functions in the utils/
directory, to process the user’s input of major and courses taken, into a populated worksheet of recommended classes to take.
Algorithm
After months of hard work, here is what our algorithm looks like:
It’s quite big, isn’t it? In short, the course recommendation algorithm for Course Planning was a very complicated, yet interesting problem we were trying to solve. Our goals for the algorithm were that it would give students a valid and optimal course schedule that fulfills all their major and GE requirements.
- Valid: Every course recommended is offered in the quarter that it is placed in, and all courses taken + recommended will fulfill all major and GE requirements for that student. More quantitative and objective aspects.
- Optimal: Is this a schedule that makes sense for a student to take? Does it balance major classes versus GE classes for each quarter? Is the workload manageable? More qualitative aspects.
There are four main pieces of the puzzle here: the Input layer, Requirements layer, Algorithm layer, and Frontend layer. We’ll go through the algorithm diagram one by one.
Input: This handles all input related to worksheets and the course recommendation algorithm. This involves managing worksheets, inputting courses, and setting a student’s major info.
Requirements: This layer does a lot of work with obtaining major and course info — you can think of the input layer as the order for an item on the menu in a restaurant, and the requirements layer gets all the ingredients needed to make that item.
- Get course reqs for major: Given some major, we talk to the allMajors collection to get the list of required courses. This isn’t as easy as just getting a list — we have to filter each condition object contained in that major
.json
, where we either select a number of courses, or select courses until we hit a unit minimum requirement. - Fulfill Major / GE Reqs: After getting the list of required courses for a major, they are then mapped to major requirements and GE requirements. This requires some dynamic programming skills to algorithmically figure out the best possible mapping arrangement from course to requirement, so students don’t need to take more courses than they need to.
- Get course reqs for GE: After seeing what GE requirements we already fulfilled through the required major courses, we add any remaining GEs that the student needs to take.
- Get course objects / prereqs: By this step, we have a list of courses to take, but only by their course codes. The algorithm layer requires us to feed it a list containing courses and their prereqs — a list with dependencies. So we do a bit of conversion.
Algorithm: This layer will find a valid and optimal way to arrange the courses in each of the quarters — it’s taking the list of ingredients and cooking up the entree the end user will enjoy. There are two main things the algorithm layer handles: course order and placement.
- Course Order: Given a list of unordered courses and their prerequisites — a list with dependencies — we use a topological sort to output an ordered list of courses, such that any proceeding course can be taken, fulfilled by preceeding courses.
- Course Placement: Given a list of ordered courses, we need to figure out how to place them in the schedule. There are multiple factors here:
- Quarters offered: We want to make sure to give a student a correct schedule, where the quarter the class is placed in, is actually offered that quarter. For any placement of a course in a quarter, we have a function that checks if a course is offered that quarter. If not, we iteratively rearrange the course placement until there is a valid offering.
- Units: To properly balance the schedule, the student can set the max number of units they would like to take per quarter. A function distributes the list of ordered courses accordingly across the many quarters.
By the end of the Algorithm layer, we end up with a list of quarters, with each quarter containing a list of courses. And from the Requirements layer, we have a list of courses, with each course containing flags for what major and GE requirements they meet. And finally, we have the Frontend, which we will cover in the next section.
There were many hours and brainstorm whiteboarding sessions dedicated to the course recommendation algorithm — this is a high-level overview. But we’ve created an intelligent system that can recommend courses for students and vet what requirements they meet!
Frontend
For our frontend, we took an iterative approach similar to the design process, where we start with the core functionality of how our page worked (content), and then worked on how that content should be displayed (design). NextJS was used for our frontend, while Tailwind was used to style the website.
We first started with some wireframes in a lo-fi setting, to set the groundwork for what components we would use along with the layout of our worksheet page.
Our key components are the YearBox, InputCard, and ReqCard.
- YearBox: A flex box that includes a list of quarters, where each quarter has a list of courses — either taken or suggested. You can enter a course by searching its course code in a course cell i.e. ECS020.
- InputCard: A flex box that includes the key info for a student: starting quarter and their major. For the course recommendation algorithm, this info is used to properly place courses and determine the current quarter offerings available for a course.
- ReqCard: A flex box that displays all and each individual requirement met by the generated schedule. Behind the scenes, the
util/
functions in the backend will map all courses, taken or suggested, to requirements.
Alongside these components, a ‘Generate!’ button hits the algo.ts
endpoint and does all its magic to recommend courses and generate a new worksheet, populated with taken courses and courses suggested.
By our mid-fi frontend, our developers started playing around with the CSS, particularly using Tailwind, to start achieving the intended look of the website, such as color scheme and flex box properties.
The frontend became more polished as the hi-fi designs were finalized and the developer similarly polished the mid-fi frontend. Many areas of the frontend were redone and polished in the worksheet page, to then include the input card and the university requirements.
Finally, when students are done editing their worksheets, they can hit the export icon on the top right section of the worksheet to export their schedule as a .json
, so they can save it for their own use or import it into our tool later on.
All of the features we have just mentioned can be found in our demo video below:
To-Do
While there is many things we have accomplished, we had to descope a fair bit. There are a few more features that would be great to work on in the future:
algo.ts
: Endpoint needs to be updated to call more of theutil/
functions (there are a few placeholders)- Input layer: Drag and drop for courses, max courses input per quarter
- Requirements layer:
- Get course reqs for major: Condition logic (it took us a while to figure out parsing the major.json
)
- Refactoring to work with course codes instead of MongoDB object_ids
- Algorithm layer: Refactoring the topological sort algorithm to work with course codes like above.
- Frontend layer: ReqCard needs to be updated to also display major requirements from the Requirements layer (there is a placeholder)
- In general, it would be great to explore frontend component libraries to help speed up the development process!
We currently handle only major and GE requirements, but not college requirements — which come with its own set of challenges. The same major can have different requirements depending on the college i.e. the Computer Science major in the College of Letters and Science vs. College of Engineering.
And of course, as we add more of these features, it would be great to get user feedback who can test our website!
Course Visualization
Course Tool was a very huge undertaking, both in complexity and breadth. Throughout this project, we worked alongside a sister team, Course Visualization. In short, Course Planning is an improved Schedule Builder, while Course Visualization is an improved OASIS. Together, our two sides would serve as the main pillars for a functional Course Tool.
Our project was hosted on GitHub, and branches were made for the different features. As they passed test cases and checks, they were then merged with the main branch, seen below.
Our leads, including the PMs and Project Mentors, met with Mr. Steinwachs in weekly standups to discuss on project planning, progress updates, and feedback from the client. It was a pleasure getting to see the project grow over time and see the client’s vision come to life.
Throughout Winter and Spring, cross-team meetings became more common to ensure that design and software in each team agreed with each other and worked towards making a cohesive Course Tool.
Regular meetings with the designers of both teams let to creation of the Course Tool design system as well as shared elements / features, and a new logo to top it off!
Since our two teams largely shared the same data, including major and course information, it was essential to have schemas and routes that both the Course Planning and Course Visualization side could use.
Our last meeting with the client included a demo walkthrough, as well as handoff: our source code, documentation, designs, and other resources to Mr. Steinwachs.
Reflection
Challenges
- Algorithm Scope — By Spring, our MVP also included displaying major and GE requirements — and suddenly the algorithm grew a lot more complex than expected. Not only did we needed to fetch the list of courses for a major and sort them, but we needed to attribute them to requirements they fulfilled, and this isn’t always a 1:1, as any set of courses could be entered by a student.
- In short, as we were working on this feature, there were either more functions that needed to be made or additional edge cases to handle — and it was something that we didn’t foresee at the time.
- Commitments — our team has changed since Fall. Some of our members had other commitments and obligations, and had to find balance in their busy work schedules. We had a new developer join us, which we were really grateful to have on the team and made lots of important contributions. Even so, losing members over time and having to onboard a new member cost engineering time and set back our timelines quite a bit.
Takeaways
- Communication — as we worked on more features for the project, we found ourselves talking with the leads and the sister team more and more about project specs and figuring things out together. There were many technical challenges, but it was super rewarding to learn and build this project with each other — especially in a large-scope setting with multiple teams.
- Anticipate setbacks — we are all human, and no project will go exactly as planned. And that’s okay — if you expect for it in the timeline. This means being more realistic with scope and timelines, finding problems sooner than later, and leaving room in the timeline for squashing bugs and some extra engineering time. Having open and honest communication with your team is a must.
- Enjoy the process — at the end of the day, be proud of what you’ve made! We definitely learned a lot from this cohort and also enjoyed the times we spent together. The skills you gain and the connections you make with others will far outlast any single project.
Closing Thoughts
It’s been a great year working on this project, and we are very grateful to our client, UC Davis SWE Matt Steinwachs, for giving us the opportunity to work on this with him. It has also been a pleasure to work alongside our sister team, Course Visualization, to embark on this journey together. From Course Planning, we thank our developers and designer who have done great work year-round. And finally, we appreciate our leads and mentors who have put in the time and energy into our teams and the project. We look forward to collaborating with Mr. Steinwachs in future CodeLab cohorts.