Joining the Backend Team

Functional vs Non-Functional Requirements

LuettavaEsikatselu

Katselet ilmaista esikatseluoppituntia.

In the previous lesson, we analysed the initial product requirement and learned why reading a requirement document is not the same as being ready to implement it.

We separated:

  • explicitly stated behaviour
  • assumptions
  • open questions
  • risks
  • scope uncertainty

The next step is to structure those requirements more clearly.

When designing a backend system, requirements can broadly be divided into two categories:

Functional Requirements

and:

Non-Functional Requirements

This distinction matters because understanding which features a system supports is not enough.

We also need to understand:

  • how reliable it needs to be
  • how secure it needs to be
  • how it should perform under expected load
  • how it should behave when failures occur
  • how easy it should be to operate and observe
  • how safely it can evolve over time

In this lesson, we will examine both categories in the context of our Order Management Backend.


What Is a Functional Requirement?

A functional requirement describes what the system does.

A useful way to think about it is:

Which user or system can perform which action, and what behaviour should that action produce?

For example:

Customer can view available products.

That is a functional requirement because it describes a capability.

Another example:

Customer can create an order containing multiple products.

That is also functional.

And:

Administrator can update product inventory.

is another functional requirement.

Functional requirements define observable system behaviour.


Our Current Functional Requirements

From the initial product brief, we can already identify several functional capabilities.

Product Browsing

The requirement says:

Customers should be able to browse available products.

This tells us the backend needs a way for Customers to retrieve Product information.

However, the exact meaning of:

available

still needs clarification.

Does it mean:

Product is active

or:

Inventory is greater than zero

or:

Product is active
AND
Inventory is greater than zero

The capability is clear.

The detailed business rule is not yet fully defined.


Order Creation

The requirement says:

Customers should be able to place orders.

This is a broad functional requirement.

We also know:

An order may contain multiple products.

and:

Customers should only be able to order products
that are currently available in inventory.

So Order creation is directly connected to Inventory behaviour.

That already tells us that Order creation is not merely:

INSERT INTO orders

It is a business workflow involving several rules.


Price Calculation

The requirement says:

The system should calculate the total price of the order.

This is also functional behaviour.

The backend must not simply trust a client-provided total.

Instead, the server determines the authoritative prices and calculates the Order total.

In our current monetary model, that eventually means values such as:

priceCents
unitPriceCents
totalCents

are calculated using whole cents.

The important requirement-level idea, however, is simpler:

The backend owns the Order price calculation.


Order History

The requirement says:

Customers should be able to view their previous orders.

That defines a clear capability.

But it creates further questions:

Can Customers view only their own Orders?

How should Orders be sorted?

Do we need pagination?

Which Order details should be returned?

Those questions refine the functional behaviour.


Order Cancellation

The requirement says:

Customers should be able to cancel eligible orders.

The capability is clear:

Cancel an Order

But:

eligible

is not yet defined.

This gives us an important lesson:

A requirement can be functional without being precise enough to implement.


Product Management

The requirement says:

Administrators should be able to manage products.

This is functional behaviour.

But manage is broad.

Possible operations include:

Create Product

Update Product

Deactivate Product

View Product

Delete Product

We cannot assume all of these are required merely because the word manage was used.

The exact operations need clarification.


Inventory Management

Similarly:

Administrators should be able to manage inventory.

defines a capability but not the complete behaviour.

Possible interpretations include:

Set Inventory quantity

Increase Inventory

Decrease Inventory

View current Inventory

Technical design should not begin until we understand what operations the business actually needs.


Payment

The requirement says:

Customers should be able to pay for their orders
using our payment provider.

This is also a functional requirement.

But unlike most of the current system, Payment involves an external dependency.

Later, we will need to understand:

provider behaviour

timeouts

failures

idempotency

payment references

Those details belong to the Payment integration design.


A Functional Requirement Is Not an Endpoint

Backend developers often see a requirement and immediately think in HTTP endpoints.

For example:

Customer can create an order.

may immediately suggest:

POST /orders

That is natural.

But the endpoint is not the requirement.

The requirement is:

Customer can create an Order.

The API is one mechanism through which we expose that behaviour.

Similarly:

Customer can cancel an eligible Order.

could technically be represented using:

POST /orders/{id}/cancel

or some other HTTP design.

The requirement itself is independent of that choice.

