jcardena.com Blog CSS arrived and changed how I thought about everything
145 posts
EN ES

CSS arrived and changed how I thought about everything

Software

Explore the enduring lesson of CSS: separating concerns. Learn how this principle applies to modern data pipelines and LLM agent architectures for building robust, adaptable systems.

CSS arrived and changed how I thought about everything
[[HERO_IMAGE]] I remember the early web as a wild frontier of inline styles and table-based layouts. Every aesthetic choice, from font color to spacing, was baked directly into the HTML. Changing the look of a site meant painstakingly hunting through dozens, sometimes hundreds, of files, adjusting each instance by hand. It was tedious, error-prone, and fundamentally limited our ambition for dynamic, consistent experiences.

The Architectural Debt of Monolithic Presentation

Before the advent of Cascading Style Sheets, HTML tags often carried both semantic meaning and presentation instructions. The `` tag was a prime offender, dictating typeface, size, and color directly on content. Layouts were often achieved using HTML `` structures, repurposed from their semantic role of displaying tabular data. This approach tightly coupled content with presentation, creating what I now recognize as a monolithic design pattern in miniature—a clear violation of the single responsibility principle. Our "content" layer was also our "presentation" layer, and neither could evolve independently without disrupting the other. This created immense architectural debt, where small changes cascaded into widespread, unpredictable breakages.

CSS: The Radical Act of Decoupling

Then CSS arrived, and it felt like magic. It introduced the revolutionary concept that HTML should define structure and semantics—*what* a heading is, *what* a paragraph is—while CSS should define its presentation—*how* that heading looks, *how* that paragraph displays. This clear, clean separation of concerns was first proposed by Håkon Wium Lie in his original 1994 paper, "Cascading HTML style sheets," a foundational document that set the stage for modern web development. Instead of embedding styles, we could declare rules globally or per-component. Want all headings to be blue and sans-serif? One rule in a single CSS file. Change your mind to red and serif? One edit. This wasn't just about aesthetics; it was about maintainability, scalability, and enabling parallel development for content creators and designers. It demonstrated the power of decoupling—a principle that would prove durable across every platform shift I've witnessed.
The ArchitecturalDebt ofCSS The RadicalActDecoupling forModern DataDeclarative Designand theDurable Lessonsfor Enterprise
How this unfolds

Decoupling for Modern Data and AI Systems

The fundamental lesson of CSS—decoupling definition from presentation—resonates deeply with modern architectural challenges in data, AI, and agentic systems. Consider an LLM agent designed to process customer support tickets. The agent's core function is to understand the user's intent, query relevant information, and formulate a correct response. This is the "what": the agent's goal state, its access to tools, and its internal reasoning process. Now, imagine the "how": how the agent interacts with the customer. This could be a professional, empathetic tone for direct customer replies, a terse, fact-based summary for internal logging, or a structured JSON output for an upstream automation system. The agent's core `ProcessSupportTicket` logic should be entirely decoupled from these presentation formats. **Agent Goal Definition (the "what"):** yaml agent_task: ResolveTicket ticket_id: XYZ-789 context_sources: [customer_CRM, knowledge_base] required_data: [product_info, customer_history] expected_output_type: action_plan_or_response **Agent Response Formatter (the "how"):** python class ProfessionalCustomerFormatter: def format(response_content): return f"Dear customer,\n\n{response_content}\n\nSincerely,\nSupport Team" class InternalSummaryFormatter: def format(response_content): return f"[TICKET {ticket_id}] Summary:\n{response_content[:150]}" Here, changing the formatter (the "CSS") does not impact the agent's ability to fulfill its core goal (the "HTML"). This isolation allows us to swap out interaction patterns or output formats without re-engineering the agent's fundamental reasoning, making the system far more adaptable and resilient. Similarly, in data pipelines, separating data schemas (the "what") from transformation logic or dashboard visualizations (the "how") ensures that a change in a BI tool doesn't break the upstream ETL.

Declarative Design and the Re-coupling Debate

CSS is largely declarative: you state *what* you want (e.g., "all H2s should be purple"), not *how* to achieve it step-by-step. This declarative power is immensely durable, echoed in Infrastructure as Code (IaC) and SQL. You declare the desired state, and the system reconciles it. However, modern UI development has seen a seeming "re-coupling" of concerns. Frameworks like React encourage bundling components (HTML) with their styles (CSS) and logic (JavaScript). Utility-first CSS frameworks like Tailwind CSS, as explained in their "Utility-First Fundamentals" documentation, provide highly granular, single-purpose classes directly within HTML, appearing to tie style directly to structure again. This isn't a rejection of separation of concerns, but a shift in the *level* at which it's applied. While styles might be co-located with components, the component itself still adheres to a higher-level separation: its internal logic (business rules, data fetching) is distinct from its UI presentation. The principle endures: at the architectural level, separating the core data model and business logic from the presentation layer (be it a UI component, an API endpoint, or an agent's output format) remains crucial. A change in UI frameworks should ideally not ripple through your core data processing or agentic decision-making systems.

Durable Lessons for Enterprise Architects

The CSS paradigm shift taught me that clear separation of concerns isn't just a nicety; it's an architectural imperative for any system expected to evolve and scale. Whether we're building complex data pipelines, orchestrating LLM agents, or integrating diverse software components, the lesson holds: define the core function and data structure independently from its presentation, behavior, or operational aspects. This approach builds systems that are easier to understand, maintain, debug, and ultimately, far more adaptable to future platform shifts and unforeseen requirements. It's about designing for the boring patterns that actually work at 3 AM.
SOURCESAppsEventsFilesAPIsINGESTIONStreamingBatch loadersPROCESSINGDeterministicpipelineLLM agentsValidation gateSTORAGELakehouseVector storeSERVINGAPIsDashboardsAgent tools
Reference data + AI architecture

Concrete Takeaways

  • **Prioritize semantic clarity:** Design "what" a component or data represents before "how" it behaves or appears.
  • **Embrace declarative patterns:** Specify desired states and outcomes rather than imperative steps, allowing the underlying engine to handle implementation details.
  • **Decouple for durability:** Isolate distinct concerns to allow independent evolution, reducing cascading failures and enabling faster iteration across your system.
  • **Design for long-term maintenance:** Architect for clarity and simplicity at every layer, anticipating future changes and operational demands.
JC
Juan Cardena
Enterprise Architect, Data & AI

Enterprise architect with 25 years across web, software, data, and AI. MIT CDAO ’25. Writing on agentic AI in production.