Joining the Backend Team

Definition of Done

LuettavaEsikatselu

Katselet ilmaista esikatseluoppituntia.

So far, we have:

  • understood the Product requirement
  • written User Stories and Acceptance Criteria
  • established the engineering context

Now we need to answer an important question:

When is an engineering task actually complete?

Is it complete when:

the code has been written?

Or when:

it runs on the developer's machine?

Or when:

the tests pass?

Or when:

the Pull Request is merged?

Or only when:

the change is running successfully in production?

In a real engineering team, the word done needs a shared meaning.

In this lesson, we will establish a Definition of Done, commonly shortened to DoD.

This will act as a shared quality bar throughout the course project.


Why “Done” Is Ambiguous

Imagine an engineer says:

BACKEND-104 is done.

What exactly does that mean?

Possibility:

I finished writing the code.

Or:

The code compiles.

Or:

I manually tested the happy path.

Or:

The Pull Request is open.

Or:

The Pull Request has been merged.

Or:

The change has been deployed successfully.

These are all different states.

If every engineer uses a different interpretation of done, planning and delivery become unreliable.


What Is a Definition of Done?

A Definition of Done is a shared team agreement that answers:

What minimum conditions must be satisfied before a work item can be considered complete?

For a backend task, a team might require:

Implementation completed

Acceptance Criteria satisfied

Relevant automated tests added

Existing tests pass

Code reviewed

Required documentation updated

CI passes

These are not feature-specific behaviours.

They are team-wide quality expectations.


Acceptance Criteria vs Definition of Done

These concepts are easy to confuse.

Suppose the Story is:

As a Customer,
I want to cancel an eligible Order,
so that I can stop an Order I no longer want.

Acceptance Criteria might include:

A Customer may cancel their own UNPAID Order.

A PAID Order cannot be cancelled in v1.

Cancelling an Order restores the Inventory
consumed by that Order.

An already-CANCELLED Order cannot be cancelled again.

These describe:

Feature Behaviour

Now compare that with:

Relevant tests exist.

Code is reviewed.

CI passes.

Documentation is updated where needed.

These describe:

Delivery Quality

So:

Acceptance Criteria
        ↓
Is the feature behaviour correct?

while:

Definition of Done
        ↓
Has the work been completed
to the team's quality standard?

Both matter.


A Feature Can Satisfy Acceptance Criteria and Still Not Be Done

Suppose an engineer implements Order cancellation.

The behaviour is correct.

Manual testing works.

Every Acceptance Criterion is satisfied.

But:

there are no automated tests

and:

the Pull Request has not been reviewed

and:

CI is failing

Then the feature behaviour may be correct, but the work is not complete according to the team's quality standard.

That is the value of a Definition of Done.


Definition of Done Is Not a Personal Checklist

A DoD should not depend on an individual engineer's personal preference.

Imagine one engineer says:

I don't usually write integration tests.

while another says:

I consider every feature incomplete
without integration tests.

The resulting quality will be inconsistent.

A shared Definition of Done aligns expectations across the team.


Our Course Project Definition of Done

For the Order Management Backend, we will use a practical baseline.

Not every item applies identically to every ticket, but the default quality bar is:

1. The agreed scope is implemented.

2. Acceptance Criteria are satisfied.

3. Relevant validation and failure behaviour are handled.

4. Relevant automated tests are added or updated.

5. Existing automated tests pass.

6. The project builds successfully.

7. The change follows the project's established
   architecture and conventions.

8. Required database migrations are included
   when persistence changes.

9. Required API documentation is updated
   when API behaviour changes.

10. Required technical documentation is updated
    when the change affects documented decisions
    or behaviour.

11. The change is reviewed through a Pull Request.

12. Meaningful review feedback is resolved.

13. CI passes.

14. Known risks are understood and acceptable
    for the scope of the change.

Later, when we begin shipping to production, some work will require additional criteria such as:

rollout verification

production health checks

migration verification

rollback planning

For now, this is our baseline.


1. The Agreed Scope Is Implemented

This sounds obvious, but it prevents a common problem:

An engineer implements part of a ticket and silently ignores the rest.

Suppose the ticket is:

Allow Administrators to deactivate Products.

Acceptance Criteria include:

Administrator can deactivate a Product.