The flow should be:

Requirement
    ↓
Technical Design
    ↓
API

not:

Endpoint
    ↓
Invent behaviour around it

Behaviour Should Be Observable

A useful functional requirement should describe behaviour that can later be verified.

Weak:

The ordering experience should be good.

What does good mean?

It is difficult to verify.

Better:

A Customer can create an Order containing
one or more valid Products.

More precise:

If sufficient Inventory is available,
the system creates the Order and returns its identifier.

And for a failure case:

If requested Inventory is unavailable,
the system rejects the Order.

Now we have behaviour that can be tested.


Positive and Negative Behaviour

Functional requirements should not describe only the happy path.

Consider:

Customer can create an Order.

A success case might be:

Authenticated Customer

Valid Product

Valid quantity

Sufficient Inventory

→ Order created

But what about:

Unknown Product

or:

Invalid quantity

or:

Insufficient Inventory

or:

Empty Order

Those behaviours may also need to be defined.

This is why functional requirements naturally lead into:

acceptance criteria

which we will cover next.


What Is a Non-Functional Requirement?

A non-functional requirement describes how the system should operate, or which quality and operational constraints matter around its functionality.

Functional:

Customer can create an Order.

A non-functional concern might be:

Order creation must remain reliable
under expected production traffic.

Another:

A Customer must never access another
Customer's private Order data.

Another:

The service must expose enough operational information
for engineers to diagnose failures.

These do not introduce new business features.

They define qualities and constraints around existing features.


Functional vs Non-Functional: A Simple Comparison

Suppose:

Customer can view Order history.

That is functional.

Now:

Order history must only expose Orders belonging
to the authenticated Customer.

That is primarily a security requirement.

Now:

Order history should remain responsive
under expected production traffic.

That is a performance concern.

And:

Failures while loading Order history
should be diagnosable through logs and metrics.

That is an observability concern.

The feature remains the same.

The expectations around it change.


Common Non-Functional Requirement Categories

Backend systems commonly need to consider:

Performance

Scalability

Reliability

Availability

Security

Data Integrity

Maintainability

Observability

Recoverability

Compliance

Not every project needs all of these at the same depth.

But a backend engineer should recognize them.


Performance

Performance concerns how quickly and efficiently a system performs its work.

Examples include:

API response latency
Database query latency
Requests handled per second
Batch processing duration

Our initial product brief does not provide a concrete latency target.

Therefore we should not invent:

All endpoints must respond within 200 ms.

That would be arbitrary.

Instead, useful open questions are:

Are there explicit response-time expectations?

and:

What production traffic should the first version support?

Scalability

Scalability concerns how a system behaves as load grows.

A system processing:

10 Orders per minute

does not necessarily need the same architecture as one processing:

10,000 Orders per second

The key principle is:

Do not build for massive scale before understanding the expected scale.

Our course project is not trying to build a distributed global commerce platform.

We are building a strong production-style backend foundation.

We should not introduce architecture complexity without evidence that it solves a real requirement.


Reliability

Reliability asks whether the system behaves correctly and consistently even when things go wrong.

For an Order system, this matters greatly.

Example:

Payment succeeded,
but the Order remained UNPAID.

That is a reliability problem.

Another:

Inventory was reduced,
but Order creation failed.

That is a serious consistency problem.

Another:

The same payment was processed twice.

That is also a reliability problem.

Later modules will connect these concerns to:

transactions

idempotency

external integration design

failure handling

Availability

Availability asks whether the service is available to serve user requests.

A backend can have excellent features and still be unusable if it is frequently unavailable.

Questions include:

Is this service business-critical?

Is occasional downtime acceptable?

Do we have an availability target?

Our current product requirement does not specify an SLA or availability target.

So we do not invent one.


Security

Security is central to backend requirements.

Functional requirement:

Customer can view previous Orders.

Security expectation:

Customer must not be able to view
another Customer's Orders.

Functional requirement:

Administrator can update Inventory.

Security expectation:

Regular Customers must not have access
to administrative Inventory operations.

These requirements will later drive our:

authentication

authorization

design.


Data Integrity

Data integrity is particularly important for our Order Management Backend.

Examples:

Inventory must not become negative
because of successful Order placement.
Order totals must remain internally consistent
with recorded OrderItems.
Historical Orders must not accidentally change
because current Product data changes.

