Blockchain Transactions: UTxO vs. Account-Based Models
Gustavo Martins | Oct 31, 2024
When we think about the process of developing an MVP, what we have in mind is to create great value in a short time, avoiding complexities and solving problems in the simplest way possible.
Then, on a beautiful sunny summer day, the Project Manager comes up and says:
“We need to create an MVP for a chat system in just one month!”
It’s chaos! It seems to be something very complex for only a month of work. Some questions begin to emerge:
After brainstorming a bit, developers start to think about various open-source alternatives, like jsxc and pyxmpp, that could fit the business model and the project’s needs.
In this case, the alternatives found didn’t meet the application requirements perfectly, because the team would have to spend a lot of time learning a new library whose features would mostly not be needed for our MVP.
After extensive research and no solution, a voice from heaven says:
“Why not create your own architecture?”
It’s just an MVP! We need to test the project before we think about scalability, right? It was then that we decided to implement this architecture with WebSockets. Here’s the breakdown of what we came up with.
Our starting point was a basic architecture, composed by a Back-end with Python and Django, using PostgreSQL database and ReactJS and Redux on the Front-end. With baby steps in mind, we thought about creating a chat system without real-time operations, in other words, just a CRUD of messages. After the database modeling, we ended up with only two tables: Chat and Message. Simple!
With the database ready, we created all the endpoints needed to communicate with the Front-end. Our API became very simple, just two endpoints: /chats
and /chats/:idChat/messages
, having the following HTTP actions:
In the Front-end we created, with the Redux, two stores: one for the chats and another for the messages, reflecting exactly what was being received from the API. For the communication between the Reducers, four actions were necessary:
The image above represents the implementation after the first phase of the project. With this, we could already carry out conversations between two users. However, we needed to refresh the page to receive new messages.
To evolve the application into a real-time architecture, we needed to add two key pieces: a data structure featuring publish/subscription and a WebSocket server.
For Pub/Sub, we chose Redis – an open source (BSD licensed), in-memory data structure store, used as a database, cache and message broker – as our team was very familiar with it. This tool has the utmost importance for the operation of our new architecture, allowing messages to almost instantaneously published without harming our web service performance.
To listen to the Redis publications and create a WebSocket server, we decided to create a microservice using NodeJS. When initialized, it creates a WebSocket using the socket.io library, subscribing as a Redis listener.
The microservice works like a messaging router. After receiving messages from Redis, it checks if the recipient is connected via WebSockets and forwards the content. Messages sent to unconnected recipients are discarded, but, when users log in to chat, they will receive messages through HTTP requests.
After adding these two pieces, our architecture looks like this:
Now it’s time to fix the page refresh issue, making our conversation more fluid. For this, we needed a bidirectional communication between the server and the client. According to our architecture, now we just need to add the socket.io library on the Front-end side and connect it to microservice. With this, we were able to have a permanent connection between the client and the server, allowing them to receive and send messages at any moment.
In the Back-end side, we added two things: the connection with Redis and the publication of the message after it has been saved in the database. For the Front-end structure, we just created a new action called ADD_MESSAGE_FROM_SOCKET
and the <WebSocket />
component.
The action has the simple responsibility of adding the messages received in the correct store. The component took the role of creating/removing the connection to the WebSocket and listening to the port. When it receives a new message via the WebSocket, it just calls the action ADD_MESSAGE_FROM_SOCKET
.
Some important decisions were made:
Using this simple approach, we were able to transform our CRUD-only chat in real-time fluent conversations.
Through this solution, we created a simple and maintainable chat application for our MVP. Also, we managed to prove that, for an MVP, this solution is extremely feasible. However, we have to keep in mind that as the project grows, some concerns should be raised, such as scalability and maintainability.
A Front-End developer passionate about open source culture. Trying to help people by sharing code.