← All engineering notes
ARCHITECTURE·7 min read

Why We Reach for Modular Monoliths in African Markets

Microservices are the default advice. For infrastructure-constrained markets, a disciplined modular monolith often ships faster and runs cheaper — without giving up module boundaries.

Most architecture guidance assumes cheap, elastic cloud infrastructure and a platform team to run a service mesh. Building for markets where a single well-specified server has to do the job changes the calculus — every extra moving part is something that can fail without anyone around to page.

On MakersMark we split the backend into modules — payments, content, live streaming, notifications — each with its own Postgres schema and a narrow interface contract. Modules talk to each other in-process through those interfaces, not HTTP, so we get the isolation microservices promise without the latency, retries, and partial-failure modes they introduce.

payments/PaymentsModule.kt
interface PaymentsModule {
    suspend fun charge(request: ChargeRequest): ChargeResult
    suspend fun refund(paymentId: PaymentId): RefundResult
}

class ReleaseService(private val payments: PaymentsModule) {
    suspend fun payoutOnRelease(creatorId: CreatorId, amount: Money) {
        payments.charge(ChargeRequest(creatorId, amount))
    }
}

Because the module boundaries are enforced in code, not just convention, extracting a module into its own service later is a mechanical change, not a rewrite. We treat that as an option to keep open, not a milestone to chase before it's earned.

Start by drawing module boundaries around your actual bounded contexts — payments, content, notifications — not around technical layers. Define one narrow interface per module, and enforce the boundary with the compiler: Kotlin's "internal" visibility, or a build-time check like ArchUnit, not just a note in a wiki.

Start with the deployment topology the business actually needs today. A modular monolith with real interface discipline gets you most of the benefits microservices are sold on, for a fraction of the operational cost.