← Better Programmer course
05
Intermediate to Advanced
3 hours 15 minutes

Technical Excellence and Software Delivery

Build quality from clear contracts, readable code, layered tests, review, automation, and production feedback.

Learning outcome

You will be able to choose maintainable boundaries, design a balanced test strategy, review changes effectively, and connect CI/CD to real production health.

Jump to a chapter
  1. 1. Contracts and Interfaces
  2. 2. Readable Code and Local Reasoning
  3. 3. Abstraction and Coupling
  4. 4. Unit Tests: Fast Feedback on Small Rules
  5. 5. Integration Tests: Verify Real Boundaries
  6. 6. End-to-End Tests: Protect Critical User Journeys
  7. 7. Version Control and Code Review
  8. 8. CI/CD and Observability: Build a Safe Feedback Loop
  9. Applied exercise
  10. Knowledge check

Chapter 1

Contracts and Interfaces

A contract describes what one part of a system promises to another.

Contracts include inputs, outputs, error shapes, side effects, and compatibility rules. An interface can be a TypeScript type, an HTTP schema, a function signature, or a team agreement. Its value is a stable boundary, not the syntax used to declare it.

A useful contract states required and optional fields, validates data at runtime where trust changes, and makes failures explicit. Changes should be additive when possible. Removing or changing meaning needs versioning or a coordinated migration.

For an order API, define currency, amount units, status values, authentication, and error codes before building screens. Frontend, backend, tests, and monitoring can then share the same behavior.

Key insight

A clear contract reduces coordination cost and makes change safer.

How to apply this

  • Validate data at system boundaries.
  • Document errors and side effects, not only success fields.
  • Plan compatibility before changing an existing contract.
Scenario — A field changes meaning

Situation

Backend changes price from cents to decimal currency without changing the schema.

Decision

Create an explicit money contract, version the change, and migrate consumers with contract tests.

Chapter 2

Readable Code and Local Reasoning

Readable code lets a developer understand one piece without loading the whole system into memory.

Good names expose intent, functions keep one coherent responsibility, and control flow makes important cases visible. Comments explain why a surprising decision exists; they should not translate unclear code line by line.

Local reasoning improves when dependencies are passed explicitly and data changes happen in predictable places. Small functions are helpful only when their names and boundaries clarify the flow. Splitting every line into a function can make navigation harder.

A price calculation should name subtotal, discount, tax, and total. It should make rounding and currency rules visible instead of hiding them in generic helpers.

Key insight

Optimize code for the next correct change, not for the fewest lines.

How to apply this

  • Name domain ideas instead of implementation details.
  • Keep error and edge-case paths visible.
  • Refactor when a concrete change is difficult, not only for style.
Scenario — Clever validation chain

Situation

A compressed expression handles six rules but nobody can identify which rule failed.

Decision

Use named validation steps and return structured errors that tests and UI can understand.

Chapter 3

Abstraction and Coupling

An abstraction hides details behind a smaller idea; coupling measures how strongly parts depend on each other.

A good abstraction groups behavior that changes for the same reason. It exposes a small contract and hides details callers should not control. A poor abstraction combines unrelated cases or leaks its internal storage, framework, or timing assumptions.

Coupling is not always bad. Stable, explicit coupling to a domain contract is often better than a generic layer that hides behavior. Watch for change amplification: if one rule change requires edits across many files, the current boundaries may be wrong.

A payment adapter can hide provider-specific requests while exposing charge, refund, and status operations. It should not pretend all providers have identical behavior when they do not.

Key insight

Abstract around proven change boundaries, not imagined reuse.

How to apply this

  • Wait for repeated behavior and change patterns before extracting.
  • Keep domain rules separate from vendor or framework details.
  • Measure an abstraction by whether it makes the next change safer.
Scenario — Universal repository

Situation

A generic data layer hides transactions and makes efficient queries impossible.

Decision

Use focused data functions that expose domain intent and allow required database behavior.

Chapter 4

Unit Tests: Fast Feedback on Small Rules

A unit test checks a small behavior with controlled inputs and dependencies.

Unit tests are best for pure calculations, state transitions, parsing, and domain rules. They run quickly and point close to a defect. A unit is a behavior boundary, not necessarily one function or class.

Avoid mocking every internal call. Tests tied to implementation order break during harmless refactors. Assert inputs and observable outputs, and use simple fakes only for dependencies that would make the test slow or uncertain.

A booking-price test can cover weekday rates, peak periods, discounts, and rounding without a database or browser. These cases document the rule and run on every edit.

Key insight

Use unit tests where logic has many cases and can be isolated meaningfully.

How to apply this

  • Test behavior and edge cases, not private implementation.
  • Keep fixtures small and named for the rule they prove.
  • Prefer deterministic clocks, IDs, and random values.
Scenario — Discount regression

Situation

A discount rule works for normal orders but produces a negative total at a boundary.

Decision

Add table-driven unit cases for limits and make the failing business rule explicit.

Chapter 5

Integration Tests: Verify Real Boundaries

An integration test checks that multiple real components work together across an important boundary.