Deactivated Products cannot be ordered.

Historical Orders remain unchanged.

Suppose the engineer only implements:

product.deactivate();

but Order creation still allows inactive Products.

The code exists.

But the agreed scope is not complete.


Do Not Implement More Than the Agreed Scope Either

The opposite problem is scope creep.

Suppose the ticket is:

Allow Administrators to deactivate Products.

But the engineer also adds:

Product deletion

Product archiving

Scheduled activation

Bulk import

Product version history

Those features may be useful someday.

But they are not part of the current work.

Extra functionality creates:

more code

more tests

more review

more risk

more maintenance

The goal of completing a task is:

Implement the agreed work completely, not expand the Product unnecessarily.


2. Acceptance Criteria Are Satisfied

Acceptance Criteria are the feature-level contract.

Before marking a task complete, the engineer should review each criterion explicitly.

Example:

AC-1
An Order must contain at least one item.

AC-2
Every referenced Product must exist.

AC-3
Quantity must be positive.

AC-4
Requested Inventory must be sufficient.

Completion review:

AC-1 → implemented and tested

AC-2 → implemented and tested

AC-3 → implemented and tested

AC-4 → implemented and tested

This is a simple habit, but it prevents many incomplete implementations.


3. Failure Behaviour Must Be Considered

Implementing only the happy path is not enough.

Suppose the task is:

Integrate Payment provider.

Happy path:

Provider confirms success
        ↓
Order becomes PAID

But known failure paths might include:

payment declined

provider error

timeout

If these scenarios are part of the agreed scope, they must be handled before the work is Done.

Our principle is:

A backend feature is not complete if only its easiest execution path works.


4. Relevant Automated Tests Must Exist

Testing is a core part of our Definition of Done.

The word:

relevant

is important.

We do not require a test for every method simply because the method exists.

Instead, tests should protect important behaviour and risk.

Examples:

Order total calculation
→ Domain/unit test
Order creation with PostgreSQL
→ Integration test
Customer cannot access another Customer's Order
→ API/security integration test
Payment provider failure behaviour
→ Controlled integration/service-boundary test

The correct test type depends on the problem.


Why Manual Testing Is Not Enough

Manual testing is useful during development.

But if it is the only form of verification, it has serious limitations:

not automatically repeatable

easy to forget

poor regression protection

A feature may work today.

Two months later, another engineer changes the system.

If important behaviour has automated tests, that behaviour can be verified again automatically.


Tests Should Protect Behaviour

Weak testing mindset:

Every class needs a test
because coverage should increase.

Better mindset:

Which behaviour would be expensive
or dangerous to break?

For our project, examples include:

Inventory must remain valid.
Order totals must be correct.
Customer ownership must be enforced.
Failed Payment must not make an Order PAID.

These are strong candidates for automated protection.


5. Existing Tests Must Still Pass

Suppose the tests for the new feature pass.

But an existing test fails.

The work is not Done.

Software changes are not isolated.

A new feature can accidentally break existing behaviour.

Example:

New cancellation logic added

but an existing behaviour now fails.

That is a regression.

Our DoD therefore includes:

Existing automated tests pass.

What Is a Regression?

A regression occurs when a new change breaks behaviour that previously worked.

Example:

Before:

Product browsing works.

After an Inventory refactor:

Product browsing returns no Products.

The new feature may work correctly.

But the system as a whole became worse.

Regression tests help catch this class of failure.


6. The Project Must Build Successfully

Suppose everything appears to work inside the developer's IDE.

But:

./gradlew build

fails.

The work is not complete.

Why?

Because:

Developer IDE state

and:

Reproducible project build

are not the same thing.

The repository should contain everything necessary for a clean environment to build the application.


Clean Builds Matter

A developer's machine may contain:

cached artifacts

generated files

local configuration

previous dependencies

that accidentally hide problems.

CI starts from a much cleaner and more controlled environment.

That is one reason automated build pipelines matter.


7. Project Conventions Must Be Followed

Suppose the established application architecture is:

Handler
    ↓
UseCase
    ↓
Domain
    ↓
Repository

with Service reserved for external or third-party integrations.

Now imagine a new engineer places all business logic directly inside an HTTP Handler.

The feature may work.

Tests may even pass.