Some of these rules sit near the boundary between:

functional correctness

and:

non-functional data integrity

That is fine.

Real-world categorization is not always perfect.

The important thing is that the rule is clear and protected.


Maintainability

Production software must remain changeable.

Engineers will need to work on this system next month and next year.

Maintainability questions include:

Can engineers understand the code?

Are responsibilities separated clearly?

Can important behaviour be tested?

Can configuration change safely?

Can new functionality be added without
rewriting unrelated parts of the system?

These expectations are not always written explicitly in a Product requirement.

But they still matter to engineering design.


Observability

When production software fails, engineers need to understand what happened.

Observability may include:

Logs

Metrics

Health checks

Request correlation

Operational dashboards

Tracing

Within this course, we will later work with:

structured logging

metrics

health checks

request/correlation IDs

Advanced distributed tracing architecture is outside the scope of this course.

We do not need it for our current modular application.


Recoverability

We also need to think about what happens after failures.

For example:

Deployment failed.

Can we roll back?

Database migration failed.

Can the previous application version continue working?

External payment provider timed out.

Can the operation safely retry?

These concerns become important later in:

deployment

database migration

external service integration

modules.


Compliance Is Context-Dependent

Some systems have legal or regulatory requirements.

Examples might include:

financial regulation

personal-data requirements

audit requirements

Our fictional product brief does not specify any particular compliance obligation.

So we will not invent one for the course project.

On a real project, however, an engineer should ask:

Are there compliance requirements that affect this feature?


Non-Functional Requirements Should Be Measurable

Weak:

The system should be fast.

Fast is not measurable.

Better:

The system should meet the agreed latency target
for normal production traffic.

And once a real target is known:

95% of requests should complete within
the agreed number of milliseconds.

But that number must come from actual engineering or business context.

We do not make it up.

Similarly:

Weak:

The system must be highly available.

Better:

The service must meet the agreed availability target.

And only once that target is known should it become part of the specification.


Avoid Fake Precision

A specification can look professional while still being meaningless.

For example:

99.999% availability
50 ms response time
100,000 requests per second

These numbers may sound impressive.

Without context, they are arbitrary.

Every target has a cost.

For example:

Higher availability
        ↓
More redundancy
        ↓
More operational complexity
        ↓
More cost

Requirements should reflect real needs, not impressive-looking numbers.


Deriving Non-Functional Concerns From the Product Brief

Our initial product brief does not specify concrete NFR targets.

But we can still identify areas that matter.

Notice that we are identifying concerns—not inventing numbers.


Security Concern

The system distinguishes:

Customers

and:

Administrators

So relevant questions include:

How will Customers authenticate?

How will Administrators authenticate?

How will authorization be enforced?

These questions will eventually lead us into Spring Security.


Reliability Concern

Order creation changes Inventory.

Payment communicates with an external provider.

So likely risks include:

Partial Order creation

Incorrect Inventory updates

Duplicate payment processing

Payment timeout

We will address these later when those capabilities are implemented.


Data Integrity Concern

The backend calculates Order prices and enforces Inventory availability.

Important likely invariants therefore include:

The Order total must be calculated by the backend.

and:

Successful Orders must respect available Inventory.

The exact Inventory behaviour still needs clarification at this stage.


Performance Concern

Customers browse Products and view Order history.

Relevant questions include:

How many Products might exist?

How many historical Orders can one Customer have?

Do list APIs need pagination?

What traffic should we expect?

We do not answer these with arbitrary assumptions.


Observability Concern

The application will eventually run in production.

So we should ask:

How will failures be diagnosed?

What health information should the service expose?

Which failures should appear in metrics?

We will implement these concerns in the production-readiness module.


Requirement Priority

Not every requirement has the same priority.

Teams may use concepts such as:

Must Have

Should Have

Could Have

Won't Have for Now

or another prioritization framework.

The specific framework matters less than having a clear v1 scope.

For example:

Core Order creation

is clearly central to the first release.

But:

Discount campaigns

do not appear in the initial requirement.

So we should not build a complicated pricing engine merely because discounts may exist one day.


Functional Requirement Decomposition

Consider the broad requirement:

Customer can place an Order.

We can decompose it into smaller behaviours.

For example:

Customer provides one or more requested items.
System validates the requested Products.
System validates quantities.
System checks required Inventory.
System determines authoritative item prices.
System calculates the total.
System persists the resulting Order.

