Procés de desenvolupament de myLeague
Introducció
- Què és “myLeague”?
My-league és una plataforma que permet la creació administració de lligues de futbol així com la visualització i seguiment dels resultats i estadístiques. - Objectiu principal
L’objectiu principal d’aquest projecte ha sigut l’aprenentatge. Vaig començar-lo l’octubre del 2022 i l’he anat fent en el temps lliure, de fet encara continuo desenvolupant-lo. - Valoració
Estic molt content de la constància que he tingut per ser quelcom que he fet en el temps lliure, i orgullós del resultat obtingut fins ara. No el considero un projecte acabat, sé que hi ha moltes coses que es poden millorar.
Taula de continguts
Disseny i desenvolupament de la base de dades
Desenvolupament del front-end
Disseny i desenvolupament de la base de dades
Primeres taules de la base de dades
Vaig triar supabase perquè facilita molt el disseny i creació d’una base de dades. És un servei que té una capa gratuïta i que ofereix una interfície per crear i administrar una base de dades postgreSQL allotjada en un servidor, i una api REST preparada. També ofereix un plugin per consumir la API des de javascript.
Vaig començar doncs amb la creació de les primeres taules “teams” i “matches”, la mínima expressió del projecte:
- teams: id, nom, points
- matches: id, date, local_team, visitor_team, result
Després vaig adonar-me que havia de definir una lògica que s’encarregués d’actualitzar la informació: quan s’actualitza un partit, s’ha d’actualitzar la informació dels equips que hi han participat. Vaig optar per tenir aquesta lògica directament en la base de dades perquè vaig considerar que era més fàcil evitar errors de sincronització. Tinc clar que si una cosa bona té SQL és la coherència de dades. En realitat son 4 les característiques “ACID”: atomicitat, coherència, aïllament i durabilitat.
Lògica d’actualització de les dades
Vaig començar a desenvolupar la lògica que s’encarregaria d’actualizar la informació cada cop que s’actualitzava un partit. A mesura que feia la lògica d’actualització de les dades vaig anar afegint més informació que trobava que era important:
- A “matches” hi vaig afegir local_goals, visitor_goals, match_day.
- A “teams” hi vaig afegir urlname, goals_scored, goals_conceded, goals_scored_home, goals_scored
Aquí tens la funció update_teams_row com a exemple. Aquesta funció permet assegurar que les estadístiques dels equips es mantinguin correctament actualitzades després de cada partit.
DECLARE
match_row record;
team record;
index int:=1;
BEGIN
UPDATE teams SET
goals_scored \= 0,
goals_scored_away \= 0,
goals_scored_home \= 0,
goals_conceded \= 0,
goals_conceded_away \= 0,
goals_conceded_home \= 0,
points \= 0,
wins \= 0,
defeats \= 0,
draws \= 0,
played_matches \= 0
WHERE teams.id=teams.id;
FOR match_row in SELECT \* FROM matches where played \= true LOOP
CALL update_teams_row(match_row);
END LOOP;
FOR team in SELECT \* FROM teams LOOP
UPDATE teams SET
goals_conceded \= team.goals_conceded_home \+ team.goals_conceded_away,
goals_scored \= team.goals_scored_home \+ team.goals_scored_away
where id \= team.id;
END LOOP;
return NEW;
END;
Explicació de la lògica:
- Primer establim totes les columnes de tots els equips a zero.
- Després recorrem tots els partits que s’han jugat (on played = true) i cridem la funció update_teams_row(match_row) que s’encarregarà d’actualitzar les estadístiques dels equips que van participar en cadascun d’aquests partits.
- Finalment, recorrem tots els equips per sumar els gols a favor i en contra, a casa i a fora, i actualitzem aquestes dades.
Afegir les taules “players i “leagues”
Després vaig afegir la taula “players”, per afegir les dades dels jugadors dels equips i així poder oferir estadístiques.
Posteriorment vaig crear la taula “leagues”, que va permetre escalar i poder guardar més d’una lliga. Finalment han sigut 4 taules:
- leagues
- matches
- players
- team
Poc a poc vaig anar afegir més dades i més complexitat en les taules i les funcions per a mantenir la coherència de les dades.
En total vaig escriure 10 funcions i 6 triggers.
Si t’interessa, pots consultar la base de dades completa en aquest [enllaç](https://github.com/eloicasamayor/my-league).
Reptes i possibles millores futures
-
Poder tenir un equip en diferents lligues En la taula de teams hi guardo els gols a favor i en contra acumulats, i també desglossats amb “a casa” i “a fora”, també les victòries, derrotes i empats, el total de partits jugats i els punts acumulats (comptant 3 per victòria i 1 per empat).
Això em va facilitar la feina a l’hora d’anar fent la lògica, però va arribar un punt en que em vaig adonar que guardar així la informació implica que no puc guardar la informació en curs d’un equip per a diferents lligues. Però bé, de moment no he afrontat aquest inconvenient. -
Tornejos amb eliminatòries Tal com he enfocat el disseny de les taules, ara mateix no és possible contemplar diferents tipus de tornejos. M’agradaria en un futur poder afegir la possibilitat de crear tornejos d’eliminatòries, o encara millor, de tornejos mixtos: amb fases de lligueta i eliminatòries.Ho vaig començar a probar creant una taula anomenada “phases”, però ho vaig deixar estar perquè no ho veia clar i implicava molts canvis.
-
Lligues sense gestió de jugadors Una altra cosa que m’agradaria implementar és la possibilitat de crear lligues sense gestionar jugadors. Ara mateix no és possible, perquè obligatòriament necessito que cada gol estigui associat a un jugador. Podria fer alguna solució des del front-end, però m’agradaria fer-ho possible a nivell de base de dades.
-
Lligues privades Una altra cosa que he pensat que podria afegir és la possibilitat de crear lligues privades. Això seria molt fàcil: simplement afegir una columna boleana, per exemple isPublic.
-
Estadístiques sobre gols encaixats i minuts jugats I encara una possible millora és poder guardar i generar estadístiques sobre els gols encaixats als porters. Això podria implicar afegir la dada de quina posició ocupa cada jugador i potser també dels minuts jugats.
Desenvolupament del front-end
Objectius
- Interactivitat i usabilitat Vull crear una aplicació molt interactiva i fàcil d’usar, amb una navegació senzilla entre les pàgines i apartats. La introducció de dades serà directa, evitant informació innecessària per assegurar una experiència intuitiva.
- Aplicació adaptativa L’objectiu és desenvolupar una aplicació que s’adapti perfectament a qualsevol pantalla. L’elecció de Tailwind CSS serà clau per aconseguir-ho, permetent una disseny responsiu i flexible.
- Rapidesa L’aplicació ha de ser ràpida tant en l’obtenció com en l’emmagatzematge de dades, garantint una experiència fluida. També, vull informar l’usuari durant els processos de càrrega o enviament d’informació.
- Accessibilitat L’aplicació serà dissenyada per ser accessible, permetent el seu ús amb el teclat, amb el mínim suport del ratolí. Inclourà opcions de canviar entre mode clar i fosc.
- Estètica moderna i disseny coherent La interfície visual serà atractiva i coherent, amb un disseny adaptat al públic objectiu, que consisteix principalment en homes joves.
- Escalabilitat Desenvoluparé una arquitectura que permeti l’addició de noves funcionalitats de manera senzilla a mesura que el projecte creixi, assegurant així la seva sostenibilitat i adaptabilitat a futurs requisits.
Elecció de framework i llibreries
- React era la única peça que tenia 100% clar que faria servir. Més que res perquè és el framework de javascript que més he utilitzat i amb el que em sento còmode.
- Vite: el vaig triar perquè ja hi he treballat i m’agrada per la seva simplicitat. No aporta tantes coses com Nextjs, però és ràpid i et permet començar un projecte de react sense pensar gaire.
- Redux.Per a la gestió de l’estat, ja coneixia redux i tenia ganes d’aprendre a usar Redux Toolkit, doncs em vaig decidir a usar-lo.
- Supabse.js Per a les crides a la api vaig fer servir el plugin de javascript oficial que proveeix supabase. Integrar redux toolkit amb el plugin de supabase em va donar bastants maldecaps… però finalment ho vaig aconseguir.
- Tailwind CSS En quant als estils, he fet servir Tailwind perquè també em permet anar ràpid i mantenir fàcilment la coherència entre components.
- Flowbite També he fet servir força components predissenyats de Flowbite, una llibreria de components que usa Tailwind.
Estructura del projecte
./components:
Alert.jsx Footer.jsx icons/ LeagueDayMatchings.jsx MatchesList.jsx PageLayout.jsx StepsNavigation.jsx
Classification.jsx forms/ index.jsx LeaguesList.jsx Modal.jsx PlayersList.jsx TeamsList.jsx
Header.jsx LeagueDayDate.jsx MatchesCalendar.jsx NewLeagueInfo.jsx SortableHeadCell.jsx WeekDaySelect.jsx
./components/forms:
EditLeagueForm.jsx EditPhotoForm.jsx EditTeamForm.jsx NewMatchForm.jsx NewTeamForm.jsx
EditMatchForm.jsx EditPlayerForm.jsx index.jsx NewPlayerForm.jsx
./components/icons:
ArrowBackIcon.jsx ArrowUpDown.jsx ExclamationCircleIcon.jsx Logo.jsx PlusIcon.jsx UpdateIcon.jsx
ArrowDownDoble.jsx CircleCheckIcon.jsx GithubIcon.jsx MoreIcon.jsx SettingsIcon.jsx UploadIcon.jsx
ArrowLeft.jsx DragDropIcon.jsx HomeIcon.jsx PencilIcon.jsx TeamIcon.jsx UserIcon.jsx
ArrowRight.jsx EmailIcon.jsx index.jsx PhotoIcon.jsx TrashIcon.jsx
./helpers:
addDatesToMatchings.js getMatchings.js nameToUrlName.js setMessage.jsx truncateString.js validateNewLeague.js
getFirstMatchDay.js index.js saveNewLeague.js shuffle.js useWindowDimensions.js
./pages:
index.js LeaguePage.jsx LeaguesPage.jsx LoginPage.jsx NewLeaguePage.jsx TeamPage.jsx UpdatePassword.jsx
./redux:
api/ auth/ constants.js index.js store.js
./redux/api:
apiSlice.js index.js leagues.js matches.js players.js teams.js
./redux/auth:
slice.js