
Tutorial Driven Development with Rob Cameron
Rob Cameron discusses building RedwoodJS's tutorial, his programming journey from BASIC to Rails, and how tutorial-driven development shapes framework design.
Episode Description
Rob Cameron discusses building RedwoodJS's tutorial, his programming journey from BASIC to Rails, and how tutorial-driven development shapes framework design.
Episode Summary
In this episode of the Full Stack Jamstack podcast, Rob Cameron, a founding member of the RedwoodJS team, shares his path from typing BASIC programs on a Tandy TRS-80 as a child to working alongside Tom Preston-Werner on RedwoodJS. The conversation traces his programming evolution through HTML, ColdFusion, and Ruby on Rails, showing how each influenced his approach to building Redwood. The core discussion centers on the RedwoodJS tutorial, which Rob authored, and how it follows a philosophy called tutorial-driven development — the idea that if a framework's interface is too complex to teach simply, the design itself may need rethinking. Rob breaks down the tutorial's two-part structure: part one covers building a blog app with the website, API, GraphQL, and deployment, while part two introduces Storybook and Jest for component isolation and testing. The group explores testing culture in JavaScript versus Ruby, the mechanics of mocking, and potential plans for a part three focused on optimization. Rob also explains his side project Repeater.dev, a background job service for Jamstack apps, and the episode wraps with a lively debate over the difference between SSR, SSG, and pre-rendering as the team prepares for Redwood 1.0.
Chapters
00:00:00 - Meet Rob Cameron and the Road to RedwoodJS
The episode opens with a brief humorous exchange before Anthony introduces Rob Cameron, the self-described "elusive fourth member" of the RedwoodJS founding team. Rob explains how his nearly 15-year relationship with Tom Preston-Werner led to joining the project, describing the early energy around Redwood as reminiscent of the early days of Ruby on Rails — a small, magical nugget that few people knew about yet.
Rob shares the timeline of his involvement, noting his first commit in September 2019 and his deeper engagement starting in January 2020. He mentions that one of his first major contributions was writing the RedwoodJS tutorial, which became a vehicle for tutorial-driven development — using the process of teaching the framework to actually drive its design and feature development.
00:02:42 - From BASIC on a TRS-80 to HTML Fan Pages
Rob recounts his earliest programming memories: typing BASIC programs from books into his father's Tandy TRS-80 Model III as an eight or nine-year-old. His father, a chiropractor, had written his own patient management software, leaving programming books around the house filled with simple games like tic-tac-toe and a skiing game. Rob describes the joy of typing in code without understanding it and seeing it run.
The conversation moves to Rob's college years, where he discovered HTML by building a Mortal Kombat fan page on his university's web server. He explains that CSS wasn't yet a spec and JavaScript was a curiosity mostly used for novelty effects. This self-taught HTML phase eventually led him to ColdFusion, a rapid application development platform that embedded server-side logic directly in HTML-like tags, which Rob describes in detail for listeners unfamiliar with it.
00:06:14 - ColdFusion's Legacy and the Path to Ruby on Rails
The hosts and Rob explore ColdFusion's surprising staying power, particularly in government websites where the .gov domains still occasionally show CFM file extensions. Rob traces ColdFusion's ownership history from Allaire to Macromedia to Adobe and notes the unusual cost barrier of its server license, which set it apart from the open-source ecosystem. He also mentions creating his own framework and references ColdFusion on Wheels, a Rails-inspired project still maintained today.
Rob then describes his transition to Ruby on Rails, which offered the same rapid development feel as ColdFusion but with far better organization and a language that matched how his brain works. This Rails background directly informed RedwoodJS's philosophy of convention over configuration. Christopher briefly highlights that the UK government has modernized to React-based systems, contrasting with the fragmented approach of U.S. government websites.
00:09:27 - The RedwoodJS Tutorial: Parts One and Two
Christopher asks about the tutorial, and Rob walks through its evolution. He starts with "part zero" — Tom's original README written on a plane outlining Redwood's vision, including the website-API architecture speaking GraphQL, plus integrated Storybook and Jest. Part one of the tutorial covers building a blog application with core Redwood functionality: components, GraphQL, database access, and deployment to Netlify, which was the first deploy target.
Part two adds a comment engine built entirely with Storybook for component isolation and Jest for testing. Rob explains the philosophy behind splitting the tutorial: part one serves users by teaching how to build the app, while part two serves developers by introducing tools for faster, more reliable development. Anthony and Rob discuss whether the two parts should be combined, with Rob arguing that the separated approach prevents overwhelming newcomers who may be learning React, GraphQL, and Prisma simultaneously.
00:14:17 - Testing Culture in JavaScript vs. Ruby
The conversation turns to testing philosophy and the state of testing in the JavaScript ecosystem. Rob observes that testing culture is deeply embedded in the Ruby world but still emerging in JavaScript, where developers often struggle to find clear guidance. Anthony notes that advocates like Kent C. Dodds are pushing testing forward, and people get excited when they hear Redwood builds testing tooling directly into the framework.
Rob describes the different testing layers in Redwood: service tests for business logic, React Testing Library tests for the front end, and the current absence of formal GraphQL tests since the SDL is simple enough to not require them. Christopher raises the topic of role-based testing for authentication, and Rob explains Redwood's mockCurrentUser function, which lets developers simulate logged-in users with specific roles during tests to verify authorization logic works correctly.
00:21:14 - Future Tutorial Ideas and Choose Your Own Adventure
Anthony asks about potential content for a part three of the tutorial. Rob shares that the team envisions it as an optimization-focused installment, covering topics like skeleton loading states integrated into Redwood's cell loading components, caching strategies, cache invalidation, and database or GraphQL performance improvements. The philosophy follows the principle that premature optimization is the root of all evil — parts one and two build the app, part three refines it for production.
Anthony proposes a "choose your own adventure" model where users could select their preferred deployment target, authentication provider, or even toggle between JavaScript and TypeScript throughout the tutorial. Rob agrees this could work well given Redwood's growing number of deployment targets and provider integrations. The group acknowledges the combinatorial complexity of front-end and back-end deployment options and jokes about the gap between imagining features and actually building them.
00:24:39 - The Art of Teaching and Beginner's Mind
Anthony asks whether Rob has formal training in education or curriculum design. Rob shares that he has none, but recounts his first teaching experience: creating SketchUp video tutorials tailored for woodworkers at a community college class. Those videos, framed around woodworking terminology like mortise and tenon joints, still receive appreciative comments weekly from viewers who failed with other tutorials.
Rob attributes his teaching ability to maintaining a beginner's mindset, referencing the concept from "Zen Mind, Beginner's Mind" and what Anthony calls the curse of knowledge. He gives a practical example from writing the Redwood tutorial: when he made mistakes or forgot how something worked, he would intentionally leave that wrong path in the tutorial to match where learners might stumble, then guide them back to the correct approach. This deliberate inclusion of common mistakes makes the tutorial feel more natural and forgiving.
00:27:56 - Testing Deep Dive: Mocking and Its Trade-offs
Rob explains the various types of tests — integration tests that render and interact with UI (like Cypress or Selenium), controller tests that bypass the UI, and unit tests that focus on database models. In Redwood's architecture, these translate to service tests and React front-end tests. The discussion then shifts to mocking, which Rob frames as simulating external dependencies so tests focus on your own code rather than third-party services.
The hosts explore the debate around mocking's fragility — mocks can become outdated when external services change. Rob references VCR from the Ruby community, which recorded real API responses and replayed them, periodically refreshing the recordings to stay current. He personally favors mocks for their speed and ability to run tests offline, accepting the trade-off of potential staleness over the latency and connectivity requirements of hitting real services.
00:36:15 - Data Migrations and the Prisma Relationship
Christopher asks about Redwood's migration tooling built on Prisma. Rob clarifies that Redwood's database migration commands simply wrap Prisma's own migrate functionality behind a unified command-line interface. However, he distinguishes this from Redwood's data migration tool, which he built to handle moving actual data between tables — something Prisma's schema migrations don't address, such as denormalizing a user table by splitting columns into a separate preferences table.
Rob notes that Prisma is developing its own data migration capabilities with a revamped migration engine that outputs raw SQL files instead of the previous SDL and JSON approach. While this means Prisma may eventually absorb this functionality, the current Redwood implementation lets developers write JavaScript to programmatically move data, which Rob considers more ergonomic than writing loops and conditionals in pure SQL.
00:39:34 - Repeater.dev: Background Jobs for the Jamstack
Rob introduces Repeater.dev, a free background job service he built to solve a fundamental Jamstack limitation: the inability to run long-running or scheduled tasks. He explains that AWS Lambda functions have a 15-minute execution limit, making tasks like PDF generation or scheduled reminders impossible within the standard Jamstack architecture. Repeater works by accepting a GraphQL request that schedules an HTTP call to a Lambda endpoint at a specified future time or on a recurring basis.
Behind the scenes, Repeater is a Ruby on Rails application using the Delayed Job gem that checks for pending jobs every ten seconds. Rob shares that the project originated from a real need at Tom's nonprofit and has attracted around 200 users without much promotion. The hosts briefly compare Repeater to Quirrel, another background job tool that takes a more JavaScript-native approach with webhook abstractions, contrasting Rob's Rails-influenced design philosophy.
00:45:20 - Redwood 1.0, Pre-rendering, and Closing Thoughts
Christopher asks what excites Rob most about Redwood 1.0. Rob mentions pre-rendering as a major anticipated feature, which sparks a lively debate about terminology. The team discusses whether generating static HTML at build time constitutes SSR, SSG, or pre-rendering, with Christopher arguing it's static site generation while Rob notes the core team has been calling it SSR. They settle on "pre-rendering" as the most accurate term, matching the prop name Danny is implementing in his draft PR.
The episode closes with Rob articulating the philosophy of tutorial-driven development, tracing it back to Tom's 2010 blog post on README-driven development. Rob extends the metaphor: writing code gives someone a fishing pole, but writing a tutorial teaches them to fish. The hosts encourage listeners to check out the tutorial at learn.redwoodjs.com, contribute translations, and request free Redwood stickers shipped anywhere in the world.
Transcript
00:00:00 - Anthony Campolo
It was great. There was one point where I was explaining it to him, and he didn't really get the lambda lift thing about how they all end up in one giant handler. He thought we were actually deploying all these lambdas and different microservices. Then it clicked in his head. He was like, "Oh, okay, cool. I thought you were crazy for a second."
Welcome back to the Full Stack Jamstack podcast. Today we have Rob Cameron. We're very excited to have you, Rob. We'll be talking exclusively about Transformers and retro gaming for this episode.
00:00:39 - Rob Cameron
Yes. Excellent. Hello everyone. Thanks for having me.
00:00:42 - Anthony Campolo
Why don't you tell the listeners a little bit about yourself, what your current role is, and then after that we can get more into your background?
00:00:50 - Rob Cameron
Sure. I'm Rob Cameron. You'll know me as Cannikin on GitHub and Twitter. I'm currently on the founding team of RedwoodJS along with Tom Preston-Werner, Peter Pistorius, and David Price. So I'm the elusive fourth member.
I've known Tom for almost 15 years, and he was like, "Hey, I'm working on this RedwoodJS thing. It's kind of like Rails, and I'm a Rails developer." So I was like, "Hmm, curious." He showed me what they were doing, and it felt like the beginning of Rails where you've got this little nugget and no one else knows about it yet, but there's something super magical there. I was like, I can get in on the ground floor of that.
After his sales pitch, I was all on board and I've been on it since. I think my first commit was September of 2019, but then I did some other side work.
00:01:36 - Rob Cameron
Technically, I'm actually employed by Tom. We can talk about that more. He has a nonprofit that I work for. So I did some other nonprofit stuff and then came back basically in January of 2020 and was on Redwood at least 50% of my time. So that's when my commits really started.
One of my first big tasks was writing the tutorial, which I think is what we're talking about, right? Tutorial-driven development. So that was me. I wrote that tutorial, which helped drive the actual development of the framework itself.
00:02:01 - Anthony Campolo
Yeah, we're definitely going to get into all those things you mentioned. Tutorial-driven development has been something I've talked about on almost every podcast I do about Redwood, because I'm very outward focused in terms of telling people about Redwood, explaining it to them, and explaining the tutorial.
It's how important it is and how important it was for my own personal story as well, getting involved in Redwood. It's been something the community can rally around in a really cool way. Claire has talked about how she went through the tutorial.
Before we get into any of that, though, how did you first get into programming? What was your very first programming language, first program you wrote? That kind of stuff.
00:02:42 - Rob Cameron
The very first program I wrote, and I wouldn't say wrote like I created the code myself.
00:02:47 - Anthony Campolo
Copy-paste counts.
00:02:48 - Rob Cameron
I would just read it out of a book and type it in on my dad's Tandy TRS-80 Model III. That was the old computer you could buy at Radio Shack. I was probably 8 or 9, and he had plenty of programming books laying around. He was a chiropractor, and he wrote the software for himself for invoicing people, basically to keep track of his patient records.
I assume they probably had BASIC software you could buy on a floppy disk and install, and that was your office management software, but he just wrote his own. So he had all these programming books laying around, and a lot of them were just little fun games, like tic-tac-toe and a little skier going down a slope.
I would get this book and open it up, and I would just sit there and read the book and type the code in, not having any idea what I was doing. At the end you'd type run and you'd have your little skier going through the thing.
00:03:31 - Rob Cameron
I actually have the first programming book I remember from my dad. It was this orange-covered book, and I found it at a bookstore in Portland, and I actually have it on my shelf back here. That's my little history thing. I'll have to print that out on one of our next Redwood meetings.
So that was my first one. It was BASIC, but the first language I wrote myself and knew what I was doing was more like HTML. In college, everyone has a home directory and you can have your own web pages up, presented on the school's internal web server.
00:03:59 - Anthony Campolo
No, this is not a thing I ever had or knew many people who had. That's a thing.
00:04:03 - Rob Cameron
As far as I know, everybody got it. I started going down the CS path, but it was before I had actually declared my major. I think even in the first year everyone had a tilde. Mine was ~RCameron and it was like cs.something.edu. So you had a home directory and it would be a publicly served web page if you wanted.
00:04:21 - Anthony Campolo
Yeah, we got an email address, but we never got a home page. Definitely not.
00:04:25 - Rob Cameron
Once you figured out how to do it, I'm assuming 90% of people never really looked into the website part of it, but somehow I got in there. I had a web page and it was a Mortal Kombat fan page. I loved Mortal Kombat at the time, so I had everyone's profile and all their moves and everything.
I basically taught myself HTML. JavaScript existed at the time, but it wasn't really a thing people just did. It was a weird curiosity for making a Windows 3.1 desktop out of JavaScript. I used to call it dynamic HTML back in the day, so you could drag and drop things, but I wasn't into that yet. I don't think CSS was even a spec yet at that time.
So I'm writing my own stuff at that point. My first quote-unquote real language would be ColdFusion. I don't know if people remember that.
00:05:04 - Anthony Campolo
I've heard about it. What exactly is ColdFusion?
00:05:07 - Rob Cameron
It kind of coined the term rapid application development, and that's what Rails started out as. That was the term du jour that everyone used, but ColdFusion sort of pioneered that.
It basically looked like HTML tags, but they would start with CF. So for conditionals you'd have CF tags, or a CF tag for a loop, or CF output when you actually wanted to interpolate a string back onto the screen. You're writing HTML tags in your HTML, but then a server would run through that HTML page first, parse out all the ColdFusion tags, turn it into whatever the output would be, and then you'd serve the HTML page. You could even have CF query and you'd write SQL right inline.
So it's basically like you'd have an HTML page with SQL and conditionals and dynamic stuff all in there. It would get compiled down to HTML and you're back in HTML land.
00:05:57 - Anthony Campolo
That's so interesting because I've heard people talking about ColdFusion before and I've never really heard it explained, like actually what it was. But now that you're explaining it, it makes sense because people always talk about it as something they did for a job, like they were paid to write ColdFusion. And it sounds like that's because it did a bunch of stuff and made it really simple to do.
00:06:14 - Rob Cameron
It caught on a lot in governments for some reason. A lot of times if you go to a government webpage, like a .gov page, if you see the extension is CFM, that's ColdFusion. They call it ColdFusion Markup Language, CFM or CFML. Every once in a while you'll go to a webpage and you'll still see CFM on there.
At one point I created my own framework. There was a ColdFusion framework called ColdFusion on Wheels. It's still out there. It was a play on Ruby on Rails. As Tom says, the worst name ever, but I believe it's still actively maintained and people still use it.
00:06:43 - Christopher Burns
It is still updated, it seems.
00:06:46 - Rob Cameron
Yeah.
00:06:47 - Christopher Burns
When I searched ColdFusion, the first article was, "ColdFusion is not dead. It's here to stay and it's alive."
00:06:54 - Rob Cameron
Yeah, it's still out there.
00:06:56 - Anthony Campolo
That's the type of article you see, and it means yes, this is dead. The conclusion you should draw is that this thing is dead.
00:07:02 - Rob Cameron
It's propaganda from the Big ColdFusion team.
00:07:05 - Anthony Campolo
It's like people saying, "Meteor's not dead."
00:07:07 - Rob Cameron
It was originally a guy, Jeremy Allaire, I think, was his name. So it was Allaire ColdFusion, and then Macromedia bought it. Macromedia, the ones who did Flash, or eventually bought Flash, I should say. And then Adobe bought Macromedia. So now it's Adobe ColdFusion, and it's a server product.
When I was doing it, one install was like $1,000. So it was kind of an outlier because you had to pay for this software to run, whereas everything else was basically open source at the time. You're paying for ColdFusion server to actually run and serve your code. I think there was a development one you could run for free, but it would only respond on localhost. So if you wanted to publish to the internet, you had to pay for a server from ColdFusion.
Then I got into Ruby on Rails, and it had that same feeling. It's really easy to get an app up and running, but it was much more organized, much more proper.
00:07:49 - Rob Cameron
It just felt better. The Ruby language to me is still my favorite. It just feels much more like how my brain works. And then from Ruby on Rails, that brought me into the Redwood side, using some of the Rails concepts, convention over configuration. That was the big mantra for Rails.
We're trying to bring all of that into Redwood as well. Although the languages aren't the same, Ruby and JavaScript, a lot of those concepts that Rails introduced are what we're bringing into the JavaScript world now.
00:08:15 - Christopher Burns
It's funny how you say government websites using ColdFusion. The UK government is actually quite modern and progressive. They use React. They have their own framework they've built. I'll post it. It's all open source on GitHub. But for a standardized government system, it's pretty good these days. Everything through the government now uses this interface. It's pretty sweet if you've never had to think about it.
00:08:46 - Rob Cameron
I feel like here every government, every state government, every city, everyone's on their own. They all just kind of do their own thing. I assume at the time maybe it was ColdFusion just because governments are the ones who had the money to pay for ColdFusion licenses so they could run it.
00:08:59 - Christopher Burns
What's the other language most governments use that's still around? Oh, it's COBOL.
00:09:05 - Anthony Campolo
It's a joke. Not most, but COBOL. No, most do not use COBOL.
00:09:10 - Christopher Burns
I've heard a lot of US governments use COBOL.
00:09:13 - Anthony Campolo
A single article was written about a single place in New Jersey that was using COBOL, and people spent a week talking about it.
00:09:20 - Rob Cameron
I haven't seen that article, but I've never seen any COBOL stuff myself. I've heard it's not great to work with on a daily basis.
00:09:27 - Christopher Burns
We're here to obviously talk about what you've done in Redwood, and one of the biggest things is the tutorial. When I first learned Redwood, I think it was like 0.8. The first tutorial was there, and I have to admit, I went through it and then never looked at it again. I don't think I've actually ever looked at it again. I've just kind of scrambled my way since. And now part two has come out. What does that involve over the first part?
00:09:58 - Rob Cameron
Part one. Well, let me go back to part zero. Step zero was sort of the philosophy of Redwood. There's a README that's still up there now, and Tom wrote that out. He was on a plane and wrote out his vision for what he wanted Redwood to be.
As part of that, it was not only this front end and this back end, the website and this API side, talking to each other, speaking GraphQL, sort of this common tongue between them, but also tools for development itself.
Storybook, which if people aren't familiar, lets you build your components in isolation. You get a nice UI interface and you'll have a navigation tree on the left side. It's basically all of your components in your app, and you can view just that component in isolation on the web page, and you can build out your whole component right there in isolation.
00:10:43 - Rob Cameron
It looks good. You like the way it looks. You can make variations of it. Maybe here's one with this prop passed in versus this prop, and how it's going to change the appearance. Get all that figured out, and now when you're ready, plug it into your app. So that's Storybook.
Then Jest handles the testing. You have UI tests, unit testing. We're doing some testing with the database, which we'll talk about in a minute. But at the time this was just part of Tom's vision. We had no idea how this was going to actually become integrated into Redwood. No one had ever done that before, as far as I understand.
When I wrote the first part of the tutorial, we hadn't figured out Storybook and Jest yet. So part one was just website and API side talking, GraphQL, building components, talking to the API, getting data out of the database.
00:11:21 - Anthony Campolo
Deployment was also in part one, though. That's worth pointing out as well.
00:11:24 - Rob Cameron
Yes, deployment was. That's one thing we wanted to do. You can build a whole app, but you can't get it out, it doesn't do any good. Our very first deploy target was Netlify, just because Tom had been really interested in them. He was very bullish on Netlify and how easy it was to deploy. So we figured out how to deploy. Netlify worked great.
Part one was out in the world and ready to go. A lot of people deployed their first Redwood app thanks to that first tutorial. I should say it's building a blog. We thought about what's a common application that most developers would probably be somewhat familiar with, and we settled on a blog.
A blog probably wasn't the best app to build with Redwood because Redwood was meant to be super dynamic, talking to a database.
00:12:06 - Anthony Campolo
It's a great example for the Jamstack, but the whole point of Redwood is we're trying to push the Jamstack further. By saying, "Here's this old application that you can already build with the Jamstack," it's not very exciting. You're saying this is a step change into what we can build. So that's why there's a disconnect there. It's nice to teach, but we always have to keep saying this isn't quite what Redwood is actually made for, right?
00:12:27 - Rob Cameron
We wouldn't say if you're going to build a blog, build your blog with Redwood. It was just that a blog was a common application that most people were familiar with. And here's how you would do that in Redwood.
A blog is ideal, right? Every page is basically statically generated because it's never going to change, which is what you would use the Jamstack for. But for the full stack Jamstack, you wouldn't necessarily go that direction. Again, it's just a very simple common app that's easy to build. People have this common language where they understand what you're talking about: blog things. So that was part one.
Part two then was, okay, now let's stay on this blog path and add a comment engine. But we're going to build this comment engine using Storybook and Jest. Storybook and Jest integration is ready in Redwood, so now here's how you actually do it. We build out the comment engine in Storybook.
00:13:11 - Rob Cameron
Ignore the rest of the app. There's no API. Ignore all that stuff. Just build the comments as you would. You can mock out the API as if it was there, but you're not really using the API. Then we write a bunch of tests to verify that functionality is still working, and you run your tests. Your tests are green. Great. Now plug that comment engine into the real app, redeploy, and now you have your comment engine.
Part one was for the users. Here's how to build the app that your users are going to use. Part two is for us, the developers. It's how to build the app quicker and smoother, and then how to verify your functionality keeps working with testing.
00:13:41 - Christopher Burns
A lot of other stuff is sadly not tested in any functionality. So when you change something in that area, you go, "Oh, just go check, it works," and it's really bad. But I think there's always a fine line between getting something out in the world and getting something perfect in the developer experience. What do you think? Do you think Redwood has got it right now? As in, I'm not spending too much time in developer land to still make sure things ship.
00:14:17 - Rob Cameron
You can completely ignore Storybook and testing. You don't have to use any of that, but I feel like the additions we've added make it more pleasurable to use.
Testing in the JavaScript world, still to this day, you ask someone, "How do you test this?" and everyone's like, "I don't know. Go search Google and figure out how to do it." Testing culture isn't really embedded in the JavaScript world yet like it was in the Ruby world. If you're doing Ruby, you're just doing testing. That's just the way it is. Everyone has sort of accepted that.
00:14:45 - Anthony Campolo
I think there's pockets of it in the JavaScript world. If you look at someone like Kent C. Dodds, he's made a huge name for himself in testing JavaScript. I agree that it's not as big as it needs to be and as it was in the Rails world, but I think there are people pushing in that direction. When I start talking about testing Redwood, they get fired up because they're like, "Oh, someone's building testing into a framework."
00:15:08 - Rob Cameron
Finally, there was Jest, which is I guess you'd call it a framework for testing, but that's it. It's just the tests. There's no front-end framework that wants you to test and gives you tools to make testing easier. I think we're kind of the first ones to do that.
00:15:21 - Anthony Campolo
Something I'm curious about, and that I've thought a lot about because I've spent a long time with both tutorials, the first tutorial and the second tutorial as you've been building it out. I'm trying to think of how we would eventually have some sort of integrated version.
I think the problem with the way we've built it out and the way we've had them separated is that you build the whole application and then you learn how to do the Jest and the Storybook stuff. I think ideally we could bring in the testing and Storybook stuff right when you first learn the cell stuff, and then before you get into the contact form, that would be where I'm thinking it might make sense to sequence it.
Then you could have it integrated throughout as you build out the contact form also. Do you have any thoughts about that?
00:16:12 - Rob Cameron
I thought about that too. Like you're saying, basically combine one and two into just one single flow of building the app all the way through. But then I was thinking, with Redwood especially, it's a lot of new concepts all at once for a lot of people.
It might be a little overwhelming because when I first started Redwood, I had never used React. I built one little sample app with React six months earlier. So I was learning React and GraphQL at the time. We had Nexus in there, which we've since pulled out for Prisma. So there's those four major ones, and then you're going to add Storybook and testing on top of that. Learning all of that simultaneously seems like a lot.
If you're in all those ecosystems already, it's no big deal. But if you're just starting out, that might be a little much. I kind of like the idea that here's one subset of tools you can build a complete app with, you get used to that, and now here's some additional new tools you can add on. It's integrated with the stuff you already know, and it's not as overwhelming. So right now I kind of like it the way it is. But yeah, we should get together and talk about that and see if that would make it even better.
00:17:08 - Anthony Campolo
That's basically what I'm thinking, because when I wrote my first "Look at Redwood" series, I essentially watched the video tutorials. I hadn't really read the docs tutorials. I watched the video tutorials beginning to end and followed along with that to build out the project.
Then as I was doing that, I screenshotted everything. Literally every single terminal command, terminal output, code, and anytime anything changed in the browser. Then I sequenced it and ended up doing two posts for each video. There's four videos. I ended up with eight posts, and each got split into two posts. It helped me break the whole thing down into pieces in my head.
Because you go from setup and pages to layouts to Prisma to cells to contact form to GraphQL to authentication to deploy. I can still just think of the whole thing as a linear sequence in my mind now. And as I was giving presentations on it, the first one I did parts one through four. The second one I did parts one, two, and eight. The third one I did parts one, two, three, four, and eight.
So now I was slowly building up more and more pieces of it to where I've essentially internalized the entire thing and can do it almost all from memory. I'm kind of thinking how to integrate both tutorials into some sort of long book. That's where my brain is at right now.
00:18:27 - Rob Cameron
I guess if you were writing it as a book, maybe it wouldn't be as tough. I guess it's no different than reading it online where you can flip back if you're getting confused and seeing too many concepts. You can always go back where you were and start over. So it could totally work. What are you going to do when we add part three?
00:18:44 - Anthony Campolo
This time it's a western.
00:18:47 - Christopher Burns
I have an idea for something that should be in part three: meshing multiple GraphQL APIs into one endpoint. It's something that you think about, but then you don't because Redwood's GraphQL API is great. But what happens if you want to use a service that also uses GraphQL? Then it starts getting quite complex to manage both schemas. There are multiple ways to do it, like just passing through functions, where you call your Redwood, then your Redwood calls their GraphQL API. But the best way would be to use something like GraphQL Mesh that would combine multiple GraphQL APIs for you. So you could call multiple APIs as well.
00:19:39 - Rob Cameron
But you're thinking you'd want that integrated into Redwood itself.
00:19:42 - Christopher Burns
Yeah. Really interesting concept. I want to host all of the strings in my Redwood application in a CMS. Redwood is a bad application for CMSes because CMSes have GUIs, and that's why I want to use a CMS. And for me to build my own CMS is a lot of effort. So I looked at something like GraphCMS that has a very nice interface and a GraphQL endpoint that you can just pull the data from.
After my experiments, you could merge GraphCMS and Redwood, then in one cell pull the strings from the CMS and the database code from Redwood. In my tests, it's worked out really well, except GraphQL Mesh is currently early and there's an authentication bug, meaning you can't do protected calls right now.
00:20:47 - Rob Cameron
If we did GraphQL Mesh and it was natively handled by Redwood, then we would totally add that to the tutorial. I think for now the tutorials are always going to be just Redwood functionality itself. 90% of people probably want to integrate with a third-party API, but we have that as a cookbook article because that's a one-time thing. Here's what you want to do. It's not really part of core Redwood itself, unless we added some tooling that made that easier. Then we would totally roll that into part three of the tutorial.
00:21:14 - Anthony Campolo
Do you have thoughts about what you would want to be in part three of the tutorial?
00:21:17 - Rob Cameron
I don't think this is necessarily written up in the README, but another thing we were thinking about was skeleton loading states. React has programmatic loading states where you get the little gray circles and gray lines that represent the visual layout of your page.
00:21:35 - Anthony Campolo
React Skeleton, I think is what it's called.
00:21:37 - Rob Cameron
Yeah. Or skeleton loader or something like that.
00:21:39 - Christopher Burns
Yeah, skeleton loading.
00:21:41 - Rob Cameron
Right. We want to bring that into Redwood. The initial thought on part three is it's the optimization part. It's going to be stuff like this.
We already provide cells with a loading component, and we don't give you any special helpers in there other than you just write some text like "loading..." We want to have that skeleton be integrated into that, so it makes it really easy to draw a skeleton as part of the loading state.
So here's how to do your loading state with Redwood. Aldo, who's another guy on the core team, he's talking about what he calls Redwood at scale, which is handling caching and cache invalidation. Eventually we'll have tools in Redwood to denote how long something should live in the cache. We'll probably have that in the tutorial, maybe some database optimizations or GraphQL optimizations.
Anything like optimize your app. Premature optimization is the root of all evil, so we didn't optimize in parts one and two. But now part three, we're ready for the optimization. You're in production, you want to speed it up, make it faster, make it smoother to use. That's the part three focus.
00:22:39 - Anthony Campolo
Something I think about is how you could turn this tutorial into a kind of choose your own adventure. I was talking about how I separated it out into eight pieces and piece seven was auth and piece eight was deployment.
I've thought about how you could have the deployment fork off in different paths, and the auth fork off in different paths. Right now we have one canonical tutorial with one canonical way to do auth and deployment, and then there's all this stuff in the docs about how to do it in other ways. But I think it would be cool if you could go through the tutorial but choose the tech beforehand, so you get the same tutorial experience but with whichever tech you want to use.
00:23:18 - Rob Cameron
I can see that with deployment working really well. We have four or five different deployment targets now, so you can split off into how you want to deploy.
00:23:26 - Anthony Campolo
It's a harder question than that, because there's different ways to deploy the front end and the back end and different ways to combine them. You could do Netlify with Heroku or with Azure Postgres, and they do the same thing with Vercel. There are so many different combinations. You could do Supabase but with different front ends.
00:23:44 - Rob Cameron
Right.
00:23:44 - Anthony Campolo
Or you could do an all-in-one deploy target. There are so many ways to section off into different tech that people might want. I see some docs that have a way you can switch everything from JavaScript to TypeScript. I know Chris would love to have in the Redwood docs a button that would turn all the examples into TypeScript automatically. How sweet would that be?
00:24:06 - Christopher Burns
Prisma does that. Prisma is one of them.
00:24:12 - Rob Cameron
We encourage and would happily look at any PR that provides that functionality.
00:24:17 - Anthony Campolo
Yeah, that's what I tell Chris every time we start suggesting all this cool stuff. Like, wow, it'd be really cool if any of us would build this.
There's so many things you could do with it. Coming from my background as a teacher and seeing the way you built this out, do you have any education experience or curriculum design experience or pedagogy? Do any of those terms even mean anything to you, or do you just do this intuitively?
00:24:39 - Rob Cameron
No, I don't have any formal training at all. My first real tutorial example, if anyone's heard of SketchUp, it's a 3D modeling software and it's 10 or 12 years old now.
I was in a woodworking course at a local community college, and the teacher was recommending, "Hey, if you want to design your stuff here, you can use SketchUp." And this is a room of 60-year-old white dudes. I'm like, there's no way these guys are going to be able to use a 3D modeling software in time for the next class.
But I had been using SketchUp myself for my own projects, and I was like, I can probably teach someone how to use this. So I made a series of videos. I think there's six or seven and they're still up on YouTube. I taught people how to use SketchUp in the mind of a woodworker. Here's how to do a certain kind of joint, here's how to do this.
00:25:21 - Rob Cameron
It wasn't like building a house. It was building a piece of furniture. And knowing the terminology that woodworkers use, it was very easy to show, like, here's how you do a mortise, here's how you do a tenon. I still get a dozen comments a week. Everyone's like, "Oh my God, this is amazing. I tried so many tutorials on SketchUp, I could never figure this out. Yours is the one that did it for me."
I just seem to have a natural way to teach people complicated concepts. I guess it's sort of that famous book, Zen Mind, Beginner's Mind, where most people's problem with teaching is you become more and more of an expert, and then you forget what it's like to not know those things. You assume everybody knows this huge catalog of knowledge already, just like you do.
00:25:56 - Anthony Campolo
The curse of knowledge is another term they use for that.
00:25:59 - Rob Cameron
Yeah. So maybe there's just something in my brain that lets me remember what it's like to have no idea what I'm doing, because I usually don't have any idea what I'm doing.
There are several times, even with the Redwood tutorial, where I would forget how we did something. I'd go down the path in the tutorial, and I'd be like, oh wait, that's not how that works, and I'd have to go research it. Then I realized, if I made that mistake and I sort of know what I'm doing, someone who has no idea what they're doing is probably going to make that mistake too.
So I would leave a little bit of that path in the tutorial and be like, now you might think you need to do this, but here's why you don't. Then we step back and do it the right way. There are a couple of little mistakes like that which I'll keep in there just to match their mindset to what they're learning, where they might make mistakes, and it's no big deal. Here's what you do to correct it.
00:26:43 - Christopher Burns
I should really read the second tutorial part. I don't think I've read it fully. I think I've looked at the test page or the story page and that's it.
00:26:51 - Rob Cameron
It was funny too, because I was dreading writing it. When I started out in Ruby, I was not a testing guy because I came from ColdFusion, which didn't care about tests. So I'm into Ruby and I'm like, "Oh man, this is great. You should be writing tests, unit tests." And I'm like, "This is twice the amount of work. Why would I write these tests?"
Eventually you're on enough projects where everyone else is writing tests, and you're like, all right, I got to write tests now. You get into it and you're like, this isn't that bad because it's kind of cool. It's like verifying what I do.
Then that one time where you have a production deploy and the deploy stops because a test failed, and you're like, oh my God, that just saved my life. That sells you on testing. Now you really want to write tests because you remember what that scary feeling in your soul was like.
00:27:30 - Rob Cameron
My life was almost ruined, but my test saved me. It makes you want to write more tests and better tests. It was just weird for me writing the testing part of the tutorial. Being a guy who doesn't write tests and now I'm trying to write tests in JavaScript, and it's a nightmare trying to find the right documentation. There are so many different ways to do it.
So I'm the one who has to distill all that down and simplify it and write tooling for Redwood to make testing easier. In my own mind, it was just ironic that I was the one that ended up doing that.
00:27:56 - Christopher Burns
Which kind of test is it again? It's not the one where it goes through the user interface. That's end-to-end, is that?
00:28:03 - Rob Cameron
I always fall back to the Rails terms. Integration testing was testing basically the actual UI. There was a tool, Selenium, where it would actually render the page in memory.
00:28:14 - Christopher Burns
Like Cypress?
00:28:15 - Rob Cameron
Yeah. You would actually click a button, see that something happens, see that new text appeared on the page. That was the quote-unquote integration test in Rails.
Then they had what they called controller tests, which was just the controller. When you first make a request back to the server, the controller is what answers that request. You pretend the UI doesn't exist and you just send the right parameters in through the URL. The controller test would handle that.
Then you had unit tests, which are more like testing the actual models, the code that would talk to the database. That was another level down, really far divorced from the UI and requests and HTTP sessions. You didn't have access to any of that. You were basically just getting raw data in and out of the database and seeing how it's manipulated by the models.
It's a little different in Redwood because we don't have those same layers. We call them service tests. That's what's testing your service. That's probably more like the classical unit test.
00:29:01 - Christopher Burns
When you say service, that's an API test.
00:29:04 - Rob Cameron
Personally, I think of the API as the GraphQL layer because that's the API talking over the internet, to me. The service is what we call the business-logic units. Services can use other services without going out over the public API. So we call them service tests.
We don't have formal GraphQL tests right now because the syntax is so simple. You're not really writing any logic into your GraphQL SDL right now, so it doesn't seem as necessary to have tests for. We would like to have something in there to verify that your GraphQL interface is what you think it is. But right now, the SDL language is so simple it's probably not as necessary.
Then we have our Jest testing, which is testing more of the React front end. If this person is logged in, does this link appear on the page? It's using React Testing Library. I always forget what it's called. It's the most generic name.
00:29:55 - Christopher Burns
React Testing Library. You can see the docs.
00:29:58 - Rob Cameron
Yeah. It's the most generic name ever. It seems like I'm getting it wrong, but that's literally what it's called.
We're using that to render the React component. Then you have an object called screen, and screen is basically what was rendered. Now you're testing: is this on the page? Is this on the page? Did this change?
Those are kind of our two layers of testing. We have the front-end React testing and we have the services testing, which is where most of your logic is going to be, not as much in the GraphQL layer.
00:30:23 - Christopher Burns
One of the tests that I'd like to see, and this is actually a problem that I noticed with Aethelflaed, is role testing. All your endpoints have different authentication. One you need to be admin, one needs to be author or whatever. You could literally just say, can you access this function with this role. If it comes back yes, then that's wrong, a failed test. If it comes back no, then that's a complete test, if that makes sense, because that's my worst nightmare.
00:31:01 - Rob Cameron
We have that in our services testing. That's where we recommend right now you put your authentication, in the service. In the tutorial, we have one called delete comment, and you'll have a check in there, require auth role as moderator. If you don't have the moderator role, you should not be able to delete a comment.
We've added something to Redwood, a function we call mockCurrentUser. Right before that test runs, you say mockCurrentUser, and here's the roles they'll have. Now if any of those auth functions are hit within the service, it's going to use that mock user as if they were really logged in, even though you just faked it for the test. Then you'll be able to either pass or not pass that test. There's a test in the part two tutorial that does that.
00:31:40 - Anthony Campolo
I would really like to first get a beginner's introduction to mocking, what mocking is, what considerations go into mocking, because it's a specific kind of testing. I think mocking is a subset of testing and it's something a lot of people talk about. I know a lot of people are asking for it in Redwood. What is a mock? How is a mock different from a test? What goes into all that?
00:32:03 - Rob Cameron
This gets into almost religious levels of fervor of what people believe on this. I will just give you my view, but please don't cancel me on Twitter for anything I'm about to say because this is just how I feel. A lot of this is influenced from the Rails community. Maybe the JavaScript community will go a different way, but this is how we do it in Rails. This is currently sort of how we do it in Redwood, in theory.
You've got a test, and a test should test one thing. It would be great if everything you need to do in your test was handled within your own code. But every once in a while, you're going to have something like talking to a third-party API. Generally in your tests, you don't want to be testing that entire stack of all code that was ever written to let you talk to an API. XHR requests and HTTP headers — you don't care about any of that. That's a settled spec. HTTP itself is not going to break. You don't want to be testing HTTP. That's not going to be your problem.
This is where the idea of a mock comes in. You have a mock object which will simulate all that stuff. It'll simulate the third-party API doing its thing, which you have no control over. They're going to do their thing, so you shouldn't really be going out to them to try to test them. You assume they're going to respond correctly, or you can mock out that it's going to return a certain error. Then you test that your code responds correctly.
You really want to be testing your code, not somebody else's code that you have no control over. In theory, that's where the mocks come in. You're going to mock out functionality that doesn't belong to you.
In Redwood, for example, when you do authentication, you're going out to Netlify, Supabase, or Magic Links, and they're going to do whatever they need to do to prove that you're who you say you are, and they're going to give you back some known data. You're going to mock that known data in Redwood, assume that they do their job. Here's what you get back. Now does your code respond to that data correctly? Does it parse out the email and the name and their roles properly? That's where our mocks come in. Jest has a bunch of built-in mocks, and we've added one like mockCurrentUser. That's our own custom flavor of that.
00:34:00 - Anthony Campolo
This is something that people talk a lot about in the serverless world. It's the same thing. They have all these different external things they're working with. I hear some people in that world who think that at the end of the day, it's not even worth mocking because you're never going to be able to mock the behavior perfectly, that you should just test the thing with the actual thing. What would you say to something like that?
00:34:26 - Rob Cameron
Yeah, that's the other side of the argument. The problem with mocks is they're fragile, meaning if that service you're mocking changes in any way, your mock doesn't know about that. Your mock is going to respond the way it used to, and your code is going to respond to that the way it used to. You won't know when that change happens, which is bad.
That's the downside of mocks. In the Ruby community they had a tool called VCR, and what VCR would do was record a response. The very first time you ran your test, it would go out to that third-party service for real and do the real thing, and then it would record the response back. The second time you ran the test, you'd hit the recording. The theory was once a day or once a week or once a month, you would clear out those recordings and start over.
00:35:03 - Rob Cameron
So you're always getting the latest version of what the third-party service would return.
00:35:08 - Anthony Campolo
It's a really clever name then.
00:35:10 - Rob Cameron
VCR, right, because recording. It was like you record cassettes. It was really smart. I don't know if there's something like that in the JavaScript community yet, but that was a really neat workaround to the problem of fragile mocks.
For me personally, I would rather have the mock and have it all internal. I'd love it if I could run my whole test suite and not even be connected to the internet. If you don't use mocks, you always have to have a good connection. You can't be working on a plane and testing your code because that third-party service won't respond and you'll be screwed.
I personally will accept the danger of a mock becoming out of date. Speed is another big factor too. As soon as you go to a third-party service, there's hundreds or thousands of milliseconds you're waiting for responses to come back, and it slows your test suite down that much more.
That was a big thing in the Rails community. The bigger your test suite got, the longer it took to run. You'd hear horror stories of test suites that took 30 minutes or an hour. The idea with testing is you really want to run it every time you make a code change. The longer it takes to run, the less often you're going to run it. Pretty soon that test suite becomes useless because nobody wants to run it anymore, and now you've defeated the whole purpose of writing the tests in the first place. You want to keep them short and snappy and fast. So I like mocks personally.
00:36:15 - Christopher Burns
Something else you've done in Redwood that I understand, but I don't fully understand, is the Redwood migration tool that's built on top of Prisma. Could you explain that?
00:36:32 - Rob Cameron
Redwood doesn't really do anything with migrations. All we do is that call you make on the command line, yarn redwood db migrate. We just give that call to Prisma and say, "Hey Prisma, migrate yourself." We don't actually do anything on top of that other than give it a common interface, because otherwise you'd be doing yarn prisma, I forget what their full thing is. It's like migrate and then...
00:36:52 - Christopher Burns
It's like yarn prisma migrate. I think you then had to use the developer flag.
00:36:57 - Anthony Campolo
Experimental flag.
00:36:58 - Rob Cameron
There's an up, and then --experimental. We're just hiding all that behind the commands. That way all the commands with Redwood are always rw something, so we just put their command behind ours.
I can explain how Prisma migrations themselves work.
00:37:11 - Christopher Burns
Not that part, but you built a tool to migrate data. Prisma migrates tables.
00:37:18 - Rob Cameron
People have complained about this naming similarity. There's DB migrations, which is Prisma's migrate database. And then we have data migrations, which is migrating the actual data in the database.
There are all kinds of occurrences where, let's say you have a user record and you're storing more and more columns of data in there. This table is getting wider and wider. You realize, I need to denormalize this. I want to split out their preferences into a separate table. Prisma will let you easily create a separate database table called preferences with whatever columns you want. But Prisma doesn't provide a way to now move that data from the user record into the preference record.
That's where data migrations came in, which is the part I wrote. You can programmatically say, okay, now that the preference table exists, loop through every user. Remove these five columns of data, put them over in preferences instead.
00:38:10 - Rob Cameron
So it's actually moving the data itself, not the structure of the database. Does that help explain it?
00:38:15 - Christopher Burns
Yeah. And is that built into the tutorial, or does that just run in the background?
00:38:20 - Rob Cameron
We don't have that in the tutorial because we didn't get that complex with the data. It's just another feature of Redwood we haven't mentioned yet. Maybe we'll do that in the optimization because that would fit. You're optimizing your database tables, you might need to migrate your data.
But Prisma is actually going to steal our lunch. They're adding data migrations themselves. They realized that was an important thing. They're going to have a version of that coming out soon.
00:38:39 - Anthony Campolo
Are they? Because we asked Jason and Jason said, "I don't know."
00:38:44 - Rob Cameron
Last we talked to them, they said they have a new version of migrations, which Redwood isn't on yet, but we're upgrading soon, probably the next release, where they've completely redone their migration engine.
Previously it was this SDL and JSON approach. You would say, here's what I want the database table to look like, and then they would diff that against the current database. They'd have this JSON file with all these changes that needed to run. They've scrapped all that now and they're basically just writing out SQL. A migration file would just be a SQL file with all the database changes.
A data migration is just more SQL. You just write the SQL to migrate your data. The downside is now you're not using JavaScript. You're using SQL to do loops and conditionals, which isn't the most fun thing in the world, but it is possible. We'll see if they add on a JavaScript layer. But last I heard it was going to be straight SQL and it would just run like another migration.
00:39:34 - Anthony Campolo
Now let's get into Repeater. What is Repeater?
00:39:38 - Rob Cameron
As you start building out more complex apps, you'll probably find that at some point you need to do something out-of-band, behind the scenes. It might be in response to a user request, but you can't make the user wait for it. A classic example is an invoicing app where you need to generate a PDF. Depending on the library you use, that might take 10 seconds. You don't want the user sitting there with a spinner.
So you'll have something generally called a background job or background task where the user says, "I want a PDF," click, and then behind the scenes it says, okay, go out and create this PDF, let me know when it's done, or email the user when it's done, rather than the user sitting there waiting.
That's kind of a problem with the Jamstack. Everything needs to be in response to a user doing something. You have these lambdas. A user clicks a button, the thing goes off to Lambda.
Currently, especially in AWS, lambdas can only run for so much time. I think the maximum is 15 minutes before the Lambda will shut down. If you have a job processing a lot of data and it's going to take more than 15 minutes, you're kind of screwed. You can't do that on the Jamstack currently. A background job will occasionally need to run for more than 15 minutes.
We realized we needed one for a project at Tom's nonprofit, Preston-Werner Ventures, where I needed to be able to say, hey, remind me tomorrow to contact this person. So we needed a background job service. I had this idea for Repeater.dev. And don't tell anybody, it's a Ruby on Rails app behind the scenes because that's just your traditional server architecture. You run the server, you do whatever you want on it.
When you want a background job, you make a request to Repeater and say, hey, 24 hours from now, hit this URL. This URL being a Lambda endpoint, a classic Jamstack endpoint. Repeater, the Ruby on Rails app, accepts that request. It's just a GraphQL request. It accepts it, puts a record in its own database, and it has a process using a Ruby gem called Delayed Job that checks the database every 10 seconds. "Any jobs to run?"
In 24 hours that job will be ready to run. It brings that job in and says, "Call this URL." It hits that URL, which is your Lambda endpoint, and then records the response.
Basically all Repeater does is make an HTTP request and record the response, but at a time that you define, or repeatedly. You can say do this every hour or every day. That solved that problem instantly. We've had about 200 people sign up. We haven't really promoted it much, and it's a totally free service right now.
00:42:00 - Rob Cameron
David, I'm not sure how to pronounce his last name, [unclear].
00:42:03 - Anthony Campolo
It's a Swedish name. It's hard to pronounce.
00:42:05 - Rob Cameron
He parses a lot of Twitter data. Tens of thousands of tweets, I think. He can't do that all inline. Lambdas aren't going to run long enough. So he makes a ton of jobs on Repeater. A lot of it we built to help him with what he needed to do. He's doing a ton of jobs all the time and it's been running great.
It's a free service, Repeater.dev. If you need background job processing for your Jamstack app, let us know.
00:42:28 - Christopher Burns
Any stickers?
00:42:30 - Rob Cameron
Not for Repeater, but you can get stickers for Redwood. Have you guys promoted the Redwood stickers?
00:42:35 - Anthony Campolo
Not as much as we should. We should just put a little tagline at the end of each episode saying, "And don't forget your stickers."
00:42:40 - Rob Cameron
Yeah. Anybody, if you want Redwood stickers, go to RedwoodJS stickers. There's also a link right on the homepage, and we will send you stickers anywhere in the world for free. As long as you can get mail there, we'll send you some. Come and get some. I should make some Repeater stickers.
00:42:55 - Anthony Campolo
At one of my talks, you made some sort of comment about stickers, and you can still find the video for it. I went, "Yes, stickers." There would be no Redwood without stickers.
00:43:06 - Rob Cameron
That's right. Is it really a real project if it doesn't have stickers? That's the question.
00:43:10 - Anthony Campolo
So do you know anything about Quirrel and how Repeater is similar or different?
00:43:16 - Rob Cameron
Very superficially. The way I wrote Repeater is you just make a GraphQL call like any other GraphQL call and say, "Here's a job, run that."
Quirrel is more like an actual library you bring into your code and you define your job with Quirrel's function syntax. I'm not explaining this very well.
00:43:37 - Anthony Campolo
That makes a lot of sense actually. You're saying that Repeater is something that you go onto a dashboard and do, whereas Quirrel is something you actually bring into your code. Repeater, you don't actually bring it into your project.
00:43:50 - Rob Cameron
I wrote a Repeater.dev JS package you can bring in, but all it's doing is making a GraphQL call, so you can make that yourself really easily. It's not doing anything special. But I believe Quirrel is built on this special library where you...
00:44:03 - Christopher Burns
It's an abstraction of webhooks, basically.
00:44:06 - Rob Cameron
Is that how it works?
00:44:08 - Christopher Burns
Yes. He still has a service running somewhere that's executing these jobs. That service pings the webhooks, his abstracted layer of webhooks. How Quirrel works: you basically give a task. So you say task one. Then you would have a Quirrel file, as well as a function that would have async functions for task one, task two, task three.
Any code in that task one would be run when that endpoint gets hit. In 24 hours time, you would have like an "email new user in 15 minutes" function. In 15 minutes it would ping that webhook, and then that webhook would run whatever code is in that function, if that makes sense.
00:44:58 - Rob Cameron
Yeah, I think so. I haven't used it personally. Repeater felt much more like the Rails way to do it, so that's how I built it.
00:45:05 - Anthony Campolo
Common theme in this episode, it sounds like.
00:45:07 - Rob Cameron
Exactly. This theme should really just be called Rails. Rob loves Ruby.
Personally, I like the Repeater way, but the Quirrel way is very interesting. It feels more like a JavaScript-ish way to do it. Mine feels more like a Ruby way to do it.
00:45:20 - Christopher Burns
One of my last questions is, what are you most excited about with 1.0 of Redwood?
00:45:29 - Rob Cameron
Oh geez. I wish you would have prepared me for this question so I could think of a pithy, interesting answer.
00:45:35 - Anthony Campolo
How were you not expecting this? 1.0 is coming up. I know this is the only question I was going to ask for the next two months, so get ready.
00:45:43 - Rob Cameron
I can't think of anything necessarily revolutionary that's going to be in 1.0 that isn't already hinted at in the current Redwood. We're hoping to have some server-side rendering.
00:45:57 - Christopher Burns
Server-side rendering.
00:45:58 - Rob Cameron
Yeah. As soon as Redwood 0.1 came out, one of the first issues that came up on GitHub was, "Do you guys support SSR?" People have been begging for that.
00:46:08 - Christopher Burns
Do you mean SSG, not SSR? Server-side generation.
00:46:13 - Rob Cameron
We're doing server-side rendering. At build time we'll render out a flat HTML file.
00:46:18 - Christopher Burns
That's SSG.
00:46:20 - Rob Cameron
Is it? Because we keep calling it SSR.
00:46:21 - Christopher Burns
I'm pretty sure SSR is when the server is spitting an HTML document out to the client, and SSG is when you look through the files, generate HTML into them, and then rehydrate them when JavaScript loads. I'm pretty sure that's SSG.
00:46:44 - Rob Cameron
But we're not doing that on the fly. There's no server sending you pages. At deploy time, we're generating all the HTML and it's done and that's what gets deployed.
00:46:51 - Christopher Burns
I think it's SSG.
00:46:53 - Rob Cameron
Are you sure? Because people a lot smarter than me keep calling it SSR.
00:46:56 - Anthony Campolo
The problem is people who say SSG are usually saying static site generation. That's why all these acronyms lead to far more confusion than clarification.
00:47:05 - Christopher Burns
I've been doing this by myself in [unclear]. The package I've been using is React Snap, but they don't say SSR or SSG.
00:47:18 - Anthony Campolo
Pre-rendering is static generation. I just learned this a week ago. Everyone's been saying pre-rendering instead of static generation for some reason.
00:47:26 - Christopher Burns
What you've just described is static generation, as you're going to render HTML to the client.
00:47:33 - Anthony Campolo
So it's SSP, server-side pre-rendering.
00:47:36 - Rob Cameron
The prop you give your route is prerender. Does that help?
00:47:42 - Christopher Burns
The most basic thing that I can understand is whenever you load an HTML file in React, that HTML file has one empty DOM that then the React tree injects into. With SSG, it builds that into that div. Then when the client renders, it will rehydrate over that generated code. That's what I understand, and I thought that was SSG.
00:48:22 - Rob Cameron
I just put a link in the chat. Do you guys have show notes? You can put this in the show notes.
00:48:26 - Anthony Campolo
Yes, we do.
00:48:27 - Rob Cameron
This is the PR that Danny has open. Danny is the one working on, I'll call it prerender because that's the name of the prop he's working on. Here's his draft PR for how he explains how it works.
00:48:38 - Anthony Campolo
That's great. We're going to have Danny on tomorrow, so we'll ask him. We'll have a whole conversation about this, so we don't need to get into it too much.
00:48:45 - Rob Cameron
Yes, please. But as we were talking about it, we had a meeting about it with the core group yesterday, and we kept calling it SSR. All I know is, your marketing page, right? You would literally from the CDN get a fully rendered...
00:48:58 - Christopher Burns
That hasn't been hydrated yet.
00:48:59 - Rob Cameron
Right. You could have JavaScript turned off and you will get your full marketing page rendered. If you have JavaScript turned on, it will then get rehydrated and replaced. Does that help?
00:49:08 - Christopher Burns
Danny is calling it pre-rendering and I agree because you're rendering to HTML before the hydration. Rehydration is obviously complex. I've only truly understood it by learning how it works with React Snap myself.
00:49:29 - Rob Cameron
He's using, I forget what it's called. It's basically a server that just renders out HTML from a React component. I can't remember the name of the npm package. React DOM server, I think.
00:49:43 - Christopher Burns
Off the top of my head, you basically need to create Chrome that will then render the whole application, capture the HTML structure, then inject it into your static HTML file.
00:49:58 - Rob Cameron
He specifically said that does not have to happen. You don't have to have a headless browser to do this. However it's working.
00:50:03 - Anthony Campolo
We got a lot of questions for Danny. All right. Is there anything else you'd like to talk about before we close it out?
00:50:08 - Rob Cameron
Tutorial-driven development in general. There was a blog post, we can put this in the show notes. A blog post from Tom back in 2010 called Readme Driven Development, where he proposed this idea of, as a developer, everyone wants to start with code. Get to the code. Let's code it.
But he was like, at some point someone else has to use this code. Writing the README to start with forces you to think about how this code is going to look and feel to someone who has no idea what your code does or how it works. It'll get you to make some decisions early on. Once you get into the code, it's a little too late to make a nice interface. So it forces you to think about that interface from the start.
Tutorial-driven development is the next evolution of that. It's like, how do you teach this to somebody? If it's not a really simple idea and easy to teach, then maybe the interface you're thinking about is too complex. It should be easy to teach first.
The analogy I like is the famous "give someone a fish and you feed them for a day, teach them to fish and you feed them for a lifetime." When you write your code, you're not necessarily giving them the fish. You're giving them the fishing pole. Here's a pole, here's your tackle, here's your bait. Good luck.
They technically have the tools, but they need to figure it out for themselves. But the tutorial is teaching them how to fish. So be the teacher, not the fishing pole giver. That sounded much better in my head. That didn't come out that great.
00:51:25 - Anthony Campolo
Well, thank you for being here, Rob. I can say that you taught me to fish, so I really appreciate that. I appreciate everything you've done on the Redwood team. Thanks a lot.
00:51:33 - Rob Cameron
Thank you very much for saying that. We've got tons of great feedback from the tutorial, and I'm really glad it's resonating with people and teaching them Redwood.
00:51:40 - Christopher Burns
It's been great. Thank you. I'm sure a lot of us appreciate the tutorial, especially Anthony. Anthony very much appreciates this tutorial.
The biggest takeaway you can take from this tutorial is that it's friendly to people doing web development for the first time or the thousandth time, and that obviously is a very hard balance.
The other thing to say is that if your native language is not English and you would like to translate the tutorial and the documentation, that is currently happening over at learn.redwoodjs.com.
00:52:21 - Rob Cameron
We're still tweaking it a little bit, so it's not technically live yet, but it will be learn.redwoodjs.com. That's where the tutorial will live and probably eventually all the docs. It'll all be i18n-ready so anybody can volunteer and help us translate into your native language.
00:52:35 - Christopher Burns
We'll try and go for every language, especially pirate.
00:52:38 - Rob Cameron
What is that? I haven't heard of that one.
00:52:40 - Christopher Burns
You've never heard of it? I think it was a Facebook joke.
00:52:42 - Anthony Campolo
You can get your Facebook translated to pirate speak, pirate Facebook-isms. That was a while ago. That's a deep cut. Good one.
00:52:55 - Christopher Burns
I don't know how long ago that was, but I remember it well. Thank you for your time.
00:53:00 - Rob Cameron
Thank you, guys.