• modular monolith
  • microservices
  • domain design
  • platform architecture

Modular Monolith or Microservices? Choose the Boundary an iGaming Platform Needs

Modular Monolith or Microservices? Choose the Boundary an iGaming Platform Needs

Compare deployment independence, financial consistency, scaling and operating cost. Use a bet-and-wallet example, an extraction plan and four acceptance tests to make an evidence-based architecture decision.

A casino platform can have separate wallet, game and bonus APIs yet still require one coordinated release and one shared database change. Conversely, a single deployed application can contain well-defined domains that are straightforward to test and maintain. Counting services does not tell you which platform is easier to change or safer to operate.

The useful question is narrower: which boundary would remove a demonstrated constraint, and what new failure states would that boundary introduce? For a CTO, architect or engineering lead, the answer should connect a business problem to a deployable design. This guide follows a stake through that decision, then shows how to choose and test a first extraction. It assumes no particular cloud, framework or traffic threshold.

Separate modularity from deployment independence

A modular monolith is an application deployed as one unit with internal boundaries around capabilities. A microservice is a separately deployed capability with an explicit contract and authority over its own data. Separate repositories or containers alone do not demonstrate that a service can be released without coordinated changes elsewhere.

For a modular platform, give wallet, betting, payments and bonuses named interfaces, permitted dependencies and responsibility for their records. Prevent another module from updating wallet tables directly; a shared transaction can still coordinate work through those interfaces. Enforce the boundary with dependency checks, code review and tests. Otherwise “modular” is merely a description of folders.

For separate services, make those contracts work across a network: callers can time out, versions can overlap and a remote result may be unknown. A service can own data logically while sharing database infrastructure, but shared capacity and failures remain dependencies. Storage ownership and physical isolation are separate decisions. The companion guide to core domains and boundaries develops the ownership model; here, the question is whether moving a boundary out of the process earns its cost.

Follow a stake across the transaction boundary

Consider a hypothetical platform that accepts a stake using its own wallet and bet records. When both records participate in one database transaction, the application can conditionally reserve available funds and create the bet record together. It must still enforce concurrency rules and a stable request identifier. Sharing a database does not automatically prevent two simultaneous requests from spending the same balance. A third-party bet acceptance or payment is outside this local transaction.

Now move the wallet behind a separate service. A proposed flow is: create a durable pending request, reserve funds with its stable operation identifier, record the accepted outcome, then finalize the reservation under the agreed contract. The exact acceptance point depends on the product and provider. Before approving the split, answer what happens if the wallet commits the reservation but its response disappears, or if the caller restarts before recording the next step.

  • Unknown reservation result: recover the existing operation by identifier, or retry under a contract that returns its existing outcome. Bind that identifier to the original request and reject changed parameters. Do not create a new debit merely because the caller saw a timeout.
  • Definite rejection before acceptance: release a confirmed reservation through a recorded, repeatable operation.
  • Acceptance may already have occurred: retain a visible pending case until the outcome is established. A timeout alone is insufficient evidence to release money that may back an accepted bet. Reservation expiry must also respect that unresolved state; an automatic release timer cannot replace outcome recovery.
  • Concurrent requests: the wallet must enforce its spending rules within its own authoritative update; a caller's cached balance cannot authorize a reservation.

These are design requirements for the example, not a universal provider protocol. AWS's saga guidance notes that coordinated local transactions introduce eventual consistency and lack transaction isolation. Compensation needs its own rules; it is not a database rollback across services. If the team cannot explain each intermediate financial state, retain the local boundary while resolving that design.

Identify the constraint that a service would actually remove

