An application for serving and managing the website of our alpaca breeding farm 🦙
The following is required:
- the Google Cloud CLI
- a Google Cloud organization
- a Google user account that is
Organization Administrator
- the GraalVM 21 SDK
- the Google Firestore Emulator
- a recent Docker installation that includes
buildx
. - a recent Terraform installation.
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
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.
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.
No. My mother had me tested.
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.
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.
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.
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.