However, be careful.

Some decomposition may start moving toward technical design.

We should remain aware of the boundary between:

required behaviour

and:

implementation strategy

Functional Requirement vs Business Rule

Functional capability:

Customer can cancel an Order.

Business rule:

Only eligible Orders can be cancelled.

An invariant might say:

A cancelled Order cannot return to an active state.

These are related but different ideas.

A backend design needs all of them.


Example Requirement Set

After clarification, a feature definition might eventually look like this:

Feature:
Create an Order

Functional Behaviour:

- Customer submits one or more OrderItems.
- Each OrderItem references an existing Product.
- Each quantity must be valid.
- Requested Inventory must be available.
- Backend determines authoritative item prices.
- A valid request creates an Order.

Alongside those functional rules, we might identify non-functional concerns:

Security:

Only an authenticated Customer can create
an Order for themselves.
Reliability:

Order creation must not leave partial state
if the operation fails.
Data Integrity:

Inventory-related rules must remain valid
when concurrent requests occur.
Observability:

Unexpected Order creation failures
must be diagnosable.

Notice that we still have not written implementation code.


Some Requirements Cross Categories

Real-world requirements do not always fit perfectly into textbook categories.

Consider:

Inventory must never become negative.

Is that:

functional?

or:

non-functional?

One engineer may call it:

a business invariant

Another:

a data-integrity requirement

Another:

functional correctness

The categorization matters less than the outcome.

What matters is:

The rule is explicit.
Everyone understands it.
The implementation protects it.
Tests verify it.

Requirement Traceability

On larger projects, it is valuable to understand:

Why does this code exist?

Ideally, we can trace:

Product Requirement
        ↓
Engineering Requirement
        ↓
Ticket
        ↓
Implementation
        ↓
Test

For example:

Requirement:

Customers cannot successfully order
more Inventory than is available.

Later:

Ticket:

Validate and safely consume Inventory
during Order creation.

Then the implementation protects that rule.

Integration tests verify that insufficient Inventory is rejected.

This makes it easier to connect code back to business intent.


Testing Starts at Requirement Time

Testing should not begin only after implementation is finished.

While reading a requirement, test scenarios should already start appearing.

Requirement:

Customers should only be able to order
Products available in Inventory.

Possible scenarios:

Inventory = 10
Requested = 2

→ success
Inventory = 2
Requested = 2

→ should this succeed?

This question helps clarify whether consuming the final available units is allowed.

Another:

Inventory = 1
Requested = 2

→ reject

Another:

Inventory = 0
Requested = 1

→ reject

Thinking about tests can expose unclear requirements before implementation starts.


Failure Cases Are Requirements Too

Consider Payment.

Functional requirement:

Customer can pay for an Order.

But what if the provider responds with:

Payment declined

or:

Provider timeout

or:

Provider unavailable

or:

Provider succeeds
but our database update fails

We do not need to solve all of these problems yet.

But recognising failure modes early is important.

Production backend quality is often revealed more clearly by failure behaviour than by the happy path.


Our Requirement Document Is Still Evolving

At this point, we have high-level requirements.

We should not treat them as a final specification yet.

Our process currently looks like:

Product Brief
    ↓
Requirement Analysis
    ↓
Functional / Non-Functional Classification
    ↓
Clarification
    ↓
Acceptance Criteria
    ↓
Technical Design

We are still in the middle.


Working Functional Requirement List

Based on the current product brief:

FR-1

Customers can browse available Products.
FR-2

Customers can place Orders.
FR-3

An Order can contain multiple Products.
FR-4

Ordering is constrained by available Inventory.
FR-5

The backend calculates Order totals.
FR-6

Customers can view previous Orders.
FR-7

Customers can cancel eligible Orders.
FR-8

Customers can pay for Orders through
the Payment provider.
FR-9

Administrators can manage Products.
FR-10

Administrators can manage Inventory.

These are not final.

Clarification may change their wording.


Working Non-Functional Concern List

These are not concrete SLAs or targets.

They are areas where additional requirements or engineering decisions may be necessary.

NFR Area: Security

Customer and Administrator capabilities
must be protected appropriately.
NFR Area: Data Integrity

Order, price, and Inventory state
must remain internally consistent.
NFR Area: Reliability

