Building a low-code platform with Neo4j (4/4) — The Rabbit Hole
By: Stefan Dreverman
Tags: Software Architecture, Low Code, Neo4j, Software Development, PHP

In the last part of this mini-series, you will discover that the the rabbit hole is as deep as you would like it to be. It’s all about modularity and what your imagination can think up for the platform to do.

If you haven’t checked out the InfoNotion repository on github, now is the time. For this last article, follow the installation instructions and load the “in_Questionnaire_example”-example.

Functional modules

Although a functional module is not a meta model concept in the sense of the previous articles, it does hold information. It forms the link for the low-code developer to a specific functionality.

In the PoC, a Functional module consists of:

A meta model (the model in which the low-code developer specifies how the logic is used)

A Symfony Controller (The generic code & logic for this module)

Twig/html templates (The UI-part)

These different concepts are written in three completely different languages, yet they are glued together via the platform. Once in place, they allow the low-code developer to specify the behavior for the end-user.

In the previous articles you’ve already seen three Functional modules:

Data Browser

Data Editor

View

These come with the platform and deliver what most of us consider standard behavior: Browsing and editing data. When using the PoC, think about how the same logic is used for every data structure retrieved/displayed/stored.

Now let’s create a new module and see what is needed to create one.

Requirements

Let’s create functionality from a previous set of articles: Answer a list of Questions. The articles were an example that explain the decisions to create the meta model. Now let’s build it into the PoC.

We need to be able to:

Low-code developer

Specify Questions, Answers and the List of Questions

This is done via the meta model to ensure we’re actually using the ‘low-code’-part. If not, we’re plain programming.

User

Load a screen to let User enter its respondent name (system) Load the List of Questions (passed as parameter in URL) Be prompted a screen in which the first unanswered question (in order) can be answered Write the answered question to the database. If there is another question, go to 2.

So let’s call this the MVP on which you can build. :-)

The meta model

The meta model for our List of Questions will look like this:

Yes, it works perfrectly although it’s a little different from the previous Questionnaire-articles.

This model can be fully defined via the Data Browser/Editor of the platform. To separate the model from the rest of the models, it is put into a new domain. Questions, for instance.

How? To add a domain go to the FunctionalType, select the Domain type in the left list. And press the Add-button under the list of Domains (one in the middle). After the domain is created, it can be made visible in the domain menu (which is defined as a navigation tree) by selecting the DomainNavTree type and editing the TopNavTree instance. You can select both the FunctionalType and Questions domains by holding ctrl and clicking. Just before saving, the edit screen should look like this:

Adding the Questions domain to the navigation tree

Returning to the root of the website, will display two domains now, allowing for a click on the new domain. Clicking on the Questions-domain will result in a domain without any types (called Subject here for some unknown reason) or instances. Which is correct.

From here we can start to add the complete meta model by clicking the add button in the right menu and entering the types. To successfully do this, start with the types that have no outgoing arrows and work outwards. For this meta model, the creation order would be: Question, ListOfQuestions, Answer, Respondent.

If you want do it yourself remember to:

Add an order-attribute to Question

Set the Multiple Answers attribute to Yes on

The contains relation from ListOfQuestions to Question,

relation from ListOfQuestions to Question, The respondedTo and respondedWith relations from Respondent to Question/Answer

The Multiple Answers-attribute on relations specifies the cardinality of the relation. The attribute specifies “1..n” when Yes and “1..1” when No.

The result is a set of types (subjects):

The types within the Questions domain

Now the meta model is done, the instances (the actual Questions, ListOfQuestions and Answers) itself can also be created via the standard Data Editor. (Btw it would be more user friendly to create a dedicated screen to enter all the data for the list in one screen, but for now this will do.)

The questionnaire for a mini series. ;-)

The Neo4j data looks like this:

Under the bonnet…

This concludes entering the meta model and instance data to create the application logic with. Noticed that up to this point, no code had to be written?!

The application logic

For this meta model to do something, we will need to write code once. Since this PoC is written in php/Symfony, a new Controller is needed for the Question-functionality.

The UI needs two sections. One:

UI: A section where the Respondent can be identified (and the Respondent information is displayed).

Backend: A call to receive a Respondent name and provide Respondent information to the UI

Two:

UI: A section where the subsequent questions are asked and can be answered by the user

Backend: A call to send answers to and provide the next question (if any) to the UI

1. Identifying the Respondent & getting the information

Normally you would take User information from a session. This PoC has none, so we need to create some replacement functionality. I’ve made a Frame where the user can type a name. The name has to exist as a Respondent in the database. If so, it is retrieved and displays this text:

What happens after the user presses the Submit button:

UI: Make ajax call to retrieve Respondent Information

Backend: Execute Query and return results

UI: Render Respondent Information (if any)

