Achievement Unlocked: Not an Affiliate
Streamed
Whole lot of ranty topics came up, weirdly. Mostly working on pagination.
scratch
topics:
recent meta thread: https://lobste.rs/s/acavsd/lobsters_site_ui_toggle_remove_last_read#c_cjnuur
about to get the Twitch Affiliate achievement; can't get an API key
close out https://github.com/Shopify/ruby/issues/556
edit out of 502 message
great lobsters community moment
memory usage per puma worker
/comments/short_id needs to 302
hat follow up:
no hat on new message
why private messages are deliberately bad
can't edit hat into a comment?
mystery! added specs but could not repro the exception
behatted comments?
should the route be: /comments/hat/asdf or /hats/asdf/comments
rails mime misdesign(?): https://github.com/lobsters/lobsters/issues/746#issuecomment-1703680599
list of current mods: https://lobste.rs/moderators
pagination
pick endpoint - behatted comments!
https://github.com/lobsters/lobsters/tree/repaginate
cursor ?after=
hopefully not once again running ashore on the reef of 'next page'
should it support a ?before cursor for 'previous' links?
probably want to extract the after() scope to a module that's included
probably want to work in the direction of a Page collection wrapper
enumeration, instance vars for per page, has_next_page
learning the STATE OF THE ART Rails 4 feature: https://stackoverflow.com/questions/11317662/rails-using-greater-than-less-than-with-a-where-statement
todo - CommentsController::COMMENTS_PER_PAGE -> Comment model
merge? https://github.com/lobsters/lobsters-ansible/pull/87
MariaDB [lobsters]> select hat, hats.short_id, count(*) from hats join comments on comments.hat_id = hats.id group by hats.id order by 3 desc limit 10;
+------------------------+----------+----------+
| hat | short_id | count(*) |
+------------------------+----------+----------+
| Sysop | une4eb | 310 |
| Rust Community Team | g7lxq0 | 198 |
| Sysop | sfkgtz | 155 |
| suckless.org developer | rxjule | 141 |
| CHICKEN developer | pfzyxi | 138 |
| Mozilla Security | iq3vhx | 134 |
| Oil Shell Developer | zh7uto | 116 |
| HardenedBSD Cofounder | gjc9m1 | 81 |
| Zig Creator | kxsyd2 | 78 |
| Sysop | d5otlg | 74 |
+------------------------+----------+----------+
title: most amount of magic I'm comfortable with
post-stream:
delete my 5yo pagination branch
twitch schedule: can I cancel JUST next Monday
Transcripts are generated with whisperx, so they mistranscribe basically every username and technical term. They're OK but not great, advice appreciated.
Recording
03:31jangomandalorian ππΌππΌππΌππΌππΌ
jameslittle230 π
Hello again, Django and James.
Nice to see you both again.
Do you like my fancy pre-stream title screen?
I made it so that I'm a little less likely to flash stuff on stream in a minute or two before I get started.
Very, very professional.
Yeah.
But then, like, you know, not totally.
Here's just the usual scratch file.
So...
I wanted to take a look at a couple of things just getting started.
There was a meta thread here that I'm going to grab up.
I don't know why I have that comment link.
We don't need to highlight my comment.
04:20This was pretty quiet.
Nobody uploaded it, so I guess it wasn't desired.
But this is pretty much what feature requests look like.
on lobsters and so i wanted to highlight it mostly because it's it's not especially exceptional the somebody said hey there's this feature that doesn't work the way i want it to or isn't working out and usually when somebody has that kind of concern they can do something like drop by the chat room or just message me or post a meta thread
And we discuss it and we kind of see what works and why the site works the way it does.
There's also the option now of dropping by these office hours for streaming.
So I just wanted to highlight that, you know, nothing is coming of this because it didn't really get any response.
So I emailed the user to suggest that they go ahead and use the ad block rule I pointed them to.
But I thought it was worth highlighting.
There's nothing, I guess, mostly the reason for that.
The thing that was interesting to me is how unexceptional it was.
It's not a big, exciting event.
It's not a big risk to talk about how the site works.
I encourage people to do so.
Anyway, speaking of how things work, let's get that browser back.
had a whole gripe about twitch affiliate so we've we've talked about how because i streamed a while ago there's this achievement thing for becoming an affiliate where they which lays out this whole path for you of building an audience and it gives very clear next steps for how to go and how to build and because i've streamed before and had some followers it
was basically getting set to be done.
The thing that it's waiting on is this stream on seven different days.
Well, this is day seven.
The achievement thing will update at the end of the stream or within a couple hours of the end of the stream.
It's not really clear to me.
And I've talked about
whether it's worth being a Twitch affiliate and kind of, I realized that this achievement is missing something that there's this, the, like how many days have you streamed?
But if we duplicate it, we grab this guy and we edit, see, I have to, I don't love the, like, let me,
rant about a big company service but i am a little bit griping about it where's the number here seven yeah i only need one i have been wanting to there we go isn't that nice see
Now there is the missing achievement for Twitch, the missing criteria.
So I would like to have a Twitch API key to develop stuff, but Twitch is not super serious about...
The thing, to get a Twitch API key, you have to sign up for 2FA, which is totally reasonable.
get it to a to sign up for 2fa you have to have a phone number which is also pretty reasonable because they want to have a fallback although it does open people up to sim swapping and also twitch streamers the the popular ones much more popular than me have had hassles with like weird fans show up at their homes that's inappropriate
And their phone number controls require that you give them a non VoIP phone number and I don't have a non VoIP phone number because Lobster's is popular enough at something like a quarter million visitors a day that I've had to get a little serious about privacy.
I've had
A couple of mildly unpleasant things like folks find me at tech conferences or tech events.
Only one person was unhappy and he just wanted to continue a fight.
It wasn't even moderation related.
He just wanted to argue a thread.
So it's very frustrating that the intersection of caring about privacy prohibits
jameslittle230 Thatβs so unfortunate :(
getting a twitch api key when you think i would have expected that twitch would be a lot savvier about that so that's just me griping and trying to do something silly about it because you know make something positive out of it i don't know i've been talking i've been sending emails to their dev rel team they have been politely ignoring them we'll see if that ever goes anywhere
tiransol Unfortunate but very common from most US based companies :(
So another fun topic.
Yeah, James, it is unfortunate.
I understand why the common case is that they have to, I'll bring that back up.
jameslittle230 ah - I was referring to people coming up to you to argue a thread, but the twitch API integration requirements are also very unfortunate
The common case is that spammers want to get API keys so they can make really abusive integrations that are like the chatbots that, you know, I average want a stream that shows up and, you know, wants to sell followers or viewers, which is really, really obvious spam.
jameslittle230 unfortunate all around
I'm surprised so many get through.
I assume they catch 99% of them.
Oh, yes.
Someone coming up to me in person to argue a thread
That was weird and unpleasant all around.
The more positive version is some people came by a meetup just because I had publicly RSVP'd.
It was the... Yeah, I'm not going to say the language, actually.
I guess I'm a little nervous.
But it was for a specific programming language.
It was like a hack night.
And it was, you know, bring your project.
And I brought my project.
And a couple of guys came up to me because they were like, hey, you're Peter, right?
jameslittle230 AAAH NO SO WEIRD
run lobsters and i was like yep yep and then we just kind of stood there and stared at each other for a minute and i was like what's what's your project what brought you to hack night and they were like oh we just wanted to meet you and i was like that's why would you tell me that what am i supposed to do with that information and they just kind of like stared at me like they were waiting for me to do something related to being a lobster moderator i was like do you expect me to
Edit tags?
I'm just here for the hack night.
I'm not going to fix story titles or remind someone not to call people names.
It was so strange.
Please don't do that.
Boundaries are good.
There have been less pleasant versions of that.
We don't need to dive into the sad story stuff, but...
That's why I got a little careful about privacy stuff.
And a standard SIM is like, let me link this location tracking device with my home address and carry it around all the time.
That's the kind of thing I'm careful about.
And so it's really frustrating to me that Twitch, who I would really expect to be to be savvy about this, or at least to have some kind of escalation path, even if I wasn't surprised that tier one support gave me just garbage copy paste answers.
It's frustrating and annoying, but I understand that they must deal with just an incredible volume of nonsense.
Getting brushed off by the DevRel team and by a Twitch employee is a little frustrating.
If anybody knows another Twitch employee, I would love to.
Anyways, I would rather move on from the Twitch drama.
I'm going to keep hassling them.
We'll see how it goes.
Oh, I don't just, I haven't just gone out and bought like a $10 track phone and a $5 a month SIM.
Because the help text around 2FA makes it clear that Twitch is going to keep using this number.
And so then it has to be a live phone number that is in my house, which is the thing I don't want.
Very unfortunate.
So there's that gripe.
And hopefully, at least the silly achievement screenshot editing is a little more fun than just me whining about
normal policies being applied to me.
So on the last stream, Byroot came by.
Byroot is the, I think he's Ruby core team.
Wait, is he Ruby core team or Rails core?
I can't remember his bio.
Okay, Rails core Ruby committer.
That's where it is.
A very, very experienced Rails developer and Ruby implementer.
Daniel Katz- came and paired on Monday, which was super great because we worked through the heap dump and we worked through like what can we learn from the flame graph.
Daniel Katz- What do we learn from the heap dumps and the really interesting thing from the heap dump was that there wasn't any smoking gun there was nothing that.
Daniel Katz- leapt out at us as Oh, this has got to be something that's leaking there were some small things like.
It's odd that RuboCop is loaded in production.
We could save that RAM.
It was odd that i18n was loaded in production.
We could not save that because lobsters uses Rails helpers that invoke that.
So, OK, fine.
But at least we can shift it to boot time so it doesn't stand out in future heap dumps.
But then the really conspicuous thing was that maybe it's that we're not using GemAlloc, which is an alternative
I'm going to tongue-tie myself and describe this wrong, but it's an alternative allocator for Ruby objects that is better about heap fragmentation, where, say, we allocate 100 little strings and then we free every other one.
Ruby, especially if I ask for slightly larger objects, well, I have half of my RAM free, but it's kind of unusual because it's broken up into too many pieces.
And GemAlloc does...
very magical compiler things that I've actually never bothered to look up and read so that it can work better.
We joked about defragging, but that is not a thing.
And probably Ruby's GC pauses are large enough already.
Actually, I couldn't tell you if Ruby does some version of this or if Jim Alec does some of this.
See, I'm ignorant.
I'm mostly, I'm a generalist.
I just try and make things work.
I think a lot about the UI.
And I know enough about what the heap is to be dangerous and to tinker with stuff like GemAlloc, but I can't actually explain it all in super depth.
So the really interesting thing was the morning after the stream, I deployed all of this code.
So that is almost exactly 48 hours ago, 48 hours within a couple of minutes.
And we have now finally had
dr3ig yay PartyHat
yjit enabled and zero puma crashes for oom kills in 48 hours where previously like 14 hours was our limit so we're now at 48 so that's that is a big smoking gun that this was our problem so if i swap out i should have grabbed it if i swap out
my generic streaming browser for one where I'm actually logged into GitHub, I can leave this comment basically saying,
17:50dr3ig and what's the memory usage per puma worker like right now?
What's the memory usage per Puma worker?
Hey Drake, good to see you again.
I will pull that up in just a moment.
18:09I'm trying to write something coherent because, you know, don't want to waste important people's time and the Ruby core team are certainly important. Although I am aware this is Shopify's fork of Ruby. They're the ones who have been doing all the YJIT stuff. Well, maybe not all. I don't know who's contributing to it. I try and be polite about giving credit. I think that's really important, especially in all these volunteer gift economy kind of things. So that's why I keep catching myself and saying, well, not everybody.
19:32Let's name check him.
Yeah.
So aside from pinging him, I really do want to credit him for fixing it.
That was enormously valuable.
And another thing that's been really nice, it's not visible anywhere here on GitHub.
But the lobsters community has been really chill about this bug that rather than immediately disable yjit and leave it off, I left it turned on so that we could try to diagnose a potential memory leak as a way of giving back to the...
I'm tweaking my to-do list here, my scratch.
I have to edit this out of the 502 message.
tiransol I didn't even notice. Would you just be greeted with a white page every now and then?
And then memory, let's do this so I can actually talk.
So I have like a mental memory.
See, I can't talk and write.
20:53There we go.
gloatingfiddle I haven't even noticed the bug, tbh
So I have a stack.
And when people ask me questions like Tyr and Sol asking about being greeted with a white page, yes, I will show you what that looks like.
When enough of those build up, my personal memory stack overflows.
And then I forget what I was going to do with streaming.
That's why I have this scratch file.
So I have to take down these notes.
hi gloating fiddle yes you hadn't noticed the bug but i certainly did especially since i finally instrumented downtime so i think i can just let's go ahead and put away that personal browser before i do something dumb in it let's bring up the streaming browser see i'm trying to be smart about this and then
I think you can just directly request the 502 page.
Yeah.
So this is what it looks like.
This is the page when Nginx gets a...
So Nginx proxies over to the various Puma workers, for anybody who doesn't know the pretty standard Rails hosting setup.
And when the Puma workers are...
tiransol Ah I actually ran into it. Just waited and retried 2min later.
either all busy, which is very rare that they're all pulling some, like, 60-second request.
I've never seen it, but it's totally possible that somebody could find an expensive endpoint in Dossus.
Or when we're in the middle of a deploy, or we're not in the middle of a deploy, but we're down.
Yeah, so Terence, you did notice it, but...
One of the nice things about, hey, all of our users are developers, is I can just say, hey, we probably think this is a memory leak.
And I can link to the GitHub issue.
tiransol It's just one of these things are like: "Ah that happens, also it's an amazing free service, not gonna complain" :)
It's very nice to be an open source project that way and have developers who are experienced with things like memory leaks, or at least know the term.
Because then I can just explain what's going on.
I don't have to be like, oops, our web server did a fucky wucky.
We'll come back and fix it.
The moles are working.
I really don't love those cutesy error pages.
I like that I can just explain what it is.
So, yeah, Tyr and Sol, you're really getting at what I wanted to say about it.
I think it's a great community moment that everybody was very patient and cool with it.
And it's like, no, these things are a pain in the ass to debug in prod.
And if it means that once or twice a day we're catching two minutes of downtime and you can literally just hit reload until it comes back up,
that's really chill that's it's not a big deal and i oops so this i just caught myself here speaking of bugs previously on stream i had vim in weird states and i was like you know smashing at the keyboard wondering why i couldn't
get my shortcuts to work.
And the answer, somebody on chat pointed out.
I'm sorry, I don't remember who.
Probably Hedgie.
That person was very perceptive.
Noticed that I was nesting VIMs.
And so I improved my VIM config so that when I open a terminal, I can't start a VIM inside the terminal from VIM.
And so I just had to dump an inception quote.
So that's me catching my own mistakes.
What I actually wanted was let's open a tab and edit files.
Specifically, let's edit the 502.
And I can just go ahead and entirely delete this paragraph because it's done.
Because we went 48 hours, 48 and a half now without Puma getting a OOM kill.
I don't think it's an issue anymore.
I think it's safe to say that it's done.
So I'm gonna go ahead and just edit that out.
Oh, I have more loose ends for later.
I didn't realize I didn't push that one up.
So let's go ahead and add this and commit.
I think I can say not seems to have been.
25:33There we go.
So with that committed, let's go ahead and push that up to prod.
So there's a funny thing where in the IRC chat room, I wired up the channel bot to print commits off of the Lobster's GitHub repo because I think it's very useful for transparency when I tweak stuff.
That can be changing meta behavior of the site.
I think it's worth having more visibility into that and also just showing off, boy, there's a lot of just unglamorous maintenance work that happens in running a site of fixing a typo, fixing a small bug, updating to the new version of Rails.
But if I'm streaming and I make like 10 commits and I push them up,
The bot will print one line for all of those.
And for anybody else who's old and uses IRC, the bot will immediately get killed for flooding because it's printing so many messages in such a short amount of time.
And rather than, I think I threw in a GitHub issue for that on the mock turtle bot repo, but it just needs like a sleep one in there somewhere.
And I just want to push commits occasionally rather than save them all up.
So I think this is a nice end to this chapter.
It's been running for a while.
dr3ig you said lobsters is on Digital Ocean, but how big is the VPS? is MariaDB running on the same box?
And it was fun to debug it with core Rails and Ruby people like Aaron Patterson and .
So Drake asks, you said Lobster's is on DigitalOcean.
How big is the VPS?
Oh, I didn't look at the memory size like you had said.
Yeah.
Let me check something here.
Good, all right.
So if that's gonna behave, I can just go ahead and SSH to prod.
So you asked how big is the VPS?
That one's on our trivia.
It is the eight gig for vCPU.
This is probably overkill for the web server, but I was upsizing the MariaDB server and I hit the wrong one and I upsized the web server.
And DigitalOcean, I understand some of the technical reasons for it, but it is also a business reason.
If you upsize the memory of a VPS, you cannot downsize the memory.
You have to kill it and recreate.
And I just didn't want to do that.
It wasn't worth a couple extra bucks a month.
So I left the web server with extra RAM.
And then it turned out handy because it meant that leak was, you know, an every 12 or 14 hour thing instead of an every six or seven hour thing because I had doubled the RAM.
So...
What's your favorite way to see how much RAM the Puma workers are taking up?
Did you want to just look at HTOP?
So they're each doing...
So it looks like they're each in the 141 to 145 range.
dr3ig yeah, ii guess htop is fine
And since this has been running for 48 hours, we know this is pretty stable.
Otherwise, it would have gotten OOM killed by now.
Is this virtual size the one that you were specifically looking for?
Or I guess maybe you want the resident size, which is in the 265 to 270 meg ram.
Yeah, so that's all fine.
dr3ig and how big did they get when they were getting OOM-ed ?
important thing about it is less how big it is because our app isn't huge and so having a a reasonably small bundle size means we can run more than enough workers for prod and how big did they get when they were getting om'd well if you take eight gigs and you throw away five percent for
operating system overhead and then divide that by 20, that's basically how big they got.
They were getting OOM killed because they filled all the RAM on the box.
I deliberately configured prod to not have, what's the one where, it's like the RAM doubler
where it swapped.
Thank you.
I don't know why I couldn't remember the word.
Deliberately configured it to not have swap space because if a prod box starts swapping, it is in a weird liminal broken state where it's not going to be serving requests in a timely manner.
dr3ig so ~400 MB
It's better that things crash right then rather than serve things at a greatly degraded performance.
So it was, you know,
So around 400 megs?
Yeah.
Whatever that number is, they just filled RAM.
So MariaDB, to address your other question, is not on the same box.
It's been up here on screen, but I haven't called it out.
I deliberately set the two of them up because Ruby web servers are hungry for RAM all the time.
That's just because Ruby is an interpreted language with garbage collection and, of course,
The easiest way to improve database performance is to just size the box so that the whole database can fit in RAM.
So that's exactly what I did.
It was one of those places where I decided to throw 10 bucks a month at it rather than spend forever tuning queries.
In case anyone is wondering, this is not the box is on fire and in an insecure state.
This is Ubuntu wanting to upsell their premium security subscription.
I do actually run the regular upgrades.
31:39So that's about memory usage from FumaWorker. If there's any more questions, I'm happy to take them now, or I'm going to jump on to some of this other stuff that is follow-up from previous, or this one is literally just a personal quick hack. There's... Why are you blowing up?
32:11error loading the, oh, this is my, so this is last stream. I, I'm going to do this off screen. Cause it's, I don't think it has a password, but the, on the last stream by route contributed a, there's no passwords in here. I'll just do it on stream. Last stream, Byroot contributed a pull request to update the gem we're using for database access from MySQL 2, which is unmaintained and going to be replaced as the default MySQL adapter. So we're moving to do it with Trilogy. And there is a helpful Rails message that says, oh, you asked to use MySQL 2. you probably want to add that gem and use it, which is misleading for this scenario of we were using MySQL 2 and now we're moving over to Trilogy. So let's make sure the bundle is up to date. And then now I should be able to, yeah. So I'm going to go ahead and get that off screen. I don't need the browser this second.
33:49One of the things about our routing is that we don't super follow the rails conventions this came up a week or two ago when I was tweaking the hat stuff for comments, we also have a bunch of custom routes because again that's our secondary God object. And one of the things that comes up. For me personally. is we never, in production, you never see this URL unless you are me looking at an exception, specifically with the get. Users do patch and put all the time to update comments, but they never get to slash comments. They often do a get to, where is this route?
34:39To the short URL for a comment, but not the long URL.
...51And so the comments controller has the redirect, but it doesn't actually work. And I don't know. Yeah, it's the, what did I put in here? Yeah, it's the plural. Rails plurality. I'll never stop. I'll never start liking that. so in the show it's calling find comment and find comment is not correctly using the short id except it is and for me why am i seeing let's let's start the rails server because there's some behavior here that's very annoying So if I pull up the console, grab a comment, short ID. What I want to see is if I curl that. So here's the short redirection. This works fine. We get a 302 over to where the comment lives on its story. If we say slash comments, I get a 400 instead of a 302. And that is the bug that is bugging me. This should just be a 404. Yeah, that's fine. I don't want to make that work. I want to fix whatever this 400 is. And it's kind of funny. This is one of those things where It is a bug that I personally see and want to fix. And there are one or two of these little things in here of if the admin is doing a thing, let them do that convenience. Because the site doesn't have a big, beautiful admin panel with every function I could want. There's a bunch of stuff where I drop back to the Rails console or I do stuff manually. I have slowly been moving these things into the website. And along the way, there are lots of these little convenience methods.
37:25So the other thing is as long as I'm in development mode, this URL should be giving me a useful exception page. Yeah, I can't find comment.
38:02I wonder if this is the show. No, that's for front end editing. This show. Oh, it's rendering because it finds the comment, but then I can't edit it because I think this is broken code. When you are on lobsters and you want to edit your comment, you can click edit on it. you go to an edit form but nobody actually does that because in practice everybody has javascript enabled and you just go to the page so if i go look at the rails server output when i load this page yeah it does actually load the comment and then load the votes on the comment so it knows it's in the database and it's successfully loaded i'm just getting bitten by this if that I didn't realize was here. So what I want to say is if you're not, if we can't find the comment, you get booted out with a 400, which I guess should be a 404. If you can't edit the comment,
39:33you should get redirected.
And now... Ta-da!
dr3ig is comment visible there outside if ?
You can see me testing some hat stuff.
There's old test data.
I don't think I did this particular test on stream, but we're going to touch hats in a minute, so it's appropriate.
Is the comment visible there outside the if?
I'm not sure what you mean.
Here?
So...
This is Ruby cleverness.
You notice I have a single equal, so I'm assigning to the comment variable.
And then standard RB enforces that if you do that, you kind of have to highlight it by putting parentheses around it.
dr3ig yes, that
So this comment variable is getting reused here, if that's what you're asking, Drake.
40:25Yes, that, yeah.
A lot of people dislike this idiom, but I'm perfectly comfortable with it, especially with the standard RB rule that it have parentheses around it.
dr3ig i was wondering if declaring a local in an `if` makes it viisble outside the `if`
I mostly like a lot of the Ruby syntax sugar.
The only one that I don't like is the nil propagation operator, which they call the safe navigation operator.
I was wondering if declaring a local in an if makes it visible outside the if.
Yeah, this is...
Ruby is nice this way.
It does the lifting that caught your eye.
I don't believe JavaScript does.
So if you do more JavaScript, that's probably why this caught your eye.
If I had said, if I change this to if true, you know, this comment variable, I honestly don't remember if it's going to get hoisted or be visible here.
I know if this is a loop,
It will not.
I've been bitten by that one.
But this is such a weird pattern.
I try not to do it.
This is the most amount of magic I'm happy with.
Or the most amount of magic I'm comfortable with.
Oh, there's a good stream title.
See, I keep looking for these.
I thought it was going to be something about griping about Twitch or the white whale.
We'll get to the white whale.
42:06Let's go ahead and run the test suite. I don't think there are any specs for that. And I don't know that I want to write a spec for a one line if that really only applies to mods who are reading backtraces. It's just not worth the two milliseconds it'll take in every test run to load a record into the database and then run through the whole stack.
...45There we go.
You make enough tiny quality of life improvements and you have a very luxurious life.
So there's that.
So looking at these hats.
One of the things I changed recently.
Was for.
Excuse me, perhaps to be looked up by short ID.
easeout I saw a "where short_id β¦ || find short_id" a minute ago, and I wonder if that 400 is related to where getting many and find getting one. (~kevinc here)
Rather than by their bear ID it's just with hats it's not really sensitive information how many hats there are, but I don't like to encourage people to you know enumerate every.
Page by having an automatic ID.
EaseOut says, you saw where short ID or find short ID a minute ago, and I wonder if that 400 is related to where getting many and find getting one.
Oh, hey, Kevin Conroy.
Nice to see you.
For anybody who doesn't recognize Kevin C, you are looking at their work right now.
Kevin C contributed the dark mode to lobsters, which is maybe the best example of bike shed painting in lobsters history.
easeout cheers
Much thanks to Kevin C for that one.
So you saw something about short ID here.
Was it up here in the show method or were you referring to down at the bottom in find comment?
You can call it a line number if it helps or either of these methods.
I think maybe you were seeing this find comment here on line 394.
which is, I don't know when you connected to the stream, but this one is a fallback that's literally just for the admin.
I don't know that I saw one where there's a where in it.
45:05easeout yeah 392 and 394.
So yeah, 392 and 394.
There is a lot of this where first in the code base, and that predates Rails find by.
So this is the modern Rails idiom for this, if that's what caught your eye.
In this case, I wanted to deliberately write find or nil.
So I think that's a perfectly safe refactor.
Let's say where dot star burst in app.
Yeah, see, it's all over the code base.
A lot of these, if I were to dig through the git blame, a lot of these are 10 plus years old.
And I've never wanted to bulk refactor these.
I tend to touch them as I see them because why risk a refactor even if it's safe?
How many times have I been burned by a safer factor?
There's always these consequences.
So if I change that, let's take a look.
I don't expect anything would start failing.
It's safe.
But boy, do I not want to touch all of those in the code base.
I don't even know if I want to commit this one.
Am I correctly understanding your concern that you noticed the missed idiom?
Or were you just puzzled by doing a where and then another where?
34 of these.
Yeah, that's not a refactor I want to do.
47:06easeout I don't particularly know rails/activerecord so just hoped it was a helpful place to zoom in
This one is doing different stuff and there is probably a clever way I could have added it.
And so, but I would rather just break it out because then it's unambiguous that this is just for the admin.
This kind of, you know, one extra predicate, one extra if is not expensive, especially when it follows is admin.
If you're not super familiar with ActiveRecord, yeah, that's why this happens twice.
easeout what seemed off is i thought they might get different entire types
Because of business logic, the other part of bind by is just site age.
So I'm going to leave that, actually.
Yeah, no changes.
34 of them.
That's more than I expected.
I've slowly whittled them down, but not very.
So let's go back to the hats controller.
speaking of find bys and short ids i had it look up hats by short id and i already did some cleanup work following this but the hat code was less comprehensively tested than i had assumed and so a couple of bugs snuck in what seemed off you thought they might get different entire types yeah the
convenience method that's happening for the admin there is even though that route looks up things by the short id which is a string occasionally i want to look up a comment by the primary key which is the auto increment id and we've been deliberate about not leaking that but every once in a while i have something that i've pulled up in a database query and i just want to throw that into a url and see it on the screen so that's why it seems to be entirely different types it is
All right.
So the specific bugs that have come up is using a hat on a private message.
It's just literally not getting applied.
And I sent someone a message with the sysop hat on and then I looked at it in my outbox and I didn't see the hat.
And I honestly don't know if that's the view of sent messages not including the hat or if it's the hat didn't get applied.
Maybe that's actually the first thing to check.
I'm gonna do that off screen, because speaking of pulling up IDs, that does.
So if I...
So I'm pulling up a Rails console, and I'm typo-ing in prod.
That's great.
And asking for the last...
Sent message.
50:10And it does not have a hat assigned. Yeah, that leaks a bunch of user ID. So that's why I'm not showing on screen. So it's the messages controller or sending private messages.
...28And it must be this create. is fined by failing. Either the user is wrong or something. And I want a spec for that one. This one, I don't think anything in here mentions hat, does it? Oh, how did I get the same file again? Spec hat. No, spec messages. We have a message model spec, but no controller specs. So if we have zero controller request integration specs, that's probably why this functionality is easy to break. The private message feature is kind of deliberately bad. It is a user interface choice. Let's mention that.
51:35private messaging feature is there so there are fewer meta threads on the site like hey can i contact you about this and then someone having to publicly reply and be like yes my email for the spam bots is or leave a comment that explains where to find their spam protected email on their personal site it's just not a interesting and useful back and forth that kind of clutter and then also it's nice for people to be able to send each other quick notes the message feature deliberately doesn't have a lot of functionality it's not especially nice because we want people to just take it to email and if the message feature works but is mildly unpleasant hopefully people will take those discussions off site and it's not a get lost it's a please just directly form a connection so let's look at the i swear the other recurring theme of this stream is do i want a controller spec a feature spec a request spec there are so many tools for the job and i never remember which one is currently in favor i know i think it's feature specs are out and request specs are in i can't remember they're almost identical we're going to write a controller spec anyways because i don't need to render the whole view i really want to test here that i can send a message that it gets logged with the right hat so let's grab an existing one for a template sure let's see how did i get into the requests Only have one controller spec. This might be for somebody who's familiar with our spec. It is totally possible that I'm forgetting that controller specs are entirely discouraged. They might be. Yeah, I think they are. And we've been slowly getting rid of them. So let's go ahead and make a feature or a request spec. Let's save this as spec request. there isn't any yeah there's a factory but that's it so let's save this as spec requests and we are describing messages which are requests we have to have a let's have a sender and we will probably need a recipient And before we are gonna sign in the sender, don't need that.
55:05So I'm going to write the basic smoke test up here, even though the spec I want to write is this, but I am feeling a little bad that there are zero tests of messages. I don't know that it's ever broken in prod. So what has that been? Over a dozen years now. That's a pretty good run that that hasn't broken. So I don't feel bad that there was never a spec, but it's nice to have just a basic smoke test. So let's go ahead and say that when... And this is, since I can't remember the difference between feature and tests, I can't remember the, is it get, or is it visit? So it's post. So we're going to say if you post to slash messages, which is the route, right?
56:03dr3ig does lobster have any error monitoring enabled (sentry/rollbar/.. homegrown ?)
Yeah.
Where's create.
If you.
Post to slash messages.
Does lobsters have any error monitoring enabled, like Sentry, Rollbar, Homegrown?
Yeah, yeah, it does.
I will show you what it looks like.
It is... Where is it configured?
...30Ah, it's in the sample production RB. I'm not going to pull up the live one because that's full of production keys, but... We use a gem called exception notification, and it just literally emails me. So if the site throws a 500, an email lands in my inbox, which is motivating. If the site has a bug and throws exceptions, my inbox fills up. My phone gives me a little ding. I have done a ton of work to make sure that in practice the site does not throw 500s. I know that there is some level of 500s that every production site throws, but if it gets above one or two a week, I get pretty annoyed. However, the flip side of this being very, very simple is when I have broken pages, like the homepage, or comment posting, I get a 500 email for every time we throw a 500. So having broken the home page once or twice, that means I get literally hundreds or thousands of emails in the span of a couple of minutes. That's no fun. I actually ended up writing a little script for this situation that logs into the IMAP of my email and then just demolishes all five hundreds that match whatever that criteria is, because I don't need to download all several thousand of them. So lobsters has, I don't know, motivational error monitoring. So if we post a messages, let's go ahead and just steal this.
58:37and say that we expect that posting two messages with params, and we will get into those, to change message.count. I think it's by one, right?
59:07BIM, why did you shell out BIM? That's not what I wanted. I've tweaked the, yeah, that's nice. I've tweaked the config so much for stream setup that some very familiar things are a little unreliable. So we're gonna say the params for this are, there's gonna be a message object And this is me looking over here and comparing. And I know, yeah, it's going to be a message. We're going to say recipient username is the actual recipient. Username subject is hello. There are a number of Simpsons references in the Lobster's code base. And now that Simpsons has been on the air for, what, 35 years, we have a number of users who are younger than the references, which is strange. I don't know that I want to put in modern memes because I'm old. I can't use modern memes, right?
01:00:37We don't need those other things. I think that's enough. And we expect. I don't have the.
01:01:09So I open the user model there because I have the very basic Vim config. It's certainly not basic Vim auto-completing. And if it doesn't have the buffer open somewhere, it doesn't auto-complete something there, which I mostly like because it is obvious. I don't want that to be too clever. Although there is neat stuff like the cursor autocomplete that would probably have just written this spec for me. Undefined method by for true, because I don't want these parentheses, right? No, I just want to move this in here. And then this can become that.
...59anshulxyz whatβs the intention behind no colorschemes?
And now that's a syntax error.
All right, let's put your parentheses back.
What's the intention behind no color schemes?
It is not no color schemes.
It is, let's pull up the link.
pushcx https://push.cx/stream#no-synta…
Did I?
There we go.
So I'll throw you this link in the chat.
It actually is,
highlighted it's just very maybe i'm an amish coder and i'm being modest or who are those folks i always see in the train station the the mennonites where they take the train but they always dress like it's 1850 wrong number of arguments given two expected one i just like having a a fairly plain color scheme
I think it's the Mennonites that call themselves the plain people.
It's not the Quakers.
So it's messages spec 15.
anshulxyz Amish?
Oh, it's, I have an extra post in there.
All right, and let's go ahead and run this over on another terminal.
Amish know the Amish don't take the train at all well, maybe for emergencies I think it's the Mennonites they call themselves the plain people that's not one that I care to look up right now, though.
01:03:40Okay, so good, we have a green dot. That's always nice. And then I always like to see specs fail. So let's go ahead and say, instead of calling new message dot save, we will just say through. And then green dot should become a red dot because there aren't any messages. So every time I run specs, I like to try and predict whether they'll succeed or fail. And if they'll fail, can I predict the reason they'll fail? And it is yes, this to change expectation to good. So I am testing what I think I'm testing. And so now that I have that basic smoke test, let's duplicate it. And now here's the one I want to write of, let's give this user a hat.
01:04:41We are going to say⦠Excuse me. Maybe I'll have to get a fancy stream deck just so I can clear my throat.
01:05:01It's not hat.it, it's hat.shortid. And I am going to go ahead and get rid of this external expectation. I think it is implicit and it's already clearly tested there. So why test it again? And so I will expect also that the received message
...51dr3ig why do you use both single quote strings and double quote strings ? :)
hat is so I expect this spec to fail because this is the behavior that did not work for me in prod like two hours ago they both failed did I not save when I put the message back yeah I didn't save I must have saved the spec and not the controller okay so the controller's back to the first spec is green dot
And now the second one is failing because I expected to see the hat and I got nil.
So that's the bug right there.
So frustrating thing is this code looks legit, like exactly what it's supposed to be.
01:06:44So let's go ahead and just, oh, nope, now I see it.
easeout nice chill stream, have a good time π
It's in the message array, isn't it?
Bet that's it.
Nice chill stream.
Yeah, thanks.
Thanks for dropping in, Kevin.
It is always good to see a contributor.
I don't know why you have a little crown on you, though.
Prime Gaming.
Oh, you must watch a lot of streams.
Cool, cool.
01:07:29Let's go ahead and look at adding some debugging.
...54easeout yes that is an accurate conclusion to draw
Just look at all of them.
01:08:09Maybe this is a model issue because so the parameters. The parameters, it's the parameters, it's not there because I didn't add no head ideas there. I'm not reading right, am I?
...36So the message parameters that were sent in. Do not include the hat ID, even though I explicitly sent it. So either. It's getting stripped off here or it's getting stripped off. It's present right here. This is one of those. A security feature is helping me.
01:09:08So let's look at the params before I do any filtering. And then. Oh, I'm reading the wrong line. I was running two tests, so let's. Yeah, let's only run the hats back here. It's confusing myself. It's not dash and is it dash E? Never remember all these switches. Okay, so now i'm only running this one, yes, had ideas present both in the rock rams. And in the. controller, but then, when looking up the users wearable hats there's nothing this might be a test data thing because. Rails is lazy about, or RSpec is lazy about creating things, so we'll just say hat equals, oh, I didn't assign the hat to the sender, so even if, that's why. So the sender didn't have that hat, so this spec was, this test was not doing what I wanted it to do of Being accurate. If I get a green dot, I'm actually going to be mad. I'm mad. So it fails in production, but the spec is happy. That's awful.
01:10:57One of the reasons, oh, is because I fixed this. That was the fix, wasn't it? I forgot I spotted a likely, there it is. So that was the bug. I had set it and then I didn't get the green dot. And so then I forgot I had left that edit in. That's the bug. Yeah. So let's add that spec and then the change to the controller is there. That's it. Let's say messages fix using hat on messages and we'll add a smoke test for messages. That's great. And then I saw a similar bug. I saw a comment someone left this morning and I was very suspicious, because I think they tried to use their hat on the first comment, but then they used it on a reply to themselves, see if I can pull that up. It was.
01:12:24So I'm just skimming here for the hat. They were using their hat on a thread talking about why Go works the way it does or compares.
...42And it was sometime overnight the comment came in, so it should be, man, speaking of pagination, it should be somewhere in these first couple of pages of comments. And I'm not going to keep scrolling forever until I see it.
01:13:01yeah not seeing it it was definitely not 18 hours ago i must have missed it somehow or maybe they removed it i don't know but the thing i saw is a message someone sent me saying that when they edited their comment they were not able to add their hat and it is probably the exact same bug where either the params is stripping it off
...39or it's not in the array. So let's go ahead and check that one as well.
...53So we have comments and we don't have any spec that someone can leave a comment with a hat. This is a, oh man, there's an important smoke test for uploading. Yeah, there was not one. There must be a spec for leaving a comment around, but I don't see it this second.
01:14:34We're going to make sure that works. We are going to say if we post to comment slash with.
...58I'm trying to think if there's a quicker way to do this. There is a comment feature. Yeah.
01:15:17So one of the, one of the things that happens with code bases and I'm doing this right now is It's so much easier to modify existing code and copy its template because you know it works, then write from scratch. And so I am writing a slightly slower feature spec instead of a slightly quicker request spec that's going to hit more of the stack.
...57Where does it create the user? Up top? All right. the user according to our current user and then we're going to fill in i think it's fill in hat it's the name of the field with hat short id we click post and we visit and we expect it to have
01:16:34The text of the head on it.
...49You don't like that. I did that, I guess. So let's see if the other specs want to go back green and only the new one fails. Yeah, so that's positive. And it doesn't see the field hat.
01:17:14So looking at this form, it is called hat underscore ID. So I guess that's fair.
...30One of the nice things about this being a request back is i'm not coupling to the parents of is it in the comment object or in the comment hash or is it external. unable to find an ID that is not disabled.
...50well.
01:18:00Let's take a look at that because I sure expected to see one.
...27So we are looking for the form.
...35We have the form container.
And it did print a select with the hat ID and the ID hat ID.
So this is some hassle with RSpec where I said fill in hat ID.
It says it can't find it.
And I get to fight around.
Am I trying to pass a CSS ID?
What will make you happy here?
The answer is nothing will make me happy.
Maybe passing a CSS selector.
Please see the documentation.
Just any page of the documentation or did you have a specific page of documentation in mind?
Getting jealous of Elman.
dr3ig select instead of fill_in ?(perhaps?_
rust errors that are nice and verbose they would have told me what an acceptable locator is or linked to it unable to find field hat i can find the field hat i can even find the mccoys
01:20:02dr3ig maybe there is a different helper for select than for input
I wonder if this is, thanks.
I wonder if this is that it's a select rather than a field.
Aha.
So if I, instead of saying fill in, if I say select option here, all right.
and do that from hat id or from hat we're gonna tinker with this till it works oh drake you got there the faster than i did i stopped looking at chat for a moment sorry okay
cool so it's another spec that passes when i'm looking at it, but I expected this back to run through and then fail here because I just did this this morning and it didn't work.
01:21:37All right, what have I changed?
I haven't changed anything except added a spec.
And I'm in the unenviable position of the spec is green, but the feature doesn't work in prod.
dr3ig is it possible that `hat.hat` is common enough that it is present on the page ?
And I have been reluctant to bring my actual inbox up on screen because I know there's some demo data in here.
Well, I know there's some old production data in here as well as demo data.
Is it possible that hat hat is common enough that it is present on the page?
No, because it's going to get filled in with lorem ipsum.
And so if I say, what's hat hat?
That's the title of the hat.
01:22:22Oh, you know what, though? The message inbox. right so it's not lorem ipsum but then and it should be the message inbox includes a form for new messages so it is totally possible that getting redirected to the page it is seeing the hat title in the new form rather than on the sent message and that must be what happened because when you send a message you get redirected to the inbox rather than viewing the sent message so that's i'm not testing what i think i'm testing all right so let's improve that hat factory and i think i can say
01:23:28I swear there was a way to... Yeah, the fake data task uses it.
...49Let me just say, how did that go?
01:24:15Most hats are two or three words.
...25So let's first check that I did what I think I just did with the factory. So this should print some lorem ipsum here for the hat title. And it prints nothing, and it fails. Wrong number of arguments, given one, expected zero. Words doesn't take an argument.
01:25:03okay it ran but i didn't did i remove my debugging yep hard to see debugging when you delete it all right so now i have looks pretty good let's throw away that period i like the test data to look reasonably like the production data and having that period at the end would bug me because it doesn't match. No hat has a period.
...48All right. So with that said, what we want to visit
01:26:04is that and we want to see you know when i was saying that the page is going to have content on the form i was talking about the messages i should have been talking about the comment the comment looking at a story will also have a form with the hat on it so this has to be
smarter to look for say the hat css but let's go ahead and check your hypothesis again because it's back in play so here's the form and it's saying yes you can use the form so that's going to be visible
hejihyuuga morning chat, morning pushcx
Ah, and then here's the markup for a comment that includes the hat.
Morning chat.
Oh, Hedgie, you came up earlier.
I thought you were the person who spotted.
So welcome back, but I think you were the person who spotted a bug and now we've covered enough ground.
I don't remember what it was.
hejihyuuga I definitely haven't spotted any bugs
Oh, I think you were the person who spotted that sometimes in Vim, I was opening terminals, and then in those terminals, I was opening a nested Vim, and that was why a bunch of my shortcuts were breaking.
You definitely haven't spotted bugs.
Oh.
I suppose not, or you would be a VIP.
Hmm.
I don't remember who spotted it.
Can't give credit.
So...
We want to say that we expect it has span with the class hat.
And I think I can just use a selector like that.
01:28:11Don't need to print all that. Don't need to have all that debugging. Let's put that away for a moment and see what I'm doing.
...25So this expected, no, it's just searching for text. It's not searching for the, so now I'm trying to remember the RSpec. What is it? RSpec what's the RSpec have content that takes a CSS selector expect page dot selector.
01:29:00So there's has content or has CSS. Yes. So this is what I want to have CSS. So I expect this to be green. It is editing a hat onto a comment. That's the functionality that's broken. So that's correct.
...36So with that working, this is the specific use case I saw fail. So this one needs for the hat to already exist. And for the user to have posted a comment with the hat, so we're going to just say, We have the hat set to the hat and then the user set to the user. Yeah, I would like that in the other order. And then if we visit the story page, we see the hat.
01:30:28So that's the setup. And now let's click on edit. We're gonna edit that comment.
...46I have the option here of, oh, I should see the form. I would rather just say that I have the form. So let's see what that looks like before I write the expectation. I just want to say that I have expected to find the half, but there were no matches. Why didn't creating a comment, I didn't put it on the story. It can't just be a free floating. So the factories there, if they don't have their associated objects, like the comments, they go ahead and create their own. So that was creating a new story implicitly. So when I look at the page, I've got the same exception. Why am I looking at the new story form?
01:31:49I think it clicked the wrong edit link.
...56So let's move that up. So there's an edit link for the stories, but I didn't realize this is shared test data. So I didn't realize the story form might have been shared or the story ownership might have been shared with the comment. Yeah, so it's clicking this story edit link instead of the comment edit link. And so if I go back in this test data, the story was created by this user. And now with this shared data, I don't know if it matters for any of these specs. It shouldn't. I don't know why it's there. Let's see if the whole suite is green without it.
01:32:55I get more than one failing, I'll put it back and I'll make my own story. No, it was fine. That was just, should never have been there.
01:33:10All right. So now if it clicks on edit, did it see the comment form? Saw the comment editor. And it didn't want to click on edit because it didn't see it. That's confused.
...43Let me run that again narrow down because I'm I'm puzzled by this.
...59I should have a page, it should have the edit link, and then I should at least be able to click the edit link. So yes, I have the comment edit link, but then no, unable to find a link or button, edit. Copybara? Hmm. Copybara doesn't want to find this edit link.
01:34:34I mean, I still have that copy bar cheat sheet open. When I said click on, I can say the link text. And that is exactly the link text. Click on is the generic. Button is for buttons. Link is for link. But I know it's a link. What if I change it to say click link?
01:35:05Here, let's turn off all that debugging. Why did I still run that with less? Come here. This is a limitation of only streaming at 1080p. On my actual desktop, I would just run this side by side in the Vim. Unable to find link edit. Well, that's not helpful, Copybara. What if I said that I expect the page to have CSS.commentEditor?
01:36:05This is an interesting puzzle. I don't know why copy bar is not finding it. It's going to be something really so it can find the comment editor, but it can't click on it.
...26What if I said have content edit. How do I have the edit link, but it doesn't have text on it? It does have the text edit on it, or I wouldn't have made it to line 43 here. Can I say that of just let me click the link directly?
01:37:09So I think you can only search by text rather than by selector, but what on earth is happening in the middle here? That the page has the content, but I can't click on it. Let's think a second.
...35I'm kind of like just at the point where I'm just Googling where why this is a Rails spec. It's unlikely. A link within another link. Do I have bad markup? So that's possible. We do a lot of raw HTML munging. It is very possible that we're outputting bad markup that capybara is not accepting. So let's. All right. Let's test my vim foo here to make sure that I am actually managing my clipboard. This is one of those Linux things. Linux has like two or three clipboards, depending how you count. And when you select text, it always goes in the wrong one. That actually worked though. So bring the browser back. I pasted it. We'll just validate. All that is fine.
01:39:13So that's fine.
This is all meta stuff.
dr3ig i wouldn't trust my clipboard-foo to paste something on stream
I'm expecting something about bad nesting.
We're going to get a bunch of these spurious errors because Vim hard wraps its embedded terminals.
And so if they were in the middle of a line.
This is suspicious.
So this is still up in the story.
We want to be down in the comment.
This is the common field.
So there's the story ID.
With this obsolete, I guess I'm obsolete.
Two strikes struck.
Hmm.
Oh, I saw the... Let's find if it had anything specific about the comment section.
Come on.
Let's get through its matches.
01:40:25Trailing slash, there's no effect. That's the initial comment form. And then here's the replier. Attribute unselectable, not allowed. Document checking complete. So it's not actually mad about anything regarding the edit link. No complaints here. So if it's good markup or good enough. Still don't know why. Wouldn't trust your clipboard foo to paste something on stream. I have a whole checklist actually before the stream and one of them is like copy things and make sure that all the clipboards are blank. So I do that before every stream and then otherwise I never show stuff. I never put stuff in the clipboard that is from another terminal or page.
01:41:46So this is me being irritated at obstreperous capybara, and I'm just going to go ahead and run it.
Because the thing I'm trying to actually express is that I can then, after there is a comment, speaking around clipboards,
oskarallan hi pushcx, big fan and user of lobsters. thanks so much for working on it!!
do it again now oh man i put something weird in the clipboard i wonder if his comments i just want to edit the comment i really don't want to spend forever debugging why copybar is refusing to find a link that i know is visible that it thinks is visible
Oh, hey, Oscar Allen.
Welcome to the chat.
And you are welcome for lobsters.
And I'm glad you visit.
What am I trying to say?
Yeah.
So here at least is an edit form.
And I know it's an edit form because here's all the help text for our markdown.
And so we have a...
edit form and the edit form has the hat field that we expect and the current hat is selected so all of that is fine what I want to do is actually that's not fine I want to add the cat add a hat to the comment that doesn't have it because that's the bug I'm seeing so we are going to take and make that nil so we're explicitly saying that the comment doesn't have a hat
and then we're going to select hat hat from hat id and click on what's the name of that button is it edit is it post can't remember all the verbiage offhand not cancel non-preview
All right, it says update.
01:44:25And now five visit.
...35Well, this one is going to be to not have the hat on it, and then this one have the CSS. Man, long road to writing a request or a feature spec. Did not expect that to wrap people. And it passed. I actually didn't want it to pass because I swear the behavior I saw and a user reported was that you can't edit the hat onto a comment. But apparently you can. Or at least Copybar can.
01:45:17so let's go ahead and pull up localhost i just now i don't trust anything so let's make a new one so this is the 29 stream test one i'm not going to put a hat on it so if i post i don't see it with a hat even when i click so now if i edit i put on the hat oh man so many good ones to choose from from old test data so the immediate render shows it and the re-render does why did i get a bug report why did i get an exception even oh mystery bug non-reproducible bugs
01:46:12So off screen, I am going to pull up that exception, because exceptions come to my inbox. And the actual exception I got was someone attempting to paste, and then they saw a 500, and I got this. trilogy cannot update add or update a child row foreign key constraint fails and the constraint is that hat id is a foreign key it's a nullable foreign key and so this did a patch i wish i could see with the copybar driver when i click on update Am I actually hitting that patch controller action?
01:47:16So if I do this, patch is going to go to slash comments slash ID. And that hits comments update.
...39And that says params hat ID. Oh, is it as simple as, is it the same thing as that? Let's look back at that form source. The hat ID, no, it's just at the top level. So Rails does a clever thing with the params where it tries to build a data structure out of them. So this just becomes a top level key. And so does this. None of them are getting nested. So it's not like message.
01:48:32It's a funny truth about apps. So experienced rails coders will look at this and notice it's not using the strong grams like message was and that's literally happening because it's the God object, and it was written first and the first written things are always the jankiest and use the conventions, the least.
01:49:01So this is fine it clears the hat and it sets it from the form. so we have this funny situation where things on story and comments least follow the rails crud conventions and tooling real cobbler's children have no shoes scenario but every app is like this it's kind of universal almost makes me want to say that for apps you should Do the ancillary features like on lobsters the private messaging before you do the stories in the comments, but it doesn't make any sense to do them in that order, even if it means slightly higher code quality by the time you get to the features you care most about. I guess it just means you have to be ruthless about polishing code and refactoring.
01:50:03so i improved the factory fixed some old test data got some specs in couldn't reproduce the bug i mean that's worth committing i don't want to throw it away but i'm very puzzled because i i mean someone tried to post a comment with a hat and they got an exception and they
Or they tried to edit a comment with a hat and they got an exception.
arh68 how many ids can a hat have, like unless it's a new hat
And it was the exact same exception that I see now.
Or that you see here.
arh68 how would the fk fail i don't get it
How many IDs can a hat have unless it's a new hat?
A hat should have exactly one.
So if you were asking about the primary key, the .id field,
That's it, the short ID also exactly one.
Cannot add or update a child or a foreign key constraint fails.
Lobster comments constraint.
So if I go look at schema,
01:51:30it's saying that the comment points at the hat id and this index is mostly there for performance but it also does a foreign key constraint and since you don't see null pulse on the end of it like these up here it is okay for it to be null because indeed virtually all comments don't have hats
dr3ig do you have info on what was the hat_id updated to ?
I was very puzzled by this one.
I think I'm going to settle for adding a spec and moving on.
I can't reproduce this exception.
The one thing I didn't look at is the line number of the exception is 195.
Come on, jump back.
So I must have tweaked something here in comments controller that
Yeah, changed a line number.
Yes.
So I tweaked this and that added three lines.
So I want to be up three.
That can't be right.
What did I say?
It's got to be this save that's throwing the exception is where I'm going with this.
If 195 is failing, I'm net down to the perils of changing code before I've tracked down the bugs.
This is why we solve bugs first.
I guess I was fixing another bug.
Yeah, I don't know.
dr3ig have any hats been deleted recently ?
arh68 i don't get how it's selecting the hat, is it by id or name. the capybara select i wonrder
going to leave that as a mystery and hopefully we'll get another bug report or another exception that has more info have any has been deleted recently no we actually never delete hats from the database
They get marked as doffed, which is to say inactive.
Doff is the fancy old-time word for the act of taking off a hat.
It's nice to have those ridiculously precise verbs in English.
You don't get how it's selecting the hat.
Is it by ID or name?
The copy bar I select.
It's actually not finding the specific hat.
It's just finding, is there one on the page?
Because I don't think this is a full query selector where I could say has text.
like that, I would expect that to error.
Where's my?
01:54:37Yeah. So it's just complaining, no, I don't have a full query selector. You can't do that. And since this is test data where there's one story with one comment, If there's any hat appearing on the page, not just an edit form for it, but if there's a hat appearing, it is the one that we selected. So that part is fine.
01:55:06Mystery.
...23I never expected that when I got into programming, that there would be so much mystery of, can I even reproduce this bug?
Is this a thing?
And instead, there's all this, like, theoretically, computers are totally explainable.
In practice, they're big enough.
The state space is large enough that it's not.
Didn't expect that one.
So I had a idea for, oh yeah, let's move that down.
Maybe that's gonna get booted to a next stream, I guess.
arh68 exploring teh ambiguities of language at gigabit speeds SeriousSloth
But I had an idea for a transition here between hats and pagination.
So I talked at the end of previous stream that pagination is my,
Big white whale, I tried fixing it on stream four years ago, but between the stress of COVID and not really planning ahead on it, it didn't get done.
And I wanted to come back and pick that up as a nice feature to develop on stream.
And I realized there was a nice transition between these two where it would be great if you could click on a hat and see all the comments that use it.
And it is not super interesting for test data like this, but I saw someone use their go developer hat, by which they mean they contribute to go development, not that they use it.
And I was super curious to see if there were other comments they had left using it and I couldn't.
And I thought, well, why not add that as an endpoint of you could click on a hat and it should take you to.
A page listing all comments using that hat and that seems very straightforward, especially now that hats have a short ID that I can put in a URL.
And so.
With rails.
An eternal hassle when you have something that.
touches two models is does it want to live under comments?
We are listing comments by hat, or does it want to list under hat?
We are listing all comments for that hat, right?
So to show it, should the route be
01:58:08dr3ig @pushcx is it possible you're mixing comment.hat_id and short_id ?
Is it possible I'm mixing comment head ID and short ID?
Oh, you're still trying to reproduce the bug?
No, because there is no field.
Well, let me say it different.
...34The way it's working in update is it says on the user model, find their association wearable hats.
So that's all the ones that have their user ID on them.
And then find by short ID passing the thing that the user passed up.
And the code is consistent about doing this nice access through the rails accessor.
So if it had said
find by id that would hit the id field or if it had said comment dot hat id equals that would create the bug you're you're talking about but the way it's working through this reference to enforce the constraint that you can only use the hats that are yours and wearable is eliminating that possibility
It's a good idea, though.
And some of the cleanup, if you look at the... Where's that commit?
pushcx f2f811e1
I'll paste it over here.
You'll have to take it to GitHub or if you have a check out of the code.
But that commit, I caught a couple of those kinds of errors or updating wearable hats.
Because it's pretty obvious from...
stream, it is not a super well-tested feature.
So if I want a list of all comments made using a particular hat, should that live under slash comments or should it live under slash hats?
I guess I lean towards the former
because comments are kind of a god object and if i look at the index method which this is going to be a specialization of there's a lot going on to preload things especially in a performant way and we are going to have to basically do that an occasional request and the thing that touched off pagination is
A page that lists a user's comments, not their threads, so we have the.
The user thread sprout.
02:01:15bsandro chikaiLurks
And that lives here and comment.
Which is kind of conspicuous.
And so.
...28I talked previously about how... Oh, hey, Bessandra.
Nice to see you.
Even if you said nothing.
I wonder if that's an emoji I didn't get.
Oh, it is a black emoji named Lurk.
I see.
Very cute.
bsandro yeah it is a lurk animated emoji =)
If I add one more of these methods to the comments controller, it's getting wider and wider.
Oh, it's an animated emoji.
I have animation turned off.
I find animated things very distracting.
bsandro makes sense
And I don't want to see that in the corner of my eye all the time.
I actually have to close OBS because the volume graph bouncing up and down as I talk was super distracting.
02:02:32dr3ig @pushcx line :195 in comments controller is `comment.current_vote = votes[comment.id]`, not `comment.save`. maybe the code running in production is different though
yeah so it is not rails convention that an action on the comments controller would live under slash user it makes a functional sense and it would allow supporting a url like this
02:03:02195 in comments controller.
dr3ig according to github rn
The code running in production is not different.
I mean, the only difference is these couple of last commits that I've done here on the stream are not pushed to production.
This commit is what's live in production right now.
...36So line 195. Oh, you're saying 195 on GitHub. So looking back, it's the vote assigning. This line? That would be down three. I guess that makes some sense.
...59Yeah, voting doesn't hit that end point.
And this is a...
This isn't even data that's about to get saved.
This is happening after the save.
So it shouldn't be triggering any kind of... Hmm.
Yeah, the exception came in yesterday at 9.40 Chicago time.
And then the previous commit that I deployed is live.
Damn, that line number is wrong.
I don't believe it.
I don't understand what's happening there, but I don't believe it.
I got to let the non-reproducible bug go right now, Drake.
I can't keep switching back to it or I'm going to let my brain fall out of my head.
dr3ig sure! :)
If you spot something, can you just throw me an email, please?
I'm peter at pushcx.
Yeah, thank you.
Or you can open an issue if you think you found it or a pull request.
Yeah, pull request is how you get to be double VIP.
Not just finding tons of bugs like ARH.
So... Do we think of browsing comments by hat or do we think of on the hat getting its comments?
And...
I guess I'm deeply ambivalent about it because if I look at... Let's change.
arh68 well am I gonna search anything else by-hat. stories ? users ? or no
I've slowly moved a bunch of these kinds of routes under slash user, like slash threads, slash stories.
But you know, everybody has user.
Well, am I going to search anything else by hat?
Stories, users, or no?
So stories do not take hats, which is not a limitation I want to change.
I can kind of see an argument for it, but they don't take hats and they're not going to anytime soon.
Hats are just on comments and just on messages.
And you can't, it doesn't make sense to search messages by hat.
02:06:52And this is not a, I guess I'm chewing on this more than I need to because it's trivial to put a redirect if I change my mind about what the right way to do this would be. So I'm gonna go ahead and just put it into the comments controller. because that's certainly where it's going to live. And I'm going to put it on a URL under slash comments and then not think about it for a minute. And maybe percolating in the back, we'll get somewhere.
02:07:34arh68 sounds about right
Yeah.
So let's go ahead and say if you
have a get hat slash.
It's not this style.
It's this style.
That goes to buy hat.
Let's look at that route real quick.
Let's fix that typo real quick.
It's not a member.
It's on the collection.
So I think I just put it after member.
I'm trying to make the routes lean more on the Rails crud.
So now where's hat?
Here we go.
Comments.
And again, it put it on the member.
Do I have to say standard?
Standard did not indent it for me.
02:08:59Comments hat.
Good.
That's the URL I want to see.
I mean, Rails wants me to have slash hats because Rails loves pluralization and URL.
And I guess I will behave and obey the convention because I used up my breaking conventions hat, my breaking conventions punch card yesterday off stream.
I've been working on a Ruby gem and...
it generates files that would live in an application.
And I just, I named the directory check because I couldn't bring myself to name it checks plural.
I just can't stand that Rails convention.
I think I understand what happened with Rails, but I think it got it wrong of having pluralization in some places.
So like the class
is hat singular, but then the route is hats plural.
The table is hats plural.
And then there was that whole fight over are we just going to infinitely grow the inflector?
Actually, do folks know that one, the Rails inflector?
That was a fun one.
Rails has a class for turning singular into plural, and I think vice versa.
arh68 oh is that called the inflector
And people kept adding special cases to it, like goose to geese.
arh68 i've known about that octopi thing lol
I mean, who doesn't have a goose model in their business app?
And I think the one that, if I remember this trivia correctly, I think the one that finally broke them was octopus.
I think they had a fight over should octopus be pluralized as yeah, ARH is here, you're ahead of me.
Is it octopi, the pseudo-Latin?
Is it octopuses, which it would be the English?
Is it octopodes, which it is a Greek root, so that's how Greek pluralizes, although those almost never make it into English unscathed.
And
after fighting over it for a while.
Let's go find it.
Now I want to see it.
It must be in Rails, right?
arh68 i feel some like indices/indexes are 50/50 it's a hard call
Nope.
Oh, yeah.
Nesting.
All right, let's make a new terminal for that.
JLo.
02:11:47yeah all right let's just go poke around in my gems directory ah it's an active support now this is Related to i18n.
02:12:30Let's hit this.
...36Yeah, here's the one.
Oh, I guess they decided it's octopi.
I didn't remember.
I thought they just went, this is ridiculous.
We're going to stop playing pluralization police.
And they just froze the list of plurals and said, we're not doing it anymore.
We're done.
Whatever Rails pluralizes right now is what it's going to pluralize forever and vice versa.
Lay to lays.
Oh, I could see that being a fun one.
Yeah.
arh68 and that's just the english ! Kappa
I wouldn't want to maintain that either, but I think they should have fallen back and said, you know what?
Pluralization of classes and table names and URLs was just a mistake.
Let's punt.
Oh, just the English.
Yeah, that's true.
Other languages are a little less aggressive about loan words than English where English just steals words and vocabulary constantly.
02:13:46So I want to grab this. Oh, ho. So speaking of things that are not visible off stream, the cat has entered the room. Hey, buddy. Hey, buddy. Can I bribe you? You want to show up on stream? Yeah. So I have one right there. We give him little bites of his favorite dry kibble. And that's his treat. And now the other one. Are you watching, sir? oh you hear it oh it's up on camera find your mark sir lean into the light after he showed up on stream the other day we were joking about getting a because he's a black cat he's hard to see we were joking about getting a a tripod so i could put the didn't you hear it Daniel Katz- Getting a tripod so that he could be well lit with a ring light and the webcam on it, and he could be the proper professional streamer because it's not gonna be me i'm not pretty enough to be on stream, so I am going to leave this off for the moment. Daniel Katz- But I did want to go ahead and close that and look down it user threads because I noticed. Daniel Katz- See this has nicer. use of scopes like for presentation where this is reiterating this and it is a common scope so we're going to go ahead and say for presentation and not on a story that is hidden by the user with that order which is newest first This is redundant with accessible to user. And. I am going to put the thing I actually want to say on the first line, which is where. Hat is. So the bang will make fine by throw an exception so that then this route will for or if needed. hat.findby. Did I get that? Where's that route? Just wanna make sure I got that parameter named correctly in the route. Colon ID, okay. the alternation between like, is it ID? Is it hat underscore ID? Is it short underscore ID? I always have to double check what I named my route params. So that should be enough to start listing comments.
02:16:51Yeah. Yeah. So let's go find an interesting hat. And let's use real data. Yeah. What if I just find a random hat that's in the middle of the stack?
02:17:18Chicken developer. Chicken, I believe, is a scheme compiler. All right, so if we go to localhost, and then I grab this short ID, I get a route error. But I just made this route. Oh, do I have to? No, I don't have to bounce the Rails server because I made a route, right? I never remember. like my rule of thumb is things in slash config, except for routes. And that's just complicated enough. I get fuzzy on it. So let's look at, I generated slash comments slash hats. Ah, it's a pluralization. It's always pluralization.
02:18:24I might get an exception about a one plus N query here. I failed to look up the hat, I suppose. There's that line of code I mentioned. Let's just grab that separately. Yeah, see this? looked for all of that okay where's my syntax error extra parentheses i should have noticed when i had to retype that parenthesis so it did correctly load the hat
02:19:29I wonder if it is possible that this hat has never been used. Because I just grabbed a random hat. I didn't actually grab a random hat that had been used. So let's grab the console up.
...54Comments. Is it not? have an association. does not have an association back to the comments it's used on. So if I go to, not hats controller, what am I doing? Model comment. This has a belongs to hat optional true, but this does not have a as many comments. I probably have to specify that it is the inverse of, oh, let's see. So here, not a colon, a semicolon. Oh, so this says that there are nine comments. Okay. So I'm going to go ahead and add messages here just because it should be there and it's not present and then comment where
02:21:32I mean, I wrote the association for a reason, right?
...44Still a 404. All right. Do we have a clever before action doing something? So this only runs on these. This only required on upvote. Rails, why are you doing this to me? Why are you giving me a 404? So we're going to comments controller line 300. Yeah, that's what we were just touching. And it does look up the hat. And then, so that's a big sigh moment because I realized what it's doing and why it's failing. And it's a thing that I spend a little time mad at Rails about. Rails, and what I didn't recognize, I'm on localhost, and you've seen a couple of times that nice development error page that Rails gives. But it didn't show up here. That should have been my clue. But I'm so used to seeing this in production that it just didn't even register that I wasn't seeing the development debug page. Rails is, I suspect, misdesigned on how it handles MIME types on routes. So if we have a route, and the one everyone complains about, is recent. So we have a slash recent route. And that shows you recently submitted stories that have not reached the homepage. And something that is conspicuously missing from this is it does not support RSS. And this is kind of ideological. RSS feeds are structured content that is in some kind of stable order and recent stories are not stable and it just doesn't seem right to submit an rss feed to have an rss feed that is constantly reordered and then on top of it the point of recents is it is recent stories that have not hit the home page and so then If you are following the RSS feed and refreshing it occasionally, you absolutely will see items in it that have been promoted to the homepage, but your feed reader saw them in a previous fetch and is continuing to present them to you. And then I'm going to get bug reports of, oh, the recent feed is showing me things that are on the homepage. Well, yes, because they weren't when you saw them. So it can never be right. so recent doesn't have an rss feed which means when people are looking at this url they often say oh i'm looking at slash recent and i am enjoying all the stories there's nothing here because it's dev data but i'm enjoying it wouldn't it be great if i just typed rss on the end of the url 404 is the correct answer to that because it is not supported rails however handles mime types oddly and it says you know what wouldn't it be great if we didn't enforce mime types here in the routes so you have to specify that a route supports particular mime type what if we did it over in the action And in this respond to block so after we've done all of the code after we've spent all of this time doing queries, then we will decide if we support the format. that's that just doesn't make sense to me, and then the second thing is if we don't support the format here rails throws an exception and says oh there's a missing template you forgot to have a. format.xml. You forgot to have a format.csv. Like I can invent, what is it, ODX? What's the, like I can invent an infinite number of MIME types. This is not a 500. This is not an exception that we don't support this format. It is a deliberate choice, but Rails throws a 500 for it. And so there's my rant. we have to catch that let's put this page back to what it was and the way we do that is where is it it's somewhere in config right
02:27:07There is a config setting. I am not remembering the name off the top of my head. Oh, it is this. It's right here on the screen that says, okay, if there is an unhandled exception, you can sort of mount a secondary Rails app just for handling exceptions. And in our case, we just deliberately mount our current app and then This is where we handle 404s. And so this is the route you're seeing here instead of the Rails development 404. But if I don't do this, my inbox fills up with 500s from people guessing at formatted URLs. And they're either guessing, shouldn't this have RSS? Shouldn't this have JSON? And Rails is like, well, obviously, every route should support every MIME type. Let's throw 500s in production about it. I'm so frustrated by it. There was a bug that was open for years on lobsters about this. Let's find it. So if anybody's curious, it is definitely not open anymore. It is closed. Yeah. This one. So there's me debugging this. This is the short version of that rant I just gave. And then the long version is, here's someone guessing at a JSON URL. This has been so many bugs on the site over the years.
02:28:57And then this is my very long explanation of how I'm...
pushcx https://github.com/lobsters/lob…
have tried to fix this over the years and have gotten really frustrated at Rails about it.
So I'll grab this one.
This is it.
I'm hitting a stopping point on this rant.
I will throw it in the scratch so that it's available for people who are reading, seeing this later.
And I keep saying, like, misdesigned question mark, because I'm not even sure it's not...
clear from the docs like maybe there is something I am doing wrong but I've tinkered with this so many times over the years and still like slash index people will say dot JSON on it and it doesn't support JSON in the routes but then it'll come here and it'll blow up so we rescue that so that's why I was seeing a 404 here is
The specific exception that Rails throws is called missing template.
And in this case, I didn't explicitly render, not action.
I didn't render a specific template.
And so it inferred that I wanted to render a template named by hat.
And then it threw an exception because that template doesn't exist because we didn't create it and I didn't explicitly render one.
And that ought to do it.
So if I look here, do I actually see it specifically complaining about by hat?
Yeah, the place that that missing template exception is getting cached or caught is not
logging it in a way that's going to show up here.
When you have to bite your framework on these sorts of things, it never stops.
So I want to render here.
I know where that is.
This rescue, which also has its own complicated thing.
So if I comment this out, now I should see a missing template?
Yes.
So it is missing template slash index.
That's because we want to say that we are rendering the comments index, I suppose.
Will that do it?
Does that make you happy, Rails?
Unknown column stories ID and where clause.
How did I lose the join to?
stories i guess i explicitly deleted it but i would have thought it was handled by that good and then it wants a page because i'm rendering a template with pages see here's where that transition from hats to pagination is these things are coupled okay so here is every time the chicken developer hat comment the hat has been used on comments
Man, a little struggle, a little side rant about Rails.
02:32:41There we go. So let's go ahead and do that. And I'm gonna say,
...56I will put this back.
dr3ig is there a way to pick a hat by default with every comment?
I don't love having to explicitly joins story, but that's probably why that one thing threw an exception.
So let's just get it in there for now and keep moving.
Is there a way to pick a hat by default with every comment?
No, every time you see a comment form, you have to pick your hat.
So if I go look at recent comments, there's gonna be a lot of test data here.
I don't know why you're suddenly dragging.
So if I were to click reply on this, I get the comment box and then there's the dropdown, but there's no way to say that a hat is on by default.
That's a deliberate choice.
If someone is here because they want to be in the Community and talk about stuff and occasionally talk about the project that they contribute to or speak on behalf of that's great that's wonderful I would love for that person to be able to use a hat, so that they can.
Just immediately have the credibility that they are associated with the project and set that context.
But setting a default implies that they are only here to talk about their project and that kind of shades into self promotion and people who do.
What do they call that marketing dev rel rather than I guess it's not cool to call it spamming so they call it dev rel and.
I don't want to make convenience features for behavior I don't want to encourage.
So no.
02:34:42So let's find a hat that has been used more times than this one. So this page is showing all comments used for this hat, but the particular hat that I just yoinked out of the database has only been used nine times.
02:35:01And I am sure there's a clever way to do this through the Rails API, but I'm just gonna write
...23Oh, yeah.
...42Let's just find which comments that have been, which hats that have been used the most.
so before i hit enter on this i am going to guess that the top hat is me using the sysop hat that just feels really plausible and if it's not me it is probably going to be somebody with a rust hat because rust comes up all the time it'll be some compiler hey okay so it's me and then it's rust and then it's a previous sysop yeah that's
That feels pretty much like what I would expect.
So let's go ahead and find, let's grab one of these that's not 300 and is not going to be like all spicy comments of me intervening in fights.
Pardon BSD.
arh68 so there are 3 sysop hats ?
Oh, actually, I'm going to grab the oil shell one because he prompted the creation of the hat editing feature when he renamed oil shell to, I think, just oils.
are three sysop hats yeah there are multiple the hat that all moderators use is labeled sysop rather than admin verse mod and sysop is a callback to the old bbs days there are a couple of these where you know the site was made by somebody older so we said
02:37:18from users join at song this is everyone who has had a hat named screwed up that join oh no it's this is lorem ipsum test data because here i've made a whole bunch of Patrick Baur, fake data, so if we go up to the top, these will be the real ones, this is everyone that has had a hat named sys up on the site, so this is everyone who has been a moderator or is a moderator has been an admin is an admin. Patrick Baur, The for anybody curious the current list is.
02:38:14It's linked from the About page.
pushcx https://lobste.rs/moderators
Ah.
dr3ig is sysop the hat with most users?
There is a URL slash moderators that lists all current moderators of the site.
arh68 moderators dot rss Kappa
Not seen on other more popular sites like Hacker News.
Is SysOp the hat with the most users?
Oh, probably.
We should ask.
Moderators.rss.
That's over here.
That's the moderation log.
So let's answer that question that Drake just had.
Actually, this is kind of a fun list in and of itself.
So I'm just going to yoink that over to the scratch.
02:39:13So you have a slightly different question, which is I guess the hat description that is duplicated the most. So if I said hat comma count star from hat, you know what? Duplicated the most. It's probably going to be like OpenBSD developer. We've had a bunch of those on the site. From hats group by hat.
...50oh, this 87 is wrong. It's all this test data that has been automatically generated. We know that the correct number for this would be what? 1, 2, 3, 4, 5, 6, 7. So yeah, it is OpenBSD developer. There have been 21 OpenBSD developer hats. And then Debian and FreeBSD tie with SysOps for seven hats. It's kind of neat.
02:40:37So all that aside, I was going to find a... That was a fun couple of rabbit holes. I was finding a hat ID so that I could find a bunch of a page with more comments, but preferably not super spicy. And I happen to know that Andy C does not write fight-picking kind of comments.
02:41:08dr3ig oh, i thought hat were unique and multiple users could wear the same hat
So yeah, these are pretty chill.
But if you notice the scroll bar, since he has used the hat 116 times, hats were unique and multiple users can wear.
No, it's not normalized in that fashion.
If we
...29arh68 so is searching by-hat like by-personal-hat ?
hat is an instance for a particular individual there really isn't any benefit to I mean it's arguable actually if someone expects that they can click the title of a hat and see like everyone who has used the any open BSD developer hat
arh68 ya or by-hat-name it's surprising idk
Yeah, I can kind of see the argument for that feature.
Boy, how did I blow up that?
Oh, it's not comments hats.
I was trying to load this page.
However, there are a bunch of these, like Arch Linux Fellow, Arch Linux Security, that are very, very similar.
And so, especially on this page where they're...
sorted alphabetically that kind of pop out of, are you a chromium developer or a chromium engineer?
And it makes even less sense that you don't see these comments together.
I don't want to start having a concept of a project and having to track that per project, which is almost the only way that sort of browsing makes sense.
Let's just do it on an individual hat.
So you're finding all the times Andy C has used this hat or push the X has used this hat.
All right.
So zooming out a little, Andy C has left some comments.
02:43:22Isn't that a great transition to pagination?
There it is.
That's my big transition that I was planning.
Speaking of pagination, when you look at the actual pagination code, it's repetitive.
All these actions know how to do pagination themselves.
And we do basic limit offset pagination where we are passing to SQL that we want how many per page, and then we know our offset.
And the problem with doing this sort of pagination is if you are, if the user requests a page that is say 300 pages deep into the stories,
And at this point, we have 100,000, 108,000-ish stories in the production database.
And so you divide that by stories per page, 25.
And so someone can go 300-odd pages deep.
Well, the database has to sort every story we've gotten, which is cheap.
arh68 i'm gettin quick
300 is not a lot for a database.
arh68 -select deja vu
But when you multiply it by all the tables we just joined against oh okay now you're starting to get up there and.
comments go even higher.
you're getting quick select deja vu, why are you still chasing that awful bug.
The.
02:45:11arh68 no the limit/offset procedure just feels like quickselect
arh68 it's similar to quicksort
limit offset pagination really breaks down when you have millions of records or tens of millions the limit offset procedure feels like quick select i don't know quick select do you mean quick sort because presumably the database does something like that all under the covers but having to yeah having to sort the entire table to figure out what's halfway down
is expensive.
arh68 finds the Kth sorted element, w/o sorting whole thing
Because even if you don't access any of the stories or any of the comments on page zero to 299, the database has to know they're there to serve you page 300.
And on the previous stream, I talked about what we want to do is
cursor-based pagination which is how reddit does it and so if i click next you'll notice it doesn't have a page number here and then up here it says after and this is their version of a story short id there are gems that do this for rails
They're kind of huge.
And I understand why they're huge.
There is actually a surprising amount of complexity to pagination, especially when you are metaprogramming to say we're supporting it on every kind of odd model or odd join that someone could throw at Active Record.
It is more complexity than I want to take on.
I don't want to use a giant API.
I just want to code pagination here into the site.
And there is a lot of opportunity for tidying up stuff like these extra page routes, because these things just become get params.
But we have every place that you can paginate stuff, we have a second route for it.
I don't love that.
It would be nice for those to go away.
02:47:41And I think doing comments by hat is a really nice place for us to test this out. It'll be a new page. There will be no pagination whatsoever. And we will figure out how to add pagination in the new way and then port it to these existing ones. And I think that's going to be about as clean as we can get. The one hassle is we're sharing this template with comments, or I suppose I should say the slash comments route. That's the RSS. And if you look at it there's. A whole bunch of pagination code in here. I will probably end up wrapping that in some kind of if or you know if at page yeah actually let me just go ahead and do that now, we will say. Because I don't want to blow up the. thing here in Dev I want to be able to work progressively. And then, otherwise. we will do new pagination. And then after I have refactored all of this code, we'll go ahead and get rid of that. However, I am not going to do that directly on master because Definitely learned last time that this is bigger than it feels. And I mean, you know, if I'm going to refactor, you saw how many paginated routes there are in the config routes a minute ago. If there's a dozen of those, that'll just take a while to churn through. And either I don't want to do it on stream because it becomes really repetitive, or even if I do, that's just not great, you know, thrill a minute. So what I am saying is I'm going to work on a branch.
02:49:50There's like 5050 I hit enter on this and it complains that I have a five year old branch named pagination.
Yeah.
How old is it?
Yeah, it's five years old is where I started a branch named pagination.
And so there's some of this is like rebased stuff.
But then a bunch of this is I started pagination.
And then I tried the pagi gem.
And yeah, it just it didn't work out.
So we are going to go ahead and call this
I don't know.
Is there a cute name we want?
Do we want repagination?
That is an English verb.
dr3ig next-pagination
We call it hatination because we're adding hats.
Let's call it repaginate.
Next pagination.
Oh, this is going to be a stream for getting rants out of Peter.
I refuse to name anything next.
oskarallan trogdor-the-paginator
And
I think I learned this from Star Trek.
They called their show Next Generation, and it was like, what are you going to call after that?
Trogdor the Paginator.
That is a good reference.
Speaking of old memes, I think I'll just call it Repaginate.
But when you call stuff like Next, I once visited a client who was like, we are going to make V2 of the site.
And then I spelunked their Git history, and they were on...
jameslittle230 V2 is a state of mind
think it was their fifth v2 the client had a lot of turnover and so every year and a half somebody started a v2 and some of those shipped i think most of them shipped and then the team turned over and then the team was like oh we're going to start a v2 and they didn't know that they had done it that the project had done it and it's even worse when they call it
dr3ig if anything deserves the "next-" prefix surely it's the pagination branch
jameslittle230 βnexterβ
oskarallan next, nexter, nextest
arh68 didn't NT stand for New Tech or did i make that up
next because it's atemporal and what are you going to call the one that comes after next because there is always a next next and so do you call it like next next like you're a graphic designer who doesn't use version control do you call it final do you call it next final yeah drake if it if anything deserves the next prefix surely it's pagination nexter nexus
Oh, I scrolling in Chicago.
One of the best streets in Chicago.
Actually, I think it has its own Wikipedia page, right?
There is a surface street named whacker.
Yeah, whacker drive.
Okay, Wikipedia.
And at the surface level, it's called upper whacker.
And then also, come on, Wikipedia, show me a good picture.
It is stacked.
So then there is Lower Wacker.
And if you saw the film Dark Knight that was shot in Chicago, this is where the Joker chases the Batmobile and shoots it with his bazooka.
And you may notice, hey, there's some more windows over here.
There is a third level that is, of course, called Lowest Wackest to me.
It has a proper name, but I think it goes Wacker, Lower Wacker, Lowest Wackest.
I forget what the proper name is, because I've called it Lowest Wackest for so long.
Yeah, they say Lower Wacker is the south end, but the west end, the southwest end of it, there is a third level.
And one of the things that makes it really fun, yeah, so you can see the three levels.
is if you get your car towed by the city there is an impound lot around half a mile down the river around here on the bottom level that a lot of people don't even know exists and up until 2005 was really dimly lit and grungy and not attractive if you walk down there you kind of had that like i'm about to get stabbed vibe
And so, if you had your car towed by the city and they would park it in their hidden lot underneath the city on lowest wackest it's an experience that.
I think every Chicago and has the experience.
Also arh I think you're right, I am pretty sure the nt and windows nt stood for new technology, I would have to ask wikipedia but i'm going to say you're right.
So we have made a branch and I have.
Named it paginate, which is potentially confusing with pagination, but I will probably just delete that branch off stream because it is five years old.
Yeah, let's say post stream.
02:55:21I want to look at it before I delete, but that almost certainly wants to just get tossed. All right. So I'm going to check in the basic hat stuff of the route that belongs to, or I should say that has many, not this pagination stuff here. Well, I guess that's fine. I guess it's fine to have the transitional pagination stuff in here in the branch.
02:56:25Tempting. Tempting to be a smartass and commit messages.
...34And there is a GitHub issue.
What is it, 394?
Yeah.
That has ended up being the catch-all for this pagination rebuild.
And so I'm going to name check it in the commit.
Did I switch to my branch?
Yes.
OK. Do I have the git history I expect?
I have master.
I paginate.
Yeah.
Let's go ahead and push this stuff up to master.
Repaginate.
I don't know that I need.
Well.
Why not push this to GitHub?
Yeah.
I'm not going to pull request it probably, but at least anybody who wants to browse it can go ahead and look.
So I'm not going to see it here because I'm not logged in.
pushcx https://github.com/lobsters/lob…
I can just go here and find this here.
And I want to grab this.
In case anybody wants to follow along at home, we'll have it there in the chat and we'll have it here in this.
Oh, I called it if I had any comments.
All right.
So there's all the setup.
vinitkme Hello, Which font is this?
OK, so I am going to click on OBS for a second and edit this text.
Oh, does somebody have that fact handy?
There are two fonts here.
02:58:45This is Inconsolata and Operator Sans Mono for the cursive. I am allowed to mix fonts. I'm a professional.
02:59:01vinitkme Inconsolata-g?
But in the meantime, here we go.
OBS transition.
I'm going to run to the restroom.
I'll be back in a minute.
And then we will jump into, I don't know what inconsolata-g is.
I'm using the old school inconsolata.
So if you can find a link for the dash g, I'm curious.
But I'll be back in a second.
03:01:09vinitkme https://github.com/powerline/fo…
vinitkme https://leonardo-m.livejournal.…
arh68 oh does it just have that different `g` ?
arh68 like the double-loop vs single-
arh68 i'm guessing -dz is dashedzero but -g idk
Okay, hello again.
Someone made a version of inconsolata that just has a different G. I have to see this.
arh68 no i'm speculating
That's a level of nitpickiness that I have to respect where someone says, you know, this font is perfect, but for that one letter.
...39Oh. OK, this page has way too much. Oh, it's live journal. Yeah, live journal has been just demolished. They've had a rough decade.
03:02:01arh68 ok lots of small changes
Oh, so they had a couple of different nitpicks about.
Apostrophes, other punctuations.
vinitkme It's actually quite nice
Hmm.
Yeah, lots of small changes.
vinitkme I used it for many years
I wonder why they chose the letter G. I don't see a G in their name.
...33All right.
I haven't been bothered by these kinds of details, but I'll have to give it another look at some point.
I had a funny moment.
Let's see, this must have been 2000... How was it?
So there's...
vinitkme How do you configure two fonts to work together?
I've been using this font for ages.
I don't even remember where I first saw it, but I've just liked it for a long time.
arh68 inconsolata fairly classic. like andale mono next lol
And years ago, I attended Recurse Center, which is this neat self-study program for programmers, sort of like a writer's retreat.
You go, you spend six or 12 weeks trying to learn something new or otherwise stretch yourself.
The really nice part is that you will be around about 30 other people who also were so curious about learning more about something in programming that they thought it would be good to take a break from whatever else they were doing and go to New York City for it.
And so it is a whole very self-motivated, very kind community.
So it was 2017, fall of 2017, that I went there.
And while I was there, that's when I became the admin of Lobsters, actually.
So the tour forever linked in my heart.
I had the free time because I had already taken the time off to go to see, to attend Recurse Center.
And then while I was there, I met Rafe Levine, who is the guy who created Inconsolata.
And so I think we were just chatting and I pulled up some code to show him.
And he was like, oh, hey, I know that font you're using.
I made it.
So it was a very fun moment.
He got a kick out of seeing it in the wild.
And I hadn't made the connection that he was the person that made it until he was looking over my shoulder at it.
If I want to tie it back to, as James called out, don't be weird around people.
That was a non-weird way to realize I recognize someone who's a little bit famous in computing.
Rafe has done, especially in the years since, just a ton of interesting graphics work.
And a bunch of that has been related to...
I'm going to mess up his resume.
It's...
vinitkme Fuschia
performance stuff in i believe flutter and what is that not replacement for android so google runs android and then it has another operating system it made for mobile and they swear it's not going to replace android and it hasn't so far but some of the ideas fuchsia yes vinik me you are correct it is
vinitkme People like him are special. Some people get so much done in a single lifetime
fuchsia that i'm thinking of so he's done a bunch of neat stuff on that and his blog is just excellent especially if you like graphics performance stuff so let's look at pagination so what we want to say here is i would like for comments to have a
03:06:17Oh, and you know, yeah. So you say people like him are special that get so much done in a single lifetime. That is so yes and no. Like there are people who do just a tremendous amount of stuff, but I don't think there's anything magical about them. A lot of it is, you know, having the luck of circumstances to be able to rearrange your life and then just setting your priorities differently. Like I said, the magical thing about Recurse Center is it's self-selected for people who think it would be great to just spend six or 12 weeks studying more about programming. And you think about who's going to show up for that. If that's you, you are going to find some kindred spirits.
03:07:04So I think I don't usually do this kind of outside-in thing, but what I would like is this. I would like to say after that. And I would like to just go ahead and express the ordering here, but I really, I can say that. I can say it can be a second parameter. See this, this is the very small API I would like to have. And I think I can get there with rail scopes. The more positive version of what I'm saying about being special is not to be Mr. Rogers, but you are.
Recording
34dr3ig re-paginate indeed
yesterday i was doing some unusual stuff and really pushing the graphics design graphics drivers repaginate indeed yeah well i got to watch fisk run for a minute that's always a little concerning having seen fisk fail before but not since honestly ext3 i think since then the recovery has been very good so
Let's figure out the state of things.
All right.
Well, that's there.
01:17Sorry about that.
arh68 audio choppy lemme f5
So I had seen some when I was tinkering around last night.
pushcx not you
I suspended the desktop, and I brought it back.
dr3ig your audio is choppy
And after I did, I saw some audio show me.
This is.
All right.
I bet audio is good now.
shurizzle All good
dr3ig yep, good
arh68 SeemsGood
How about yes or no?
...58All good.
Yeah.
So this is.
This is the
yeah calm i have a whole checklist for streaming of like put your phone on do not disturb switch to the stream layout set up all of this stuff and so i just kind of hopped back on rather than run through the checklist and if you remember all of the ridiculous fun one of them was
leave volume control open or audio gets choppy and since i was hustling back i didn't go through the whole pre-flight checklist i am not exactly nasa over here that was the missing step thank you for calling out that audio was choppy oh hello again sure as well haven't seen you for a minute so that's where we were so having chopped the viewership in half
shurizzle I was lurking, hello everybody
Let's start by hat.
So I don't know exactly where I cut out.
Did you all see that?
I wrote this code of what I would really like to do is say none of this at page, none of this, like having to have a routing error in here.
I don't want to, I definitely don't want to be doing arithmetic.
I just want to say, let's have the cursor and let's look up anything that comes after the cursor.
And I don't usually do this kind of outside in, let me write the interface I want.
Get rid of that too.
But we're going to try it here.
Let's see how this goes.
03:57So I have comments. Yeah. And I got here and I was scrolling. Oh, I didn't finish the end of that story. Yeah, yesterday I suspended the desktop and I brought it back and I noticed some visual tearing on an app or two that is hardware accelerated. And I thought, well, that's weird. But I didn't take that next step of, you know, I should probably just bounce the system to get it in a clean, known good state before the stream tomorrow. I just put it to sleep again and I didn't think about it. And that is my only guess, is building up weird, complicated state. Yeah. All right. So I want to have a scope called after. And this is eventually going to become a concern or a module or something. But I definitely don't want to start there. I want to start with the simpler. Let's just do this here. After is going to take a cursor and an order. This is overloading a little, but the concept of after is so tied to sorting that I want to include it here. And in Active Record Scopes, I can just call any, I mean, I can write any Ruby, but it is normal to call various things. So we're going to go ahead and say, we're going to just pass the order on. And then you're going to say, almost makes sense in the other order.
05:59I don't even have... I lost that Firefox I was using. And not just lost, it doesn't even have it as a... Man, the machine crashed hard. Oh, no, okay. So Firefox continues to be excellent. As much as I griped about the ads the other day. And it brought back the window. So what I want to say is at some point after about 25 of these comments per page, I want to draw a line mentally and say, OK, let's make a next link that's going to be after. And so I'm thinking of how to express this. if i was indexing by the id i would be saying where id is greater than i mean but what i really want to say is in the i want to make this cursor the short id
07:28arh68 older comments have .. smaller ids? or bigger
And since this is tied to order, I guess what I want to say is older comments have smaller ideas or bigger, smaller because ID is the auto incrementing primary key.
...45dr3ig do you plan to have a default "cursor" column for each paginated model?
So I think maybe what I have to say is.
Find that comment.
do i plan to have a default cursor column for each paginated model no it's pretty much always going to be the short id because that is the the two underscore param in the rails convention it is the the thing that shows up in urls so this is the hats short id and also every comment if you look at the
link down at the bottom of firefox there you see that c underscore that pdp sof is the comments short id so i want the cursor to be that comment short id so let's say before i add this
08:47Let's really go outside in so I can leave this alone because. Now it is at least valid syntax. Let's go over to comments index.
09:07And what I want to do is link to.
...22And I think if I don't specify anything, I can just pass params directly. And so I can say after is like that.
...41And over here, I do want to say limit comments per page. I left that out for rhetorical effect when loading this browser. But oh, boy, since I crashed the whole computer, Probably restart ranks. Come on. Close these out.
10:13So now there are 25 comments on the page. and a next page link that says, good, it's exactly what I want to. It's the current URL, but we're adding this after. And you see it says after pvk. And then up here, this comment is comment pvk jfx. So that part is correct. If I click it I will probably just get the same 25 comments because i'm not actually doing anything with that parameter and the next page link down here just says pvk that's okay.
11:01So if somebody gives me an after i'm going to write the. simpler version of the code and then kind of migrated into that scope, I think.
...18Let's see if I can just find the comment.
...35And if you give a cursor that doesn't exist, I'm fine with just throwing a 404 because something odd is happening there.
...51And if I look up this, that's a very fast primary key lookup.
arh68 Comemnt ..
And then I guess as soon as I have that, I don't so much want to pass in this.
I type a thank you for catching that.
I will pass in the cursor comment itself.
12:25funny i can physically see that my typo rate has increased because i'm nervous having crashed the stream i'm just a little embarrassed it's kind of funny how that works it'll get out of my system in a couple of minutes but until then i can tell i'm jumpy you know the nerves annoying
...55so there and then the scope this is taking a cursor and i guess this after so now order is tied to it so i'm going to just
arh68 I still wonder "id > ?" vs "id < ?"
support the one use case that you are ordering newest to oldest and then i'm going to add back that complexity later all right so now i get rid of that order i think i can i think it's safe to say whenever you were paginating that you want to do pagination although i think this is a
13:53eric give me a second i think this is a constant on the controller rather than a constant on the yeah i'm gonna go ahead and it's 20 and not 25 huh i'm gonna go ahead and just duplicate that here on comment because it feels like that's the sort of thing that should go ahead and move in
14:24It's funny to see max depth. So this is the maximum depth that you are allowed to reply right now on the site. And in practice, all deep reply chains have gone off topic or turned into flame wars. There was one of those yesterday or the day before. Yeah, if you go that deep, something odd is happening. So let's go ahead and say... So that's enough to get things working now. And I can come back and, well, let's just go ahead and do it now. Yeah.
15:12Oh, was that the only instance of it? No, it's comments, plural.
...30And you just go away. And then what is this? Oh, upvoted comments. So now we're seeing the duplication of, yeah, I don't actually want to touch 40 different references right now. Let's back up to just unify that now. And I will come back and to do that.
16:09Because the other thing is, maybe I don't even have to do that because I wanna delete all that pagination code. If I can just delete it, I don't have to update it. Let's go back on down to by hat where we were working. So, Eric, you asked about, is it ID greater than or ID less than? We are going newest first. So you're right. It's ID less than because IDs will decrease as we descend. Yes. Good catch.
17:00I'm going to put those two things next to each other, even if they're usually in the other order. So let's just start there. Does that load? Do I have any typos? So this is complaining that over here, I still had the order. Even if I fix that symbol for a variable, let's go ahead and update that call site. Better. column id is ambiguous so this is happening because i am saying we're ordering by the id but also joining over to story which has its own id column or i'm sorry it's failing because of this one yeah so i want to say comments id i don't remember if there's a nice rails syntax for expressing where as opposed to having to put it in a string because if i'm doing it as like colon id rails knows when merges get complicated and joins get complicated and you eager load occasionally a table will get aliased or nested in a funny way, and if you have a spring rails won't look inside that string to realize Oh, I renamed comments to T nine. that's one of the reasons I changed this order to use the hash syntax because it does maintain it there, but if I have the string ID desk I would get the same error basically so.
18:54Is there a nice syntax for this?
Yeah, that's what I don't want.
And I don't want the string.
On the other hand, this is also 15 years old.
Rails 2.7.
arh68 LUL `state of the art` mmmmk
The begin list range.
Does that?
I got to see that work.
state-of-the-art for Rails 4.
And it tells you how long I've been doing Rails that I didn't notice this new feature in Rails 4.
I don't remember when Rails 4 came out, but it wasn't last week.
So let's say, let's see, how many comments do I have again?
half a million.
So let's say we go like half of that range.
20:08OK, hey, there's a syntax for it.
And so is this working the direction I expect?
Because I just picked half.
So if I say throw away the first 100.
OK, so I'm finding everything up to that ID versus everything after that ID.
OK, I can live with that.
dr3ig not including is 3 dots
so here i will say where id is and we are saying up to but not including our cursor you know i'm going to leave that commented out just because i mean it's new syntax what if it doesn't want to work for me
21:13Not including is three dots.
Well, I guess that's what I want to say is up to but not including the cursor comment.
I named it after.
One of the rabbit holes I went down four years ago was should the cursor be the last comment or should it be like the comment after the one that would have appeared on the page?
vinitkme Your voice is pretty calming. Love these kind of programming streams.
And in the time since I've thought about it and also, I guess, paid more attention to Reddit and realized
It has to be the short ID of the final comment presented, so we're not over-selecting.
And then you say after, so we're doing a greater than versus a greater than or equal.
I'm glad to hear my voice is calming.
vinitkme ahaha.
You must not have tuned in when I was ranting about how Rails handles MIME types or how Twitch handles privacy.
22:19vinitkme Rants are for passionate people.
So that actually looks like it worked.
That can't have worked, right?
So the thing I'm puzzled by is the three years ago, Andy must have left a comment more recently than that.
...50Although it is possible that we are on the second page, aren't we?
Yeah.
OK, maybe that's fine.
vinitkme Could I please get an invite to Lobste.rs if possible/
vinitkme ?
All right.
And it's the same whichever syntax I use.
So that's fine.
pushcx https://lobste.rs/chat
The best way to get an invite if you don't already know somebody on the site is drop by
The chat room, not the Twitch chat.
And if you have a, social profile, like your GitHub repo or your GitHub profile, that's probably the easiest way to say hello and get trusted.
Right.
So we have this.
23:51vinitkme Okay, makes sense. Thanks
trust this code now this is correct this is just saying after cursor comment wow pagination got a heck of a lot shorter that previous attempt there was so much code there was so much going on so at this point what i really want to say is shove all this down into the model i want to say
24:27And cursor comment can be nil.
So I'll say if there is a cursor comment.
This is not a cursor comment now.
Now that we're just back down to it being a cursor.
nanerbag I clicked because your editor looks nice but i have to say, you have a really pleasant voice and microphone.
So we will say if cursor.
...49What's the biggest duplication? Let me do the big duplication.
25:11nanerbag Just looked a few messages above and it seems im not alone
Oh, hi Nannerbag.
Nannerbag?
Is it banana or is it like you're putting grandmas in a bag?
I don't know.
It's like Polish versus Polish where the pronunciation changes based on whether the P is capital or not.
As for microphone, I wondered when someone would ask.
It is a not very fancy ATR2100.
which was the pick that people were like, well, at least it's not a webcam mic.
So we will say that.
...51Yeah. And so then having made the duplication and then simplified it, let's say, what would I call this? Let's call it query. We'll say. We'll start with the thing we know that we order and we limit by page. And if there is a cursor, we will find by that otherwise there's nothing. And we always return. Yeah. So that becomes this. I'm kind of mechanically working this refactor because Otherwise, I goof things up. Let's just leave that like that for a second and see that it wants to work. Yes, we're still on page two. I can see I'm going to because the special case here is page one at this point. Does that work? Yes. All right. So let's go page one, page two. I can close that tab because it worked out. Thank you. random stack overflow person. Let's grab that one for the scratch file. That's kind of fun.
27:29State of the art.
...40So let's drop that because it's redundant. And both of these are still good, yes? So speaking of working outside in, I also don't tend to work with test-driven development. I find it couples me to a particular implementation before I know I want the implementation. And I kind of have to see the code, and so I like to write as you saw, I like to in line right the simplest possible version and then one little step at a time okay well, let me shove the order in there and then oh. I don't need the order at all, because i'm only going to support one way at first, let me move this along, let me tidy let me tidy so.
28:38So if I have this which is fine for now i'm leaving this split because I suspect i'm going to come back and touch it in a minute.
...55Maybe I should have picked somebody who writes shorter comments typically a lot of scrolling.
So the after is correct.
And then down here, there's a new after, which is this one.
nanerbag Isnt the point of TTD precisely that you define the specifications and public interface first?
Yes.
So that part is good.
dr3ig plus the api will surely change before you land onsomething you like
That can't be all I need for pagination, right?
Surely I have to struggle some more.
I struggled ages ago.
nanerbag Which is a constraint indeed, but its not a bad one.
But there's something nice about putting problems on the back burner and letting your hindbrain sleep on them.
And I guess four or five years is plenty of time.
Isn't the point of TDD precisely that you define the specifications in the public interface first?
I suppose so.
dr3ig reddit has a `before` param as well when you go `next` and `prev`
And this might be a Peter is old thing where the API will change before you land on something you like.
But I'm very comfortable with the lowest level representation.
And what I'm running in my head when I write stuff like this is I am thinking of the implementation.
I type this, but in my head, I am hearing the SQL query that it's getting built up.
30:25So Drake points out that Reddit has a before param as well when you go next and preview. Yeah, I was just writing next. The issue with prev is if I landed on page two, I suppose I could say previous to the current one. I see how that would work. Do I want to support it? It's a good question.
31:20I'm going to think about this for a minute.
I.
We currently have, you know, paginate previous and paginate next links on all of these.
but I'm so early in the implementation and I feel like there's other missing complexity that I don't wanna add that option as a feature just yet.
And I can't totally articulate why.
It is some vibe-based programming.
One of the reasons I like doing this stream and I like pair programming with folks is when I have to explain stuff,
especially to a junior developer, I have found a lot of the times over the years, there are many ways to design something or many features to support.
And if you asked me why I want the class to work like this, my answer is, I don't know, it just feels right.
And the first couple of times I pair programmed, I gave answers like that of, you know, you just design it on, we didn't say vibes back then, back in the,
nanerbag The teacher always learns more than the student
late 1700s we just said you know we didn't even say hashtag mood what did we say i think i just called it a gut feel and what i came to realize is that was experience that i had never made explicit teacher learns more than the student yeah quite often
Because what I realized was my intuition was guided by experience and the experience I had had was which of these designs is going to be more bug hunting in the future.
But I had never stopped to articulate rules for it or guidelines or rules of thumb.
And that's okay.
It's okay to start based on intuition.
But then you have to interrogate that intuition and get to rules.
And so that is how I have gotten to rules like prefer immutable objects, try to encapsulate state, avoid temporal coupling, avoid side effects, all of these kinds of things.
I actually gave a talk at RailsConf, what was it, 2015?
Let's just look at the link.
Yeah, RailsConf 2015 about MVC.
Ooh, teeny video.
And the very short version, the spoiler version of this talk was learning to control mutability and side effects.
And that definitely came out of pair programming with people when I realized how to articulate what I was doing different in the design from them.
which is a long tangent for saying, yeah, I probably want to support previous links and have this become like a .paginate that passes up params before and a params app.
It's something, I don't know what that API is going to look like.
I have to see more of that.
I have to clean up this, but it'll get to the point where that works.
yeah and i guess as i'm saying that i've come around and i've convinced myself that i do want to continue to have the previous page links yeah so one thing this doesn't have is a knowledge of a last page
So I'm going to go ahead and you also can't seek pages anymore, but that's a feature, not a bug at this point.
So I'm going to jump down through all of these oil shell comments to find the last page, because what's going to happen here is I'm going to run off the end of the array.
I'm still going to get a next page and then I get a 404.
So what happened here is, I bet there aren't 20 comments on this page.
Let's count.
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 16.
So this just links to next page regardless.
36:21do i want how do i detect that i am kind of okay with printing a next page i am not okay with when you try and find it there are no comments so this wants to have like a
...52You know I want to handle that so now, if I click this next page link. I still get a new method or why is comments not empty. For an instance of. Oh, this is it's not a. It might just be as simple as yeah the did you mean is there. okay so this is the exception i wanted and in development mode i get a hey you had an uncaught exception in production this would just be a 404 page that's not a great user interface to say next and then link you to a page that doesn't exist and the tempting thing is like
37:47if comments count as less than 20, well, then we know we don't need to link to the next page. But as you can guess by the fact that I didn't even put the ERB syntax around it, that's not gonna work because there might be a final page with an even multiple of 20 comments on it.
38:10See, now the complexity is sneaking back in.
...24gtfrvz I do query for N+1 "things" and display only N and use the last one to display next page link or not
I almost want to say, so if we have comments, I do query for n plus one things and display only n and use the last to display the next page link or not.
Hello again.
And that is one approach.
I can have the query over select.
And then only display per page items.
In which case.
This loop has to.
Get smarter.
gtfrvz or check for size == N+1
And it has to get significantly smarter where it's.
Well, not a lot.
Actually, this would become
What is this.
39:29yeah check for sizes and plus one. And i'm going to have to. I think that's right. I'm trying to remember if there is an N plus one error. One of the things about pagination is it's full of N plus one errors in a way most things aren't. And, you know, as a programmer, I will be making n plus 1 errors until the day after I die. So I have to check this stuff in terminal.
40:11jameslittle230 HA the day after I die
jameslittle230 that made me laugh to my empty room
So if I want two items, yeah.
And again, I want three dots, not two.
...26I'm glad you got a laugh out of it, James. I cannot claim to have written that joke, but the first time I heard it, I also cracked right up. So I am very glad to share it. So this could loop there. And then this would want to say if
41:04that's okay that's not a heck of a lot of complexity because the other thing i was reaching for here is i think the other thing was way more complex it's funny i was thinking i might end at this over selecting and ignoring but
dr3ig but you need to care aboout @comments.last.short_id
A nice thing about live coding here is that GTFRVZ popped up and said, what about this?
And I realized that that suggestion was small enough.
I could just put it up on the screen and look at it, but I need to care about comments last short ID.
dr3ig it's not last anymore
Yup.
That becomes comments.last2, I think.
I know on the other stream,
This might be an active support thing.
When I was pairing with by root, I saw.
He knew.
So you can say first, you can say first two.
Can I say last two?
Yeah, but then.
That's hideous.
So I just say like minus two.
I mean, that's less bad.
Let's make sure that's... See, need more unique elements.
Is there a...
It would feel very Rails-y to have... No.
I'm honestly surprised that Rails doesn't have something, an active support.
42:59it's got to have a next to last idiom, right?
There was a whole joke where Rails added like dot second and then Rails added dot third.
Like you could tell, like, well, anytime there's an end, programmers are like, why isn't there an, you know,
dr3ig i think there is fortysecond
dr3ig or something
What if we added more and this became a minor flame war and I think I think it goes up to 10 and then what's the can I make a. yeah so.
gtfrvz second_to_last
yep you're skipping ahead on the jokes, people are well informed.
43:56yeah they put in a. Oh, is there a second-to-last? What an East Coast way of phrasing that. No, it is next-to-last, not second-to-last. God, regional dialects.
44:20And so they just capped it as, I want to say .10, and then added 42 to be silly. No, there's no 10th. Oh, no ninth?
...36I misremembered the gag.
All right, so they had fifth, and then I guess fifth is where they were like, all right, this is, we can see the progression.
By induction over the integers, we can see that we have a problem.
Second to last, who says that?
You know who says that?
The kind of people who say that, they say they wait online instead of waiting in line.
Anybody from the New York metro area?
It is a very New Yorkism to wait online.
I picked it up and I said it once and everybody in the Midwest went, no, you can't say that.
jameslittle230 I say second to last but I wait in line
It's America online, not wait online.
jameslittle230 Close, Boston MA
arh68 i've never noticed these idioms
okay you say second to last but wait in line james are you from new zealand are you one of those strange anglosphere speakers i say strange but the kiwis are pretty great boston massachusetts yep pegged the east coaster
You've never noticed these idioms?
Oh, you are one of today's lucky 10,000.
What is that?
46:10arh68 the word "penultimate" comes to mind lol
There is a wonderful quiz online.
Yeah, so the New York Times did it.
gj1118 But english is indeed a funny language.. consider the plight of non english users when they are trying to learn english :D
This is probably paywalled now.
Is this...
This is all upsells.
Yeah.
It's paywalled.
And it's probably not going to work if I pull up the archive is.
So I'm not instantly finding the links.
gtfrvz in german wie say "vorletzte (/r/s)"
You'll have to poke around a little online.
Hitherandthither.com.
Yeah, this is the one I'm thinking of.
So this is the New York Times map where you could answer a bunch of questions like, do you wait online or in line?
And do you say soda or do you say pop or do you say Coke?
gtfrvz "pre-last"
And then it would try to figure out where you are.
And I remember I confused it because I had a lot of Chicago regionalisms like
Do you wear sneakers?
Do you wear tennis shoes?
No.
In Chicago, you wear gym shoes.
They're always called gym shoes.
And that is hyper regional.
I think it's Chicago and just about nobody else says gym shoes.
And we used to say soda.
When I was a kid, we said soda, but it's slowly changing to pop.
And it had mostly pegged me, but I have a few New Yorkisms because some of my family is from Jersey City.
gtfrvz do you say steamed hams?
nanerbag archive.org?
gj1118 I was once told that "prepone" was not a word.. Pray tell me , what is the opposite of postpone is all I could muster , respectfully
it's such a shame that they lock this behind the paywall i mean i understand why they do it but god they put like connections archive.org nainerbag that would work for viewing the article but i really wanted to see the interactive quiz because it makes these maps
and guesses personally where you are.
And they're kind of pretty, like you can see this is very nice graphic design, but it's very deliberate about like regionally these similarities.
And it's just, it was super interesting.
It was great.
It was viral content back in the day.
Anyway, English has regional variations.
It is not, and it's kind of funny because the English,
the american english regional variations are almost all vocabulary at this point you know tenant shoes versus sneakers as opposed to accents like if you are paying attention you can tell i sound like a midwesterner but i don't have you know the chicago accent i don't talk about these guys over there i'm going to sit in my front room with my two tree buddies that's that's a joke you know i'm putting that on i know what the chicago accent sounds like but it's not
My native accent, that bears.
Where other places that developed accents before mass media have a lot more regional accents.
Anyways, language is beautiful.
Prepone is not a word.
What is the opposite of postpone?
Yeah, I don't know prepone.
I've never heard that one before.
And oh, to catch up to your earlier questions, no, I do not say steamed hams.
I'm not principal Skinner, but the kids are wrong.
That is very true.
The older I get.
shurizzle anteponed?
So anyways, to finish a thought I started like a half an hour ago, I was going to say
If there aren't comments, we could say if comments dot after, and then set a, but that is so much worse than what I actually came up with.
So first off, it is a second query back to the database.
And since it's a second query, it has to have all of this stuff again, because otherwise well as discussed scopes could do anything.
gj1118 it is indeed a word.. :)
And then there's this magic variable coupling the two.
gj1118 prepone that is
And as long as i'm going to couple to the implementation of pagination I am going to go ahead and.
Just go ahead and use exactly what GTFRVZ said.
That is a totally clear way of putting it.
51:19I think I might wrap it up in a helper method. As I'm writing this code, it's clear what I'm doing.
...33Me doing. Don't tell me I can't open that file.
...45Let's make a pagination helper.
dr3ig i think you still have to update `.limit`, no?
Definitely going to need it.
Oh, there's already something here.
dr3ig with +1
yeah this this Max pages is up here, because when you do limit offset pagination it can get expensive and so at least one or two parts of the site limit things.
Think I still have to update limit probably let's check on that in a minute, I want to grab this thing first.
I want to say.
This page.
I want to say.
hasNextPage.
And these are both going to take a collection.
So here, come here.
We're just going to say hasNextPage.
So then this becomes, see, I would kind of like to make collection the object, but
I am not quite willing to monkey patch.
relation and then the active record results that would be a little much I know.
I joked in the channel description on twitch that the most obscene thing I would put on stream as a monkey patch, but I am going to be approved and not even write it now yeah.
So we are coupled to comment and let's just.
To do that one.
And then here is also going to get up.
All right.
53:44Yeah, this is getting a little. See, there isn't a. Specific rails object for. a collection i mean there is but it's two different objects of it's an active record relation before and then it's a result set after there's no concept for an object that generically accumulates people just have primitive obsession go right to array hash
54:33vinitkme Just got invited by ngoldbaum Such a nice community. Thanks for the tip to contact the support there.
It's nicer.
I like that.
I am helped by those helpers.
...44Oh, and Goldbaum. He is a longtime, very active user. I don't know if you're here in the stream at the moment, and Goldbaum, but thanks for taking a look at been inviting. I do not have the IRC chat open. The first stream or two where I had both the Twitch chat and the IRC chat, it was just a little too much. Already programming while talking feels like juggling. There's the actual code I'm writing. There's the running dialogue. That's the second ball. Then there's glancing at the Twitch chat. And I guess I can just barely juggle three balls, but I cannot juggle four. The alternative, if I could get a Twitch API key and horrifically unified them as a Frankensteinian monster, wouldn't that be nice?
55:46There we go. So that's fine. And then, yes, Drake, as usual, is right about their bug fixes. I do have to say to over select in the after. All right, can I load these pages? Let's take a look. So here is the first page. And we get an exception, wrong number of arguments because I just said wrong. 1080p.
56:38All right, so that's correct. And we do have a next page link that points to the next page. And then page two is correct. And page last should not have a link. Ooh, that is nice. Yeah, I like that a bunch. All right, that's totally reasonable. We can keep working with that.
57:12Oh, speaking of distracting things I can't pay attention to, Twitch put a big notification dot on my channel dashboard.
Achievement completed like clockwork?
What the heck does that even mean?
Never heard of that one.
Oh.
Oh, man.
I have to pull this on stream.
This is actually pretty cute.
dr3ig following your schedule ?
On a previous stream, I mentioned that these things can get out of sync.
So path to affiliate that I showed at the beginning of the stream still says I have streamed six out of seven days in the last month.
However, like clockwork says, I have streamed seven unique days in the last month.
And I got this one, but I didn't get the one up top.
That's
it's funny like i realize it is waiting for some like once a day this recalculates but i always get a kick out of seeing let's screenshot that guy it feels like a very front-end app thing where two parts of the page disagree on very basic facts like six verse seven
Now the the schedule is decoupled from everything, there is no I mean maybe there's an achievement for making a schedule, but you don't get anything for having scheduled stuff all of their.
All of their metrics and achievements and everything have to be written for what if somebody games, the heck out of this.
59:02gtfrvz there is also a disconnect in twitch where it says your sub has run out but you cannot (yet) resubscribe via prime and you'll get ads
What's the right exception here?
dr3ig i thought "like clockwork" would commend you for having and following a schedule (kind of silly of me)
There's a disconnect on Twitch where it says your sub has run out, but you can't resubscribe via Prime and you'll get ads.
Oh, that's irritating.
I wonder if that's like on a cron job where one... Oh, you thought like Clockwork would commend you for having and following a schedule.
Oh, that would be a smart achievement.
I don't know that they have an achievement like that, but it feels... You know what?
That feels gameable.
so if i just wanted to get the achievement i would create a schedule that i am going to stream one minute from now and then three minutes from now and then four minutes from now and i would just turn the schedule on and off you know turn the stream on and off and then or you'd have to spread it across days like at some point rules lawyering that out takes 200 words and you just punt
The thing they want to encourage is that I stream lots of days.
So that's what the achievement is.
I know I checked this in the controller, but it's going to happen somewhere along the way.
And if I do that, then I feel better about saying there's a what's the Ruby idiom for
Switching on the class can say case collection dot first when comment.
I think I can triple equals that.
01:00:44All right. Let's test that one. Class A. Class B.
01:01:15okay yeah it works exactly like i remembered it's i do it so infrequently because usually you want to invert this and shove it down and i don't quite feel confident enough to make it a class interface i mean i know the other one is going to be when story right and if this scope moves off into a module then it becomes very natural to say
...56yeah let's let's keep it simpler we can get closer to that later yeah let's leave myself a little reminder to fill that in at some point and if you think this is funny you should see the the time bomb test did i ever resolve that Okay, yeah, it got fixed. I never remember this. I'll have to dig through Git history. But at one point I wrote a test that just said, like, if the date is after June 1st of next year, fail the test to remind me to come back to something. I remember somebody caught it going by and was like, you can't do that in a test. And my answer was, yes, I could. I absolutely could and did. It's the best way to remember something in six months is put it in the code, and then someone has to look at it when the test fails and the build fails. I don't know that I would quite do it in a large team. But here, YOLO. All right. So this feels pretty good, actually. This is good alright so let's let's review this because i've touched a lot of code, we have the new pagination helper. We moved comments per page yes. And then the hats method got this after method has a raise. think that's all good. model comment got this why don't I see the constant oh it's below yeah all right so I add the constant and the scope I'm going to do a little whip commit because I'm on a branch and I want a checkpoint like I've pushed around enough code in a half a dozen places
01:04:29OK.
So let's see, where is my clock?
So we're coming about four hours, which is pretty long.
And there is the part of me that wants to just have an eight hour straight stream and check out all of pagination.
But then there is the reasonable adult part of me that wants to bring the stream to a close.
And I think that's going to win out
And I'm going to try and keep these to streams.
You know, I said two or three hours and I keep running three or four, which I'm okay with, but boy, as tempting as it is, I don't want to have an eight hour stream.
So I am going to especially thank the folks who stuck around after the crash.
Let's hope that doesn't become a recurring stream feature in the way the choppy audio does.
And if anybody has any last questions about the site or context or the code base, I will be happy to take them.
But otherwise, I am going to bring the stream to a close because I've been talking for four hours straight.
My neck is stiff.
dr3ig i have this urge to introduce a pagination wrapper object that delegates `each` to the query object (aka the page collection); and it would also encapsulate the `after` scope logic. what's your thoughts about that?
And I don't see any.
I think my stream delay is only a couple of seconds at this point.
So I'm going to wind it down.
Yeah, thank you all for coming.
Oh, you have the urge to have a pagination wrapper object that delegates each to the query.
My thoughts on that are it's a very good idea.
I think that is where I talked about wanting to write.
I think that's where that wants to go.
But I have to see this imperative version of it first.
And if I don't see it, it's just too much metaprogramming for me all at once, especially with the distraction of the running dialog of a screen.
dr3ig it has to work for multiple models first for sure
I think that's probably, yeah, let's write that down.
01:07:00dr3ig and then you can begin to abstract
That would be getting better grammar.
And I also probably, as part of this,
...42yeah i like i literally want to sleep on it like when i see some of these design issues but i have a pretty high confidence that's the direction it wants to go and i probably want to do it in this order and then the question was whether Oh, yeah, this question that wants to get answered first so that there is more code visible for this other stuff. But that feels like it's trending in a very nice, reasonably direction.
01:08:35That was the other part of it. The instant fires for per page. And has next page that would pick up that method from the collection. Yeah, that's really, that's really pretty attractive, but I said I was not going to stream for eight hours straight and just hack it all out. So there's that. And I will, yeah, I don't need, that's not real code.
01:09:17how did i write that message rough first draft that's fine i will go ahead and push that up to github in case anybody really wants to go look at this repaginate branch i would appreciate it especially those of you who are and i'm specifically looking at gtfr vz and drake please do not jump ahead and pr the actual code i'd like to keep working it out on stream
gtfrvz Don't worry, im no ruby dev
but I think you two are basically right about the direction this wants to go and what this interface is gonna end up looking like.
Don't worry, you're not a Ruby dev.
I mean, wouldn't you like to have
gtfrvz b2wGG
no semicolons and methods like second to last ah come on let your hair down you know all right well thanks everybody for hanging out and listening to me give a couple of mildly spicy rants we're gonna wind up here oh man everybody's got
gtfrvz b2wBit
pushcx bye π¦
cooler emotes than i do i don't even know anything about the emotes on twitch so i can't like pick one to sign up with it doesn't have a lobster does it no i can't use from the regular what if i grab come here can i just grab it from the about page and paste it in chat to say goodbye with yes i can
arh68 HahaGingercat laters
Alright, take care folks thanks for streaming have a good one, I will oh that's important, I will not see you Monday September 1 I will be offline at forest on a trip with some friends.
But don't go posting nasty stuff on lobsters because I will actually have a cell phone and the other moderators will still be watching.
So the next stream will be one week from today, 9 a.m. Chicago time, and I will pull up, let's put it on the list, because otherwise I forget which schedule.
01:11:40I sort of suspect I have to delete all the Monday events, and I can't just one-off delete, but I'll find out in a few minutes after I've stretched and all that good stuff.
So I look forward to seeing you all again next Thursday.
dr3ig bye!
Take care out there.
Bye.