Tuesday, September 23, 2025

N+1 query problem? More like 1+N query problem!

Some years back, when I first learned about the N+1 query problem, I had a little bit of difficulty wrapping my mind around it -- or at least the naming of it. Inadvertently making lots of round trips to the database is bad, sure. And the problem gets a lot worse when you have record counts in the thousands (or more) instead of just a handful, sure. But why are we calling this "N+1"?

I eventually realized that the problem is that the nomenclature is backwards, chronologically! The order of operations happening when this problem gets triggered is:

  1. The database is queried for a list of records. (1 query)
  2. For each of those records, a follow-up query is made. (N queries)

I started thinking of the problem instead as the "1+N query problem." And for me, at least, the naming immediately became much more intuitive to grasp!

 


A quick perusal of search results makes it clear that this is a pretty #unpopularopinion. Almost all of the discussion of this problem out there exclusively uses the "N+1" terminology. 

I'm going to keep saying "1+N" in conversations with peers, though. I don't mind being one man standing against the tide on this specific issue! 🌊👨‍đŸ’ģ

Thursday, July 10, 2025

TimeSnapper for Mac: Custom Directory Selection Now Available!

TimeSnapper for Mac has been updated to allow a custom directory to be selected for your captured screen images!

If you're not already familiar with TimeSnapper, it's a utility that runs in the background on your Mac or PC and saves an image of your screen(s) (or just the active application window) every few seconds. This can be highly useful when, to take a few examples: 

  • A piece of text you were composing got lost because your browser crashed, or because a web form submit failed. (Retrieve the text out of your screenshot history!) 
  • You want to search up information about a specific error message that you encountered a few minutes ago, for which you don't remember the exact wording. (Again, it'll be waiting for you in your screenshot history!) 
  • You want to remember what all you were working on the afternoon of two days ago. (Click and drag across the TimeSnapper timeline UI to pan through your screenshot history!)  

Previously, the Mac version of TimeSnapper saved your screen images to subfolders of a particular "sandboxed" directory that the TimeSnapper app was by default permitted to access. This worked, but the target folder was in a fairly deep location on the MacOS filesystem, and thus was inconvenient to access by any means other than the "View in Finder" button in TimeSnapper's Preferences window.

Now, starting in version 1.1.0, TimeSnapper for Mac has been enhanced to use security-scoped bookmarks to allow you to choose any folder on your local computer for TimeSnapper to use to save its screen images. 

To use the new feature, after updating your copy of TimeSnapper to the latest version via the Mac App Store, click on the TimeSnapper icon in your Mac's top menu bar, then select Preferences, then the Auto Cleanup tab in the Preferences window. You'll see a "Change folder..." button in that window. 

TimeSnapper Preferences window > Auto Cleanup tab 
If you aren't already using TimeSnapper, take a look at the reviews and ratings (4.8 out of 5 stars as of today!) of TimeSnapper on the Mac App Store, and treat your personal productivity to a lifetime license for a quite reasonably low price!

Tuesday, May 27, 2025

Fix: Large file upload tests in a Rails app start failing after bumping rack to 3.0.16

Problem: After bumping the Rack gem in a Rails app from 3.0.14 to 3.0.16, a couple of tests which tested an HTTP POST of a large-ish (~30 MB) PDF file to a controller started failing. Other similar tests, which did not upload a large file, continued passing.

The failure symptom was the POST returning an HTTP 400 Bad Request error. The error was returned before the request made it to any of our application code (as evidenced by none of our breakpoints being hit, or debug statements appearing in the output log).  

For our particular test, the specific error message was: Minitest::Assertion: Expected response to be a <413: payload_too_large>, but was a <400: Bad Request>

Fortunately, there were no other gem dependencies that came with the bump of Rack to 3.0.16. So we knew the problem must be caused by some change in Rack 3.0.15 or 3.0.16. 

Solution: The single item in the rack 3.0.16 release notes did turn out to be the pertinent change:

Security: CVE-2025-46727 Unbounded parameter parsing in Rack::QueryParser can lead to memory exhaustion.

As that linked advisory mentions, a new check is added in rack 3.0.16 that turns away "extremely large" application/x-www-form-urlencoded bodies. From this nist.gov page on CVE-2025-46727, links were available to the fix's specific code changes. From the first linked change, we can see that a "BYTESIZE_LIMIT" of 4194304 (a little over 4 MB) is now imposed on application/x-www-form-urlencoded request bodies. 

Per the mozilla.org page on HTTP POSTapplication/x-www-form-urlencoded is only one possible form Content-Type HTTP header value -- and not the one that is supposed to be used with binary data, such as PDF file uploads! Instead, multipart/form-data should be used.

Our original unit test code was actually not specifying any Content-Type HTTP header value in our test POST request. Changing the test's POST request to additionally send the HTTP header Content-Type: multipart/form-data fixed the problem, and got our test passing once again.

Aside: When I spent a minute during the investigation to ask ChatGPT about this problem -- a POST request failure introduced as of Rack 3.0.16, possibly due to a large request payload -- ChatGPT obligingly hallucinated up a plausible-sounding (but 100% fictional) response about Rack introducing a default limit in POST request payload size, and a corresponding plausible-sounding (but 100% fictional) response about a configuration line to be added to config/applicaiton.rb to override the supposed new behavior. 😂🙄

Friday, May 23, 2025

Yet another use case for LIFO stacks (humor)

This is like what happens while I'm working on a coding project at my job on an unfortunately-often basis. Anyone else? 😂

