Why "Small" Changes Are Not Always Small

Share
Why "Small" Changes Are Not Always Small

An honest look at what happens behind the screen when you submit a feature request

I'm sure everyone in the western world has had the thought "Why can't the developers of this software or product just do X and Y? It would be such a simple and quick change that would make using this product so much better".

However, for those that write code or have studied and looked into the world of programming, you know that "small changes" are not always small and simple. Programming computers, software, and webpages etc has been steadily (or rapidly at times) been growing in complexity. That complexity involves many many layers, mostly because we no longer live in a world where a company or team writes every line of code from scratch. They use "parts" that others have written, pre-built libraries, frameworks, and APIs etc. No online company writes all their code from scratch, because there is no need to reinvent the wheel, just build on top of what someone else has already done.

In general though, first there is the front end, what the end user (you and me) see when interacting with a webpage or software. Then there is the back end (the code that developers wrote for how it works). Then there is the database (where data like you name and settings are stored) and the "calls" that get made from the front end to the back end to the database and how it all gets sent back to the browser on your computer or app on your phone.

The "Just Add a Button" Illusion

Different feature requests or changes to the code require different layers of the programming artitecture to be changed, different amounts of time to accomplish based on the complexity, and different level and amount of QA testing to prove the changes implemented work as expected.

You're using your facility management software. You notice something that would make your life easier — a new filter option on the search bar, a different color scheme on your dashboard, a notification when a task finishes, or a new integration with a tool your team just adopted.

"It should be a quick fix," you think. "It's just one small thing."

You submit a feature request. A week later, it's still not done. Two weeks. A sprint goes by. You wonder: Are they ignoring me? Did it get lost? Why is this taking so long?

It's not being ignored. The truth is that what looks like one small change from the outside often touches multiple layers of a software system — and each layer has its own complexity, rules, testing requirements, and risk profile.

This article explains, what those layers are (using a programming architecture of 6 layers, common in the real world), why some changes are fast and others are slow, and how development teams estimate the effort before writing a single line of code.


Software Is a House, Not a Spreadsheet

Most people imagine software the way they imagine a spreadsheet: you click a cell, type a new formula, and the result updates instantly. If only building software were that simple.

A better analogy is a house. If you want to paint a wall a different color, that's quick — buy the paint, grab a brush, tape off the parts you don't want paint to get on, and your maybe done in an afternoon. But what if you want to move a wall? Suddenly you need to check whether it's load-bearing, reroute the plumbing, update the electrical, replaster, repaint, inspect, and possible get more contractor or permits involved. What looked like "just move the wall over a few feet" becomes a multi-day project involving multiple trades.

Software works the same way. Like stated earlier, modern applications are built in layers — each layer has a job, and the layers depend on each other. A change that looks small on the surface (what you see on the screen) might ripple through one, two, three, or even several layers of the system underneath.

Although different softwares have different number of layers depending on what programming language they are written is and their overall programming architecture, in this article we are going to go over a programming software that has 6 layers: UI, HTTPS/API call, business logic, controllers, database, and scheduled jobs.


The Typical Layers of a Software Application

When a developer receives your feature request, the first thing they do (or ask their agent to do) is figure out which layers of the codebase this change will touch. Here is a real world example of software using six layers (very typical):

1. UI Design — What You See

The user interface. This is the page, the buttons, the dropdowns, the grid, the form the end user can see and interact with in their browser. If the feature request is "change the color of this button" or "move this field to the top of the form," it likely only touches this layer.

Think of it like repainting a wall.

2. HTTPS / API Call — How Systems Talk to Each Other

When your software page needs to send specific data or get specific data in order to update parts of the software webpage, typically HTTPS calls, specifically API (Application Programming Interface) calls are involved. Liking posts or images on social media, adding products to your shopping cart online, and typing into a search bar on a webpage are good examples. Also, if you software needs data from another system (like a payment provider, data from a third party integration like Slack or Zapier, or a third-party calendar). It's like making a phone call over the internet to the company's server for specific data or to another company's server requesting the needed data.

