Bad software does not always start with bad code. Often, it starts with a poorly understood problem. See how clear requirements reduce rework and lead to better architecture decisions.


You know when a project starts with a simple sentence?
“We need a scheduling system,” “we need a dashboard,” or “we need a subscription area.”
At first, that seems like enough. The team already starts imagining screens, endpoints, databases, integrations, and even a few architecture decisions.
But soon, the unanswered questions start appearing:
That is where a lot of complexity starts to appear. Not because the code is impossible, but because, at that point, the understanding of the problem is still insufficient.
Software built on assumptions usually sends the bill later: rework, scope changes, hidden rules, missing tests, and technical decisions made too early.
Requirements Engineering comes in precisely at this point: before we start building, we need to understand the problem, the rules, and the constraints.
There is no value in producing a huge document that nobody reads. Documentation exists to align business, users, product, and technology before a vague idea turns into code.
TL;DR
Requirements Engineering helps turn vague requests into clear understanding.
The goal is not to document everything excessively, but to reduce uncertainty: understand what needs to be built, why it matters, which rules must be respected, and how to validate whether the solution actually works.
A requirement is a clear and usable representation of a need: something that a change, process, or solution must satisfy to create value or meet a condition.
It helps answer questions such as:
A common mistake is treating a requirement as a synonym for a feature.
A feature is one possible delivery. A requirement is the need that justifies that delivery.
For example:
The same applies to technical decisions.
Saying “we need Kafka” jumps straight to the solution. Maybe Kafka makes sense, maybe it does not. The underlying requirement could be:
We need to process events with fault tolerance, without losing messages, and with the ability to reprocess them.
Now the conversation changes.
Instead of discussing technology based on preference, the team starts discussing which solution best satisfies the problem.
The clearer the requirement, the less the technical decision depends on guesswork.
Bad requirements usually do not start as a code problem.
They start in communication.
One person makes the request, another turns it into scope, someone else decides how to build it, and in the end, the user may receive something different from what they actually needed.
The comic is decades old and still describes modern projects. The drawing exaggerates on purpose. The problem it shows does not.
The client imagines one thing. Product understands another. Development implements another. And the user may have needed something much simpler, something they could not even explain clearly themselves.
This mismatch happens because each person looks at the problem from their own context:
None of these perspectives is necessarily wrong. The problem appears when they remain implicit and everyone assumes they understood the same thing.
The role of requirements is to make these interpretations visible before they turn into scope, code, and rework.
A good requirement is not the longest text.
It is the shared understanding that reduces ambiguity between those who request, decide, build, and use the solution.
Not every requirement describes a system feature.
Some explain why a change needs to happen. Others represent the needs of users and involved areas or define what the solution needs to deliver.
There are different ways to organize requirements. In this article, we will use a practical division that follows the path between the problem and the solution:
The arrow does not indicate importance or execution order. It shows that each level exists because of what is above it.
In practice, this becomes a useful question: if we take a requirement from the bottom, can we trace it back to a business outcome? When the answer is no, there is usually a conversation missing before we start building.
Business rules and constraints also participate in this path, but they play a different role: they guide or limit solution requirements.
Business requirements explain why a change needs to happen and what outcome the organization expects to achieve.
They describe objectives, problems, or desired results without necessarily defining how the solution will be built.
A simple way to recognize them is to ask: what business outcome justifies this initiative?
Reduce by 40% the number of subscription cancellations processed manually by support.
This requirement does not describe a screen, an endpoint, or a specific system action. It defines the outcome that motivated the change.
From it, different solutions could be considered: allowing customers to cancel by themselves, improving the support team's internal process, or automating part of the service.
The business requirement sets the direction. The solution comes later.
can be users, customers, support, finance, legal, operations, security, or any other party affected by the change.
Their requirements describe what these people or areas need to achieve the expected outcome.
It is not simply a requirement “requested by someone.” It captures a need of someone affected by the change without deciding yet how the solution will satisfy it. While the business requirement explains the desired outcome, the stakeholder requirement makes clear who needs what to get there.
A simple way to recognize them is to ask: who is affected by the change, and what does that person or area need?
The customer needs to cancel their subscription without contacting support.
Support may have another need related to the same process:
Support needs to see who canceled the subscription, when the action happened, and through which channel.
Neither statement fully defines the solution. They show the needs of different stakeholders that will have to be addressed.
It is common for these perspectives to conflict. The customer wants fewer steps, while security may require an additional confirmation. Product wants a simple experience, while finance needs to preserve traceability.
Requirements Engineering helps make these conflicts visible before they become implicit decisions in the code.
Solution requirements describe what the solution needs to provide to meet the needs of the business and its stakeholders.
They are commonly divided into:
This distinction helps separate the capabilities of the solution from the quality conditions under which those capabilities need to operate.
Functional requirements describe behaviors, capabilities, and responses of the solution.
In other words: what the system must do.
Some examples:
A simple way to recognize them is to ask: is there an observable action or response that the system needs to perform?
When the payment is approved, the system must activate the subscription and send a confirmation email to the customer.
This is a functional requirement because it describes actions the system needs to perform: activate the subscription and send the confirmation.
The behavior can also happen without direct human interaction. Jobs, integrations, events, and automated processes are still functional when they describe something the system does.
Non-functional requirements describe quality characteristics and the conditions under which the solution needs to operate.
They do not necessarily describe what the system does, but rather the performance, security, availability, reliability, or scale under which a capability must work.
Compare:
The user must be able to search for orders.
This is a functional requirement because it describes a capability.
The search must respond within two seconds for 95% of requests under normal operating conditions.
This is non-functional because it defines the expected performance for that capability.
Simply saying that a system must be “fast,” “secure,” or “scalable” is still vague. Whenever possible, the requirement should be observable, measurable, or verifiable.
Other examples include preventing sensitive data from appearing in logs, maintaining a given monthly availability level, or generating tracing identifiers across services.
A simple way to recognize them is to ask: does this requirement define the performance, security, availability, or reliability under which the solution needs to operate?
There are also gray areas.
“Allow two-factor authentication” can be considered functional because it adds behavior to the system. “Protect accounts against unauthorized access,” on the other hand, represents a broader security objective.
The classification helps organize the conversation, but it should not turn into an argument over terminology.
Transition requirements exist only to move the operation from the current state to the new one. They may involve data migration, training, gradual rollout, or temporary coexistence with legacy systems.
A simple way to recognize them is to ask: does this need disappear once the change is fully operational?
Before the new system is released, active subscriptions must be migrated with their plans and renewal dates preserved.
What separates them from the others is their expiration date. Once the transition is complete, they stop being necessary, while the other requirements continue to describe the solution in operation.
Business rules and constraints do not represent needs at the same level as the previous requirements.
They accompany this path from the outside, defining decisions that must be respected or limits that reduce the available options as the solution takes shape.
Business rules represent policies, decisions, and conditions that belong to the company or domain.
They define how a situation must be handled, regardless of whether there is a system automating it.
A simple way to recognize them is to ask: what decision has the business made for this situation?
When a subscription is canceled, the customer keeps access until the end of the already paid period.
This is a business choice.
Another company could terminate access immediately or refund the proportional amount. Neither alternative is technically more correct. The organization decides which policy applies.
From this rule, functional requirements may emerge to cancel the renewal, keep the subscription active until a specific date, prevent new charges, and notify the customer.
The business rule defines which policy the system's behavior must respect.
The functional requirement describes what the system must do to apply that policy.
Constraints are limits that reduce the options available to the project.
They do not necessarily describe a user need or a desired quality. They determine which paths the solution may or may not take.
They may come from technical, financial, legal, operational, organizational, or contractual sources.
Some examples:
A simple way to recognize them is to ask: does this condition limit a technology, infrastructure, cost, schedule, operational, or compliance choice?
The system must integrate with the company's current ERP because the financial process will remain centralized there.
This constraint reduces the options available to the solution. Even if a technically better alternative exists, the project still needs to work with the current system.
Another example would be requiring customer data to remain stored on servers located in Brazil. The source may be legal, contractual, or organizational, but the effect is the same: it limits infrastructure decisions.
The difference between a non-functional requirement and a constraint may seem small.
A non-functional requirement defines an expected result or quality:
The service must remain available for 99.9% of the month.
A constraint limits how the solution can be built:
The service must run on the AWS infrastructure already contracted by the company.
The first defines quality. The second reduces options.
Data, security, integration, compliance, accessibility, and domain concerns often receive their own treatment in documentation. That helps organize the material, but it creates a trap: the topic starts to look like a category.
Many of these areas describe non-functional requirements, such as performance, availability, reliability, observability, and maintainability. Others describe behavior, business policies, or limits imposed on the project. The topic may be the same. The nature of the need is not.
Security makes this clear. Four statements about the same topic, four different categories:
The goal is not to find the perfect label, but to keep every need, rule, and limit clear, validated, and visible to those who will decide, build, and test the solution.
How to identify them quickly
Turning a need into a requirement is not about filling out a document in a straight line.
The team discovers information, analyzes conflicts, records its understanding, and validates it with the people involved. When a new question appears, the process goes back a few steps. In practice, elicitation, analysis, specification, and validation happen iteratively.
Let's use the same request as a thread throughout the process:
I want the user to be able to cancel a subscription.
Before discussing a screen or endpoint, we need to understand what problem exists and why it is worth solving. In this case, the goal may be to reduce support requests, give customers more autonomy, and shorten service time.
Without context, the team risks delivering a cancel button that looks correct but does not solve the pain that motivated the change.
Elicitation is the work of discovering what is still unclear. This can happen through conversations, interviews, data analysis, process observation, workshops, or prototypes.
For cancellation, the questions begin to appear:
Analysis turns separate answers into a coherent decision. This is where conflicts become visible: the customer wants fewer steps, finance wants to avoid improper refunds, and support needs access to the history.
In this case, the business may decide that cancellation stops only the next renewal, keeps access active until the end of the already paid period, and does not generate an automatic refund. These decisions become rules that the solution needs to respect.
Specification means recording the understanding clearly enough to guide implementation and testing.
The customer may cancel the automatic renewal of an active subscription at any time.
After cancellation, access must remain available until the end of the already paid period. The system must record the date and the person responsible for the action and send a confirmation email to the customer.
Recording a requirement is not about writing more. It is about writing in a way that business, development, and testing can interpret consistently.
| Vague | Verifiable |
|---|---|
| The system must be fast | Search must respond within 2 seconds for 95% of requests. |
| Send an email | The system must send an email after the payment is approved. |
| The user can cancel | The customer may cancel the automatic renewal of an active subscription. |
| The report must work | The report must respect the same filters applied to the listing. |
Validation means confirming that the requirement represents what the business, users, and affected areas actually need. In our example, we should confirm the access policy, the absence of an automatic refund, the history required by support, and whether the behavior can be tested.
The answers should not be invented by the development team. A requirement is only complete once the understanding has been validated by people who know the product, the process, and the business rules.
AI can help summarize conversations, find ambiguities, and suggest questions or acceptance criteria. But it does not know the company's context on its own, nor can it decide which policy the business should adopt.
When validation reveals a different decision from what was documented, the requirement goes back to analysis or specification. That is why these steps do not form a queue. Reworking something here costs a conversation. Discovering it after implementation costs rework.
Architecture should emerge from requirements, not from technology preferences. The requirement is what makes a decision necessary and allows us to evaluate whether its cost and complexity make sense.
Most of the time, it is not the functional requirement that drives an architecture decision. Two systems may cancel subscriptions in exactly the same way and still have very different architectures. What separates them is the required quality: how long a response may take, how long the system may remain unavailable, or how much history needs to be preserved.
| Need | Possible technical impacts |
|---|---|
| Low latency | indexes, cache, and pagination |
| High availability | redundancy, health checks, and fallback |
| Auditability | logs, history, and tracing |
| External integration | timeout, retry, and idempotency |
| Heavy reports | asynchronous jobs and export |
Notice that the left column is still vague. “Low latency” does not decide anything by itself: responding in 2 seconds and responding in 200 milliseconds lead to different architectures, with different costs. The requirement only guides the decision once it becomes a number.
Every added piece also comes with a cost. Cache brings invalidation and stale-data risk. Queues bring ordering, reprocessing, and another failure point. Replicas bring synchronization. The benefit often appears quickly, and the bill arrives in operations.
Before asking whether we need cache, a queue, microservices, or a separate database, we need to understand which requirement makes that decision necessary. One way to check is to reverse the question: if we remove this component, which requirement stops being satisfied? When nobody can answer, it probably entered the architecture by preference.
Requirements change because the team learns more about the problem, the business changes direction, or operations reveal limits that were not visible at the beginning. That is normal.
Almost every team has seen a small request affect far more than expected. The problem is not the change itself. It is accepting it without evaluating what it affects: business rules, integrations, data, architecture decisions, acceptance criteria, and tests.
When the change makes sense, update the requirement, the related criteria, and the tests. It is also worth preserving the reason behind important decisions and maintaining enough traceability between the need, requirement, implementation, and validation.
Documentation does not need to become a huge matrix to be useful. It only needs to keep reflecting what the team decided to build and why.
Before we wrap up, five quick questions about requirement types, rules, constraints, and how they affect architecture:
Along the path from business to stakeholder to solution requirements, what does moving from one level to the next represent?
Requirements Engineering is not bureaucracy. It is about reducing uncertainty before it turns into code, rework, and the wrong technical decision.
The work starts by understanding the problem, moves through needs, rules, and constraints, and ends with requirements clear enough to guide implementation, validation, and evolution.
When that happens, architecture and System Design stop being guesses. They become consequences of what the business and operations actually need.
Now open the last requirement your team wrote and try to trace it upward: does it lead to a business outcome? If the answer does not come quickly, you have found a conversation that should have happened before the code.
Software Architect and Engineer | Java & AI