8 min read

You don't always own the environment

ESISSamsung
Engineering Story

Have you ever built something that worked perfectly on your machine, looked exactly as it should on staging, and then watched it fall apart when it reached the place where it was actually supposed to live?

I have.

Early in my career, I worked on the redesign of ESIS, short for eShopInShop. Samsung wanted a dedicated shopping experience inside retailers’ existing web shops. To the visitor, it looked and behaved like a Samsung web shop, with its own navigation, offers, product categories and product pages. The experience was entirely Samsung, but it didn't live in a standalone shop of its own.

ESIS itself was built in Vue 2 and delivered as a Web Component. It had its own structure, styles and conventions, and we treated it as an application of its own. But its UI still lived in the same document as the web shop hosting it.

And every one of those web shops already had a world of its own. Its technology, styles, libraries and years of accumulated decisions had nothing to do with us.

I knew that from the beginning. I knew the application was being integrated into other web shops, and I was given rules for working safely within that setup. Be careful with naming. Scope styles. Pay attention to selectors.

I followed them, but I didn't yet understand why those rules mattered as much as they did.

When the application meets its environment

Locally, the redesign could look exactly right. The same was true on our standalone staging environment. Then that same application would be integrated into the environment it was actually built to live in.

On one web shop, everything might still look exactly as expected. On another, part of the layout could suddenly behave differently. A slider could lose its styling. An icon could look wrong. Sometimes the problem was small and irritating. Sometimes a larger part of the layout could visibly break.

The application was the same. The environment around it wasn't.

At first, I mostly saw them as individual frontend problems. Something is overriding this. This selector isn't strong enough. These class names are colliding. This library is bringing more into the page than I expected.

So I got better at dealing with them.

That project taught me a lot of practical CSS. I learned to be careful about naming and scoping. Specificity stopped being a CSS concept I knew in theory and became something I had to think about in practice. I became much more conscious of global styles, third-party libraries and the assumptions hidden inside things that worked perfectly well when they were alone.

There was creativity in it too. Real environments have a wonderful habit of finding cases your clean development setup never showed you.

Eventually, I stopped being surprised. Not because those problems stopped happening, but because “it works on our staging” no longer felt like the end of the argument.

Our standalone environment wasn't the environment in which the software ultimately had to survive.

At the time, the lesson was mostly practical. Write CSS that can survive the integration. Years later, I find the reason behind those rules more interesting than the rules themselves.

The boundary the browser couldn't see

We treated ESIS as a separate application. However, the browser did not.

Both still lived in the same document.

The browser doesn't organize a document according to which team owns which part of the software. Elements in the light DOM participate in the same styling environment. CSS selectors match whatever elements they match. The cascade doesn't know that one button belongs to ESIS and another belongs to the host web shop.

We had ways of making that shared space safer. Careful naming reduced accidental collisions. Scoped styles helped keep component styles where they belonged. More careful selectors gave us better control over what we were targeting.

The techniques we used reduced the risk. But scoping isn't the same thing as encapsulation.

You can become very disciplined about sharing a space without creating a boundary that the browser itself enforces. It took me much longer to understand that than to learn the practical CSS rules.

What if the browser knew about the boundary?

Think of the two applications as roommates.

We weren't strangers who had accidentally dumped all our belongings into the same room. We were two clearly defined tenants with our own things and our own rules. We just still shared the apartment.

Careful naming, scoped styles and defensive CSS were ways of being good roommates. We could agree which shelves were mine and which were yours, label everything carefully and try not to step on each other's toes. But our conventions didn't build a wall.

Shadow DOM changes that relationship. We're still in the same apartment, but now one roommate has a room with an actual door. The boundary is no longer just something we've agreed to respect. The browser understands it too.

For an embedded application, that immediately sounds attractive. Shadow DOM gives us a much stronger, browser-enforced style boundary. Styles from the host don't cross that boundary and start rearranging things inside. Styles from the component don't wander out and interfere with the host either.

An iframe goes further. Now we're in separate apartments. The embedded application gets another browsing context, with its own document and its own window. From an isolation perspective, that's a much stronger separation.

Separate apartments solve the kitchen problem rather effectively. They also make it harder to pass someone the salt.

So why not isolate everything as much as possible?

Because isolation works both ways.

A boundary that keeps unwanted styles out can also keep styles we depend on out. Third-party libraries may make assumptions about the document they live in, where their styles are available, or where they can render parts of their UI.

With an iframe, the separation becomes even stronger. The host and the embedded application no longer share a document. If they need to cooperate, their interaction now has to cross the boundary we've created.

A stronger boundary doesn't prevent cooperation. It makes cooperation more deliberate.

Sharing an environment can make that cooperation easier. The downside is that the two systems can also affect each other in ways we never intended.

Strengthening the boundary reduces that accidental interaction, but some of the interaction we do want now has to be made explicit.

It's easy to point to a technology that would have prevented one class of problems. It doesn't tell us what other requirements shaped the system, what constraints existed at the time, what compatibility concerns mattered, or what new problems a different boundary would have introduced.

Shadow DOM isn't “the solution” to this story. Neither is an iframe. They're useful to think about because they make the original problem easier to see.

The browser wasn't violating the boundary between our application and the host web shop. We had been sharing more of the environment than the architectural boundary between the two applications might suggest.

And once I look at the problem that way, the question changes. It's no longer just How do I stop somebody else's CSS from breaking mine?

It becomes What should these two systems share, what should they isolate, and what needs to cross the boundary between them?

What I actually learned

When I first worked on ESIS, I didn't walk away thinking about browser-enforced boundaries. I walked away much better at CSS.

I had more tricks, better instincts, and much more respect for the difference between a controlled development environment and the messy reality software eventually meets.

But I had learned the practical rules before I understood the model underneath them. Coming back to that experience later changed the lesson for me.

I knew, even then, that I didn't own the environment.

What I hadn't understood was how deeply that fact belonged to the engineering problem itself.

Software doesn't become part of another system only when we deploy it there. That relationship is already part of the design.

Sometimes the right choice is to share an environment and become very good at living inside it. Sometimes the right choice is to create a stronger boundary.

Back then, I learned how to write frontend code that could survive the integration. It took me much longer to understand why that was necessary.

The CSS was where I first saw the boundary.