But the design becomes inconsistent and harder to maintain.

Our Definition of Done therefore includes:

The change follows the established
project architecture and conventions.

Convention Does Not Mean Blind Copying

Existing patterns matter.

But they are not automatically perfect.

If an existing pattern is clearly problematic, an engineer should raise the issue.

For example:

Validation logic is duplicated everywhere.

That may deserve a design discussion.

But silently introducing an entirely different architecture while implementing an unrelated ticket is also risky.

Consistency and improvement both require judgement.


8. Database Changes Need Migrations

Suppose a feature requires a new database column.

The developer manually executes:

ALTER TABLE orders
ADD COLUMN status TEXT;

on their local machine.

The application works locally.

But no migration file exists.

Other environments now have no reproducible way to reach the required schema.

Therefore:

Any persistent schema change must include the corresponding versioned Flyway migration.


Application Code and Schema Must Move Together

Imagine:

New application version expects orders.status

but the target database does not contain that column.

The result is application failure.

Versioned migrations allow application evolution and database evolution to move together in a controlled way.


9. API Changes Need Documentation

Suppose we add:

POST /api/v1/orders

but the API contract is not documented.

How should another client know:

request shape

response shape

validation rules

possible errors

Later, we will use OpenAPI for the public API contract.

When API behaviour changes, API documentation should remain consistent with that behaviour.


Documentation Should Be Relevant

Our DoD says:

Documentation updated where needed.

That does not mean rewriting the README for every ticket.

Documentation should match the change.

For example:

API Behaviour Change

Update the API contract.

Important Architecture Decision Change

Update or replace the relevant ADR/RFC when appropriate.

Deployment Configuration Change

Update operational documentation where necessary.

Pure Internal Refactor

No documentation update may be required.


Documentation Is Part of the System

A common mistake is thinking:

Code is the real work.

Documentation is optional.

Some information is difficult to reconstruct from code alone.

For example:

Why did we choose this transaction boundary?
Why do we not physically delete Products?
Why is automatic retry disabled
for a particular Payment operation?

That reasoning may belong in:

ADR

RFC

Pull Request description

depending on the size of the decision.


10. Technical Decisions Must Stay Consistent

Suppose an existing ADR says:

Products are not physically deleted
because historical Orders must remain valid.

A new feature introduces Product deletion without revisiting that decision.

The change may now conflict with the system's documented design.

Before considering the work Done, the engineer should check whether relevant architectural decisions are still being respected.


11. Pull Request Review Is Required

Our simulated engineering workflow does not use direct unreviewed merges.

Changes go through a Pull Request.

Reviewers can ask:

Does the behaviour match the requirement?

Are edge cases handled?

Is the design understandable?

Are tests meaningful?

Are there security concerns?

Are there migration risks?

Is the scope larger than necessary?

A reviewer is not merely a syntax checker.


Code Review Is Not About Proving Who Is Smarter

A healthy review aims to:

improve correctness

share context

identify risk

maintain consistency

Unhealthy review culture focuses on:

personal preference battles

low-value nitpicking

showing superiority

We will cover code review in more depth later.

For now:

Review is part of our Definition of Done.


12. Review Feedback Must Be Resolved

A Pull Request receiving comments does not make it complete.

Suppose a reviewer writes:

Inventory is reduced before Order persistence.

What happens if persistence fails?

That concern cannot simply be ignored.

Meaningful feedback should result in one of the following:

code changed

or:

discussion confirms the existing design is correct

or:

a deliberate follow-up is agreed
when the issue is not required for current correctness

Unresolved meaningful review feedback is incompatible with Done.


13. CI Must Pass

Our Continuous Integration pipeline will automatically verify at least:

build

automated tests

Later, additional checks may become useful.

But we will not add pipeline complexity simply for appearance.

The baseline is simple:

CI is red
→ work is not Done

even when:

it works on my machine

Why CI Is More Trustworthy Than One Developer Environment

Every developer machine is slightly different.

CI gives us a standardized environment.

If:

Developer A

Developer B

CI

can all build and test the same source successfully, confidence increases.


14. Known Risks Must Be Acceptable

Sometimes the code is correct and every test passes, but the change still has operational risk.

Examples:

A migration rewrites a large table.
Payment behaviour changes.
Authorization rules change.

