Skip to content

A web application developed for the Check24 GenDev Scholarship Program that helps users find the optimal combination of streaming providers to watch their favorite football teams.

Notifications You must be signed in to change notification settings

luffdavid/best-combination-web-app

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

86 Commits
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Best Combination Challenge

👋 Herzlich Willkommen zu meiner Check24-GenDev Best Combination Lösung!


📋 Inhaltsverzeichnis

  1. Demo / Deployment / Run Locally
  2. Systemarchitektur
  3. Funktionalitäten
  4. Greedy Algorithmus
  5. Codequalität & Performance
  6. Mögliche Verbesserungen
  7. Dankeschön

🎬Demo / Deployment / Run Locally

📌 Deployment Frontend: https://best-combination-pwa.web.app/ (the initial loading time can take some seconds as backend is deployed on "free instance"

📌 Lokal starten: Backend:

npm run start:backend

und dann Frontend:

npm run start:frontend
  • Installiert alle Dependencies
  • Startet Backend und Frontend (BE: localhost:8080 , FE: localhost:3009)

🏛️Systemarchitektur

image

Backend

Technologieüberblick:

Kategorie Technologie
Programmiersprache TypeScript
Laufzeitumgebung Node.js
Framework Express.js
Datenbank Google Firebase Firestore
Caching node-cache
Deployment Google Cloud Platform

Funktionsweise:

Das Backend bietet eine RESTful API und wurde mit Node.js und Express umgesetzt. Durch TypeScript wird Typensicherheit und bessere Wartbarkeit erreicht. Folgende Endpunkte sind verfügbar:

  • /api/games GET: Gibt die Games zurück
  • /api/streamingoffer GET: Gibt die Streamingangebote zurück
  • /api/streamingpackage GET: Gibt die Providerinformationen zurück

Datenhaltung:

  • NoSQL-Datenbank: Google Firebase Firestore
  • Import: Daten wurden von csv nach json konvertiert und in Collections abgelegt.
  • Vorteile: Flexible Datenspeicherung und keine JOIN-Operationen.
  • Nachteile: Joins müssen dann im Frontend durch Typescript gemacht werden.

Datenabfrage:

  • Datenabfrage durch das Backend erfolgt jeweils im backend/services Ordner
  • Es wurde ein Caching-Mechanismus eingeführt, der zum einen die Leseoperationen an die Datenbank deutlich minimiert, zum anderen aber auch die Performance im Frontend erhöht
  • Implementiert mit node-cache, welche die Daten im RAM des Servers speichert, solange der Prozess der spezifischen Serverinstanz aktiv ist (!!!lokal funktioniert es, das deployte Backend nur teilweise, wenn die Serverinstanz aktiv ist!!!)
  • Für jede Abfrage (games, streamingoffer, streamingpackage) existiert ein "eigener" Nodecache, auf den durch ein unique Schlüssel zugegriffen wird
  • Bei der Datenabfrage wird also zunächst der Cache abgefragt, bei Cache-Hit werden die Daten aus dem Cache zurückgegeben, bei Cache-Miss werden die Daten von der DB abgefragt und für nächste Anfragen dann gecached

Frontend

Technologieüberblick:

Kategorie Technologie
Programmiersprache TypeScript
Framework React
Styling Material-UI, Styled-components
Datenverwaltung TanStack Query, zustand
Hilfsbibliotheken Day.js, React Window
Deployment Google Firebase
Näheres zur "Datenverwaltung":
  • TanStack Query / React Query:
    • Zur Vereinfachung des Datenmanagements und der Kommunikation mit dem Server, zum Prefetchen der Daten und zum clientseitigen Halten der Daten, die vom Server zurückgegeben werden.
  • zustand:
    • zum Verwalten des clientseitigen Zustands (wie z.B. selektierte Teams, ausgewählte Filter, usw.), wodurch auch bei reload und bei nächsten Besuchen der Zustand erhalten bleibt.

💡Funktionalitäten

Seiten Pfad
Home /
Suche + Favoritenauswahl /favouriteselection
Überblick + Filter /overviewfilter
Ergebnis / Best Combination /bestcombination
Provider-Preis Überblick /providerprices
spez. Spiele finden /gamefinder

Alles, was mit 🌟 versehenen ist, stellt ein zusätzliches Feature dar, welches nicht explizit in der Challenge gefordert wurde.

Home - Funktionalitäten

Anzeigen
  • Startpunkt der Anwendung
  • Attraction Section: Button, um neuen Vergleich zu starten
  • 🌟Überblick der Favoriten und der letzten Best Combination wenn vorhanden
  • Links zu den Seiten: GameFinder, Provider Prices, Best Combination

