{"id":438,"date":"2021-08-17T21:34:25","date_gmt":"2021-08-18T04:34:25","guid":{"rendered":"https:\/\/icanthascheezburger.com\/wordpress\/?p=438"},"modified":"2021-08-17T21:34:25","modified_gmt":"2021-08-18T04:34:25","slug":"leaky-abstractions-when-ifttt-triggers-arent-what-they-seem","status":"publish","type":"post","link":"https:\/\/icanthascheezburger.com\/wordpress\/2021\/08\/leaky-abstractions-when-ifttt-triggers-arent-what-they-seem\/","title":{"rendered":"Leaky Abstractions: When IFTTT Triggers Aren&#8217;t What They Seem"},"content":{"rendered":"<p><img loading=\"lazy\" decoding=\"async\" style=\"display:block; margin-left:auto; margin-right:auto;\" src=\"https:\/\/icanthascheezburger.com\/wordpress\/wp-content\/uploads\/2021\/08\/CleanShot-2021-08-17-at-21.13.03@2x.png\" alt=\"screenshot of my IFTTT recipe titled When I like a tweet, append its URL to a file in my Dropbox\" title=\"CleanShot 2021-08-17 at 21.13.03@2x.png\" border=\"0\" width=\"599\" height=\"329\" \/><br \/>\nAs part of my ongoing initiative to always show up to internet arguments with receipts, I built a bespoke Rube Goldberg machine that can automatically download and archive tweets I like, turning them into Markdown files, complete with attached Twitter images and video downloaded.<\/p>\n<p>Once I really get all the kinks worked out I promise I&#8217;ll write about it in full, but needless to say, it&#8217;s a fun system. I&#8217;m also in the habit of meticulously putting tags on the files for every liked tweet for easier lookup later, and it&#8217;s making me realize that I like a <em>ton<\/em> of tweets (over 500 tweets just this month alone, and the month is barely half over!).<\/p>\n<p>Recently, I started getting the suspicion that some of my favorited tweets weren&#8217;t ending up in the archive at all. Eventually I caught my system in the act. I found a tweet from Andrew Cuomo that was hitting differently more recently (<a href=\"https:\/\/twitter.com\/NYGovCuomo\/status\/335434417193508864\">this one, if you&#8217;re wondering<\/a>). I liked the tweet (well, I didn&#8217;t <em>like<\/em> it, but you know what I mean). But a Markdown file of the tweet never showed up.<\/p>\n<p>As I mentioned, this whole system is a Rube Goldberg machine. A liked tweet starts its journey with an IFTTT recipe. That recipe is set up so that when I like a tweet, IFTTT takes that tweet&#8217;s URL and appends it to a text file in my Dropbox. I have a Hazel script that watches for changes to that file which will then pass the file into a Rake task that grabs the tweet URLs in that file, imports them, then deletes the file and marks the URLs as processed.<\/p>\n<p>I checked my IFTTT logs, and there&#8217;s no sign of the recipe having fired for this particular tweet.<\/p>\n<p>I contacted support, and they were baffled themselves, because they could like that tweet and there were no problems for them.<\/p>\n<p>I noticed the age of this particular tweet, and started testing this out with other older tweets. None of them worked, but relatively new tweets were fine. <\/p>\n<p>I asked IFTTT support if they had logs of any webhooks or other events coming in from Twitter. They responded that they aren&#8217;t doing anything event-based, but rather they are just polling Twitter.<\/p>\n<p>And that was my &#8220;aha&#8221; moment.<\/p>\n<p>You see, I have more Twitter likes than your average bear. I&#8217;ve been liking tweets for over a decade now, and I have accumulated tens of thousands of them.<\/p>\n<p>When IFTTT polls Twitter, they&#8217;re just sending a request to Twitter saying &#8220;Twitter, give me Aaron&#8217;s likes.&#8221; Twitter, in their infinite wisdom designing this particular API, will give IFTTT back those liked tweets in reverse chronological order. But the tweets aren&#8217;t sorted by when I liked them; they&#8217;re sorted by the tweets&#8217; own timestamps. In other words, if I have thousands of liked tweets and I like a tweet from five years ago and I ask Twitter for my most recent likes, Twitter will give me the most recently tweeted tweets that I liked, leaving the older tweet buried in the list.<\/p>\n<p>IFTTT probably never anticipated people liking as many tweets as I do, and I&#8217;m sure they never ran into this issue when they were testing this feature. For a normal user who hasn&#8217;t liked a ton of tweets, the trigger works correctly; aka it will always fire when the user likes a tweet, because the number of liked tweets is reasonable and Twitter can send the whole list back. But when they poll my list of Twitter likes, they&#8217;re just getting the ones for the most recent tweets (probably the last 100 or so). So if I like a tweet from five years ago, even though I just liked it, IFTTT&#8217;s polling will never see it because they&#8217;re not paging through the hundreds of pages of my favorites every time they poll Twitter.<\/p>\n<p>In other words, for me, this trigger is incapable of doing what it says it does, and I don&#8217;t think there&#8217;s an easy way for IFTTT to fix it because I don&#8217;t think Twitter actually offers an API that will notify IFTTT on newly liked tweets as they come in; it&#8217;s just a polling system.<\/p>\n<p>However, not all hope is lost!<\/p>\n<p>My little bespoke Ruby script doesn&#8217;t care whether I liked a tweet or not, it just takes a tweet&#8217;s URL and it dutifully downloads it. So, I built two simple solutions for myself:<\/p>\n<p>For iOS, I made a Shortcuts app shortcut that is accessible from the iOS share sheet. When I pass it a URL, it will write a file to the same Dropbox folder as my IFTTT action and the file will contain the URL of the tweet. My Hazel script takes it from there.<\/p>\n<p>For my Mac, I don&#8217;t have the Shortcuts app yet, but never fear; I built a simple Alfred workflow that runs a Ruby script that does the same thing.<\/p>\n<p>The iOS shortcut required no code but interestingly enough it was more cumbersome to put together and required more trial and error; the Ruby script was kind of a one-and-done situation. Of course, I write Ruby for my day job, so it damn well better be easy for me to do that.<\/p>\n<p>That&#8217;s all well and good from here on out, but what about all those previous old tweets I liked that are missing? Well, not to worry; one of these days I&#8217;ll download another archive of my Twitter account and run through a script to re-import what&#8217;s missing.<\/p>\n<p>IFTTT&#8217;s trigger behavior here is an example of what we call a leaky abstraction. I shouldn&#8217;t care about how it&#8217;s built; if it worked perfectly I would have been able to count on it to always do what it says: fire when I like a new tweet. But because of <em>how<\/em> it was built, it doesn&#8217;t do that, and when I saw this bad behavior, the reality leaked through.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>As part of my ongoing initiative to always show up to internet arguments with receipts, I built a bespoke Rube Goldberg machine that can automatically download and archive tweets I like, turning them into Markdown files, complete with attached Twitter images and video downloaded. Once I really get all the kinks worked out I promise [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","enabled":false}}},"categories":[],"tags":[],"class_list":["post-438","post","type-post","status-publish","format-standard","hentry"],"jetpack_publicize_connections":[],"jetpack_sharing_enabled":true,"jetpack_featured_media_url":"","_links":{"self":[{"href":"https:\/\/icanthascheezburger.com\/wordpress\/wp-json\/wp\/v2\/posts\/438","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/icanthascheezburger.com\/wordpress\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/icanthascheezburger.com\/wordpress\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/icanthascheezburger.com\/wordpress\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/icanthascheezburger.com\/wordpress\/wp-json\/wp\/v2\/comments?post=438"}],"version-history":[{"count":0,"href":"https:\/\/icanthascheezburger.com\/wordpress\/wp-json\/wp\/v2\/posts\/438\/revisions"}],"wp:attachment":[{"href":"https:\/\/icanthascheezburger.com\/wordpress\/wp-json\/wp\/v2\/media?parent=438"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/icanthascheezburger.com\/wordpress\/wp-json\/wp\/v2\/categories?post=438"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/icanthascheezburger.com\/wordpress\/wp-json\/wp\/v2\/tags?post=438"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}