Think of it like calling a supplier to order a new part for your house — you don't need a whole new house and you don't control the external supplier, but you send a request with what you need hopefing to get something specific.

3. Business Logic (Service Layer) — The Brains

This is where the actual thinking happens. This code decide what the software does, what each click in the browser is supposed to do based on the user who clicked it, what subscription level they are on, what settings they have enabled etc. When you click "Complete" on a task, the service layer decides: Is this allowed? Does this person have permission? Are there dependencies? Does this trigger anything else? If your feature requires new rules or new behavior, this layer gets dragged in.

Think of it like the wiring and plumbing inside the walls — you can't see it, but everything depends on it working correctly and defines where you plug things in and where water comes out.

4. Controller — Traffic Control

The controller is the middleman between the UI and the service layer. When you click a button, the controller receives the request, decides which service to call, passes the data, and returns the result to the page. Every page has one or more controllers managing the conversation. Examples are PostLikeController, which handles the HTTPS/API call from the browser when a user clicks to like a photo in a social media app and sends it to the service layer to make that like on a post actually happen or SearchSuggestionController, which handles the HTTPS/API call requests when a user uses the search bar on a webpage and sends their search to the service layer to process the request and then send back the correct search results.

Think of it like a switchboard operator routing calls to the right department.

5. Database — Where Data Lives

The database stores everything: user accounts, event schedules, list of users in the platform or social media app, files the users uploaded, profile or software settings. If the feature requires saving new information, changing how existing data is stored, or running a complex query (like "show me all users in Colorado that like hiking and love pizza"), the database layer is involved.

Think of it like the foundation of the house, the structure of the house, and the filing cabinets in the basement full of important documents - it defines the layout of the house and houses all the information regarding the house structure, materials, blueprints etc.

6. Scheduled Job — Background Work

Some things in software don't happen when you click a button. They happen automatically, on a schedule — every night at 2:00 AM, every 15 minutes, or on the first of every month. Syncing data to an external system, sending reminder emails or emails about "people you may want to connect with", running a cleanup process — these are "scheduled jobs." If the feature requires something to happen automatically in the background, this layer joins the party.

Think of it like the sprinkler system — it runs on a timer, and if you want to change what it does, you need to reprogram the whole controller box.


How Long Does Each Layer Take? (The Real Data)

Depending on the size of the codebase, the programming language, and complexity of the software, the time to make changes to one or more layers greatly differs. Using the example artitecture above, the time it would take a developer to adjust code in each layer, assuming whatever change they were making only required them to touch one layer, would be as follows:

When Only One Layer Is Changed

Layer Avg. Days Median Days
UI Design only 0.80 0.50
HTTPS / API only 0.85 1.00
Database only 1.58 1.50
Service Layer only 3.00 3.00
Scheduled Job only 2.00 2.00

A UI-only change (a simple visual tweak) takes, on average, less than one day to develop. That's a half-day of writing code and a half-day of testing.

A database-only change — modifying a stored procedure, adding a column to a table, writing a new query — takes nearly two days. Why? Because database changes are risky. One wrong column in a query and the page breaks. One bad stored procedure and the entire event system stops loading. Database changes require careful design, testing against real data volumes, and often a deployment window.

When Multiple Layers Are Touched

Most real-world feature requests touch more than one layer.

Layers Touched Avg. Days Example
1 layer 1.16 Change a button text
2 layers 0.99 Fix a page that also tweaks a query (small bug fix)
3 layers 0.99 Page + controller + database bug fix
4 layers 1.30 New page + new service + new API + new table
5 layers 1.31 Dashboard overhaul touching everything
All 6 layers 1.57 Full-stack feature: new UI, new controller, new service, new API call, new scheduled sync, new database table

Here's what might surprise you: changes touching 2-3 layers average less time than changes touching only 1 layer. Why? Because many 2-layer and 3-layer changes are small bug fixes or feature requests — a page that displays something wrong or lacking something and needs a small database query tweak to fix it or enhance it. These are fast, focused fixes that an experienced developer can knock out in an hour or two once they understand the root cause.

