4.3 “Aan welke voorwaarden moet de interface voldoen, zodat regels op een overzichtelijke en duidelijke manier
5. Ontwerp en realisatie
5.2.2. Technische toelichting
5.2.2.4. Back-end
De back-end van de applicatie is opgezet met een Rails JSON API, in dit hoofdstuk wordt beschreven hoe de afhandeling van data gaat vanaf het moment dat deze aankomt bij de controller van de API.
5.2.2.4.1. Framework/programmeertaal
De back-end is gebouwd met het Rails framework versie 6, deze versie is gebouwd met de programmeertaal Ruby. Rails 6 is afhankelijk van een minimum versie 2.5 van Ruby, om te kunnen draaien. Voor deze versie is Ruby 2.7 gebruikt.
5.2.2.4.2. Rails
Rails is een webframework dat gebruikt kan worden met een geïntegreerde front-end of, wanneer de ‘--api’ flag aan het genereer commando van een nieuwe applicatie wordt meegegeven, als JSON API. Omdat het gebruik van een losse front-end applicatie meer flexibiliteit biedt, is in dit geval voor het laatste gekozen. Voor dit project worden Rails Models gebruikt om de kenmerken en logica van de back-end modellen te definieren en controllers voor het afhandelen van verzoeken van de client applicatie. Meer informatie over de mogelijkheden die Rails biedt en de manier waarop de API gebruikt kan worden is te vinden op:
https://api.rubyonrails.org/ en https://apidock.com/rails/browse
5.2.2.4.3. Ruby
Het Rails framework is gebaseerd op de programmeertaal Ruby, waarvan de maker tracht om het er simpel uit te laten zien, met complexe mogelijkheden ‘onder de motorkap’. Één van de belangrijkste concepten van Ruby is dat alles een object kan zijn met zijn eigen attributen en acties. Waarbij bijvoorbeeld zelfs een getal een object is met instantie variabelen en functies. Op https://docs.ruby-lang.org/en/2.7.0/ kan de documentatie van Ruby v2.7 gevonden worden.
5.2.2.4.4. Database
Het Rails framework beschikt met ActiveRecord over een prima database beheer systeem. ActiveRecord is een zogenaamd Object Relational Mapping systeem dat zorgt voor:
- Beschrijving van modellen en hun data.
- Beschrijving van de relaties tussen deze modellen.
- Validatie van modellen voordat ze in de database worden opgeslagen. - Database operaties kunnen doen op een object georiënteerde manier. Postgres is een database die goed samengaat met Rails en ActiveRecord. Tevens wordt deze door de opdrachtgever bij meerdere projecten reeds gebruikt. Daarom is deze ook voor dit project gebruikt.
5.2.2.4.5. Postgres
Postgres is één van de meest gebruikte databases ter wereld. Het is een open source object-relationele database, gebaseerd op SQL, waardoor objecten, klassen en
Postgres kan gevonden worden op: https://www.postgresql.org/docs/.
5.2.2.4.6. Klassen & relaties
In onderstaand klassendiagram worden de model, en dus database relaties binnen de back-end applicatie weergegeven:
Het model van de database in het systeem is gebaseerd op de datastructuur die is ontworpen om regels in op te kunnen slaan. Binnen het systeem zijn er drie ‘hoofd’ tabellen:
- Rule
Een regel heeft een naam en en versie en één of meerdere Antecedenten en één of meerdere Consequents (als relatie met het Action model).
- Antecedent
Hiervoor zijn de subclasses gespecificeerd die voorkomen in de datastructuur. Zodat herkend kan worden wel type Antecedent het betreft.
- Action
Onderdeel van Rules als has_many attribuut ‘consequents’
5.2.2.4.6.1. Antecedents - Event
Dit antecedent type komt in iedere regel minimaal één keer voor. Een Event heeft één of meerdere ‘event_attributes’, dit kunnen variabele waardes zijn bijvoorbeeld wanneer een gebruikers id verwacht word. Of vaste waarden. Wanneer er een ‘isAdmin’ Event attribute verwacht word bij een logged_in event die true moet zijn.
- Counts
Counts kan tellen of een andere antecedent meer dan één keer voorkomt. Bijvoorbeeld bij de regel ‘wanneer een logged_in event drie keer voorkomt’. Dan heeft een Counts antecedent een amount van 3 en een Event met name “logged_in”
- Duration
start_antecedents zijn de trigger voor het expertsysteem om de timer,
gespecificeerd in ‘interval’ te starten. De timer wordt beeindigd wanneer deze afloopt of alle end_antecedents zijn voorgekomen.
- TimeUnit
Deze start een timer gedurende een dag, week of maand. Als de timer afloopt kijkt het expersysteem voor welke target_attributes van de Actions die aan de regel verbonden zijn deze voorwaarde als true geevalueerd kan worden. Deze krijgen dan de action_attributes uitgekeerd.
- NEq - Eq - GreaterThan - GreaterThanOrEquals - LessThan - LessThanOrEquals
Dit zijn alle zogenaamde vergelijkings antecedenten. Deze hebben een max van twee ‘compare_attributes’, waarmee afgedwongen kan worden dat het variabele attribuut ‘user_id’ die in twee antecedenten voorkomt, overeenkomt middels de Eq antecedent, of juist niet met de NEq antecedent.
- Action
Een Action heeft één of meerdere ‘action_attributes’ dat bijvoorbeeld een badge of een certificaat kan zijn die het platform kan toekennen. Daarnaast één of meerdere ‘target_attributes’ waaraan de action_attributes worden toegekend.
6. Conclusie
Het belangrijkst bij het doen van een onderzoek is uiteraard het trekken van
conclusies en bediscussiëren van de uitkomsten van het onderzoek. In dit hoofdstuk worden de conclusies puntsgewijs behandeld en worden aanbevelingen gedaan voor verdere ontwikkeling van het project.
6.1. Discussie
Bij het ontwerpen van de datastructuur is geen rekening gehouden met het
evaluatiemechanisme in het expertsysteem, zoals de data nu gestructureerd is, is het mogelijk om allerlei soorten antecedenten aan een regel toe te voegen, waarbij volgorde bijvoorbeeld bepalend kan zijn voor de manier van evalueren. Aangezien niet getest kon worden met een expertsysteem kan niet gegarandeerd worden dat het geheel een werkbaar systeem zal vormen of dat er mogelijk nog aanpassingen nodig zijn aan de datastructuur. Daarnaast is voor nu aangenomen dat, wanneer er het antecedent type period gebruikt wordt, de periode ingaat wanneer het
expertsysteem begint met evalueren van events voor deze regel. Wellicht dat hier in de toekomst nog een start- en einddatum aan toegevoegd kunnen worden zodat er meer controle is over wanneer een regel actief is en wanneer niet. Op basis van de set gedefinieerde regels is een aanname gedaan dat alle antecedent types zijn verwerkt in het schema, mogelijk kunnen er nog regels bedacht worden waarvoor andere antecedent types nodig zijn. Het huidige schema biedt in ieder geval een goede basis om mee te beginnen en er is rekening gehouden met mogelijke uitbreidingen. Op dit moment is er geen rekening gehouden met mogelijke wijzigingen van regels, of het aan- en uitzetten van regels aan de kant van het expertsysteem. Zodra in de webapplicatie een regel gewijzigd en opgeslagen wordt, betekent dit niet direct dat het expertsysteem hier ook van op de hoogte is, dat kan zorgen voor
miscommunicatie waardoor uiteindelijk onverwachte resultaten zouden kunnen voorkomen, dat badges niet uitgekeerd worden terwijl dat wel zou moeten.
6.2. Aanbevelingen
De belangrijkste aanbeveling is, voordat er verder ontwikkeld wordt, een
testopstelling te realiseren waarin het domein gesimuleerd wordt met een platform dat events verstuurd, een expertsysteem dat deze events kan evalueren en de applicatie behorende bij dit project om regels mee te maken en naar het expertsysteem te verzenden. Hierdoor zullen eventuele haken en ogen die zijn ontstaan door de ontwikkeling van het expertsysteem en de regel beheer applicatie gelijktijdig te laten plaatsvinden, snel naar voren komen. Daarnaast wordt er een vorm van authenticatie voor de applicatie geadviseerd, om te voorkomen dat ongewenste gasten zomaar de applicatie kunnen benaderen wanneer deze op een productieserver draait.
7. Bronvermelding
1. Nerds & Company, ‘website’, geraadpleegd op 11-02-2020:
https://nerds.company/
2. Wikipedia, ‘No-code development platform’, geraadpleegd op 14-02-2020:
https://en.wikipedia.org/wiki/No-code_development_platform
3. Wikipedia, ‘Low code’, geraadpleegd op 14-02-2020:
https://nl.wikipedia.org/wiki/Low_code
4. E-learning.nl, ‘Wat is e-learning?’, geraadpleegd op: 31-05-2020:
https://www.e-learning.nl/Achtergrond.aspx
5. M. Fowler (2005), ‘Event sourcing’, geraadpleegd op 21-02-2020:
https://martinfowler.com/eaaDev/EventSourcing.html
6. Microservices.io, ‘Event sourcing’, geraadpleegd op: 21-02-2020:
https://microservices.io/patterns/data/event-sourcing.html
7. Medium, ‘Event sourcing is awesome!’, geraadpleegd op: 24-02-2020:
https://medium.com/jettech/event-sourcing-is-awesome-c4fe25ad24cd
8. Wikipedia, ‘Business rules’, geraadpleegd op 11-03-2020:
https://en.wikipedia.org/wiki/Business_rule
9. Wikipedia, ‘Expertsysteem’, geraadpleegd op: 27-02-2020:
https://nl.wikipedia.org/wiki/Expertsysteem
10. H. Streck (2016), ‘Gamification’, geraadpleegd op 23-02-2020:
https://www.managementboek.nl/code/inkijkexemplaar/9789492221322/gamifi
cation-horst-streck.pdf
11. M. Jacobs, A. Coppens, R. Niels, N. Verhoeven e.a. (2015), ‘Proeven van
onderzoek: De methodenkaart in de beroepspraktijk van ICT & Media’,
geraadpleegd op 11-03-2020:
https://www.researchgate.net/publication/277003225_Proeven_van_Onderzoe
k_De_Methodenkaart_in_de_Beroepspraktijk_van_ICT_en_Media
12. A. Abraham (2005), ‘Rule-Based Expert Systems’, geraadpleegd op 31-03-2020:
http://03.softcomputing.net/fuzzy_chapter.pdf
13. P.J.F. Lucas & L.C. van der Gaag (1991), ‘Principles of Expert Systems’, geraadpleegd op 22-03-2020: https://www.cs.ru.nl/P.Lucas/proe.pdf 14. Wikipedia, ‘XML-Schema’, geraadpleegd op 01-06-2020:
https://nl.wikipedia.org/wiki/XML_Schema
15. Medium, ‘How to use YAML Schema to validate your YAML files’, geraadpleegd op 01-06-2020:
https://blog.picnic.nl/how-to-use-yaml-schema-to-validate-your-yaml-files-c82
c049c2097
16. JSON Schema, ‘website’, geraadpleegd op 10-03-2020:
https://json-schema.org/
17. JSON Schema, ‘getting started’, geraadpleegd op 10-03-2020:
https://json-schema.org/learn/getting-started-step-by-step.html
18. JSON Schema, ‘properties’, geraadpleegd op 10-03-2020:
https://json-schema.org/understanding-json-schema/reference/object.html#p
roperties
19. Wikipedia, ‘Grafische gebruikersomgeving’, geraadpleegd op 15-04-2020:
https://nl.wikipedia.org/wiki/Grafische_gebruikersomgeving
20. Scrumguide, ‘Wat is scrum?’, geraadpleegd op 01-06-2020:
https://scrumguide.nl/wat-is-scrum/
21. Trello, ‘website’, geraadpleegd op 01-06-2020:
https://trello.com/nl/tour
22. VSCode, ‘website’, geraadpleegd op 01-06-2020:
https://code.visualstudio.com/
23. GitHub, ‘website’, geraadpleegd op 01-06-2020:
https://github.com/
24. Docker, ‘website’, geraadpleegd op 01-06-2020:
https://www.docker.com/products/docker-desktop
25. C’t, ‘Docker met Linux in de praktijk: de kracht van containers’, geraadpleegd op 01-06-2020:
https://www.ct.nl/achtergrond/docker-containers-onder-linux-praktijk/
26. Medium (2019), ‘Phoenix vs. Rails benchmarks’, geraadpleegd op 01-06-2020:
https://medium.com/@elviovicosa/phoenix-vs-rails-benchmark-2019-f0e68336
d557
8. Bijlagen
{
"$schema": "http://json-schema.org/draft-07/schema#",
"$id": "http://github.com/nerds-and-company/rewarden-specifications/schema.json", "title": "Rule schema",
"description": "A schema to which rules for the Rewarden system must resolve", "type": "object"
"properties": {
"name": { "type": "string" },
"version": { "enum": ["0.1", "0.2"] }, "antecedents": { "type": "array", "contains": { "$ref": "#/definitions/requiredAntecedent" },
"items": { "$ref": "#/definitions/antecedent" }, "minItems": 1 }, "consequents": { "type": "array", "contains": { "$ref": "#/definitions/action" },
"items": { "$ref": "#/definitions/action" }, "minItems": 1
},
"additionalProperties": false,
"required": ["name", "version", "antecedents"], }, "definitions": { "requiredAntecedent": { "type": "object", "oneOf": [ { "$ref": "#/definitions/antecedents/event" }, { "$ref": "#/definitions/antecedents/duration" }, { "$ref": "#/definitions/antecedents/period" }, { "$ref": "#/definitions/antecedents/time_unit" }, { "$ref": "#/definitions/antecedents/count" } ] }, "antecedent": { "type": "object", "oneOf": [ { "$ref": "#/definitions/requiredAntecedent" }, { "$ref": "#/definitions/antecedents/equal" }, { "$ref": "#/definitions/antecedents/not_equal" },
{ "$ref": "#/definitions/antecedents/greater_than" }, { "$ref": "#/definitions/antecedents/greater_than_or_equal" }, { "$ref": "#/definitions/antecedents/less_than" }, { "$ref": "#/definitions/antecedents/less_than_or_equal" } ] }, "antecedents": { "event": { "type": "object", "properties": {
"type": { "const": "event" }, "name": { "type": "string" }, "attributes": {
"type": "array",
"items": { "$ref": "#/definitions/eventAttribute" }, "minItems": 1
} },
"required": ["type", "name", "attributes"], "additionalProperties": false
},
"duration": { "type": "object", "properties": {
"type": { "const": "duration" },
"interval": { "type": "integer", "minimum": 1 }, "start_antecedents": {
"type": "array",
"items": { "$ref": "#/definitions/antecedent" }, "minItems": 1
},
"end_antecedents": { "type": "array",
"items": { "$ref": "#/definitions/antecedent" }, "minItems": 1
} },
"required": ["type", "interval", "start_antecedents", "end_antecedents"], "additionalProperties": false
},
"period": {
"type": "object", "properties": {
"type": { "const": "period" },
"interval": { "type": "integer", "minimum": 1 }, "antecedents": {
"type": "array",
"items": { "$ref": "#/definitions/antecedent" }, "minItems": 1
"required": ["type", "interval", "antecedents"], "additionalProperties": false }, "time_unit": { "type": "object", "properties": {
"type": { "const": "time_unit" },
"interval": { "enum": ["hour", "day", "week" , "month", "year"] }, "amount": { "type": "integer", "minimum": 1 },
"antecedents": { "type": "array",
"items": { "$ref": "#/definitions/antecedent" }, "minItems": 1
} },
"required": ["type", "amount", "antecedents"], "additionalProperties": false
},
"count": {
"type": "object", "properties": {
"type": { "const": "count" }, "antecedents": {
"type": "array",
"items": { "$ref": "#/definitions/antecedent" }, "minItems": 1
},
"amount": { "type": "integer", "minimum": 1 } },
"required": ["type", "antecedents", "amount"], "additionalProperties": false
},
"equal": {
"type": "object", "properties": {
"type": { "const": "equal" }, "compares": {
"type": "array",
"items": { "$ref": "#/definitions/compareAttribute" }, "minItems": 2
} },
"required": ["type", "compares"], "additionalProperties": false
},
"not_equal": { "type": "object",
"properties": {
"type": { "const": "not_equal" }, "compares": {
"type": "array",
"items": { "$ref": "#/definitions/compareAttribute" }, "minItems": 2
} },
"required": ["type", "compares"], "additionalProperties": false
},
"greater_than": { "type": "object", "properties": {
"type": { "const": "greater_than" }, "compares": {
"type": "array",
"items": { "$ref": "#/definitions/compareAttribute" }, "minItems": 2
} },
"required": ["type", "compares"], "additionalProperties": false
},
"greater_than_or_equal": { "type": "object",
"properties": {
"type": { "const": "greater_than_or_equal" }, "compares": {
"type": "array",
"items": { "$ref": "#/definitions/compareAttribute" }, "minItems": 2
} },
"required": ["type", "compares"], "additionalProperties": false
},
"less_than": { "type": "object", "properties": {
"type": { "const": "less_than" }, "compares": {
"type": "array",
"items": { "$ref": "#/definitions/compareAttribute" }, "minItems": 2
} },
"required": ["type", "compares"], "additionalProperties": false
"type": "object", "properties": {
"type": { "const": "less_than_or_equal" }, "compares": {
"type": "array",
"items": { "$ref": "#/definitions/compareAttribute" }, "minItems": 2
} },
"required": ["type", "compares"], "additionalProperties": false } }, "action": { "type": "object", "properties": {
"type": { "const": "action" }, "rule_name": { "$ref": "#/name" }, "attributes": {
"type": "array",
"items": { "$ref": "#/definitions/actionAttribute" }, "minItems": 1
},
"targets": { "type": "array",
"items": { "$ref": "#/definitions/actionAttribute" }, "minItems": 1
} },
"required": ["type", "rule_name", "attributes", "targets"], "additionalProperties": false }, "eventAttribute": { "type": "object", "oneOf": [ { "$ref": "#/definitions/eventAttributes/variable" }, { "$ref": "#/definitions/eventAttributes/value" } ] }, "eventAttributes": { "variable": { "type": "object", "properties": {
"type": { "const": "variable" }, "name": { "type": "string" }, "key": { "type": "string" } },
"required": ["type", "name", "key"], "additionalProperties": false }, "value": { "type": "object", "properties": {
"type": { "const": "value" }, "name": { "type": "string" },
"value": { "type": ["string", "number", "integer" , "boolean", "null"] } },
"required": ["type", "name", "value"], "additionalProperties": false } }, "actionAttribute": { "type": "object", "properties": {
"type": { "type": "string" }, "id": { "type": "string" } },
"required": ["type", "id"], "additionalProperties": false } } }