The deeper DoD question becomes:

Are the known risks understood and appropriately handled?

For a small change:

No special rollout concern.

may be sufficient.

For a risky production change, we may later require:

rollout plan

monitoring plan

rollback plan

The process should match the risk.


Definition of Done Is a Minimum, Not a Maximum

Suppose the DoD says:

Relevant tests added.

Now imagine a ticket changes critical concurrency behaviour.

A single minimal test may not be enough.

The DoD is the baseline.

Engineering judgement still matters.


Definition of Done Should Not Become Bureaucracy

An unhealthy DoD might require:

47 checkboxes

12 mandatory documents

3 approval committees

5 reports

even for a trivial change.

That would make the process more expensive than the work.

A good Definition of Done protects meaningful quality without creating unnecessary ceremony.

Our baseline is intentionally compact.


Different Work May Need Additional Conditions

Consider a small internal refactor.

A sufficient completion bar may be:

behaviour preserved

tests pass

review complete

CI passes

Now consider a database migration.

We may also need:

migration validated

For an external Payment change:

failure behaviour tested

becomes especially important.

For a production deployment change:

rollback considerations

may matter.

So the model is:

One baseline Definition of Done, plus work-specific completion conditions.


Definition of Ready Is Different

Some teams use another concept:

Definition of Ready

It answers:

Is this work sufficiently understood to begin implementation?

Possible conditions:

scope is clear

Acceptance Criteria exist

blocking questions are resolved

We will not introduce a separate formal Definition of Ready in this course.

That would add unnecessary process.

Conceptually, however, the previous lessons have already been doing the same work:

Understand requirement

Clarify behaviour

Define Acceptance Criteria

Understand engineering context

Then we begin planning implementation.


Do Not Confuse “Merged” With “Delivered”

Suppose a Pull Request has been merged.

Has the Customer received the feature?

Not necessarily.

The lifecycle can look like:

Code Complete
    ↓
Reviewed
    ↓
Merged
    ↓
Built
    ↓
Deployed
    ↓
Verified

We will explore this in the shipping module.

For the early implementation modules, a merge-ready, reviewed, green-CI change is our baseline completion standard.

For production-specific work, the DoD will expand.


Ticket Statuses Can Reflect Reality

A team may use:

To Do
   ↓
In Progress
   ↓
In Review
   ↓
Done

Another team may also distinguish:

Ready for Deployment

or:

Released

The exact workflow is organization-specific.

The important thing is that a status communicates the real state of the work.


“Code Complete” Can Be a Useful Intermediate State

An engineer might say:

Implementation is complete,
but the ticket is still in review.

That is precise.

It is much better than saying:

It's basically done.

Basically done usually hides important unfinished work.


Example: Order Creation Ticket

Suppose a future ticket is:

BACKEND-125

Implement Order creation workflow

Acceptance Criteria:

Order contains at least one item.

Products must exist.

Quantity must be positive.

Inventory must be sufficient.

Backend calculates the total.

Any invalid item causes
the full request to fail.

Before marking it Done:

[✓] Required behaviour implemented

[✓] Domain/business validations implemented

[✓] Relevant unit tests added

[✓] Integration tests added for the workflow

[✓] Existing tests pass

[✓] Build passes

[✓] No unrelated scope added

[✓] API documentation updated if required

[✓] Pull Request opened

[✓] Review completed

[✓] Feedback resolved

[✓] CI passes

Now the word Done has useful meaning.


Example: Database Migration Ticket

Suppose the ticket is:

Create persistence schema for Products.

Completion may include:

Migration file committed

Application persistence mapping works

Integration tests run against
the expected PostgreSQL schema

A clean environment can apply migrations

Build and tests pass

Review completed

A manually created local table is not enough.


Example: Documentation-Only Ticket

Suppose the ticket is:

Document the Order cancellation design decision.

For this work:

database migration

is irrelevant.

And:

API integration test

may also be irrelevant.

The Definition of Done should not be applied blindly.

Only relevant conditions apply.

Engineering judgement matters.


Example: Bug Fix

Suppose production has a bug:

Order total is calculated incorrectly.

A strong completion standard might include:

root behaviour understood

bug fixed

regression test added

existing tests pass

