Anik Sikder
Technical Writing/engineering-practices/requirements-engineering-from-business-problems-to-software-architecture
article.sh

$ open article

engineering-practices

Before You Write Code, Ask Better Questions

20 min readAugust 14, 2026
Requirement Engineering From Business Problems to Software Architecture

Imagine you're building a SaaS platform.

Nothing unusual.

Just an employee management system.

The client says:

"We need employee management."

A developer says:

"Sure. I'll build employee CRUD."

So the implementation begins.

code
Employee
   ↓
Create
Read
Update
Delete

Simple.

Until the real requirements appear.

A few weeks later:

  • HR wants approval workflows.
  • Managers shouldn't see salary information.
  • Employees can belong to multiple departments.
  • Former employees must remain in historical reports.
  • The organization has multiple branches.
  • Some actions require approval.
  • Sensitive changes must be audited.
  • Another system needs an API.
  • Finance needs historical payroll data.

The developer didn't necessarily write bad code.

The problem happened before the code existed.

The team misunderstood the problem.

That's one of the most important lessons in software engineering:

Great software starts with great questions, not great code.

Requirement engineering is the process of turning:

code
Business Goals
      ↓
User Problems
      ↓
Requirements
      ↓
Business Rules
      ↓
Data
      ↓
Workflows
      ↓
Architecture
      ↓
Implementation
      ↓
Validation

When this chain breaks, even excellent developers can build the wrong system extremely well.


The Real Problem With Requirements

Consider this requirement:

"Managers can manage employees."

What does manage mean?

Can a manager:

  • create an employee?
  • edit personal information?
  • change salary?
  • change department?
  • deactivate an employee?
  • delete an employee?
  • invite an employee?
  • approve leave?
  • transfer an employee?
  • view payroll?
  • restore a former employee?

Every answer changes the software.

It can affect:

  • database structure
  • authorization
  • API design
  • service logic
  • UI workflows
  • audit requirements
  • testing
  • security
  • operational cost

The ambiguity existed before implementation.

The architecture simply exposes it later.

This is why requirements matter.

The earlier ambiguity is discovered, the cheaper it usually is to correct.


Requirements Are Not Features

One of the most important distinctions is between a business problem, a requirement, and a feature.

A client says:

"We need a dashboard."

That's a proposed solution.

Ask:

"Why?"

Maybe the real problem is:

"Finance managers cannot quickly identify overdue customer payments."

Now the requirement becomes:

"Authorized finance users must be able to identify overdue customer balances and prioritize collection actions."

The eventual feature could be:

code
Payment Aging Dashboard
        +
Overdue Invoice Table
        +
Filtering
        +
Notifications
        +
Collection Workflow

The feature came after understanding the requirement.

This distinction matters because stakeholders often describe what they think should be built.

Engineers need to discover why it needs to exist.

A useful mental model is:

code
Business Problem
      ↓
Desired Outcome
      ↓
Requirement
      ↓
Feature
      ↓
Implementation

Don't start at the bottom.


The Three Questions Behind Every Requirement

When someone gives you a requirement, don't immediately ask:

"How do we build this?"

Ask three questions first.

1. Why?

What business problem are we solving?

2. What?

What capability does the system need?

3. Under What Conditions?

What rules, permissions, constraints, and exceptions apply?

Consider:

"Users should be able to transfer organization ownership."

Why?

The current owner is leaving the company.

What?

Ownership must be transferred to another eligible member.

Under what conditions?

Perhaps:

  • the target must belong to the organization
  • the owner cannot transfer ownership to themselves
  • only one active transfer request can exist
  • the target must accept the request
  • the request expires after 72 hours
  • the operation must be transactional
  • the transfer must be audited
  • notifications must be sent

Now we have something engineers can actually design.

The original sentence was only the beginning.


How Engineers Discover Requirements

Requirements rarely arrive in a perfectly structured document.

They are usually discovered through conversations, observation, existing systems, documents, and prototypes.

Ask People to Explain the Workflow

A weak interview asks:

"What features do you want?"

