3 minute read

πŸ“š 1. Introduction

There are approximately 6,800 courses at the University of Auckland. These courses are organized into around 250 studies, which are further grouped into 9 faculties (including General Education).

πŸ› οΈ 2. Database Design Choices

When designing the database, I considered a few options. One was to create three separate tables β€” Faculty, Study, and Course β€” and perform joins when querying, for example, the list of studies under a specific faculty. The other option was to consolidate all information into a single table with 6,800 rows.

I chose to create a single, denormalized table for the following reasons:

  1. Courses rarely change, and the system would experience very few write or delete operations. In other words, the table can be treated as a static dataset with primarily read operations, making a single table sufficient.
  2. 6,800 rows is relatively small and does not warrant normalization purely for size reasons. Querying such a table typically takes around 150ms, which is fast enough that it would not negatively impact user experience (UX).

Therefore, considering both the low update frequency and the acceptable query performance, I determined that a simple, denormalized design would be the most efficient and practical choice for this case.

Engineering Faculty Page β€” Listing Studies

Screenshot 2025-04-26 at 9.32.52β€―PM

Accounting Study Page (Business Faculty) β€” Listing Courses

Screenshot 2025-04-26 at 9.35.05β€―PM

🎯 3. UX Challenges and Improvements

Initially, I designed three separate pages: a Faculty page, a Study page, and a Course page. However, navigating to course reviews required too many steps: Faculty page β†’ click β†’ Study page β†’ click β†’ Course page β†’ click β†’ finally see the reviews.

To improve the user experience (UX), I replaced the Faculty page with a faculty navigation bar that allowed users to jump directly to their desired faculty. This reduced user’s click and made navigation much more intuitive.

🐒 4. Performance Bottleneck: Initial Observations

However, I noticed another issue: loading studies and courses felt slow. It wasn’t that it took longer than a second to load, but it still wasn’t as smooth and immediate as I wanted.

Upon reviewing my code, I initially suspected that alphabetical sorting might be a bottleneck. But after analyzing the complexity, I realized that sorting a maximum of 80 courses would only involve approximately O(n log n) = 504 comparisons β€” a trivial amount of work for a modern CPU, likely completing within just a few milliseconds.

After further research, I discovered Redis.

πŸš€ 5. Implementing Redis for Caching

Redis is an in-memory, NoSQL key-value store, which was exactly what I needed.

Being ` NoSQL-based means Redis stores data in flexible key-value structures, making it **highly accessible** and **intuitive** for my use case. Furthermore, its schema-less` nature perfectly matches the structure of courses and studies, which do not require rigid relational models.

From a performance perspective, Redis is optimized for speed: all data is kept directly in RAM rather than on disk. This allows data retrieval times to skyrocket β€” accessing RAM is thousands of times faster than disk I/O. Redis can easily handle hundreds of thousands of requests per second, making it an ideal solution for reducing latency and delivering a much smoother user experience.

πŸŽ‰ 6. Conclusion

I implemented caching for studies and courses using Redis, which significantly improved data retrieval speed compared to direct database queries. As a result, users experienced minimal loading times when navigating the frontend, and overall, the application’s responsiveness and user experience were greatly enhanced. Although there is still a slight delay, it has been reduced considerably. Beyond the performance improvements, I am also glad that I discovered Redis and its many powerful features through this process.

Leave a comment