<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>sef.kloninger.com (Posts about Technology)</title><link>https://sef.kloninger.com/</link><description></description><atom:link href="https://sef.kloninger.com/categories/technology.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><lastBuildDate>Mon, 06 Jul 2026 22:42:32 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>No More Blog Comments</title><link>https://sef.kloninger.com/posts/enshittification/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;div style="float:right; align:right; width:30%; font-size:150px"&gt;
  &lt;p align="center"&gt;💩&lt;/p&gt;
&lt;/div&gt;

&lt;p&gt;I turned off comments on this site today. The good people at &lt;a href="https://disqus.com/"&gt;Disqus&lt;/a&gt; had
provided me with a free service for commenting that had worked for ten-plus
years. But they appear to have gone down the &lt;a href="https://en.wikipedia.org/wiki/Enshittification"&gt;enshittification&lt;/a&gt; path and
started running a bunch of link-spam right above the comment box on all my
pages. Of course they did. I captured a &lt;a href="https://sef.kloninger.com/f/disqus-enshittified.png"&gt;screenshot&lt;/a&gt; if you want to see. Boo.&lt;/p&gt;
&lt;p&gt;Shame on me for entrusting a company to handle content for my personal site in
the first place. Isn't controlling things the whole point of this old-school
blog business? Not a big loss, nobody had posted a comment in a long time. But
still.&lt;/p&gt;</description><category>Technology</category><guid>https://sef.kloninger.com/posts/enshittification/</guid><pubDate>Thu, 04 Dec 2025 00:15:00 GMT</pubDate></item><item><title>Leaving Google</title><link>https://sef.kloninger.com/posts/leaving-google/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;p&gt;&lt;img style="float:right" class="postimage" src="https://sef.kloninger.com/f/google-10year.jpeg" alt="Sef holding a framed certificate, Google ten years of service." width="60%"&gt;&lt;/p&gt;
&lt;p&gt;An offer of a Voluntary Exit from Google HR landed in my mailbox right around my
ten-year anniversary with the company, give or take. We'd had a couple of
packages like this at Google before (&lt;a href="https://9to5google.com/2025/01/30/pixel-android-voluntary-exit-employees/"&gt;news&lt;/a&gt;), basically the same deal you'd
get if you got laid off. But this was the first one put in front of those of us
working in one of the revenue engines of the company — I worked on Search.&lt;/p&gt;
&lt;p&gt;I wasn't aiming to leave. I liked the work, I had a good team and boss. But
the package was enough to kickstart a discussion, "why &lt;em&gt;not&lt;/em&gt; now?". My wife and
I ran numbers and discussed our futures. I clicked the button. My last day as a
Googler was earlier this week, October 4th.&lt;/p&gt;
&lt;p&gt;I have good feelings about my time at Google. It was nice that I saw a some
different parts of the business: some consumer (three years at YouTube, four
years at Search) and some enterprise (three years at Cloud). I got to play with
big infrastructure and solve some hard problems. I saw behind the curtain. But
the best part was the smart and interesting people I got to work with. I know
it's a cliche, but it's the truth.&lt;/p&gt;
&lt;p&gt;Not everything was great. I've decided to not use this space for dishy stories
about how Google isn't all it claims to be. But I sure do love reminiscing and
grousing as much as any engineer. If you want to share war stories over a beer,
I'm always up for that.&lt;/p&gt;
&lt;p&gt;What's next? I haven't decided if this is retirement, or a sabbatical, or
something else. I've been off work for extended stretches twice before, once by
choice and once not. Those two times taught me that the difference between a
wonderful, mind-expanding time and a stress-fest is my own mindset. And now
that I haven't been really working for six weeks now, I can confidently say
that my mindset is positive and good.&lt;/p&gt;
&lt;p&gt;I'm excited about the next phase. I feel fortunate to have some time to focus on
what's important.&lt;/p&gt;</description><category>Life</category><category>Technology</category><guid>https://sef.kloninger.com/posts/leaving-google/</guid><pubDate>Fri, 10 Oct 2025 05:00:00 GMT</pubDate></item><item><title>Naming Is Hard</title><link>https://sef.kloninger.com/posts/naming/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Lenna"&gt;&lt;img style="float:right" class="postimage" src="https://sef.kloninger.com/f/lena.png" alt="Photo of Lena Forsén" width="40%"&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;This is a story about how hard it is to come up with a good name.&lt;/p&gt;
&lt;p&gt;This was in 2013. I was part of a team building a &lt;a href="https://sef.kloninger.com/posts/201207on-line-education/"&gt;system for online
education&lt;/a&gt; at Stanford. We &lt;a href="https://engineering.stanford.edu/news/stanford-launches-class2go-open-source-platform-online-classes"&gt;launched&lt;/a&gt; a nice little site,
Class2Go, with a small team in a few months. It worked well and
supported the basic features of an online course: videos, assessments,
auth, reporting. We decided to keep it going and worked on it for
another year, expanding the covered use cases and taking on more
classes.&lt;/p&gt;
&lt;p&gt;But even from the beginning the name &lt;em&gt;Class2Go&lt;/em&gt; felt a bit off. Our
original aim was to enable offline &lt;a href="https://en.wikipedia.org/wiki/Massive_open_online_course"&gt;MOOC&lt;/a&gt; students, people trying
to take classes offline or in poorly-connected places. We ended
up pivoting away from the offline use case to more standard
hosted-course features. It became a little multi-tenant CMS with a
small database for auth, assessment results, and some basic analytics.&lt;/p&gt;
&lt;p&gt;We decided to rebrand. Someone knew a naming consultant, presumably
an alum, and soon enough we had an expert on board. They were really
interesting to work with. After understanding the platform's goals
and features, they generated hundreds of candidate names. Each was
vetting for domain name availability and copyright conflicts. The
consultant was good at their job, bringing us something like a hundred
candidate names (I wish I still had that list).&lt;/p&gt;
&lt;p&gt;One name caught everyone's attention: &lt;strong&gt;Tindra&lt;/strong&gt;. It's a Swedish
word that means "sparkle" or "twinkle." It's evocative and easy to
say. It also happens to be a woman's name, but not a particularly
common one we were told. &lt;/p&gt;
&lt;p&gt;Surprisingly, &lt;code&gt;tindra.com&lt;/code&gt; was available! In 2013 short and catchy
domain names were getting hard to come by. The &lt;a href="https://newgtldprogram.icann.org/"&gt;new gTLD program&lt;/a&gt; had
only just been approved in 2012, and &lt;code&gt;.com&lt;/code&gt; and &lt;code&gt;.org&lt;/code&gt; were pretty
crowded.&lt;/p&gt;
&lt;p&gt;The problem was that if you Googled "tindra," the top result was a
Swedish adult film actress! Not good. Maybe with enough SEO juice,
over time, we would have overtaken that. But on launch day, that's
not the association you want to have.&lt;/p&gt;
&lt;p&gt;We ended up punting on the problem and going with a generic name,
&lt;strong&gt;Stanford Online&lt;/strong&gt;. It got the job done, but felt like a missed
opportunity. We later merged with edX and &lt;a href="https://sef.kloninger.com/posts/leaving-stanford/"&gt;I found another job&lt;/a&gt;.
Eventually the team re-branded the site with the name &lt;strong&gt;&lt;a href="https://online.stanford.edu/lagunita-learning-platform"&gt;Lagunita&lt;/a&gt;&lt;/strong&gt;,
the name of the lake on campus, which they're still using today. I
like it.&lt;/p&gt;
&lt;p&gt;I admit I still have a thing for Tindra though. The name, not the actress.&lt;/p&gt;
&lt;p&gt;Postscript: &lt;code&gt;tindra.com&lt;/code&gt; still doesn't seem to be used for anything
today. It looks to just be parked by a German domain registrar.
Google results don't seem to be a problem. Maybe it's available for
something interesting?&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Thanks to Jane Manning for her review, she was there too.&lt;/em&gt;&lt;/p&gt;</description><category>Education</category><category>Technology</category><category>War Stories</category><guid>https://sef.kloninger.com/posts/naming/</guid><pubDate>Wed, 24 Sep 2025 05:00:00 GMT</pubDate></item><item><title>Cleaning Up Photo Duplicates</title><link>https://sef.kloninger.com/posts/photo-dups/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;p&gt;&lt;img style="float:right" class="postimage" src="https://sef.kloninger.com/f/dups-pie.png" alt="Pie Chart" width="30%"&gt;&lt;/p&gt;
&lt;p&gt;I did a data cleanup over the weekend. I doubt this is interesting
for anyone else, I just wanted to capture my own notes.&lt;/p&gt;
&lt;p&gt;Our family photos are stored up in Google Photos. We have about
100k photos and short movies that take up 0.5TB. I wanted to back
up to &lt;a href="https://www.synology.com/en-us/products?product_line=ds_plus"&gt;local storage&lt;/a&gt;, but also I liked the idea of trying the
&lt;a href="https://www.mdisc.com/"&gt;mdisc&lt;/a&gt; format for long-term storage.&lt;/p&gt;
&lt;p&gt;I ran &lt;a href="https://takeout.google.com/"&gt;Takeout&lt;/a&gt; and unzipped everything. I was surprised to see
so many duplicates. Some are copies in the same folders with suffixes
like "(1)", most are multiple copies in different folders.
Takeout seems to just store a copy for each album a photo is in.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://docs.google.com/spreadsheets/d/10pRVc1_6u0G2z62uEJSHHZ0yzf43Zoa9yx0D2bpICmE/edit?usp=sharing"&gt;Some poking at the data&lt;/a&gt; shows 88% of 302,755 files / 72% of
the bytes were unique (histogram at the bottom of the post).  Removing
dups can save 200+GB. Sure not really worth the trouble but why
not.&lt;/p&gt;
&lt;h4&gt;Steps&lt;/h4&gt;
&lt;p&gt;1. On the NAS, gather file checksums (&lt;code&gt;md5sum&lt;/code&gt;) and sizes for all
the files under &lt;code&gt;Takeout/Google Files&lt;/code&gt;. Mostly variations on
of &lt;code&gt;find -print0 | xargs -0&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;2. Data cleanup to get into nice file paths and clean delimiters,
mostly interactively with &lt;code&gt;vi&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;3. Insert into &lt;code&gt;sqlite&lt;/code&gt; using &lt;code&gt;.separator&lt;/code&gt; and &lt;code&gt;.import&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Here's what the database ended up looking like: &lt;code&gt;Photos&lt;/code&gt; and &lt;code&gt;Sizes&lt;/code&gt;
are inputs, &lt;code&gt;HashCounts&lt;/code&gt;, &lt;code&gt;Duplicates&lt;/code&gt;, and &lt;code&gt;Candidates&lt;/code&gt; are
outputs.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Photos&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sizes&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HashCounts&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Duplicates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;TABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Candidates&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="n"&gt;pos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;INT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;4. Find the dups. I'm surprised to find some with 50 or more copies,
but it out some family favorites end up in lots of albums.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HashCounts&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Photos&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;group&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;5. Figure out candidates for deletion&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Duplicates&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Photos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Photos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HashCounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;found&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sizes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Photos&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HashCounts&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Sizes&lt;/span&gt;
&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HashCounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Photos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Photos&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;Sizes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;
&lt;span class="k"&gt;and&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;HashCounts&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;found&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The first of each set is the one we'll keep.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;insert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;into&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Candidates&lt;/span&gt;
&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row_number&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;over&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;partition&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row_number&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Duplicates&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;order&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;desc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;where&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;row_number&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I was surprised that sqlplus supports window functions, nice.&lt;/p&gt;
&lt;p&gt;The inner reverse-alpha sort on "path" takes care of two cases.
I tend to prefer keeping photos with names that start with
years, and Those come first alphabetically (nice). Also within
folders often there are many copies with "(1)" and "(2)" suffixes
that are generally cruft and most worthy of removing, and those
also sort last alphabetically (nice).&lt;/p&gt;
&lt;p&gt;5. Dump out the "Candidates" using &lt;code&gt;.output&lt;/code&gt;. Copy back to the NAS.
Do lots of spot checks. Convert to a bash script of &lt;code&gt;rm&lt;/code&gt; commands,
run very carefully.&lt;/p&gt;
&lt;h4&gt;Tools&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;Sqlite&lt;/strong&gt; is my go-to tool for ad-hoc work like this.  It's fast
and simple, but only for small jobs -- this one is MB-scale.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;select&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pgsize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dbstat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;group&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;by&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="k"&gt;sum&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pgsize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;-------------  -----------&lt;/span&gt;
&lt;span class="n"&gt;Candidates&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;3006464&lt;/span&gt;
&lt;span class="n"&gt;Duplicates&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;5541888&lt;/span&gt;
&lt;span class="n"&gt;HashCounts&lt;/span&gt;&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="mi"&gt;11051008&lt;/span&gt;
&lt;span class="n"&gt;Photos&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mi"&gt;23240704&lt;/span&gt;
&lt;span class="n"&gt;Sizes&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="mi"&gt;13807616&lt;/span&gt;
&lt;span class="n"&gt;sqlite_schema&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="mi"&gt;4096&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;My &lt;strong&gt;Synology&lt;/strong&gt; is a pretty good place for storage with ability to
ssh in and run local commands.  But if I had to do this again,
though, I should have just bought a large locally-connected SSD.
All the transfers to-from the NAS were a hassle. Looking now I'm
stunned that you can get a 4 TB external SSD for under $300.&lt;/p&gt;
&lt;p&gt;Some &lt;a href="https://docs.google.com/spreadsheets/d/1O4gzeTn8GNeL1X4DrBUprcEqpK6jKbQrtEfBNdJF-Pw/edit#gid=810787524"&gt;private notes&lt;/a&gt; here.&lt;/p&gt;
&lt;p&gt;&lt;img class="postimage" src="https://sef.kloninger.com/f/dups-histo.png" alt="Histogram" width="100%"&gt;
(&lt;a href="https://docs.google.com/spreadsheets/d/10pRVc1_6u0G2z62uEJSHHZ0yzf43Zoa9yx0D2bpICmE/edit?usp=sharing"&gt;source&lt;/a&gt;)&lt;/p&gt;</description><category>Technology</category><guid>https://sef.kloninger.com/posts/photo-dups/</guid><pubDate>Mon, 19 Feb 2024 20:00:00 GMT</pubDate></item><item><title>The iPhone's SIM Tray Went Away Too Soon</title><link>https://sef.kloninger.com/posts/esim/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;p&gt;&lt;img style="float:right" class="postimage" src="https://sef.kloninger.com/f/sim.png" alt="SIM" width="25%"&gt;&lt;/p&gt;
&lt;p&gt;If you've traveled internationally, likely you've used a SIM card
for local data and calls. There is a nice ecosystem around SIMs
with a wealth of easy and affordable Pay As You Go (PAYG) options.&lt;/p&gt;
&lt;p&gt;But the newer iPhones did away with the SIM slot in favor of some new
eSIM hotness. Apple has all kinds of &lt;a href="https://support.apple.com/en-gb/HT209096"&gt;info&lt;/a&gt; claiming they have good
international support, but I found reality falls short.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Only a few carriers support eSIMs,&lt;/li&gt;
&lt;li&gt;The few that do require a contract. A tourist or student
   studying abroad is better served by a PAYG plan, and&lt;/li&gt;
