Пређи на главни садржај

Engineering Philosophy

When I started Borrowd, I wanted to build software that is easy to reason about, simple to operate, and built to last. Having spent years working with complex enterprise stacks, I formed a set of core values that guide every design choice in this repository.


My Five Pillars​

1. True FOSS Commitment​

I build exclusively with open-source tools: PostgreSQL, PostGIS, Keycloak, MinIO, Ktor, and React.

Why: Proprietary cloud services and "open core" tools add vendor lock-in and unpredictable pricing models as usage scales. By sticking to standard open-source protocols, I maintain total freedom to run Borrowd on any server, cloud provider, or local machine.

2. Production-Ready from Day One​

I don't write "throwaway prototype code." From my first commit, I set up real database pooling, migration management, security contracts, and automated GitOps deployment pipelines.

Why: "Temporary hacks" almost always turn into permanent technical debt. Treating production constraints as first-class requirements from the start saves massive refactoring pain down the road.

3. Scale-Ready Architecture​

I chose non-blocking R2DBC persistence, PostGIS spatial indexing, and decoupled object storage right from the beginning.

Why: Neighborhood item search is naturally location-aware and high-concurrency. Using a reactive spatial stack ensures the backend handles thousands of concurrent location queries without thread starvation or high memory usage.

4. Maintainability over Framework Magic​

I choose explicit Kotlin coroutines and constructor dependency injection over heavy magic frameworks.

Why: Magic framework features — like heavy reflection, hidden proxy classes, and annotation-driven dependency wiring — make execution flows opaque. I want to trace any request from the HTTP route down to the SQL query instantly by clicking through explicit method calls.

5. Package-First Naming​

Standard Kotlin and Java conventions often repeat package context inside type names, producing verbose names like items.domain.service.ItemsDomainService. I use Package-First Naming across both backend and frontend code to keep names terse and contextual.

Why: Package paths carry architectural context. Inside items.domain, the service class is named simply Service. Domain ports are named after the capability (photos.domain.Storage), while concrete infrastructure adapters are named after the technology (photos.storage.Minio). This enforces clean contracts where feature domain packages never import HTTP models or infrastructure details.