Skip to content

Projectstructuur

Het is belangrijk om bij het schrijven van code een bepaalde mappenstructuur aan te houden, daarmee dwing je onder andere af dat er op een consistente manier gewerkt wordt.

In dit artikel zal kort worden uitgelegd wat de mappenstructuur van het startproject is, en naar welke mappenstructuur je gaat toewerken.

Mappenstructuur van het startproject

Het startproject bestaat uit de volgende belangrijke mappen en bestanden:

  • package.json beschrijft welke NPM packages er nodig zijn voor alle projecten in de Visual Studio Code omgeving(workspace).
  • apps\web\package.json beschrijft welke NPM packages er nodig zijn voor het Dokkie project.
  • apps\web\src bevat alle Dokkie-specifieke code.
  • apps\web\tests bevat alle Dokkie-specifieke geautomatiseerde tests.
  • apps\web\wwwroot bevat alle HTML-bestanden, CSS-bestanden en afbeeldingen voor Dokkie.
  • docs bevat één of meerdere Markdown-bestanden om een documentatiesite voor te genereren.

De wwwroot-map

De conventies voor de bestanden onder de wwwroot-map is lower-kebab-case, bijvoorbeeld participant-add.html.

De wwwroot-map bevat alle HTML-pagina’s.

Daaronder bevat de assets-map alle CSS en afbeeldingen die door de verschillende HTML-pagina’s gebruikt worden. CSS-bestanden voor een specifieke pagina hebben altijd de naam van de HTML-pagina, bijvoorbeeld participant-add.css.

De public-map is speciaal en bedoeld voor alle bestanden (meestal afbeeldingen) waar de broncode (src-map) direct mee werkt. Dit gaat anders niet goed tijdens de npm build-fase!

De src-map

De conventies voor de bestanden onder de src-map is lower-kebab-case, bijvoorbeeld participant-add.ts.

Daarnaast is in deze map voor elke HTML-pagina een bijbehorend .ts-bestand te vinden.


Uiteindelijke mappenstructuur

In deze paragraaf wordt beschreven hoe de uiteindelijke mappenstructuur eruit komt te zien.

De wwwroot-map

Geen veranderingen ten opzichte van wat hiervoor is beschreven.

De src-map

De conventies voor de bestanden onder de src-map zijn als volgt:

  • Niet-classes (specifiek pages)
    • Naamgeving: lower-kebab-case, bijvoorbeeld participant-add.ts.
  • Niet-classes (overige):
    • Naamgeving: camelCase, bijvoorbeeld hicConfig.ts.
  • Classes
    • Naamgeving: PascalCase, bijvoorbeeld Participant.ts als die de Participant-class bevat.
    • Elk bestand bevat altijd maar één export class, maar kan eventeel wel types bevatten ter ondersteuning.

De src-map is opgedeeld in vier mappen:

  • pages
  • controllers
  • models
  • repositories

Deze mappenstructuur draagt bij aan het benaderen van een Model-View-Controller architectuur (MVC).


Toepassing MVC architectuur

Pages

Voor je met Object Oriented Programming (OOP) aan de gang gaat, zul je je werk vooral in de pages-map doen. Voor elke HTML-pagina is er altijd een bijbehorend TypeScript-bestand in deze map te vinden, zelfs als je alleen met JavaScript werkt, bijvoorbeeld participant-add.ts.

Als je met OOP aan de gang gaat, komen de andere mappen qua structuur om de hoek kijken.

Controllers

Elk cluster van CRUD-pagina’s krijgt één controller class onder de controllers-map, bijvoorbeeld PartipantController.ts. De bestanden onder pages voor die pagina’s doen niks meer dan de controller instantieëren en render-functies aanroepen, vrijwel altijd in DOMContentLoaded.

Dit is de eerste refactor die je zal moeten doorvoeren: het creatief schuiven van hun origineel geschreven code naar een controller-class. Het makkelijkste wat hier gedaan kan worden is het volgende, uitgaande van participant-add.ts en andere CRUD-acties als voorbeeld:

  • Maak een PartipantController.ts, als deze nog niet bestaat.
  • Voeg een render-functie toe met de naam die je wilt overzetten, een goede naamgeving is: render[CRUD-actie][Entiteit-naam]Page, bijvoorbeeld renderAddParticipantPage.
  • Knip en plak alle code uit de participant-add.ts in deze functie, dit zal in de meeste gevallen geen problemen geven.

De makkelijkste pagina’s om mee te beginnen zijn de index, register en login.

Models

Bij het verplaatsen van de pagina’s ben je eigenlijk al aan het nadenken over de benodigde entiteiten.

Voor elke controller is daarom de kans groot dat er ook een model-class met die naam nodig is, zo zal de ParticipantController een model Participant krijgen. Deze plaats je dan in de models-map met de naam Participant.ts.

De afspraak voor models is dat die alleen data bevatten, geen complexe logica. Elk model heeft naast de gegevens die ze moeten vasthouden vrijwel altijd een id-attribuut en moet van correcte Encapsulation voorzien zijn.

Let op! Als je een JSON.stringify met een object instantie doet, worden de private attributes gebruikt, niet de getters. Bij JSON.parse moet je daar dus rekening houden met je type! Dit zal echter alleen een rol spelen als je kiest voor localStorage-opslag, niet bij een echte database.

Repositories

Waar models zijn, zijn meestal ook repository-classes nodig om de data die ze vasthouden op te slaan of juist weer in te laden. Heb je een Partipant-model, dan heb je een PartipantRepository. Deze plaats je dan in de repositories-map met de naam PartipantRepository.ts.

De afspraak is dat de controllers geen weet hebben van de databron waar ze tegen praten. De repository-class is de enige die weet of data uit de localStorage of de database komt. Het maakt de controller niet uit hoe die zijn Participant-model instantie krijgt, als die hem maar krijgt.

De repository bevat alle functies die de controllers nodig hebben om hun werk te kunnen doen, meestal zijn dat in ieder geval de volgende acties:

  • getAll
  • getById
  • create
  • update
  • delete

Maar daarnaast kan je per model specifieke functies toevoegen, zo zal de UserRepostory een login en register krijgen.