review complete

CI passes

The important principle is:

A bug fix should ideally prevent the same regression from returning.

It should not merely change one line and move on.


A Useful Question Before Marking Work Done

Ask:

If I disappear after this change is merged, does the repository contain enough code, tests, migrations, and context for the team to safely own it?

If the answer is no, the work is probably not complete.


Ownership Changes the Meaning of Done

Tutorial mindset:

I made it work.

Professional mindset:

The team can now safely own this change.

That difference is significant.

Production code is not personal code.

Once merged, the team collectively owns and maintains it.


“Works Today” vs “Can Be Maintained Tomorrow”

A rushed implementation may work today:

// one large method
// duplicated logic
// no tests
// hidden assumptions

But the next change becomes much more difficult.

A Definition of Done helps preserve a minimum level of maintainability.


Definition of Done and Technical Debt

Sometimes a team intentionally accepts a compromise.

For example:

We cannot complete the ideal refactor
before the release.

Then the limitation should be explicit.

A reasonable approach might be:

Current change is safe for release.

Known limitation is documented.

Follow-up ticket is created.

But a follow-up ticket cannot be used to skip required correctness.


A Follow-Up Ticket Is Not an Escape Hatch

Bad:

Authorization validation is missing.

We'll create a follow-up.

If Authorization is required for the feature to be correct, the ticket is not Done.

Reasonable follow-up:

The current API satisfies the agreed requirement.

Additional performance optimization
would be useful but is not required for v1.

The distinction is:

Required Correctness

versus:

Future Improvement

Quality Is Cheaper Before Merge

A defect is cheapest to catch while coding.

Then it becomes progressively more expensive to discover during:

automated testing

then:

code review

then:

non-production deployment

and eventually:

production

By the time a problem becomes a production incident, it may involve:

Customer impact

investigation

rollback

hotfix

operational coordination

The Definition of Done creates quality gates earlier in the lifecycle.


Review the Diff, Not Just the Result

Suppose all Acceptance Criteria are satisfied.

But the implementation also:

changes unrelated files

or:

removes validation elsewhere

or:

adds unnecessary dependencies

The Pull Request review should catch this.

Small, focused changes are easier to understand and safer to review.


Small Work Items Make “Done” Easier to Understand

Consider this ticket:

Build the entire ordering system.

Asking:

Is it done?

is difficult.

Now compare:

Implement Product creation API.

The boundary is much clearer.

This is one reason our next lesson will break the project into smaller engineering tickets.


Definition of Done Helps Planning

Suppose an engineer estimates:

This feature is one day of coding.

But completion also requires:

implementation

tests

review iteration

migration

documentation

Then the actual work may be larger than the coding effort alone.

Definition of Done helps teams plan the full cost of delivery rather than only the time spent typing code.


Definition of Done Builds Team Trust

If everyone knows:

Done means tested, reviewed,
and CI is green.

then teammates can trust status updates.

They do not need to repeatedly ask:

Did you add tests?

Does it build?

Did anyone review it?

A shared standard reduces communication overhead.


Our Definition of Done Document

We can capture the baseline in a lightweight repository document:

# Definition of Done

A work item is considered complete when all relevant
conditions below are met.

## Behaviour

- Agreed scope is implemented.
- Acceptance Criteria are satisfied.
- Relevant validation and failure behaviour is handled.

## Quality

- Relevant automated tests are added or updated.
- Existing automated tests pass.
- The application builds successfully.
- The change follows established project conventions.

## Data and API Changes

- Required database migrations are included.
- API documentation is updated when API behaviour changes.
- Relevant technical documentation is updated when needed.

## Review

- The change is submitted through a Pull Request.
- Meaningful review feedback is resolved.
- CI passes.

## Risk

- Known risks are understood and acceptable
  for the scope of the change.

This will be our baseline throughout the project.


What We Deliberately Did Not Add

Our Definition of Done does not require:

multiple mandatory approvals
performance benchmarks for every ticket
an ADR for every change
production deployment for every code task
an arbitrary code-coverage percentage

because those requirements are not justified by the current context.


Why We Are Not Setting a Code Coverage Percentage

A rule such as:

80% code coverage required

is easy to measure.

But coverage does not guarantee test quality.