A better question is:

"Walk me through what happens today."

Suppose you're building an expense management system.

Don't only ask:

"Do you need expense approval?"

Ask:

"What happens when an employee submits a $500 expense?"

You may discover:

code
Employee submits expense
        ↓
Manager reviews
        ↓
Large expenses require additional approval
        ↓
Finance validates receipt
        ↓
Approved expense goes to payroll
        ↓
Employee is reimbursed
        ↓
Audit history is preserved

The requirement wasn't simply:

code
Expense → Approved

It was a business workflow.

Observe the Work

Users sometimes cannot explain everything they do because much of their workflow has become habitual.

An accountant might say:

"I just reconcile the transaction."

But observation might reveal:

code
Export bank statement
        ↓
Normalize dates
        ↓
Match transaction IDs
        ↓
Search invoice numbers
        ↓
Compare amounts
        ↓
Resolve discrepancies
        ↓
Send exceptions to finance

The real requirement may be:

"Reduce manual reconciliation effort while preserving traceable exception handling."

Observation exposes implicit requirements.

Bring Stakeholders Together

Different departments often have different expectations.

HR might say:

"Managers should edit employee information."

Finance might say:

"Managers shouldn't edit salary information."

Security might say:

"Sensitive changes must be audited."

The requirement becomes more precise:

code
Managers
   ↓
Can edit permitted employee data
   ↓
Compensation changes require additional authorization
   ↓
Sensitive changes are audited

Workshops are useful because contradictions become visible before implementation.

Study Existing Systems

If you're replacing an old system, don't assume it has nothing useful to teach you.

Look at:

  • existing workflows
  • spreadsheets
  • reports
  • APIs
  • database schemas
  • approval forms
  • policies
  • integrations
  • historical behavior

Existing software often contains years of accumulated business rules.

Sometimes the best requirements are hiding inside:

what the current system already does.

Use Prototypes

People often discover missing requirements when they see something concrete.

Imagine showing:

code
Expense #1042

Employee: John
Amount: $1,450
Category: Travel

[Approve] [Reject] [Request Changes]

The stakeholder says:

"Managers shouldn't approve anything above $1,000."

Excellent.

The prototype just revealed a business rule.

Prototypes aren't only design tools.

They're requirement discovery tools.


Ask About Failure, Not Just Success

Most people naturally explain the happy path.

For example:

"A customer places an order and we ship it."

But production systems need answers to:

  • What if payment fails?
  • What if payment succeeds but order creation fails?
  • What if inventory disappears?
  • What if the customer cancels?
  • What if the address is invalid?
  • What if the order is partially shipped?
  • What if the payment provider sends the same webhook twice?
  • What if the external service is unavailable?

The happy path is usually easy.

The exceptions define the real system.

This is why one of the most valuable questions in requirement engineering is:

"What happens when things go wrong?"

And an even stronger one is:

"What must never happen?"

For example:

code
Payments
→ Customer must never be charged twice.

IAM
→ A user must never access another tenant's data.

Payroll
→ An employee must never be paid incorrectly.

Inventory
→ Stock must not become negative unless explicitly allowed.

Ownership
→ Two people must never become owners simultaneously.

These statements reveal business invariants.

And invariants are extremely valuable architectural information.


Functional vs Non-Functional Requirements

Another important distinction is between functional and non-functional requirements.

Functional Requirements

These describe what the system does.

Examples:

  • Users can create invoices.
  • Managers can approve expenses.
  • Employees can submit leave requests.
  • Administrators can deactivate users.
  • Customers can reset passwords.

Non-Functional Requirements

These describe how the system should behave or what constraints it must satisfy.

Examples:

  • APIs should meet a defined latency target.
  • Sensitive data must be encrypted.
  • Protected resources require authentication.
  • The system must support a defined number of concurrent users.
  • Audit records must be retained for a specified period.
  • The service must meet an agreed availability target.

A simple mental model:

code
Functional
=
Capability

Non-Functional
=
Quality + Constraint + Operational Expectation

Both can change architecture.

