A developer working on an embedded IoT data pipeline recently found themselves deep in a familiar kind of trouble. Their team had been building a many-to-many data system in Rust, and after a week of chasing down architectural code smells, they arrived at a diagnosis that pointed back to a well-worn book on design patterns. The story is worth unpacking because it captures something real about how good intentions in software architecture can curdle into complexity.
The Problem: Too Many Moving Parts
The project involved an embedded IoT pipeline where numerous heterogeneous modules needed to exchange data. The team had been using Rust micro traits to adapt each struct's interface to work across a variety of data channels. On the surface, this approach seemed flexible. Under the surface, it was creating a thicket of abstractions that made the system hard to extend and harder to reason about.
The developer described a growing sense of unease within the team. There was a shared feeling that things could be better, a low-grade uncertainty that had its own name in dev slang: FUD. The temptation to reach for an LLM and ask it to refactor the abstractions away was acknowledged but rejected. That approach, the developer noted, felt like putting band-aids on top of band-aids. A diagnosis was needed, not a patch.
The Diagnosis: Decorator Overload
The breakthrough came from pulling out a physical copy of the classic Design Patterns book. The developer's mentor had made them study it years earlier, and the reference proved decisive. Flipping through its pages, they recognized the pattern of their own mistakes. The system had become over-decoratorized.
The book lays out two specific problems with the Decorator pattern. First, a decorator and its component are not identical. A decorator wraps an object, but from an identity standpoint, the decorated object is no longer the original. If code relies on object identity, it will break. Second, Decorator-heavy designs produce systems composed of many small objects that look alike. The objects differ only in how they connect to one another, not in their class or the values stored inside them. Such systems are easy to customize once you understand them, but they are genuinely hard to learn and debug.
In the Rust context, these two symptoms mapped directly onto the codebase. Structs were being decorated via trait implementations just to conform to interfaces, and in the process the original struct information was being lost. Then there were simply too many structs, too many traits, too many generics, all interlocking in ways that made the overall architecture opaque.
The Remedy: The Mediator Pattern
With the diagnosis in hand, the search turned to the book for a solution. The Mediator pattern offered a clean path forward. Rather than having modules refer to each other directly through a web of trait implementations and decorators, the pattern recommends encapsulating collective behavior in a single mediator object. That mediator controls and coordinates interactions among a group of objects. The objects know only the mediator, which dramatically reduces the number of interconnections.
This approach addressed the specific need the team had: a central place to define data transformation and packet protocol across many heterogeneous modules. The developer spent the next day drawing out the object diagram, working through the structure until the project became clear in their head. Presenting that diagram to the team cleared away the collective uncertainty. As a team lead, the act of translating the architectural confusion into a concrete visual model turned out to be one of the most valuable contributions they could have made.
Why This Matters Beyond One Project
The developer acknowledged the common dismissiveness toward design patterns. Some would say the answer is obvious: just code well from the start, and patterns are an unnecessary crutch. But the reality of agile development is messier than that. Progress often happens with architecture as an afterthought, an emergent property of iterative work. When that emergence produces something smelly, it helps to have a vocabulary and a set of established solutions to diagnose and fix it.
The mentor who made that developer study the book years ago had been preparing them for exactly this moment. Not every problem requires a new approach. Sometimes the answer is hiding in a chapter you have already read, waiting for you to recognize the pattern.