Can a room of developers reach a consensus on the minutiae of syntax and formatting for a Rails project?
We asked the attendees at this town hall-style RailsConf 2023 session to perform that seemingly impossible feat … and it went kinda okay!
As you’ll see in this video of the talk, we laid the groundwork for Standard Ruby’s first plugin: standard-rails. Our goal? To crowdsource the toughest debates once and for all, saving your (and every other) team the time of having to do it all over again.
We started by sorting the rubocop-rails rules in descending order of spicyness ("🌶️ desc"
), gave a high-level overview of each rule, solicited arguments from the attendees, and then held a vote over whether to enable or disable the rule.
To keep things interesting, there were lots of props, playful heckling, and increasingly-spiteful consequences for votes that we as presenters didn’t agree with. To keep the tempo up, we threatened the audience with the knowledge that every rule that gets a vote is one fewer rule that Justin gets final say over—it proved to be a powerful motivator!
We voted on the following rules during the session. Feel free to peruse these or just install standard-rails yourself and give it a go!
{{< transcript >}}
[00:01] - [Justin] So order, order.
[00:05] I was trying to think of what would be a fun thing to do,
[00:10] now that we are all back in person again
[00:14] and able to spend time in close quarters.
[00:18] And I thought one thing I fell out of love with
[00:21] during the pandemic was traditional conference talks
[00:24] where I have a whole lot of slides
[00:26] and it's just me blasting at you
[00:28] because those don't perform well on YouTube.
[00:32] And so this time, I thought it would be a lot of fun
[00:35] if we had a more interactive session.
[00:38] And so this is going to really,
[00:40] if this goes really, really well, then I had a great idea
[00:43] and Meagan did an amazing job helping me.
[00:46] And if this goes really poorly, you all didn't show up.
[00:49] (all laughing)
[00:51] And if anything, you let me down.
[00:54] So without further ado, let's get rolling,
[00:59] a couple people are still trickling in.
[01:03] Everyone should have a paddle
[01:04] 'cause we're going to be doing some voting.
[01:07] Green means you vote for a measure
[01:10] and red means you vote against a measure.
[01:12] And if you're red green colorblind,
[01:14] just ask the person next to you how you're voting.
[01:20] All right, let's begin.
[01:24] So you may be familiar with a tool called RuboCop.
[01:28] It is a linter and a formatter for Ruby.
[01:32] One of the things that I first noticed about RuboCop
[01:36] was it has default configurations of how it wants you
[01:40] to use your Ruby that a lot of teams disagree with.
[01:43] And whenever a tool has defaults
[01:46] that people generally disagree with,
[01:47] it means everyone goes and configures them.
[01:50] Whenever programmers spend a lot of time
[01:52] on a low priority argument or debate
[01:56] about something that doesn't really matter very much
[01:58] or is certainly lower priority than building the thing
[02:00] that they've been tasked with doing,
[02:02] we tend to call that bike shedding,
[02:04] like arguing over the color of the bike shed
[02:08] at a nuclear power plant is like really low on the list
[02:10] and yet it really works us up
[02:11] and you get in fights about it.
[02:14] And at Test Double, we're consultants,
[02:16] so we see a lot of teams
[02:17] and we just saw this pattern repeat over and over again,
[02:19] where you go to a team and then you see them pull
[02:22] in RuboCop and then they get in a big fight about it.
[02:24] And what ends up is they have their own kind of custom,
[02:26] bespoke RuboCop preference.
[02:29] Then I go to another team, same thing happens,
[02:31] I go to another team, same thing happens.
[02:32] And what's actually emerging from each of these teams
[02:34] isn't that they use RuboCop,
[02:36] it's that they're using RuboCop as a framework
[02:38] for having stupid arguments.
[02:41] And I got really frustrated with this
[02:44] because I firmly believe that tools should reduce friction
[02:47] and make it easier to do our jobs and focus on what matters.
[02:49] That's why we use Rails after all.
[02:51] That's what that was all about.
[02:53] And so back in 2018,
[02:54] I created a gem called Standard Ruby.
[02:57] You can go and gem install it.
[02:59] And what Standard is,
[03:01] is it simply depends on RuboCop,
[03:03] as well as RuboCop performance,
[03:05] some additional performance related rules.
[03:07] And it's got a configuration in it,
[03:10] it just preconfigures everything in one way.
[03:13] But the special thing about Standard
[03:14] is that it locks it down.
[03:16] So if you use Standard,
[03:17] you cannot go and futz with and change and bike shed
[03:19] these configuration options, you're just stuck with it.
[03:23] And so now a whole lot of teams just started using Standard
[03:25] and hopefully they're arguing about more important nonsense.
[03:30] And I've been really happy with just seeing
[03:32] how the community has shown up to pull all those bike sheds
[03:36] into the standard repo and so we can have
[03:38] one last bike shed to rule them all.
[03:42] Today, 2023, here's what we're going to do.
[03:45] We're going to create a new gem called Standard Rails.
[03:47] And it's going to look a lot like the first go around,
[03:50] where we're depending here on a RuboCop extension
[03:53] called RuboCop Rails, a lot of Rails specific rules.
[03:56] We're going to establish a configuration for it
[03:59] here on stage, and then we're going to lock it down
[04:01] so that we can all adopt Standard Rails
[04:03] and have more consistency
[04:04] between our different Rails projects.
[04:06] There's just going to be one difference
[04:07] where with the Standard,
[04:09] I came in, made my own configuration,
[04:11] and then the whole internet got mad at me
[04:14] and they argued with me.
[04:15] So, I was benevolent dictator for life and I don't,
[04:20] that role doesn't suit me as well as some people
[04:22] in our community.
[04:24] So this time around, (audience laughing)
[04:27] we're going to give democracy one last chance
[04:31] and put everything to a vote.
[04:33] And so here's Standard Rails,
[04:35] you'll vote on everything and then that's you right there.
[04:37] And then, so everyone can get mad at you.
[04:39] (audience laughing)
[04:41] So, what I'm doing here is I'm optimizing
[04:45] for developer happiness, where I'm the developer
[04:48] and it's my happiness that I'm optimizing for.
[04:52] And so now you know the basic goal of the day,
[04:57] I'm going to hand it over now to my wonderful co-presenter,
[04:59] Meagan Waller, and she's going to discuss the ground rules.
[05:03] - [Meagan] All right.
[05:05] Let's sort of like just set the scene here.
[05:07] It's all of us against him.
[05:09] The rules that we don't get to,
[05:10] he's going to get to decide on.
[05:12] So let's get through these quickly.
[05:15] All right, so ground rules that we have here are.
[05:20] - [Justin] Okay, we thought she'd be able
[05:24] to see the screen a little bit.
[05:26] - [Meagan] All right, so you're going to use your paddle to vote.
[05:27] I want everyone to be able to raise their paddle high
[05:29] so I can see it.
[05:32] Green means you agree.
[05:33] So if you are putting up red,
[05:35] you're saying you're not voting.
[05:37] Let's see everyone's green paddles.
[05:41] Okay, it's looking pretty good. That looks great.
[05:46] So the way that we're sort of thinking about Standard Rails
[05:50] and when we're thinking about the things that we do want
[05:52] to turn on, these rules should make sense
[05:55] when they're applied to pretty much any type of application.
[05:58] And so, if someone is using Standard Rails for one project
[06:01] and they're not able to use it for another,
[06:03] then like we all have failed.
[06:05] So we also are going to look out for rules
[06:09] that tell people what they should do with their apps
[06:12] or what they shouldn't do with their apps.
[06:13] So like restricting aliases, things like that,
[06:17] instead of like just mandating specific APIs.
[06:19] So keep that in mind as we're voting.
[06:21] It's not just,
[06:23] I guess it's not just like the things
[06:24] that are like your little pets,
[06:27] favorite rules that you want to have enabled.
[06:29] Let's keep the whole community in mind
[06:31] as we vote on these rules.
[06:33] And we really would like to try
[06:37] and optimize for portability.
[06:39] So if there's a built-in that would prefer that you use,
[06:44] Active Support alias versus a Ruby core method,
[06:47] be more portable for us to be able
[06:48] to use the Ruby core method.
[06:51] So if a vote is too close to call,
[06:53] that's telling us that there's probably
[06:55] too much tension between it, it's kind of divisive,
[06:59] so we're just going to disable it.
[07:01] That will be the default option there,
[07:05] when it's like a photo finish kind of vote.
[07:09] And any rule that gets enabled by you all
[07:13] that we disagree with,
[07:16] you will have a little sponsor read from us
[07:19] now that the bird app's not really a place where we can go
[07:21] to air our grievances.
[07:22] So that's what's in store for you all.
[07:27] So we have 40 minutes,
[07:28] we have tons of people here
[07:31] and we have four of these flip charts
[07:37] with 30 pages each full of rules.
[07:38] It's 120 rules for those of you keeping score at home.
[07:42] So let's keep the tempo up.
[07:43] In order to maximize the amount of time,
[07:47] I also have these 30 second sand timers. Wow, okay.
[07:55] We'll be using these when we hand the mic to anyone
[07:58] who might have a thing to say about a rule,
[08:01] you'll have 30 seconds to say what you want to say.
[08:05] Alright, so let's do another practice vote,
[08:08] now that we have all the ground rules established.
[08:11] If you agree and you want to vote
[08:13] and you want to be a part of this process,
[08:15] let's raise your paddles up to the green side.
[08:20] All right, looking good, let's go.
[08:22] - [Justin] The yeas have it.
[08:24] All right, so now on to the main event.
[08:27] So, it's the end of the conference.
[08:29] I know that everyone's really, really excited
[08:31] and the energy's really super high.
[08:32] But I'm going to ask you all just to chill a little bit
[08:35] and we're going to do this politely.
[08:38] And because there's 120 rules,
[08:40] we have presorted it for you in spiciness descending.
[08:44] So we've picked out some of our favorites
[08:48] that we think are going to lead to some interesting discussion.
[08:51] Here's the first on the list, Active Support aliases.
[08:55] So what this rule does is it checks
[08:57] that Active Support aliases to core Ruby methods
[09:00] are not used.
[09:02] Meaning like, don't use append and prepend on array
[09:06] when those are Active Support methods,
[09:09] instead use the shovel operator and unshift.
[09:13] Now one of the funny things if you've been doing Rails
[09:15] for a long time is lots of built-in Standard Ruby methods
[09:19] started off as Active Support custom aliases
[09:23] and then found their way into Ruby.
[09:26] So to just turn them off is kind of cutting off that path.
[09:32] So I've just shared my bias.
[09:34] In terms of like how we're going to conduct each of these,
[09:38] we'd love to give somebody from the audience
[09:41] a chance to make a case for or against
[09:43] enabling a particular rule.
[09:46] And then if somebody has something else
[09:48] to say that's a rebuttal,
[09:49] we'll give somebody else 30 seconds, their equal time,
[09:51] to make a counter case.
[09:53] Does anyone here want to make a case
[09:55] for or against enabling Active Support aliases?
[10:05] Somebody's got a hand up.
[10:07] We're going to bring a microphone to you, so everyone can hear.
[10:17] - [Audience Member] I always get confused with unshift
[10:20] and I always have to look it up,
[10:21] like what the crap is this doing again?
[10:24] But append prepend just clicks in my brain.
[10:27] - [Justin] All right, so this is a vote in favor
[10:29] of not enabling the rule, disabling the rule.
[10:33] Okay, anyone want to raise a counter argument?
[10:38] No. All right, let's go vote.
[10:39] - [Meagan] All right, let's vote.
[10:41] All right, raise your paddles to green
[10:45] if you want it enabled.
[10:46] Raise it to red if you want it disabled.
[10:49] (indistinct from audience)
[10:49] Yes.
[10:50] (indistinct from audience)
[10:52] - [Justin] Enabling prevents the use.
[10:54] (audience speaking) This is where they get you!
[10:56] - [Meagan] Yes.
[10:57] - [Justin] A lot of rules are written this way
[11:01] and this is why we we're here to put in the work.
[11:04] (audience laughing)
[11:08] So, okay, ballots up.
[11:12] The nays have it.
[11:13] - [Meagan] The nays have it.
[11:15] (audience laughing)
[11:20] - [Justin] Disable.
[11:21] All right, so next up.
[11:24] We've got create table with timestamps.
[11:26] So here it's saying if we enable this rule,
[11:29] all tables that you define in your migrations
[11:32] must have the t.timestamps,
[11:34] so the create at and updated at columns must be defined,
[11:37] unless it looks like a joiner table
[11:39] of just these different IDs.
[11:42] Anyone want to make an argument in favor or opposed?
[11:48] (indistinct from audience)
[11:50] Okay, we're going to get the microphone to you so you can.
[11:57] One more time for the video.
[11:59] - [Audience Member] There are sometimes append only tables,
[12:01] so we don't want to have updated at on them.
[12:03] - [Justin] Append only tables, so you don't want to have updated at
[12:06] 'cause they're never updated.
[12:06] Got it. Okay.
[12:08] Anyone want to, so that's an argument then in favor
[12:10] of enabling it or wait no, of not enabling it.
[12:13] (audience laughing)
[12:15] See, you got my back.
[12:17] Okay. Aaron.
[12:24] Cathy's getting her steps in.
[12:25] - [Aaron] I think like nearly all tables
[12:27] would want to have timestamps.
[12:28] So if you want to disable it on a,
[12:31] if you have append only, you could just do it for that one.
[12:34] - [Justin] Yes, there's a real special case.
[12:36] There is a standard disabled comment directive,
[12:40] so that's okay.
[12:41] Doesn't mean a thousand percent of the time just,
[12:44] you know, it's the golden half.
[12:45] All right.
[12:46] - [Meagan] All right. We heard our argument.
[12:51] - [Justin] Again, should have seen this coming.
[12:54] - [Meagan] Really, we should've.
[12:55] - [Justin] Green means you want to enable this rule,
[12:58] and what this rule will do is force you to use t.timestamps.
[13:03] Ballots up.
[13:05] - [Justin And Meagan] All right.
[13:06] - All right. The yeas have it. Enabled.
[13:10] (audience applauding)
[13:12] - [Justin] See, just four or five more hours and we're going to be.
[13:18] (audience laughing)
[13:21] Through this thing. All right?
[13:22] I hope you don't have any flights tonight.
[13:24] All right, so Rails freeze time.
[13:27] This identifies usage of travel to,
[13:30] which time travels not the system clock,
[13:33] but Ruby's idea of what the system clock is
[13:36] with an argument of the current time.
[13:39] And then if enabled,
[13:41] this cop forces you to use freeze time instead.
[13:46] Anyone want to chime in?
[13:48] - [Meagan] We had a very emphatic raise back here.
[13:53] Did you have a comment in the red back here?
[14:02] - [Audience Member] I don't see a good reason
[14:04] not to enable it, freeze time makes sense.
[14:09] Traveling time, there's a variety of different arguments.
[14:11] Takes more brain cycles.
[14:14] - [Justin] Okay, so freeze time's better.
[14:16] Anyone have an opposing?
[14:18] Behind you, somebody's got a disagreement.
[14:21] - [Audience Member] Having built a time and labor system,
[14:24] you got to use travel time.
[14:29] - [Justin] Okay, because freeze time actually stops the clock,
[14:33] travel_to will move the clock to a time
[14:36] and then keep the clock running.
[14:39] (audience groaning)
[14:41] Yeah, okay, I get it.
[14:45] Okay, let's take those words and put 'em in our ballots.
[14:49] Let's, yeah, so red, okay, you all get it.
[14:57] The nays have it.
[15:00] All right, moving right along, Http Status.
[15:03] This will, by default if enabled,
[15:05] it'll enforce the use of the symbolic shortcuts or names
[15:11] for any sort of head status code
[15:14] that you want to send in your controller.
[15:16] Meaning like, symbol not found as opposed to 404.
[15:20] Or we could enable it and then enforce the exact opposite
[15:23] and say, no, you have to type 404,
[15:25] you may not put the symbol not found.
[15:27] So for rules like these that have options,
[15:30] we have a two-tiered voting system.
[15:33] (audience laughing)
[15:35] Because it was too expensive to make triangular cut outs.
[15:40] So first up, if you think this should be enabled at all,
[15:45] either way, green.
[15:49] Let's try that first.
[15:50] So everyone vote, either enable or disable right now,
[15:54] regardless of what the setting is,
[15:56] then we'll vote on the setting second.
[16:00] So green, so people are voting in favor of consistency.
[16:03] So the yeas have it, we're going to enable it.
[16:05] Now some of you're going to get mad though.
[16:07] (audience laughing)
[16:08] If you don't get your way.
[16:10] You see now, like if nothing else,
[16:12] I hope I'm building empathy for how much this job sucks.
[16:16] Okay, so now we're going to do a second vote
[16:19] for enforced style, right?
[16:20] - [Meagan] Yep.
[16:21] So we have symbol or numeric, right?
[16:24] Those are the two styles?
[16:25] - [Justin] Okay? So which color should be which?
[16:27] - [Meagan] Okay, let's do green for symbol, red for numeric.
[16:31] - [Justin] All right, ballots up.
[16:35] Oh wait, do we want to have an argument?
[16:37] We didn't have an argument.
[16:40] I didn't give a chance to give the argument. Hold on.
[16:42] Eileen wants to speak. Let's give her the microphone.
[16:52] - [Eileen] Do people actually use this?
[16:54] This is bonkers. It's the same number of characters.
[16:57] It doesn't make your code better.
[16:59] I hate both.
[17:00] There shouldn't be a choice.
[17:02] This should be disabled.
[17:03] (audience laughing)
[17:08] - [Justin] Eileen missed the boat.
[17:12] Okay, anyone have a comment about,
[17:16] we'll take one comment on symbolic versus numeric.
[17:21] And Cathy keeps picking the people furthest away from her.
[17:24] - [Cathy] I'm not picking, they're doing it.
[17:29] - [Audience Member] If I'm searching the code base,
[17:31] it's easier to search for the numeric codes than words
[17:34] that also are used all over the place.
[17:36] And I have to look up all of these anyway,
[17:38] so numbers.
[17:40] (audience applauding)
[17:41] - [Justin] All right, okay, let's not get carried away
[17:44] in this sort of populist law fervor.
[17:49] Call a vote?
[17:50] - [Meagan] Yeah, let's vote.
[17:51] Alright, green for symbols, red for numeric.
[18:00] - [Justin] Wow.
[18:00] All right, so the left side of the room is mostly green
[18:03] and the right is most.
[18:04] I don't like this.
[18:06] - [Meagan] Does that mean we get to disable it?
[18:07] Do we get to disable it?
[18:09] - [Justin] This is too close to call
[18:11] and therefore the rule is disabled.
[18:13] (audience cheering)
[18:18] (audience indistinctly talking and laughing)
[18:24] Yeah, not unrelated,
[18:27] Eileen has my phone number and can text me anytime
[18:29] when she's not happy.
[18:33] All right, next one we got here
[18:34] is the three state boolean column.
[18:39] What this refers to is,
[18:41] when enabled, it enforces that any new boolean column
[18:44] that you add in the migration
[18:46] must have a default setting and must be not nullable.
[18:49] Meaning that the column's value is either always false
[18:52] or true, but never null.
[18:56] Steven would like to chime in.
[19:03] - [Steven] This is terrible in any code base
[19:05] with a very large table or a number of very large tables
[19:08] because you can't like, safely doing this is hard.
[19:11] - [Justin] So more clearly you want to not enable this.
[19:14] - [Steven] I want this disabled, yes.
[19:15] - [Justin] You want this disabled
[19:16] because if you have a large table, it's bad.
[19:19] - [Steven] I can't, yes.
[19:21] Wait, what does disabled mean again in this case?
[19:23] (audience laughing)
[19:28] - [Justin] Okay, so here's a way to look at it everyone.
[19:30] If we disable all the rules,
[19:33] then it's like this just homeopathic thing
[19:35] that prevents us from having any constraints
[19:38] on how we write our code.
[19:40] So disabling everything means like we're allowed
[19:42] to do whatever we want.
[19:44] Enabling things disallows us from doing something.
[19:46] And in this case that something is nullable boolean columns.
[19:51] So if you enable it,
[19:53] you can't make a nullable boolean column.
[19:57] And he wants nullable boolean columns,
[19:59] which means he does not want to enable it
[20:04] because defaults are expensive on large tables.
[20:06] There we go.
[20:08] Any counterarguments?
[20:10] Hey Aaron. Oh, here we go, Landon.
[20:12] - [Landon] I think it's frustrating the other way
[20:14] because it's like like developers are lazy
[20:17] and like they won't set a true or false
[20:19] and you have a null and you don't know what it is
[20:21] or something will happen
[20:22] and you're looking at the database later to debug something
[20:24] and you're confused.
[20:28] - [Justin] Okay, so.
[20:31] - [Meagan] Are we feeling like we're ready to vote
[20:33] with all this information?
[20:35] All right, enabled is green, disabled is red.
[20:41] Let's vote.
[20:43] - [Justin] Oh wow, this is close.
[20:45] There's some late breaking nays.
[20:48] - [Meagan] I don't know, I think the yeas have it.
[20:49] - [Justin] The yeas have it.
[20:51] (audience applauding)
[20:54] And Steven accidentally voted yes.
[20:58] (all laughing)
[20:59] He's just catching that now.
[21:04] No one to blame but yourself.
[21:06] All right, Rails Blank.
[21:12] This rule checks for code that can be written
[21:14] with simpler conditionals using object blank
[21:16] defined by Active Support
[21:18] as opposed to like nil or empty or present.
[21:23] So, let's get some comments.
[21:26] - [Meagan] Yeah. Anyone have anything to say about this one?
[21:33] - [Justin] I think everyone's still working out the algebra.
[21:35] - [Meagan] Yeah, yeah.
[21:38] - [Justin] If enabled it will force you to use blank
[21:40] whenever blank would be terser.
[21:43] Blank is defined in Active Support.
[21:46] Nil and empty are defined in Ruby.
[21:51] Noel's got a comment, point of order.
[21:55] (audience member indistinctly speaking)
[22:00] Blank is defined inactive report in terms of empty
[22:02] on whatever the Ruby object is.
[22:04] - [Noel] Yeah, so just blank
[22:05] is so you can get some unexpected behavior from blank.
[22:10] Not a pro or a con, just a point of order here
[22:13] that blank is defined in terms of empty on its object.
[22:17] - [Justin] Noel, author of many books, says that it's not a pro
[22:20] or a con to have unexpected behavior from your computer.
[22:23] (audience laughing)
[22:27] - [Audience Member] I'm in favor of this one
[22:32] 'cause I'm trying to be more present.
[22:34] (audience laughing and applauding)
[22:38] - [Justin] All right, so on one hand your Ruby code is less portable,
[22:42] but on the other hand you made a pun.
[22:43] - [Meagan] Yeah.
[22:46] All right, let's vote.
[22:49] Green, the yeas definitely have this.
[22:51] - [Justin] Ah, the yeas definitely have it.
[22:54] Oh, fun story. Meagan and I disagree with you all.
[22:57] So now you get your first sponsor read.
[23:01] - [Meagan] All right. Is this for the newsletter?
[23:03] - [Justin] Yes.
[23:04] - [Meagan] All right.
[23:06] "You've Got Mail" isn't just a 1998 classic by Nora Ephron,
[23:10] it's your reality when you sign up
[23:12] for the Test Double newsletter.
[23:14] (audience laughing)
[23:16] Get updates, insights, expert tips,
[23:18] and more from our Test Double double agents.
[23:21] Sign up today at TestDouble.com/newsletter.
[23:24] (audience applauding)
[23:31] - [Justin] The panic on my face is that I realized that we split up
[23:34] the sponsor reads, but she prepared way more for this.
[23:37] (audience laughing)
[23:39] Lower your expectations for when it's my turn.
[23:42] Next up, environment variable access.
[23:47] Wait a second, we enabled the last one, right?
[23:50] There's a whole bunch of options inside of this one.
[23:54] I don't care.
[23:55] We're just going to enable it all.
[23:56] You were that enthusiastic.
[23:57] (audience laughing)
[23:59] We'll fix it in 0.1.
[24:03] Environment variable access,
[24:05] what this would do is prevent you
[24:06] from using the environment, all caps ENV cache,
[24:14] to hash like thing to reference
[24:16] and write environment variables.
[24:18] Instead, you'd have to use Rails application secrets
[24:21] or config to read and write them.
[24:24] Any comment?
[24:27] Anyone want to chime in? Don't be shy.
[24:35] Voting yes means you can't do it, yes.
[24:38] That's the theme of the.
[24:42] This is why RuboCop is so popular.
[24:46] No comment?
[24:47] Oh, we got one over here.
[24:53] - [Audience Member] Yeah. What about if we don't.
[24:55] So I'd vote against, not enabling this.
[25:00] I think I got that right.
[25:01] If we don't use secrets
[25:02] or if we don't want to store anything sensitive in config.
[25:06] - [Justin] Then you would want to disable this rule.
[25:08] If if you want to be able to use ENV,
[25:10] then you'd just vote to disable it.
[25:12] - [Audience Member] Okay, so I think that might be, but.
[25:16] - [Justin] The person behind you, may have a follow up.
[25:20] - [Audience Member] Actually I'm just unclear
[25:21] what we're gaining by this
[25:22] since they can just do Rails.application.secrets
[25:25] and then write or read.
[25:28] Are we just making them think more about it
[25:30] since they have to write more code?
[25:32] I don't know.
[25:34] - [Justin] Kevin, you want to, looks like Kevin's got a comment.
[25:39] - [Kevin] So I believe the advantage of this
[25:41] is that you discover an error
[25:43] due to a missing environment variable at boot time
[25:46] instead of while the application is running.
[25:48] So if you're missing this environment variable,
[25:51] you're forcing it to be in Rails application secrets,
[25:53] which gets populated at boot time.
[25:55] That will cause an error immediately
[25:57] instead of waiting for some point
[25:58] when the application is running.
[25:59] - [Justin] Oh. Knowing murmurs.
[26:05] - [Meagan] All right, with that in mind, let's vote.
[26:12] - [Justin] Oh, I'd say this is 60-40 green red.
[26:15] - [Meagan] Yeah.
[26:17] - [Justin] Yeas have it.
[26:18] - [Meagan] Yeah.
[26:19] (audience laughing)
[26:22] Very tepid response.
[26:23] - [Justin] Well, we disagree again, so I don't like that one.
[26:27] So I'm going to go to the next sponsor read.
[26:29] All right, so we're doing,
[26:32] well, I'm doing something funny.
[26:33] I'm going to Japan next month
[26:36] for what was going to be a vacation,
[26:37] but then RubyKaigi got scheduled at the same time.
[26:39] So now I'm going to RubyKaigi and I'm not speaking,
[26:41] I'm just going to go there
[26:42] and I'm going to do kind of like a travel blog
[26:44] of like ramen pictures and travel tips
[26:47] and also see Ruby internals.
[26:51] And so I'm going to be live blogging at Test Double's blog.
[26:55] We'll set something up and if you're interested
[26:57] in kind of getting an inside scoop of what's coming
[27:01] in Ruby 3.3 and what are the 3.2 enhancements
[27:04] that we're already benefiting from and how they work,
[27:06] there's going to be a lot of really cool technical talks there
[27:08] and I'm going to try to do a better job of covering those
[27:10] for our Western audience.
[27:11] 'Cause normally the stuff that goes on at Kaigi
[27:13] doesn't get talked about very much,
[27:14] even though it's like literally the future of our language.
[27:17] So if you're interested, just check out TestDouble.com/field
[27:22] and you can sign up and you'll get notified
[27:24] when the live blog goes up in the middle of May.
[27:28] Thanks, Thomas.
[27:31] He's the real hero.
[27:32] That was nowhere near as good as her reads.
[27:36] Next up, application controller.
[27:38] This one requires that all of your controllers
[27:42] subclass the application local application controller
[27:46] that's generated for you when you start with.
[27:49] Comments.
[27:53] And I've bundled up like five of these.
[27:55] There's like five rules just like this.
[27:56] So after we do this one,
[27:57] we're going to do a speed round on the subsequent ones.
[28:00] - [Audience Member] Just learned today
[28:01] from the Rails engines talk
[28:03] that if you want to decouple your application logic
[28:06] from your engine, you can do action controller base
[28:10] instead of doing application controller,
[28:12] so that would be an argument for disabling this.
[28:15] - [Justin] Thank you.
[28:15] You see, now there was a comment where somebody said
[28:18] to disable or enable as part of their argument
[28:20] and it was much clearer.
[28:21] (audience laughing)
[28:23] - [Audience Member] Just a point of order.
[28:25] The explanation given on the previous one on what gain
[28:28] this is giving us is helpful in general,
[28:30] so if we could have someone provide a,
[28:33] Hey, this is why it'd be a good idea as a part of going in,
[28:35] that might help the dialogue.
[28:37] - [Justin] Yes, feel free to offer those whenever you'd like.
[28:40] (audience laughing) Aaron.
[28:44] - [Aaron] So I like this particular rule
[28:46] because we can put application specific stuff
[28:49] in our application controller.
[28:51] That application controller constant is controlled
[28:53] by your application versus action controller base,
[28:57] which is owned by Rails.
[28:58] So you would want put any common methods
[29:01] in the application controller
[29:03] versus monkey patching Rails, which we all know is bad.
[29:12] - [Justin] Let's have one last from Brittany.
[29:14] - [Brittany] I just want to clarify that in the off chance
[29:16] that you want to do that thing that he said before,
[29:19] you can just comment out this rule, right?
[29:22] In the one random case that you want to.
[29:25] - [Justin] Yes you can.
[29:25] - [Brittany] Okay, cool.
[29:26] Yeah, just just so you know, you don't have to vote no
[29:29] just so you can do some crazy shit.
[29:30] (audience laughing)
[29:35] - [Meagan] All right, let's vote.
[29:40] All right. Yeas have it.
[29:45] - [Justin] All right, well, congratulations
[29:47] 'cause this is another sponsor read
[29:49] 'cause I don't like this one.
[29:55] Too many ads. Yeah, right.
[29:57] Dynamic ad insertion. All right, this one's on Meagan.
[30:02] - [Meagan] All right.
[30:03] So, we officially have a GitHub organization
[30:07] for standardrb.
[30:08] All of our officially sanctioned standard plugins
[30:11] are going to live here.
[30:13] If you're excited about bringing Standard to a new library,
[30:16] we're excited as well
[30:18] but please don't use names like Standard-Rspec
[30:22] without talking with us first,
[30:23] and we can work together to get those things going.
[30:27] So just check out our GitHub.org
[30:29] to get involved in any new standard plugins
[30:32] that are coming out in the future.
[30:34] - [Justin] All right, thank you very much for that.
[30:36] Okay, so like I said, this is going to be a lightning round.
[30:38] We're just going to vote on the next four or five.
[30:41] I vote for chaos.
[30:43] I think we should just alternate whether we support.
[30:46] So application job,
[30:48] should they extend from application job or from.
[30:52] - [Meagan] All right. The yeas have it.
[30:56] - [Justin] Does that mean another sponsor read?
[30:57] - [Meagan] Yeah.
[30:58] - [Justin] Then no, no, no, no, no, no, no, no.
[31:00] Okay. Application mailer.
[31:03] All right.
[31:04] Yeas have it.
[31:05] Application record.
[31:07] Yep. Yep.
[31:08] You don't have to raise your arms higher every time.
[31:11] (audience laughing)
[31:12] - [Meagan] We get it.
[31:13] - [Justin] I get it. I don't know how multi database support works,
[31:20] but Eileen wrote that, so she knows.
[31:24] If you inherit from active record base,
[31:26] you will break multi database support.
[31:29] So that's probably a vote in favor of the rule.
[31:35] Next up, belongs to.
[31:38] Look for belongs to associations where we control
[31:42] whether the association is required
[31:44] via the deprecated required option
[31:47] instead of apparently some cutoff text,
[31:50] instead of optional true.
[31:51] So like before Rails 6.1 or whatever,
[31:55] when you did belongs to association definition,
[31:59] it was optional by default.
[32:01] And it has since become required by default.
[32:03] So you can say belongs to blog required.
[32:10] Good grief.
[32:11] - [Meagan] Optional true. (audience laughing)
[32:16] - [Justin] Look at the good and the bad code example.
[32:18] (audience laughing)
[32:19] And you kind of get it.
[32:20] - [Meagan] It's the last day.
[32:21] - [Justin] All right.
[32:23] Ali's got a comment.
[32:24] We're not voting yet.
[32:26] Let's see.
[32:28] Ali, save me.
[32:32] - [Ali] Well, I just have a question.
[32:33] What happens if you're on an old version of Rails
[32:35] that doesn't do the optional thing?
[32:36] - [Justin] Right?
[32:37] So the RuboCop Rails will detect the Rails version
[32:43] by looking at the gem file, or there's also,
[32:46] you can specify it in an option
[32:48] and if the rule is not relevant to that option
[32:51] or that version of Rails yet, it will disable itself.
[32:58] - [Meagan] Someone back here.
[33:01] - [Justin] All right.
[33:05] - [Audience Member] Okay, would it be good practice
[33:06] to just have belongs to blog
[33:08] and leave out required or optional
[33:11] since it's defaulted to be required.
[33:14] - [Justin] It would've been a good idea to maybe make this one rule
[33:16] with four configuration settings,
[33:18] but there's like four scattered throughout RuboCop Rails,
[33:20] so here we are.
[33:22] All right.
[33:23] I think we should probably just put it to a vote.
[33:25] - [Meagan] Yeah, let's vote.
[33:29] - [Justin] Okay. Sure. - [Meagan] All right.
[33:31] The yeas have it.
[33:31] - [Justin] You see, so I don't know how about you,
[33:34] but decision fatigue tends to build up towards the end
[33:37] of the day and you started just like anything
[33:40] to get out of here.
[33:41] Okay, sure, I'll.
[33:42] (audience laughing)
[33:45] Redundant presence validations on belongs to,
[33:48] so this one's similar
[33:50] because now the valid.
[33:55] Because by default belongs tos are required.
[33:59] Like there's a validation that happens automatically
[34:02] by a default, that they be set.
[34:04] If you also say, I validate the presence of that thing,
[34:07] if enabled this rule will be violated.
[34:11] And you'll have to delete the validates user presence
[34:13] 'cause it'll be redundant.
[34:16] People are to vote.
[34:17] - [Meagan] We're voting. We're voting. All right.
[34:19] Very decisive bunch here.
[34:21] - [Justin] See. You guys are taking over.
[34:23] I feel better about you all taking the blame
[34:26] for however this goes.
[34:28] - [Meagan] Ready and eager.
[34:30] - [Justin] Next up, action controller test case.
[34:34] This one, you may recall that in Rails 5,
[34:37] controller tests were deprecated
[34:40] and instead integration tests
[34:45] were the preferred alternative.
[34:47] We're now at Rails 7, which is two Rails' later
[34:50] and if enabled, this rule would say,
[34:53] Hey, no more controller test.
[34:54] It'll actually trigger a violation
[34:55] for every controller test.
[34:59] Anyone have a comment about whether or not?
[35:01] - [Meagan] Who feels strongly about this?
[35:06] - [Justin] Okay, so somebody shouted impolitely,
[35:10] but audibly, that it's going to be a huge.
[35:15] - [Audience Member] In favor of disabling.
[35:18] This is just going to make a huge amount of noise
[35:20] if you run it on, try to adopt this in a code base
[35:23] that wasn't already using this rule.
[35:26] - [Justin] That's true.
[35:29] - [Audience Member] And not easy and quick to change either,
[35:31] it's not just like switch some syntax,
[35:33] it's rewrite your tests.
[35:36] - [Justin] Any strong counter arguments?
[35:38] - [Audience Member] RSpec.
[35:39] (audience laughing)
[35:41] - [Justin] I've got lots of counter-arguments against RSpec, too.
[35:46] - [Audience Member] I just want to say you don't have
[35:47] to include standard Rails,
[35:51] this gem in your old code base
[35:54] if it's going to cause a bunch of issues like that.
[35:56] - [Justin] That's true.
[35:57] (audience laughing)
[36:02] I mean, he's not wrong.
[36:10] - [Meagan] All right, shall we vote?
[36:14] In favor is green.
[36:16] - [Justin] Oh, this is too close to call.
[36:18] - [Meagan] Is it? Oh, it might be.
[36:21] - [Justin] I think this session's turning me colorblind.
[36:23] - [Meagan] Yeah. All right. Too close to call.
[36:25] - [Justin] Too close to call. I think we got to disable.
[36:27] - [Meagan] We're going to have to disable.
[36:31] - [Justin] Oh this is a fun one.
[36:33] So this action order cop
[36:37] mandates the order of your public methods
[36:39] in your controllers to be first you define index
[36:43] and then show and then new and then edit and then create
[36:46] and then update and then destroy.
[36:47] And if it's out of order, you're in violation.
[36:50] Anyone have any comments?
[36:53] (audience laughing) - [Meagan] I kind of like it.
[36:55] - [Eileen] I guess Aaron said it better,
[36:56] but I was going to say this is ridiculously pedantic
[36:59] and really annoying, like who cares?
[37:01] Like is this what keeps you up at night?
[37:03] - [Justin] So that's an argument.
[37:05] - [Eileen] It's an argument against turning this on
[37:07] 'cause it shouldn't matter what the order is, it doesn't.
[37:10] - [Justin] Quadruple negative, it's a vote to disable.
[37:12] (audience laughing)
[37:15] One more counterargument?
[37:16] - [Noel] Everyone knows that if you're being pedantic,
[37:17] the proper order is alphabetical.
[37:19] (audience laughing)
[37:28] - [Meagan] All right, let's vote.
[37:33] Oh.
[37:35] - [Justin] This is too close.
[37:37] No. Okay. No, not too close to call. I'm going to.
[37:39] - [Meagan] I mean it's too close for my comfort.
[37:41] - [Justin] That's right.
[37:42] I don't like that we have this many greens up.
[37:46] But it was like 60-40 red, right?
[37:47] - [Meagan] Yeah.
[37:49] - [Justin] Alright, so the nays have it.
[37:51] Here's another rule.
[37:54] I got plenty.
[37:55] Active record override,
[37:57] this checks for overriding built-in methods
[37:59] and active record, like save
[38:01] instead of using callbacks to augment the behavior
[38:05] of these built-in methods.
[38:06] So if enabled, you can no longer define save again
[38:10] inside of your custom model.
[38:13] Comments, thoughts, murmurs?
[38:20] - [Cathy] Share that?
[38:21] - [Audience Member] Do I want to share it?
[38:23] I like using callback, so sure.
[38:25] (audience laughing)
[38:34] - [Audience Member] I could still have exception
[38:35] on a case-by-case basis, right?
[38:37] - [Justin & Meagan] Yes.
[38:42] - [Justin] One last comment.
[38:44] - [Audience Member] Much as I dislike callbacks,
[38:47] some of the biggest holes in my feet
[38:49] were caused by places where we overrode
[38:51] one of the standard methods like save or update attributes.
[38:56] - [Justin] So the first comment elicited a lot of curious murmuring
[39:01] and the last comment
[39:02] elicited a lot of very aggressive head nodding.
[39:05] (audience laughing)
[39:07] - [Meagan] We'll see how that translates to votes.
[39:10] Let's vote on this one.
[39:14] - [Justin] Easy. 90 10, the yeas have it, yeah.
[39:16] - [Meagan] Enabled.
[39:18] - [Justin] All right, prepare to get confused again.
[39:21] So Rails date, if you say date.today,
[39:25] it doesn't take into account the time zone,
[39:28] it's just the system time, free of time zone.
[39:32] Which means that if your offset is like five hours
[39:37] and it's the last five hours of the day basically
[39:39] and you say date.today,
[39:40] it'll actually give you the wrong day,
[39:43] that you probably don't mean.
[39:44] So if you enable this rule,
[39:46] it basically steers you towards using like time.zone.today
[39:50] instead of date.today.
[39:52] And if you put it in strict mode,
[39:54] it also doesn't let you use date.current or date.yesterday,
[39:57] even though I'm pretty sure those do call through
[39:58] to the time zone, maybe 'cause they look like today.
[40:04] Andy.
[40:06] - [Andy] I'm British and I don't see why this is a problem.
[40:08] (audience laughing)
[40:10] - All right, so Andy is a Greenwich supremacist,
[40:16] who lives in the UTC and his CI always passes.
[40:21] (audience lauging)
[40:27] - [Audience Member] I have a code base
[40:28] that has many devs in it and is riddled with these bugs,
[40:33] these time zone related bugs
[40:34] and where our test suite doesn't pass at the end
[40:36] of the month for reasons.
[40:38] (audience laughing) So I don't care if you put it in Standard or not,
[40:43] I'm turning it on as soon as I get home.
[40:45] (audience laughing)
[40:46] - [Justin] All right.
[40:48] - [Meagan] All right, let's vote.
[40:52] - [Justin] The yeas have it.
[40:53] - [Meagan] Yes, they do.
[40:54] - [Justin] Sorry that this isn't that bright in Ruby, but.
[40:59] - [Meagan] What's our enforced style for date?
[41:01] - [Justin] Enforced style?
[41:03] We're going to keep it flexible
[41:06] because Matthew Draper reacted really negatively
[41:09] when I explained what the strict mode does
[41:12] and he's smarter than a lot of us, at least me.
[41:15] All right, so we actually just,
[41:17] we're coming up on time, we only have a few minutes left,
[41:19] which means we're going to go to the lightning round
[41:22] where we're going to go by spicy order ascending
[41:27] and we're going to try to get through
[41:28] just some of these extra rules while we can.
[41:31] So we're going to go as fast as possible,
[41:33] not really explain what the hell is going on
[41:35] and allow votes.
[41:37] No more arguments, just votes.
[41:40] And we'll see how many we get through.
[41:42] - [Meagan] we'll see what happens. Fun.
[41:43] - [Justin] Okay, so where not, you know,
[41:45] so you can't write not equals and not inside of your queries
[41:49] instead of, coaches you to use where.not.
[41:52] - [Meagan] All right, let's vote.
[41:52] - [Justin] Hands up. Turn it on.
[41:55] Where missing.
[41:56] So instead of doing that janky left joins thing
[42:00] where you're like, Hey, is that association not there
[42:01] or there, use the very cool dot missing method,
[42:04] which I forgot existed,
[42:06] which somebody just learned, I'm sure.
[42:07] Yeah, it's pretty cool.
[42:09] All right, the yeas have it.
[42:11] Unused ignore columns.
[42:14] So if you ignore a column and it doesn't exist,
[42:18] it'll tell you to stop ignoring the non-existent column.
[42:24] - [Meagan] Cool.
[42:30] - [Justin] Okay, Uniq before pluck.
[42:32] So if you call pluck and then Uniq,
[42:34] it will fetch from the database unnecessarily.
[42:37] But if you call distinct or uniq and then pluck,
[42:40] you're getting the idea that this is a very agreeable one.
[42:43] Hands up, everyone's yes. Alright, cool.
[42:46] Top level hash with indifferent access.
[42:50] This one requires you,
[42:51] if you want to instantiate a hash within different access,
[42:53] meaning that the keys can either be strings or symbols,
[42:57] you have to actually reference it
[42:59] via the Active Support constant.
[43:02] All right.
[43:03] - [Meagan] Everyone get that?
[43:04] - [Justin] See, there are a few reds.
[43:05] - [Meagan] Oh.
[43:06] - [Justin] We got a lot of abstainers.
[43:08] All right, I think this too close?
[43:09] - [Meagan] That's too close.
[43:11] - [Justin] What's that?
[43:12] (audience member speaking indistinctly)
[43:14] I don't know. Yes.
[43:16] All right, so we're going to disable that one, I guess.
[43:18] Time zone assignment.
[43:19] So if you see code like this,
[43:21] the bad time zone thing,
[43:22] I think what that's doing is it's setting it
[43:24] for the whole process.
[43:27] And the good time zone is wrapped in a block.
[43:32] So if enabled, it requires the block usage.
[43:35] People are saying that's good.
[43:38] Trust the wisdom of the crowds.
[43:40] Strip Here doc.
[43:41] So this will require you to use,
[43:47] instead of calling strip here doc, the squiggly,
[43:50] Ruby 2.3, end up squiggle gear docs.
[43:55] All right, cool.
[43:55] - [Meagan] All right.
[43:57] - [Justin] Scope arguments.
[43:58] So this, instead of passing an argument
[44:02] that is like relation made right away,
[44:04] it's a block to that relation so that it's,
[44:08] yes, run at the time of use
[44:11] and everyone sees that this is a good idea.
[44:13] All right, cool.
[44:13] See, not very spicy. This is very bland.
[44:17] Safe navigation with blank.
[44:19] Can anyone tell me why the bad one is bad?
[44:24] Right.
[44:25] So it doesn't check anything
[44:26] because nil responds true to blank.
[44:29] And if the ampersand,
[44:34] what's the right name for this operator?
[44:37] - [Audience Member] The lonely operator.
[44:38] - [Justin] The lonely operator, right?
[44:40] So the lonely operator. Basically just bad, useless.
[44:42] So everyone just vote now.
[44:44] All right, cool.
[44:45] - [Meagan] All right.
[44:46] - [Justin] Now, Safe Navigation.
[44:47] Now this is try bang
[44:50] does exactly what the lonely operator does now,
[44:52] it just predates it.
[44:53] So this says any try bangs should be converted
[44:56] to lonely operators.
[44:58] So let's vote on that first.
[45:01] Okay, now there's a second mode here called convert try.
[45:05] So try non bang, which will not,
[45:11] wait, it will not raise an error if it's not defined?
[45:13] The behavior is not identical is the point
[45:16] between try and the existential operator.
[45:21] - [Meagan] You all get that?
[45:22] - [Justin] Something about what response to.
[45:24] Does anyone want to take a flyer?
[45:27] Yeah, so try does what with respond to?
[45:30] (audience member speaking indistinctly)
[45:34] We don't know for sure how this works.
[45:36] - [Meagan] Right?
[45:37] (audience laughing)
[45:37] - [Justin] So turn it on, see what happens.
[45:39] - [Meagan] Yeah.
[45:40] - [Justin] All right.
[45:44] Let's not turn that on.
[45:46] Let's keep it at default.
[45:48] Okay, so we're right at time.
[45:52] This was an experiment and it had a result.
[45:58] (audience laughing)
[46:00] - [Meagan] It definitely had a result.
[46:01] - [Justin] Like my most of my favorite experiments.
[46:04] (audience applauding and cheering)
[46:14] I appreciate all of your patience, all of your votes,
[46:18] you can keep the paddle.
[46:21] - [Meagan] Feel free to bring it to your stand ups
[46:23] or your PM meetings.
[46:25] - [Justin] Yeah, wave it at your boss next time.
[46:28] But thank you so much for hanging out.
[46:30] You can run gem install standard-rails
[46:32] and you'll get a sneak preview edition
[46:34] that doesn't work quite right
[46:36] and then we'll update it with these rules
[46:38] and some more later on this week.
[46:41] So thanks again.
[46:42] - [Meagan] Thank you.
[46:43] (audience applauding)
{{< /transcript >}}