Imagine:

code
System A
50 internal users
Single region
Business hours

versus:

code
System B
5 million users
Multiple regions
24/7 operation
High availability

Both could have:

"Users can create profiles."

But System B may require:

  • caching
  • replication
  • partitioning
  • queues
  • rate limiting
  • CDN
  • horizontal scaling
  • observability
  • disaster recovery

The feature didn't change.

The constraints did.


Requirements Shape Architecture

A useful mental model is:

code
Business Goal
      ↓
Requirements
      ↓
Constraints
      ↓
Architecture
      ↓
Implementation

Consider:

"Every financial change must be traceable."

That requirement might influence:

  • database design
  • transaction boundaries
  • audit tables
  • event logging
  • authorization
  • API design
  • service boundaries
  • data retention

Another example:

"A payment must only be completed once."

That can lead to:

  • idempotency keys
  • unique constraints
  • event IDs
  • transaction boundaries
  • webhook verification
  • retry handling

Another:

"An organization can only access its own data."

That can influence:

  • authentication
  • authorization
  • database queries
  • service-layer rules
  • background jobs
  • caching
  • testing

This is why requirement engineering is not separate from architecture.

Requirements are constraints on architecture.


Requirements Create Domain Models

Consider:

"An organization has members with different roles."

Simple?

Not for long.

You need to ask:

  • Is a role global or organization-specific?
  • Can one member have multiple roles?
  • Who can assign roles?
  • Can roles be removed?
  • Are permissions inherited?
  • Can roles change over time?
  • Should role changes be audited?

You may eventually discover:

code
Organization
      ↓
Membership
      ↓
Role
      ↓
Permission

The requirement didn't simply create a UI.

It created a domain model.

The same thing happens with:

  • orders
  • payments
  • invoices
  • employees
  • subscriptions
  • ownership
  • verification
  • inventory

A requirement often contains the seeds of the domain model.


Current State Isn't Always Enough

Suppose:

"John is a manager."

That's current state.

But six months later someone asks:

"Was John a manager when he approved expense #10042?"

Now you need historical state.

This is why enterprise systems often need to answer:

"What was true when this event happened?"

That can affect:

  • audit design
  • financial records
  • reporting
  • authorization history
  • compliance
  • event storage

Consider an employee who leaves the company.

You might not want:

code
DELETE Employee

Instead:

code
Employee.status = inactive

Why?

Because historical payroll, expenses, approvals, and audit records may still depend on that employee.

This leads to an important principle:

Business history is often more important than current state.


A Ticket Is Not a Requirement

A ticket says:

"Add employee deletion."

Don't immediately write:

code
def delete_employee():
    ...

Ask:

"What does delete mean in this business?"

It could mean:

Hard Delete

The record disappears.

Soft Delete

The record remains but is marked inactive.

Deactivation

The employee loses access but historical records remain.

Archival

The employee moves into a historical state.

Termination

A business event occurs and triggers downstream workflows.

These are completely different behaviors.

The ticket gave you a verb.

Your job is to discover the domain meaning behind the verb.


User Stories Are Useful — But Not Enough

Consider:

As a manager, I want to approve an expense so that employees can be reimbursed.

That's useful.

But you still need to know:

Preconditions

code
Expense exists
Expense is submitted
Manager has permission

Rules

code
Manager cannot approve their own expense
Large expenses require additional approval

State Transition

code
Submitted → Approved

Failure Cases

code
Already approved
Already rejected
Permission removed

Audit

code
Who?
When?
What changed?

A user story describes intent.

It doesn't necessarily describe the complete system behavior.


Think in State Machines

Many business processes are really state machines.

For example:

code
Draft
  ↓
Submitted
  ↓
Under Review
  ↓
Approved
  ↓
Completed

Not every transition is valid.

For example:

code
Draft → Completed

may be forbidden.

And:

code
Approved → Rejected

may be impossible.

Once you recognize the state machine, the requirement becomes much clearer.

You can define:

code
State
Transition
Actor
Permission
Condition
Side Effect

