Drupal vs. 11ty w/ kittens & puppies
Tags: database, webdev, 11ty, drupal
Published: 2020-11-05 17:23:12

---
title: "Drupal vs. 11ty w/ kittens & puppies"
published: true
description:  "A visual comparison of SQL vs. objects"
date: 2020-11-05 15:00:00 UTC
tags: database,webdev,11ty,drupal
cover_image: https://katiekodes.com/images/cateating.jpg
canonical_url: https://katiekodes.com/drupal-11ty/
---

On StackOverflow, Drupal user Alec [asked how dynamic “list” generation worked in 11ty](https://stackoverflow.com/questions/64667959/how-to-create-dynamic-lists-in-11ty-static-site-generator) compared to [Drupal views](https://www.drupal.org/docs/7/modules/views/what-are-views).

I know nothing about Drupal, but I thought perhaps I could shed some light on the impact differing content data models may have on the two web site building systems: **relational** _(SQL)_ vs. **object**.

We'll take a visual, low-code look at datasets of kittens and puppies in both systems, contrasting the approaches you might take to listing them by color.

* * *

## Data storage

Drupal, like Wordpress, is a web site generation tool whose content is stored in a [relational (SQL) database management system](https://en.wikipedia.org/wiki/Relational_database#RDBMS).

By contrast, 11ty is meant to generate web sites from content either:

1. stored in [ordinary computer files](https://en.wikipedia.org/wiki/File_system), or
2. stored elsewhere on the internet, but that would _make_ a perfectly good computer file, and that is retrievable by executing some code written in Node.js-style JavaScript

* * *

![Stock photo of a cat begging](https://katiekodes.com/images/catbegging-wide.jpg)

## Data shape

The biggest difference, though, is not so much where the data is stored but the _shape_ in which the site generation tool sees it.

Go have a look at my explanation of [table-shaped vs. nested-list-shaped data](https://dev.to/katiekodes/intro-to-xml-and-json-2-datas-shape-3iji) to get some sense of the difference.

{% link https://dev.to/katiekodes/intro-to-xml-and-json-2-datas-shape-3iji %}

Not explained in that post, however, is the idea of combining multiple table-shaped data files by including identifying data from one table inside the details of another and indicating that it represents a link into a row of some other table – and having the computer automatically understand those links. _(That’s what is meant by “relational” in “relational database.”)_

Let’s look at data about some kittens and puppies waiting for adoption out of an animal shelter.

To let me be lazy in typing up sample data, my shelter is magical, and no two pets of the same name ever arrive at the same time, so I can use their names as unique record IDs.

* * *

### Relational-database-shaped

In a fully relational database, we’d probably normalize our data – that is, we’d probably break it up into a lot of different tables.

Here’s an example data model with 4 tables: `kittens`, `puppies`, `valid_colors`, and `pet_coloration`:

#### kittens

| slug | name |
| --- | --- |
| oreo | Oreo |
| hershey | Hershey |

#### puppies

| slug | name |
| --- | --- |
| fido | Fido |
| rover | Rover |
| snickers | Snickers |

#### valid\_colors

| row\_id | color |
| --- | --- |
| 1 | black |
| 2 | brown |
| 3 | white |
| 4 | gray |
| 5 | orange |
| 6 | tan |
| 7 | red |

#### pet\_coloration

| pet\_table | slug | color\_id |
| --- | --- | --- |
| kittens | oreo | 1 |
| kittens | oreo | 3 |
| kittens | hershey | 2 |
| puppies | fido | 1 |
| puppies | fido | 7 |
| puppies | rover | 6 |
| puppies | snickers | 1 |
| puppies | snickers | 3 |

* * *

### Nested-list-shaped

While there’s nothing stopping us from structuring our data into four tables that cross-reference each others’ row IDs in a file-based nested-list-shaped data store, in practice I’ve found that it’s not terribly common.

People have a tendency to store their data more like this, in 2 files called `kittens` and `puppies`, with coloration details buried inside each animal’s record:


#### kittens

<blockquote>
<ol>
	<li><i>(kitten #1)</i>
	<ul>
		<li><b>name</b>:  Oreo</li>
		<li><b>colors</b>:
		<ul>
			<li>black</li>
			<li>white</li>
		</ul>
		</li>
		<li><b>slug</b>:  oreo</li>
	</ul>
	</li>
	<li><i>(kitten #2)</i>
	<ul>
		<li><b>name</b>:  Hershey</li>
		<li><b>colors</b>:
		<ul>
			<li>brown</li>
		</ul>
		</li>
		<li><b>slug</b>:  hershey</li>
	</ul>
	</li>
</ol>
</blockquote>

#### puppies

<blockquote>
<ol>
	<li><i>(puppy #1)</i>
	<ul>
		<li><b>name</b>:  Fido</li>
		<li><b>colors</b>:
		<ul>
			<li>white</li>
			<li>red</li>
		</ul>
		</li>
		<li><b>slug</b>:  fido</li>
	</ul>
	</li>
	<li><i>(puppy #2)</i>
	<ul>
		<li><b>name</b>:  Rover</li>
		<li><b>colors</b>:
		<ul>
			<li>tan</li>
		</ul>
		</li>
		<li><b>slug</b>:  rover</li>
	</ul>
	</li>
	<li><i>(puppy #3)</i>
	<ul>
		<li><b>name</b>:  Snickers</li>
		<li><b>colors</b>:
		<ul>
			<li>black</li>
			<li>white</li>
		</ul>
		</li>
		<li><b>slug</b>:  snickers</li>
	</ul>
	</li>
</ol>
</blockquote>

* * *

## Listing pets by color

### Relational

From what I can tell, it looks like relational-database-aware web site building systems like Drupal can make it relatively easy to build a URL like `https://mysite.com/colors/black/` that lists all black pets available, no matter whether they’re a kitten or a puppy.

That’s largely because SQL, the _**declarative**_ programming language built into the database management system storing the data, offers the opportunity to inspect the data from that perspective with very little code.

This code _(note: did not execute; may have bugs, but hopefully gets the gist)_:

```sql
SELECT DISTINCT
 DECODE(pets.pet_table, "kittens," "kitten", "puppies," "puppy", pets.pet_table) as pet_type
 pets.slug, 
 pets.name
FROM valid_colors
INNER JOIN pet_coloration
 ON valid_colors.row_id = pet_coloration.color_id
INNER JOIN (
  SELECT "kittens" as pet_table, slug, name
  FROM kittens
  UNION ALL
  SELECT "puppies" as pet_table, slug, name
  FROM puppies
) pets
 ON pets.slug = pet_coloration.slug
 AND pets.pet_table = pet_coloration.pet_table
WHERE valid_colors.color = 'black'
```

… would produce this data:

| pet\_type | slug | name |
| --- | --- | --- |
| kitten | oreo | Oreo |
| puppy | snickers | Snickers |

In fact, I’m not going to type it all out here _(the concept is a bit hard to doodle in 2 dimensions)_, but because “querying” the data in almost any pattern we can imagine is so easy, I can definitely see how a tool like Drupal would make an easy user interface by which you can simply say that you’d like it to manage building appropriate URLs under `https://mysite.com/colors/` – `black`, `tan`, `orange`, etc.

### Nested-list-shaped _(objects)_

Building a similar type of URL called `https://mysite.com/colors/black/` using nested-list-shaped data that simply contained “kittens” and “puppies” would likely take a lot more manual coding.

Not only did we leave the “coloration” data about each pet buried inside individual pet listings, but web site building tools optimized to work with this kind of data, like 11ty, offer _**imperative**_ programming languages that make us do all the hard work ourselves.

_We_ have to hand-write code that loops over every single kitten or puppy record, inspecting it to see whether it’s black or not, and if so, setting aside the right details about that kitten or puppy.

The code might be something more like:

```javascript
const pets = [
 ...kittens.map((kitten) => {
  kitten.pet_type = "kitten";
  return kitten;
 }),
 ...puppies.map((puppy) => {
  puppy.pet_type = "puppy";
  return puppy;
 }),
];

const pets_for_color = ({ color }) => {
 return pets.filter((pet) => {
  return pet.colors.includes(color);
 });
};

const black_pets = pets_for_color({ color: "black" });

module.exports = black_pets
```

Such code would produce data like this, out of which your web site builder could generate `https://mysite.com/colors/black/`:

<blockquote>
<ol>
	<li><i>(pet #1)</i>
	<ul>
		<li><b>name</b>:  Oreo</li>
		<li><b>colors</b>:
		<ul>
			<li>black</li>
			<li>white</li>
		</ul>
		</li>
		<li><b>slug</b>:  oreo</li>
		<li><b>pet_type</b>:  kitten</li>
	</ul>
	</li>
	<li><i>(pet #2)</i>
	<ul>
		<li><b>name</b>:  Snickers</li>
		<li><b>colors</b>:
		<ul>
			<li>black</li>
			<li>white</li>
		</ul>
		</li>
		<li><b>slug</b>:  snickers</li>
		<li><b>pet_type</b>:  puppy</li>
	</ul>
	</li>
</ol>
</blockquote>

**Tricky?  It gets better.**

Once you’ve broken your “relational data” thinking habits and gotten the hang of “object data” thinking habits, and once you’ve accustomed yourself to a new programming language, the new approach won’t be so bad.

I’m high-fiving myself right now for learning enough JavaScript over the last half-year to finally remember tricks like `...`, `.map()`, and `.filter()`.

**Always celebrate your small wins!**

In fact, as long as your dataset isn’t too big, once you know what you’re doing, it’s not too tough to write a few additional lines of code and generate a nested-list-shaped dataset that your web site builder could use for building all the `https://mysite.com/colors/` URLs on your behalf:

```javascript
// Code shown previously,
// except final lines pertaining to black_pets,
// goes here

const current_colors = [
 ...new Set(
  pets
   .map((pet) => {return pet.colors;})
   .flat()
 ),
];

const pets_by_color = current_colors.map((color) => {
 return { color, pets: pets_for_color({ color }) };
});

module.exports = pets_by_color;
```

Such code would produce data like this. Your web site builder could use the outermost level of listing to decide what pages to make, then pursue the details contained within each `pets` sub-listing to manage building appropriate URLs under `https://mysite.com/colors/` – `black`, `tan`, `red`, etc.

<blockquote>
<ol>
	<li><i>(color #1)</i>
	<ul>
		<li><b>color</b>:  black</li>
		<li><b>pets</b>:
		<ul>
			<li><i>(...all the details about Oreo...)</i></li>
			<li><i>(...all the details about Snickers...)</i></li>
		</ul>
		</li>
	</ul>
	</li>
	<li><i>(color #2)</i>
	<ul>
		<li><b>color</b>:  white</li>
		<li><b>pets</b>:
		<ul>
			<li><i>(...all the details about Oreo...)</i></li>
			<li><i>(...all the details about Fido...)</i></li>
		</ul>
		</li>
	</ul>
	</li>
	<li><i>(color #3)</i>
	<ul>
		<li><b>color</b>:  brown</li>
		<li><b>pets</b>:
		<ul>
			<li><i>(...all the details about Hershey...)</i></li>
		</ul>
		</li>
	</ul>
	</li>
	<li><i>(color #4)</i>
	<ul>
		<li><b>color</b>:  red</li>
		<li><b>pets</b>:
		<ul>
			<li><i>(...all the details about Fido...)</i></li>
		</ul>
		</li>
	</ul>
	</li>
	<li><i>(color #5)</i>
	<ul>
		<li><b>color</b>:  tan</li>
		<li><b>pets</b>:
		<ul>
			<li><i>(...all the details about Rover...)</i></li>
		</ul>
		</li>
	</ul>
	</li>
</ol>
</blockquote>

Writing such “data transformation” code and making the results available to Eleventy HTML templates is one of the big reasons 11ty treats JavaScript files stored in its `_data` folder as special.

Be sure to take advantage of data pre-processing in JavaScript on your next 11ty web site.

It should help you reach the data-list & URL-building experience you're accustomed to if you're starting anew after using a database-based site building tool like Drupal or Wordpress.

* * *

## Recommended resources

- [Using a relational database vs JSON objects for data](https://softwareengineering.stackexchange.com/questions/235707/using-a-relational-database-vs-json-objects-for-event-activity-data) from StackOverflow
- [Imperative vs Declarative Programming – the Difference Explained in Plain English](https://www.freecodecamp.org/news/imperative-vs-declarative-programming-difference/) by Mike Zetlow for FreeCodeCamp
- 11ty [global `_data` files](https://www.11ty.dev/docs/data-global/) and [template-specific data files](https://www.11ty.dev/docs/data-template-dir/)