By using this site, you agree to the Privacy Policy and Terms of Use.
Accept
World of SoftwareWorld of SoftwareWorld of Software
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Search
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
Reading: Poor State Management Breaks Everything (and Why Distributed Systems Do It Better) | HackerNoon
Share
Sign In
Notification Show More
Font ResizerAa
World of SoftwareWorld of Software
Font ResizerAa
  • Software
  • Mobile
  • Computing
  • Gadget
  • Gaming
  • Videos
Search
  • News
  • Software
  • Mobile
  • Computing
  • Gaming
  • Videos
  • More
    • Gadget
    • Web Stories
    • Trending
    • Press Release
Have an existing account? Sign In
Follow US
  • Privacy
  • Terms
  • Advertise
  • Contact
Copyright © All Rights Reserved. World of Software.
World of Software > Computing > Poor State Management Breaks Everything (and Why Distributed Systems Do It Better) | HackerNoon
Computing

Poor State Management Breaks Everything (and Why Distributed Systems Do It Better) | HackerNoon

News Room
Last updated: 2026/02/05 at 10:24 AM
News Room Published 5 February 2026
Share
Poor State Management Breaks Everything (and Why Distributed Systems Do It Better)  | HackerNoon
SHARE

Imagine this: you’re in a team meeting, and your manager tells you there’s an old service, written a couple of years ago, that used to work fine but now breaks in some weird way. And you need to fix it. On top of that, they ask you to implement a new feature that the team has been wanting for a long time. At this point, your happiness for the next few hours, days, or even weeks largely depends on what the previous developer left behind.

You open the code and find… something. There are a few possibilities, depending on how careful the previous developer was.

Maybe they were a FORTRAN enthusiast doing a proof-of-concept who planned to rewrite the service before production. Design? Forget about it. Everything is stuffed into a single procedure.

Or maybe they were a true engineering guru: they defined a set of simple, strict abstractions that perfectly captured the domain, implemented everything cleanly, covered it with tests, and documented it.

Or something in between.

The closer the code is to the second scenario, the less pain you’ll have digging through it. Now, let’s put ourselves in the shoes of that service’s author. How do we get closer to the second scenario and further away from the first one?

My name is Dmitry, I’m a software engineer and Python mentor. My experience in real-world projects has shown me how painful dealing with implicit or messy state can be — very similar to the config issues I covered in my previous article.

In this article, I’ll show one approach — borrowed from distributed systems development — that helps you manage state responsibly, reduce overall code complexity, and ship features faster.

Why complexity matters

Software complexity affects almost every aspect of software engineering. The more complex an application becomes, the harder it is to:

  • read and understand its source code
  • add new features without breaking existing behaviour
  • predict how the system will behave under real load
  • reason about its internal state, and therefore…
  • …debug it when something inevitably goes wrong

What makes this especially dangerous is that complexity rarely announces itself. The code may still “work”, tests may still pass, and yet every change starts to feel risky. Progress slows down, confidence drops, and even small features begin to require disproportionate effort.

Two parts of complexity

For any non-trivial application, complexity comes in two very different forms.

1. Domain complexity

This is the complexity inherent to the problem you’re solving. If you’re building a weather forecasting system, you need to understand meteorology, statistics, and prediction models. There is no clever architecture or design pattern that can remove this complexity — and that’s a good thing.

Domain complexity is exactly what makes the application valuable. If you remove it, there’s no product left.

2. Accidental (or overhead) complexity

This is the complexity introduced by how the application is designed and implemented.

Here’s a simple thought experiment. Take a Python program and list every variable name it uses. Now replace each of them with a unique, randomly generated string. Then do a global search-and-replace in the source code.

Apart from some minor details, the program will behave exactly the same. You haven’t changed the domain logic at all — the type-1 complexity is untouched.

But the code will become dramatically harder to read, reason about, and modify. The overhead complexity has exploded.

The same thing is happening in the example from the introduction. The problem isn’t what the program does — it’s how that behaviour is packaged into the source code.

Why this distinction matters

Managing complexity is largely about reducing accidental complexity while preserving the essential one. And this is not a niche concern: complexity management has a direct and measurable impact on development speed, correctness, and team morale.

Most of the pain developers feel when working with legacy systems comes not from the domain being hard, but from the overhead complexity quietly accumulating over time.

Application design “gap”

Let’s look at the kinds of applications that are typically written in Python and loosely arrange them along the spectrum of size and complexity.

