Michael Baltaks
2019-08-20T02:39:30+00:00
Copyright © 2004 - 2014 Michael Baltaks
https://baltaks.com/
Michael Baltaks
m@baltaks.com
Fix it yourself
2019-08-13T16:08:57+00:00
2019-08-13T16:08:57+00:00
https://baltaks.com/2019/08/fix-it-yourself
Michael Baltaks
https://baltaks.com/
<p>I use Simplenote iOS every day, and recently they added a task list feature to the app, meaning you can just tap to mark an item as done. The only problem was, there was a bug where sometimes that tap would make the list scroll to the very bottom, which was really annoying for me, and I noticed I was starting to avoid using the feature because of this problem.</p>
<p>Eventually I thought to report the problem, and only then did I find that the app is open source, which meant the time I would have taken to only report the problem, was instead spent actually fixing the problem.</p>
<p>So version 4.9 is now available, and it includes the fix, and I’m very pleased about that.</p>
<p>This is the kind of situation where open source really shines, because the problem probably doesn’t bother many people, and so was low priority for the main team, but it <em>really</em> bothered me. And it’s reminded me that before I got so focussed on iOS, it was more common for me to be using open source software, and therefore be able to do this kind of work. But iOS put a bit of a dent in that workflow - most iOS apps are not open source, to the extent I didn’t even consider that a possibility even when using an app every day that actually is open source.</p>
<p>I’m really happy with the outcome in this situation, and this is a big reason I like to build my main workflows on software that has source available like this. Data portability is more important overall, but open source is a great bonus.</p>
Why We Encrypt
2019-07-18T09:52:34+00:00
2019-07-18T09:52:34+00:00
https://baltaks.com/2019/07/why-we-encrypt
Michael Baltaks
https://baltaks.com/
<blockquote>
<p>There are two morals to all of this. One, we should push companies to offer encryption to everyone, by default. And two, we should resist demands from governments to weaken encryption. Any weakening, even in the name of legitimate law enforcement, puts us all at risk. Even though criminals benefit from strong encryption, we’re all much more secure when we all have strong encryption.</p>
</blockquote>
Democracy as an Information System
2019-05-18T16:23:01+00:00
2019-05-18T16:23:01+00:00
https://baltaks.com/2019/05/democracy-as-an-information-system
Michael Baltaks
https://baltaks.com/
Oversharing?
2018-04-07T13:02:10+00:00
2018-04-07T13:02:10+00:00
https://baltaks.com/2018/04/oversharing?
Michael Baltaks
https://baltaks.com/
<p>Oversharing.</p>
The Most Ancient Music Known To Man
2016-09-17T03:22:29+00:00
2016-09-17T03:22:29+00:00
https://baltaks.com/2016/09/the-most-ancient-music-known-to-man
Michael Baltaks
https://baltaks.com/
<p>It’s very cool that we can listen to this ancient tune.</p>
I Could Care Less
2015-09-18T11:19:17+00:00
2015-09-18T11:19:17+00:00
https://baltaks.com/2015/09/i-could-care-less
Michael Baltaks
https://baltaks.com/
<p>I want <strong>you</strong> to feel less alone.</p>
How to change text fields to a real UUID type for Django and PostgreSQL
2015-08-28T16:38:18+00:00
2015-08-28T16:38:18+00:00
https://baltaks.com/2015/08/how-to-change-text-fields-to-a-real-uuid-type-for-django-and-postgresql
Michael Baltaks
https://baltaks.com/
<p>Switch to a dedicated UUID field type, they said, it’ll be better they said.</p>
<p>Things are rarely simple.</p>
<p>If you’ve been storing UUID’s as text in <a href="https://www.djangoproject.com">Django</a> and <a href="http://www.postgresql.org">PostgreSQL</a> and now want to take advantage of the dedicated UUID type of both <a href="https://docs.djangoproject.com/en/1.8/ref/models/fields/#uuidfield">Django >= 1.8</a> and <a href="http://www.postgresql.org/docs/8.3/static/datatype-uuid.html">Postgres >= 8.3</a> then you’re wanting to migrate your fields. But the process is not as simple as just changing the type of the field in the model like it usually is.</p>
<p>Postgres does have a way to convert text to uuid, but you have to do it manually because Django won’t put that into the migration for you.</p>
<p>Django will most likely create a migration for you that looks something like:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Migration</span><span class="p">(</span><span class="n">migrations</span><span class="o">.</span><span class="n">Migration</span><span class="p">):</span>
<span class="n">dependencies</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">(</span><span class="s">'app'</span><span class="p">,</span> <span class="s">'0001_auto'</span><span class="p">),</span>
<span class="p">]</span>
<span class="n">operations</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">migrations</span><span class="o">.</span><span class="n">AlterField</span><span class="p">(</span>
<span class="n">model_name</span><span class="o">=</span><span class="s">'modelname'</span><span class="p">,</span>
<span class="n">name</span><span class="o">=</span><span class="s">'uuid'</span><span class="p">,</span>
<span class="n">field</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">UUIDField</span><span class="p">(</span><span class="n">db_index</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span>
<span class="p">),</span>
<span class="p">]</span>
</code></pre></div></div>
<p>If your uuid field has no indexes or constraints, then you might actually be done, in which case I doubt you’re reading this. For those who’ve found this, it’s likely because you have one or both of indexes and constraints.</p>
<p>Here is what I had to do to make this work.</p>
<p>First, put the auto created migration operations into a RunSQL operation as the <code class="highlighter-rouge">state_operations</code> parameter. This allows you to provide a custom migration, but keep Django informed about what’s happened to the database schema.</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">class</span> <span class="nc">Migration</span><span class="p">(</span><span class="n">migrations</span><span class="o">.</span><span class="n">Migration</span><span class="p">):</span>
<span class="n">dependencies</span> <span class="o">=</span> <span class="p">[</span>
<span class="p">(</span><span class="s">'app'</span><span class="p">,</span> <span class="s">'0001_auto'</span><span class="p">),</span>
<span class="p">]</span>
<span class="n">operations</span> <span class="o">=</span> <span class="p">[</span>
<span class="n">migrations</span><span class="o">.</span><span class="n">RunSQL</span><span class="p">(</span><span class="n">sql_commands</span><span class="p">,</span> <span class="bp">None</span><span class="p">,</span> <span class="p">[</span>
<span class="n">migrations</span><span class="o">.</span><span class="n">AlterField</span><span class="p">(</span>
<span class="n">model_name</span><span class="o">=</span><span class="s">'modelname'</span><span class="p">,</span>
<span class="n">name</span><span class="o">=</span><span class="s">'uuid'</span><span class="p">,</span>
<span class="n">field</span><span class="o">=</span><span class="n">models</span><span class="o">.</span><span class="n">UUIDField</span><span class="p">(</span><span class="n">db_index</span><span class="o">=</span><span class="bp">True</span><span class="p">,</span> <span class="n">unique</span><span class="o">=</span><span class="bp">True</span><span class="p">),</span>
<span class="p">),</span>
<span class="p">]),</span>
<span class="p">]</span>
</code></pre></div></div>
<p>Now you’ll need to provide some SQL commands for that <code class="highlighter-rouge">sql_commands</code> variable. I opted to put the sql into a separate file and then load in with the following python code:</p>
<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">sql_path</span> <span class="o">=</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">abspath</span><span class="p">(</span><span class="n">__file__</span><span class="p">)),</span> <span class="s">'0001.sql'</span><span class="p">)</span>
<span class="k">with</span> <span class="nb">open</span><span class="p">(</span><span class="n">sql_path</span><span class="p">,</span> <span class="s">"r"</span><span class="p">)</span> <span class="k">as</span> <span class="n">sqlfile</span><span class="p">:</span>
<span class="n">sql_commands</span> <span class="o">=</span> <span class="n">sqlfile</span><span class="o">.</span><span class="n">read</span><span class="p">()</span>
</code></pre></div></div>
<p>Now for the real tricky part, where we actually perform the migration. The basic command you want looks like:</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">alter</span> <span class="k">table</span> <span class="n">tablename</span> <span class="k">alter</span> <span class="k">column</span> <span class="n">uuid</span> <span class="k">type</span> <span class="n">uuid</span> <span class="k">using</span> <span class="n">uuid</span><span class="p">::</span><span class="n">uuid</span><span class="p">;</span>
</code></pre></div></div>
<p>But the reason we are here is because of indexes. And as I discovered, Django likes to use your migrations to created randomly named indexes on your fields while running tests, so your tests will fail if you just delete and then recreate a fixed name index or two. So the following is sql that will delete one constraint and all indexes on the text field before converting to a uuid field. It also works for multiple tables in one go.</p>
<div class="language-sql highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">DO</span> <span class="err">$$</span>
<span class="k">DECLARE</span>
<span class="n">table_names</span> <span class="n">text</span><span class="p">[];</span>
<span class="n">this_table_name</span> <span class="n">text</span><span class="p">;</span>
<span class="n">the_constraint_name</span> <span class="n">text</span><span class="p">;</span>
<span class="n">index_names</span> <span class="n">record</span><span class="p">;</span>
<span class="k">BEGIN</span>
<span class="k">SELECT</span> <span class="n">array</span><span class="p">[</span><span class="s1">'table1'</span><span class="p">,</span>
<span class="s1">'table2'</span>
<span class="p">]</span>
<span class="k">INTO</span> <span class="n">table_names</span><span class="p">;</span>
<span class="n">FOREACH</span> <span class="n">this_table_name</span> <span class="k">IN</span> <span class="n">array</span> <span class="n">table_names</span>
<span class="n">LOOP</span>
<span class="n">RAISE</span> <span class="n">notice</span> <span class="s1">'migrating table %'</span><span class="p">,</span> <span class="n">this_table_name</span><span class="p">;</span>
<span class="k">SELECT</span> <span class="k">CONSTRAINT_NAME</span> <span class="k">INTO</span> <span class="n">the_constraint_name</span>
<span class="k">FROM</span> <span class="n">information_schema</span><span class="p">.</span><span class="n">constraint_column_usage</span>
<span class="k">WHERE</span> <span class="k">CONSTRAINT_SCHEMA</span> <span class="o">=</span> <span class="n">current_schema</span><span class="p">()</span>
<span class="k">AND</span> <span class="k">COLUMN_NAME</span> <span class="k">IN</span> <span class="p">(</span><span class="s1">'uuid'</span><span class="p">)</span>
<span class="k">AND</span> <span class="k">TABLE_NAME</span> <span class="o">=</span> <span class="n">this_table_name</span>
<span class="k">GROUP</span> <span class="k">BY</span> <span class="k">CONSTRAINT_NAME</span>
<span class="k">HAVING</span> <span class="k">count</span><span class="p">(</span><span class="o">*</span><span class="p">)</span> <span class="o">=</span> <span class="mi">1</span><span class="p">;</span>
<span class="n">if</span> <span class="n">the_constraint_name</span> <span class="k">is</span> <span class="k">not</span> <span class="k">NULL</span> <span class="k">then</span>
<span class="n">RAISE</span> <span class="n">notice</span> <span class="s1">'alter table % drop constraint %'</span><span class="p">,</span>
<span class="n">this_table_name</span><span class="p">,</span>
<span class="n">the_constraint_name</span><span class="p">;</span>
<span class="k">execute</span> <span class="s1">'alter table '</span> <span class="o">||</span> <span class="n">this_table_name</span>
<span class="o">||</span> <span class="s1">' drop constraint '</span> <span class="o">||</span> <span class="n">the_constraint_name</span><span class="p">;</span>
<span class="k">end</span> <span class="n">if</span><span class="p">;</span>
<span class="k">FOR</span> <span class="n">index_names</span> <span class="k">IN</span>
<span class="p">(</span><span class="k">SELECT</span> <span class="n">i</span><span class="p">.</span><span class="n">relname</span> <span class="k">AS</span> <span class="n">index_name</span>
<span class="k">FROM</span> <span class="n">pg_class</span> <span class="n">t</span><span class="p">,</span>
<span class="n">pg_class</span> <span class="n">i</span><span class="p">,</span>
<span class="n">pg_index</span> <span class="n">ix</span><span class="p">,</span>
<span class="n">pg_attribute</span> <span class="n">a</span>
<span class="k">WHERE</span> <span class="n">t</span><span class="p">.</span><span class="n">oid</span> <span class="o">=</span> <span class="n">ix</span><span class="p">.</span><span class="n">indrelid</span>
<span class="k">AND</span> <span class="n">i</span><span class="p">.</span><span class="n">oid</span> <span class="o">=</span> <span class="n">ix</span><span class="p">.</span><span class="n">indexrelid</span>
<span class="k">AND</span> <span class="n">a</span><span class="p">.</span><span class="n">attrelid</span> <span class="o">=</span> <span class="n">t</span><span class="p">.</span><span class="n">oid</span>
<span class="k">AND</span> <span class="n">a</span><span class="p">.</span><span class="n">attnum</span> <span class="o">=</span> <span class="k">any</span><span class="p">(</span><span class="n">ix</span><span class="p">.</span><span class="n">indkey</span><span class="p">)</span>
<span class="k">AND</span> <span class="n">t</span><span class="p">.</span><span class="n">relkind</span> <span class="o">=</span> <span class="s1">'r'</span>
<span class="k">AND</span> <span class="n">a</span><span class="p">.</span><span class="n">attname</span> <span class="o">=</span> <span class="s1">'uuid'</span>
<span class="k">AND</span> <span class="n">t</span><span class="p">.</span><span class="n">relname</span> <span class="o">=</span> <span class="n">this_table_name</span>
<span class="k">ORDER</span> <span class="k">BY</span> <span class="n">t</span><span class="p">.</span><span class="n">relname</span><span class="p">,</span>
<span class="n">i</span><span class="p">.</span><span class="n">relname</span><span class="p">)</span>
<span class="n">LOOP</span>
<span class="n">RAISE</span> <span class="n">notice</span> <span class="s1">'drop index %'</span><span class="p">,</span> <span class="n">quote_ident</span><span class="p">(</span><span class="n">index_names</span><span class="p">.</span><span class="n">index_name</span><span class="p">);</span>
<span class="k">EXECUTE</span> <span class="s1">'drop index '</span> <span class="o">||</span> <span class="n">quote_ident</span><span class="p">(</span><span class="n">index_names</span><span class="p">.</span><span class="n">index_name</span><span class="p">);</span>
<span class="k">END</span> <span class="n">LOOP</span><span class="p">;</span> <span class="c1">-- index_names</span>
<span class="n">RAISE</span> <span class="n">notice</span> <span class="s1">'alter table % alter column uuid type uuid using uuid::uuid;'</span><span class="p">,</span>
<span class="n">this_table_name</span><span class="p">;</span>
<span class="k">execute</span> <span class="s1">'alter table '</span> <span class="o">||</span> <span class="n">quote_ident</span><span class="p">(</span><span class="n">this_table_name</span><span class="p">)</span>
<span class="o">||</span> <span class="s1">' alter column uuid type uuid using uuid::uuid;'</span><span class="p">;</span>
<span class="n">RAISE</span> <span class="n">notice</span> <span class="s1">'CREATE UNIQUE INDEX %_uuid ON % (uuid);'</span><span class="p">,</span>
<span class="n">this_table_name</span><span class="p">,</span> <span class="n">this_table_name</span><span class="p">;</span>
<span class="k">execute</span> <span class="s1">'create unique index '</span> <span class="o">||</span> <span class="n">this_table_name</span> <span class="o">||</span> <span class="s1">'_uuid on '</span>
<span class="o">||</span> <span class="n">this_table_name</span> <span class="o">||</span> <span class="s1">'(uuid);'</span><span class="p">;</span>
<span class="k">END</span> <span class="n">LOOP</span><span class="p">;</span> <span class="c1">-- table_names</span>
<span class="k">END</span><span class="p">;</span>
<span class="err">$$</span>
</code></pre></div></div>
<p>Hopefully this helps you move from text fields to uuid fields without having to do all the work I had to.</p>
I made a cell phone
2015-08-18T13:06:31+00:00
2015-08-18T13:06:31+00:00
https://baltaks.com/2015/08/i-made-a-cell-phone
Michael Baltaks
https://baltaks.com/
<p>What do you do when your 2G phone finally won’t work anymore? You create your own phone of course!</p>
How to adjust car mirrors correctly
2015-06-12T21:49:58+00:00
2015-06-12T21:49:58+00:00
https://baltaks.com/2015/06/how-to-adjust-car-mirrors-correctly
Michael Baltaks
https://baltaks.com/
<p>I am astounded that I’ve never come across this before. It really does eliminate the blind spot.</p>
<p>Passing cars on the M7 today, I watched as the car was visible in my side mirror <em>before</em> it was gone from my eye sight, and then appeared in the rear mirror before it was gone from the side mirror. Great for road safety.</p>
<p>Take ten seconds next time you drive your car and fix your mirrors.</p>
Passwords for the Manly Man
2015-04-14T14:49:06+00:00
2015-04-14T14:49:06+00:00
https://baltaks.com/2015/04/passwords-for-the-manly-man
Michael Baltaks
https://baltaks.com/
<p>Easy to remember, hard to crack, and manly as anything. (But anyone is welcome to use them).</p>
<p>Best used with something like <a href="https://lastpass.com">LastPass</a>, <a href="http://keepass.info">KeePass Password Safe</a> or <a href="https://agilebits.com/onepassword">1Password</a>.</p>
<p>This post inspired by <a href="https://www.youtube.com/watch?v=yzGzB-yYKcc">Edward Snowden on Passwords</a>.</p>
A Cooking Show For The Rest Of Us
2015-02-19T22:30:39+00:00
2015-02-19T22:30:39+00:00
https://baltaks.com/2015/02/a-cooking-show-for-the-rest-of-us
Michael Baltaks
https://baltaks.com/
<p><a href="http://thekateringshow.com">The Katering Show</a> feels like a cooking show I could really sink my teeth into. If I hadn’t already bitten off more of life than I can chew right now. I give it five ironic gold star stickers out of five.</p>
SpiderOak is serious about privacy
2015-02-19T22:12:06+00:00
2015-02-19T22:12:06+00:00
https://baltaks.com/2015/02/spideroak-is-serious-about-privacy
Michael Baltaks
https://baltaks.com/
<p>SpiderOak is a service a bit like Dropbox, which makes it easy to backup, sync and share files. But they take <a href="https://spideroak.com/zero-knowledge/">data privacy</a> so seriously, they put this prominently on their <a href="https://spideroak.com/mobile/">page about mobile access</a>:</p>
<blockquote>
<p>Here’s the deal: when accessing your data via the SpiderOak website or on a mobile device, you must enter your password. The password will then exist in the SpiderOak server memory for the duration of your browsing session. For this amount of time, your password is stored in encrypted memory and never written to an unencrypted disk. The moment your browsing session ends, your password is destroyed and no further trace is left.</p>
</blockquote>
<blockquote>
<p>The instance above represents the only situation where your data could potentially be readable to someone with access to the SpiderOak servers. That said, no one except a select number of SpiderOak employees will ever have access to the SpiderOak servers. To fully retain our ‘zero-knowledge’ privacy, we recommend you always access your data via the SpiderOak desktop application, which downloads your data before decrypting it locally.</p>
</blockquote>
<p>I think they’ve done just about as well as you could possibly expect to explain this issue clearly, while also providing the features that everyone wants.</p>
How the sun sees you
2014-09-26T09:08:04+00:00
2014-09-26T09:08:04+00:00
https://baltaks.com/2014/09/how-the-sun-sees-you
Michael Baltaks
https://baltaks.com/
<p>Wow. Just wow. I’m putting some sunscreen on.</p>
Fame and the Internet
2014-09-25T08:43:14+00:00
2014-09-25T08:43:14+00:00
https://baltaks.com/2014/09/fame-and-the-internet
Michael Baltaks
https://baltaks.com/
<p>I didn’t know anything about the events mentioned in this video, but you don’t have to in order to understand the point. And the core message is very much worth understanding, and spreading, because as the video explains, the very nature of fame has changed considerably due to the Internet, and none of us knows if it might happen to us.</p>
What is Functional Programming?
2014-09-19T08:10:12+00:00
2014-09-19T08:10:12+00:00
https://baltaks.com/2014/09/what-is-functional-programming?
Michael Baltaks
https://baltaks.com/
<blockquote>
<p>Usually, when you ask a question, [if] everybody tells you something different, you know it’s maybe not that easy.</p>
</blockquote>
<p>Manuel Chakravarty presented an excellent talk last month about Functional Programming, and how the Swift language fits into that world.</p>
<p>I’ve been unable to fully wrap my head around this topic for years, and I felt like I was missing something. So I was extremely grateful to have someone with his expertise explain that there is no single definition of what Functional Programming is, but rather that there are a whole set of techniques and technologies that can be useful to improve software quality. And after talking to him last night, I’m going to try learning a little Haskell, just to start rewiring my brain so I can write better software myself.</p>
David Mitchell on Machines
2014-09-05T16:07:14+00:00
2014-09-05T16:07:14+00:00
https://baltaks.com/2014/09/david-mitchell-on-machines
Michael Baltaks
https://baltaks.com/
<blockquote>
<p>And it’s also why machines now… pause.</p>
</blockquote>
<p>It’s not all progress, then.</p>
Posting a sentry
2014-08-15T15:23:09+00:00
2014-08-15T15:23:09+00:00
https://baltaks.com/2014/08/posting-a-sentry
Michael Baltaks
https://baltaks.com/
<p><a href="https://github.com/getsentry/sentry">Sentry</a> is brilliant. If you have to know anything about the operations of some specific software, that is.</p>
<p>And, you can choose between paying for a hosted service at <a href="https://getsentry.com/">getsentry.com</a>, or hosting the code yourself. I wasn’t sure whether it was the right solution for a project, so I opted to try hosting on <a href="https://heroku.com">Heroku</a> and see if that worked.</p>
<p>My first attempt used the fully free Heroku option, including the free hobby postgres database, and that worked fine, but quickly hit the database row limit of 10000 rows. So then I looked into the new AWS RDS Postgres option, since AWS has more flexible plans generally than Heroku, which means you pay either more or less depending on your usage, where Heroku makes the price more stable from month to month. There are a couple of ways to get sentry running on Heroku, and <a href="https://github.com/doptio/django-sentry-on-heroku">django-sentry-on-heroku</a> is the closest to how I ended up getting it working, but I also looked at <a href="https://github.com/fastmonkeys/sentry-on-heroku">sentry-on-heroku</a> for inspiration.</p>
<p>So I created the database, and updated the DATABASE_URL environment variable in the Heroku app, and it worked fine again, this time without the database row limits. However, very soon the app stopped responding and just became practically unusable. Looking into the AWS console I realised that the region had defaulted to US West, where Heroku is hosted in AWS US East. So the procedure to migrate was to create a new RDS instance in US East, and configure it the same way, and then copy the database across. With the postgres server in the same AWS zone as the Heroku web server, it works great again.</p>
<p>The procedure for migrating the data was:</p>
<div class="highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pg_dump -Fc "postgres://sentryadmin:password@sentrydb.random.us-west-2.rds.amazonaws.com:5432/sentrydb?sslmode=verify-full" > sentry.dump
pg_restore --host=sentrydb.random.us-east-1.rds.amazonaws.com --username=sentryadmin --dbname=sentrydb sentry.dump
</code></pre></div></div>
<p>We are using the Cocoapod “Raven” in our iOS projects to log directly from iOS devices to our sentry server, so we can easily see what’s happening with the iOS apps we’ve made. It’s really handy to be able to watch the iOS apps remotely.</p>
<p><strong>Update 18th August 2014:</strong> I’ve just changed the <code class="highlighter-rouge">sslmode</code> to <code class="highlighter-rouge">verify-full</code> from <code class="highlighter-rouge">required</code> now that AWS RDS supports certificate verification, as per the <a href="http://docs.aws.amazon.com/AmazonRDS/latest/UserGuide/CHAP_PostgreSQL.html#PostgreSQL.Concepts.General.SSL">AWS Postgres docs</a>. I’m also not sure that the <code class="highlighter-rouge">pg_restore</code> command above uses SSL, so you should use a temporary password for that restore, and immediately change the password afterwards, then ensure you set the Heroku DATABASE_URL with the verify-full option as well. I also neglected to add <a href="http://blog.daniel-watkins.co.uk/2012/07/deploying-sentry-on-heroku.html">the blog post I initially used to get Sentry up and running on Heroku</a>.</p>
Developers Don’t Just Build
2014-06-12T08:07:50+00:00
2014-06-12T08:07:50+00:00
https://baltaks.com/2014/06/developers-don’t-just-build
Michael Baltaks
https://baltaks.com/
<p>I love this description of developers that Horace Dediu wrote, in reply to comments about WWDC 2014:</p>
<blockquote>
<p>Developers don’t just build. Using an analogy of building or construction, they are architects and designers as well as contractors and craftsmen and artists as well as builders. And not of just of houses but of cities and communities. They see and think through tools and techniques for building and innovations in building materials. Innovations which allow them to imagine first and, later, to build new cities in ways that were never before possible.</p>
</blockquote>
Thinking Like A Bézier Path
2014-05-28T11:49:28+00:00
2014-05-28T11:49:28+00:00
https://baltaks.com/2014/05/thinking-like-a-bézier-path
Michael Baltaks
https://baltaks.com/
<p>David Rönnqvist has created the best tutorial I’ve ever seen. Worth viewing just to play with the curve drawing.</p>
Balance Your NSNotification Observers
2014-05-02T13:54:52+00:00
2014-05-02T13:54:52+00:00
https://baltaks.com/2014/05/balance-your-nsnotification-observers
Michael Baltaks
https://baltaks.com/
<p>One aspect of using NSNotifications I hadn’t encountered before, is that you can add the same observer for a particular notification multiple times, which will result in that observer having it’s method called multiple times.</p>
<p>I tend to balance out my own calls, which might explain why I’ve not seen it before, but in examining other code I came across this and I didn’t actually know about this behaviour.</p>
A Conference Call in Real Life
2014-04-16T22:41:42+00:00
2014-04-16T22:41:42+00:00
https://baltaks.com/2014/04/a-conference-call-in-real-life
Michael Baltaks
https://baltaks.com/
<p>I think anyone who has spent any significant time in a conference call will find this very funny.</p>
Stuff
2014-04-13T22:42:17+00:00
2014-04-13T22:42:17+00:00
https://baltaks.com/2014/04/stuff
Michael Baltaks
https://baltaks.com/
<blockquote>
<p>The good news is, if you’re carrying a burden without knowing it, your life could be better than you realize. Imagine walking around for years with five pound ankle weights, then suddenly having them removed.</p>
</blockquote>
Let's Photograph All Life
2014-04-13T21:53:00+00:00
2014-04-13T21:53:00+00:00
https://baltaks.com/2014/04/let's-photograph-all-life
Michael Baltaks
https://baltaks.com/
<p>“Here’s a great idea, let’s photograph all life on this planet.”</p>
Stepping Into The Future
2014-04-10T23:02:40+00:00
2014-04-10T23:02:40+00:00
https://baltaks.com/2014/04/stepping-into-the-future
Michael Baltaks
https://baltaks.com/
<p>Just to follow on from my last post about <a href="/2014/04/the-future-of-programming">the future of programming</a>, here is an article about some possible steps into that future.</p>
The Future of Programming
2014-04-10T13:41:12+00:00
2014-04-10T13:41:12+00:00
https://baltaks.com/2014/04/the-future-of-programming
Michael Baltaks
https://baltaks.com/
<p>I’ve always felt like I don’t know what I’m doing when it comes to software engineering. Watching this is the first time I’ve felt like maybe that has actually been a good thing.</p>
Heartbleed Bug
2014-04-10T13:10:13+00:00
2014-04-10T13:10:13+00:00
https://baltaks.com/2014/04/heartbleed-bug
Michael Baltaks
https://baltaks.com/
<p>Oh dear.</p>
Virtualised Radio
2014-04-07T19:14:53+00:00
2014-04-07T19:14:53+00:00
https://baltaks.com/2014/04/virtualised-radio
Michael Baltaks
https://baltaks.com/
<p>Skip past the intro of this video, and see apparently how 4k video will be broadcast over wireless.</p>
The Expert
2014-04-03T20:40:39+00:00
2014-04-03T20:40:39+00:00
https://baltaks.com/2014/04/the-expert
Michael Baltaks
https://baltaks.com/
<p>Funny, and slightly depressing. I wonder if the popularity of this video has any potential to improve this kind of project meeting?</p>
A Whine About NSDate
2014-02-27T16:40:09+00:00
2014-02-27T16:40:09+00:00
https://baltaks.com/2014/02/a-whine-about-nsdate
Michael Baltaks
https://baltaks.com/
<p>I really wish NSDate was not named NSDate.</p>
<p>NSTimestamp would be best, NSDateTime also fine; even NSMoment would work. But NSDate just causes confusion, because a lot of people think of a date as meaning something like “the first of November”. That’s a date in the calendar (some calendars), but the group of timestamps that make up that calendar date depends on what timezone you’re talking about. So you can’t even know what date an NSDate refers to without adding a timezone. If you think that sounds confusing, you’re right.</p>
<p>So, if you have a product on sale for the month of November, when does that time begin? The first of November, right? But the first second of the first day of November is a different timestamp depending on your timezone, so does the price begin at the same time everywhere in the world all at once, or does it begin when November begins where you are at that moment? And if you’ve opted for the beginning of November where you are, how do you store that? You can’t just use NSDate alone, because that is a specific moment which is only the beginning of November in one timezone.</p>
<p>To describe “the first day of November” you have to add to NSDate, perhaps by having a clear convention, like using midnight in UTC on that date. In this case a few category methods on NSDate can be a great help.</p>
<p>In any case, having a class named NSDate only adds to the confusion, where another name, in my opinion, might help make things clear.</p>
<p>And that’s all I really wish for.</p>
Make One And Pass It On
2014-02-02T20:54:28+00:00
2014-02-02T20:54:28+00:00
https://baltaks.com/2014/02/make-one-and-pass-it-on
Michael Baltaks
https://baltaks.com/
<p>I used to have a bad habit, and I sometimes slip back into it without thinking. This bad habit makes my code really hard, maybe even impossible, to test, which is a bit of a problem when I want to know that it works correctly.</p>
<p>What is this habit? It’s using an object right where I’ve made it. That might not sound too bad, in fact for some people that might sound completely normal, just like it always did to me. But in using the object in the same method where it’s been created, you’ve coupled together the creation and use, and so now how can you possibly test just the use on it’s own? Not very easily.</p>
<p>In Objective-C:</p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">untestable</span>
<span class="p">{</span>
<span class="n">SomeClass</span> <span class="o">*</span><span class="n">obj</span> <span class="o">=</span> <span class="p">[[</span><span class="n">SomeClass</span> <span class="nf">alloc</span><span class="p">]</span> <span class="nf">init</span><span class="p">];</span> <span class="c1">// make an object</span>
<span class="p">[</span><span class="n">obj</span> <span class="nf">doSomeWork</span><span class="p">];</span> <span class="c1">// Oh no, we've used it here, making this hard to test</span>
<span class="p">}</span>
</code></pre></div></div>
<p>The simple solution to this problem is to decouple the creating from the using of objects, by having an object passed in to the method where it’s used. That method can then very easily have a mock injected at test time, making testing very straightforward.</p>
<div class="language-objc highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="n">callMeInProduction</span>
<span class="p">{</span>
<span class="n">SomeClass</span> <span class="o">*</span><span class="n">obj</span> <span class="o">=</span> <span class="p">[[</span><span class="n">SomeClass</span> <span class="nf">alloc</span><span class="p">]</span> <span class="nf">init</span><span class="p">];</span> <span class="c1">// make an object</span>
<span class="p">[</span><span class="n">self</span> <span class="nf">easyToTestWithSomeClass</span><span class="p">:</span><span class="n">obj</span><span class="p">];</span> <span class="c1">// tell the doing code about it</span>
<span class="p">}</span>
<span class="k">-</span> <span class="p">(</span><span class="kt">void</span><span class="p">)</span><span class="nf">easyToTestWithSomeClass</span><span class="p">:(</span><span class="n">SomeClass</span> <span class="o">*</span><span class="p">)</span><span class="nv">obj</span>
<span class="p">{</span>
<span class="p">[</span><span class="n">obj</span> <span class="nf">doSomeWork</span><span class="p">];</span> <span class="c1">// in a test this can be a mock</span>
<span class="p">}</span>
</code></pre></div></div>
<p>That’s great, but I have to remember to do that, so I thought of a phrase to help me just at the point where I’m creating an object so I won’t accidentally use it right there. “Make one and pass it on”. Just a simple reminder to pass it on as soon as I’ve made it. It’s not difficult, and it makes testing my code much easier when I can just pass in mock objects and isolate the code under test.</p>
<p>Sometimes it’s simple things that are the most effective.</p>
Defining the term Unit Test
2013-11-27T15:59:05+00:00
2013-11-27T15:59:05+00:00
https://baltaks.com/2013/11/defining-the-term-unit-test
Michael Baltaks
https://baltaks.com/
<p>When you’re writing software, how can you know if some test code is a “unit test”?</p>
<p>The “test” part of the term is obvious, so let’s look at “unit”. What is the smallest unit of software? Perhaps a single line of code? Well, if you do want to run a single line of code, you’ll have to have some way of referring to it, like perhaps a name, and at that point what you have is a function or method.</p>
<p>So if a method is the smallest unit of software, then <strong>I define a unit test as a test where only a single method of production code is run</strong>.</p>
<p>Now it’s easy, just look at your tests, and if there’s only one production method being called, it’s a unit test. If there is more production code, then it’s some kind of integration test.</p>
<p>But why does this even matter? Well, I find it’s hard to go wrong with unit tests, because they are so focussed, and they are not likely to make the codebase harder to change later, because you’ll only have to change a few unit tests if you change a method, and it won’t affect any other code. Integration tests, on the other hand, are more complex, and you have to be careful that you’re creating worthwhile integration tests that add value rather than just make the codebase harder to change. It’s easy to accidentally couple different parts of the code together via these tests, and make things worse rather than better.</p>
<p>This is what I’ve found with my work anyway, let me know if you disagree.</p>
What Screens Want
2013-11-24T14:01:20+00:00
2013-11-24T14:01:20+00:00
https://baltaks.com/2013/11/what-screens-want
Michael Baltaks
https://baltaks.com/
<p>Frank Chimero has managed to brilliantly articulate a number of key realisations about the age of software. The message is about the medium, and here the medium makes up part of the message, so be sure to watch the short videos.</p>
The Overview Effect
2013-11-20T20:08:37+00:00
2013-11-20T20:08:37+00:00
https://baltaks.com/2013/11/the-overview-effect
Michael Baltaks
https://baltaks.com/
<p>Some great little video snippets of our planet in this short piece.</p>
Software quality in the wider world
2013-11-13T23:42:29+00:00
2013-11-13T23:42:29+00:00
https://baltaks.com/2013/11/software-quality-in-the-wider-world
Michael Baltaks
https://baltaks.com/
<p>I was thinking last night about how the software industry compares to other industries. In construction there are government building inspectors and safety standards, and restaurants have health and safety standards and inspectors - what if there were software code inspectors? Random audits of our test suite and production code?</p>
<p>How would that change the way we write our code? Or estimate the time required? How we define what needs doing, when it’s done and how we charge for the work?</p>
<p>And then today I read this <a href="http://blog.8thlight.com/uncle-bob/2013/11/12/Healthcare-gov.html">article on healthcare.gov</a>:</p>
<blockquote>
<p>“If I were in government right now, I would be leery of starting another big software project. I’d also know that big software projects are going to be necessary as our civilization gets more and more complex. So, if I were in government right now, I’d be thinking about laws to regulate the Software Industry.”</p>
</blockquote>
<p>Years ago I wondered when and how software would start to be regulated (around the time that people started being prosecuted for accessing a computer system without permission), but then in a “follow the money” strain of thinking I thought perhaps it would be insurance premiums that finally enforced some level of quality in software systems. That doesn’t seem to have happened.</p>
<p>Making software is a fairly new thing historically, and it’s <a href="http://blog.securemacprogramming.com/2013/11/story-points-because-i-dont-know-what-im-doing/">difficult</a>, but surely at some point society will stop only complaining about poor quality software, and instead demand better quality? In any case, I’m aiming to make high quality software now, so that I’ll be comfortable when the inspections begin.</p>
<p><strong>Update 15th November 2013</strong>: It does seem that somehow whenever <a href="http://www.osnews.com/story/27416/The_second_operating_system_hiding_in_every_mobile_phone">software is in some way regulated or certified</a>, that it actually has a negative impact on the quality. Perhaps it has to do with certification making the software less soft, and quality software needing to improve and adapt over time.</p>
Government Transparency
2013-10-22T14:12:26+00:00
2013-10-22T14:12:26+00:00
https://baltaks.com/2013/10/government-transparency
Michael Baltaks
https://baltaks.com/
<blockquote>
<p>In her statement to the Legislative Assembly on 23 June 2011, the Chief Minister indicated that the ACT Public Service would move to an information ‘disclosure as default’ position in all its operations.</p>
</blockquote>
<p>I have no idea how broad this is intended to be, but on the surface this sounds like a good thing.</p>
Why Great Software Takes Time
2013-10-10T09:33:06+00:00
2013-10-10T09:33:06+00:00
https://baltaks.com/2013/10/why-great-software-takes-time
Michael Baltaks
https://baltaks.com/
<p>This little story from David Smith is a great example of one of the many creative solutions that any software project needs.</p>
<blockquote>
<p>As with all great thoughts, while taking a shower I came up with an interesting alternative in the meantime. I got to wondering which values get truncated and which do not. It turned out that not all values greater than 10k get shortened, any number that happens to include two 1 digits is shown in full. So that led me to the workaround solution that will be shipping in version 1.1.1.</p>
</blockquote>
<p>Because this is a creative solution that came while taking a shower, it also demonstrates why <a href="http://www.joelonsoftware.com/articles/fog0000000017.html">great software takes time</a>: you can’t place these solutions on a schedule before they happen.</p>
Change The Way You Look At The World
2013-10-03T15:01:57+00:00
2013-10-03T15:01:57+00:00
https://baltaks.com/2013/10/change-the-way-you-look-at-the-world
Michael Baltaks
https://baltaks.com/
<p>Playing with maps for fun and education.</p>
You Need A Budget
2013-09-10T12:50:45+00:00
2013-09-10T12:50:45+00:00
https://baltaks.com/2013/09/you-need-a-budget
Michael Baltaks
https://baltaks.com/
<p>I really like the approach this site takes towards planning and keeping a budget, and I think the approach works with all kinds of planning, because a big part is realising that plans change as time goes on, and you have to constantly revisit the plan. Without that, plans are just a fantasy you throw away as soon as you start working on what you originally planned.</p>
Re-signing Enterprise iOS apps
2013-08-05T20:02:59+00:00
2013-08-05T20:02:59+00:00
https://baltaks.com/2013/08/resigning-enterprise-ios-apps
Michael Baltaks
https://baltaks.com/
<p>If you have ever supported In-House Enterprise iOS apps, you’ll know that every so often the certificate expires and you need to re-sign the app with a new provisioning profile.</p>
<p>This is something a lot of people who make iOS apps have to do, so of course when the need arose for me, I went looking for solutions that other people had already found.</p>
<p>But while the first script I tried looked like it worked, it failed to change the embedded provisioning profile. And then when I tried another set of manual steps, the package was missing the entitlements, meaning the app couldn’t access the iOS keychain.</p>
<p>So, after a few hours of work, I’ve built my own <a href="https://github.com/mbaltaks/vomitorium/blob/master/resign-ipa">ipa resigning script</a>, which I’ve successfully used to re-sign an existing ipa, one with an expired profile.</p>
<p>With this script, all you need is your expired ipa and a new provisioning profile using all the same details, and it’ll build you a new ipa that will be able to access the keychain data from the existing install.</p>
One Stilt At A Time
2013-05-10T14:03:15+00:00
2013-05-10T14:03:15+00:00
https://baltaks.com/2013/05/one-stilt-at-a-time
Michael Baltaks
https://baltaks.com/
<p>Jon Reid writes in a comment:</p>
<blockquote>
<p>“Either you’re coding to get a new test to pass, or you’re refactoring. But don’t do both at the same time. We’re basically walking on stilts: Lift one, or the other, but not both. By keeping one foot grounded, so to speak, we reduce the risk of falling over.”</p>
</blockquote>
<p><a href="/2013/05/is-tdd-worth-it%3F">I wrote the other day</a> that I have previously used “CDD” - “commit driven development” or “change driven development” and I often found that I had feature or bug fix code in with refactoring code to support it. And when git came along I could use GitX very easily to separate that code in the commits. So I’m yet to change my style to be able to stop, refactor as required, and then continue with the feature code. And it seems that that is only really feasible when you’re actually coding just one test at a time, as in this kata.</p>
<p>I’m not there yet, but I’ll press on.</p>