The hidden costs of additions to a system


Product and Tech your-code-is-not-the-most-important-thing system-thinking hidden-costs

"The natural bias towards adding is strong and pervasive"

–Alberto Brandolini, Event Storming

Software engineers that were never exposed to the cost of their “additions” throughout their careers (in my experience, most developers who never worked at an early stage startup) will have a tendency towards adding complexity instead of reducing it (or at least maintaining it).

They’ve never paid the price of maintaining those things they added because in bigger organizations they probably:

  • moved teams more often, causing other people to pay the bill they created and/or;
  • they had a Devops/Security/Finance team to offload part of this cost and/or;
  • they were so focused on delivering tickets instead of value that they did not even realize that the work they are doing now is a consequence from their own decisions a couple of months back, and which could 100% be avoided.

Systemic thinking would allow them to see the impact of their additions not just in the short term but also in the long term, not just to the current technical system but to the overall people’s system that is the organization they are part of.

When doing a cost-benefit analysis of a given solution, you must take into account its hidden costs even if you are not the one paying it later on. Remember that as a value creator your goal is to save time and reduce stress to people around you.

Example of additions with lots of hidden costs:

  • a new database
  • a new programming language
  • a new framework
  • a new pattern in the codebase
  • a new external service
  • a new server-to-server communication protocol (eg. REST, SOAP, GraphQL, gRPC) or pattern (eg. sync, event-driven)

And the most neglected hidden costs:

  • higher onboarding cost of new team members
  • higher context switching costs when working on that codebase or system
  • higher surface area of things that can break
  • higher surface area of things you need to monitor
  • extra monitors you need to setup
  • extra alerts you need to setup
  • extra security patches and updates you need to be on top
  • extra possible unknown-unknowns for your team that can cause outrages

If you add all of those hidden costs up it will be clear to you that you’d need a REALLY strong reason for justifying that addition. That the reason should be based on the company goals and objectives for the long term, not just the optimal solution to the ticket at hand.

As an extreme example, would you believe if I told you that you probably could have your current architecture at your current scale with just a server and postgres?

”No way, I handle payment processing at a high scale and I need a queuing system.” Well, postgres natively supports that via tables storing payment events and consumers using SELECT FOR UPDATE SKIP LOCKED semantics.

“Okay, but I need Elasticsearch as a search engine for fuzzy text search.” Sure, but pg_trgm gives you fuzzy and partial matching, ranking, and even stemming directly in SQL.

“Hum… Ok, but for a specific part of the data structure we really need MongoDB for it’s flexible JSON documents.” Postgres has JSONB that you can query nested structures, index them, and still join them with relational data.

And the list goes on:

  • background jobs -> jobs table + grab tasks with FOR UPDATE SKIP LOCKED
  • recurring jobs → pg_cron for native scheduling
  • pub/sub → LISTEN / NOTIFY for lightweight real-time notifications
  • analytics → window functions, CTEs, and materialized views for reporting
  • columnar storage → cstore_fdw for analytical queries
  • machine learning → MADlib for in-database regressions and clustering
  • ETL and pipelines → http_fdw + pg_cron for scheduled data ingestion and transformation
  • caching layer → UNLOGGED tables or materialized views as durable caches
  • geospatial queries → PostGIS for coordinates, distances, and shape operations
  • vector search → pgvector for embeddings and similarity search
  • policy enforcement → Row-Level Security (RLS) for user-level access rules
  • configuration store → versioned config tables with constraints and history
  • auditing → triggers + JSONB logs for a full change history
  • REST API → PostgREST automatically exposes CRUD endpoints
  • GraphQL API → Hasura for instant GraphQL on top of Postgres
  • file storage → bytea or large objects for small to medium files

Again, this an extreme example and it doesn’t mean that keeping everything in postgres is going to be the right answer for all your use cases. I just added it here to show you what’s possible and to challenge you to think about this question on any given feature: “How can I achieve this business or technical objective by introducing the minimum amount of complexity, now and for the long run, for me and for my peers?”

---

This is a sample chapter/section from Your code is not the most important thing in the world.

If you're a software engineer working on product teams and found this useful, you might enjoy my book Your Code is Not the Most Important Thing in the World — it's all about understanding value creation, making value-driven trade-offs, communicating with excellence and knowing how to navigate organizations.

Learn more on the book page
© 2026 Leonardo Max