Typical boundaries include application code with a database, a service with a message broker, or serialization across an API adapter. These tests find schema, configuration, transaction, and mapping problems that isolated unit tests cannot see.

Keep the environment controlled and reset data between tests. Test a small number of high-value paths instead of copying every unit case. Use real dependencies where their behavior matters; use a contract-faithful fake only when the external system cannot be controlled.

An order repository integration test creates an order, verifies line items and transaction behavior, then confirms a duplicate intent is rejected by the actual unique constraint.

Key insight

Integration tests prove that important boundaries work as configured, not merely as mocked.

How to apply this

  • Use real storage for queries and transaction behavior.
  • Isolate test data and make cleanup reliable.
  • Cover boundary failures as well as the happy path.
Scenario — Mocked transaction passes

Situation

Unit tests say an order and payment record save together, but production commits only one.

Decision

Add an integration test against the real database transaction and simulate a failure between writes.

Chapter 6

End-to-End Tests: Protect Critical User Journeys

An end-to-end test drives the system through the same public interfaces a user uses.

E2E tests provide confidence that routing, UI, APIs, storage, and authentication connect correctly. They are slower and more fragile than smaller tests, so reserve them for critical journeys and high-risk integrations.

Stability comes from controlled test data, accessible selectors, explicit waiting for user-visible states, and ownership of failures. Do not use arbitrary sleeps. Keep detailed logic coverage in unit and integration tests so the E2E suite remains small.

A checkout E2E test signs in, adds one known product, pays through a test provider, and confirms one order appears. It proves wiring without testing every discount permutation.

Key insight

Use a thin E2E layer to protect outcomes, not to replace lower-level tests.

How to apply this

  • Choose journeys based on business and operational risk.
  • Select elements by role and label where possible.
  • Remove flaky tests only after finding what uncertainty they expose.
Scenario — Flaky login flow

Situation

The test sleeps two seconds and sometimes clicks before the page is ready.

Decision

Wait for the accessible dashboard heading or a known network result and control the test account state.

Chapter 7

Version Control and Code Review

Version control records changes; code review creates a shared decision point before those changes enter the main line.

Small, coherent commits make intent visible and rollback safer. A pull request should explain the problem, approach, risk, and verification. Reviewers should check correctness, maintainability, security, user impact, and operational behavior—not rewrite code to match personal taste.

Fast review depends on scope. Separate mechanical refactors from behavior changes, include screenshots or traces when useful, and respond to comments with reasoning. Teams should automate formatting and basic checks so human attention stays on judgment.

A risky checkout change can be split into contract, backend behavior, UI, and rollout commits while staying one understandable product slice.

Key insight

Review is a system for risk reduction and knowledge sharing, not a gate for authority.

How to apply this

  • Keep each change focused enough to review in one sitting.
  • State risks and evidence in the pull request description.
  • Distinguish required corrections from optional suggestions.
Scenario — Week-long pull request

Situation

A large mixed change receives shallow review and is hard to roll back.

Decision

Slice by behavior, isolate refactors, and deliver smaller reviewable increments behind a safe flag.

Chapter 8

CI/CD and Observability: Build a Safe Feedback Loop

Continuous integration checks every change; continuous delivery makes a verified change ready for safe release. Observability shows what the released system is doing.

CI should run deterministic formatting, types, tests, security checks, and builds. CD promotes one known artifact through environments with clear approvals or automation. A deployment is not successful because the command finished; production signals must show that users and dependencies remain healthy.

Observability uses logs for events, metrics for trends and thresholds, and traces for request paths. Connect deploy markers to error rate, latency, saturation, and business outcomes. Use staged rollout and rollback when risk is meaningful.

For a new search API, CI verifies contracts and tests, CD deploys to a small traffic group, and dashboards compare latency, errors, and successful searches before expansion.

Key insight

Delivery is complete only when verified code reaches users safely and its behavior is visible.

How to apply this

  • Build once and promote the same artifact.
  • Define release health signals before deployment.
  • Practice rollback and record deployment markers in telemetry.
Scenario — Green pipeline, broken production

Situation

All tests pass, but a configuration error causes live requests to fail.

Decision

Use a staged rollout, production smoke checks, deployment markers, and automatic rollback thresholds.

Applied exercise

Create a delivery safety case for one feature

Choose a feature in a real project and prove how it can move from contract to production with evidence at each boundary.

  1. 01Write the public contract, error behavior, and compatibility plan.
  2. 02Identify one readability or coupling risk and propose the smallest refactor.
  3. 03Create a test matrix across unit, integration, and E2E layers.
  4. 04Plan commits and a review description with risks and evidence.
  5. 05Define CI gates, rollout stages, dashboards, and rollback thresholds.

Deliverable

A concise delivery plan containing the contract, code-boundary sketch, test matrix, review plan, and production verification checklist.

Knowledge check

Check your understanding before finishing

Answer from the reasoning and trade-offs, not keyword memory. After submitting, review the explanation for every question.

Q1What makes a contract useful?
Q2When is an abstraction most justified?
Q3Which test best verifies a real database transaction?
Q4Why keep the E2E suite small?
Q5When is a deployment complete?