Write down the symptom before proposing a service. “The platform is slow” is too broad. A report may compete with wallet writes for database capacity; an image-processing task may consume application CPU; or a provider integration may block a release because every change ships together. These are different constraints.

  • A costly background task: test a separately budgeted worker or read model first. A worker can be independently scaled without splitting every domain into services; moving work to another process is an operational change even if it shares the codebase.
  • A hot financial record: measure lock contention, query plans and write concurrency. A network hop around the same serialized update does not increase the capacity of that update.
  • A release dependency: identify which contract or database change forces coordination. Separating deployments helps only if consumers can continue using a supported contract.
  • A failure spreading from one integration: first bound its concurrency, queue and resource use. A separate process may improve containment, but synchronous dependencies and shared infrastructure can still transmit failure.

Capture a baseline using workflow metrics, logs and traces. Compare the same representative workload before and after the proposed change. Include completed operations, waiting time and recovery effort, rather than only CPU or successful HTTP responses. Extraction is credible when it improves the stated constraint without hiding unfinished work in a queue.

Compare options with evidence, not an architecture score

Use the following questions as a decision worksheet. They deliberately produce no weighted “winner”: an unacceptable financial state cannot be cancelled out by a faster deployment.

  • Boundary stability: do business rules frequently move between the proposed components? Review recent changes and the next known product requirements. Frequent movement favors an internal boundary that is easier to revise.
  • Consistency: which records must change together, and which readers may tolerate delay? Walk through a timeout after each committed step. Keep tightly coordinated updates together unless a complete distributed workflow is justified.
  • Release independence: can the owner ship a compatible change while consumers stay on their current version? Demonstrate this with a contract test and a rehearsal, not a new repository.
  • Scaling or containment: is the constrained resource separable? Use profiling and an outage exercise to show that isolating this component helps the required user journey.
  • Operating responsibility: who owns alerts, upgrades, recovery and contract retirement? An autonomous deployment still needs a team able to support it after the original implementer leaves.
  • Total cost: estimate build, migration and parallel operation costs, then recurring infrastructure, telemetry, security maintenance, incident handling and reconciliation. Compare those with the current constraint's measured cost and the simpler alternative.

Martin Fowler's Monolith First makes an experience-based case for starting together when boundaries are uncertain. It also discusses starting with coarse services. Treat this as design reasoning, not a universal rule; choose from the capabilities and constraints your team can demonstrate.

Test whether the services can change and fail independently

Investigate three warning signs of coupling: a consumer must deploy whenever its dependency changes; several services can write the same business record without one authority; and one unavailable service prevents an otherwise unrelated journey from completing. None is fixed by renaming components.

Rehearse a compatible release with old and new consumers present. Introduce a new field or behavior without requiring consumers to adopt it immediately. Migrate consumers and observe use of the older contract before requiring the new behavior or retiring old support. Apply the same sequence to schema changes. Keep cross-service writes behind the owning contract; database permissions should support the intended authority. A shared read model may help reporting, but it must not become another financial writer.

Then stop a dependency. Decide which operations can wait durably, which can use a clearly limited stale view and which must stop because an authoritative decision is unavailable. Reporting may tolerate an agreed delay; a cached report must not silently become permission to place a bet or withdraw funds. Bound waiting work and test what happens when that bound is reached.

Fowler's Microservice Prerequisites highlights deployment automation, monitoring and joint development/operations responsibility. Treat them as capabilities to demonstrate before increasing the service count. They are useful for a monolith too. Review a real incident path: who sees it, what identifies the affected operations and who can recover them safely?

Extract one capability without creating competing writers

Suppose reporting is the candidate because analytical queries interfere with transaction processing. First define a report's source records, acceptable freshness and reconciliation method. Confirm that this reporting capability is not making eligibility or financial decisions. Build its read model without changing the authoritative writer. Measure whether the new queries actually stop competing for the constrained resource; a replica or a separate store may help, but copying the same expensive work into another shared bottleneck may not.

When publishing committed changes, AWS's transactional outbox guidance describes saving the record and outgoing event within one transaction, then publishing separately. It also warns about duplicate delivery. This closes a local database/message gap; it does not make all consumer effects atomic or remove delivery delays.

