jcardena.com Blog Tables for layout, and other sins I committed in 2003
145 posts
EN ES

Tables for layout, and other sins I committed in 2003

Software

Juan Cardena critiques the architectural sin of fusing content structure with presentation. From 2003 HTML table layouts to modern AI systems, he advocates for ruthless separation of concerns for dura

The request from the client seemed simple enough. It was 2003, and they wanted a small promotional banner added to the right-hand sidebar of every page on their e-commerce site. "Should be an hour of work, right?" they asked. I agreed, foolishly. That one-hour task ended up consuming two full days of untangling a web of nested <table>, <tr>, and <td> tags, each with its own menagerie of width, valign, and colspan attributes. The foundation of the site was a house of cards, and I was the one who had built it.

The Clever Hack That Wasn't

Back then, we didn't have CSS Grid or Flexbox. We had CSS, but browser support for positioning was a battlefield of quirks and inconsistencies. The pragmatic, battle-tested tool for forcing a page into a reliable three-column layout was the HTML <table>. It just worked. You could nest tables within tables to create complex grids that held their shape across both Netscape Navigator and Internet Explorer. It felt like a victory, even as pioneers of web standards were already advocating for a cleaner separation of concerns.

Publications like A List Apart and authors like Jeffrey Zeldman, in his influential 2003 book *Designing with Web Standards*, were loudly championing the approach of using semantic HTML for structure and CSS for presentation. I was aware of it, of course, but the immediate pressure for pixel-perfect cross-browser consistency often led to expedient choices.

My masterpiece of the era was a layout built on a single, invisible master table. One row, three columns. The left cell held the navigation menu (itself another table). The middle cell held the main content (again, often containing tables for internal layout). The right cell held the sidebar. To the browser, it was just data in a grid. To me, it was a perfectly controlled visual canvas.

This approach conflated two completely different jobs: defining the document's structure and dictating its visual presentation. The HTML, which was supposed to give semantic meaning to the content—this is a heading, this is a paragraph, this is a list—was now also a rigid, invisible scaffold. It was a sin of convenience, and I was about to pay for it.

Business RequestThe Table LayoutImmediate RenderHidden Rigidity
The 2003 Table Layout Trap

When the Foundation Cracked

The first crack appeared with that "simple" sidebar request. Squeezing in a new banner meant recalculating column widths, checking every colspan in the path, and praying I didn't break the layout on a different page. What should have been a one-line CSS change became a structural crisis.

The real collapse came a few years later with the rise of mobile. The concept of a "responsive" design was just emerging. A layout that could reflow from a 1024px desktop monitor to a 320px phone screen was the new goal. My table-based layouts couldn't just reflow; they were fundamentally locked. You can't tell a table row to suddenly render underneath the previous one. It’s a row. Its identity is inseparable from its presentation.

The only solution was a complete rewrite. We had to go through every single page and strip out the layout tables, replacing them with semantic HTML (<div>, <nav>, <article>) and a separate CSS file that handled all the positioning. It was a painful, expensive lesson in technical debt. The "clever hack" that saved us a few hours in 2003 cost us weeks of work years later – precisely the problem that projects like CSS Zen Garden were so brilliantly demonstrating could be avoided by strictly separating content from presentation.

The Real Sin: Conflating Structure and Presentation

This isn't just a story about old web development techniques. It’s about a recurring pattern of hidden debt that I still see every day in modern software, data, and AI systems. The sin is binding your core logic or data structure to a specific, transient presentation format.

I've seen this same pattern emerge repeatedly. For instance, I've worked with APIs meticulously crafted to match the exact layout of a specific front-end component. The moment the UI team wanted a layout change, the backend team faced a redeployment. Or consider a data pipeline I once debugged that embedded HTML tags directly into database fields. The data became a pre-rendered web component, useless for any other purpose. Even in LLM agent design, I've encountered core prompts hardcoding output formatting for a Slack message, making it painful to reuse that summary via email or for structured logging.

In every case, a choice made for immediate convenience creates downstream rigidity. You've coupled the "what" (the data, the content, the answer) with the "how" (the layout, the color, the format). This coupling is a time bomb.

The Durable Pattern: Separation of Concerns

The antidote then, as it is now, is a ruthless separation of concerns. This isn't just a textbook slogan; it's the most reliable architectural principle for building systems that can survive platform shifts.

A durable system keeps its layers distinct:

  1. The Semantic Core: The data is just data. An API returns entities and their relationships, not a pre-formatted view model. A pipeline stores clean, normalized information, not formatted strings.
  2. The Presentation Layer: This layer is responsible for transformation. It takes the semantic core and arranges it for a specific context—a web page, a mobile app view, a PDF report, a Slack message.
  3. The Behavioral Layer: This layer handles interaction and logic, operating on the semantic core and triggering changes in the presentation.

If I had followed this in 2003, the HTML would have contained only the content, structured with meaningful tags. The CSS file would have contained the three-column layout rules. The sidebar banner request would have been, correctly, a one-line CSS change. The mobile revolution would have required updating one file—the CSS—not rewriting the entire application.

DATA SOURCESEvents StreamsFilesDatabasesSEMANTIC LAYERNormalized DataCore ModelsPROCESSING LAYERLLM AgentsDeterministicPipelinesValidationPRESENTATION LAYERUI TemplatesReportsAPI OutputSERVING LAYERAPIsDashboardsNotifications
Durable AI Architecture: Separation of Concerns

That discipline pays the same dividends today. When your API is semantic, you can build a new web client, a mobile app, and a partner integration on top of it without ever touching the backend. When your data is clean, you can use it to power a dashboard, train a model, and generate a report without a bespoke cleaning step for each one.

I still carry the scars from those table layouts. They serve as a constant, humbling reminder: the cleverest hack is often the one that creates the most debt. The most durable architecture is the one that respects the boundaries between what something is and how it happens to look today.

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.