This model is useful for:

  • orders
  • payments
  • invoices
  • expenses
  • leave requests
  • ownership transfers
  • verification
  • onboarding
  • procurement
  • support tickets

A workflow isn't just a sequence of screens.

It's a set of valid state transitions.


Requirements Can Define Transactions

Consider ownership transfer:

code
Validate target
      ↓
Accept request
      ↓
Remove old owner
      ↓
Assign new owner
      ↓
Create audit event

What happens if the old owner is removed but the new owner isn't assigned?

The organization could become invalid.

So the requirement may be:

"Ownership transfer must happen atomically."

That's not merely a coding preference.

It's a business integrity requirement.

It can lead directly to:

  • database transactions
  • consistency rules
  • locking
  • failure handling
  • service boundaries

Business requirements can become database requirements.


Requirements Can Define Security Boundaries

Consider:

"Organizations can manage their own users."

That sentence contains a security boundary.

The system must guarantee:

code
Organization A
      ↓
Authorized Users

cannot access:

code
Organization B
      ↓
Private Users

This affects more than the UI.

It affects:

  • queries
  • services
  • APIs
  • authentication
  • authorization
  • background jobs
  • caching
  • logging
  • tests

For multi-tenant systems, tenant isolation isn't just an implementation detail.

It's a requirement.


Requirements Should Be Testable

Consider:

"The application should be fast."

Everyone agrees.

But how do you test it?

A better requirement might be:

"95% of API requests under the expected workload should complete within 300ms."

Now it is measurable.

The same principle applies to business behavior.

Instead of:

"Managers can approve expenses."

Use something closer to:

Given an authorized manager and a submitted expense, when the manager approves it, the expense transitions to Approved, the approver and timestamp are recorded, and an audit event is created.

Now:

  • the developer knows what to build
  • QA knows what to test
  • the buyer knows what to expect

That's the value of acceptance criteria.


Requirement Validation

After discovering requirements, validate them.

Ask:

Is it correct?

Does it represent the real business need?

Is it complete?

Are important cases missing?

Is it consistent?

Does it conflict with another requirement?

Is it feasible?

Can the system realistically satisfy it?

Is it testable?

Can we objectively determine whether it works?

Is it traceable?

Can we connect it to the business goal, implementation, and tests?

A requirement such as:

"The system should be secure."

is too broad.

Break it into observable guarantees:

code
Protected endpoints require authentication.
Users cannot access another tenant's resources.
Sensitive actions are audited.
Reset tokens expire.
Authorization is enforced server-side.
Payment confirmations are verified server-side.

Now the team can actually build and test against it.


Ambiguity Is Expensive

Imagine a requirement misunderstanding happens during week one.

The team discovers it before implementation.

Maybe the solution is a conversation and a revised workflow.

Now imagine the same misunderstanding is discovered after production.

You may need:

  • database migrations
  • API changes
  • frontend changes
  • data migration
  • regression testing
  • security review
  • deployment changes
  • customer communication

The exact cost varies.

But the principle is consistent:

The later ambiguity is discovered, the more expensive it becomes.

This is why requirement engineering isn't bureaucracy.

It's risk management.


Estimation Starts With Understanding

Developers are often asked:

"How long will this take?"

But estimating an ambiguous requirement is mostly guessing.

Compare:

Requirement A

"Build reporting."

Requirement B

"Finance managers need monthly revenue reports filtered by organization, branch, customer, product category, payment status, and date range. Reports must support CSV export and preserve historical transaction values."

Requirement B is much easier to estimate.

Not because it's necessarily smaller.

Because uncertainty has been reduced.

Better requirements don't make work magically disappear.

They make the work visible.


Prioritization Is Also Risk Management

Not every requirement deserves the same priority.

A practical model:

Must Have

The system cannot provide its core value without it.

Should Have

Important, but not essential for the first release.

Could Have

Useful, but optional.

Won't Have Now

Explicitly outside the current scope.

But business priority isn't the only consideration.

Technical risk matters too.

Consider:

"Integrate with the bank's payment system."

