| name | validation-author |
| description | Write validation/query lessons with SQL comparisons |
| allowed-tools | Read, Write, Edit, Glob, Grep |
Validation Author Skill
Purpose: Write validation/query lessons that prove the value of what was built with SQL comparisons.
When to use: Workshop lesson requires proving the value of what learners just built.
Prerequisites:
- WORKSHOP-PLAN.md exists with validation details
- Skeleton lesson.adoc file exists
- Previous challenge lesson completed
- Understanding of what was built
- SQL equivalent identified
Overview
This skill writes validation/query lessons that:
- Query the data that was just imported/created (3-5 minutes)
- Show SQL comparison side-by-side
- Prove concrete value (performance, simplicity, readability)
- Use business questions, not abstract queries
- Follow the Learn → Do → Verify pattern (this is the "Verify")
Do NOT write concept lessons, challenges, or practice lessons. This skill focuses ONLY on validation lessons.
Core Principle: Teaching Graph Databases
Focus on graph databases and graph technologies.
- Prove what they built works - Show that the graph structure enables real business queries
- Use comparisons when they add value - Visual diagrams (ERD vs Graph) or code comparisons can be helpful context
- Be factual, not salesy - Show concrete metrics (lines of code, what the engine does) not vague superiority claims. Do not use Big O or O(n), O(k), O(n×m); use natural language for performance (e.g. "cost scales with connections traversed", "pointer traversal vs table scans and joins").
- Make it satisfying - They should see their work pay off with queries that actually work
Validation lesson approach:
- Show the business question
- Show the Cypher query that answers it
- Explain what the query does (using graph concepts)
- Show results proving it works
- Optionally: Include comparisons (SQL, relational model) when they demonstrate value effectively
When comparisons are helpful:
- Final workshop solution (showing dramatic difference in simplicity)
- Complex multi-hop traversals where alternatives are significantly more complex
- Visual diagrams (ERD vs Graph model) to show structural differences
- When teaching concepts where the comparison provides valuable context
Keep it balanced:
- Don't compare constantly - teach graph query patterns on their own merits
- When comparing, use facts (lines of code, pointer traversal vs table scans/joins, cost scales with connections not table size) not marketing language—no Big O or O(n) notation
- Focus on proving their work produces something valuable
Phase 1: Understand What to Validate (5 min)
Checklist: Gather Information
Key Questions to Answer
Before writing anything, answer:
- What was just built? (e.g., Product nodes, Customer→Order relationships)
- What business questions can we now answer?
- What's the SQL equivalent? How would you do this in a relational database?
- What value do we prove? (fewer lines? no JOINs? better performance?)
- How many queries? 2-4 progressive examples showing increasing complexity
- What's the connection? How does this move toward the workshop goal?
Read These Files
MUST READ:
- WORKSHOP-PLAN.md (for validation objectives)
- Previous challenge lesson (what was built)
- Source course lesson (for query examples)
- CONTENT_GUIDELINES.md (for SQL comparison patterns)
REFERENCE:
- modules/4-many-to-many/lessons/4-multi-hop-traversals/lesson.adoc
- SQL comparison examples throughout workshop
Phase 2: Plan Validation Structure (10 min)
Checklist: Lesson Outline
Structure Template
Introduction
├── References what was just built
└── States what will be validated
Query 1: Simple Business Question
├── Question in plain language
├── Cypher query with explanation
├── SQL comparison
└── Why graph is better for THIS query
Query 2: More Complex Question
├── Question in plain language
├── Cypher query with explanation
├── SQL comparison
└── Why graph is better for THIS query
Comparison Table
└── Metrics (Lines, JOINs, Performance, Readability)
Connection to Goal
└── How this pattern enables the final workshop goal
Summary
└── What was proven, forward reference
Query Progression Pattern
Start simple, build complexity:
- Query 1: Single-hop traversal (Customer → Orders)
- Query 2: Multi-hop traversal (Customer → Orders → Products)
- Query 3: Filtering and aggregation
- Query 4: Advanced pattern (collections, counts)
Phase 3: Write Opening (5 min)
Checklist: Introduction
Opening Pattern
[.slide.discrete]
== Introduction
You [what was just built in previous challenge]. Now you can answer business questions that would require complex JOINs in SQL.
In this lesson, you will query [what was built] and compare the Cypher queries to their SQL equivalents.
Example:
[.slide.discrete]
== Introduction
You created relationships between Order and Product nodes. Now you can traverse the complete Customer → Order → Product path with simple queries.
In this lesson, you will answer business questions using multi-hop traversals and compare them to the equivalent SQL queries.
Phase 4: Write Query Sections (30 min)
Checklist: Query Section Structure
Query Section Pattern
[.slide]
== [Business Question as Header]
[Plain language business question]
[source,cypher]
.[Descriptive query title]
----
[Cypher query here]
----
[Explanation of what query does]
Click **Run** to see the results.
**SQL equivalent:**
[source,sql]
----
[SQL query here]
----
**Comparison:**
* [Specific advantage 1]
* [Specific advantage 2]
Example Query Section
[.slide]
== Finding Customer Purchases
What products has a specific customer purchased?
[source,cypher]
.Products purchased by customer
----
MATCH (c:Customer {id: 'ALFKI'})
-[:PLACED]->(:Order)
-[:ORDERS]->(p:Product)
RETURN DISTINCT p.name AS product
ORDER BY product;
----
This query starts at a customer, traverses through their orders, and collects all products they've purchased.
Click **Run** to see all products purchased by customer ALFKI.
**SQL equivalent:**
[source,sql]
----
SELECT DISTINCT p.productName
FROM customers c
JOIN orders o ON c.customerId = o.customerId
JOIN order_details od ON o.orderId = od.orderId
JOIN products p ON od.productId = p.productId
WHERE c.customerId = 'ALFKI'
ORDER BY p.productName;
----
**Comparison:**
* **Cypher:** 2 relationship hops, reads like the question
* **SQL:** 3 JOIN operations scanning intermediate tables
* **Performance:** Graph traversal follows pointers in memory (cost scales with connections traversed); SQL JOIN repeatedly scans indexes and materializes result sets (cost scales with table sizes)
SQL Comparison Patterns
Side-by-side blocks:
[.slide]
== Query Comparison
**Cypher:**
[source,cypher]
----
MATCH (c:Customer)-[:PLACED]->(o:Order)
WHERE c.id = 'ALFKI'
RETURN count(o) AS orderCount;
----
**SQL:**
[source,sql]
----
SELECT COUNT(o.orderId) AS orderCount
FROM customers c
JOIN orders o ON c.customerId = o.customerId
WHERE c.customerId = 'ALFKI';
----
Two-column layout:
[.slide.col-2]
== Query Comparison
[.col]
====
**Cypher:**
[source,cypher]
----
MATCH (c:Customer)
-[:PLACED]->
(o:Order)
RETURN c.name, count(o)
----
====
[.col]
====
**SQL:**
[source,sql]
----
SELECT c.companyName,
COUNT(o.orderId)
FROM customers c
LEFT JOIN orders o
ON c.customerId = o.customerId
GROUP BY c.companyName
----
====
Phase 5: Create Metrics Table (10 min)
Checklist: Comparison Metrics
Metrics Table Pattern
[.slide]
== Cypher vs SQL Comparison
[options="header"]
|===
| Metric | Cypher | SQL
| Lines of code | [N] | [M]
| JOIN operations | 0 | [N]
| Cost scales with | Connections traversed | Table sizes and number of JOINs
| Readability | Matches question structure | Multiple JOIN clauses
|===
**Key insight:** [Specific advantage for THIS query pattern]
Example:
[.slide]
== Multi-Hop Traversal Comparison
[options="header"]
|===
| Metric | Cypher | SQL
| Lines of code | 4 | 8
| JOIN operations | 0 | 3
| Tables accessed | 0 | 4 (customers, orders, order_details, products)
| Cost scales with | Connections traversed | Table sizes and JOIN count
| Readability | Path-based, visual | Multiple JOIN conditions
|===
**Key insight:** For connected data queries, graph traversal eliminates expensive JOIN operations that scan entire tables.
Phase 6: Explain Advantages (10 min)
Checklist: Value Proposition
Advantage Explanation Patterns
Performance explanation:
[.slide]
== Performance Advantage
**Relational approach:**
* Scans entire tables (or large index ranges) for JOIN conditions
* Creates intermediate result sets
* Cost grows with table sizes and number of JOINs
**Graph approach:**
* Follows direct relationship pointers in memory
* No repeated table scans or join materialization
* Cost grows with how many connections you traverse, not total graph size
For highly connected data, graph traversal stays predictable as data volume increases because it only touches the paths it follows.
Simplicity explanation:
[.slide]
== Simplicity Advantage
**Graph queries read like the questions you're asking:**
* "What products did this customer buy?" →
`(Customer)-[:PLACED]->(:Order)-[:ORDERS]->(Product)`
**SQL requires understanding schema implementation:**
* Which tables to JOIN
* Which foreign keys to match
* ORDER of JOIN operations
Anti-Patterns to AVOID
❌ Vague sales claims:
Graphs are powerful and provide amazing performance.
✅ Concrete technical facts:
Graph traversal follows pointers in memory; cost scales with connections traversed. SQL JOIN repeatedly scans indexes and materializes result sets; cost scales with table sizes and number of joins.
❌ Generic statements:
Cypher is easier to read and write.
✅ Specific comparison:
Cypher: 4 lines, 0 JOINs. SQL: 8 lines, 3 JOINs scanning 4 tables.
Phase 7: Connect to Workshop Goal (5 min)
Checklist: Goal Connection
Connection Pattern
[.slide]
== Building Toward [Workshop Goal]
[Current capability statement]
[How this pattern extends for final goal]
[What comes next to complete the path]
Example:
[.slide]
== Building Toward Recommendations
You can now traverse Customer → Order → Product to find what each customer has purchased.
To build a recommendation query, you'll extend this pattern: find customers who bought similar products, then recommend products they haven't purchased yet.
This multi-hop traversal pattern is the foundation for collaborative filtering.
Phase 8: Write Summary (5 min)
Checklist: Summary Section
Summary Pattern
[.summary]
== Summary
In this lesson, you validated [what was built] by answering business questions:
* **[Query 1]** - [What it showed]
* **[Query 2]** - [What it showed]
* **[Query 3]** - [What it showed]
**Cypher vs SQL:** [N] lines vs [M] lines, [X] JOINs eliminated
In the next lesson, you will [what comes next].
Example:
[.summary]
== Summary
In this lesson, you validated the Customer → Order → Product path by answering business questions:
* **Customer purchases** - Found all products a customer bought
* **Popular products** - Identified most frequently ordered items
* **Order totals** - Calculated spending per customer
**Cypher vs SQL:** 4 lines vs 8 lines, 3 JOINs eliminated; graph cost scales with connections traversed, SQL with table sizes and joins
In the next lesson, you will learn how to find similar customers using bidirectional traversals.
Phase 9: Apply Style Rules (10 min)
Checklist: Technical Requirements
Code Block Requirements
Every Cypher query:
- Context before (why this query)
- Descriptive title
- Explanation after (what it does)
- "Click Run" prompt
- Experiment suggestions (optional)
Every SQL query:
- Shown for comparison
- Same business question
- No "Click Run" (not executable in workshop)
Phase 10: Review and Refine (10 min)
Checklist: Self-Review
Test Queries
Before completing:
-
Test each Cypher query:
- Returns expected results?
- Syntax is correct?
- Uses workshop dataset?
- Property names match (id, name not customerId, productName)?
-
Verify SQL equivalents:
- Produces same results as Cypher?
- Accurately represents relational approach?
- Fair comparison (not intentionally bad SQL)?
-
Check metrics:
- Line counts accurate?
- JOIN counts correct?
- Performance claims defensible?
Examples and References
Example Validation Lessons
See these real files:
-
modules/4-many-to-many/lessons/4-multi-hop-traversals/lesson.adoc
- Demonstrates: Multi-hop queries, SQL comparisons, metrics table
-
modules/3-modeling-relationships/lessons/3-traversing-relationships/lesson.adoc
- Demonstrates: Simple traversals, explaining advantages
-
modules/5-final-review/lessons/1-recommendation-query/lesson.adoc
- Demonstrates: Complex query with full SQL comparison
What These Files Demonstrate
4-multi-hop-traversals/lesson.adoc:
- Shows queries on data just imported
- Includes SQL comparison side-by-side
- Provides metrics table (Lines | JOINs | Performance | Readability)
- Explains advantages concretely in natural language (pointer traversal vs table scans/joins; cost scales with connections not table size)
- Multiple query examples building in complexity
- Connects pattern to final recommendation goal
Key patterns:
- Business questions as headers
- Cypher query with
.Title
- SQL equivalent in separate block
- Concrete comparison (4 lines vs 8 lines, 0 JOINs vs 3 JOINs)
- "Click Run" encouragement
- Metrics table with AsciiDoc format
Common SQL Comparison Scenarios
Single-Hop Traversal
Cypher:
MATCH (c:Customer {id: 'ALFKI'})-[:PLACED]->(o:Order)
RETURN c.name, o.id, o.date;
SQL:
SELECT c.companyName, o.orderId, o.orderDate
FROM customers c
JOIN orders o ON c.customerId = o.customerId
WHERE c.customerId = 'ALFKI';
Comparison: 1 line vs 4 lines, 1 JOIN
Multi-Hop Traversal
Cypher:
MATCH (c:Customer {id: 'ALFKI'})
-[:PLACED]->(:Order)
-[:ORDERS]->(p:Product)
RETURN DISTINCT p.name;
SQL:
SELECT DISTINCT p.productName
FROM customers c
JOIN orders o ON c.customerId = o.customerId
JOIN order_details od ON o.orderId = od.orderId
JOIN products p ON od.productId = p.productId
WHERE c.customerId = 'ALFKI';
Comparison: 4 lines vs 7 lines, 3 JOINs, 4 tables
Bidirectional Traversal
Cypher:
MATCH (c1:Customer {id: 'ALFKI'})
-[:PLACED]->(:Order)
-[:ORDERS]->(p:Product)
<-[:ORDERS]-(:Order)
<-[:PLACED]-(c2:Customer)
WHERE c1 <> c2
RETURN c2.name, count(DISTINCT p) AS sharedProducts;
SQL:
SELECT c2.companyName, COUNT(DISTINCT p2.productId)
FROM customers c1
JOIN orders o1 ON c1.customerId = o1.customerId
JOIN order_details od1 ON o1.orderId = od1.orderId
JOIN products p1 ON od1.productId = p1.productId
JOIN order_details od2 ON p1.productId = od2.productId
JOIN orders o2 ON od2.orderId = o2.orderId
JOIN customers c2 ON o2.customerId = c2.customerId
WHERE c1.customerId = 'ALFKI' AND c1.customerId <> c2.customerId
GROUP BY c2.companyName;
Comparison: 7 lines vs 11 lines, 6 JOINs; each extra JOIN in SQL adds more index scans and materialization—cost grows quickly with depth
Output Checklist
Before marking validation lesson complete, verify:
References