The real cost shows up at 4+ layers, when you're not fixing a bug or just doing an enhancement — you're building something genuinely new. That's when average estimates climb to 1.3-1.6 days, and that's before QA testing, code review, staging deployment, and release scheduling.

When a Specific Layer Is Present (alone or with others)

This table shows the average estimate for any task where the layer shows up — whether alone or in combination with others:

Layer Tasks Avg. Days
Database (present anywhere) 178 1.17
UI Design (present anywhere) 163 1.10
HTTPS / API (present anywhere) 110 1.21
Controller (present anywhere) 81 1.13
Service Layer (present anywhere) 81 1.20
Scheduled Job (present anywhere) 42 1.50

Scheduled jobs are the most expensive layer. When a task involves changing code that runs automatically on a schedule, the average jumps to 1.50 days. That's because scheduled code is invisible — you can't click a button and see it work. You have to write it, deploy it, wait for the schedule to trigger under normal and real world conditions, confirm the results, and debug if something went wrong.

By Issue Type

Issue Type Tasks Avg. Days
Bug 148 0.95
QP (Quick Pick) 42 1.48
Project 38 1.71
Integration 5 1.90
New Feature 4 2.50

Bug fixes, depending on what they are, can be the lightest — averaging under one day. This is because the code already exists and just needs a tweak t be corrected. New features (things that have never been written before into the code) as you can imagine are the heaviest — averaging 2.5 days. If the software has external integrations, time spent on those code changes or updates are usually higher as well, driven by the complexity of working with external systems you don't control.


How Industry Data Compares

These numbers align closely with what's reported in the software industry at large. Agile methodology — the standard framework used by most modern development teams — recognizes that estimates must account for not just the time to write code, but for design, testing, code review, and deployment. Industry-standard "story points" (the unit agile teams use to indicate effort) consider complexity, risk, and the amount of uncertainty involved, not just how long a task would take if everything went perfectly.

Atlassian, one of the leading authorities on agile development methodology, defines estimation as accounting for "the work, the risk, and the complexity" of a task. The numbers above in this article show that risk and complexity (measured by how many layers are touched) dominate the estimate more than the raw size of the change.

In other words: don't focus on "how many lines of code changed." Focus on "how many layers did this touch, and how risky is each one."


Business Logic: .NET vs. Python vs. Go

The business logic layer — where the thinking happens — is where the programming language matters most. Different languages have different characteristics that affect how fast a change can be made. Here's a plain-English comparison:

.NET (C#) — What eSPACE Is Built On

.NET is a strongly typed language, which means the code is very strict about what data goes where. If you try to put text where a number should be, the compiler catches it before the code ever runs. This makes refactoring safer — you can change something and get immediate feedback about what else breaks. However, .NET projects tend to have deep inheritance hierarchies (classes that inherit from classes that inherit from interfaces), which means tracing through the layers takes experience. There's also a recompilation step — after editing code, the project must be rebuilt before you can test it. For large projects, that can take several minutes.

Best for: Large enterprise applications with complex business rules and many developers working simultaneously.

Speed of changes: Moderate. Strict typing makes changes safer but slightly slower to prototype.

Python — Quick to Write, Riskier to Change

Python is dynamically typed — you don't declare what type of data goes into each variable. This makes writing new code extremely fast. You don't need to compile anything — you just save the file and refresh. But this same flexibility means that changing existing business logic is riskier. If you change a function's behavior and something breaks, you might not find out until the code runs in production and crashes. Testing is more important with Python because the compiler won't catch type errors.

Best for: Startups, data-heavy applications, scripts, prototyping.

Speed of changes: Fast to write, slower to verify safety. Changes require comprehensive test coverage to avoid regressions.

Go (Golang) — Fast and Simple

Go was built by Google specifically to solve the problem of large codebases that take too long to compile and are hard to maintain. Go compiles in seconds (not minutes), has a minimalist syntax (fewer language features means fewer ways to overcomplicate things), and enforces strict formatting so all code reads the same way. However, Go deliberately avoids some advanced features (like inheritance or generics until recently), which means business logic that's complex in nature can require more boilerplate code — more lines of straightforward, repetitive code instead of fewer lines of abstract, clever code.

Best for: High-performance backend services, microservices, scheduled jobs.

Speed of changes: Fast compilation and simple syntax make iterations quick, but writing complex business rules can be more verbose than in Python or C#.

The Bottom Line on Languages

Language Compile Time Type Safety Change Speed Risk Level
.NET (C#) Moderate (minutes) Strict Moderate Low — compiler catches errors
Python None (interpreted) Dynamic Fast to write Medium — type errors surface at runtime
Go Seconds Medium Fast iterations Low — strict compiler + fast feedback

Softwares using C# as their programming language use a structured, well-organized codebase with strict type checking, which is slower to explore but safer to modify. Softwares using Python are faster to write code changes in but require more testing to ensure nothing breaks. In Go, the code changes compile fast but might require more lines of code to express the same logic (complexity in a software).


Real-World Feature Requests: How Much Effort?

Here are four common requests that different software companies receive from customers, what each one actually involves, and how many layers and days of effort it takes (based on the 6 layer example).


Example 1: "I Want to Customize the Colors of Items on My Dashboard"

What the customer sees: "I just want to change the colors. Can't you add a color picker?"

What the developer sees: The dashboard renders data using a chart library (Kendo UI, DevExpress, or a similar component). The colors are currently hardcoded in the UI layer — meaning the color values are written directly in the code. To let users customize colors, the developer needs to:

  • UI Layer: Add a color picker control to the dashboard settings page, store the selected color values, and apply them when the chart renders. (~0.5-1 day)
  • Database Layer: Create a new table (or add columns to an existing one) to store each user's color preferences. Write queries to save and load them. (~0.5-1 day)
  • Controller Layer: Add a new controller action to receive the color preference save request and route it to the service. (~0.25 day)
  • Service Layer: Add logic to validate the color values (prevent invalid formats, enforce limits on how many custom colors can be saved per user). (~0.5 day)

Layers touched: 4 (UI, Database, Controller, Service)
Estimated effort: ~2-3 development days
Plus: QA testing across different browsers, testing with existing dashboard configurations, release scheduling

Why it's not "just add a color picker": The color picker is the easy part. The hard part is making the color choices persistent — they need to survive page reloads, be unique to each user or organization, play nicely with existing theme settings, and be validated so someone doesn't save a malicious value. That's why a 4-layer change averages 1.3 days of development work, plus testing and deployment.


Example 2: "I Want Custom Notifications When Tasks Are Completed on My Dashboard"

What the customer sees: "Just send me an email or a notification when my task is done."

What the developer sees: This is more complex than it sounds because "when a task is completed" requires the system to detect the completion event, decide who should be notified, look up their preferred notification method, and send the message. Here's what the developer needs to do:

  • UI Layer: Add a notification preferences panel where users can opt in/out and choose their notification method (email, SMS, dashboard alert). (~1 day)
  • Controller Layer: Add controller actions for saving notification preferences and for acknowledging/dismissing notifications. (~0.5 day)
  • Service Layer: Write the notification engine — when a task status changes to "Complete," evaluate who should be notified, assemble the message body, and dispatch it. This is the most complex piece because it needs to handle edge cases: what if the user was the one who completed the task? What if they have notifications turned off? What if the task was auto-completed by the system? (~1.5-2 days)
  • Database Layer: Add tables for notification preferences, notification queue/log, and notification templates. (~0.5-1 day)
  • Scheduled Job Layer: If notifications are sent in batches (e.g., a digest email every morning summarizing completed tasks), add a scheduled job that runs on a timer, checks the queue, and dispatches. This is the layer that makes this request expensive. (~1 day)

Layers touched: 5 (UI, Controller, Service, Database, Scheduled Job)
Estimated effort: ~4-5.5 development days
Plus: Testing the scheduled job (you have to wait for it to run), testing across user permissions, email deliverability testing, handling notification failures

Why it's not "just send an email": You're not just sending an email — you're building a notification system. The system needs to know who to notify, when, how, and what to do if the notification fails. Scheduled jobs average 1.50 days alone, and this feature requires one.


Example 3: "I Want a New Integration with Another Third-Party Software So Changes Automatically Sync"

What the customer sees: "I want changes in eSPACE to show up in [other system] automatically. I know they have an API."

What the developer sees: This is the single most complex type of feature request. Integrations involve your system, their system, and the internet between them. You don't control the other company's API, their rate limits, their authentication changes, their downtime, or their data format. Here's what's involved:

  • HTTPS / API Layer: Implement authentication with the third-party API (OAuth, API keys, or whatever they support). Build the HTTP client code to send requests, handle responses, and retry on failure. Handle rate limiting (if the other system allows 10 requests per second, you need to respect that). (~1.5-2 days)
  • Service Layer: Map eSPACE data fields to the third-party's data fields (e.g., eSPACE calls it "Event Name" but they call it "Title" — you need a field mapping). Handle data transformations, field mismatches, and conflict resolution (what if the same record was edited in both systems?). (~1.5-2 days)
  • Scheduled Job Layer: Build a background sync job that runs on a schedule, finds records that changed since the last sync, and pushes them to the other system. Handle edge cases: what if the sync fails halfway through? What if the other system is down? (~1-1.5 days)
  • Database Layer: Add tables to track sync state (when was the last successful sync? Which records have been synced? Which failed?). Store the API credentials securely. (~0.5-1 day)
  • UI Layer: Add a settings page for users to enter their credentials for the third-party system, configure what gets synced, view sync status, and see error logs. (~1 day)
  • Controller Layer: Add controller actions for the settings page and for manual sync triggering. (~0.5 day)

Layers touched: 6 (ALL six layers — full-stack change)
Estimated effort: ~6-8 development days
Plus: Testing against the live third-party API (which may have a test/sandbox environment, or may not), handling API changes, monitoring sync failures in production, providing support when the integration breaks

Why it's not "just call their API": Calling their API is one piece. The real work is building a system that stays in sync reliably — handling failures, retries, partial syncs, conflicts, rate limits, credential rotation, and giving users visibility into what's happening. New integrations in our data average 1.90 days of estimated time and complexity, but that's for simple integrations. Complex two-way sync requests can easily run a full sprint (8-10 days).


What the customer sees: "I want to filter by date range, building, status, and assignee all at once in the search bar."

What the developer sees: Search and filtering seems straightforward, but the complexity lives in the database. Each filter the user adds is another condition in the SQL query — and the more conditions you add, the more important it is that the query performs well. Here's the breakdown:

  • UI Layer: Add filter controls (date range picker, building dropdown, status multi-select, assignee search) to the search bar. Wire up the UI so filtering happens live as the user adjusts filters. (~1 day)
  • Controller Layer: Add a controller action that receives the filter parameters and passes them to the service layer. (~0.5 day)
  • Service Layer: Build the filtering logic — take the raw filter parameters, validate them (can't filter by a date in the year 3000), and construct the query. (~0.5-1 day)
  • Database Layer: This is where it gets interesting. The existing search query needs to be enhanced — or rewritten — to accept the new filter conditions dynamically. If the table has millions of rows, adding multiple filter conditions can slow the query to a crawl. The developer may need to add database indexes (pre-computed lookup tables that make queries faster) — and that requires testing against production-sized data volumes. (~1-2 days)

Layers touched: 4 (UI, Controller, Service, Database)
Estimated effort: ~3-4.5 development days
Plus: Performance testing (does the search still return results in under 2 seconds when filtering across a million records?), testing combined filter scenarios, ensuring adding filters doesn't break existing search behavior

Why it's not "just add more filters": Each filter adds a condition to the database query. Four simultaneous filters on a large table can slow the query dramatically — or return incorrect results if the conditions interact in unexpected ways. The database layer averages 1.58 days when changed alone, and adding complex filtering to an existing search often requires touching the schema (indexes) plus rewriting the stored procedure — that's a heavy change that needs careful testing.


The Hidden Costs You Don't See

Development time is only part of the picture. Every code change also requires:

  1. Code Review — Another developer reviews the code for correctness, style, and potential issues (~30 min to 2 hours per change)
  2. QA Testing — Someone tests the change against existing features to make sure nothing broke. For a 4-layer change, this can take a full day or more.
  3. Staging Deployment — The change is deployed to a staging (non-production) server and tested there before going live.
  4. Production Deployment — Scheduling a release window (often after hours or on a weekend).
  5. Regression Risk — Every change carries the risk of breaking something else. Even a UI-only change can break a page layout on a different browser or screen size.

Add all that up and a "2-day development estimate" often means a full week from start to release.

To summarize so far:


How to Write a Better Feature Request

Now that you understand the layers, here are examples of feature requests that effectively explain what you want and quickly help product teams and developers understand what code would be involved with that type of change:

Great Request: "I'd like to add a color picker to the dashboard so users can customize the colors of event blocks."

Why it's great: It's specific. It names the screen (the dashboard), the feature (color customization), and the scope (event blocks only). The developer can quickly identify the layers involved and estimate effort.

Great Request: "When a work order is marked Complete, I'd like an email sent to the assigned team's manager. I don't need it in real-time — a daily summary email at 8:00 AM would be fine."

Why it's great: You've defined the trigger (work order completed), the recipient (team manager), the deliverable (email), and the timing (daily at 8 AM). The developer knows immediately this needs a scheduled job + service + database — and they can estimate accurately.

Harder Request: "Make the dashboard show real-time data."

Why it's harder: "Real-time" means different things to different people. Are you OK with data updates every 30 seconds? Or do you want the display to update the instant something changes? Those are wildly different implementations — one is a simple refresh timer; the other requires a persistent connection technology (WebSockets) that touches every layer in the system. Specify what "real-time" means to you, and be open to the developer's recommendation for the best approach.

Harder Request: "Integrate with [system I just heard about]."

Why it's harder: Integration requests need to specify what data should flow in which direction, how often, and what should happen if the other system is unavailable. "Integrate with X" could mean a simple one-way weekly export — or a bi-directional real-time synchronization with conflict resolution. Those are 10x apart in effort.


The Takeaway

Next time you submit a feature request and it doesn't show up the next day, the next week, month etc, remember this:

  • What you see (the user interface) is only the tip of the iceberg. Underneath it are (in the example in this article and similar to the real world) five more layers — business logic, controllers, API/integration code, database, and background jobs.
  • The size of the visible change does not predict the size of the total effort. Changing one line on a page might take 30 minutes. Adding one filter to a search might take 3 days because of what it touches in the database.
  • Every change carries regression risk — the possibility that your "small change" breaks something unrelated. Testing takes time, and it's non-negotiable.
  • The more layers a change touches, the more days it costs. Our data shows 4+ layer changes average 30-60% more development time than single-layer changes. While you may not know what all your feature request requires, product teams and developers do.
  • Integrations are always more expensive than they look — you're not just writing code for your system, you're depending on someone else's system to behave correctly with your's, forever. This takes more time to investigate, write, and test before end user ever use it in in their browser.

While feature requests are easy to see and write from a customer standpoint, product teams and development teams have to evaluate the multiple layers of code underneath and understand how that change needs to be made. They have to think though what all layers might be affected, have time to write and test. Then QA teams will need time to test and make sure that not only does the code change work, but that nothing else is broken. Even with agentic AI advising teams on what code needs to change and how and what QA tests need to happen, all this still takes time.

In typical fashion, what one customer wants may not be what another requests and the more and wider spread the customer base is, the more feature requests start pouring in. All of these need to not just be approved, but prioritized. The best thing you can do is describe your request as specifically as possible, try to think though "what layers does this touch?" in your mind before you submit, and trust that teams are working as best they can to evaluate, prioritize, and plan when and what feature requests will land where on the product roadmap.

Bottom line, behind every "quick fix" is a system with multiple layers of complexity.

Read more