For the past 6 months I have been working with a friend on a crowdsourced shipping marketplace catered to the African diaspora in Europe. The platform is called litomba which means “reward” in Lingala, a language spoken in central Africa, and it addresses the challenge of sending documents or goods back to Africa.
Now for the technical part of the article!
First of, let’s take a look at the overall architecture that powers litomba:
Now let’s break that down!
The code is split along quite traditional lines, with a rich client that communicates with a server via an RESTful API. The stack is also quite boring, as it’s just a React app on top of a NodeJS/Express web server and a PostgreSQL database, all wrapped into a monolith and deployed on Heroku. The interesting thing about the code is that it has enough abstraction levels that it should be trivial to split it and move onto a different architecture or stack if (and only if) needed.
The client is scaffolded using
create-react-app which makes things really simple to get started! For now we haven’t had to eject yet, so really kudos to the people behind that tool, it’s really a pleasure using it!
Screens and Components
litomba is composed of a couple a dozen of screens, and we manage all the routing on the client-side thanks to React Router.
All the screens are inside a
screens folder and each screen is then composed of small (if possible functional stateless) components that live in the
In terms of styling (that’s a hot topic right now), we prefer to just use plain CSS for now!
Also a hot topic, but here again we try to keep it simple and boring!
Each screen is responsible for its state and any request to the server (loading data, posting changes, etc…). We usually prefer to keep things simple and use the built-in state management system until we outgrow it before looking at other tools such as Redux.
If some of the screens need to share state, lifting state up to the
App root component is always a good strategy.
If you look closely, you’ll notice that layer in between the client and the API endpoints that is called store (I know, that’s not really a great name as Redux uses it too for something else, but I guess we ain’t that good at naming things!).
The main idea here is to have a data layer abstraction, so that the front-end requests data or posts data to a store, and then receives it back without knowing where that data came from. The main benefit here is that we can completely change the data fetching code without touching the front-end. This also allows for the implementation of a cache system based on localStorage for example, with a fallback on an API.
The server is a simple NodeJS/Express web server linked to a simple PostgreSQL database and with some hints of Redis for storing the session.
It exposes RESTful API endpoints (or as RESTful as we can get).
The actual endpoints are dissociated from the data processing mechanism. Not much more to say here as it is pretty much what you’d expect on an Express app!
The actual business logic resides in a separated folder. It retrieves the data from the database or a third-party API and then sends it back to the client by exposing a function for each HTTP verb to the API layer.
All the meat of the app resides in this folder!
Communicating with the database
We personally like to write my SQL queries in … SQL, so we are using a tiny wrapper that reads and executes SQL files rather than a full-blown ORM.
This part is also abstracted and decoupled from the rest of the app, to make things as swappable as possible when needed!
The good thing about this architecture is that it is relatively simple to mount, and yet quite flexible as it does try to decouple as much as possible without bringing too much abstraction.