From smallest to largest, it often looks like this:

  1. Simple one-off scripts — essentially a replacement for small Bash scripts
  2. Medium-sized services or tools — for example, a configurable CPU fan control service
  3. Large distributed systems — systems that process significant amounts of data and must do so efficiently

These categories aren’t meant to be precise. They’re just a mental model.

For class-1 programs, design rarely matters. These scripts are short-lived, often written and maintained by a single person, and rarely evolve over time. Adding too much structure or abstractions usually brings little benefit.

On the other end of the spectrum, class-3 systems simply cannot exist without deliberate design. They are typically built and maintained by teams, which already requires shared abstractions and conventions. On top of that, distributed systems almost always involve persistent state — usually stored in a database — and multiple processes interacting with it concurrently. You need to define what state exists, where it lives, how it changes over time, and which components are allowed to modify it. Without clear answers to these questions, such systems fall apart very quickly.

For classes 1 and 3, the situation is clear: one doesn’t need design at all, and the other cannot survive without it.

The problem lies in the middle.

Class-2 applications are often just small enough that developers can get away with a loosely defined design — or no deliberate design at all. And this is where things quietly go wrong. Projects rarely shrink; they evolve. What starts as a simple tool or service can gradually grow into something that demands careful complexity management. When that moment arrives, the lack of an explicit design suddenly has an outsized impact on developer productivity, confidence, and delivery speed.

This gap — where an application is too big to stay ad-hoc, but not big enough to force proper design — is where most Python services slowly become painful to work with.

In my career, I’ve seen far more class-2 projects with unmanaged complexity than I’d ever like to admit. So instead of complaining about them, I want to share an approach I’ve been using successfully to keep such projects under control.

And the idea doesn’t come from typical “Python architecture” discussions.

It comes from distributed systems.

A closer look at distributed systems design

Earlier, we talked about class-3 systems and mentioned that their distributed nature — combined with a database — forces developers to maintain a clear design. Let’s take a closer look at why that happens.

You can think of any application as a black box that consumes inputs and produces outputs. Now imagine a horizontally scalable distributed system with a transactional database at its core. In such a system, workers can be added or removed dynamically based on load, and overall throughput increases as more workers are added.

A common way to achieve this is to keep workers stateless and move all shared state into the database. “Stateless” here doesn’t mean that workers have no state at all — every running program does — but that a worker’s local state is never relevant to other workers. To do its job, a worker only needs access to its own state and the database.

With this setup, workers are almost completely independent. The remaining challenge is state updates: workers still need to modify shared state in the database, and those updates could affect other workers. This is where transactions come in.

By defining what it means for the database to be in a valid state and using transactions to ensure that state only ever moves between valid states, the database itself enforces consistency. As a result, workers can be written under a simple assumption: the state they read from the database is always valid. This allows developers to reason about each worker in isolation, without caring about what other workers are doing at the same time.

Takeaways from distributed systems design

This design works extremely well for distributed systems and horizontal scalability, but its usefulness doesn’t stop there. It turns out to be a generally strong way to structure software — not just distributed systems, but applications in general.

At its core, this approach has a few important properties:

  • the structure of the application state is explicitly defined (typically via a database schema)
  • the application state is always valid
  • state evolution is clearly defined by the workers’ code
  • all interactions with the state follow a strict contract, which decouples components from each other
  • this decoupling allows components to be tested independently
  • testing is further simplified by the ability to mock the database
  • finally, the application state can be thoroughly inspected by directly querying the database

Together, these properties result in code that is clean, testable, and easy to reason about. This naturally raises a question: can the same ideas be applied to systems that are not distributed?

Applying these ideas to class-2 systems

The fact that class-2 systems don’t strictly require a carefully thought-out design doesn’t mean that such a design wouldn’t help. Having learned valuable lessons from distributed systems, it makes sense to try applying them here as well.

One obvious way to do that would be to turn a class-2 system into a distributed one. In some cases, that might even be justified. However, as a general solution it is rarely practical. Distributed systems backed by databases introduce significant overhead that plain Python projects don’t otherwise need:

  • hardware provisioning, including the database
  • networking
  • database management
  • database deployment and migrations

For many projects, this cost makes such an approach infeasible.

The good news is that distribution is not required to apply the core ideas. Below are two ways to borrow them without turning the application into a distributed system.

Option 1: no to distributed, no to a database

Most of the complexity-management benefits can be achieved simply by structuring the code around explicit state:

  1. strictly define the core application state (for example, using dataclasses or Pydantic models)
  2. define explicit state-update scenarios
  3. treat the core state as an external dependency by passing it into the functions that implement those scenarios (similar to dependency injection)
  4. avoid interaction between scenarios through anything other than the core state