To find the Respondent, I’m using the following query:

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

The Query retrieves both the total number of questions in the list and the number of answers given by this Respondent, so we can use this for the text in the Respondent Information.

2. Getting and displaying the Next Question

When a Respondent is returned in step 1, a new call can be done to retrieve the next question. Doing so will need two parameters: The ListOfQuestionsID and the 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

As you can see, this query retrieves only the first Question of this ListOfQuestions that has not been answered by the Respondent yet. And all the Answers for that Question.

To display the next Question, I’ve created a View. It returns the complete form for the Question:

Hey, is this Questionnaire about these articles?

Clicking one of the answers will set the AnswerID to that Answer. Clicking the submit button will send a call for the Next Question again, this time with an AnswerID… so…

Storing the Answer

…there’s more to do in this NextQuestion-call. If an answer is given, it needs to be stored in the database. This can be done by calling:

MATCH (r:Respondent),(a:Answer)

WHERE r.in_id={RespondentID} AND a.in_id={AnswerID}

MERGE (r)-[:respondedWith]->(a)

Note that it’s important to do this before the new next Question is retrieved, because else the same Question would pop up twice before going to the next.

After the answer is stored, your Neo4j data will look like:

Respondent “test” likes the series. Yes! :-)

Stateless

Since the model and query don’t require a state to be stored, the next Question can be loaded any time. Restarting the browser/device and loading the questionnaire again would show:

The code is stateless, so the next question can be loaded any time…

After finishing the last questions, you are informed that you’re done:

You’re done!

Content added for Questionnaire

So what was added to make this possible? I’ve added the following:

A meta-model and some new content in the database (creating the desired information and behavior from low-code developer perspective) A Controller with 3 functions: One to redirect from a different URL and the 2 ajax calls above (Executing the behavior from developer perspective) One Frame and one View (Gathering and displaying the information)

It didn’t take much programming for something that can be used for any List of Questions. Though, in a future version, the four files added could be packed neatly together in a package.

Sorting the meta model out takes care and effort (see the Questionnaire articles). Once that’s done, writing the rest is easy, because the real work is in when/how the information is gathered/displayed.

Conclusions

And as this was a PoC, it is far from finished. Though a fun and learning exercise that triggers a lot of new questions. There’s so many things that can be done and explored from here. Most importantly I’d like to build an actual platform based on these principles as I’ve seen it can be very powerful with little effort.

To summarize what I learnt:

Neo4j and Low-code are a good marriage

Neo4j is a very good candidate for use in low-code platforms. The simplicity of its meta model mixes very well Its possibilities mix very well with the abstractions and meta models needed to build a low-code platform. Furthermore, the tooling of the Neo4j database can be made available to the platform because of the easy and powerful Cypher query language.

In my mind, a low-code platform adopting Neo4j as its database would blow the competition away in terms of versatility and speed of implementation.

Twig and Low-code are also a good marriage! :-)

The versatility of Twig is exactly what’s needed to deliver the variety of webpages that are needed for a low-code platform.

Interesting: Hybrid between low-code and standard development

Not a fan of low-code? Not a problem. Think about this: The programming style done in this series can be adopted to form a hybrid between low-code platform and plain coding. The developer has the possibility to chose which parts to put in low-code and which parts to program. This stretches the ‘configurability’ and ‘speed of design’ (or fast-prototyping) of your implementations.

I really fancy this in my work as an IT Architect, because it allows for fast prototyping with a complete set of tools and fast information analysis!

Shortcomings

Open-source worse case scenario — I chose Php/Symfony as the basis of this PoC. In the mean time, Neo4j has upgraded to 4.0. Good thing? Not for php-lovers: Upgrading to this version was not possible, because the Graphaware client I’m using to communicate with the database has been ‘archived’ in Github, meaning it won’t be updated. Ever. However, since Graphaware is a company, it might have a paid version?

The Functional modules are not modules yet — Yeah, I know. :-/ For the Questionnaire I’ve just added a Symfony Controller and a few templates. It’s fast, but not modulra. These should somehow be im- and exportable in a neat way in the platform.

Built too fast— Not surprising, but definitely worth mentioning: there are more than a few flaws in there. :-) The PoC has not been built taking into account security, production environments, sessions/users or internationalization to name a few. Though possible, it’ll need work to build a website with this as a basis.

Next steps

As mentioned, one of my next steps to take is to explore the possibilities of building a low-code platform built on the principles displayed in this series. Starting with the shortcomings mentioned above. Maybe with php/Symfony but definitely with Neo4j and twig.

Any way it’s worth exploring because of the benefits it gives me as an architect and the head start it can give a development team that needs to deliver results fast.

Hope this was a useful read and a learning experience for you as well. If you want to discuss this topic further or like to build with me, please drop a note.

Happy coding!

Stefan