Skip to content

Latest commit

 

History

History
139 lines (95 loc) · 7.26 KB

README.md

File metadata and controls

139 lines (95 loc) · 7.26 KB

Dessine-Moi un Alpaga

GitHub workflow

Google Cloud Run GitHub development deployment GitHub production deployment

Quality Gate Status Maintainability Rating Security Rating Reliability Rating

Technical Debt Bugs Vulnerabilities

Lines of Code Duplicated Lines (%) Coverage

License: GPL v3 Terraform Gradle GrralVM Kotlin Ktor

What is this?

An application for serving and managing the website of our alpaca breeding farm 🦙

Prerequisites

The following is required:

Bootstrapping the Project

This project includes a Terraform configuration that will prompt you for several configuration items and make sure everything is set up for deploying the application to Google Cloud Run from your local box and from GitHub.

$ make infrastructure/bootstrap/plan

Once the plan looks right, apply the changes to bootstrap the infrastructure:

$ make infrastructure/bootstrap/apply

Configuration files will be saved in the ~/.dmua directory.

You are now all set to build using GitHub Actions, or locally:

$ make app/run

Running tests:

$ make app/test

Preparing the Native Build

Compiling a native executable with GraalVM requires some configuration, which can be automatically generated:

$ make app/prepare-native-build

You must then make sure that all relevant code paths are covered by your interactions with the app and all the configuration files in app/src/main/native will be updated accordingly.

Contributing

All changes must take place on the beta branch. Every commit will trigger a semantic pre-release, tag the commit accordingly, publish a GitHub pre-release and deploy it to the development environment.

Once the development environment is in a satisfactory state, create a pull request to the main branch and merge it. This will trigger a semantic release, tag the commit accordingly, publish a GitHub release and deploy it to the production environment.

Isn't this overkill? Are you crazy?

No. My mother had me tested.

Functional Requirements

The main functional requirement behind its design is that it must include an API to CRUD most of the contents of the website at runtime:

  • animals
  • news articles
  • photos
  • factsheets
  • etc.

Non-Functional Requirements

The first non-functional driver behind its design is that it should minimize application startup time and resource usage, so that it can shine when deployed on Google Cloud Run, thus reducing its carbon footprint (and, as a side benefit, its price) as much as possible, in a measurable way.

The second non-functional driver is that I should be having fun working on it 😊

Coming from a JVM background, I opted for Kotlin, compiled into a native binary by GraalVM.

Ktor was the next logical choice, as most of its features can be compiled into native binaries quite easily.

Design Considerations

Hexagonal architecture

The goal is to decouple the domain and application use cases from the underlying technologies, which end up being isolated under the adapters and interfaces packages.

Pretending to be domain-driven would be abusive, as there is no real business logic. We recognize that the domain layer is anemic and live happily with it.

Avoid obese and invasive frameworks and libraries

This project initially used the standard libraries made for interacting with the external services on which it depends (Firestore and SendGrid) and the Koin Dependency Injection library.

Replacing those with a few lines of custom code cut the resulting binary's size in half (from ~120MB to ~60MB).

A nice optimization was also introduced by replacing the XML Logback configuration at runtime by a serialized configuration created at build time. This prevents the whole XML parsing code to be included in the executable.