This approach already gets you most of the way:

  • the state and its transitions are clearly defined
  • the state remains valid
  • transitions are decoupled
  • transitions are easy to test, especially since the core state is easy to mock

What’s missing here is state inspectability and the transactional guarantees provided by databases. The latter is usually not an issue in single-threaded applications, but it can become problematic in multi-threaded ones. In such cases, additional synchronization or libraries may be required — or you can move on to the second option.

Option 2: no to distributed, yes to a database

For most database systems, provisioning and operating them is a significant burden, which often rules them out for class-2 Python applications. However, there is at least one practical exception: SQLite.

SQLite is an SQL database that requires almost no setup and stores its entire state in a file. Despite its simplicity, it provides transactions and isolation guarantees, allowing you to retain many of the benefits of a production-grade database without the operational overhead. While SQLite has limitations in both functionality and performance, they are far less restrictive than many developers assume.

By using SQLite to store application state and applying the same design principles discussed for distributed systems, it’s possible to achieve the same complexity-management benefits — including state inspectability and transactional safety in multi-threaded scenarios.

Conclusion

In medium-sized Python projects, complexity rarely explodes all at once. It creeps in quietly and almost always involves poor state management. When the state is implicit, and its guarantees and assumptions are undocumented, every change becomes riskier than it should be.

Distributed systems ran into this problem early and solved it the hard way. By making state explicit and treating state changes as first-class operations, they found a way to keep complexity under control.

The same mindset works just as well in non-distributed Python code. You don’t need heavy infrastructure to apply it — just a clear model of state and disciplined rules for how it changes. Do that, and your codebase stays understandable, even as the project grows.

Sign Up For Daily Newsletter

Be keep up! Get the latest breaking news delivered straight to your inbox.
By signing up, you agree to our Terms of Use and acknowledge the data practices in our Privacy Policy. You may unsubscribe at any time.
Share This Article
Facebook Twitter Email Print
Share
What do you think?
Love0
Sad0
Happy0
Sleepy0
Angry0
Dead0
Wink0
Previous Article ISE 2026: Maxhub unveils partnerships, products to enrich unified collaboration | Computer Weekly ISE 2026: Maxhub unveils partnerships, products to enrich unified collaboration | Computer Weekly
Next Article Cozey’s Neptune Sofa Bed Is Firm, but It’s Also Flexible Cozey’s Neptune Sofa Bed Is Firm, but It’s Also Flexible
Leave a comment

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

Stay Connected

248.1k Like
69.1k Follow
134k Pin
54.3k Follow

Latest News

Why Trust Will Be the Defining Metric of 2026 |
Computing
Jabra PanaCast Room Kits, scalable video solutions for business meetings
Jabra PanaCast Room Kits, scalable video solutions for business meetings
Mobile
Anthropic reveals new Opus 4.6 model with more autonomy and better focus – 9to5Mac
Anthropic reveals new Opus 4.6 model with more autonomy and better focus – 9to5Mac
News
Ikea’s New Matter-Compatible Smart Home Devices Are Struggling to Connect
Ikea’s New Matter-Compatible Smart Home Devices Are Struggling to Connect
News

You Might also Like

Why Trust Will Be the Defining Metric of 2026 |

4 Min Read
How to Master Concurrency: Best Practices for Symfony 7.4’s Lock Component  | HackerNoon
Computing

How to Master Concurrency: Best Practices for Symfony 7.4’s Lock Component | HackerNoon

11 Min Read
AISURU/Kimwolf Botnet Launches Record-Setting 31.4 Tbps DDoS Attack
Computing

AISURU/Kimwolf Botnet Launches Record-Setting 31.4 Tbps DDoS Attack

5 Min Read
Want to own a piece of the Seahawks? Seattle startup presents its private equity idea to fans
Computing

Want to own a piece of the Seahawks? Seattle startup presents its private equity idea to fans

8 Min Read
//

World of Software is your one-stop website for the latest tech news and updates, follow us now to get the news that matters to you.

Quick Link

  • Privacy Policy
  • Terms of use
  • Advertise
  • Contact

Topics

  • Computing
  • Software
  • Press Release
  • Trending

Sign Up for Our Newsletter

Subscribe to our newsletter to get our newest articles instantly!

World of SoftwareWorld of Software
Follow US
Copyright © All Rights Reserved. World of Software.
Welcome Back!

Sign in to your account

Lost your password?