For the pilot, preserve identifiers and the ordering needed for each record. Have the consumer record message processing and its local update together where possible. Specify how it rebuilds, catches up and detects missing changes. Budget the outbox and downstream backlog, and decide what happens if delivery stays unavailable long enough to exhaust that budget; asynchronous work still consumes resources. Compare the old and new reports at the same data boundary; otherwise ordinary replication lag can look like a migration error. Stop shadow processing from making external payments or other duplicate side effects.

If a later extraction moves write authority, create a separate cutover plan: drain or account for in-flight work, route commands to one designated owner, disable old write paths and reconcile at the handover boundary. Retain a recovery path that includes writes made after cutover. Returning traffic to an old database is unsafe if those changes exist only in the new one. Use live data migration planning for the data controls and incremental modernization for retiring old paths.

Record a bounded decision and prove it in a pilot

Finish with a decision someone can challenge. Record the affected capability, current constraint, chosen option, rejected simpler alternative, authoritative records, owner, added failure states, migration scope and evidence that would trigger a review. Include costs and assumptions whose uncertainty could change the choice.

For the hypothetical reporting pilot, the decision might be to keep wallet and bet writes together while moving reporting reads to a separate worker and store. Its acceptance criteria are less interference with transaction processing, report freshness within an agreed limit, bounded backlog and reproducible reconciliation. Define the workload, measurement interval, limit and reviewer before running it. This is a proposed experiment, not a claim about a client or a guaranteed improvement.

A successful pilot justifies that boundary. It does not justify separating the wallet next, or predict an optimal service count. If compatible releases, recovery or ownership fail the checks below, keep improving the boundary before expanding the distribution.

For a wider review, iGaming platform architecture covers commissioning a design the team can implement, while platform modernization addresses the transition from a platform in operation. Use those alongside the migration and observability guides linked above. For the chosen boundary, require these four demonstrations before calling the extraction complete:

  • Compatible release: deploy the candidate while an existing consumer continues to work. Exercise a mixed-version period and show how the old contract will be retired.
  • Contained outage: stop the candidate and test the affected and unaffected journeys. Demonstrate bounded waiting work and the agreed behavior when capacity is exhausted; no stale read may authorize a financial action.
  • Interrupted operation: restart after a committed update but before its acknowledgement. Repeat the same request or event and recover one recorded outcome without duplicate financial effects. Check pending-case visibility and responsibility.
  • Recoverable handover: reconcile both sides at the same data boundary and rehearse recovery with in-flight work and post-cutover changes. Prove which writer owns each command throughout the transition.
Can a modular monolith handle high traffic?

It can run on multiple application instances if its state and concurrency model support that arrangement. The actual limit may be a database, one contested record or an external provider. Measure the limiting resource under a representative workload; neither the word monolith nor a service count supplies a capacity guarantee.

How many developers or requests justify microservices?

There is no universal threshold. Use evidence of a stable capability, a constraint that independent deployment or scaling would remove, a complete consistency design and an owner able to operate it. Team size and traffic are inputs to that review, not a substitute for it.

Must each service have a separate physical database?

A service needs clear authority over its data and a contract for other components to access it. Physical separation is an additional decision about capacity, security and failure containment. Sharing a database host does not require sharing write authority, but it preserves infrastructure dependencies that must be acknowledged.

What if the split still requires a coordinated release?

Identify the incompatible contract, shared write path or cross-service schema dependency that forces coordination. Fix that dependency and rehearse old and new consumers together. If independent operation provides no worthwhile benefit, keeping the capability as a module may be the clearer and less costly choice.

Review one architecture decision

Bring a failing workflow, a release dependency or a measured bottleneck, together with its current owner and recovery process. SPINDO.TECH can review the proposed boundary and define the evidence needed to keep the module, separate a worker or extract a service.

We use cookies to ensure the security and proper functioning of our website. With your consent, we also use non-essential cookies for analytics and advertising purposes. You can accept or reject the use of non-essential cookies. You can change your preferences at any time. Learn more in our Cookie Policy.