00:00:21.170
Okay, so the name of the talk is 'Commit Messages to the Rescue.'
00:00:26.270
My name is Aji, which is a pretty short name, but a lot of people still have trouble with it.
00:00:31.829
It's spelled right up there—A-J-I—and you say it like 'Ah-ji.' Just so that you never forget who I am, I'd like you all to do it along with me.
00:00:40.230
Okay, I'll spell it out: A-J-I. And I want to hear you say 'Ah-ji' as well. Excellent! But you didn't do the snap, so one more time, please. A-J-I, 'Ah-ji.' Great!
00:00:52.530
The entire room sounds disappointed in me. It's a good thing I'm comfortable now, though. My pronouns are he/him, and my website is in the upper left. If Twitter is something you do, it's in the upper right. I completely understand if you don’t.
00:01:07.950
I know that you have a choice in conference talks, and I want to thank you for being here with me. I work for a company called Snap Sheet, based in Chicago. We're not unleashing the world's creativity or anything, and I don't honestly have a pithy one-liner to explain what we do.
00:01:31.080
But a story from a friend of mine is the best way to describe it. He called an Uber and went outside to wait, standing next to his motorcycle. The Uber driver pulled up and smashed right into his bike, knocking it over.
00:01:45.090
The Uber driver said, 'Oh no, it's okay,' which is terrifying in and of itself. My friend said, 'No, it's not! That's my bike!' He anticipated weeks of shopping around at body shops and having to fight with his insurance carrier to see if it would ever get fixed.
00:02:10.440
But the next day, he got a text from his carrier saying to download our app. He took pictures of his damage with his phone, and he had money in his account the next day. So technically, our customers are the insurance companies.
00:02:28.859
We're streamlining processes, saving millions of dollars, and increasing efficiency. But it's what we can do for people like Brett that makes it exciting for me. And here's where I insert the obligatory 'We're hiring' statement: come work with me and let's make beautiful commit messages!
00:02:37.260
I gave a lightning talk version of this before, and I wanted to set up some situations in which commit messages could really save your bacon. So, I fabricated a story about a workplace that could have been helped by good message practices.
00:02:48.989
When looking for pictures to put on my slides during this story, I reached for Dr. Seuss imagery. I especially liked it because the fish could be the project manager, and that just felt right to me.
00:03:08.400
So, I thought, since I'm going to give this talk at RailsConf, which is a little bit bigger than the other venue, why not go all out? So, I present to you: 'Git Add, Git RM, Git Commit -em: Definitely Not by Dr. Seuss.'
00:03:18.230
An e-commerce site on AWS is a good enough scene for our story. I guess they employed developers, but I'd like to speak of Thing 1 and Thing 2. Thing 1 took some work from their burn-it-down chart because a bug had been found in the site's shopping cart.
00:03:32.519
Even through all the planning, deep in Rails magic, requests had timed out, causing dips in their traffic. Thing 1 raced to make known what was causing the fault, sweating and anxious that the server might catch fire and halt for a week without sleep.
00:03:51.870
At long last, with many cans of LaCroix, he uncovered our one tragic flaw. With 'Git Blame,' we found out that Thing 2 wrote the class that had been a pain in our workflow for the last week.
00:04:04.410
Now it's readable and tested, but something is amiss. No one class should employ as much logic as this. Thing 2, unrepentant, said, 'All of my code is self-documenting.'
00:04:18.810
But it needs a refactor now. Help me find out just what that method is after; it seems like dead code to me, not much more than obstruction. Then their fix was merged in, and they pushed to production.
00:04:32.099
I had so much fun doing this, you guys, but their sigh of relief only lasted a flash. Never before had a site started crashing so fast!
00:04:38.910
Looking at server logs, their heartbeats all quickened. 'Hey, I wonder if we could ask Sean Griffin? He maintained Active Record, and his opinion I trust. Now he'll just tell us we should have used Rust!'
00:04:50.220
So, they called Aaron Patterson. We’re hemorrhaging money all over the place as our devs contemplate the lost data and sales. When code loses context, apps run off the rails! See what I did there?
00:05:04.890
Okay, fun's over; down to business: commit messages. We all do that, thank you. Come have I said that? We all do them, and kind of like TDD, we all agree that they're very important, but we probably cut some corners here and there.
00:05:25.110
And I don't want to stand up here and tell you all that you're doing something wrong because you're not. You might just not be getting the most out of your commit messages.
00:05:36.300
In general, version control is something that most people encounter fairly early on while learning to code. Therefore, the concepts need to be imparted in uncomplicated ways. I bet I know a couple of those: It's a save point, like in a video game, or a moment captured in time, or saving your work as you go along.
00:05:54.460
When you're first learning coding or Git, there's a lot to take in. It is a little inaccessible at best. So simplifying the steps is important to help you learn.
00:06:07.230
We're shown to write a brief description and move on, especially because if we type 'git commit' without the '-m,' we are going to get stuck in a Twilight Zone from which there is no escape. Yes, that's right; 'git commit' was going to land us in Vim!
00:06:32.120
Now, much like I've seen the one true light and used them as my daily driver, now that I have more familiarity, I've circled back around to commit messages. Because when these messages aren't thought about as a tool, but as a hindrance to work or as a chore that we have to do that doesn't really matter, we end up with messages that are unhelpful.
00:06:45.270
They can be incredulous, maybe a bit on the nose, even desperate, dishonest, depressing, or downright belligerent. Yeah, I’ve got nothing. But I do have to note that couple of instances didn't get translated into an emoji.
00:07:01.700
I listened to a podcast called The Bike Shed, which was hosted by Sean Griffin and Derek Pryor. Somewhere amidst those episodes, I remember Sean talking about what a good commit message was and how it could save you from bad situations. I thought to myself, 'Alright, this is a guy who talks about complicated code concepts like it's nothing, and so often I have no idea what he's talking about.'
00:07:39.080
But commit messages? There’s a bit of wisdom from this programming celebrity that I can put into practice. So, I started to look into commit messages. I read some blogs, forums, and plenty of Stack Overflow questions. Some pieces of advice rose to the top time and time again.
00:08:12.140
Show of hands: how many people here have heard of or seen rules a lot like these and actually use them? Let's hand them down. How many people here are seeing these ideas for the first time? Okay, some of these have reasons behind them.
00:08:28.930
You keep the subject short because Git and GitHub will truncate it around fifty characters. Capital letters, periods, tense—you use those.
00:08:34.479
Those are all just tabs and spaces, and there's a convention that we gravitate to, probably those rules. But if your team or your project prefers something else, or has a different style guide, go for it. And the '-m'? Well, we'll see why that shortcut is just like an ice cream breakfast. It's nice at the time, but it's not going to help you get through the day.
00:08:57.270
Let's take a moment to look at some well-intentioned commit messages that I pulled off of GitHub. Again, please raise your hand if you've written a commit message like this or this one. What about this one?
00:09:03.880
So what do all of these examples have in common? They all follow those canonical rules, don't they? They might enforce some stylistic consistency, but really they're addressing the wrong things because those examples all had something else in common. Every last one of those did not include a body to the commit message.
00:09:22.930
The habit of not using message bodies is so prevalent that I bet there are some capable, smart, great developers out there who have never written a commit message body. There might be some at this conference or even in this room, and to you, if you’re out there, I cannot wait to share this new perspective on this boring common tool.
00:09:40.510
Because it absolutely can be a game-changer. Now that we’ve seen some examples, it seems pretty easy to agree on what makes a commit message unhelpful. So what goes into a good commit message? This is from an open-source project by Thoughtbot called Clearance.
00:10:04.720
The subject line reads, 'Use Route Independent Password Reset Redirect.' The body is: 'Using edit_user_password_url requires that particular path helper to exist. That's not necessarily the case since all we want to do is redirect to the same action; we can use url_for instead.'
00:10:36.910
It's a concise but descriptive subject in two sentences. This message conveys the problem that required a change to be made, the intention of the code originally, and therefore what the change is aiming for. This is the little commit message that could!
00:10:48.399
So much conveyed with only as much text as it needs! Sure, this is more to write than a 50-character '-m' message, but wouldn't you already have this kind of information in your head if you had just made this change? It's not really a lot of extra work to make this kind of thing happen.
00:11:02.260
Let's take a look at an example from Rails: 'Fix secret key base for rail ties.' This was missed in the security fix for the local dev. CI doesn’t have a temp directory in the app's built for testing, so these end up failing.
00:11:19.250
This adds the secret key base so we don’t need to generate one. This talks about the problem being fixed, even where and how the bug was introduced. It can certainly be useful, mentioning what this commit adds and why.
00:11:40.120
Again, this is less than the amount of information you would share with someone who walked by your desk and asked what you were working on, but it gives us a lot to work with if we're thinking about changing the underlying code.
00:12:06.160
So what made those messages better than some of the others we've looked at? Context. Context is so important! I'll illustrate my point by going back to a Dr. Seuss story—not another poem, sorry—but a story about Theodore Geisel, which is his real name, and one of his stories, 'Horton Hears a Who.'
00:12:55.640
In which an elephant named Horton vows to protect a tiny civilization that's floating on a speck of dust, met with ridicule from the other animals who can't or won't hear them. Horton proclaims, 'A person's a person no matter how small.' Well, here’s some context for you: Theodore Geisel was born in 1904 and, like many white people at the time, was pretty darned racist.
00:13:42.360
I'm not going to put those images on screen, but he drew troubling images of Japanese citizens in the run-up to World War II as a political cartoonist, among far too many other examples. But after the war, he traveled to Japan, met the people there, saw the relationship with the American occupation, and heard their direct experience with nuclear weapons. He wrote 'Horton Hears a Who' as an allegory about the war.
00:14:22.520
Some lines in there are straight references to the atom bomb falling from the sky. Without the context, Horton is a silly book with a good message. With context, it becomes one man's attempt to admit wrongs of his past attitudes in a very public way. He tried to influence others to realize the same mistakes in themselves, or at the very least inoculate the young folks as best as he could.
00:15:05.560
Just as a work of art cannot be fully understood without context, code can be difficult to impossible to wrap your head around without it. The commit itself is going to tell you who, what, where, when, and how, but it's missing why. It's a blessing and a curse of programming; there are a million different ways to solve every problem.
00:15:47.100
It's less like engineering and math and more like creative writing. We're constantly making decisions that have consequences for the future, and there's always a reason we make the decisions we do, even if it's sometimes a little thin. Record that reason in a commit message, because you or someone else might need it.
00:16:32.450
I mean, how many times have you looked into a file that you didn't write, only to think, 'Why does this look like this?' Wouldn't it be great if we could hover over a line of code in our editors and read a note explaining exactly why a thing looks the way it does? Well, you can! Here it is in VS Code. This is an extremely popular extension called GitLens.
00:17:27.040
This file is in the Rails source code, Active Record. You can see the module name on line 3. We're going to jump down a few lines and hover the mouse on line 44. Look at that! It's beautiful! Have you ever had an annotated Shakespeare book before? It really opens up the text in a way that you probably had never experienced. How about annotated source code? You already have it. Who's all this context for anyway? Other developers.
00:18:42.400
Developers who are changing this code, or using this API, or debugging an issue—basically anyone who might write something that interacts with our code in the future. But what if I'm the only one working on this? Great! Other developers can beam you in the future to properly review code. You're going to need more than just seeing the change, especially if you're using a tool that truncates. If the reviewer might not even see all the code that's affected by this change, if you see there on the left, the line numbers go from 120 to 167, that's 47 lines of hidden code.
00:19:38.310
Who knows what could be in there without opening each folded section in the UI? Okay, but that's what the PR comment is for. I 100% agree! That means you're already thinking context is important, so why wouldn't you save it in history instead of throwing it out when the code gets merged?
00:20:22.490
Has anyone ever searched for something because you're stuck, only to find a blog post from one of your colleagues—or even yourself—that gives you the answer? Anybody? That has definitely happened to me! You can have that without Googling or if your internet is down. With rich messaging, what's going to be easier to capture: context while you're closer to your thoughts, or a summary at the end of feature work after the fact?
00:21:06.830
It's the same thing with TDD: writing tests upfront as you work or going back in and struggling to cover all your bases. Okay, I'm willing to admit that this is what won me over to actually doing TDD instead of just thinking it was a good idea. When you're in the middle of feature development, you have all the energy of an exciting new task, and if we write our thoughts in the Git history as we go, we can leverage that immediacy and capture helpful information for the project's future.
00:22:00.340
Developers and tooling make it easy to copy out any relevant information for code review and put it right there in a PR. You don't have to write it twice! The body of a commit message doesn't need to be a novel or an entire page of documentation. The explanation should match the size of the context that you have to share.
00:22:35.540
So what do we write? Well, if it's part of a public interface, how could it be used or extended? What's relying on it? We're Rails developers; we love conventions! We can all speak more or less the same language, and it should be easy for new developers to come onto a project if it all looks Rails-y enough. Did something need to go against a convention for some reason? Is there a non-obvious side effect that falls out of this change? And really, what does 'obvious' even mean?
00:23:54.580
Okay, this never happens, but if it did and the actual execution of a library didn't line up with the documentation—are there any gotchas that this code introduces? Are there any pitfalls that you saw when you were up to your elbows in this subsystem that would be good to know about in the future? Think about what precise domain knowledge you have right now that you might want to remember.
00:24:33.550
Try to write a message that will make sense without seeing the code. It can be kind of difficult, but you don't need to replicate the code method for method or anything. If reading the Git logs without the code open makes sense, then that history becomes a much more useful document. Is there an external resource that applies? Link to a ticket, a feature spec, user story, PR comment, slack discussions, deep linked resources that you use, Stack Overflow answers, blog posts, videos, documentation specification, conference talks from cool guys in bowties—remember that links aren't forever!
00:25:06.050
The message should still make sense. We all refer to old code as a reference from time to time: how did I solve this the last time? A little explanation, and you're leaving breadcrumbs about how a design pattern, a library, or a technique worked or didn't work, and you're able to be one step ahead next time.
00:25:49.220
I've had a little success with tagging my messages—not Git tags, plaintext tags that I can search either with GitHub's search box or with 'git log' on the command line. A little example here: I use this convention when it's some piece of work I might want to refer back to, and I try to give it a good name. But you know what they say: there are only two hard problems in computer science.
00:26:31.690
This is in a repo of code for a workshop I led, and I think what I need is near the beginning. So, I'm going to log in reverse. I didn’t see it there though, so we'll try to grep through it. This command is a regex after the equal sign, so we're going to have to escape the dollar sign, and here's the syntax for that command, by the way: 'git log --grep='.
00:27:22.710
What are you looking for? Well, there it is! Okay, self-documenting, completely self-contained context-free code is an unrealistic myth. At worst, it's an excuse not to try.
00:27:40.550
Even if you're using a tool like Yard or Javadoc, which I really like for generating API documentation, that's just adding more to 'what' and 'why' we wrote some code. One way isn't necessarily going to be helpful for someone looking up what arguments a function takes, so 'why' doesn't really seem to go there.
00:28:14.680
But it can be helpful for someone who's making a change to this code. API docs and code comments—they don't stay in sync with the code as it's written, but commit messages persist exactly the same length of time as the code they describe, because new code necessarily changes those commit messages. Change your code, and update your docs for free!
00:29:12.000
So, we've talked about why we want to write better messages and how we can assemble a useful Git history. It sounds like we're going to get to know our way around some parts of Git that might be unfamiliar, because treating the commit history as a kind of documentation requires a little more thought about what commits you leave behind.
00:29:56.530
Git has a lot of baked-in tools to help us accomplish that, like message templates. Many of us are probably familiar with this message; it's what appears when you start a new commit from the command line, but this is customizable! It doesn't have to be the same as this. If a team has a standard of what should be included in a message, we can leave prompts for ourselves to fill in.
00:30:45.700
Remember the default message? Any line with an octothorpe will be ignored. On line 12, we see 'closes' with an issue number. GitHub will close the related issue once this commit is merged to the default branch. Any of these keywords actually work on GitHub: 'closed', 'closes', and 'closing.'
00:31:31.050
If you don't use GitHub, many other tools have very similar features as well. This example has width guides in case we can't set a hard wrap. It also includes a reference to tags in the subject line. This is a convention popular in a lot of open-source projects: Angular, Electron, and others. It's called Conventional Commits.
00:32:18.230
I'm not really going to touch on that here, but the super simplified version is to make commit messages both more human-readable and helpful, and also machine-parsable. Thank you! Okay, until Git, where to find the template in the Git config? That’s a file that lives in the home directory.
00:32:53.920
On Windows, it looks something like that. There are plenty of configuration options that are possible in here, but the one that we're going to care about right now is this: commit in the brackets is the section heading 'template=' and then the path to the file that you just made. If this is the only configuration in the file, that's totally valid. Commit templates can be stored; maybe you have a dotfiles management system for that.
00:34:22.800
And if you want to geek out about that in the hall afterwards, I'll be there. You know who you are! Sometimes, small changes need to happen after a commit—whitespace fixes, or we want to change a variable name. But we've written a really great commit message, insightful and future-aware. What's that going to do for the messages for that file?
00:35:01.680
Well, this is kind of a contrived example, but here's a bit of code. We see that there are some typos—autocomplete makes that easy sometimes. It's valid code still, but it’s got to be fixed. If I fix the typo and commit again, what will the commit message look like if you try to 'git blame' or read through line-by-line in your editor?
00:35:35.120
Good messages on all the lines, but the typos override it in some fairly important places. Sometimes, there are changes that are not worth the commit message, but there still needs to be a commit. Or maybe there’s a commit that you needed for development that doesn't need to be pushed up or merged, right?
00:36:10.800
So you don’t have to retype or copy-paste messages! There's a command to merge commits, and we can sweep that typo or fix it under the rug. No one even needs to know whatever happened! If you've had trouble with rebase in the past, that's okay! We don’t need to really grok the concept in the same way with this technique.
00:36:57.270
-i means this is an interactive rebase, and we're just going to change within our current branch. This allows us a lot of flexibility in manipulating the commit history, and it’s done by opening a text file in your chosen editor. More on that in a minute.
00:37:40.950
This is the file that comes up. It will serve as a set of instructions to Git on how it should handle each commit. We see they're listed out in order, oldest to newest. The first is the action that we want Git to take for each commit, defaulting to 'pick.' Second, is the short form of the hash that acts as an ID for that commit, and finally, the subject line of the commit message.
00:38:03.430
Note here that the body of the messages are not displayed, just the subject for now. This is another reason why a descriptive subject line is important—because try messing around in the Git history with a bunch of subject lines like 'some changes do model.' Hopefully, the available actions we can use are listed below in the commented section.
00:38:35.520
I've lightened some of them out because today we're going to cover just those four. First up is 'pick,' which is the default action for each commit, and it essentially means 'use this commit.' It doesn’t do anything; it replays it into the history just the way it is.
00:39:12.250
Next up is 'reword,' so use the commit but edit the commit message. Let's take a look at what a reword action looks like in practice. So, before we start, let's take a look at the commits that we want to change. It's the last commit relative to where we are now. We use 'git log HEAD~' to mean show me the message on the commit right before HEAD where I am.
00:39:35.630
We don't need to memorize the content here to understand what happens next. Two paragraphs kind of roughly describe the shape of it, and you will understand. So let's continue: we'll use our git rebase -i to get started, and the first step is to change the text on the line of the commit that we want to reword, and then we’re going to save and close the file.
00:39:53.610
It will read in those instructions and proceed. It opens the commit prompt, the same as if it was a brand new commit, but pre-populated with the message that currently exists. We're going to make a really obvious change here to show what's going on.
00:40:10.340
Okay, we didn't change the subject line there, but we could if we wanted to. Let's log out the same message and see what it looks like now.
00:40:24.500
Nice! I’ll change—I'll superimpose the old log, and as you can see, the commit hash has changed because the content of the commit changed with the message, but the date and everything else stays the same.
00:40:46.020
Next is 'squash.' I find it most useful for managing unnecessary commits or creating commits that more succinctly encompass the work done for a branch. Sometimes development adds more commits than we're going to need in master.
00:41:01.940
I'm looking at these three commits—it seems like they're doing very similar things, and I want to have the messages and changes merged into one commit to push it up for code review. What I want to do is take the commits on lines three and four and merge them into the commit on line two.
00:41:38.830
When you label a commit for squashing, it will be merged into the commit before it. So remember that squashes move up, and because the contents of the commit has changed, I want to change the subject to.
00:41:57.690
Let’s see that a little bit in practice—again, we fire up our interactive rebase, same as before, but now we choose 'squash,' save, and quit. Yes, we need to save, quit, and there it is.
00:42:13.510
The file that opens is where we tell Git what to do with the messages as three commits become one. Each message is delineated with a comment, and each section consists of the commit’s subject, a blank line, and the message.
00:42:52.050
If we did nothing, the new commit message would look exactly like this, but without the comments. That doesn't seem necessary to me to keep all the outdated subject. So I’ll remove the comments, too, so I can better see what the finished message is going to look like.
00:43:28.150
The first line will become our new subject, and since this doesn't accurately reflect what this commit is changing, we’re going to update that too. We'll take a look at the new commit now that we're all done. I’m going to use 'git log --oneline' to see a compact version of the log.
00:44:06.880
With only the subjects, I’ll copy that short hash to use for our Git log, it’ll start the printout at the specific commit—there it is!
00:44:27.680
Finally, 'fixup,' which doesn't really need a whole run-through, because fixup merges up just like squash, but deletes the commit message. This is perfect for typos, whitespace commits, things like that.
00:44:51.640
I could literally spend another hour up here going through Git commands and minutiae. So if you wanted more of that, I sincerely hope that you went to Chris’s deep dive into Git workshop yesterday.
00:45:01.360
As for me, I made a bold promise in the talk description that I would teach you how to do all of this Git wrangling in an editor other than Vim. I know this is why you're all here.
00:45:35.680
So, I've put that at the end. Okay, first, I do want to show you how to use Vim just enough to not have to open another application; see, you can stay in the terminal for all your message crafting needs.
00:46:04.830
Okay, 'git commit' will likely drop you into Vim, yes, and that can be a scary place if you don't know all of the arcane incantations required. But you can handle committing and message editing with three commands.
00:46:42.680
Nothing works the way you're used to when you first get into Vim. That’s because you're in a mode for navigating the text, not editing. To edit, you must enter insert mode—press 'I' to get into insert mode, and then you can type and move around the way you're used to. Even the arrow keys work here.
00:47:13.200
When you're done editing, you’ll need to press 'Escape.' I don't have a mnemonic for that; it's just 'Esc'. To complete the process, you'll type ':wq' to enter a command—'W' to write and 'Q' to quit.
00:47:43.360
So, all told, that's 'I,' type your message, 'Escape,' ':wq.' Now you know Vim! But if you feel the need to use another editor, all you're going to have to do is open up that git config and add another setting.
00:48:15.470
Core.editor equals the command to open your editor from the command line. Sometimes you're going to have to install that command. It should be in your editor's FAQ or the like if you don't already have that set up. If you use a GUI editor, definitely for Atom, VS Code, or Sublime, you'll need to append '--wait' to the command or it's only going to open a blank file.
00:49:07.560
Or you can just run this command from the command line once if you don’t want to set up a git config. So, I'm pretty close to being out of time, but I want to let you know that I'll be tweeting out a copy of these slides, along with a post about all of the other things I didn't get to cover.
00:49:36.090
After running my talk for the first time, I realized it's about two hours long, and some things just had to go—things like a mini-review of my opinions on plugins for most of the major editors and more useful Git commands for reading and managing commit history.
00:50:05.460
I really like Git, so I apologize for not being able to get it all together for you to be ready for today, but we were woken up this morning by a call from our doggy daycare that they had to rush my little boy here to the vet.
00:50:16.060
He's fine, but it's obviously left me with less time than I thought I had. So, not religious or anything, but hugs at a distance for Henson please! I hope that you have all formed, or started to form, your ideas on what a good commit message is.
00:51:03.040
I think you'll find that the answer to how we write good commit messages is different for every team, every person, every situation. But still considering its usefulness, I’m going to close with my answer to that—a line that is quickly becoming my personal catchphrase.
00:51:36.840
Probably get it tattooed, written on my gravestone, maybe at the next RailsConf I'll hire a skywriter! The answer, like the answer to most things, is empathy! Empathy for your teammates, empathy for yourself, empathy for developers of the future you might never meet.
00:52:19.330
Someone earlier in the week said something that I absolutely loved when I told them about my talk. They called me a 'commit message archaeologist!' Yeah, so I encourage you to be commit message archaeologists!
00:53:03.200
At the same time, leave something behind that can be useful for fellow archaeologists. And even if you can't convince everyone else that you work with that commit messages should be more than 'uh-huh,' if you're one in a team of five, taking up the mantle of meaningful commit messages still means you'll have 20% more of a chance that a commit message can save your bacon!
00:53:45.070
And once your message saves someone else, I'm willing to bet it'll be a 40% chance soon after! So, I'll leave you with that thought and a paraphrased quote. Thank you!