<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
  <channel>
    <title>Software on Noetic Nought</title>
    <link>https://punchagan.muse-amuse.in/tags/software/</link>
    <description>Recent content in Software on Noetic Nought</description>
    <generator>Hugo</generator>
    <language>en-US</language>
    <copyright>© 2006-2026 CC-BY-SA-4.0</copyright>
    <lastBuildDate>Wed, 08 Mar 2023 23:35:00 +0530</lastBuildDate>
    <atom:link href="https://punchagan.muse-amuse.in/tags/software/index.xml" rel="self" type="application/rss+xml" />
    <item>
      <title>Made in 2022</title>
      <link>https://punchagan.muse-amuse.in/blog/made-in-2022/</link>
      <pubDate>Wed, 08 Mar 2023 23:35:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/made-in-2022/</guid>
      <description>&lt;p&gt;Keeping with last year&amp;rsquo;s tradition, this post comes when we are almost 1/5th&#xA;through this year.&lt;/p&gt;&#xA;&lt;h2 id=&#34;2022-projects&#34;&gt;2022 projects&lt;/h2&gt;&#xA;&lt;dl&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://github.com/punchagan/expense-tracker&#34;&gt;Expense Tracker&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;I built a personal Expense Tracker over the month of&#xA;October using SQLite and Streamlit, because I wasn&amp;rsquo;t comfortable sharing my&#xA;financial data with a 3rd party. I&amp;rsquo;ve tried to keep it simple, so it&amp;rsquo;s not a&#xA;pain to use.  But, I&amp;rsquo;ve also tried to keep it extensible, for others to try&#xA;and use.&#xA;&lt;p&gt;The last few months have been quite busy personally, and I haven&amp;rsquo;t been able&#xA;to use it as much as I would like to, but hopefully things will settle down&#xA;soon.  A couple of things that I&amp;rsquo;d like to improve:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The Sqlite file is stored locally, and the data is not synced between&#xA;different computers.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The tagging/categorization of expenses is very manual, and a little bit&#xA;more automation would be handy.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://github.com/punchagan/artful-dodger/&#34;&gt;artful-dodger&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;A Next.js project for hosting an art/photo gallery with&#xA;metadata stored in a Google Spreadsheet and images in a Google Drive (with an&#xA;optional CDN, recommended). I built this for a friend, who is experimenting&#xA;with creating &amp;ldquo;a more equitable model for curating, buying, and selling&#xA;art&amp;rdquo;. The gallery is currently in &amp;ldquo;private beta&amp;rdquo;, and I can&amp;rsquo;t link to&#xA;it. But, here&amp;rsquo;s a sample gallery &lt;a href=&#34;https://punchagan.github.io/artful-dodger/&#34;&gt;here&lt;/a&gt;, whose configuration lives &lt;a href=&#34;https://github.com/punchagan/artful-dodger/blob/main/.env.local.default&#34;&gt;here&lt;/a&gt;.&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://github.com/punchagan/ox-gist&#34;&gt;ox-gist&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;I released my first Emacs MELPA package &amp;ndash; &lt;a href=&#34;https://melpa.org/#/ox-gist&#34;&gt;ox-gist&lt;/a&gt; &amp;ndash; an Orgmode&#xA;backend to export and update sub-trees and buffers to GitHub gists.  It was a&#xA;great experience contributing to MELPA.  I wrote a blog post about it &lt;a href=&#34;https://punchagan.muse-amuse.in/blog/ox-gist/&#34;&gt;too&lt;/a&gt;.&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://github.com/punchagan/android-dotfiles/tree/main/bin&#34;&gt;Termux scripts&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;I&amp;rsquo;ve started using Termux on my Android phone and have&#xA;found the Text-to-Speech (TTS) API quite handy.  I&amp;rsquo;ve a couple of scripts on&#xA;my phone that lets me use TTS to read out contents on the clipboard or an&#xA;article from my browser.&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://github.com/india-ultimate/fantasy&#34;&gt;Fantasy League Site&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;With help from a bunch of volunteers collecting and&#xA;validating data, &lt;a href=&#34;https://github.com/Joe2k&#34;&gt;Jonny&lt;/a&gt; and I built a &lt;a href=&#34;https://fantasy.indiaultimate.org/&#34;&gt;website&lt;/a&gt; for the Fantasy League for&#xA;Indian Ultimate State Championships. There was nothing technically&#xA;challenging about the project, but it just involved a lot of data cleaning&#xA;and co-ordination between the volunteers. The data was collected using pen&#xA;and paper, instead of a digital app for collecting the stats.  This made the&#xA;data cleaning and validation significantly harder. I&amp;rsquo;d definitely push for&#xA;digital data collection if people try to do something like this again.&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://github.com/punchagan/bookmarklets&#34;&gt;Bookmarklets&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;A &lt;a href=&#34;https://punchagan.github.io/bookmarklets/&#34;&gt;web-page&lt;/a&gt; with a bunch of Bookmarklets from my browser&amp;rsquo;s&#xA;Bookmarks bar. I&amp;rsquo;ve had most of them around for a while, but putting them on&#xA;a web page makes it easy to share and find myself on other&#xA;browsers/computers.&lt;/dd&gt;&#xA;&lt;dt&gt;Music&lt;/dt&gt;&#xA;&lt;dd&gt;Unlike 2021, I&amp;rsquo;ve only been able to record a couple of songs. And&#xA;this year (2023) hasn&amp;rsquo;t been any better, so far. I hope I&amp;rsquo;ll be able to make&#xA;amends to this, soon, though.&lt;/dd&gt;&#xA;&lt;/dl&gt;&#xA;&lt;h2 id=&#34;review-of-2021-projects&#34;&gt;Review of 2021 projects&lt;/h2&gt;&#xA;&lt;dl&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://github.com/punchagan/earworm/&#34;&gt;Earworm&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;I didn&amp;rsquo;t make any updates to the package, not because it&amp;rsquo;s perfect&#xA;but because I didn&amp;rsquo;t use it much in 2022 &amp;ndash; thanks to how little I&amp;rsquo;ve been&#xA;able to record.&#xA;&lt;p&gt;While, writing this blog post I realized that workflow had a couple of&#xA;annoyances. I improved the code to fix them.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I need to move an audio file back-and-forth between my phone and my&#xA;laptop, one full round trip to add ID3 tags and cover image.  This makes&#xA;me put off uploading recorded files to the site.  Also, the new media file&#xA;needs to be named in a specific format.  I&amp;rsquo;ve added a new CLI subcommand&#xA;to automate all of this for me.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;I always need the full collection of the music files on the computer,&#xA;where I&amp;rsquo;m updating the site from. I can just &lt;code&gt;scp&lt;/code&gt; the existing site onto&#xA;my computer and merge the media directories.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://ukulele.muse-amuse.in/&#34;&gt;Ukulele Tutorials Aggregator&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;The job of manually updating the site is a&#xA;lot of work, and I haven&amp;rsquo;t had the interest to keep doing it.&lt;/dd&gt;&#xA;&lt;dt&gt;RPi Server and Phone Backup&lt;/dt&gt;&#xA;&lt;dd&gt;The physical setup was accidentally dismantled&#xA;by folks I share my physical space with, and I haven&amp;rsquo;t been able to put back&#xA;everything in place, yet.  I&amp;rsquo;m hoping I&amp;rsquo;ll be able to get back to doing this&#xA;at some point this year.&lt;/dd&gt;&#xA;&lt;/dl&gt;&#xA;&lt;h2 id=&#34;outro&#34;&gt;Outro&lt;/h2&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve already built a couple of small things in 2023, and I hope I am able to&#xA;find some interesting things to do this year.&lt;/p&gt;&#xA;&lt;p&gt;Link to the &lt;a href=&#34;https://punchagan.muse-amuse.in/blog/made-in-2021/&#34;&gt;2021&lt;/a&gt; post.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Made in 2021</title>
      <link>https://punchagan.muse-amuse.in/blog/made-in-2021/</link>
      <pubDate>Thu, 24 Feb 2022 02:23:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/made-in-2021/</guid>
      <description>&lt;p&gt;Some things I made in 2021:&lt;/p&gt;&#xA;&lt;dl&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://github.com/punchagan/earworm/&#34;&gt;Earworm&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;A static site generator to listen to audio (and video?) files in a&#xA;directory. I use it to host a couple of simple websites for music files. It&#xA;also happens to be the first package I uploaded to PyPI despite writing&#xA;Python for many years.&lt;/dd&gt;&#xA;&lt;dt&gt;&lt;a href=&#34;https://ukulele.muse-amuse.in/&#34;&gt;Ukulele Tutorials Aggregator&lt;/a&gt;&lt;/dt&gt;&#xA;&lt;dd&gt;Inspired by &lt;a href=&#34;https://ukealong.com/&#34;&gt;Ukealong.com&lt;/a&gt;, I set out to create&#xA;an aggregator for Ukulele Tutorials for Indian songs. I&amp;rsquo;ve, with help from&#xA;&lt;a href=&#34;https://twitter.com/kamalx&#34;&gt;Kamal&lt;/a&gt;, populated about 300 songs on the site. I haven&amp;rsquo;t been able to keep up&#xA;with maintaing it, after an initial bunch of work. I&amp;rsquo;ve wanted to automate&#xA;more of the workflow, but haven&amp;rsquo;t yet.&lt;/dd&gt;&#xA;&lt;dt&gt;RPi Server and Phone Backup&lt;/dt&gt;&#xA;&lt;dd&gt;I&amp;rsquo;ve started to use a Raspberry Pi to backup&#xA;data from my phone and laptop to a personal Hard disk. I&amp;rsquo;ve &lt;a href=&#34;https://github.com/punchagan/ansible-raspberry-pi&#34;&gt;ansible scripts&lt;/a&gt;&#xA;to reproduce the RPi&amp;rsquo;s setup, and some &lt;a href=&#34;https://github.com/punchagan/sync-rpi&#34;&gt;scripts to &amp;ldquo;sync&amp;rdquo;&lt;/a&gt; my phone&amp;rsquo;s data&#xA;every few hours, when it&amp;rsquo;s on the same network. There&amp;rsquo;s a lot more that I&#xA;need here, before I can ditch cloud backups of important things.&lt;/dd&gt;&#xA;&lt;dt&gt;Music&lt;/dt&gt;&#xA;&lt;dd&gt;I made covers of about 10 songs on the Ukulele, that I shared with&#xA;some friends. I&amp;rsquo;ve ways to go before I&amp;rsquo;m comfortable sharing them on the web,&#xA;publicly.&lt;/dd&gt;&#xA;&lt;/dl&gt;&#xA;&lt;p&gt;I&amp;rsquo;m glad to have had the energy, time and resources to be able to spend time&#xA;working on some fun things despite everything that 2021 had in store for&#xA;us. Let&amp;rsquo;s see what 2022 has in store!&lt;/p&gt;&#xA;&lt;p&gt;PS: This post is quite late into 2022, but it&amp;rsquo;s an excuse to post something to&#xA;a blog that&amp;rsquo;s not seen any updates since the middle of 2020.&lt;/p&gt;&#xA;&lt;p&gt;&lt;em&gt;Hat tip to Bryan Braun whose &lt;a href=&#34;https://www.bryanbraun.com/2022/01/11/made-in-2021/&#34;&gt;post&lt;/a&gt; inspired me to write this&lt;/em&gt;&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Instagram&#39;s user-friendliness</title>
      <link>https://punchagan.muse-amuse.in/blog/instagram-user-friendliness/</link>
      <pubDate>Wed, 24 Jun 2020 20:13:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/instagram-user-friendliness/</guid>
      <description>&lt;p&gt;TL; DR: I&amp;rsquo;m a video content creator on Instagram, and don&amp;rsquo;t tell me Instagram is&#xA;user friendly. Being able to preview posts before making them viewable for&#xA;everyone will go a long way, though.&lt;/p&gt;&#xA;&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve been using Instagram quite regularly from around the beginning of this&#xA;year, posting about one video a week on an average. Previously, I used it&#xA;primarily as a content consumer for about a year, before getting off it for&#xA;quite long since it started to turn into a big time-suck. In the current stint&#xA;of using Instagram as a content-creator, I&amp;rsquo;ve had quite a few frustrating user&#xA;experiences. On a platform that comes with a giant reputation of being&#xA;user-friendly, this is a surprise.&lt;/p&gt;&#xA;&lt;p&gt;A lot of my posts this year have been video content. While posting them, I ran&#xA;into a bunch of things that didn&amp;rsquo;t &amp;ldquo;just work&amp;rdquo;. For instance, in the first 3 or&#xA;4 posts of the &lt;a href=&#34;https://www.instagram.com/tiks_ultimate/channel/&#34;&gt;Humans of TIKS&lt;/a&gt; series, every post had some thing broken, leading&#xA;to a poor viewing experience.&lt;/p&gt;&#xA;&lt;p&gt;Some of my friends, though, found it surprising that I was frustrated with&#xA;Instagram. &amp;ldquo;Isn&amp;rsquo;t it very user-friendly?&amp;rdquo;, I was asked by many. I think&#xA;Instagram is just riding on their reputation from the past. The newer features,&#xA;especially around video content, aren&amp;rsquo;t exactly &amp;ldquo;user-friendly&amp;rdquo;. Instagram does&#xA;focus on giving the content consumer a nice (read: addictive) experience. But,&#xA;as a creator, there are a bunch of hoops to jump. Content creators probably put&#xA;up with it just for the reach Instagram gives.&lt;/p&gt;&#xA;&lt;p&gt;In this post, I&amp;rsquo;ve listed down everything that I see as broken. I&amp;rsquo;ve also tried&#xA;to suggest improvements to each broken feature that would make the experience&#xA;more friendly. I start with the more common problem scenarios and progress&#xA;towards the edge cases.&lt;/p&gt;&#xA;&lt;h2 id=&#34;caption-formatting-is-needlessly-hard&#34;&gt;Caption formatting is needlessly hard&lt;/h2&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve always had to fiddle with the caption of a post, after publishing it, if it&#xA;had multiple paragraphs. There&amp;rsquo;s a magic algorithm that Instagram uses to decide&#xA;if multiple line-breaks in the text actually mean separate paragraphs or not.&lt;/p&gt;&#xA;&lt;p&gt;After some trial and error, I&amp;rsquo;ve figured out a few things about it. For&#xA;instance, leaving a trailing space at the end of a paragraph causes paragraphs&#xA;to be joined together. But, when the second &amp;ldquo;paragraph&amp;rdquo; starts with a non-text&#xA;character, it doesn&amp;rsquo;t seem to matter what the previous paragraph ends with, they&#xA;always are joined together as a single one.&lt;/p&gt;&#xA;&lt;p&gt;I don&amp;rsquo;t want to find out these details by trial and error. Adding previews for&#xA;captions would make this so much nicer. Some documentation for the &amp;ldquo;magic&amp;rdquo; would&#xA;probably help too. Instagram could even look at WhatsApp, its messaging cousin,&#xA;for some lessons on how to make writing text easier. Switching to a more common&#xA;markup language would be a nice bonus.&lt;/p&gt;&#xA;&lt;h2 id=&#34;albums-are-restrictive&#34;&gt;Albums are restrictive&lt;/h2&gt;&#xA;&lt;p&gt;Posting multiple images in a single post (an album) is a pain. All images are&#xA;&lt;a href=&#34;https://help.instagram.com/269314186824048&#34;&gt;cropped to the same orientation&lt;/a&gt; &amp;ndash; square, portrait or landscape.&lt;/p&gt;&#xA;&lt;p&gt;Until a few years ago, Instagram required every image to be square. If you want&#xA;to keep things dead simple for your users, the square image restriction is as&#xA;simple as it can get. At least it&amp;rsquo;s easy to understand and remember, even though&#xA;I can&amp;rsquo;t post my pictures exactly the way I want.&lt;/p&gt;&#xA;&lt;p&gt;The current same orientation restriction is worse on both fronts. I&amp;rsquo;m still left&#xA;with not being able to post my pictures exactly the way I want. But, also the&#xA;restriction is not easy to infer from the UI. I had to fiddle with the UI and my&#xA;pictures for a while, to understand that there&amp;rsquo;s no way around this, and that&#xA;Instagram is actually enforcing this restriction.&lt;/p&gt;&#xA;&lt;p&gt;I don&amp;rsquo;t want to be thinking about Instagram&amp;rsquo;s restrictions while clicking my&#xA;pictures. I want to take the best pictures I can, and upload them with the best&#xA;possible orientation/crop.&lt;/p&gt;&#xA;&lt;p&gt;Instagram may have these restrictions in place to ensure the best possible&#xA;&amp;ldquo;viewing&amp;rdquo; experience. But, for the creators the user-friendly thing to do here&#xA;would be to remove these restrictions. I think, even going back to the universal&#xA;square image restriction would feel more user-friendly!&lt;/p&gt;&#xA;&lt;h2 id=&#34;public-profiles-really&#34;&gt;Public profiles, really?&lt;/h2&gt;&#xA;&lt;p&gt;I think, a public profile should be viewable by anybody without having to login,&#xA;or having to use a specific kind of device. But, Instagram&amp;rsquo;s idea of &amp;ldquo;public&amp;rdquo;&#xA;profiles is quite different.&lt;/p&gt;&#xA;&lt;p&gt;If you are not logged into Instagram, and are viewing a public profile, you are&#xA;prompted to login after scrolling down through a few posts on the profile. If&#xA;you are on a desktop browser, you can&amp;rsquo;t open up any post from a public profile.&#xA;You are prompted to login, when you try to view a post. Even on a mobile&#xA;browser, you are prompted to login after opening 3 or 4 posts. Opening direct&#xA;links (or opening posts in a new tab) works, though.&lt;/p&gt;&#xA;&lt;p&gt;Instagram obviously wants to grow as much as it can, and it doesn&amp;rsquo;t really care&#xA;about people not on the platform. As a content creator, though, I care about my&#xA;audience, irrespective of whether they have an Instagram account or not. A user&#xA;friendly platform would keep their users&amp;rsquo; interests ahead of their growth goals&#xA;and not do such shady stuff. Or at least, tell us the truth and stop calling it&#xA;&amp;ldquo;public&amp;rdquo; profiles.&lt;/p&gt;&#xA;&lt;h2 id=&#34;so-many-video-types&#34;&gt;So many video types!&lt;/h2&gt;&#xA;&lt;p&gt;When I want to post a video on Instagram, I&amp;rsquo;ve to first decide what kind of a&#xA;&amp;ldquo;post&amp;rdquo; to make. If I want to post a &amp;ldquo;short&amp;rdquo; video, it can go into a normal&#xA;post/album if it is under a minute. If not, I&amp;rsquo;ll either need to split it up into&#xA;smaller segments, or post it as an IGTV video. Stories can only be 15 seconds&#xA;long, or they get chopped into multiple shorter stories.&lt;/p&gt;&#xA;&lt;p&gt;IGTV supports longer videos &amp;ndash; from 1 minute up to 60 minutes long. The videos&#xA;need to be portrait videos with an aspect ratio of 4:5 or smaller, 9:16 is&#xA;recommended, while normal posts prefer square (1:1) videos.&lt;/p&gt;&#xA;&lt;p&gt;Just like with pictures, I don&amp;rsquo;t want to care about Instagram&amp;rsquo;s restrictions&#xA;when capturing a video. I want to shoot my video, and let Instagram do what is&#xA;required to share that video. I find it strange that there are hundreds of blog&#xA;posts documenting how to upload an already recorded video to IGTV.&lt;/p&gt;&#xA;&lt;p&gt;A user-friendly platform would let users upload the videos as they shot them,&#xA;and prompt about adding some padding, or allowing users to crop and select a&#xA;part of the video, to match the aspect ratio requirements.&lt;/p&gt;&#xA;&lt;h2 id=&#34;9-16-igtv-videos-are-broken&#34;&gt;9:16 IGTV videos are broken&lt;/h2&gt;&#xA;&lt;p&gt;The documented aspect ratio for an IGTV video is 9:16, but guess what! They&#xA;aren&amp;rsquo;t displayed correctly in the mobile app.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://user-images.githubusercontent.com/315678/85221173-6017dc00-b3cf-11ea-8b84-43d44cf89d20.png&#34; width=&#34;150px&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;They are displayed correctly in mobile and desktop browsers, though. But, given&#xA;how Instagram nudges everyone to use the app, I would guess that 90-95% of&#xA;viewers would be using the app, if not more.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://user-images.githubusercontent.com/315678/85098070-21d7bc80-b217-11ea-9432-bfb8ebe3ab0b.png&#34; width=&#34;150px&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;After a lot of trial and error, I figured out that I need to upload my videos at&#xA;a ratio of 9:21 or lower to be able to prevent the sides from being chopped off.&#xA;Instagram&amp;rsquo;s UI or docs don&amp;rsquo;t mention this at all. Also, this workaround only&#xA;works when uploading from a destkop browser. I haven&amp;rsquo;t yet figured out how to&#xA;prevent mobile uploads from looking broken.&lt;/p&gt;&#xA;&lt;p&gt;For a visual platform that is so bullish on everything looking perfect, this is&#xA;horrendous! I don&amp;rsquo;t know where to place this - is this a bug in Instagram&amp;rsquo;s&#xA;processing pipeline? Or is this a part of attempts to provide the best viewing&#xA;experience? Just display my videos as advertised, please!&lt;/p&gt;&#xA;&lt;h2 id=&#34;video-post-processing-is-magic&#34;&gt;Video post-processing is magic&lt;/h2&gt;&#xA;&lt;p&gt;Any video I upload goes through a processing pipeline, that is undocumented,&#xA;before it gets displayed to the users. This is possibly done to optimize for&#xA;space, etc., but it has led to broken user experience for at least a couple of&#xA;my videos.&lt;/p&gt;&#xA;&lt;p&gt;On one occassion, it made the audio and video go out of sync. To be fair, the&#xA;video did have some issues with the audio stream data missing for the first 3&#xA;seconds of the video, due to a &lt;a href=&#34;https://github.com/thatte-idli-kaal-soup/humans/commit/77f10800ce6663e1e118b425421662206e3f50c4&#34;&gt;bug in my video processing pipeline&lt;/a&gt;. The same&#xA;video worked perfectly fine in &lt;a href=&#34;http://www.mplayerhq.hu/design7/news.html&#34;&gt;MPlayer&lt;/a&gt;, &lt;a href=&#34;https://mpv.io/&#34;&gt;mpv&lt;/a&gt;, &lt;a href=&#34;https://www.videolan.org/vlc/&#34;&gt;VLC&lt;/a&gt;, and on YouTube. Noticing that&#xA;Instagram&amp;rsquo;s post-processing made the audio and video go out of sync, after about&#xA;50 people watched it, is such a shame!&lt;/p&gt;&#xA;&lt;p&gt;To avoid such problems, we decided to make a demo account and upload every video&#xA;there, before posting it from the real account. Needing to do this seems super&#xA;broken to me. I still did it, since I wanted everything to work just right. But,&#xA;that wasn&amp;rsquo;t to be.&lt;/p&gt;&#xA;&lt;p&gt;We had a video where we added some background music on the video, and it ended&#xA;up having a 4-channel audio stream. It turns out the Instagram app on iOS won&amp;rsquo;t&#xA;play such videos, and we only detected that after some people in our audience&#xA;let us know. Instagram has this documented on their IGTV documentation under&#xA;&lt;a href=&#34;https://help.instagram.com/1038071743007909&#34;&gt;additional technical details&lt;/a&gt;. But, I only read that because things weren&amp;rsquo;t&#xA;working. Again, our followers had a broken experience because of this.&lt;/p&gt;&#xA;&lt;p&gt;It can be hard to &amp;ldquo;document&amp;rdquo; all the technical details of the post-processing&#xA;pipeline. But, it should be fairly easy to detect things like 4-channel audio,&#xA;and warning users about it!&lt;/p&gt;&#xA;&lt;p&gt;Even simpler, but user-friendlier thing to do here would be to allow users to&#xA;view the video after it has been uploaded and processed, before making it&#xA;viewable by everyone. Currently, draft posts cannot be shared with friends. I&amp;rsquo;m&#xA;not sure if they can even be found and viewed from multiple devices &amp;ndash; it wasn&amp;rsquo;t&#xA;intuitive to do this, when I tried. Just making it easy to preview posts before&#xA;sharing it publicly would make things a lot lot more user-friendly. It feels&#xA;quite backward to be using a private account for this to ensure no broken&#xA;content is published.&lt;/p&gt;&#xA;&lt;p&gt;This may sound too extreme, but just give me the exact &lt;a href=&#34;https://www.ffmpeg.org/&#34;&gt;ffmpeg&lt;/a&gt; command being run&#xA;on the uploaded videos somewhere in the docs! I would then be able to verify&#xA;that my videos are Instagram compliant, without having to upload a dozen videos&#xA;and checking on multiple devices. With a lot of big brands using Instagram, I&#xA;think there&amp;rsquo;d be other &amp;ldquo;expert&amp;rdquo; users who would appreciate these details.&lt;/p&gt;&#xA;&lt;h2 id=&#34;published-content-is-uneditable&#34;&gt;Published content is uneditable&lt;/h2&gt;&#xA;&lt;p&gt;I would find the brokenness more tolerable if I could go back and change the&#xA;uploaded videos. But, Instagram doesn&amp;rsquo;t let you edit published posts. It does&#xA;seem like a reasonable restriction, since this content may have been referenced&#xA;elsewhere. This seems to be Twitter&amp;rsquo;s take too, for instance.&lt;/p&gt;&#xA;&lt;p&gt;For something as &amp;ldquo;heavy&amp;rdquo; as a video, though, it seems a little too restrictive.&#xA;It may not be a great idea to allow changing content behind people&amp;rsquo;s backs. But,&#xA;I&amp;rsquo;m not happy about my followers having to watch a broken post. Deleting a&#xA;broken post and making a new one doesn&amp;rsquo;t really cut it &amp;ndash; it feels spammy.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;d like to see some kind of versioning added to the videos. Let user upload a&#xA;newer version, and make it possible for users to see older versions too, if they&#xA;chose to. Google Drive and Dropbox seem to do this, for instance.&lt;/p&gt;&#xA;&lt;h2 id=&#34;outro&#34;&gt;Outro&lt;/h2&gt;&#xA;&lt;p&gt;Instagram started off by allowing users to only post square pictures. It was&#xA;very easy to undestand and use, even if not very accomodating of different use&#xA;cases. Everyone and their dog could use it!&lt;/p&gt;&#xA;&lt;p&gt;A whole bunch of new features have been added in the last few years, trying to&#xA;compete with the other platforms. Doing the simplest thing - posting a single&#xA;picture - may still be easy to do, but trying to do anything more than that&#xA;leads to a frustrating experience quite often. I think the reputation of being&#xA;user-friendly is now just a vestige of the past.&lt;/p&gt;&#xA;&lt;p&gt;People who use it regularly get used to its quirks and probably put up with the&#xA;annoyances, because it gives them a way to reach their audiences with whom&#xA;Instagram is popular. Instagram is &amp;ldquo;friendly&amp;rdquo; to the content consumer, and tries&#xA;its best to keep the content extremely consumable to keep them coming back for&#xA;more. The burden of figuring out and making the content fit the restrictions is&#xA;left on the content-creators. This can often be frustrating.&lt;/p&gt;&#xA;&lt;div style=&#34;font-size:small;&#34; class=&#34;reviewers&#34;&gt;&#xA;&lt;p&gt;Thanks to &lt;a href=&#34;https://balu.muse-amuse.in/&#34;&gt;Kartik&lt;/a&gt;, Meghana, Nitin, Pratiksha, &lt;a href=&#34;https://a-travelers-tales.blogspot.com/&#34;&gt;Ranjan&lt;/a&gt;, &lt;a href=&#34;https://www.lightstalking.com/author/riteshsaini/&#34;&gt;Ritesh&lt;/a&gt;, &lt;a href=&#34;http://baali.muse-amuse.in&#34;&gt;Shantanu&lt;/a&gt; and &lt;a href=&#34;https://vkrishnaswam.github.io/&#34;&gt;Vivek&lt;/a&gt;&#xA;for reading drafts (or parts) of this post and helping by boucing off ideas.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>An innocent query that caused Zulip downtime</title>
      <link>https://punchagan.muse-amuse.in/blog/zulip-downtime-postmortem/</link>
      <pubDate>Thu, 28 May 2020 11:34:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/zulip-downtime-postmortem/</guid>
      <description>&lt;h2 id=&#34;introduction&#34;&gt;Introduction&lt;/h2&gt;&#xA;&lt;p&gt;Recently, &lt;a href=&#34;https://github.com/zulip/zulip/commit/8f32db81a1a1230b425aef8f7c6d2b7fc4543ee7&#34;&gt;a change&lt;/a&gt; that I contributed caused some downtime on the Zulip cloud&#xA;(zulipchat.com). Here&amp;rsquo;s a user &lt;a href=&#34;https://twitter.com/zulip/status/1255005502599131137&#34;&gt;tweeting at us&lt;/a&gt;, about this.&lt;/p&gt;&#xA;&lt;p&gt;I shared this with some friends (who use Zulip) and they asked me to share more&#xA;about what happened. I began writing an explanation, and it eventually turned&#xA;into a blog post. The post tries to explain what caused the down-time, without&#xA;assuming too much knowledge of the Zulip DB schema, but it would help if you&#xA;used Zulip a little.&lt;/p&gt;&#xA;&lt;p&gt;The goal of my change was to change how Zulip backend calculates the&#xA;&lt;code&gt;furthest_read_time&lt;/code&gt; for a user &amp;ndash; the time stamp indicating when the last&#xA;message was read.&lt;/p&gt;&#xA;&lt;p&gt;Previously, the code used simply kept track of the message ID of the messages&#xA;being read by a user in a field called the &amp;ldquo;pointer&amp;rdquo;. My change was to move away&#xA;from this &lt;code&gt;pointer&lt;/code&gt; approach to using the actual timestamp of when a user last&#xA;read a message.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-the-pointer&#34;&gt;What is the pointer?&lt;/h2&gt;&#xA;&lt;p&gt;Put very simply, the pointer is just a message ID&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt; &amp;ndash; ideally, the ID of the&#xA;&amp;ldquo;last message&amp;rdquo; a user has read. Message IDs in Zulip are incremental &amp;ndash; a&#xA;message that has arrived after another one, would have a higher ID than the&#xA;older message. So, it would&amp;rsquo;ve been a great way to keep track of the last read&#xA;message, if all the messages were in &amp;ldquo;one continuous feed&amp;rdquo;. But, guess what,&#xA;Zulip has streams and topics which are precisely what make Zulip such a valuable&#xA;communication tool!&lt;/p&gt;&#xA;&lt;p&gt;The pointer can be set to the ID of the message that is currently being read,&#xA;but only when we are in the &amp;ldquo;All messages&amp;rdquo; view. In this view, all messages are&#xA;ordered chronologically, so any message that is after another message would have&#xA;arrived after it, and would have an ID greater than the other message. So&#xA;reading a message in this view means, any message with a lower ID must&amp;rsquo;ve&#xA;already been read.&lt;/p&gt;&#xA;&lt;p&gt;When you are reading messages in a stream/topic (narrowed) view, the &lt;code&gt;pointer&lt;/code&gt;&#xA;is not updated. We can&amp;rsquo;t be sure that all messages with ID lower than the&#xA;current message&amp;rsquo;s ID have already been read. There could be a whole bunch of&#xA;unread messages in other streams/topics than the current one you are reading.&#xA;So, the &lt;code&gt;pointer&lt;/code&gt; doesn&amp;rsquo;t get updated until you go to the &amp;ldquo;All messages&amp;rdquo; view&#xA;and scroll over the messages, even if you have already read them in a narrowed&#xA;view.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-change-this&#34;&gt;Why change this?&lt;/h2&gt;&#xA;&lt;p&gt;Using the &lt;code&gt;pointer&lt;/code&gt; to compute the &lt;code&gt;furthest_read_time&lt;/code&gt; doesn&amp;rsquo;t work very well,&#xA;because it is only updated in the &amp;ldquo;All messages&amp;rdquo; view. In other words,&#xA;&lt;code&gt;furthest_read_time&lt;/code&gt; turned out to actually mean something like&#xA;&lt;code&gt;furthest_read_time_in_all_messages_view&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The &lt;code&gt;furthest_read_time&lt;/code&gt; is used in the UI to display the bankruptcy banner &amp;ndash; a&#xA;prompt shown to a user to mark all messages as read, if they have &amp;ldquo;too many&amp;rdquo;&#xA;unreads, and haven&amp;rsquo;t read new messages in the last 48 hours.&lt;/p&gt;&#xA;&lt;p&gt;But, this is a problem, especially in Zulip instances with a lot of traffic,&#xA;where people leave a lot of messages unread until they have the time to&#xA;catch-up. It is common for people to communicate only in a handful of&#xA;streams/topics, and leave a lot of messages unread in other streams or topics,&#xA;that they are hoping to catch-up on, when they have more time at hand. Such&#xA;users would avoid using the &amp;ldquo;All messages&amp;rdquo; view at any cost.&lt;/p&gt;&#xA;&lt;p&gt;Even in not-so-high-traffic realms, some users just prefer not to use the &amp;ldquo;All&#xA;messages&amp;rdquo; view, and just stick to narrowed views.&lt;/p&gt;&#xA;&lt;p&gt;So, for these users the &lt;code&gt;furthest_read_time&lt;/code&gt; would get updated very rarely, and&#xA;could potentially remain at a date way back in the past. This meant the users&#xA;would see the bankruptcy banner despite actively participating in the Realm,&#xA;even if only in a few topics/streams. This is annoying UX, and what something we&#xA;wanted to fix.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-did-we-change-this-to&#34;&gt;What did we change this to?&lt;/h2&gt;&#xA;&lt;p&gt;We decided to use the last read message time as the message to consider for the&#xA;&lt;code&gt;furthest_read_time&lt;/code&gt;. The following &amp;ldquo;innocent looking&amp;rdquo; query should do that for&#xA;us, we thought&amp;hellip;&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;UserMessage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;objects&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_profile&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_profile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;UserMessage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Well, it does, but not without bringing down the whole of &lt;code&gt;zulipchat.com&lt;/code&gt; after&#xA;a deploy! 🙈 But, why?!&lt;/p&gt;&#xA;&lt;p&gt;Some background on how data is stored would be useful to see why.&lt;/p&gt;&#xA;&lt;h2 id=&#34;usermessage-table-is-huge-my-friend&#34;&gt;UserMessage table is huge, my friend&lt;/h2&gt;&#xA;&lt;p&gt;Zulip&amp;rsquo;s data model has a &lt;code&gt;Message&lt;/code&gt; table that stores the content of each&#xA;message, when it was sent, by whom, to which topic, etc. The &lt;code&gt;UserMessage&lt;/code&gt; table&#xA;is then used to keep track of what the status of this message is, for each user&#xA;that has received the message.  A 32 bit flag field is used to keep track of&#xA;things like, whether the user has read a message, starred a message, has been&#xA;mentioned in a message, etc. So, if a messages is sent to a stream with N users,&#xA;it creates 1 row in the &lt;code&gt;Message&lt;/code&gt; table and N rows in the &lt;code&gt;UserMessage&lt;/code&gt; table.&#xA;If M such messages are sent, it would create M*N rows in the &lt;code&gt;UserMessage&lt;/code&gt;&#xA;table. So, pretty soon, the &lt;code&gt;UserMessage&lt;/code&gt; table becomes huge! &lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;To make common queries on this table efficient, the DB has indexes for them.&#xA;Some of the indexes on the &lt;code&gt;UserMessage&lt;/code&gt; table are documented &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/production/expensive-migrations.html#running-expensive-migrations-early&#34;&gt;here&lt;/a&gt;, though the&#xA;documentation was created in the migration context for production deployments.&#xA;There are indexes for various things, including &lt;strong&gt;unread&lt;/strong&gt; messages.&lt;/p&gt;&#xA;&lt;p&gt;And here&amp;rsquo;s our innocent looking query, as a reminder.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&lt;span class=&#34;n&#34;&gt;UserMessage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;objects&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;filter&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_profile&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;user_profile&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;UserMessage&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;flags&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;read&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;last&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This query searches through the &lt;code&gt;read&lt;/code&gt; messages for a particular user, and tries&#xA;to figure out the last message they read. Note that the DB only has indexes for&#xA;unread messages, not read messages! So, this query isn&amp;rsquo;t using DB indexes to&#xA;search for this needle in the haystack, and ends up being pretty damn slow!&lt;/p&gt;&#xA;&lt;p&gt;Additionally, this query is run for every user when the &amp;ldquo;home page&amp;rdquo; is loaded&#xA;since we want to calculate their &lt;code&gt;furthest_read_time&lt;/code&gt; to decide if should show&#xA;the bankruptcy banner.&lt;/p&gt;&#xA;&lt;p&gt;Also, Zulip&amp;rsquo;s architecture is designed to allow using the same app server and DB&#xA;to host multiple different realms. And zulipchat.com is such a deployment where&#xA;a few servers are used to serve all the realms. (I don&amp;rsquo;t know too much about the&#xA;deployment setup, though).&lt;/p&gt;&#xA;&lt;p&gt;When a new change is deployed to zulipchat.com and the server is restarted, all&#xA;the clients of all the users reload. Having an expensive query in that path,&#xA;would just kill the DB. And this innocent looking query &lt;a href=&#34;https://twitter.com/zulip/status/1255005502599131137&#34;&gt;didn&amp;rsquo;t disappoint&lt;/a&gt;!&lt;/p&gt;&#xA;&lt;h2 id=&#34;how-did-we-fix-this&#34;&gt;How did we fix this?&lt;/h2&gt;&#xA;&lt;p&gt;Well, this change was &lt;a href=&#34;https://github.com/zulip/zulip/commit/976e554799a03ff9d82d7b75d77d45985cd25df4&#34;&gt;reverted&lt;/a&gt; immediately by &lt;a href=&#34;https://github.com/timabbott&#34;&gt;Tim&lt;/a&gt;, and things were kicked back&#xA;into a usable state.&lt;/p&gt;&#xA;&lt;p&gt;Later, we decided to take a different approach. We decided to look at a&#xA;different table (&lt;code&gt;UserActivity&lt;/code&gt;) that tracks user activity, mainly for the&#xA;purpose of analytics. This table keeps track of the last time a user performed&#xA;an action based on the API calls made.&lt;/p&gt;&#xA;&lt;p&gt;Among other things, changing any of the flags in the 32-bit flag field is one of&#xA;the actions that is tracked. Marking a message as read was being tracked too. We&#xA;use the last time this action was performed to compute the last time a user was&#xA;&amp;ldquo;active&amp;rdquo;, and based on that decide if we should show the bankruptcy banner or&#xA;not.&lt;/p&gt;&#xA;&lt;p&gt;Here&amp;rsquo;s the &lt;a href=&#34;https://github.com/zulip/zulip/commit/ded3b0076070365dddccd43d7f05fd627c2637f7&#34;&gt;actual commit&lt;/a&gt; that makes this change. But, it turns out that needed a&#xA;&lt;a href=&#34;https://github.com/zulip/zulip/commit/734d651b45542e9a1bdea10cd290637f73be30d9&#34;&gt;follow-up fix&lt;/a&gt; too. 🙈&lt;/p&gt;&#xA;&lt;div style=&#34;font-size:small;&#34; class=&#34;reviewers&#34;&gt;&#xA;&lt;p&gt;Thanks to &lt;a href=&#34;https://web.mit.edu/tabbott/www/&#34;&gt;Tim Abbott&lt;/a&gt; and &lt;a href=&#34;http://baali.muse-amuse.in&#34;&gt;Shantanu&lt;/a&gt; for reading drafts of this post.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;The pointer was used to do a &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/subsystems/pointer.html&#34;&gt;bunch of useful things&lt;/a&gt;, but we are&#xA;currently in the process of &lt;a href=&#34;https://github.com/zulip/zulip/issues/8994&#34;&gt;removing it&lt;/a&gt;.&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;Zulip&amp;rsquo;s code base uses a concept called &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/subsystems/sending-messages.html#soft-deactivation&#34;&gt;soft-deactivation&lt;/a&gt;&#xA;to mitigate this problem on Realms where there are a lot of users who log in&#xA;very infrequently, or don&amp;rsquo;t login after an initial period of activity. So, the&#xA;number of rows are not exactly &lt;code&gt;M*N&lt;/code&gt; in all the cases, but in the worst case&#xA;they are.&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>My Favorite Git Resources</title>
      <link>https://punchagan.muse-amuse.in/blog/git-resources/</link>
      <pubDate>Fri, 22 May 2020 16:07:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/git-resources/</guid>
      <description>&lt;p&gt;I often help friends who are new to using &lt;code&gt;git&lt;/code&gt; with using it. This blog post is&#xA;going to serve as a single link to share with them, instead of trying to find&#xA;individual links over and over.&lt;/p&gt;&#xA;&lt;h2 id=&#34;understanding-git&#34;&gt;Understanding Git&lt;/h2&gt;&#xA;&lt;p&gt;I got started with using &lt;code&gt;git&lt;/code&gt; after using &lt;code&gt;svn&lt;/code&gt; and &lt;code&gt;hg&lt;/code&gt; for a few months. But,&#xA;I would often be lost in the myriad of command line options, putting myself in&#xA;situations I couldn&amp;rsquo;t come out of without some scars. I didn&amp;rsquo;t really understand&#xA;how &lt;code&gt;git&lt;/code&gt; worked, and that was the real problem.&lt;/p&gt;&#xA;&lt;p&gt;Improving my mental model of how &lt;code&gt;git&lt;/code&gt; works, and then trying to fit the&#xA;commands into this mental model is what made &lt;code&gt;git&lt;/code&gt; finally click for me. The &lt;a href=&#34;http://tom.preston-werner.com/2009/05/19/the-git-parable.html&#34;&gt;Git&#xA;Parable&lt;/a&gt; really helped me understand &lt;code&gt;git&lt;/code&gt; from the inside out, and gave me a&#xA;much clearer mental model of &lt;code&gt;git&lt;/code&gt;. There was no looking back from there.&lt;/p&gt;&#xA;&lt;p&gt;If parables are not your thing, and you&amp;rsquo;d rather read something that takes a&#xA;less flowery and more straighforward approach to explaining these concepts, I&#xA;really liked John Wiegley&amp;rsquo;s &lt;a href=&#34;https://jwiegley.github.io/git-from-the-bottom-up/&#34;&gt;Git from the Bottom Up&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;day-to-day-git&#34;&gt;Day-to-day git&lt;/h2&gt;&#xA;&lt;p&gt;&lt;a href=&#34;https://zulipchat.com&#34;&gt;Zulip&lt;/a&gt; (an open source group chat application that I spend a lot of time&#xA;contributing to) uses a rebase-heavy workflow, where good commits are merged&#xA;from different PRs, as and when they are reviewed, instead of waiting for all&#xA;the commits in a PR to be good to be merged. Developers often have to pull from&#xA;branches that have been force-pushed to, rebase their commits, squash commits,&#xA;learn to change &lt;code&gt;git&lt;/code&gt; history, etc.&lt;/p&gt;&#xA;&lt;p&gt;Zulip&amp;rsquo;s &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/git/index.html&#34;&gt;Git Guide&lt;/a&gt; is top-class documentation that gives guidelines on using git&#xA;from a practical stand-point. A lot of new developers use it to get upto speed&#xA;with Zulip&amp;rsquo;s workflow that involves a lot of things that I&amp;rsquo;ve seen devs who have&#xA;been using git for many years struggle with.&lt;/p&gt;&#xA;&lt;p&gt;The section on &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/git/pull-requests.html&#34;&gt;pull request workflow&lt;/a&gt; is quite helpful, and should work&#xA;reasonably well for contributing to other FOSS projects too.&lt;/p&gt;&#xA;&lt;p&gt;I also like the sections with recipes for common &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/git/fixing-commits.html&#34;&gt;&lt;code&gt;git&lt;/code&gt; history edit actions&lt;/a&gt;, and&#xA;the &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/git/troubleshooting.html&#34;&gt;troubleshooting section&lt;/a&gt; with recipes to get out of common troublesome&#xA;situations. &lt;a href=&#34;https://ohshitgit.com/#accidental-commit-master&#34;&gt;Oh shit, git!&lt;/a&gt; is a very similar resource to this, that has a bunch&#xA;of useful &amp;ldquo;recipes&amp;rdquo; to recover from different scenarios.&lt;/p&gt;&#xA;&lt;p&gt;Julia Evans&amp;rsquo;s &lt;a href=&#34;https://jvns.ca/blog/2019/08/30/git-exercises--navigate-a-repository/&#34;&gt;exercises&lt;/a&gt; approach to learning to explore a &lt;code&gt;git&lt;/code&gt; repository is&#xA;quite interesting, though I haven&amp;rsquo;t run through all the exercises myself.&lt;/p&gt;&#xA;&lt;h2 id=&#34;git-as-a-communication-tool&#34;&gt;Git as a communication tool&lt;/h2&gt;&#xA;&lt;p&gt;I like to look at &lt;code&gt;git&lt;/code&gt; history as telling the story of evolution of a code&#xA;base. The advice that is sometimes given to writers about doing the hardwork, so&#xA;that the readers can do less of it, holds true for git history too. Communicate&#xA;the story as clearly as possible for your readers to understand, and don&amp;rsquo;t just&#xA;publish a &amp;ldquo;stream of consciousness&amp;rdquo; piece.&lt;/p&gt;&#xA;&lt;p&gt;What does this mean in practical terms, though?&lt;/p&gt;&#xA;&lt;p&gt;I think editing git history to present a clearer story is completely acceptable.&#xA;If one tries a handful of different things, and then finally finds the solution&#xA;to do something, it&amp;rsquo;s not necessary to have all the failed attempts as commits.&#xA;Just the final approach can be a commit/pull-request, while documenting the&#xA;other approaches the commit message or as a comment in the code, if that makes&#xA;sense.&lt;/p&gt;&#xA;&lt;p&gt;Expect your collaborators (including future you) to look at not just older&#xA;versions of code, but the commit history for understanding how a piece of code&#xA;evolved, for undertsanding the history. Make your git &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/contributing/version-control.html#commit-messages&#34;&gt;commit messages&lt;/a&gt; as useful&#xA;as you can. Writing a good summary line goes a long way in understanding a&#xA;change. In most cases a body would be useful to explain the how and the why of&#xA;the change, while the summary line explains the what.&lt;/p&gt;&#xA;&lt;p&gt;I like this &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/contributing/version-control.html#commit-discipline&#34;&gt;commit discipline&lt;/a&gt; that the Git project itself uses, and was adopted&#xA;by the Zulip project: &amp;ldquo;Each commit is a minimal coherent idea&amp;rdquo;. Simply put, you&#xA;want each commit to be such that they can be can be deployed (and/or reverted by&#xA;itself), without depending on any other commits alongside them. You can read&#xA;more about what minimal and coherent mean in this context in the &lt;a href=&#34;https://zulip.readthedocs.io/en/latest/contributing/version-control.html#commit-discipline&#34;&gt;Zulip&#xA;documentation&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;tools-for-git&#34;&gt;Tools for Git&lt;/h2&gt;&#xA;&lt;p&gt;Some of the confusion in using &lt;code&gt;git&lt;/code&gt; even after understanding how it works is&#xA;the inconsitent CLI API that it often exposes. There has been some work going&#xA;into this, to make this more consistent. But, using a nice client can help with&#xA;this. I use the excellent Emacs client for &lt;code&gt;git&lt;/code&gt; called &lt;a href=&#34;https://magit.vc/screenshots/&#34;&gt;&lt;code&gt;magit&lt;/code&gt;&lt;/a&gt;. It is an&#xA;intuitive UI on top of &lt;code&gt;git&lt;/code&gt;&amp;rsquo;s data model, that allows me to do things that I&#xA;commonly want to do, with just a few hot-keys, instead of typing out elaborate&#xA;recipes to do things. I highly recommend it, if you are an Emacs user.&lt;/p&gt;&#xA;&lt;p&gt;It is also helpful to change you shell&amp;rsquo;s prompt to tell you more about the&#xA;status of the current directory&amp;rsquo;s repository. There are a bunch of&#xA;configurations out there (Stackoverflow, Gists, etc.) that let you do this. The&#xA;git repo itself comes with a &lt;a href=&#34;https://github.com/git/git/blob/master/contrib/completion/git-prompt.sh&#34;&gt;prompt customisation&lt;/a&gt;. I like being able to see at&#xA;least the current branch and dirty/clean state of the repo.&lt;/p&gt;&#xA;&lt;p&gt;Here are some simple changes to the global &lt;code&gt;git&lt;/code&gt; config, off the top of my head.&#xA;These could make your &lt;code&gt;git&lt;/code&gt; workflow more pleasant.&lt;/p&gt;&#xA;&lt;pre tabindex=&#34;0&#34;&gt;&lt;code class=&#34;language-gitconfig&#34; data-lang=&#34;gitconfig&#34;&gt;[push]&#xA;  # Push to the branch to the same remote branch as the one we are working on,&#xA;  # locally. This is the default in Git &amp;gt;= 2.0, so you may not need to set it.&#xA;  default = simple&#xA;&#xA;[diff]&#xA;  # You could configure a GUI tool to use here. (I haven&amp;#39;t used one in a long&#xA;  # time, and I don&amp;#39;t have recommendations on what to use)&#xA;  tool = icdiff&#xA;&#xA;[merge]&#xA;  # Shows common ancestor in a merge conflict. Makes it easier to understand&#xA;    # the conflict and merge, for me.&#xA;  conflictstyle = diff3&#xA;&#xA;# Never garbage collect commits/blobs that are unreachable&#xA;# The cost of keeping this data around is negligble compared losing data&#xA;[gc]&#xA;  reflogExpire = never&#xA;  reflogExpireUnreachable = never&#xA;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&#34;outro&#34;&gt;Outro&lt;/h2&gt;&#xA;&lt;p&gt;If you have other recommendations or tools that you&amp;rsquo;d like to share with me,&#xA;please do! Using &lt;code&gt;git&lt;/code&gt; better, and understanding it better, is something that&#xA;I&amp;rsquo;m always excited about. I&amp;rsquo;d also be happy to answer questions, or help you&#xA;with specific things that you are trying to do with &lt;code&gt;git&lt;/code&gt;.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>The tools we build change us</title>
      <link>https://punchagan.muse-amuse.in/blog/the-tools-we-build-change-us/</link>
      <pubDate>Wed, 22 Apr 2020 12:54:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/the-tools-we-build-change-us/</guid>
      <description>&lt;p&gt;A couple of weeks ago, I spent some time building a couple of &amp;ldquo;automation tools&amp;rdquo;&#xA;for myself. It is still early days to talk about their impact, but I have&#xA;already noticed some changes, and have some thoughts to share.&lt;/p&gt;&#xA;&lt;p&gt;Thanks to the lock-down, I felt like I needed to do something to get more&#xA;fresh-air and sunlight. I figured out a nice setup to work from my balcony, when&#xA;I feel like it. It&amp;rsquo;s nice to sit in the balcony, since there&amp;rsquo;s not as much&#xA;traffic, and there&amp;rsquo;s enough fresh-air and sunlight.&lt;/p&gt;&#xA;&lt;p&gt;I usually work with dark themes in all my tools - code editor, terminal, OS,&#xA;chat clients, etc. But, switching to the balcony during the day makes it harder&#xA;to read text in dark mode. I have to switch all my tools to light mode. And then&#xA;switch back, when I come back in. It takes me about a minute or so, each time to&#xA;make this switch. In a few days, this started to seem like work! And I could see&#xA;myself needing to push myself to step out, or step back in.&lt;/p&gt;&#xA;&lt;p&gt;A few days later, I spent about half a day writing a tool that could switch&#xA;modes for all of these programs with one command. If I was doing the switches&#xA;manually each time, it would take 2-4 months for the switching time to add up to&#xA;the 4-6 hours, I spent on getting everything working correctly. So, it&amp;rsquo;s not&#xA;really a bad investment. But, what matters more is that I don&amp;rsquo;t feel a mental&#xA;block to alternate between indoors and outdoors because of all the extra work&#xA;that manual theme switching felt like. I am getting some fresh air and sunlight&#xA;everyday. :)&lt;/p&gt;&#xA;&lt;p&gt;The other tool I wrote recently was for generating a daily summary of what I&#xA;worked on from my org-mode based clock entries. I add more detail to the&#xA;bulleted-list summary that gets generated, and then post it on our team&amp;rsquo;s Zulip.&#xA;I noticed a couple of changes because of this.&lt;/p&gt;&#xA;&lt;p&gt;First, I clock things more diligently than I did before. If I forget to clock&#xA;into something, I go back and add some manual entries, to maintain a proper log.&#xA;Second, a couple of other people on my team also have started posting a summary&#xA;of their day&amp;rsquo;s work, which is quite nice. This tool may have triggered a change&#xA;in my teammates&amp;rsquo; behavior, though I didn&amp;rsquo;t really intend it to.&lt;/p&gt;&#xA;&lt;p&gt;We are creatures of habit, often going through the motions, without needing to&#xA;think about what we are doing. This is evolution helping us save energy for the&#xA;more critical tasks. But, our environments can have a big impact on our habits.&#xA;Having tools around us, that are easy to use, can help us nudge ourselves in&#xA;directions that we want to be nudged in.&lt;/p&gt;&#xA;&lt;p&gt;The tools we build can change us; if we let them.&lt;/p&gt;&#xA;&lt;div style=&#34;font-size:small;&#34; class=&#34;reviewers&#34;&gt;&#xA;&lt;p&gt;Thanks to Rajesh, &lt;a href=&#34;https://www.lightstalking.com/author/riteshsaini/&#34;&gt;Ritesh&lt;/a&gt;, &lt;a href=&#34;https://tcluri.github.io/&#34;&gt;Tejaa&lt;/a&gt; and &lt;a href=&#34;http://baali.muse-amuse.in&#34;&gt;Shantanu&lt;/a&gt; for reading drafts of this post.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Django ModelFormSet and multiple saves</title>
      <link>https://punchagan.muse-amuse.in/blog/django-modelformset-multiple-saves/</link>
      <pubDate>Wed, 08 Jan 2020 09:45:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/django-modelformset-multiple-saves/</guid>
      <description>&lt;p&gt;A friend and I were trying to &lt;a href=&#34;https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#using-a-model-formset-in-a-view&#34;&gt;use the Django ModelFormSets&lt;/a&gt; in a project, and we&#xA;ran into a subtle bug that took a little big of digging into the Django code to&#xA;identify and work around.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-bug&#34;&gt;The Bug&lt;/h2&gt;&#xA;&lt;p&gt;We weren&amp;rsquo;t really familiar with Django&amp;rsquo;s &lt;code&gt;FormSet&lt;/code&gt; or &lt;code&gt;ModelFormSet&lt;/code&gt;, when we&#xA;started. We began by reading the documentation to get started.&lt;/p&gt;&#xA;&lt;p&gt;The Django docs had &lt;a href=&#34;https://docs.djangoproject.com/en/2.2/topics/forms/modelforms/#using-a-model-formset-in-a-view&#34;&gt;an example&lt;/a&gt; that looked straight-forward, and showed how to&#xA;use &lt;code&gt;ModelFormSet&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;manage_authors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modelformset_factory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Author&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fields&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FILES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_valid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;c1&#34;&gt;# do something.&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;manage_authors.html&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;You create a &lt;code&gt;ModelFormSet&lt;/code&gt; class using the &lt;code&gt;modelformset_factory&lt;/code&gt; using the&#xA;required model, and the required fields.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Use the data from a &lt;code&gt;POST&lt;/code&gt; to create an instance of the class from above.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Save the data if the formset validates, and we are done!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;We tweaked the example to our needs, and it worked for us. Mostly.&lt;/p&gt;&#xA;&lt;p&gt;A user reported that after saving the form once with some data, trying to save&#xA;more data didn&amp;rsquo;t work! The form would try to save the data already saved in the&#xA;last save, and fail validation that required some of the fields to be unique.&lt;/p&gt;&#xA;&lt;p&gt;On the second save, the data which was saved during the last save was still&#xA;being treated as newly filled in data!&lt;/p&gt;&#xA;&lt;p&gt;This also caused newly filled-in data during the second save to be lost forever.&#xA;The user was forced to reload the page and re-enter the data.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-why&#34;&gt;The Why&lt;/h2&gt;&#xA;&lt;p&gt;The way Django keeps track of newly filled-in data in the form along with&#xA;multiple levels of caching causes this bug to manifest.&lt;/p&gt;&#xA;&lt;h3 id=&#34;modelformset-queryset-argument&#34;&gt;&lt;code&gt;ModelFormSet&lt;/code&gt; &lt;code&gt;queryset&lt;/code&gt; argument&lt;/h3&gt;&#xA;&lt;p&gt;&lt;code&gt;AuthorFormSet&lt;/code&gt; (or any &lt;code&gt;ModelFormSet&lt;/code&gt; created using the &lt;code&gt;modelformset_factory&lt;/code&gt;)&#xA;takes an additional optional argument &lt;code&gt;queryset&lt;/code&gt;. This argument can be used to&#xA;choose specific rows in the DB that need to be used to populate the initial form&#xA;rows, if any. If no &lt;code&gt;queryset&lt;/code&gt; is specified, all the objects in the DB are used.&lt;/p&gt;&#xA;&lt;h3 id=&#34;formset-metadata&#34;&gt;&lt;code&gt;FormSet&lt;/code&gt;  metadata&lt;/h3&gt;&#xA;&lt;p&gt;First, metadata about the form is saved in a few hidden input fields (called the&#xA;&lt;code&gt;ManagementForm&lt;/code&gt;). This hidden form keep tracks of metadata like the total&#xA;number of forms to show, initial form count and the minimum &amp;amp; maximum number of&#xA;forms to display.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-html&#34; data-lang=&#34;html&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-TOTAL_FORMS&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;19&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;id_form-TOTAL_FORMS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-INITIAL_FORMS&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;7&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;id_form-INITIAL_FORMS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-MIN_NUM_FORMS&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;0&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;id_form-MIN_NUM_FORMS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;p&#34;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&#34;nt&#34;&gt;input&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;type&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;hidden&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;name&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;form-MAX_NUM_FORMS&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;value&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;1000&amp;#34;&lt;/span&gt; &lt;span class=&#34;na&#34;&gt;id&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;s&#34;&gt;&amp;#34;id_form-MAX_NUM_FORMS&amp;#34;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;&amp;gt;&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;Initial form count is the count of the number of forms that are pre-filled using&#xA;data from the DB &amp;ndash; essentially, the length of the &lt;code&gt;queryset&lt;/code&gt;&lt;/p&gt;&#xA;&lt;h3 id=&#34;metadata-does-not-change&#34;&gt;Metadata does not change&lt;/h3&gt;&#xA;&lt;p&gt;When the &lt;code&gt;ModelFormSet&lt;/code&gt; is used as described in the documentation, the metadata&#xA;in the &lt;code&gt;ManagementForm&lt;/code&gt; doesn&amp;rsquo;t get updated when the form is re-rendered in the&#xA;response to a successful &lt;code&gt;POST&lt;/code&gt; request. If one form with new data was&#xA;successfully saved, the number of initial forms in the re-rendered form must go&#xA;up by 1, but it doesn&amp;rsquo;t.&lt;/p&gt;&#xA;&lt;h3 id=&#34;queryset-caching-problem&#34;&gt;Queryset caching problem&lt;/h3&gt;&#xA;&lt;p&gt;Django has caching at the queryset level which means that the queryset doesn&amp;rsquo;t&#xA;get updated with the newly created instances, even if they match the query that&#xA;the queryset uses.&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FILES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;queryset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;existing_authors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;&lt;code&gt;existing_authors&lt;/code&gt; is a queryset that looks for a specific set of authors in the&#xA;DB, or may be all the authors in the DB, if that&amp;rsquo;s what the form needs to do.&lt;/p&gt;&#xA;&lt;p&gt;So, when a formset has been submitted, and some new rows have been created in&#xA;the model&amp;rsquo;s table, the new rows don&amp;rsquo;t automatically get added to the &lt;code&gt;queryset&lt;/code&gt;&#xA;since it the results fetched from the DB are cached by the &lt;code&gt;queryset&lt;/code&gt;. We need&#xA;to create a new &lt;code&gt;queryset&lt;/code&gt; for it to include the newly created rows.&lt;/p&gt;&#xA;&lt;p&gt;These two levels of caching combined make the bug manifest, as it does. I&amp;rsquo;m not&#xA;yet sure what the correct &amp;ldquo;fix&amp;rdquo; for this is, but we ended up using a work-around&#xA;&amp;ndash; create a new formset when returning from a successful &lt;code&gt;POST&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;the-work-around&#34;&gt;The Work-Around&lt;/h2&gt;&#xA;&lt;p&gt;We instantiate a new &lt;code&gt;ModelFormSet&lt;/code&gt; instance when returning the form, on a&#xA;successful &lt;code&gt;POST&lt;/code&gt;. This means, the &lt;code&gt;ManagementForm&lt;/code&gt; is recreated for the new&#xA;formset and has the correct metadata about the form, even when being rendered in&#xA;the response of a successful &lt;code&gt;POST&lt;/code&gt;.&lt;/p&gt;&#xA;&lt;p&gt;The code in the example in Django docs, would look something like the one below:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-python&#34; data-lang=&#34;python&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;  &lt;span class=&#34;k&#34;&gt;def&lt;/span&gt; &lt;span class=&#34;nf&#34;&gt;manage_authors&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;):&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;modelformset_factory&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;Author&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;fields&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;=&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;name&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;title&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;))&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;method&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;==&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;POST&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;POST&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;FILES&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;)&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;if&lt;/span&gt; &lt;span class=&#34;ow&#34;&gt;not&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;is_valid&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;():&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;manage_authors.html&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;          &lt;span class=&#34;k&#34;&gt;else&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;              &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;o&#34;&gt;.&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;save&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt; &lt;span class=&#34;o&#34;&gt;=&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;AuthorFormSet&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;()&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;      &lt;span class=&#34;k&#34;&gt;return&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;render&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;(&lt;/span&gt;&lt;span class=&#34;n&#34;&gt;request&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;s1&#34;&gt;&amp;#39;manage_authors.html&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;,&lt;/span&gt; &lt;span class=&#34;p&#34;&gt;{&lt;/span&gt;&lt;span class=&#34;s1&#34;&gt;&amp;#39;formset&amp;#39;&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;:&lt;/span&gt; &lt;span class=&#34;n&#34;&gt;formset&lt;/span&gt;&lt;span class=&#34;p&#34;&gt;})&lt;/span&gt;&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;&lt;p&gt;This blog post should probably become a PR or an issue, but I&amp;rsquo;m not familiar&#xA;with how contributing to Django works. This blog post is an attempt to&#xA;understand the issue better, and potentially help others who get bit by it.&lt;/p&gt;&#xA;&lt;div style=&#34;font-size:small;&#34; class=&#34;reviewers&#34;&gt;&#xA;  &lt;div&gt;&lt;/div&gt;&#xA;&lt;p&gt;Thanks to &lt;a href=&#34;http://baali.muse-amuse.in&#34;&gt;Shantanu&lt;/a&gt; for reading drafts of this post.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Been there, done that, and still doing it!</title>
      <link>https://punchagan.muse-amuse.in/blog/been-there-done-that-and-still-doing-it/</link>
      <pubDate>Thu, 05 Sep 2019 12:23:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/been-there-done-that-and-still-doing-it/</guid>
      <description>&lt;p&gt;I was talking to a friend a few days ago about a new internship she got. She&#xA;wasn&amp;rsquo;t sure if and how much she was going to get paid for it. Unpaid internships&#xA;aren&amp;rsquo;t cool, and experience doesn&amp;rsquo;t pay the bills, &lt;a href=&#34;https://twitter.com/aoc/status/1154466530500812800&#34;&gt;as they say&lt;/a&gt;. Eventually, it&#xA;turned out that she was indeed going to get paid for it.&lt;/p&gt;&#xA;&lt;p&gt;But, when she found out that she&amp;rsquo;ll be paid, she felt way more pressure to &amp;ldquo;not&#xA;screw up&amp;rdquo;. I think working in this mode of &amp;ldquo;don&amp;rsquo;t screw up&amp;rdquo; isn&amp;rsquo;t very productive.&#xA;Staying in the mindset of &amp;ldquo;learn as much as I can&amp;rdquo; would still be the best way&#xA;to go about the internship.&lt;/p&gt;&#xA;&lt;p&gt;Screwing up is a part of the job. People make mistakes and learn from them.&#xA;Screwing up is a part of gaining experience, and learning. To let people feel&#xA;comfortable and safe while they are learning, it&amp;rsquo;s important to have better&#xA;fallback and recovery mechanisms when things go wrong. The productivity gains&#xA;are worth investing time into such systems.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;m going to write down a couple of times I screwed up &amp;ndash; one of them in my very&#xA;first job after college, and the other just a month or so ago. People screw up&#xA;every day, irrespective of how much experience they have.&lt;/p&gt;&#xA;&lt;h2 id=&#34;corrupted-a-server-s-hard-disk&#34;&gt;Corrupted a server&amp;rsquo;s hard-disk&lt;/h2&gt;&#xA;&lt;p&gt;In my &lt;a href=&#34;https://python.fossee.in/&#34;&gt;first job&lt;/a&gt;, I had screwed up big time in the first couple of weeks of my&#xA;job. It&amp;rsquo;s been a while, and a lot of the details escape me now.&lt;/p&gt;&#xA;&lt;p&gt;I was supposed to resize partitions on a server&amp;rsquo;s hard disk so that there&amp;rsquo;s more&#xA;space available for the media that we were going to store on the server. The&#xA;server was pretty newly setup, and there wasn&amp;rsquo;t all that much data on it, but my&#xA;bosses (&lt;a href=&#34;https://in.linkedin.com/in/pasokan&#34;&gt;Asokan&lt;/a&gt; and &lt;a href=&#34;https://www.aero.iitb.ac.in/~prabhu/&#34;&gt;Prabhu&lt;/a&gt;) had spent some time on configuring it, and setting up&#xA;user accounts, etc., for all the people that were going to join the project.&lt;/p&gt;&#xA;&lt;p&gt;I tested the resize operation on a machine locally in the office that I worked&#xA;in, and it seemed to work. I replicated this on the server, and it went kaput!&#xA;All the data was lost and I could no longer SSH into it. I was totally freaking&#xA;out!&lt;/p&gt;&#xA;&lt;p&gt;But my boss ended up being really calm about it, and asked me to just write to&#xA;the server hosting service to get a new machine with a bigger media disk. And&#xA;no, I didn&amp;rsquo;t get fired from the job. I worked with him for 5-6 years after that,&#xA;including being hired again at a company he started working for.&lt;/p&gt;&#xA;&lt;h2 id=&#34;almost-deleted-7-8-years-of-email&#34;&gt;Almost Deleted 7-8 years of email&lt;/h2&gt;&#xA;&lt;p&gt;A few weeks ago, I screwed up again. It could&amp;rsquo;ve been pretty bad, but luckily&#xA;for me it wasn&amp;rsquo;t.&lt;/p&gt;&#xA;&lt;p&gt;I administer a &lt;a href=&#34;https://support.google.com/a/answer/2855120?hl=en&#34;&gt;legacy Google Suite&lt;/a&gt; for &lt;a href=&#34;https://indiaultimate.org&#34;&gt;UPAI&lt;/a&gt;. We have only 10 email IDs to&#xA;allocate, and we often recycle them. Recently, I had to merge 3 accounts into a&#xA;single one to free up 2 new accounts. I transferred data from two of them to the&#xA;third, and went ahead and deleted them. I did this with a couple of other email&#xA;accounts before, but they were barely used and nobody really cared about them.&lt;/p&gt;&#xA;&lt;p&gt;I hadn&amp;rsquo;t paid attention to what data gets transferred, and what doesn&amp;rsquo;t. It&#xA;turns out &lt;a href=&#34;https://support.google.com/a/answer/33314?hl=en&#34;&gt;emails don&amp;rsquo;t get transferred&lt;/a&gt;, and only data in the Google Drive gets&#xA;transferred. This meant I had lost years of important email communication for&#xA;the organisation. I freaked out!&lt;/p&gt;&#xA;&lt;p&gt;My &amp;ldquo;&lt;a href=&#34;https://indiaultimate.org/u/manickam-narayanan&#34;&gt;boss&lt;/a&gt;&amp;rdquo; was again pretty calm, and asked me to write to Google to see if I&#xA;could get them to restore the data. I looked around, and found that Google&#xA;allowed restoring deleted accounts for 20 days! I &lt;a href=&#34;https://support.google.com/a/answer/1397578&#34;&gt;restored those accounts&lt;/a&gt;,&#xA;&lt;a href=&#34;https://support.google.com/a/answer/6351475?hl=en&amp;amp;ref_topic=6351498&#34;&gt;transferred the email&lt;/a&gt; and then deleted the accounts again.&lt;/p&gt;&#xA;&lt;h2 id=&#34;learning-from-screw-ups&#34;&gt;Learning from screw-ups&lt;/h2&gt;&#xA;&lt;p&gt;Learning and improving the systems in-place to prevent such screw-ups is the&#xA;best thing that we can do from such screw-ups. Just like a piece of software&#xA;gets hardened by bug reports that are acted upon, over the course of time, other&#xA;systems can and should too.&lt;/p&gt;&#xA;&lt;p&gt;As described in this &lt;a href=&#34;https://about.gitlab.com/2015/01/23/how-to-turn-screw-ups-to-your-advantage/&#34;&gt;blog post by GitLab&lt;/a&gt; on how to take advantage of screw-ups,&#xA;acknowledging mistakes, fixing them, and improving the systems in-place to&#xA;prevent such mistakes is a good way to go about it.&lt;/p&gt;&#xA;&lt;p&gt;Systems needn&amp;rsquo;t always be super complicated things, but just a &lt;a href=&#34;https://punchagan.muse-amuse.in/blog/automation-and-habits/&#34;&gt;little bit of&#xA;automation&lt;/a&gt;, and even &lt;a href=&#34;http://scattered-thoughts.net/blog/2016/01/28/notes-on-the-checklist-manifesto/&#34;&gt;simple checklists&lt;/a&gt; go a long way in improving work-flows and&#xA;making processes less error prone. Google&amp;rsquo;s recovery mechanism definitely&#xA;helped, and gives me confidence to continue working with these user accounts.&#xA;Our server had a system admin pretty soon, and he had automated back-ups and the&#xA;usual stuff in place, for us!&lt;/p&gt;&#xA;&lt;p&gt;The way a team deals with mistakes sets the tone for how the team works, takes&#xA;responsibility, and feels about working together. I still screw up after working&#xA;for about a decade as a developer, and being paid for it. I&amp;rsquo;m sure I&amp;rsquo;ll continue&#xA;to have my screw-ups, even though I&amp;rsquo;d like to have none. What was nice in both&#xA;the cases was the way in which my mentors/bosses reacted, and how calm they were&#xA;about the whole situation.&lt;/p&gt;&#xA;&lt;p&gt;May you have screw-ups that you learn and grow from!&lt;/p&gt;&#xA;&lt;p&gt;PS: Google&amp;rsquo;s &lt;a href=&#34;https://support.google.com/a/answer/6351475?hl=en&amp;amp;ref_topic=6351498&#34;&gt;Data Migration Service&lt;/a&gt; doesn&amp;rsquo;t support legacy Google Suite&#xA;accounts, and I ended up using &lt;a href=&#34;https://github.com/jay0lee/got-your-back&#34;&gt;Got Your Back&lt;/a&gt; to move email from the accounts I&#xA;wanted to delete to the other accounts. It worked pretty smoothly!&lt;/p&gt;&#xA;&lt;div style=&#34;font-size:small;&#34; class=&#34;reviewers&#34;&gt;&#xA;&lt;p&gt;Thanks to Aishwarya, Meghana, &lt;a href=&#34;https://twitter.com/cst2bicycle/&#34;&gt;Tejaa&lt;/a&gt; and &lt;a href=&#34;http://baali.muse-amuse.in&#34;&gt;Shantanu&lt;/a&gt; for reading drafts of this&#xA;post.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Thoughts on Technical Debt</title>
      <link>https://punchagan.muse-amuse.in/blog/thoughts-on-technical-debt/</link>
      <pubDate>Tue, 23 Apr 2019 07:52:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/thoughts-on-technical-debt/</guid>
      <description>&lt;p&gt;I recently watched &lt;a href=&#34;https://www.youtube.com/watch?v=pqeJFYwnkjE&#34;&gt;this short video by Ward Cunningham&lt;/a&gt; where he reflects on the&#xA;history, motivation for, and common misunderstandings of the term Technical&#xA;debt.&lt;/p&gt;&#xA;&lt;p&gt;This post is just some of my reflections on Technical debt, based on ideas and&#xA;thoughts from &lt;a href=&#34;https://en.wikipedia.org/wiki/Ward%5FCunningham&#34;&gt;Ward Cunningham&lt;/a&gt;, &lt;a href=&#34;https://martinfowler.com/&#34;&gt;Martin Fowler&lt;/a&gt; and &lt;a href=&#34;https://en.wikipedia.org/wiki/Robert%5FC.%5FMartin&#34;&gt;Uncle Bob&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-technical-debt&#34;&gt;What is Technical Debt?&lt;/h2&gt;&#xA;&lt;p&gt;Ward Cunningham coined the &amp;ldquo;Techincal Debt&amp;rdquo; metaphor &amp;ndash; he used the metaphor to&#xA;explain the idea of shipping something with a limited understanding of the&#xA;problem, in the hope of gaining a better understanding as more people interact&#xA;with the shipped code.&lt;/p&gt;&#xA;&lt;p&gt;The difference between the understanding of the problem and how the code models&#xA;it is going to slow down the developers. This &amp;ldquo;slowing down&amp;rdquo; is equivalent to&#xA;paying interest, until we take out the time to refactor the code to accurately&#xA;reflect the current understanding of the problem.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-take-on-technical-debt&#34;&gt;Why take on Technical Debt?&lt;/h2&gt;&#xA;&lt;p&gt;When Cunningham says debt, he means shipping code with a partial, unclear or&#xA;even incorrect understanding of the problem and how it should be modeled. You&#xA;are willing to get the code out of the door, to improve this understanding.&lt;/p&gt;&#xA;&lt;p&gt;With borrowed money, sometimes you can do something sooner than you would&#xA;otherwise. Similarly, rushing software out the door can help us get some&#xA;experience with it, which would help gain a better understanding and improve the&#xA;software.&lt;/p&gt;&#xA;&lt;h2 id=&#34;a-mess-is-not-a-debt-or-is-it&#34;&gt;A mess is not a debt, or is it?&lt;/h2&gt;&#xA;&lt;p&gt;Cunningham says that people confuse messily written code with technical debt. He&#xA;is of the opinion that messy code isn&amp;rsquo;t technical debt. He&amp;rsquo;s never in favor of&#xA;shipping bad or messy code. He emphasizes that code that&amp;rsquo;s shipped should always&#xA;be clear enough to refactor easily, when required, even if it doesn&amp;rsquo;t model our&#xA;current understanding of the problem very accurately.&lt;/p&gt;&#xA;&lt;p&gt;Uncle Bob also has a post, on similar lines, where he says, &lt;a href=&#34;https://sites.google.com/site/unclebobconsultingllc/a-mess-is-not-a-technical-debt&#34;&gt;a mess is not a&#xA;technical debt&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;Martin Fowler, on the other hand, argues that the debt metaphor is a useful&#xA;metaphor to think about and to communicate problems in code &amp;mdash; especially to&#xA;non-technical people &amp;mdash; irrespective of the reason for the problem.&lt;/p&gt;&#xA;&lt;p&gt;Not shipping messy code makes sense. But, the debt metaphor is a useful tool to&#xA;talk about existing &amp;ldquo;messy&amp;rdquo; code, compared to just calling it messy code.&#xA;Looking at it as a debt lets you think about whether or not it&amp;rsquo;s worth paying&#xA;off, and if so when, etc. The Technical Debt Quadrant (explained below) further&#xA;classified this debt into 4 classes, which makes it even more useful to identify&#xA;bad code as debt.&lt;/p&gt;&#xA;&lt;h2 id=&#34;technical-debt-quadrant&#34;&gt;Technical Debt Quadrant&lt;/h2&gt;&#xA;&lt;p&gt;Martin Fowler came up with a &lt;a href=&#34;https://martinfowler.com/bliki/TechnicalDebtQuadrant.html&#34;&gt;Technical Debt Quadrant&lt;/a&gt; which incorporates other&#xA;kinds of debt, along with the one Ward Cunningham originally defined.&lt;/p&gt;&#xA;&lt;figure&gt;&lt;img src=&#34;https://martinfowler.com/bliki/images/techDebtQuadrant.png&#34;&gt;&#xA;&lt;/figure&gt;&#xA;&#xA;&lt;p&gt;Fowler comes up with two kinds of divisions of debt &amp;mdash; Reckless vs Prudent and&#xA;Inadvertent vs Deliberate.&lt;/p&gt;&#xA;&lt;p&gt;When Ward says he&amp;rsquo;s against writing bad code, I think he means he&amp;rsquo;s never for&#xA;taking on reckless debt. Uncle Bob&amp;rsquo;s mess is also what Fowler would call&#xA;Reckless debt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Reckless-Deliberate&lt;/strong&gt; debt is code written out of not caring enough about the&#xA;code, or not stopping to think about everything that&amp;rsquo;s going on with the code,&#xA;or just being mentally lazy. Code-reviews seem like one good way to avoid this&#xA;kind of debt.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Reckless-Inadvertent&lt;/strong&gt; debt is something that&amp;rsquo;s hard to prevent. It sounds like&#xA;&lt;a href=&#34;https://www.youtube.com/watch?v=GiPe1OiKQuk&#34;&gt;unknown-unknowns&lt;/a&gt; territory to me. The developers or the team would probably&#xA;benefit from improving their general design skills and/or getting some external&#xA;help as consultants, etc.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Prudent-Deliberate&lt;/strong&gt; debt is what Ward talks about, I think, in his video. You&#xA;know your understanding is not good enough, but you aren&amp;rsquo;t yet sure what&amp;rsquo;s the&#xA;right design is. You may gather more knowledge about the problem while the&#xA;software is out there in the wild and being used.&lt;/p&gt;&#xA;&lt;p&gt;Ward talks about better understanding. But, you may not always realize that your&#xA;understanding is incomplete, when you are shipping the code. This I think would&#xA;put it in the 4th quadrant - &lt;strong&gt;Prudent-Inadvertent&lt;/strong&gt; debt.&lt;/p&gt;&#xA;&lt;h2 id=&#34;is-everything-tech-debt&#34;&gt;Is everything tech debt?&lt;/h2&gt;&#xA;&lt;p&gt;The Tech Debt quadrant seems to make a lot of things seem to fit into the debt&#xA;metaphor, but there are some things that I&amp;rsquo;m not sure about.&lt;/p&gt;&#xA;&lt;p&gt;For example, it can be a significant time investment to update dependencies.&#xA;Often, teams don&amp;rsquo;t update dependencies until it becomes absolutely essential &amp;mdash;&#xA;&amp;ldquo;don&amp;rsquo;t fix what ain&amp;rsquo;t broken&amp;rdquo;. This strategy of postponing of updates, to use&#xA;the time for other things, seems like taking on a debt. But, I&amp;rsquo;m not sure which&#xA;quadrant to put it into.&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-should-i-care&#34;&gt;Why should I care?&lt;/h2&gt;&#xA;&lt;p&gt;Just calling code messy isn&amp;rsquo;t really qualifying the mess, and helping us talk&#xA;about how to tackle it. Thinking about debt while taking decisions seems&#xA;helpful, especially with further classification of debt into the 4 quadrants.&lt;/p&gt;&#xA;&lt;p&gt;It helps think about whether we&amp;rsquo;d like to pay off debts we have taken, and to&#xA;communicate with non-technical people the kind of &amp;ldquo;maintenance&amp;rdquo; or refactoring&#xA;work we plan to take up, and why it is important to do so. The deliberate debt&#xA;concept can be used to think and communicate about things we aren&amp;rsquo;t dealing&#xA;with, right now, in the interest of shipping software quicker.&lt;/p&gt;&#xA;&lt;h2 id=&#34;keeping-track-and-repaying-debt&#34;&gt;Keeping track and repaying debt&lt;/h2&gt;&#xA;&lt;p&gt;If a debt is something we can take on deliberately, and we can take on multiple&#xA;such debts, what would be a good way to keep track of these debts?&lt;/p&gt;&#xA;&lt;p&gt;Keeping a list of these debts that we periodically review, seems like a good&#xA;idea. We check if our understanding has improved from the time we took on a&#xA;debt, and take out time to incorporate it back into the code.&lt;/p&gt;&#xA;&lt;p&gt;This list could just be a bunch of FIXMEs in the code with some detailed&#xA;explanation of the debt, and why it was required, or just a list of issues in&#xA;the issue tracker with a special tag to make it easy to find them.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;div style=&#34;font-size:small;&#34; class=&#34;reviewers&#34;&gt;&#xA;  &lt;div&gt;&lt;/div&gt;&#xA;&lt;p&gt;Thanks to &lt;a href=&#34;https://baali.muse-amuse.in&#34;&gt;Shantanu Choudhary&lt;/a&gt; and &lt;a href=&#34;https://vkrishnaswam.github.io/&#34;&gt;Vivek Krishnaswamy&lt;/a&gt; for reading drafts of this post&#xA;and giving helpful suggestions.&lt;/p&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
    <item>
      <title>Self-care tips for new developers</title>
      <link>https://punchagan.muse-amuse.in/blog/self-care-tips-for-new-developers/</link>
      <pubDate>Wed, 24 Oct 2018 20:14:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/self-care-tips-for-new-developers/</guid>
      <description>&lt;p&gt;A couple of weeks ago, I was at &lt;a href=&#34;https://in.pycon.org/2018/&#34;&gt;PyCon India&lt;/a&gt; &amp;ndash; the 10th edition, the 8th PyCon I&#xA;was attending. It was great to see so many enthusiastic young developers,&#xA;attending their first PyCon. With each year, as the event gets bigger, you see&#xA;more and more of them. Lot of curiosity, and enthusiasm to become better&#xA;programmers.&lt;/p&gt;&#xA;&lt;p&gt;The conference had a whole bunch of talks, catering to people with varied&#xA;interests, at different stages in their career &amp;ndash; war stories, tips and tricks,&#xA;helpful advice on getting started with a library or tool, thoughts on the&#xA;community culture, etc. With each passing year, there are more and more&#xA;proposals for talks, and a lot of good talks have to be left out due to&#xA;constraints on the number of talks that the conference can accommodate.&lt;/p&gt;&#xA;&lt;p&gt;Having said that, I&amp;rsquo;d have liked to see a talk on self-care tips for developers&#xA;&amp;ndash; advice on staying sane and productive in the long run. It is quite common for&#xA;programmers to get burnt-out. I&amp;rsquo;m sure there are some useful lessons to be&#xA;shared by everyone who has been programming professionally for a while &amp;ndash;&#xA;ranging from about a couple of years to many decades!&lt;/p&gt;&#xA;&lt;p&gt;In a hallway conversation, &lt;a href=&#34;https://twitter.com/noufalibrahim/&#34;&gt;Noufal&lt;/a&gt; was telling some of us about the &lt;a href=&#34;https://en.wikipedia.org/wiki/Okinawan_martial_arts&#34;&gt;Okinawa&#xA;martial art&lt;/a&gt; lessons he&amp;rsquo;s been taking - it was inspiring to see how seriously he&#xA;takes the lessons. A lot of programmers that I know, who have been programming&#xA;for a while, have other interests that they pursue quite seriously, to take time&#xA;off from programming. It would be nice to have someone speak about mental health&#xA;and self care in a talk, rather than hope that people pick it up in hallway&#xA;conversations. Explicit is better than implicit.&lt;/p&gt;&#xA;&lt;p&gt;I was considering doing a lightning talk on this, but I didn&amp;rsquo;t get in touch with&#xA;the organizers early enough to get a slot. So, here&amp;rsquo;s a blog post.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;: Not all of these are things I&amp;rsquo;m good at doing consistently, but&#xA;they are things that have at some point helped me. This post is also a way for&#xA;me to write down things that I (or others) can come back to whenever necessary.&lt;/p&gt;&#xA;&lt;h2 id=&#34;take-breaks&#34;&gt;Take breaks&lt;/h2&gt;&#xA;&lt;p&gt;We are often so engrossed in getting something to work, that we lose track of&#xA;time &amp;ndash; slumping in our chairs for hours on end, forgetting to eat, hydrate or&#xA;move around.&lt;/p&gt;&#xA;&lt;p&gt;Our bodies weren&amp;rsquo;t made for this &amp;ndash; we were built to move around. Also, stepping&#xA;away from the problem for a bit, after wrestling with it for a while, brings a&#xA;fresh perspective and new ideas.&lt;/p&gt;&#xA;&lt;p&gt;You could use a tool like &lt;a href=&#34;http://www.workrave.org/&#34;&gt;workrave&lt;/a&gt; to remind you to take regular breaks and&#xA;stretch. Or use a &lt;a href=&#34;https://francescocirillo.com/pages/pomodoro-technique&#34;&gt;Pomodoro timer&lt;/a&gt;. Another trick is to drink keep drinking water&#xA;regularly, so you are forced to get up and take a piss, every once in a while.&lt;/p&gt;&#xA;&lt;h2 id=&#34;hydrate-eat-and-sleep&#34;&gt;Hydrate, Eat and Sleep&lt;/h2&gt;&#xA;&lt;p&gt;Being dehydrated can make one feel tired and sleepy, making it hard to focus&#xA;well. Same goes for being hungry and sleep-deprived. Not having enough glucose&#xA;in your blood has been &lt;a href=&#34;http://www.pnas.org/content/108/17/6889&#34;&gt;shown&lt;/a&gt; to cause people to make bad decisions.&lt;/p&gt;&#xA;&lt;p&gt;Mental work uses up a lot of energy, even if we seem to be just sitting around&#xA;all day, and not expending much more energy than sleeping. It is important to&#xA;feel good physically to work effectively.&lt;/p&gt;&#xA;&lt;p&gt;You could have a bottle of water next to you, that you frequently drink from and&#xA;keep re-filling at breaks. Don&amp;rsquo;t skip on your lunch to use that extra half an&#xA;hour being productive. Keeping some snack accessible for you to eat towards the&#xA;end of the day, when you are tired, helps. Use a sleep tracker or just roughly&#xA;track sleep each night manually. Make sure you are getting enough of it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;invest-in-a-good-set-up&#34;&gt;Invest in a good set-up&lt;/h2&gt;&#xA;&lt;p&gt;We spend around half of our waking time at work - over a life time, that&amp;rsquo;s a lot&#xA;of time! Sitting in a bad posture, or doing a only-slightly-uncomfortable action&#xA;over and over, can easily grow into bigger problems in the long run.&lt;/p&gt;&#xA;&lt;p&gt;You deserve good quality equipment, that &amp;ldquo;fits&amp;rdquo; you well. Get yourself a good&#xA;keyboard and mouse, an external monitor, or whatever it is that you think will&#xA;make your body thank you. If you end-up working a lot from your home office,&#xA;invest in a good chair and a table.&lt;/p&gt;&#xA;&lt;h2 id=&#34;sunlight-and-exercise&#34;&gt;Sunlight &amp;amp; Exercise&lt;/h2&gt;&#xA;&lt;p&gt;Being locked up in our office buildings all day doesn&amp;rsquo;t help with how much&#xA;exposure we get to the sun. Not getting enough sunlight regularly can effect us&#xA;both mentally and physically. Same goes for exercise. Getting some exercise&#xA;everyday has been shown to have significant mental and physical health benefits.&lt;/p&gt;&#xA;&lt;p&gt;You can start playing a sport, if hitting the gym or doing something alone seems&#xA;like a chore. Playing a team sport helps even more since there are other people&#xA;you are accountable to. Try to get some sunlight every morning, even if it is&#xA;just standing out in the sun, while you drink your coffee.&lt;/p&gt;&#xA;&lt;h2 id=&#34;take-vacations&#34;&gt;Take Vacations&lt;/h2&gt;&#xA;&lt;p&gt;Switch off completely, and give your body and mind the rest they deserve. The&#xA;break not only lets you rejuvenate physically, but also gives your brain the&#xA;time to synthesize all the inputs it has, and come back with surprising ideas or&#xA;solutions to problems that have been troubling you for a while.&lt;/p&gt;&#xA;&lt;p&gt;The importance of taking a break is often forgotten, when we have so much to do.&#xA;Honestly, I&amp;rsquo;m not very good at taking regular vacations, myself.&lt;/p&gt;&#xA;&lt;p&gt;But, having a fixed time every year to take a vacation is something that I&amp;rsquo;ve&#xA;seen working. For example, 2 weeks around your birthday every year, you can&#xA;decide to take a vacation.&lt;/p&gt;&#xA;&lt;h2 id=&#34;do-other-things&#34;&gt;Do other things&lt;/h2&gt;&#xA;&lt;p&gt;We get into the game because we are really excited by the things we can build by&#xA;flipping bits. We get so obsessed with it, that we lose ourselves in it,&#xA;oblivious to the world outside. All the people we hangout with are people very&#xA;similar to us.&lt;/p&gt;&#xA;&lt;p&gt;Often, we are building stuff for people very unlike us. It&amp;rsquo;s very helpful to see&#xA;the world from a different perspective than ours. Also, there is only so much we&#xA;can express through code. There is a whole lot of us that can be expressed in&#xA;other ways.&lt;/p&gt;&#xA;&lt;p&gt;Pick up a &lt;a href=&#34;https://thatteidlikaalsoup.team/&#34;&gt;team sport&lt;/a&gt;, do improv/stand-up, draw or paint, write, learn a martial&#xA;art, join a cross fit gym &amp;ndash; anything that you find interesting, other than&#xA;writing code. Hangout with people who do very different things everyday than&#xA;what you do. Their completely different perspective at life will make you a&#xA;better programmer and a better person.&lt;/p&gt;&#xA;&lt;h2 id=&#34;avoid-distractions&#34;&gt;Avoid distractions&lt;/h2&gt;&#xA;&lt;p&gt;The internet can be &lt;a href=&#34;https://xkcd.com/477/&#34;&gt;so distracting&lt;/a&gt;! But, as developers, we tend to be constantly&#xA;connected, leaving ourselves vulnerable to all this distraction. All these&#xA;distractions can lead to very &lt;a href=&#34;https://heeris.id.au/2013/this-is-why-you-shouldnt-interrupt-a-programmer/&#34;&gt;expensive context switches&lt;/a&gt;.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve found getting into, and working in flow-states to be enormously satisfying.&#xA;What I&amp;rsquo;m actually working on, doesn&amp;rsquo;t matter very much when I&amp;rsquo;m to deeply focus&#xA;on something I want to be doing.&lt;/p&gt;&#xA;&lt;p&gt;Creating an environment for yourself, where its easy to get into these states,&#xA;is totally worth it. I&amp;rsquo;ve found using &lt;a href=&#34;https://francescocirillo.com/pages/pomodoro-technique&#34;&gt;Pomodoros&lt;/a&gt; to be quite helpful, when I&amp;rsquo;m&#xA;feeling distracted. Shutting off the Internet, or using a tool like&#xA;&lt;a href=&#34;https://github.com/viccherubini/get-shit-done&#34;&gt;get-shit-done&lt;/a&gt; helps with stopping myself from getting distracted by cat videos&#xA;on the internet. Turning off all notifications on my phone and computer is&#xA;another thing that is quite effective I also find it helpful to not be able to&#xA;constantly have sight of the clock on my computer - so I work with all my&#xA;windows full-screen. &lt;a href=&#34;https://www.journals.uchicago.edu/doi/full/10.1086/691462&#34;&gt;Leaving the phone in another room&lt;/a&gt; or in my bag works great,&#xA;too. You can find a lot more tips on the internet, if these tricks aren&amp;rsquo;t up&#xA;your alley.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;p&gt;If you see your team over-working themselves, and holding exhaustion as a badge&#xA;of honour, please be the person to strike conversations around self care. Your&#xA;team will thank you.&lt;/p&gt;&#xA;&lt;p&gt;I&amp;rsquo;ve only listed down some of the things that I&amp;rsquo;ve found helpful. But, I hope&#xA;this serves as a good starting point. Also, do take a look at &lt;a href=&#34;http://selfcare.tech/&#34;&gt;selfcare.tech&lt;/a&gt; for&#xA;more resources and advice.&lt;/p&gt;&#xA;&lt;p&gt;Thanks Akilesh Mani and &lt;a href=&#34;http://baali.muse-amuse.in/&#34;&gt;Shantanu Choudhary&lt;/a&gt; for&#xA;reading drafts of this and giving helpful suggestions.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Automation and Habits</title>
      <link>https://punchagan.muse-amuse.in/blog/automation-and-habits/</link>
      <pubDate>Wed, 15 Aug 2018 18:44:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/automation-and-habits/</guid>
      <description>&lt;p&gt;We usually see automation as a thing we do to save time. But, there&amp;rsquo;s more to it&#xA;than just saving time.&lt;/p&gt;&#xA;&lt;p&gt;Several years ago, I built a tool called &lt;a href=&#34;https://github.com/org2blog/org2blog&#34;&gt;org2blog&lt;/a&gt; that let me write blog posts&#xA;in my text-editor, and publish them with just a couple of key-strokes. I spent&#xA;several man-weeks getting it to work well &amp;ndash; adding lots of features including&#xA;image uploads. The time I spent on developing and maintaining it dwarfs the time&#xA;saved by automation.&lt;/p&gt;&#xA;&lt;p&gt;But, in the three months following this, I published 30 blog posts &amp;ndash; as many as&#xA;I would&amp;rsquo;ve otherwise published during the whole year. &lt;code&gt;org2blog&lt;/code&gt; wasn&amp;rsquo;t just&#xA;saving time &amp;ndash; it drastically reduced the friction to publish new posts. On some&#xA;occasions where I would&amp;rsquo;ve previously avoided writing a new post, I ended up&#xA;writing one because &lt;code&gt;org2blog&lt;/code&gt; made it a breeze. I could focus on actually&#xA;writing the post and not let my attention be hijacked by the repetitive and&#xA;boring steps that were previously required to start writing a new post and&#xA;publish it.&lt;/p&gt;&#xA;&lt;p&gt;Automation abstracts away the details that we would&amp;rsquo;ve otherwise had to spend&#xA;our attention on. This reduced mental overload encourages us to &amp;ldquo;do the right&#xA;thing&amp;rdquo;, when we would&amp;rsquo;ve otherwise been lazy and taken the easier route of not&#xA;doing something. No wonder, Douglas Adams &lt;a href=&#34;https://www.goodreads.com/quotes/587524-i-have-a-well-deserved-reputation-for-being-something-of-a&#34;&gt;confessed&lt;/a&gt; to happily spending a day on&#xA;automating something that would&amp;rsquo;ve taken him ten seconds.&lt;/p&gt;&#xA;&lt;p&gt;When extended to a team setting this would mean our (automation) tools nudging&#xA;everyone on the team towards better habits and behavior. We must recognize this&#xA;and treat our tools as an integral part of our team, and not just time-savers.&#xA;The Zulip &lt;a href=&#34;https://github.com/zulip/zulip/tree/master/tools&#34;&gt;community&lt;/a&gt; is a good example of this. Tim, the lead developer of Zulip,&#xA;pays particular attention to developer workflows in Zulip and is constantly on&#xA;the lookout to automate tasks and/or eliminate unnecessary tasks, to make it&#xA;easier for everyone to &amp;ldquo;do things right&amp;rdquo;.&lt;/p&gt;&#xA;&lt;p&gt;The tools we build aren&amp;rsquo;t just saving us time, but are changing us back.&#xA;Building better tools helps build better teams. Go forth and automate!&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;PS:&lt;/strong&gt; This post is inspired from &lt;a href=&#34;https://www.youtube.com/watch?v=Lbcyyu8XB%5FY&#34;&gt;this talk by Jessica Kerr&lt;/a&gt; where, among other&#xA;things, she talks about Automation and some reasons for doing it.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;PPS:&lt;/strong&gt; &lt;a href=&#34;https://www.facebook.com/jasonlsilva/videos/1735277136736564/UzpfSTE1NzgwNTI3MDU3OTIzNDI6MTg2OTEyNDY5NjY4NTE0MA/&#34;&gt;Jason Silva talks&lt;/a&gt; about humans as being a technology creating species,&#xA;and how the tools we create change us, and how we change them to change us&#xA;further. This seems a lot like the idea in this post, except at a much larger&#xA;scale.&lt;/p&gt;&#xA;&lt;p&gt;Thanks to &lt;a href=&#34;http://baali.muse-amuse.in&#34;&gt;Shantanu&lt;/a&gt; for reviewing this blog post.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Error messages and new users</title>
      <link>https://punchagan.muse-amuse.in/blog/error-messages-and-new-users/</link>
      <pubDate>Tue, 17 May 2016 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/error-messages-and-new-users/</guid>
      <description>&lt;p&gt;I was helping a friend of mine setup &lt;a href=&#34;http://jajoosam.github.io&#34;&gt;his blog&lt;/a&gt; and we were trying to use &lt;a href=&#34;http://hexo.io&#34;&gt;Hexo&lt;/a&gt; &amp;ndash;&#xA;a static site generator.  We chose a Javascript based tool since he&amp;rsquo;s trying to&#xA;learn Javascript.  I skimmed through active Javascript projects in &lt;a href=&#34;https://staticsitegenerators.net&#34;&gt;this list&lt;/a&gt;&#xA;and finally zeroed down upon Hexo based on its popularity.  I promised to help&#xA;my friend to set this up, but he first tried to do it on his own and got back&#xA;to me after an hour or so, quite frustrated and almost on the verge of giving&#xA;up setting it up.  I didn&amp;rsquo;t expect this from a tool that had so many stars,&#xA;forks, plugins and so much active development.&lt;/p&gt;&#xA;&lt;p&gt;We finally got it working, but we found that the error messages were horrendous&#xA;&amp;ndash; even for someone who has been using free and open-source tools for a while&#xA;now.  Printing out errors from compiler or interpreter directly along with the&#xA;stack trace is almost always the worst thing to do for a tool/utility (as&#xA;opposed to an API or library).  The stack trace is definitely useful, for&#xA;developers trying to build upon or improve your tool.  Have a debug or&#xA;development mode where developers can get all the information they need.&lt;/p&gt;&#xA;&lt;p&gt;If you care about your users, especially new users, make sure you spend&#xA;sufficient time on showing human-readable messages. If possible list the&#xA;possible causes for every error along with tips for troubleshooting.&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Learning about Spaced Repetition, SuperMemo, Org-drill, et al.</title>
      <link>https://punchagan.muse-amuse.in/blog/learning-about-spaced-repetition-supermemo-org-drill-et-al/</link>
      <pubDate>Fri, 24 Oct 2014 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/learning-about-spaced-repetition-supermemo-org-drill-et-al/</guid>
      <description>&lt;p&gt;I have been reading a bunch of articles on the SuperMemo site (including the&#xA;&lt;a href=&#34;http://www.supermemo.com/english/ol.htm&#34;&gt;original thesis&lt;/a&gt; of P. A. Wozniack, the creator of SuperMemo).  I initially&#xA;started off trying to understand the algorithms SM2,5 and 8 which org-drill&#xA;implements, but reading the articles has given me a lot of general background&#xA;and theory on how memory works, and why SuperMemo is as effective as it is (for&#xA;those who stick with it).  This blog post is an attempt to summarize and&#xA;capture what I have read in all those &lt;a href=&#34;http://www.supermemo.com/english/contents.htm&#34;&gt;articles&lt;/a&gt;, and not get lost in them.  I&#xA;would recommend reading the thesis and the suggested reading there, yourself,&#xA;but if you really don&amp;rsquo;t want to &amp;ndash; this blog post + the summary in &lt;a href=&#34;http://www.supermemo.com/articles/20rules.htm#Prioritize&#34;&gt;here&lt;/a&gt;, and&#xA;&lt;a href=&#34;http://www.supermemo.com/articles/decalog.htm#decalog&#34;&gt;here&lt;/a&gt; would be a good alternative.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Memory works by repetition.  Each time you recall a fact, the time it takes&#xA;for the memory to fade increases.  Spaced repetition is the idea of repeating&#xA;items, just when you are about to forget them &amp;ndash; trying to optimize the time&#xA;spent on learning, as well as the retention of learned material.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Prioritization of the items we need to learn is key to being able to stick to&#xA;Spaced repetition.  Beginners tend to be over-enthusiastic about the&#xA;technique and fill up their system with stuff that they don&amp;rsquo;t really care&#xA;about.  Applicability of the knowledge you are trying to gain, is a good test&#xA;for whether or not it goes into your system.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Each version of SuperMemo comes with a slightly modified (on most occassions,&#xA;improved!) algorithm.  SM2, SM5, &amp;hellip; refer to these algorithms. Org-drill&#xA;currently supports only sm2,5 and 8.  It may be worth looking at sm15/16 and&#xA;seeing if it can be implemented and is worth doing.  In any case, using any&#xA;of these is &lt;strong&gt;way&lt;/strong&gt; better than not using Spaced repetition at all.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Understanding what we are trying to learn goes a long way in helping&#xA;memory. It is, therefore, good to start with basic material. People have been&#xA;surprised by how easily the advanced stuff fell into place, once they had the&#xA;basics covered.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Keep items in the system simple.  Stick to the minimum information&#xA;principle.  Keeping it simple, doesn&amp;rsquo;t mean you leave out on learning the&#xA;complex stuff; instead break it into simpler components.  Simpler items has&#xA;the following advantages:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Simple is easier to remember.&lt;/li&gt;&#xA;&lt;li&gt;Simpler items are easier to schedule.  You get more resolution to figure&#xA;out what the problem areas are.&lt;/li&gt;&#xA;&lt;li&gt;Simple makes brings in redundancy automatically.  And &lt;a href=&#34;http://en.wikipedia.org/wiki/Wikipedia:Redundancy_is_good&#34;&gt;redundancy is good&lt;/a&gt;&#xA;for memory, just like it is for managing hardware failure.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Keep learning fun!  Don&amp;rsquo;t make review sessions a chore.  Think about the&#xA;material you are reviewing. Edit/delete/improve items based on your reviews,&#xA;then and there. Stay active.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;It is useful to add a link to the source of the items added to your system,&#xA;considering that you wish to use the system over a long period of time&#xA;(ideally, the rest of your life!)&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Prioritize, add examples, appeal to your emotional state, link to existing&#xA;knowledge, use images. Anything else that works for you!  Use all of these&#xA;techniques, that work well and you probably already use in everyday life, in&#xA;the items you add to your system, to make them easier to recall.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Being physically fit and healthy is important for being so&#xA;mentally. Exercise, sleep, eat well, avoid caffeine.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;Try &lt;a href=&#34;http://www.supermemo.com/help/read.htm&#34;&gt;incremental&lt;/a&gt; &lt;a href=&#34;http://www.supermemo.com/articles/devour.htm&#34;&gt;reading&lt;/a&gt;, as an input source of items into your memory system.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Learning to use Org-drill</title>
      <link>https://punchagan.muse-amuse.in/blog/learning-to-use-org-drill/</link>
      <pubDate>Tue, 14 Oct 2014 00:07:04 -0400</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/learning-to-use-org-drill/</guid>
      <description>&lt;p&gt;Org-drill is an Org-mode extension that provides spaced-repetition and&#xA;flash-card functionality.  It has a &lt;a href=&#34;http://orgmode.org/worg/org-contrib/org-drill.html&#34;&gt;wonderful documentation on Worg&lt;/a&gt;, but&#xA;somehow I couldn&amp;rsquo;t get myself to read the whole document, and setup org-drill,&#xA;until now.&lt;/p&gt;&#xA;&lt;p&gt;The setup is quite straight forward, once you have org-mode along with the&#xA;&lt;code&gt;contrib&lt;/code&gt; packages.  Just &lt;code&gt;(require &#39;org-drill)&lt;/code&gt;, and you are all set!  To add&#xA;a new card, all you need to do is add a &lt;code&gt;:drill:&lt;/code&gt; tag to the items you wish to&#xA;&amp;ldquo;Org-drill&amp;rdquo;.  You can start a review session with simply &lt;kbd&gt;M-x org-drill&lt;/kbd&gt;.  You&#xA;will be shown flash cards, and you can rate how correct and comfortable you&#xA;were, in answering the questions.  Based on your responses, the cards are&#xA;scheduled for review.  Start another review session, whenever you need one!&lt;/p&gt;&#xA;&lt;p&gt;What I could only understand once I got myself to read the whole document was&#xA;that:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The default scope of a drill session is the current file.  But, you can start&#xA;sessions with scopes like current tree, current directory, or a specified&#xA;list of files. This is super-useful!&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;&#xA;&lt;p&gt;The review sessions are not automatically scheduled, based on when you&#xA;schedule failed flash-cards.  Scheduling the review for a card only sets a&#xA;due-date for them, and effects, what you are asked in your next session.&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Cram mode and incremental reading are also things I want to try, as I go along.&lt;/p&gt;&#xA;&lt;p&gt;Happy Learning!&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Best Practices for Scientific Computing</title>
      <link>https://punchagan.muse-amuse.in/blog/best-practices-for-scientific-computing/</link>
      <pubDate>Mon, 24 Dec 2012 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/best-practices-for-scientific-computing/</guid>
      <description>&lt;p&gt;Shantanu and I gave a short talk titled &amp;ldquo;Software Carpentry for&#xA;Scientists&amp;rdquo; for the graduate students of Chemical Engineering&#xA;department, IISc, this Friday.  We gave a short introduction to&#xA;Git, TDD, Numpy/Scipy, etc and mentioned a few things from Greg&#xA;Wilson et al&amp;rsquo;s paper.&lt;/p&gt;&#xA;&lt;p&gt;I promised to revert to them with links to a few resources.  I&#xA;figured it would be more beneficial, if I just put it in a&#xA;publicly available place.&lt;/p&gt;&#xA;&lt;p&gt;A summary of the paper by Greg Wilson et. al., is below.&lt;/p&gt;&#xA;&lt;h2 id=&#34;useful-resources&#34;&gt;Useful resources&lt;/h2&gt;&#xA;&lt;h3 id=&#34;software-carpentry&#34;&gt;Software Carpentry&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Paper by Greg Wilson et. al.&lt;/li&gt;&#xA;&lt;li&gt;Software Carpentry&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;git-and-version-control&#34;&gt;Git &amp;amp; version control&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://bit.ly/VfbOww&#34;&gt;http://bit.ly/VfbOww&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://karlagius.com/2009/01/09/version-control-for-the-masses/&#34;&gt;http://karlagius.com/2009/01/09/version-control-for-the-masses/&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://try.github.com&#34;&gt;http://try.github.com&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://betterexplained.com/articles/a-visual-guide-to-version-control/&#34;&gt;http://betterexplained.com/articles/a-visual-guide-to-version-control/&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://betterexplained.com/articles/intro-to-distributed-version-control-illustrated/&#34;&gt;http://betterexplained.com/articles/intro-to-distributed-version-control-illustrated/&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;tdd&#34;&gt;TDD&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://software-carpentry.org/4_0/test/index.html&#34;&gt;http://software-carpentry.org/4_0/test/index.html&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;https://www.google.co.in/?q=TDD+matlab&#34;&gt;https://www.google.co.in/?q=TDD+matlab&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;scipy&#34;&gt;SciPy&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://scipy-lectures.github.com&#34;&gt;http://scipy-lectures.github.com&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;python&#34;&gt;Python&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://docs.python.org/tutorial&#34;&gt;http://docs.python.org/tutorial&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h3 id=&#34;gui-tools-in-python&#34;&gt;GUI tools in Python&lt;/h3&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://code.enthought.com/projects/traits/docs/html/tutorials/traits_ui_scientific_app.html&#34;&gt;http://code.enthought.com/projects/traits/docs/html/tutorials/traits_ui_scientific_app.html&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://docs.enthought.com/traits&#34;&gt;http://docs.enthought.com/traits&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://docs.enthought.com/traitsui&#34;&gt;http://docs.enthought.com/traitsui&lt;/a&gt;&lt;/li&gt;&#xA;&lt;li&gt;&lt;a href=&#34;http://docs.enthought.com/enaml&#34;&gt;http://docs.enthought.com/enaml&lt;/a&gt;&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;h2 id=&#34;summary-of-paper-by-greg-wilson-et-dot-al-dot&#34;&gt;Summary of paper by Greg Wilson et. al.&lt;/h2&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Write programs for people, not computers&#xA;&lt;ul&gt;&#xA;&lt;li&gt;a program should not require its readers to hold more than a&#xA;handful of facts in memory at once.&lt;/li&gt;&#xA;&lt;li&gt;names should be consistent, distinctive and meaningful.&lt;/li&gt;&#xA;&lt;li&gt;code style and formatting should be consistent.&lt;/li&gt;&#xA;&lt;li&gt;all aspects of software development should be broken down&#xA;into tasks roughly an hour long&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Automate repetitive tasks&#xA;&lt;ul&gt;&#xA;&lt;li&gt;rely on the computer to repeat tasks&lt;/li&gt;&#xA;&lt;li&gt;save recent commands in a file for re-use&lt;/li&gt;&#xA;&lt;li&gt;use a build to automate scientific work-flows&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Use the computer to record history&#xA;&lt;ul&gt;&#xA;&lt;li&gt;software tools should be used to track computational work&#xA;automatically.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Make incremental changes&#xA;&lt;ul&gt;&#xA;&lt;li&gt;work in small steps with frequent feedback and course&#xA;correction&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Use version control&#xA;&lt;ul&gt;&#xA;&lt;li&gt;use a version control system&lt;/li&gt;&#xA;&lt;li&gt;everything that has been created manually should be put in&#xA;version control&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Don&amp;rsquo;t repeat yourself (or others)&#xA;&lt;ul&gt;&#xA;&lt;li&gt;every piece of data must have a single authoritative&#xA;representation in the system&lt;/li&gt;&#xA;&lt;li&gt;code should be modularized rather than copied and pasted&lt;/li&gt;&#xA;&lt;li&gt;re-use code instead of rewriting it&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Plan for mistakes&#xA;&lt;ul&gt;&#xA;&lt;li&gt;add assertions to programs to check their operation&lt;/li&gt;&#xA;&lt;li&gt;use an off-the-shelf unit testing library&lt;/li&gt;&#xA;&lt;li&gt;use all available oracles when testing programs&lt;/li&gt;&#xA;&lt;li&gt;turn bugs into test cases&lt;/li&gt;&#xA;&lt;li&gt;use a symbolic debugger&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Optimize software only after it works correctly&#xA;&lt;ul&gt;&#xA;&lt;li&gt;use a profiler to identify bottlenecks&lt;/li&gt;&#xA;&lt;li&gt;write code in the highest-level language possible&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Document design and purpose, not mechanics&#xA;&lt;ul&gt;&#xA;&lt;li&gt;document interfaces and reasons, not implementations&lt;/li&gt;&#xA;&lt;li&gt;refactor code instead of explaining how it works&lt;/li&gt;&#xA;&lt;li&gt;embed the documentation for a piece of software in that software&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;li&gt;Collaborate&#xA;&lt;ul&gt;&#xA;&lt;li&gt;use pre-merge code reviews&lt;/li&gt;&#xA;&lt;li&gt;use pair programming when bringing someone new up to speed&#xA;and when tackling particularly tricky problems&lt;/li&gt;&#xA;&lt;li&gt;use an issue tracking tool&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;</description>
    </item>
    <item>
      <title>3 tips for those shipping (commercial) apps</title>
      <link>https://punchagan.muse-amuse.in/blog/3-tips-for-those-shipping-commercial-apps/</link>
      <pubDate>Wed, 28 Nov 2012 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/3-tips-for-those-shipping-commercial-apps/</guid>
      <description>&lt;p&gt;Here are some very generic (and paraphrased) notes from a short&#xA;talk today, by Deepankar Sharma.&lt;/p&gt;&#xA;&lt;ol&gt;&#xA;&lt;li&gt;Whenever you release a new major version, make sure you keep a&#xA;copy of the whole &amp;ldquo;ecosystem&amp;rdquo; to be able to run it whenever you&#xA;want.  At any point in time, you should be able to run any&#xA;version of your software.&lt;/li&gt;&#xA;&lt;li&gt;When writing benchmarks/tests/etc., try and ensure that you&#xA;cover a broad spectrum of test data, to try and replicate the&#xA;different types of data that users could possibly have.&lt;/li&gt;&#xA;&lt;li&gt;Don&amp;rsquo;t develop applications with modes.  Be very careful before&#xA;you add a new mode to your application, effectively adding one&#xA;more code path to maintain.&lt;/li&gt;&#xA;&lt;li&gt;(Bonus) Beware of too much extensibility&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;</description>
    </item>
    <item>
      <title>GetHub: Chrome Notifications for Github updates</title>
      <link>https://punchagan.muse-amuse.in/blog/gethub-chrome-notifications-for-github-updates/</link>
      <pubDate>Wed, 02 Mar 2011 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/gethub-chrome-notifications-for-github-updates/</guid>
      <description>&lt;p&gt;Over the last two days, I hacked up my first Chrome extension.&#xA;I&amp;rsquo;ve been using Chrome only for the past couple of weeks or so and&#xA;I begin to like it, though some of the extensions aren&amp;rsquo;t as mature&#xA;as I would&amp;rsquo;ve liked.&lt;/p&gt;&#xA;&lt;p&gt;The original idea was floated by my friend,  Madhu, and Lee helped&#xA;me quite a bit, while I was working on it.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-does-it-do&#34;&gt;What does it do?&lt;/h2&gt;&#xA;&lt;p&gt;It is a simple extension, that shows pop-ups, whenever there is&#xA;an update in your GitHub &amp;ldquo;Wall&amp;rdquo; (yes, this is a Facebook world)&#xA;or News Feed as they call it.&lt;/p&gt;&#xA;&lt;p&gt;After installation, you will need to save your &lt;code&gt;username&lt;/code&gt; and&#xA;&lt;code&gt;token&lt;/code&gt; for the extension to work.&lt;/p&gt;&#xA;&lt;h2 id=&#34;where-to-get-it&#34;&gt;Where to get it?&lt;/h2&gt;&#xA;&lt;p&gt;Presently, you will need to get it from GitHub.&lt;/p&gt;&#xA;&lt;p&gt;I might add it to the Chrome Web Store, once I see more people&#xA;using it.  I couldn&amp;rsquo;t justify, to myself, paying the initial&#xA;one-time verification fee that Google asks for.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;UPDATE&lt;/strong&gt;: &lt;span class=&#34;timestamp-wrapper&#34;&gt;&lt;span class=&#34;timestamp&#34;&gt;[2011-03-04 Fri] &lt;/span&gt;&lt;/span&gt; Added GetHub to the store&lt;/p&gt;&#xA;&lt;h2 id=&#34;comments-and-feedback&#34;&gt;Comments and Feedback&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Feel free to write to me at &lt;code&gt;punchagan+gethub@jeemail.com&lt;/code&gt;&lt;/li&gt;&#xA;&lt;li&gt;Or file issues at GitHub.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Happy GitHubbing!&lt;/p&gt;&#xA;</description>
    </item>
    <item>
      <title>Richard Stallman in IIT-Bombay</title>
      <link>https://punchagan.muse-amuse.in/blog/richard-stallman-in-iit-bombay/</link>
      <pubDate>Wed, 01 Sep 2010 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/richard-stallman-in-iit-bombay/</guid>
      <description>&lt;p&gt;RMS will be in IIT-Bombay on the 6th of this month. He will &amp;ldquo;speak&#xA;about the goals and philosophy of the Free Software Movement, and&#xA;the status and history of the GNU operating system, which in&#xA;combination with the kernel Linux is now used by tens of millions&#xA;of users world-wide. &amp;quot;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Date:&lt;/strong&gt; 6th September, 2010&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Time:&lt;/strong&gt; 8:30 P.M&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Venue:&lt;/strong&gt; PC Saxena Auditorium, IIT Bombay&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Sage Days 25, Mumbai, India</title>
      <link>https://punchagan.muse-amuse.in/blog/sage-days-25-mumbai-india/</link>
      <pubDate>Wed, 21 Jul 2010 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/sage-days-25-mumbai-india/</guid>
      <description>&lt;h2 id=&#34;what-is-sage-days&#34;&gt;What is &amp;lsquo;Sage Days&amp;rsquo;?&lt;/h2&gt;&#xA;&lt;p&gt;Sage Days is a confluence of present and prospective SAGE Users and&#xA;Developers. It is an opportunity to come together to share ideas,&#xA;brainstorm and hack on Sage. Sage Days 25 is the 25th version of Sage&#xA;Days, and is being organized in Mumbai, India. In order to cater to an&#xA;Indian audience and scenario, this version has been tweaked&#xA;slightly. Sage Days 25 has beginner level tutorials, in addition to&#xA;the usual talks and sprints, to help new users get started with Sage&#xA;and help promote the use of Sage in India.&lt;/p&gt;&#xA;&lt;h2 id=&#34;what-is-sage&#34;&gt;What is Sage?&lt;/h2&gt;&#xA;&lt;p&gt;Sage is a free, open-source mathematics software system licensed under&#xA;the GPL. It combines the power of numerous existing open-source&#xA;packages into a common Python-based interface. It&amp;rsquo;s mission is to&#xA;create a &amp;ldquo;viable free open source alternative to Magma, Maple,&#xA;Mathematica and Matlab&amp;rdquo;. Sage has tools for a broad range of&#xA;mathematical areas like Linear Algebra, Calculus, Symbolic Math,&#xA;Plotting, Rings &amp;amp; Groups, Graph Theory, Number Theory and&#xA;Cryptography. Essentially, &amp;ldquo;it can do anything from mapping a&#xA;12-dimensional object to calculating rainfall patterns under global&#xA;warming&amp;rdquo; - as Science Daily puts it . Eager to get started? Start&#xA;here. Apart from being feature rich, it&amp;rsquo;s usability is one of it&amp;rsquo;s&#xA;greatest strengths. Sage Notebook, a web-interface for all the math&#xA;you&amp;rsquo;ll ever want to do, is really the killer feature! As the Sage&#xA;Marketing page says, &amp;ldquo;The SAGE GUI surely works on your computer box,&#xA;because it just runs in Firefox!&amp;rdquo;. Try it Now!&lt;/p&gt;&#xA;&lt;h2 id=&#34;why-should-you-attend&#34;&gt;Why should you attend?&lt;/h2&gt;&#xA;&lt;p&gt;Sage Days 25 is being attended by the creator and lead developer of&#xA;Sage, Prof. William Stein. It will also be attended by other&#xA;developers of Sage. This would be a great opportunity to meet and&#xA;interact with them! The conference will be attended by a plethora of&#xA;enthusiastic people from all over the country who use Sage or are&#xA;interested in doing so. The conference will also see the presence of&#xA;many mathematicians interested in software. Who knows, you may run&#xA;into someone you&amp;rsquo;d want to collaborate with, for your future work!&#xA;This event will be a great learning experience, if you are even&#xA;remotely interested in math and software for it!&lt;/p&gt;&#xA;&lt;h2 id=&#34;when-and-where&#34;&gt;When and Where?&lt;/h2&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Venue: IIT-Bombay, Mumbai, India&lt;/li&gt;&#xA;&lt;li&gt;Dates: August 9-12, 2010&lt;/li&gt;&#xA;&lt;li&gt;Tentative Schedule&lt;/li&gt;&#xA;&lt;li&gt;Register Here&lt;/li&gt;&#xA;&lt;li&gt;Click here for more info&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;</description>
    </item>
    <item>
      <title>Software Freedom Day</title>
      <link>https://punchagan.muse-amuse.in/blog/software-freedom-day/</link>
      <pubDate>Sun, 21 Sep 2008 00:00:00 +0530</pubDate>
      <guid>https://punchagan.muse-amuse.in/blog/software-freedom-day/</guid>
      <description>&lt;p&gt;Three Cheers to &amp;lsquo;Free Software&amp;rsquo;!&lt;/p&gt;&#xA;&lt;p&gt;A toast for GNU on its 25th Birthday!&lt;sup id=&#34;fnref:1&#34;&gt;&lt;a href=&#34;#fn:1&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;&#xA;&lt;p&gt;If you intend to ask, what I did on this day, I have nothing to show. I haven&amp;rsquo;t done anything that&amp;rsquo;s tangible but yes, I have re-dedicated myself to the idea of Free Software.&#xA;This post intends to shed some light on a few things (if not for the benefit of others, just as a reminder for myself)&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;Free Software is a matter of liberty, not price. I&amp;rsquo;ve often been&#xA;in a position that required me to correct people. &amp;lsquo;Free&#xA;Software&amp;rsquo; is software that&amp;rsquo;s free as in free speech and not free&#xA;beer. For the lack of a better word in english, the word &amp;lsquo;free&amp;rsquo;&#xA;which also means gratis has been used. Using the term &amp;lsquo;Libre&amp;rsquo;&#xA;sometimes helps and if you are in this part of the world, &amp;ldquo;mukt&amp;rdquo;&#xA;is the best word to use.&lt;/li&gt;&#xA;&lt;li&gt;Free Software&lt;sup id=&#34;fnref:2&#34;&gt;&lt;a href=&#34;#fn:2&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;2&lt;/a&gt;&lt;/sup&gt; comes along with four fundamental freedoms. To put&#xA;it simply, the freedom to use, study, share and modify any&#xA;software.&lt;/li&gt;&#xA;&lt;li&gt;Free Software may have the advantage of being &amp;rsquo;technically&#xA;sounder&amp;rsquo;, but the philosophy is what matters the most to me.&lt;/li&gt;&#xA;&lt;li&gt;I will do whatever is possible within my capacity to spread the&#xA;philosophy and the associated freedom&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Be Free, My Friend!&lt;/p&gt;&#xA;&lt;p&gt;Here is an extract from one of Stallman&amp;rsquo;s &lt;sup id=&#34;fnref:3&#34;&gt;&lt;a href=&#34;#fn:3&#34; class=&#34;footnote-ref&#34; role=&#34;doc-noteref&#34;&gt;3&lt;/a&gt;&lt;/sup&gt; essays:&lt;/p&gt;&#xA;&lt;blockquote&gt;&#xA;&lt;p&gt;We must talk about Freedom&lt;/p&gt;&#xA;&lt;p&gt;Estimates today are that there are ten million users of&#xA;GNU/Linux systems such as Debian GNU/Linux and Red Hat&#xA;Linux. Free software has developed such practical advantages&#xA;that users are flocking to it for purely practical reasons.&lt;/p&gt;&#xA;&lt;p&gt;The good consequences of this are evident: more interest in&#xA;developing free software, more customers for free software&#xA;businesses, and more ability to encourage companies to develop&#xA;commercial free software instead of proprietary software&#xA;products.&lt;/p&gt;&#xA;&lt;p&gt;But interest in the software is growing faster than awareness&#xA;of the philosophy it is based on, and this leads to&#xA;trouble. Our ability to meet the challenges and threats&#xA;described above depends on the will to stand firm for&#xA;freedom. To make sure our community has this will, we need to&#xA;spread the idea to the new users as they come into the&#xA;community.&lt;/p&gt;&#xA;&lt;p&gt;But we are failing to do so: the efforts to attract new users&#xA;into our community are far outstripping the efforts to teach&#xA;them the civics of our community. We need to do both, and we&#xA;need to keep the two efforts in balance.&lt;/p&gt;&#xA;&lt;/blockquote&gt;&#xA;&lt;hr&gt;&#xA;&lt;div class=&#34;footnotes&#34; role=&#34;doc-endnotes&#34;&gt;&#xA;&lt;hr&gt;&#xA;&lt;ol&gt;&#xA;&lt;li id=&#34;fn:1&#34;&gt;&#xA;&lt;p&gt;&lt;a href=&#34;http://www.gnu.org/fry/&#34;&gt;http://www.gnu.org/fry/&lt;/a&gt;&amp;#160;&lt;a href=&#34;#fnref:1&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:2&#34;&gt;&#xA;&lt;p&gt;The Free Software Definition&amp;#160;&lt;a href=&#34;#fnref:2&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;li id=&#34;fn:3&#34;&gt;&#xA;&lt;p&gt;The GNU Project by Richard Stallman&amp;#160;&lt;a href=&#34;#fnref:3&#34; class=&#34;footnote-backref&#34; role=&#34;doc-backlink&#34;&gt;&amp;#x21a9;&amp;#xfe0e;&lt;/a&gt;&lt;/p&gt;&#xA;&lt;/li&gt;&#xA;&lt;/ol&gt;&#xA;&lt;/div&gt;&#xA;</description>
    </item>
  </channel>
</rss>
