Why a "small" software change can realistically take a week
For non-engineering clients who want to understand why a one-line request can still take days. This guide explains where the time actually goes, what risks are being managed, and how to tell the difference between padding and necessary work.
TL;DR — A small visible change can touch many hidden parts of a live system: code, database, tests, deployment, security, analytics, and rollback planning. The most likely reason it takes a week is not typing speed; it is safely changing production software without breaking existing behavior, data, or integrations. Reading time: ~7 min
What it is and where it sits
When a client says, "It is just a small change," they usually mean the visible result is small: one new field, one button label, one extra rule, one email tweak. In software delivery, the visible change is only the tip of the work.
A production system usually has several layers:
- the browser or mobile app the user sees
- the frontend (the UI code)
- the backend (the server-side application)
- the database (where data is stored)
- third-party services like payments, email, analytics, CRM, or identity providers
- infrastructure like hosting, DNS (the internet phonebook), TLS certificates (the encryption setup), logging, backups, and monitoring
A small request can sit in one place visually but require changes across several of these layers.
For example, "add a required VAT number field to checkout" sounds tiny. But where does it sit in the architecture?
- The frontend must display the field and validate it.
- The backend must accept it and reject bad input.
- The database may need a new column.
- The order confirmation email may need to include it.
- The admin panel may need to show it.
- Analytics may need to track whether the field reduces conversion.
- Existing orders without that field must still load correctly.
Here is a typical request flow:
User browser
|
v
Frontend form
|
v
Backend API ----> Third-party services (email, payments, CRM)
|
v
Database
|
v
Admin/reporting/analytics
What does this replace? Often, nothing. That is the point: the team is not swapping one isolated part for another. They are extending a system that already works and already has users, data, and dependencies. That makes the work less like editing a document and more like modifying plumbing in an occupied building.
How it actually works
Let us walk one realistic example end to end: "Add a company VAT number field to checkout, make it required for business customers, and show it in the admin order view."
Step 1: Clarify the rule
Before coding, the team has to pin down behavior that sounds obvious but usually is not:
- Is the field required for all customers or only some countries?
- What counts as a valid VAT number?
- Should existing customers be forced to add it later?
- Should the field appear on invoices and emails?
- What happens if the CRM or accounting system does not have a matching field?
This is often where "one day" becomes "three days" if the rule is still moving.
Step 2: Find every place the data flows
The engineer traces the path of order data through the system:
- Checkout page form
- API endpoint that receives the order
- Database table storing orders or customer billing details
- Admin page where staff review orders
- Email template for order confirmation
- Export or webhook (an automatic notification to another system) to accounting or CRM
Missing one of these creates bugs that only appear later: support cannot see the value, exports fail, or old records break the admin page.
Step 3: Change the data model safely
If the database needs a new field, this is not just "add a column and ship it." Live systems need backward compatibility (old and new versions can coexist briefly during deployment).
A safe sequence is usually:
- Add the new database column as optional.
- Deploy backend code that can read and write it.
- Deploy frontend code that starts sending it.
- After traffic proves stable, optionally enforce stricter rules.
Why not make it required immediately? Because during deployment, one server may run the old code while another runs the new code for a few minutes. If the database changes are too strict too early, orders can fail.
Step 4: Update validation and business logic
The frontend may check "field cannot be blank," but the backend must also validate it. Users can bypass browser checks, and integrations may call the API directly.
The backend also needs rules like:
- if customer type = business, VAT number is required
- if customer type = individual, ignore or store as optional
- if field is too long or malformed, return a clear error
Step 5: Update dependent outputs
Now the team updates everything downstream:
- admin order details page
- PDF invoice or invoice export
- confirmation email template
- analytics event schema if reporting needs the new field
This is where many "small changes" get larger: the system is not one screen, it is a chain.
Step 6: Test the risky paths
A responsible team does not only test the happy path. They test:
- business customer with valid VAT number
- business customer with blank VAT number
- individual customer without VAT number
- existing old order records with no VAT number
- admin page loading old and new orders
- email rendering when the field is missing
If the app has automated tests, they are updated too. That takes time now but saves emergency fixes later.
Step 7: Deploy with rollback in mind
Deployment is not "press publish" for most custom systems. The team usually:
- merges the code
- runs CI/CD (automated build, test, and deploy pipeline)
- applies the database migration (a scripted schema change)
- checks logs and error monitoring
- verifies checkout, admin, and email behavior in production
- keeps a rollback plan ready if conversion drops or errors spike
That final verification is part of the work. If the change affects checkout, the agency is touching revenue. Caution is not bureaucracy; it is risk control.
When to use it (and when not to)
The useful question is not "Why does this take a week?" but "Does this request touch enough risk that a week is reasonable?"
| Scenario | Recommendation |
|---|---|
| Text-only copy change in a CMS-managed page | Usually same day or next day. You probably do not need a full engineering cycle. |
| CSS spacing, color, or label tweak in one isolated screen | Usually small, unless the design system or approvals are complex. |
| New field that must be stored, validated, exported, and shown in admin | A few days to a week is normal. It crosses UI, backend, database, and operations. |
| Change to login, payments, checkout, permissions, or data deletion | Expect careful handling. These are high-risk paths. |
| Change that affects existing records or requires data migration | Slower is normal. Data mistakes are expensive to undo. |
| "Just add one rule" in a legacy system with poor tests | You probably do not want a fast change here. Speed without safety often creates outages. |
You probably do not need a week if...
- the change is content, not code
- the value already exists in the database and only needs to be displayed
- the page is not connected to other systems
- there are no approval, compliance, or release-window constraints
- the team can prove the area is well tested and isolated
You should expect more time if...
- the request sounds simple but changes business rules
- customer data, billing, or permissions are involved
- multiple environments exist (staging, production, regional deployments)
- there is a formal QA step, security review, or client approval round
- the system is older and undocumented
Trade-offs
Every benefit in software delivery has a cost.
| Benefit | What it costs |
|---|---|
| Safer releases with fewer production bugs | More testing, review, and staging time |
| Backward-compatible database changes | Extra implementation steps instead of one quick edit |
| Good rollback options | More planning and sometimes temporary duplicate logic |
| Clear validation and edge-case handling | More code than the visible feature suggests |
| Integration consistency across admin, emails, exports, and APIs | More coordination and more places to update |
| Auditability and approvals for sensitive changes | Slower turnaround and more process |
A fast change is cheaper today but can be more expensive tomorrow if it causes:
- lost orders
- bad invoices
- broken reports
- support workload
- emergency hotfixes
- customer trust damage
That does not mean every delay is justified. Sometimes slow delivery is a sign of poor architecture, weak tooling, or unclear ownership. A good agency should be able to explain the time in concrete terms: "half a day for schema change, one day for frontend and backend, one day for testing, half a day for deployment and verification," not just "software is complicated."
In practice
Below are two concrete examples of the kind of work hidden inside a "small change."
Example 1: Database migration for a new field
⚠️ Database changes can cause downtime or data loss if written incorrectly. Apply schema changes in a staging environment first, take a backup or confirm point-in-time recovery is enabled in your hosting database dashboard, and schedule production changes outside peak hours.
In your cloud database or app platform dashboard, look for a path like Databases → Your database → Backups first. If your team uses migrations, the actual change may look like this:
ALTER TABLE orders
ADD COLUMN vat_number VARCHAR(32);
CREATE INDEX idx_orders_vat_number ON orders(vat_number);
This adds a nullable column first, which is the safer pattern for live systems. The gotcha: do not add NOT NULL immediately unless every existing row already has a value and every running app instance is ready for the new rule.
If your team uses a migration tool in CI/CD, they might run something like:
npm run migrate
That command is simple, but the important part is when it runs relative to the app deploy.
Example 2: Backend validation that matches the business rule
{
"customerType": "business",
"vatNumber": "GB123456789"
}
And a server-side validation example in JavaScript:
function validateCheckout(payload) {
const errors = [];
if (payload.customerType === "business" && !payload.vatNumber) {
errors.push({ field: "vatNumber", message: "VAT number is required for business customers" });
}
if (payload.vatNumber && payload.vatNumber.length > 32) {
errors.push({ field: "vatNumber", message: "VAT number must be 32 characters or fewer" });
}
return errors;
}
This enforces the rule on the server, not just in the browser. The gotcha: if the frontend requires the field but the API does not, other integrations can still submit bad data; if the API requires it too aggressively, older clients may break during rollout.
Example 3: Admin display that handles old records safely
<tr>
<th>VAT number</th>
<td>{{ order.vat_number || "—" }}</td>
</tr>
This shows the new field in the admin view without crashing on older orders. The gotcha: old data is normal in production, so templates and reports must handle missing values gracefully.
Further reading
- The "Database Migrations" section of your framework's official docs
- The "HTTP: Conditional Requests" and related caching chapters of the MDN HTTP docs
- Martin Fowler, "Evolutionary Database Design"
- The PostgreSQL documentation, "ALTER TABLE"
- The "Deployment" section of your CI/CD platform's official docs
This article was written by an AI system and published pending human review. Verify anything you intend to act on.
Have a project in mind?
Get an instant AI price estimate for it, or talk directly to our team.
One email a month on what we learn building with AI