Skip to main content
← Back to articles

The BMAD Method: Structuring Software Projects

10 min read

Why a Method?

After more than fifteen years delivering software projects — from portfolio sites to custom CRMs — I've observed a recurring pattern: projects rarely fail for technical reasons. They fail because development begins before the business problem is clearly defined. The BMAD method (Business → Model → Architecture → Development) enforces a disciplined progression that ensures each phase rests on the solid foundations of the previous one.

Phase B: Business — Understanding the Real Problem

Before writing a single line of code, you must understand the why. Who are the users? What business processes must the software support? What are the regulatory, budgetary, and timeline constraints?

In practice, this phase produces three deliverables:

  • Business Requirements Document (BRD): objectives, KPIs, constraints
  • Prioritized User Stories: with verifiable acceptance criteria
  • Risk Matrix: technical, business, organizational
# Structured User Story example
story: US-042
role: "Sales Manager"
action: "Export qualified leads from last quarter as CSV"
benefit: "Feed Power BI reporting without technical intervention"
acceptance_criteria:
  - "File contains columns: name, email, score, qualification_date"
  - "Leads with score < 50 are excluded"
  - "Export completes in under 5 seconds for 10,000 leads"
priority: must_have
sprint: 3

This initial rigor prevents the "we'll figure it out as we go" syndrome that turns projects into death marches.

Phase M: Model — Structuring Data and Flows

Once the business is understood, we model. Entities, their relationships, data flows, possible states. This is where entity-relationship diagrams, sequence diagrams, and state machines prove their worth.

// Lead modeling with explicit states
final class Lead
{
    public function __construct(
        public readonly int $id,
        public readonly string $name,
        public readonly string $email,
        private LeadStatus $status = LeadStatus::New,
        private int $score = 0,
        private readonly DateTimeImmutable $createdAt = new DateTimeImmutable(),
    ) {}

    public function qualify(int $score): void
    {
        if ($score < 0 || $score > 100) {
            throw new DomainException('Score must be between 0 and 100');
        }
        $this->score = $score;
        $this->status = $score >= 50
            ? LeadStatus::Qualified
            : LeadStatus::Disqualified;
    }

    public function canBeContacted(): bool
    {
        return $this->status === LeadStatus::Qualified
            && $this->score >= 70;
    }
}

enum LeadStatus: string
{
    case New = 'new';
    case Qualified = 'qualified';
    case Disqualified = 'disqualified';
    case Converted = 'converted';
}

The model becomes the contract between the technical team and the business. If the model is wrong, everything that follows will be wrong too.

Phase A: Architecture — The Structural Decisions

Architecture answers the "how" questions without diving into implementation. Tech stack selection, application patterns, deployment strategy, network topology. This is where you decide between a modular monolith and microservices, between an ORM and native SQL, between Kubernetes and a simple VPS.

An Architecture Decision Record (ADR) documents each significant choice:

# ADR-003: Caching Strategy for Product Catalog

## Context
The catalog contains 50,000 references with daily updates.
Catalog pages represent 70% of traffic.

## Decision
HTTP cache (Varnish) with tag-based invalidation.
Application cache (Redis) for aggregations (filters, counters).
No MySQL query cache (invalidation too complex).

## Consequences
+ Catalog TTFB < 100ms (vs 800ms without cache)
+ Horizontal scalability via additional Varnish nodes
- Invalidation complexity during catalog imports
- Redis infrastructure dependency (monitoring required)

Phase D: Development — Execute with Discipline

Only in Phase D do we write code. And because the three previous phases were rigorously executed, development flows smoothly: User Stories are clear, the model is validated, the architecture is documented.

In Phase D, the following practices are non-negotiable:

  • Tests first: each User Story has acceptance tests before implementation
  • CI/CD from day 1: automated pipeline with linting, tests, static analysis
  • Systematic code review: every merge request is reviewed by at least one peer
  • Frequent deployments: continuous delivery reduces risk per deployment
# Minimalist but effective CI/CD pipeline
stages:
  - lint
  - test
  - security
  - deploy

php-stan:
  stage: lint
  script:
    - vendor/bin/phpstan analyse src --level=max

phpunit:
  stage: test
  script:
    - vendor/bin/phpunit --coverage-text --min=80

dependency-check:
  stage: security
  script:
    - composer audit
    - vendor/bin/psalm --taint-analysis

BMAD in Practice: Lessons Learned

On my latest CRM project (12 modules, 18 months of development), the BMAD method enabled on-time delivery with a production bug rate below 2 per sprint. The Business phase lasted 6 weeks — an investment that prevented months of later corrections. The ADRs served as reference throughout the project, avoiding recurring debates over decisions already made.

Conclusion

The BMAD method is not a revolutionary invention. It is the formalization of proven practices: understand before modeling, model before architecting, architect before coding. Its strength lies in its discipline: each phase has its deliverables, exit criteria, and validations. In an environment where the pressure to "code first" is constant, BMAD provides a framework to resist that temptation and deliver software that truly solves the problem at hand.