At the beginning of this year, I wanted to challenge myself by building a blog application with a microservices architecture using the technologies that I knew best. The intended purpose of the blog was to share what I’ve learned over the past few years and as a portfolio. In this article, I will give an overview of the architecture and technologies used when constructing this blog, the challenges I faced along the way, the lessons learned, how I feel about the product in its current state, and new features that I hope to implement in the near future.
As previously mentioned, I chose to go with a microservice-based architecture with each service having a very specific role. There are four main components in this system: the frontend UI which was written in React with CSS support from Tailwindcss and state management handled by Redux, a content management layer written in Kotlin with Spring Boot, a data abstraction layer written in Python using FastAPI and SQLAlchemy, and finally a Postgres database to persist the blogs. For version control, I used Git and used Github to host the repositories. The frontend is hosted on Vercel, as I already had Github integration setup with and a domain purchased through them, and the backend was hosted on Google Cloud Platform using a Compute Engine instance running Ubuntu 20.04.
To structure the operation of building the blog, I practiced a solo adaption of Scrum where I played both the developer and product owner roles. I wrote user stories and prioritized them based on how critical they were to reaching MVP. I created a Jira account so I could manage my development cycle and track the progress of each story, organize the stories into epics, and tried to work in one-week sprints, though I wasn’t always successful because of other obligations.
The first thing I wanted to do was create a “walking skeleton,” a basic connection between all of the components of the system, but in order to do that, I need to make some design decisions on how the blog data would be structured and stored. I knew that a blog would contain an id, title, a timestamp for creation, and the blog content. Initially, I thought about just storing HTML in the database for the content, but that didn’t seem very safe. Instead, I decided to have two tables in the database, one table for the blog, which contained everything other than the content, and a content table. The content table had a blogId as the foreign key and a number representing the order that the piece of content should be rendered, the type of content e.g. “p” for paragraph, and the value of the content. The blogId and the order number created the primary key for the content. This gave me some flexibility in adding new types of content in the future and would make it easy to render the content properly.
After those decisions had been made, I filled a local database with some fake data and started constructing the other services. I started with the React application where I created a home view component that would display blog cards and a blog view where the blog content would be rendered for each blog, which used React-Router to set up the blog pages. I then set up the Spring Boot application that would make a GET Request to the FastAPI data abstraction layer which would retrieve them from the database. After I wired everything up and tested the application was working as expected, I added a POST and a DELETE endpoint. I also created a bash script that went through all of the steps necessary to start the backend of the application to automate its deployment (Vercel automated the frontend deployment). At this point, felt confident that I would be able to quickly deploy the application to production.
This is where things got a little tricky, however. My Vercel React application was not able to retrieve the data from GCP for two reasons. The first was because of CORS as the domain I was using in GCP was not the same. To resolve this problem, I just had to add my primary domain to the accepted origins allowed by my Spring Boot application, however, this did not fully solve the problem. Vercel requires that the HTTPS be used by default, which is definitely a good thing for security but was bad news for my HTTP content management system. I first tried creating my own certificate, but that wasn’t allowed either. In the end, I used GCPs Load Balancer to create an HTTPS abstraction of the content manager and allowed cross-origin requests from my frontend domain which finally allowed the two systems to communicate properly.
To be entirely honest, I think I am going to make quite a few changes to this blog over the next few months. There are three areas that I am not satisfied with: the frontend, the data abstraction layer, and cross-domain communication. The frontend, being a CRA (Create React App) application, does not have very good SEO and integrates poorly with my CSS framework of choice, Tailwind. I am considering switching to Next.js, which along with solving these problems will allow me to use Server Side Rendering for each blog. The data abstraction layer is somewhat unnecessary. I built it primarily so that I could use FastApi, which I do like overall, but I think I would prefer to use JPAs in Spring Boot to interact with the database. I also didn’t realize that I could use the domain that I have with Vercel within GCP for the backend, which would eliminate the need to worry about cross-origin communication.
In the coming months, as I am making these improvements to the software system, I will also be adding new features. I plan to add the ability for users to contact me, learn more about me and what I’m passionate about, an admin portal so I can create and manage blogs more effectively, and have the ability to filter blog posts by type, e.g. a button for Kotlin development would only show blogs about Kotlin. As I start working on other software projects, I would also like to add a way to share those projects with others.