The good notes project is a simple and functional notes web application.
The link to access it's: good notes
Β
Initially it was to learn about Javascript
and how the flow of a "real application" works, however i learned a lot more than i expected. For these reasons, i would like to share about the project study and development process.
For educational reasons and because it was my first "big" application, i didn't use any library that provided me with ready-made stuff.
- Short explanation
-
With good notes you can create an account and store your notes by organizing them into categories.
- Technical explanation
-
In this project we have three entities, user, category and note. For each one, we have a
CRUD
(Create, Read, Update, Delete), this entities are related, that's why we useSQL
(Structured Query Language; Used to relate tables).To keep everything organized, i used
MVC
(Model View Controller) in the backend,Factory
andObserver
patterns in the frontend (More details about the software architecture will be cited bellow).
The links to access the repositories are:
Β
Β
On the frontend, HTML
, CSS
and JS
are used to build all interfaces. The Serve
library is used to create a static server on Heroku
(heroku only allows you to deploy a repository if it is a server).
On the backend, i'm using Python
as main language (but today i would use Node.js
). Flask
is a framework used to create APIs (Application Programming Interface, are used to create communication points between the frontend and backend in an application).
Heroku
is a hosting service used to "go up" an application (create a domain, ex: https://github.com), so everyone can access it. Cloudinary
is a simple service used to store images. PostgreSQL
is a relational database used to store system and user information.
For the server to identify each user, between various authentication types i chose JWT
(Json Web Token) authentication. The access token allows the main actions, refresh token can create new access token and emailConfirmation token allows and autorizes all email actions.
An organized and architected project makes your code more readble, scalable and maintainable. I "suffered" a lot until understood that i need an achitecture. For these reasons i used the MVC (Model View Controller), factory and observer pattern.
M
The model is an entity representation, responsible for storing business rules and database queries.
V
The view is the client interface, responsible for makes to communication between the user and the model.
C
The controller is an intermediary between the view and the model, responsible for autorizing the view to access the model action.
Β
With factory, we can create a layer (represents an application component) and with observer you can separate these layers.
function createCounter() {
const state = {
currentValue: 0 // When the increment function is called, this value is changed
}
const increment = () => state.currentValue++;
return { increment } // Here stays the public methods (Methods that all layers can access)
}
const counter = createCounter(); // { increment }
counter.increment();
The state stores the layer's global values. Creating layers like this, we can organize what are the private and public values and functions.
function createDisplay() {
const state = {
display: document.querySelector('.display')
}
const setValue = value => {
state.display.innerText = value;
}
return { setValue }
}
function createCounter() {
const state = {
observers: [], // List of observers for this layer
currentValue: 0
}
const subscribe = observerFunction => {
state.observers.push(observerFunction); // Register an observer
}
const notifyAll = counterValue => {
for (const observerFunction of state.observers) {
observerFunction(counterValue);
}
}
const increment = () => {
state.currentValue++;
notifyAll(state.currentValue); // Notify all observers
}
return { subscribe, increment }
}
const counter = createCounter(); // { subscribe, increment }
const display = createDisplay(); // { setValue }
display.setValue(0);
counter.subscribe(display.setValue);
Every time the counter state is updated, all counter observers are notified. So we can decouple/separate the layers, improving code control and maintainability.
Important: It is not always good to use the observer pattern, because this pattern adds a (sometimes unnecessary) complexity that is considered "over engineering". For these reasons, i don't use it on every layer.
All sensitive keys are hidden in the .env
file and all error handling like database connection and user actions are implemented. Other basic security implementations such as database password encryption were also introduced.
In everything we do, there is always a way to improve and this project is no different, here are some improvements i would make if i were to redo it.
-
Rich Text
The rich text is a good notes feature used to edit notes but this feature is limited, because it was created with pure
Javascript
and the only way to make a rich text is using the execCommand method of the document (this method is deprecated). To solve this problem i would add a rich text library, so the rich text would have more functionality and would also improve the user experience. -
Switch to React.js
I would add
React.js
to increase development scalability and productivity. -
Category Filters and Customizations
Maybe it would be interesting to add category filters and more customizations, also improving the user experience.
-
Pagination of Categories and Notes
For improving categories and notes loadings, i would add a pagination of up to 15 items, reducing the amount of traffic on the first load.