Hoe begin je een low-code platform met Neo4j? – Hoe diep ga jij?

In het laatste deel van deze mini-serie, zul je zien dat het hol van de leeuw erg diep kan zijn. Zo diep als je zelf wilt. Het draait allemaal om modulariteit en wat je verbeelding aan functionaliteit kan bedenken.

Als je de InfoNotion repository op github nog niet gedownload hebt: Doe het nu. 🙂 Voor dit laatste artikel kun je de instructies volgen voor het installeren van het “in_Questionnaire_example”-voorbeeld.

Functionele modules

Een functionele module is geen meta model concept zoals in de voorgaande artikelen. Het bevat echter belangrijke informatie die de specifieke functionaliteit levert voor een low-code ontwikkelaar of een gebruiker.

In de PoC bestaat een Functionele module uit:

  • Een meta model (het model waarin de low-code ontwikkelaar vast legt hoe de logica gebruikt gaat worden)
  • Een Symfony Controller (De generieke code en logica voor deze module)
  • Twig/html templates (De gebruikersinterface)

Deze concepten zijn in drie compleet verschillende talen geschreven, maar komen samen in het platform-concept. Ze laten de low-code ontwikkelaar een toepassing voor de eindgebruiker definiëren.

In de voorgaande artikelen heb je feitelijk al drie functionele modules gezien:

  • Data Browser
  • Data Editor
  • View

Ze worden meegeleverd met het platform en laten functionaliteit zien die we als standaard beschouwen: De CRUD-acties op informatie. Wanneer je de PoC gebruikt, bedenk dan dat dezelfde CRUD-logica gebruikt wordt voor alle datastructuren.

Voor dit artikel gaan we een nieuwe functionele module maken om te zien wat er voor nodig is om er een te maken.

Requirements

In een vorige set artikelen heb ik het maken van een vragenlijst behandeld. Deze artikelen legden uit welke beslissingen je moet/kan nemen voor het maken van een meta model. Ik neem hier deze vragenlijst als voorbeeld.

We moeten daarbij:

Low-code ontwikkelaar

  • Een vragen, antwoorden en een vragen lijst kunnen definiëren.
  • Dit moet via het meta model kunnen om te waarborgen dat we het ‘low-code’-deel van het platform wel gebruiken. Zo niet zijn we ‘gewoon’ 😉 aan het programmeren.

Gebruiker

  1. Een scherm laden om de gebruiker zijn naam in te laten voeren
  2. (system) Een vragenlijst laden (meegegeven als parameter in URL)
  3. Een scherm tonen waarin de eerste onbeantwoorde vraag beantwoord kan worden
  4. Het wegschrijven van de beantwoorde vraag naar de database.
  5. Als er nog een vraag is: ga naar 2.

Laten we dit de MVP noemen van waaruit we de functionaliteit van de vragenlijst kunnen uitbouwen.

Het meta model

Het meta model voor onze vragenlijst ziet er zo uit:

Ja, deze werkt perfect. Al ziet hij er wel ietsje anders uit dan die van de Questionnaire-artikelen.

Dit model kan volledig via de Data Browser/Editor van het platform gedefinieerd worden. Om het model van de rest van de modellen te onderscheiden, zetten we het in een nieuw domein: Questions genaamd.

Om een domein toe te voegen, kun je met de browser naar domein FunctionalType gaan en daar het type Domein selecteren. Daarna klik je de Add-knop onder de lijst met Domeinen (die in het midden). Nadat het domein is gemaakt, kan het zichtbaar gemaakt worden in het domein-menu door het DomainNavTree-type te selecteren en daarvan de TopNavTree te editen. Je kunt beiden domeinen selecteren door de ctrl knop ingedrukt te houden en te klikken. Vlak voor het opslaan zou het scherm er zo uit moeten zien:

Het toevoegen van het Questions domein in het menu