Sunday, January 26, 2025

The Jon Schneider Game of the Year awards: 2024

There were my favorite games that I played for the first time during 2024 (along with the platforms that I played them on)!

1. Minishoot' Adventures (Steam Deck / Windows) 

I picked up Minishoot' Adventures on Steam when looking for a twin-stick shooter game to play without knowing anything about it beforehand, and am so glad I did! This game is an exploration / combat game a little bit reminiscent of the original Legend of Zelda; except that it's a twin-stick shooter, and more of a sci-fi theme. The exploration, combat, and upgrade systems are all really nicely designed. I immediately started a second playthrough on the "Hard" difficulty after completing my "Normal" playthrough, which for me is a rarity, and indicative of a really good game. Highly recommended!

2. Slice & Dice (iPhone)

This is the best new strategy game I've played on my phone in years. (Also available on other mobile and desktop platforms.) Slice & Dice is a really tight turn-based combat-only game where your party of 5 heroes takes on a series of 20 increasingly difficult battles. There's a free demo with the first 12 fights so you can try before you buy. The base game is plenty replayable, but Slice & Dice also comes with a plethora of different game modes if you want to change things up. Stands out even further from the crowd by being seamlessly playable in both Portrait and Landscape modes!

3. dotAGE (Mac / Windows)

dotAGE is a turn-based village builder where disasters periodically befall your town -- but you are able to see them coming some time in advance! If you successfully forestall a disaster -- for example, having enough heat sources to counteract a freezing weather event -- then the event becomes a blessing instead. Features quirky humor and pixel art, both of which are right up my alley. 

4. Unicorn Overlord (Switch)

Unicorn Overlord is a very polished small-squad battlefield combat game. A bit like the Fire Emblem games, except that instead of controlling individual heroes, you're controlling several squads of 3-5 characters, with movement across the battlefield happening in pausable real-time. Individual battles play out automatically according to if-then rules that you assign to each unit in advance. A simple set of tactics for a healer hero might be "If any ally is at less than 75% HP, heal them; otherwise, attack the lowest % HP enemy with holy magic." As a programmer, I had a lot of fun setting up those rulesets and then watching them play out!

5. Star Trek Resurgence (Windows) 

Although I'm a big fan of the TNG-era Star Trek shows, I haven't played many Star Trek computer games. Resurgence, though, did come pretty close to making me feel like I was playing through a short series of TNG-era Star Trek episodes! Although some of the action/combat sequences in the game were a little rough, the interesting nature of the "command decisions" in the game more than made up for that.

6. Sea of Stars (Steam Deck / Windows)

Sea of Stars in a fun turn-based, small-party RPG that is a bit reminiscent of classics from that era like Chrono Trigger. The combat system features the heroes having small mana pools -- but mana can be restored via "normal attacks," a little like in Diablo 3. Although the story was a bit uneven in places, I enjoyed the combat, graphics, and music enough to play Sea of Stars through to completion!

7. Lil' Guardsman (Steam Deck / Windows)

It's Papers, Please, except that rather than dystopian, it's fantasy-cartoony; and the protagonist is a 12-year-old girl! Despite the silly premise, there are some serious-ish enough plot elements that I (as an adult guy gamer) found Lil' Guardsman engaging enough to play through to completion. It was also fun to pair-play a bit with my own real-life 12-year-old daughter!

8. Dragon Quest 3 HD-2D Remake (Steam Deck / Windows) 

Ask a kid, I had somehow missed out on all of the NES Dragon Quest (nÊe Dragon Warrior) games beyond the first. Nevertheless, I had a good time checking out this game for the first time, with its early implementation of a job system, and anachronisms such as individual non-combatant NPC characters hanging out by themselves deep in monster-filled dungeons. I progressed fairly deep into the game, but the combat system was a little too old-school for me with regard to the lack of interesting decision-making to be had in most combats, and I didn't quite make it through to completion.

9. Spider-Man Remastered (Windows)

I've never owned nor played a Playstation 4, but I'd heard a lot of positive buzz around the Spider-Man games, so when I finally hooked up a decent gaming PC to my family's main big screen TV, this was one of the first games I fired up. My favorite part was the amazing feeling of just web-swinging around New York City -- what a rush! As a (mostly) old-school gamer, I never quite felt like I had mastery of Spider-Man's abilities in combat, resulting in Spider-Man getting beat up by non-super-powered goons a little more than it felt reasonable than he should; perhaps at some point I'll put in the effort to come back to this game and "get good" at it.

10. Balatro (iPhone, Steam Deck)

I actually originally bounced off this game on its original release. My two main criticisms at that time were that (1) it seemed too easy (just a matter of getting some "good" jokers, after which it hardly mattered which cards you even played; and  (2) it seemed unbalanced (certain jokers just seemed terrible, e.g. increasing the score multiplier in tiny increments of 0.1). I gave Balatro another try when it came out later in the year on iOS at which time I figured out that my two criticisms were met by (1) the built-in higher difficulty levels, and (2) the jokers that had seemed terrible generally actually were quite good because they multiplied the score multiplier, rather than just adding to it. Balatro hasn't dominated my gaming time as it has for some, but it's been an occasional fun diversion!

Other games I played for the first time, and enjoyed, in 2024 (in descending order of where they would have been appended onto the top 10) included: Shogun Showdown; Ara Fell; Dungeons of Aether; Paperback Adventures; No Man’s Sky; Tangledeep.