It sounds like one feature.

But it may involve:

  • authentication
  • webhook verification
  • retries
  • idempotency
  • reconciliation
  • settlement
  • refunds
  • duplicate events
  • failure recovery

That requirement may deserve early investigation even if it isn't the most visible feature.

A useful prioritization model considers:

code
Business Value
+
Technical Risk
+
Dependencies
+
Cost
+
Security Impact

Requirement Changes Need Impact Analysis

Requirements don't stop changing when development begins.

Businesses change.

Customers change.

Regulations change.

New information appears.

Suppose the buyer says:

"Managers should also be able to approve payroll."

Don't simply add a permission.

Ask:

"What else changes?"

Potentially:

code
Authorization
     ↓
Workflow
     ↓
Payroll Data Access
     ↓
Audit
     ↓
Notifications
     ↓
Reporting
     ↓
Compliance
     ↓
UI
     ↓
Tests

This is why:

"It's just a small change."

can sometimes become a very expensive sentence.

A requirement change can have architectural consequences.


What Great Engineers Actually Do

Great engineers don't just translate tickets into code.

They ask:

Is this the real problem?

What assumption are we making?

What happens when it fails?

Who is allowed to do this?

What happens to historical data?

What if the request is duplicated?

What if two users act simultaneously?

What if an external service is unavailable?

What happens when the business grows?

What must never happen?

These questions reveal the system's true boundaries.

That's engineering judgment.


The Difference Between Working Software and Correct Software

A system can technically work.

The API returns 200.

The UI looks beautiful.

The database is normalized.

The tests pass.

And the product can still be wrong.

Why?

Because:

Implementation correctness does not guarantee business correctness.

You can implement the specification perfectly and still fail if the specification misunderstood the business.

That's why one of the most important questions isn't:

"Did we build it correctly?"

It's:

"Did we define the right thing correctly?"


The Real Engineering Loop

A mature development process looks more like:

code
Understand
   ↓
Question
   ↓
Model
   ↓
Validate
   ↓
Design
   ↓
Implement
   ↓
Test
   ↓
Observe
   ↓
Learn
   ↓
Refine

Not:

code
Ticket
  ↓
Code
  ↓
Deploy

The second approach may feel faster.

The first approach is much more likely to produce software that survives real-world complexity.


For Buyers: Ask Better Questions

If you're buying serious software, don't ask only:

"How quickly can you build this?"

Ask:

"How will you make sure you're building the right thing?"

Before development begins, you should expect discussion around:

  • business goals
  • workflows
  • users
  • roles
  • permissions
  • data
  • integrations
  • exceptions
  • performance
  • security
  • scalability
  • reporting
  • operational requirements

A developer who asks difficult questions isn't necessarily slowing your project down.

They may be preventing expensive mistakes.


For Developers: Your Value Isn't Just Code

Frameworks change.

Libraries change.

Cloud services change.

Programming languages evolve.

But the ability to understand ambiguous problems remains valuable.

A developer who can:

  • discover requirements
  • challenge assumptions
  • model domains
  • identify invariants
  • understand workflows
  • design secure boundaries
  • reason about failure
  • preserve business history
  • evaluate tradeoffs

is solving a much bigger problem than implementing endpoints.

Your value isn't simply:

code
How fast can I write code?

It's:

code
How accurately can I turn
an ambiguous business problem
into a reliable system?

That's a much harder skill.

And a much more valuable one.


The Question Worth Remembering

Before writing the first line of code, ask:

"What do we need to know before we can confidently build this?"

That question may expose:

  • an unclear business rule
  • an undefined permission boundary
  • missing historical requirements
  • an unknown failure scenario
  • an architectural constraint
  • a security risk

And finding those things early is usually far cheaper than discovering them after production.

Because in software engineering:

A fast developer can build the wrong thing quickly.

A strong engineer makes sure the right thing is being built in the first place.


Frequently Asked Questions

What is requirement engineering?

Requirement engineering is the process of discovering, analyzing, documenting, validating, prioritizing, and managing what a software system needs to accomplish and the constraints it must satisfy.


