The Software Development Process

A practical, educational guide from idea to GA

Introduction

High-quality software delivered fast is not an accident; it’s the result of a repeatable process that starts with the business domain, flows through clear boundaries and contracts, and ships in vertical slices with built-in quality. This article lays out that process end to end—what to do, why it matters, and how to keep it lean.

The Lifecycle at a Glance

  1. Discover & Frame the Domain
  2. Boundaries & Context Map
  3. Capabilities & Use Cases
  4. Domain Model (Entities/VO/Policies/Events)
  5. Application Layer (Ports/Use Cases)
  6. Adapters (HTTP/DB/Messaging)
  7. Vertical Slice Build
  8. Quality (Tests/Obs/SLOs)
  9. Security & Data
  10. Release (Flags/Canary)
  11. Docs & Governance
  12. Operate & Evolve

1) Discover & Frame the Domain

Goal: Align the team’s language and outcomes with the business reality.

Template — Domain Brief (≤1 page)

Domain: <name>
Problem/Outcome: <who is helped + measurable change>
Ubiquitous Language: <5–10 key terms with crisp definitions>
Bounded Contexts (initial guess): <1–3>
Key Business Events: <3–7 named in past tense>
Non-Goals: <out-of-scope items>

2) Boundaries & Context Map

Goal: Prevent one giant, inconsistent model.

Deliverables: a simple Context Map diagram and a list of event/API contracts.


3) Capabilities & Use Cases

Goal: Turn strategy into executable units.

Template — Use Case

Title:
Actor:
Primary Flow: 1) ... 2) ... 3) ...
Business Rules: - ...
Errors/Exceptions: - ...
Emitted Events: - ...
DoD: flag + logs/metric/trace + contract tests + rollback plan

4) Domain Model (Entities, Value Objects, Policies, Events)

Goal: Encode business rules where they belong.

Micro-Example (TypeScript)

export class Money {
  constructor(readonly value: number, readonly currency: "USD" | "BRL") {
    if (value < 0) throw new Error("Negative amount");
  }
}

export class InvoiceIssued {
  readonly type = "InvoiceIssued";
  constructor(public id: string, public total: Money) {}
}

export class Invoice {
  constructor(
    private status: "DRAFT" | "ISSUED" | "PAID",
    private total: Money
  ) {}
  issue() {
    if (this.status !== "DRAFT") throw new Error("Only DRAFT can be issued");
    this.status = "ISSUED";
    return new InvoiceIssued(crypto.randomUUID(), this.total);
  }
}

5) Application Layer (Ports & Use Cases)

Goal: Orchestrate domain logic; no infrastructure here.

export interface InvoiceRepo {
  save(inv: Invoice): Promise<void>;
  findById(id: string): Promise<Invoice | null>;
}
export interface EventBus {
  publish(event: object): Promise<void>;
}

export class IssueInvoice {
  constructor(private repo: InvoiceRepo, private bus: EventBus) {}
  async exec(input: { amount: number; currency: "USD" | "BRL" }) {
    const inv = new Invoice("DRAFT", new Money(input.amount, input.currency));
    const evt = inv.issue();
    await this.repo.save(inv);
    await this.bus.publish(evt);
    return { status: "ISSUED" };
  }
}

6) Adapters (Infrastructure at the Edges)

Goal: Connect to the outside world, keeping the domain pure.


7) Build the First Vertical Slice

Goal: Deliver one end-to-end path with quality.

Minimal folder layout

domains/<context>/
  domain/           # entities, VOs, policies, events
  application/      # ports, use cases, DTOs
  tests/            # unit + contract
apps/api/
  adapters/http/    # routes/controllers
  adapters/persistence/
  adapters/messaging/
infra/
  feature-flags/
  observability/dashboards/

8) Quality Gates (Tests, Observability, SLOs)

Goal: Make quality automatic.

Template — DoD (paste in PR)

- [ ] Feature flag in place and off by default
- [ ] Unit + contract tests passing in CI
- [ ] Logs, metric, and trace present
- [ ] Runbook attached; rollback tested
- [ ] SLOs defined and dashboard linked

9) Security, Privacy, and Threat Modeling

Goal: “Secure by default” from day one.


10) Data Management & Migrations

Goal: Keep data safe and evolvable.


11) Release Strategy (Flags, Rings, Canary)

Goal: Reversible releases with fast feedback.


12) Docs & Governance (Lightweight)

Goal: Decisions are discoverable; onboarding is fast.

Template — ADR (≤1 page)

Title:
Context:
Decision:
Alternatives considered:
Consequences (positive/negative):
Date & Owners:

13) Operate & Evolve

Goal: Learn continuously and keep change cheap.


Common Pitfalls & Antidotes


48-Hour Starter Plan (Reality-Proof)

Day 1: Domain Brief + Context Map (90m), pick one capability, write Use Case (60m), model entities/VO/policy (2h).
Day 2: Implement use case + ports + adapters (3–4h), unit & contract tests (2h), logs/metric/trace + flag + runbook + SLO (2h), canary deploy (1h).


Conclusion

Starting from the domain grounds your system in business reality; moving through bounded contexts, contracts, and vertical slices keeps you fast and safe. The non-negotiables—tests, observability, SLOs, security, feature flags—turn quality into a property of the process, not heroics. Keep artifacts short, automate the checks, and iterate in small, meaningful steps. That’s how you ship high-quality software—quickly and repeatedly.