A test can execute code without meaningfully verifying behaviour.

For example:

createOrderUseCase.execute(command);

with no meaningful assertion may increase line coverage without increasing confidence.

Our approach is:

Test important behaviour and risk deliberately.

Coverage may later be a useful signal.

It is not our Definition of Done.


Why We Are Not Requiring an RFC for Every Ticket

RFCs are useful when:

design scope is large

or:

a decision is significant

But a ticket like:

Add quantity validation

does not need a ten-page RFC.

Our documentation principle remains:

Ticket
→ bounded implementation work

ADR
→ important architecture decision

RFC
→ larger technical proposal

Use the lightest mechanism that preserves the necessary context.


Why the Definition of Done Will Evolve

As the system and team mature, the DoD may change.

Later, we may discover that:

deployment verification
must become mandatory

or:

migration rollback planning
needs explicit attention

or:

certain security checks
should become standardized

The team can then update the shared baseline.

A Definition of Done is not an immutable law.

It is an engineering agreement.


The DoD Should Reflect Actual Practice

One of the worst situations is when documentation says:

All changes require automated tests.

while reality is:

Half the team skips them.

Then the Definition of Done is fiction.

A smaller standard that the team actually enforces is better than a huge checklist that nobody follows.

Throughout this course, we will apply the established DoD consistently.


Completion Review

Before marking a ticket Done, an engineer can perform a quick self-review:

Did I implement only the agreed scope?

Did I satisfy every Acceptance Criterion?

Did I consider meaningful failure paths?

Are important behaviours protected by tests?

Did I accidentally break existing behaviour?

Does the project build cleanly?

Are migrations and documentation included where needed?

Is the change understandable to the reviewer?

Have meaningful review comments been resolved?

Is CI green?

Are there known risks I have not communicated?

This is a practical habit.


Definition of Done and Production Ownership

Later in the course, the application will be running in production.

At that stage, completion may also require:

Deployment completed

Health checks healthy

Expected metrics look normal

No obvious error-rate regression

Database migration succeeded

We will add those delivery criteria when they become relevant.

For now, we are establishing the implementation-workflow baseline.


Engineering Principle

The core principle from this lesson is:

Code written is not the same as work completed.

Professional completion means:

correct behaviour
+
appropriate tests
+
review
+
reproducible build
+
required documentation
+
understood risk

And the most important mindset is:

A change is Done when the team can safely own it, not merely when the author stops typing.


Where We Are Now

Our Module 1 journey is now:

Product Requirement
        ↓
Requirement Analysis
        ↓
Functional vs Non-Functional Requirements
        ↓
User Stories and Acceptance Criteria
        ↓
Engineering Context
        ↓
Definition of Done
        ↓
Initial Engineering Backlog

The Product behaviour is sufficiently clear.

The engineering environment is clear.

The quality bar is also clear.

We can now begin planning implementation work.


Summary

In this lesson, we learned that:

  • Done needs a shared team-wide meaning.
  • A Definition of Done is a minimum quality bar.
  • Acceptance Criteria define feature behaviour.
  • Definition of Done defines delivery quality.
  • Writing the code does not mean the work is complete.
  • Relevant automated tests are part of completion.
  • Existing tests must continue to pass.
  • The project must build successfully in a reproducible environment.
  • New work should follow the project's established architecture and conventions.
  • Persistent schema changes require versioned Flyway migrations.
  • API documentation should be updated when API behaviour changes.
  • Technical documentation should be updated when relevant design decisions change.
  • Pull Request review is part of the workflow.
  • Meaningful review feedback must be resolved.
  • CI must be green.
  • Known risks must be understood and communicated.
  • The DoD applies according to the nature of the work rather than as a blind checklist.
  • We are not adding arbitrary coverage targets, mandatory RFCs, or unnecessary approval processes.
  • A follow-up ticket cannot be used to skip required correctness.
  • Quality issues are cheaper to catch before merge than in production.
  • Small work items make completion easier to evaluate.
  • A professional change becomes team-owned software, not author-owned code.

Next lesson:

Creating Our Initial Engineering Backlog

There, we will use the Product Stories, Acceptance Criteria, engineering context, and Definition of Done to create the project's first realistic engineering tickets, identify dependencies, order the work, and prepare the project for implementation.