&lt;li&gt;Even if you can stomach a contract, that would require a UK bank
   account; no way to easily pull that off.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;We ended up falling back to &lt;a href="https://www.att.com/international/day-pass/"&gt;international roaming&lt;/a&gt;. It works but
is expensive.&lt;/p&gt;
&lt;p&gt;I think Apple made the wrong call removing the trusty old SIM tray.
Clearly the new models can be made to work well with it, since how
they are sold in the UK.  If you're unlucky enough to have bought
your recent iPhone in the US, you're out of luck. &lt;/p&gt;
&lt;p&gt;This is an example of Apple's bad tendency to sometimes choose
form over function, "&lt;a href="https://www.theringer.com/2016/9/7/16038622/why-did-apple-remove-the-headphone-jack-courage"&gt;courage&lt;/a&gt;" over usability.&lt;/p&gt;</description><category>Technology</category><guid>https://sef.kloninger.com/posts/esim/</guid><pubDate>Fri, 05 Jan 2024 10:34:49 GMT</pubDate></item><item><title>YouTube</title><link>https://sef.kloninger.com/posts/youtube/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;p&gt;&lt;img style="float:right" class="postimage" src="https://sef.kloninger.com/f/YouTube-icon-full_color.png" alt="YouTube" width="200px" height="148px"&gt;&lt;/p&gt;
&lt;p&gt;I'm excited to start my new job at YouTube in a few weeks. I'll manage the
engineering team building the data warehouse for usage metrics.&lt;/p&gt;
&lt;p&gt;I like that YouTube is &lt;strong&gt;important&lt;/strong&gt;. It's firmly a part of our culture
and I'm sure it will be how my kids watch video. YouTube's impressive
&lt;a href="https://www.youtube.com/yt/press/statistics.html"&gt;statistics&lt;/a&gt; are the result. You don't see usage like that without a
bunch of &lt;strong&gt;hard problems&lt;/strong&gt;, and hard problems attract &lt;strong&gt;bright people&lt;/strong&gt;.
Indeed that's the clincher for why I'm looking forward to working there.
People vote with their feet, and I have a lot of friends who have opted
for Google, and YouTube specifically. They tell me that it's a great place
to work.&lt;/p&gt;
&lt;p&gt;YouTube is one of the world's foremost platforms for social commentary,
education, and free speech. And it's plenty of &lt;a href="https://www.youtube.com/watch?v=9bZkp7q19f0"&gt;entertainment&lt;/a&gt; too. Sounds
like fun.&lt;/p&gt;</description><category>Life</category><category>Technology</category><guid>https://sef.kloninger.com/posts/youtube/</guid><pubDate>Wed, 26 Aug 2015 06:25:00 GMT</pubDate></item><item><title>Thick Apps Still Lose </title><link>https://sef.kloninger.com/posts/thick-apps/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;p&gt;&lt;img style="float:right" class="postimage" src="https://sef.kloninger.com/f/online-required.png" alt="Microsoft Excel 2016 Error Message" width="60%"&gt;&lt;/p&gt;
&lt;p&gt;Thick apps won mobile. Fine. &lt;/p&gt;
&lt;p&gt;On laptop (and desktop) it's not so clear. What is better, thick or thin?
I tend to live mostly in thin land, although I use some thick apps
regularly, like Twitter's Mac client and Apple Photos.&lt;/p&gt;
&lt;p&gt;Every so often I give a big native app a try: &lt;strong&gt;Excel&lt;/strong&gt; instead of
&lt;strong&gt;Google Sheets&lt;/strong&gt;, &lt;strong&gt;Mail.app&lt;/strong&gt; instead of &lt;strong&gt;Gmail&lt;/strong&gt;, &lt;strong&gt;Reminders&lt;/strong&gt;
instead of the barebones &lt;strong&gt;Tasks&lt;/strong&gt; built into Gmail. (I can't bring myself
to try Word). But it's disappointing to see how those fancy apps keep
shooting themselves in the foot!&lt;/p&gt;
&lt;p&gt;Take for example this Excel error message. Excel is whining that it
can't verify my subscription the first time I ran Excel untethered
(version 15.11.2, for what it's worth). Sure you can click through the
warning, but would a newbie know to do that? At best off-putting, at worst
downright disorienting. Why warn me of this at all? And why in a modal
that stops me dead in my tracks?&lt;/p&gt;
&lt;p&gt;It seems thick apps should win. They rock the unplugged use case. An even
better situation is flaky networks -- tethered, conference WiFi,
travelling. UIs deal notoriously poorly with intermittent or partial
outages. A thick client, relying on that connection only for hitting
API's, can hide the network.&lt;/p&gt;
&lt;p&gt;Another place they should shine is the UI itself. They should be fast,
beautiful, and featureful. Too often they're not. For example I find
Mail.app to be clunky, difficult to customize, and its keyboard shortcuts
few and poorly done. Gmail is pretty good!&lt;/p&gt;
&lt;p&gt;Finally there's the upgrade problem. Thick apps need conscious effort from
their users before their work sees user time and they get feedback. And
that's what drives innovation. Long cycles means slower (less) invention.
One example I love is Gmail's "undo send" feature. Boy, you sure do miss
that when you need it and it's not there! That should be on every thick
client by now, but I don't think it is. I do know that Gmail has it and
Mail.app still doesn't.&lt;/p&gt;
&lt;p&gt;Maybe the Internet can help. Look at &lt;strong&gt;&lt;a href="https://www.getchrome.com/"&gt;Chrome&lt;/a&gt;&lt;/strong&gt; with its awesome auto
updates. What makes this work is solid engineering and exceptional quality
control. I've never seen behind the Google curtain, but I bet there's no
magic, just a lot of good engineering that leads to good software. Like:
good design and code reviews, tons of test coverage across many scenarios,
diverse and well-instrumented canaries, and thorough performance and
resource use testing. If Google didn't do all of that so well, then we
wouldn't accept frequent pushes. Without the frequent upgrade cycle,
Chromes feature cycle would languish.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.getelectron.com/"&gt;Electron&lt;/a&gt;&lt;/strong&gt; is another bright spot. This is the framework that gives
Slack and GitHub's thick clients their fit and finish. It makes these feel
like true native apps, even though they are mostly web controls with
JavaScript the covers. Right-clicking still doesn't do what I want, and
text controls are finicky, but it's close. But what those rough edges buy
you, and the software producer, are frequent, reliable, and clean
upgrades.&lt;/p&gt;
&lt;p&gt;My natural preference would be for thick apps. If they were done well,
I'd use them.&lt;/p&gt;</description><category>Technology</category><guid>https://sef.kloninger.com/posts/thick-apps/</guid><pubDate>Wed, 19 Aug 2015 20:20:00 GMT</pubDate></item><item><title>My Next Job</title><link>https://sef.kloninger.com/posts/job-15/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;p&gt;&lt;img style="float:right" class="postimage" src="https://sef.kloninger.com/f/snowflake.png" alt="Snowflake" width="25%"&gt;&lt;/p&gt;
&lt;p&gt;I left &lt;a href="http://www.wavefront.com/"&gt;my last job&lt;/a&gt; a few weeks back and it's high time to look for a new
one. If you're working on something interesting and think I could help, &lt;a href="mailto:sefklon@gmail.com"&gt;let
me know&lt;/a&gt;! &lt;/p&gt;
&lt;p&gt;It's nice to not have a day job while looking for another. I was lucky enough
to do this &lt;a href="https://sef.kloninger.com/posts/201204my-sabbatical.html"&gt;once before in 2012&lt;/a&gt; which turned out great. I learned then
that time and flexibility lets you talk to lots of friends and learn about a
breadth of projects. I found a fun project in a new domain (&lt;a href="https://sef.kloninger.com/posts/201207on-line-education.html"&gt;online
education&lt;/a&gt;), something I doubt I'd have found the normal way.&lt;/p&gt;
&lt;p&gt;Maybe I'll get lucky again.&lt;/p&gt;
&lt;p&gt;Enough small talk, what am I looking for?&lt;/p&gt;
&lt;p&gt;I'm looking for some flavor of &lt;strong&gt;line manager&lt;/strong&gt;. I'm a good senior manager and
code-every-day engineer; but I'm exceptional leading a team and running a
project. That's what line managers do: lead engineers, not other managers or
departments or matrix-anything. Also, if you're some kind of executive then
coding is an indulgence, and I'd rather it just be part of my job. Mostly I'm
talking to &lt;strong&gt;small companies&lt;/strong&gt;, say 10-100 people (fun-size).&lt;/p&gt;
&lt;p&gt;I want to &lt;strong&gt;build on my experience&lt;/strong&gt;. I know infrastructure and cloud, SaaS
and enterprise, and online education. I'm probably not the best person for
your storage, security, gaming, e-commerce, or cryptocurrency company. I want
to stay working on &lt;strong&gt;Internet technology&lt;/strong&gt;. I like the (micro)services model.
For my own projects I choose Python, JavaScript (frontend and backend), and
Java. I know web operations, especially the &lt;a href="https://sef.kloninger.com/posts/aws.html"&gt;Amazon stack&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Location&lt;/strong&gt; is important: I don't want to do a daily Menlo Park to San
Francisco round-trip. I'd like to &lt;strong&gt;work with friends&lt;/strong&gt; if possible. And I
want to do something &lt;strong&gt;worthwhile&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;You can always get to my resume from the header here, or via this &lt;a href="http://bit.ly/sef-resume"&gt;short
link&lt;/a&gt;. I'm open to a bunch of things, just no &lt;a href="https://www.youtube.com/watch?v=VEgu7jdc_fs"&gt;kick boxing&lt;/a&gt;.  Let's
have coffee/drink or take a walk.&lt;/p&gt;</description><category>Life</category><category>Technology</category><guid>https://sef.kloninger.com/posts/job-15/</guid><pubDate>Sun, 10 May 2015 16:30:00 GMT</pubDate></item><item><title>Lessons from Three Years in AWS</title><link>https://sef.kloninger.com/posts/aws/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;p&gt;&lt;img style="float:right" class="postimage" src="https://sef.kloninger.com/f/aws.png" alt="AWS Logo" width="30%"&gt;&lt;/p&gt;
&lt;p&gt;I've spent the last three years building and operating web sites
with Amazon Web Services and here are a few lessons I've learned. 
But I first have to come clean that I'm a fan of AWS with only
casual experience with other IAAS/PAAS platforms.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;S3 Is Amazing&lt;/strong&gt;. They made the right engineering choices and
compromises: cheap, practically infinitely scalable, fast enough,
with good availability. $0.03/GB/mo covers up for a lot of sins.
Knowing it's there changes how you build systems.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IAM Machine Roles From The Start&lt;/strong&gt;. IAM with &lt;a href="http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html"&gt;Instance Metadata&lt;/a&gt;
is a powerful way to manage secrets and rights. Trouble is you can't add
to existing machines. Provision with machine roles in big categories
(e.g. app servers, utility machines, databases) at the start, even if 
just placeholders.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Availability Zoness Are Only Mostly Decoupled&lt;/strong&gt;. After the 2011
&lt;a href="http://www.networkworld.com/article/2202805/cloud-computing/amazon-ec2-outage-calls--availability-zones--into-question.html"&gt;us-east-1 outage&lt;/a&gt; we were reassured that a coordinated 
outage wouldn't happen again, but it happened again just
&lt;a href="https://www.reddit.com/r/aws/comments/2zpag7/aws_internal_dns_outage/"&gt;last month&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;They Will Lock You In And You'll Like It&lt;/strong&gt;. They secondary services
work well, are cheap, and are handy. I'm speaking of SQS, SES,
Glacier, even Elastic Transcoder. Who &lt;em&gt;wants&lt;/em&gt; to run a durable queue
again?&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;CloudFormation No&lt;/strong&gt;. It's tough to get right. My
objection isn't programming in YAML, I don't mind writing Ansible plays, it's the
complexity/structure of CloudFormation that is impenetrable. Plus
even if you get it working once, you'd never run it again on something
that is running.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Boto Yes&lt;/strong&gt;. Powerful and expressive. Don't script the CLI, use
Boto. Easy as pie.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Qualify Machines Before Use&lt;/strong&gt;. Some VMs have lousy networking,
presumably due to a chatty same-host or same-rack neighbor. Test
for loss and latency to other hosts you own and on EBS. (I've used
home-grown scripts, don't know of a standard open-source widget,
someone should write one).&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;VPC Yes&lt;/strong&gt;. If you have machines talking to each other (i.e. not a
lone machine doing something lonely) then put them in a VPC. It's not
hard.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;NAT No&lt;/strong&gt;. You think that'll improve security, but it will just
introduce SPOFS and capacity chokepoints. Give your machines publicly
routable IP's and use security groups.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Network ACLs Are A Pain&lt;/strong&gt;. Try to get as far as you can with just security
groups.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;You'll Peer VPC's Someday&lt;/strong&gt;. Choose non-overlapping subnet IP ranges
at the start. It's hard to change later.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Spot Instances Are Tricky&lt;/strong&gt;. They're only For a very specific use
case that likely isn't yours. Setting up a test network? You can
spend the money you save by using spot on swear jar fees.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Pick a Management Toolset&lt;/strong&gt;. Ansible, Chef, all those things aren't
&lt;em&gt;all&lt;/em&gt; that different when it comes down to it. Just don't dither back
and forth. There's a little bit of extra Chef love w/ AWS but not enough to tip
the scales in your decision I'd reckon. &lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Tech Support Is Terrible&lt;/strong&gt;. My &lt;a href="http://www.wavefront.com/"&gt;last little
startup&lt;/a&gt; didn't get much out of the &lt;a href="https://aws.amazon.com/premiumsupport/"&gt;business level tech
support&lt;/a&gt; we bought. We needed it so we could call in to get
help when we needed it, and we used that for escalating some problems.
It was nice to have a number to call when I urgently need to up a
system limit, say. But debugging something real, like a networking
problem? Pretty rough.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;...Unless You Are Big&lt;/strong&gt;. Stanford, on the other hand, had a named
rep who was responsive and helpful. I guess she was sales, but I
used her freely on support issues and she worked the backchannels
for us. Presumably this is what any big/important customer would
get, that's just not you, sorry.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;The Real Power Is On Demand&lt;/strong&gt;. I'm reaffirming cloud
koolaid here. Running this way lets you build and run systems
differently, &lt;em&gt;much better&lt;/em&gt;. I've relied on the cloud this to bring
up emergency capacity. I've used it to convert a class of machines
on the fly to the double-price double-RAM tier when hitting a
surprising capacity crunch. There are a whole class of problems
that get much easier when you can have 2x the machines for just a
little while.  When someone comes to you with that cost/benefit
spreadsheet arguing why you should self-host, that's when you need
your file of "the cloud saved my bacon" stories at the ready.&lt;/p&gt;</description><category>Engineering</category><category>Technology</category><guid>https://sef.kloninger.com/posts/aws/</guid><pubDate>Fri, 24 Apr 2015 07:10:00 GMT</pubDate></item><item><title>CS Students: Learn to Write</title><link>https://sef.kloninger.com/posts/learn-to-write/</link><dc:creator>Sef Kloninger</dc:creator><description>&lt;p&gt;&lt;img style="float:right" class="postimage" src="https://sef.kloninger.com/f/writing-hand.jpeg" alt="Writing Hand" width="40%"&gt;&lt;/p&gt;
&lt;p&gt;If I could do my college years over I would focus on writing. I
would take courses that required a lot of writing, in the spirit
of "learn by doing". I'd also take courses in the mechanics and
craft: grammar, vocabulary, and rhetoric.&lt;/p&gt;
&lt;p&gt;I used to consider myself a competent writer. And certainly good
enough for an engineer, right? But I've learned that I have a long
way to go. I've learned that engineers spend much more time writing
than you expect. And I appreciate how hard it is to write well.&lt;/p&gt;
&lt;p&gt;This came up just this past week. I came across a beautiful four
page essay. It laid out the problem, described alternatives, and
lead you concisely to a well-reasoned conclusion. Sure, it was about
technology, but what carried the day was the good writing. Humbling!&lt;/p&gt;
&lt;p&gt;You're saying: but wait, you're a &lt;a href="http://en.wikipedia.org/wiki/Pointy-Haired_Boss"&gt;pointy-haired boss&lt;/a&gt; now
Sef, one of those guys who doesn't do &lt;em&gt;Real Work&lt;/em&gt; anymore. You write
email and boss people around. I understand why managers like you
need to write, I'm an engineer. I write code. Well, there's some
truth to that. But I'd like to convince you that even monster coders,
if they're any good, write a lot, write well, and value good writing
in others.&lt;/p&gt;
&lt;p&gt;It is rare for someone to do their work in isolation and have it
matter. Either you're working as part of a team, in a company or
a community of developers, say on an open-source project. Sure, you
build a great system or feature. But to have it matter to the world,
for others to adopt it, you need to document, publicize, support,
teach. 98% of that is writing.&lt;/p&gt;
&lt;p&gt;I had a lunchtime conversation with &lt;a href="http://jacobian.org/writing/great-documentation/"&gt;Jacob Kaplan-Moss&lt;/a&gt;,
Django's co-founder, at last year's PyCon. I asked him why Django
caught on and was adopted by so many of us (including &lt;a href="http://class2go.stanford.edu/"&gt;my last
project&lt;/a&gt; and &lt;a href="http://code.edx.org/"&gt;my current project&lt;/a&gt;). I was expecting him
to point to features or timing. Instead he said it was "because we
wrote good docs". The Django team didn't treat documentation as an
afterthought. They have lots of docs, and they are good.&lt;/p&gt;
&lt;p&gt;Consider that rare bird, the iconoclastic engineer working in
isolation on their own project. I'm thinking of &lt;a href="http://antirez.com/"&gt;Antirez&lt;/a&gt; or
&lt;a href="http://www.marco.org/"&gt;Marco&lt;/a&gt;. (Maybe they aren't even truly on their own so much.
Humor me!) They are prolific and strong coders. But they also write
a lot of words! They write a ton about their project; also tech
landscape and their place in it. Would their software have as much
of an impact if they didn't write so much (and well)? I say no.&lt;/p&gt;
&lt;p&gt;Case in point. Both Marco and I wrote blog posts riffing off the
same topic two weeks ago. First, read &lt;a href="http://sef.kloninger.com/posts/consume-produce-public.html"&gt;mine&lt;/a&gt;, then
&lt;a href="http://www.marco.org/2014/01/03/the-builders-high"&gt;his&lt;/a&gt;.  It takes me a ton of words to get something
basic out.  His is concise and clear. Sheesh.&lt;/p&gt;
&lt;p&gt;So kids, don't shortchange those liberal arts classes. It's not
fluffy stuff on the side. &lt;strong&gt;That is core&lt;/strong&gt;. You need to write well
to be a good engineer.&lt;/p&gt;
&lt;p&gt;Protip: the best way to do this is to major in the humanities. They
write like crazy over there. Be like my friend Dan Chu and major
in history, but secretly take CS courses on the side. If you're
super smart like him, and can manage getting both degrees, then
you're awesome. But don't sacrifice the BA for the BS. I would
&lt;strong&gt;love&lt;/strong&gt; to talk to a candidate with a History BA and a Computer
Science MS.&lt;/p&gt;</description><category>Engineering</category><category>Technology</category><guid>https://sef.kloninger.com/posts/learn-to-write/</guid><pubDate>Sun, 26 Jan 2014 00:17:00 GMT</pubDate></item></channel></rss>