Failures should not leave the system
in unintended partial states.
NFR Area: Performance

Expected traffic and list sizes
must be understood before finalizing
performance targets.
NFR Area: Observability

Production failures must be diagnosable.
NFR Area: Maintainability

The application should remain understandable
and safely changeable as requirements evolve.

Notice that we have not invented:

SLA

latency target

throughput target

because we do not yet have evidence for them.


What Belongs in the Product Requirement?

Not every technical concern belongs in a Product Manager's requirement document.

Examples:

Database indexes
Connection pool size
Spring Boot configuration

These are engineering implementation details.

On the other hand:

Customer must not see another Customer's Orders.

is important both as:

product behaviour

and:

security expectation

Good collaboration requires understanding the boundary between business requirements and engineering implementation.


A Useful Review Method

When analysing a feature, ask four questions:

1. What should happen?
2. When should it be allowed?
3. What should happen when it cannot succeed?
4. What qualities or constraints matter?

Example:

Feature:
Order cancellation

Question 1:

What should happen?

The Order becomes cancelled.

Question 2:

When is it allowed?

Still unclear.

Question 3:

What happens if cancellation is not allowed?

Still needs definition.

Question 4:

What constraints matter?

Authorization

Inventory consistency

Possibly Payment state

Now the remaining ambiguity is visible.


Avoid Architecture Requirements Without Reason

A dangerous requirement might say:

The system must use microservices.

without explaining why.

Or:

The system must use Kafka.

These are not functional requirements.

They are technical constraints or implementation choices.

Technology choices should have reasons.

Our current system begins as a simple modular backend because the current requirements do not justify distributed architecture.


Requirement Quality Checklist

When reviewing a requirement, ask whether it is:

Clear

Would different people understand
the same behaviour?

Testable

Can we verify whether the behaviour is correct?

Necessary

Does it solve an actual problem?

Scoped

Does it belong in the current release?

Consistent

Does it conflict with another requirement?

Feasible

Can it be implemented within known constraints?

Not every requirement will be perfect.

These questions help us improve them.


Engineering Does Not Mean Making Requirements Bigger

Being a strong engineer does not mean adding more technology.

Weak interpretation:

Order system?

Let's add:

Kafka

Redis

Elasticsearch

Kubernetes

CQRS

Event Sourcing

Strong interpretation:

What behaviour is required?

What risks exist?

What is the simplest design
that safely satisfies those requirements?

That is the mindset we will follow throughout this course.


Where We Are Now

Our project has progressed through:

Initial Product Brief
        ↓
Requirement Analysis
        ↓
Functional Requirements
        ↓
Non-Functional Concerns

But the requirements are still not ready for implementation.

Our next question is:

How do we define exactly what success looks like?

For example:

Customer can create an Order.

is still broad.

When can an engineering ticket be considered complete?

That is where:

User Stories

and:

Acceptance Criteria

become useful.


Engineering Principle

The core principle from this lesson is:

A feature is not fully understood until both its behaviour and the qualities that matter around that behaviour are considered.

Functional requirements describe:

what the system does

Non-functional requirements describe qualities and constraints such as:

security

reliability

performance

observability

maintainability

Production software needs both.


Summary

In this lesson, we learned that:

  • Functional requirements describe system capabilities and observable behaviour.
  • Non-functional requirements describe quality, constraints, and operational expectations.
  • An API endpoint is a technical representation of a requirement, not the requirement itself.
  • Requirements should consider failure behaviour as well as the success path.
  • Security, reliability, data integrity, performance, observability, and maintainability are important backend concerns.
  • Non-functional targets should not be invented without evidence.
  • Arbitrary latency, throughput, and availability numbers do not make a specification professional.
  • Some rules sit between functional requirements, non-functional requirements, business invariants, and data-integrity requirements.
  • Clear behaviour matters more than perfect categorization.
  • Test scenarios can be identified while requirements are still being analysed.
  • Requirement traceability helps connect Product intent to implementation and tests.
  • Technology choices should not masquerade as business requirements.
  • We should not add microservices, Kafka, Redis, CQRS, Event Sourcing, or other architectural complexity unless a real requirement justifies them.
  • The simplest design that safely satisfies actual requirements is usually the best starting point.

Next lesson:

User Stories and Acceptance Criteria

There we will begin turning broad requirements into smaller, testable, engineering-ticket-ready behaviours.