Favoriteselection - Funktionalitäten

Anzeigen
  • Suche nach Teams und 🌟Wettbewerben
  • 🌟Empfehlungen basierend auf letzten ausgewählten Favoriten + bekannte / beliebte Wettbewerbe (einfach anpassbar :)
  • Mit Klick auf die Chips sind die Teams selektiert
  • Möglichkeit alle Teams auszuwählen (ihr wollt es ja testen :)) und 🌟alle Favoriten zurückzusetzten
  • Sobald Teams/Wettbewerbe ausgewählt sind, können diese auch wieder in der unteren Section entfernt werden.
  • 🌟Favoriten bleiben bei Reload erhalten (implementiert mit zustand)

Überblick und Filter - Funktionalitäten

Anzeigen
  • Übersicht aller selektierten Favoriten
  • 🌟Möglichkeit, Filter zu setzen (nur zukünftige Spiele berücksichtigen und nur monatl. kündbare Verträge vorschlagen wenn möglich)
  • 🌟Filter bleiben bei Reload erhalten durch zustand
  • Button „Show Result“ leitet zur Best Combination

Best Combination - Funktionalitäten

Anzeigen
  • 5 Hauptteile:
    1. 🌟Filter: Auswahl Live/Highlight/Default
    2. Best Providers: Berechnung durch Greedy Algorithmus, Anzeige der für die Selektion beste Provider
    3. Provider Tabelle: Lazy Loaded, mit Pagination, tabellarischer Überblick welcher Provider welchen Wettbewerb zeigt, sortiert nach Abdeckung, Möglichkeit nur die besten Provider oder alle anderen anzuzeigen
    4. Wettbewerbe: Abdeckung der ausgewählten Wettbewerbe (Live und highlight), auch hier mit Pagination zur Reduktion der Ladezeit
    5. 🌟Covered/Uncovered Games: Details zu abgedeckten und nicht abgedeckten Spielen

🌟Game Finder - Funktionalitäten

Anzeigen
  1. Auswahl eines Wettbewerbs
  2. Auswahl von Heim- und Auswärtsteam
  3. Anzeige der Live- und Highlight-Übertragungen

🌟Provider Prices - Funktionalitäten

Anzeigen
  • Überblick über die Preise der Provider

🤖Greedy Algorithmus

Für die Berechnung der besten Kombination von Providern, die zusammen möglichst alle Spiele der selektierten Favoriten abdecken sollten wurde in meinem Code der Greedy Algorithmus angewandt. Code: frontend-web\src\services\util\bc\getBestCombi.ts

Ablauf:

  1. Zuvor: Aufruf der Funktion mit Parametern
    • Spiele der selektierten Teams
    • alle Streamingangebote
    • alle Streamingpackages
    • mode (Live, Hihglight, Default)
  2. Zuvor (2):
    • alle relevanten Spiel-IDs aus der Liste der gefilterten Spielen extrahieren
    • Zuordnung Angebote - Spiele: welche Streamingangebote gibt es zu den jeweiligen Spielen im jeweiligen Mode
    • Zuordnung Angebote - Streamingpackages: Die einzelnen Angebote werden den jeweiligen Streaming-Paketen ihrer Anbieter zugeordnet.
  3. Durchführung des Greedy Algorithmus
  4. Sortieren der Pakete nach Anzahl der von ihnen abgedeckten Spiele in absteigender Reihenfolge, bei gleicher Abdeckung => nach Preis entscheiden
  5. Bestpackage Auswahl: Das Paket, das die meisten aktuell nicht abgedeckten Spiele enthält wird ausgewählt
  6. Abdeckung aktualisieren: Die durch das ausgewählte Paket abgedeckten Spiele werden markiert, sodass sie bei zukünftigen Schritten nicht erneut berücksichtigt werden
  7. Wiederholung, bis entweder alle Spiele abgedeckt sind oder keine weiteren Pakete mehr zur Verfügung stehen
  8. Nach Anwenden des Algorithmus:
  • es wird geprüft, ob es Spiele gibt, die durch kein ausgewähltes Paket abgedeckt werden konnten.
  • Die Anbieter, deren Pakete Teil der finalen Lösung sind, werden ausgewählt und nach ihrer Abdeckungsrate sortiert.

</>Codequalität & 🚀Performance

Codequalität:

Bei dieser Challenge wurde besonders auf die Codequalität geachtet, anders als bei meiner letzten Bewerbung auf das Stipendium.

  • TypeScript statt JavaScript: Typsicherheit und besser wartbarer Code
  • gleicher Aufbau bei React Komponenten: erst typesDefinition für Props, dann React Code
  • ESLint & Prettier: Einhaltung von Code-Standards

Performance:

Eine gute Performance ist durch einige Überlegungen, sowohl client- als auch serverseitig gewährleistet.

  • Backend-Caching: Wie schon im oberen Abschnitt erwähnt, wurde ein Cachingmechanismus angewandt, um zum einen Anfragen an die Datenbank zu minimieren, zum anderen auch die Antwortszeit an den Client zu verbessern

    • Beispiel Erster Request: 872ms image

    • Beispiel Zweiter Request: 8ms image

    • durch den header x-Datasource kann man auch sehen, ob die Daten von der DB oder vom Cache kommt

  • Frontend:

    • React Query: Daten-Caching und Prefetching (Anwendung in der gesamten Applikation Frontend): durch die Nutzung von React Query wird ein gutes Caching und ein gute Kommunikationsverhalten zum Server gewährleistet. Konkret wird in App.tsx alle nötigen Daten prefetched und durch die Einstellungen des QueryClients im Cache abgelegt. Es erfolgen also pro Session genau 3 Request, diese Daten werden für die ganze Session gehalten, genauer gesagt 1 Tag (= staleTime, die Zeit, nachdem Daten als veraltet betrachtet werden).
    • Lazy Loading: Optimierung der Ladezeit (Anwendung: best-combination-fullstack-web-app/frontend-web/src/components/result/bestcombination/providerXcompetitonsXgames/ProviderXcompetitionsXgamesTable.tsx). Es basiert darauf,dass Teile der Anwendung nur bei Bedarf geladen werden. Das reduziert die initiale Ladezeit und verbessert die Performance, bei mir im Projekt wird das angewandt, um die initiale Ladezeit zwischen "Überblick/Filter" und dem Ergebnis zu reduzieren. Auf der Route /bestcombination wird BCProvider als Teil des Ergebnis-Displays genutzt. Die Tabelle (ProviderXCompetitionsXgamesTableLazy) wird jedoch erst geladen, wenn der Benutzer sie explizit durch das Accordion öffnet, die Tabelle erhält durch viele Icons eine erhöhte Renderingzeit.
    • React Window: Virtuelles Scrollen großer Listen (Anwendung: best-combination-fullstack-web-app/frontend-web/src/components/result/bestcombination/coverage/BCCoveredGamesModal.tsx): Durch das Konzept der Virtualisierung werden nur die Spiele, die aktuell im sichtbaren Bereich sind, gerendert. Dadurch werden die Anzahl der DOM-Knoten deutlich verringert.
    • useMemo:

📈Mögliche Verbesserungen

  1. Styling: Einheitliche Nutzung von Material-UI und styled-components würde den Code besser lesbar machen.
  2. Lazy Loading: Das Implementieren von Lazy Loading hat zwar einige Vorteile hinsichtlich der Ladezeit gebracht, aber hat den unschönen Nebeneffekt, dass bei vielen selektieren Favoriten die gesamte /bestcombination Route für kurze Zeit nicht bedienbar ist (z.B. kein Klick auf Show Details bei den Covered Games möglich).
  3. Caching im Backend: Der Einsatz einer Lösung wie Redis, die einen zentralen Cache bietet, hat gegenüber einem "lokalem" Caching mit Node-Cache erhebliche Vorteile in Bezug auf Effizienz.“
  4. Performance hinsichtlich des Renderings: Aufwendige Styles unnötige geschachtelte HTML-Elemente könnten entfernt werden, um für ein noch schnelleres Ergebnis insbesondere der Tabelle der Bestcombination zu sorgen

🙌Danke

Zuletzt möchte ich mich noch bedanken, mir und anderen Studenten die Möglichkeit geben, mit solch großen Datensatzen und "real-world" Applikationen an eigenen Projekten zu arbeiten. Es hat mir sehr viel Spaß gemacht, die Herausforderung anzunehmen. Ich bin selbst Fußballfan und habe Woche für Woche das Problem, den Provider zu finden der das Spiel zeigt, deshalb war es etwas besonderes für mich so etwas selbst zu programmieren. Ich freue mich von Ihnen bald zu hören :)
Bei Fragen, bitte an david.luff03@gmail.com :)
Viele Grüße,
David

About

A web application developed for the Check24 GenDev Scholarship Program that helps users find the optimal combination of streaming providers to watch their favorite football teams.

Topics

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published