# Architectural Patterns Overview — Design Patterns

Source: https://www.skillbyai.com/en/design-patterns/a-architecture

> MVC, repository, unit of work and a pointer to CQRS.

## Patterns at a larger scale

Some patterns organise whole applications rather than a few classes. **MVC** (Model-View-Controller) separates data and rules (model), presentation (view) and input handling (controller); variants include MVP and MVVM. The **Repository** pattern (from Martin Fowler's *Patterns of Enterprise Application Architecture* and Domain-Driven Design) gives a collection-like interface for loading and saving domain objects, hiding SQL or ORM details from business logic. **Unit of Work** tracks changes made during a business operation and commits them together, usually in one transaction; many ORMs implement it for you (for example a session or context object). **CQRS** (Command Query Responsibility Segregation) uses separate models for writes and reads; it can help with complex domains or very different read and write loads, but adds significant complexity and is not a default choice.

## From catalogue to judgement

Patterns at the architecture level, the smells that signal misuse, and how to talk about patterns.

![Four ideas: architectural patterns, anti-patterns, interviews and reviews, a final checklist.](assets/figures/design-patterns/section-8-map.svg) — Figure 8.1 — Architecture, smells, communication and review.

## Repository and unit of work

Business logic talks to interfaces; one transaction commits the changes.

```typescript
interface AccountRepository {
  findById(id: string): Promise<Account | null>;
  save(account: Account): Promise<void>;
}

interface UnitOfWork {
  accounts: AccountRepository;
  ledger: LedgerRepository;
  commit(): Promise<void>;
  rollback(): Promise<void>;
}

async function transferFunds(uowFactory: () => Promise<UnitOfWork>, fromId: string, toId: string, cents: number) {
  const uow = await uowFactory();          // e.g. begins a database transaction
  try {
    const from = await uow.accounts.findById(fromId);
    const to = await uow.accounts.findById(toId);
    if (!from || !to) throw new Error('Account not found');
    from.withdraw(cents);                   // domain rules live on the model
    to.deposit(cents);
    await uow.accounts.save(from);
    await uow.accounts.save(to);
    await uow.ledger.record({ fromId, toId, cents });
    await uow.commit();                     // all or nothing
  } catch (err) {
    await uow.rollback();
    throw err;
  }
}
```

## Do not wrap an ORM twice

If your ORM already provides a repository-like API and a unit of work, a generic repository layer on top often adds code without adding value. Introduce one when you need to hide persistence from domain logic or test without a database.

**Quiz:** What does the Unit of Work pattern do?

- [ ] Separates read and write databases
- [ ] Renders HTML views
- [ ] Ensures only one database connection exists
- [x] Tracks changes in a business operation and commits them together

*Answer:* Tracks changes in a business operation and commits them together. It groups changes into one atomic commit.