Als je nu de root van de website laadt, zie je twee domeinen. Als je nu op het Questions-domein klikt, zul je een domein zien zonder typen (deze worden Subject genoemd in de PoC) of instanties. Dit klopt:

We kunnen nu het meta model toe gaan voegen door op de Add-knop in het rechter menu te klikken en de typen toe te voegen. Om dit succesvol te doen, zul je moeten starten met de typen die geen uitgaande relaties hebben en van daar uit naar buiten werken. Voor dit meta model is de volgorde: Question, ListOfQuestions, Answer, Respondent.

Als je het zelf doet, onthoud dan het volgende:

  • Voeg een order-attribuut toe aan Question

Zet het attribuut Multiple Answers op Yes bij

  • De contains relatie van ListOfQuestions naar Question,
  • De respondedTo en respondedWith relaties van Respondent naar Question/Answer

De attribuut Multiple Answers op relatie geeft de cardinaliteit aan van de relatie.  Het attribuut is “1..n” bij Yes en “1..1” bij No.

Het resultaat is een set van typen (subjects) in het domein Questions:

The types within the Questions domain

Nu het meta model klaar is kunnen de instanties van de typen (de vragen, antwoorden, vragenlijst en een respondent) ook in de standaard Data Editor aangemaakt worden. (Ja, het zou hier nuttig zijn om één scherm voor het invoeren van één vragenlijst te maken, maar het blijft een PoC 🙂

De vragenlijst voor een mini-serie. 😉

De data ziet er dan zo uit in Neo4j:

Onder de motorkap

Nu zitten het meta model en de vragenlijst in het systeem. Rest ons de logica toe te voegen. Merk op dat er nog geen regel code is geschreven!

De applicatie logica

Om dit meta model tot leven te wekken, is een stuk generieke code nodig. De PoC is geschreven in Php/Symfony dus er is een nieuwe Controller nodig voor de logica van een vragenlijst.

De gebruikersinterface heft twee secties. Eén:

  • UI: Een sectie waar de Respondent geïdentificeerd kan worden (en de informatie over de Respondent wordt weergegeven)
  • Backend: Een call om informatie over de Respondent op te halen

Twee:

  • UI: Een sectie waar de opeenvolgende vragen gesteld worden en beantwoord kunnen worden door de gebruiker
  • Backend: Een call om antwoorden naartoe te sturen, welke ook de volgende vraag teruggeeft (als die er nog een is)
  1. Het identificeren van de Respondent

Normaal gesproken zou hier de sessie van een ingelogde gebruiker gebruikt worden. Aangezien deze PoC dat alles niet heeft, wordt dit vervangen door een Frame waarin de gebruiker een naam kan opgeven. De naam moet bestaan als Respondent in de database. Als dat het geval is, dan wordt deze opgehaald en wordt het volgende getoond:

Jou Inhoud Komt Hier

Na het drukken op de “Submit”-knop gebeurt het volgende:

  • UI: Voor een AJAX call uit om de informatie over de Respondent op te halen
  • Backend: Voer de bijbehorende Query uit en lever de resultaten terug in een response bericht
  • UI: Render de informatie over de Respondent in het scherm (als die er is)

Om de Respondent te vinden, wordt de volgende query gebruikt:

MATCH (q:Question)<-[:contains]-(loq:ListOfQuestions)
WHERE loq.in_id={LoQID}
WITH loq,q
MATCH (r:Respondent) where r.name={RespondentName}
OPTIONAL MATCH (r)-[rw:respondedWith]->(a:Answer)-[:isAnswerTo]->(q) RETURN r.in_id as RespondentID,
r.name as RespondentName,
count(rw) as QuestionsAnswered,
count(q) as TotalQuestions

De Query haalt zowel het totaal aantal vragen in de lijst op als het aantal gegeven antwoorden, zodat deze informatie gebruikt kan worden bij het samenstellen van de tekst.

  1. Het ophalen en weergeven van de volgende vraag

Wanneer een Respondent is gevonden in stap 1, kan een nieuwe call gedaan worden om de ‘volgende vraag’ op te halen. Hiervoor zijn twee parameters nodig: ListOfQuestionsID en RespondentID:

MATCH (n:ListOfQuestions)-[:contains]->(q:Question),(r:Respondent) WHERE r.in_id={RespondentID} AND n.in_id={LoQID} and NOT (q)<-[:isAnswerTo]-(:Answer)<-[:respondedWith]-(r)
WITH q,r
ORDER BY q.order
LIMIT 1
MATCH (q:Question)<-[:isAnswerTo]-(a:Answer)
RETURN q as Question, COLLECT(a) as Answers

Zoals je ziet haalt deze query alleen de eerste vraag van de ListOfQuestions op die nog niet is beantwoord door de Respondent met daarbij alle mogelijke antwoorden op die vraag.

Er is een View aangemaakt om de opgehaalde vraag te tonen: Deze bestaat uit het complete form voor de vraag:

Hey, is dit een vragenlijst over deze artikelen?

Het aanvinken van één van de antwoorden zet het AnswerID voor dat antwoord. Bij het klikken op de Submit-knop, wordt weer een call gedaan om de volgende vraag op te halen. Ditmaal mét AnswerID, dus…

Het antwoord opslaan

… er is meer te doen in de NextQuestion-call. Als er een antwoord is gegeven, moet dit opgeslagen worden in de database. Dit gebeut door:

MATCH (r:Respondent),(a:Answer)
WHERE r.in_id={RespondentID} AND a.in_id={AnswerID}
MERGE (r)-[:respondedWith]->(a)

Merk op dat dit gedaan moet worden voordat de nieuwe volgende vraag opgehaald wordt. Zo niet, wordt tweemaal dezelfde vraag opgehaald en getoond voordat de volgende getoond wordt.

Respondent “test” vindt deze serie artikelen leuk! 🙂

Stateless

Aangezien de state van de vragenlijst is opgeslagen in de database, kan de volgende vraag op elk moment geladen worden. Het herstarten van de vragenlijst (na afsluiten en opnieuw opstarten van de browser) zou het volgende scherm tonen:

De state van de vragenlijst wordt opgeslagen in de database, dus de vragenlijst kan op elk moment vervolgd worden.

Na het beantwoorden van de laatste vraag, wordt een scherm getoond dat je klaar bent:

Klaar!

Toevoegingen voor de Questionnaire

Wat is er nu toegevoegd aan het platform? Ik heb hiervoor het volgende toegevoegd:

  1. Een meta-model (Questionnaire meta model) en nieuwe instanties in de database (de vragenlijst informatie)
  2. Een Symfony Controller met 3 functies: Redirect URL (/questionnaire => /FrameN) en de Twee AJAX calls van hierboven (om de functionaliteit uit te voeren)
  3. Eén Frame en één View (om de informatie te tonen op het scherm)

Er was niet veel programmeerwerk nodig voor iets dat hergebruikt kan worden voor elke vragenlijst. Deze vier bestanden (want zoveel waren het er) kunnen echter wel netjes samengepakt worden in een package om er een echte module van te maken.

Het opstellen van het meta model vergt zorg en moeite (zie ook: Questionnaire artikelen). Als dat eenmaal is gedaan is het schrijven van de code en het maken van de schermen niet veel werk. Het maken van vragenlijsten is daarna een kwestie van het toevoegen van informatie aan de database.

Conclusies

Hoewel di teen leuk en leerzaam traject was, is deze PoC verre van af en werpt ze een aantal nieuwe vragen op. Er zijn veel nieuwe perspectieven te ontdekken en verkennen vanuit dit startpunt. Belangrijkste conclusie is dat ik een platform zou willen bouwen dat gebaseerd is op deze principes. Het kan met weinig inspanning een zeer krachtig platform worden.

Wat heb ik geleerd?

Neo4j en Low-code gaan goed samen

Neo4j is een zeer goede kandidaat om te gebruiken in low-code platforms. De eenvoud en functionaliteiten van het Neo4j data model gaan goed samen met de abstracties en meta modellen die nodig zijn voor een low-code platform. Daarnaast kan ook uitgebreidere tooling van het Neo4j platform gebruikt gaan worden vanwege de krachtige Cypher-querytaal.

In mijn ogen zou een low-code platform, dat Neo4j op deze manier gebruikt als haar database, de concurrentie ver achter zich laten in termen van veelzijdigheid en implementatiesnelheid.

Twig en Low-code gaan ook goed samen! 🙂

De veelzijdigheid van Twig is precies wat nodig is om de veelzijdigheid aan webpagina’s te leveren die nodig is.

Interessant: Hybride tussen low-code en standaard ontwikkeling

Geen fan van low-code? Geen probleem! Stel je voor: De programmeerstijl in deze serie kan gebruikt worden om een hibryde ontwikkelstraat te maken waarin een low-code platform samen gaat met standaard programmeerwerk. De ontwikkelaar heeft de keuze om delen in low-code of juist in standaard code te maken.

Dit is één van de aspecten die ik erg waardeer in rollen als IT Architect, omdat dit fast prototyping en snelle informatieanalyse toestaat met de (uitwijk)mogelijkheid om een en ander toch in standaard code te realiseren.

Tekortkomingen

Open-source worst-case scenario — Ik heb Php/Symfony als basis voor deze PoC heb genomen. In de tussentijd heeft Neo4j versie 4.0 uitgebracht. Fantastisch? Niet voor php + Neo4j liefhebbers: Een upgrade naar deze versie was niet mogelijk omdat de Graphaware client die php laat praten met Neo4j ‘gearchiveerd’ is op Github. Dit houdt in dat er geen onderhoud meer op gepleegd wordt en geen upgrades meer voor komen. Troost is dat Graphaware een bedrijf is en dat ze waarschijnlijk wel een betaalde versie hebben van die client. Het haalt op zijn minst het open-source doel onderuit.

De Functionele modules zijn nog geen modules— Ik weet het… Voor deze vragenlijst heb ik gewoon een Symfony Controller en een paar templates toegevoegd. Snel, maar geen module. Deze zouden op één of andere manier geimporteerd en geexporteerd moeten kunnen worden.

Te snel gebouwd— Niet verrassend, wel belangrijk om te vermelden: er zitten meer dan een paar oneffenheden in deze PoC. Zo is er geen rekening gehouden met onder anderen: beveiliging, productieomgevingen, sessies/gebruikers of internationalisatie. Hoewel mogelijk is er zeker werk nodig om deze PoC als basis voor een website te kunnen gebruiken.

Hoe nu verder?

Zoals gezegd wil ik als een van mijn volgende stappen gaan verkennen wat de mogelijkheden zijn om op de principes uit deze serie een volledig low-code platform te bouwen. Misschien met Php/Symfony, maar zeker met Neo4j en Twig.

Het onderzoeken hiervan is alleen al de moeite waard omdat het me waardevolle inzichten geeft als architect over de kwalitatieve voorsprong die het een ontwikkelteam kan geven als er snel resultaten neergezet moeten worden.

Ik hoop dat dit voor jou waardevol leesvoer en een leerzame ervaring was. Mocht je er verder over willen praten of wil je me helpen om dit platform te bouwen, stuur me even een mail.

Happy coding!

Stefan

Terug naar overzicht

Meer lezen van Stefan? 

Vond je dit een interessant artikel? Lees dan meer van Stefan via onderstaande knop:

Bekijk alle artikelen van Stefan

Stefan Dreverman, Trending Technologies Zuid

MEER LEZEN?

Bekijk hier alle blogs.

Alle blogs

Plaats een reactie