Why is requirement engineering important?

Because a technically correct implementation can still be the wrong product if the underlying business problem or expectations were misunderstood.


Are requirements the same as features?

No.

A requirement describes what the system needs to achieve or guarantee. A feature is a concrete capability used to satisfy that requirement.


What is the difference between functional and non-functional requirements?

Functional requirements describe what the system does.

Non-functional requirements describe qualities and constraints such as performance, security, scalability, reliability, and availability.


Why should developers ask about edge cases?

Because production systems rarely operate only on the happy path. Failure scenarios, duplicate requests, concurrency, and external-service failures often determine the real architecture.


Should developers code before requirements are complete?

For small, low-risk changes, some ambiguity can be resolved during implementation.

For significant features, important business rules, security boundaries, constraints, and acceptance criteria should be sufficiently understood before committing to the design.


Can requirements change after development starts?

Yes.

Requirements evolve as businesses learn, users provide feedback, regulations change, and new constraints appear.

The important part is understanding the impact of those changes instead of treating them as isolated edits.


How do requirements influence architecture?

Requirements can shape database design, transactions, authorization, APIs, state machines, event processing, audit systems, caching, scalability, and operational behavior.


Key Takeaways

  • Great software starts with understanding the problem, not choosing a framework.
  • Requirements are not the same as features.
  • Ask why, what, and under what conditions.
  • Discover both the happy path and failure paths.
  • Functional requirements define capabilities.
  • Non-functional requirements define quality and constraints.
  • Requirements can directly shape architecture.
  • Historical data can be as important as current state.
  • Authorization and tenant isolation are requirement-level concerns.
  • Business invariants should be explicitly identified.
  • State transitions reveal hidden complexity.
  • Transactions and idempotency can emerge directly from business requirements.
  • Acceptance criteria turn vague expectations into observable behavior.
  • Requirement changes should trigger impact analysis.
  • Great engineers don't just implement tickets—they challenge assumptions.
  • Better questions reduce ambiguity, rework, cost, and architectural surprises.
  • Thinking is part of engineering.

If you found this article useful, share it with fellow backend engineers, software architects, founders, product managers, and engineering leaders who want to build software that solves the right problem—not just software that works.


About the Author

Anik Sikder is a Software Engineer specializing in Backend Systems, SaaS Architecture, Cloud Infrastructure, Python, Django, FastAPI, distributed systems, and scalable software engineering.

He writes about system design, networking, distributed systems, cloud computing, software architecture, business automation, and modern engineering practices.

$ tags

requirement-engineeringengineering-practicessoftware-architecturesystem-designbusiness-analysisdomain-modelingsoftware-engineeringbackend-engineeringsaasenterprise-systemssoftware-development

$ ls related_articles

status: end_of_file

Related Blueprints

Continue exploring related architecture patterns.

Multi-Tenant SaaS Architecture

Designing tenant-aware platforms with strong data isolation, scalability, and shared infrastructure efficiency.

01Schema-per-tenant isolation
02Tenant-aware request routing
03Shared infrastructure model
04Secure data segregation
05Subscription-driven tenancy

TalentFlow HCM (Human Capital Management Platform)

Enterprise-grade human capital management platform designed to unify employee lifecycle management, payroll operations, recruitment workflows, attendance tracking, performance management, and workforce analytics within a secure multi-tenant architecture.

01WebSocket-first real-time communication
02Versioned contracts and acceptance workflows
03Double-entry escrow and wallet ledger
04Atomic milestone state transitions
05Transactional outbox and idempotent events
06Dispute-driven fund freezing
07CQRS read models for messaging and transactions

FinCore Treasury (Financial Operations & Treasury Platform)

Architecture blueprint for a multi-tenant treasury platform covering bank connectivity, cash management, payment orchestration, reconciliation, approval governance, immutable financial accounting, and event-driven financial operations.

01Multi-bank cash visibility
02Event-driven payment orchestration
03Automated reconciliation engine
04Tiered approval governance
05Immutable financial ledger