Wednesday, July 30, 2014

Physics can answer that question

Vin Scully (after an Upton brother fouls a ball off his foot): "You always wonder how something that weighs five ounces can cause so much pain."
E_\text{k} =\tfrac{1}{2} mv^2

Law is Code

Code is Law Lawrence Lessig
In a decision of startling breadth, the Court holds that commercial enterprises, including corporations, along with partnerships and sole proprietorships, can opt out of any law (saving only tax laws) they judge incompatible with their sincerely held religious beliefs. RBG
So it seems that Hobby Lobby was a patch release that aliased sudo to my god told me to. Except that sudo provides an audit trail and this new command does not, so it's actually a buggy patch release.

Sunday, July 27, 2014

I still hate computers, but I solved my problem

I finally solved the problem described in this blog post, in which, in order to improve my "Songs not in 4/4" website so that several different people could each have an opinion about the time signature of a song, I needed to figure out how to get a number from point A to point E in the website code.  This ended up taking 8.5 hours of work.  That doesn't count the work put in by kind souls who, when I gave up and asked for help, provided it.  This does not include the time spent recovering from the moment when, just I had just gotten everything perfectly poised (in nerd terms, the website hit the breakpoint and paused and I had the debugger open in a terminal) to dissect the final data transmission failure between, let's call them point D and point E, I was interrupted by a blowout by a certain mammal not to be named at this juncture but weighing under 20 pounds and sitting on the couch next to me, and while I was in the process of carefully separating this mammal from any solids and/or fluids and/or gels that may have been emitted, the uninterruptible power supply started keening, a sound that turns out to signify that, rather than uninterrupting the power supply, it had instead interrupted the otherwise perfectly acceptable power being supplied to my computer, causing not only the computer to shut down but the virtual machines I was working in to get confused, such that a problem I had solved weeks ago (nerd terms: a default expiration of 30 days on x509 ssl certificates is a pain in the ass thirty-first day that your webserver tries to talk to your database) returned from under the waves where it did eternal lie.  That all amounted to another hour or so.  Nor does it count the time spent replacing the mouse battery that just died while writing the last sentence.

So.  Problem solved.

The final piece of the solution was, in case you are curious, that
song_id = form.song_id 
needed to be
song_id =['song_id']

The identities and species of some individuals described in this post may have be modified to preserve anonymity.

That pitch was off the plate

Also, Kershaw allowed two hits and a walk, so he's still not at peak form.

Friday, July 25, 2014

The pain of programming: trying to get this little bit of data from here to there

So many things have been driving me crazy about my web development project that I got completely overwhelmed with trying to document it all.  So I'm picking one little thing to share, as representational of all of the barriers.  It's this:

I am trying to add Song Opinions to my "Songs not in 4/4" website.  I can now import the hundreds of Songs and Song Opinions that people submitted to the old, and I have the user interface for Songs working, if rudimentary.  So I'm really just adding Song Opinions to the user interface.  And in fact, I previously got it to where you can glimpse the Song Opinions when you look at the Songs.  On this screen:

"Action This Day" and "Queen" and "Hot Space" come from the Song table, and "2/4 (according to nic)" comes from the Song Opinions table.  Now I want to make "Add an Opinion" work.  I am relying on the time-saving conveniences of Django (which is why I picked it to try out as a web application framework), and indeed, I can get this whole form below to appear with only one or two lines of code *:

Where I'm presently stuck is this: When you click Done, the website needs to keep track of what Song you are submitting an Opinion for.  So I need to stuff a hidden field into this form that contains the number, 1259, which happens to be the arbitrary ID number in my database for Action This Day.  And figuring out the code to pass that number from the Add an Opinion link only took ten minutes (I had to force myself not to go dig up a debate I'd vaguely tracked about the implicit grammar of POST and GET and what was properly RESTful (c.f. this for just a taste.)  Be Agile: just get something working, and then perfect it later).  That code, by the way, is

<p><a href="{% url 'songs:song_opinion_create' %}">Add an Opinion</a></p>
Where I'm currently stuck is, okay, I can get that number from point A (the Song detail page) to point B (hovering somewhere in the aether, or more specifically, in the request context for the Song Opinions Create/Update form, whatever that means), but I can't get it to Point C, into the form on the actual web page for Song Opinions Create/Update, which is where it needs to be to get to Point D, whatever doohickey processes the form and saves the Song Opinion, so that the doohickey knows that I am talking about Action This Day.  I can see it in Point B, thanks to the lovely debug interface in Django:

But exactly what magic incantation of code will nudge it forward escapes me, even though I thought I had figured it out previously.  Some things that are not it, for your amusement:
{{ song_id }}
{{ context.song_id }}
{{ context:song_id }}
{{ request.song_id }}
{{ request:song_id }}
{{ request['song_id'] }}
{{ 'song_id' }}
{{ ['song_id'] }}
{{ please give me my song id }}
{{ I am begging you }}
{{ song_id }}
{{ I know I already tried that but I was hoping maybe you would give me a pass this time }}
Total time spent just on attempting and failing to add Song Opinions (including time spent on an ill-fated foray into poorly documented Generic Class-Based View Formsets, and time spent using Mercurial to easily sweep away the debris of that ill-fated foray, and time spent manually cleaning up the debris of using Mercurial to automatically and easily sweep away the debris of the ill-fated foray, and writing this blog post): over 3 hours and counting.

* If Song Opinion is already defined in the database, then the code necessary to get an almost working creation form for Song Opinions is:

class SongOpinionCreate(CreateView):
    model = SongOpinion
    form_class = SongOpinionForm

class SongOpinionForm(forms.ModelForm):
    class Meta:
        model = SongOpinion

and also
<form action="" method="post">
{% csrf_token %}
    {{ form.as_p }}
    <input name="song_id" type="hidden" value="{{ song_id}}" />
    <input type="submit" value="Done" />

and I guess also this:

     url(r'^opinion/create/(?P<song_id>\d+)/$', SongOpinionCreate.as_view(), name='song_opinion_create'),
Which altogether isn't too bad, although I do wonder why I need to specify the model in two different places, which is odd given that DRY (Don't Repeat Yourself) is one of the many guiding principles of the cool programmers these days.

UPDATE: I couldn't help myself; I had to google a bit more and finally fix this little problem. A solution, maybe not the best, who knows, is to add more code, because even though Django clearly knows what song_id is in the aether (as evidenced by its existence in the debug toolbar), before I can pull that information down in my template (point C in my model), I have to push it from one place in the aether to another, using this code:
    def get_context_data(self, **kwargs):
        context = super(SongOpinionCreate, self).get_context_data(**kwargs)
        context["song_id"] = self.kwargs.get('song_id')
        return context
Simple and elegant, right?  Just a matter of kwargs.

Friday, July 18, 2014

Quiz Question

Which is most disturbing?

a) empty boxes of artificial logs in the recycling dumpster of your apartment building, which does not have fireplaces or chimneys
b) six FedEx trucks clustering around a smaller FedEx van on a side street
c) listening to a 9-minute Meatloaf song and wondering if it's the abridged version

Monday, July 7, 2014

Getting context variables to display in the template, or, How Programming is like Knitting

Despite some interruptions, I've made much progress rebuilding my database of songs not in 4/4 time.  In about 10 hours (dating back over a month), I've built the new data model, gotten all of the old data (almost 700 songs, submitted by almost 100 different people) extracted from the old and loaded into the new one, and gotten a few pieces of the new interface working.  Since the new interface is barely more sophisticated than the tutorial, I kind of wished I were further, but part of mastering a new system is accepting the time-suck of the learning curve.  More on that in a minute; let's look at where I'm stuck now.

Here's the current screen to show a song, with a song displayed.  Sort of.

I know what data I want to display, and how I want to display it, and where the data is in the database.  And when I used Django's shortcut (Generic Class-Based Views) for displaying this, I got results pretty quickly.  But then I put the song and the opinion about what signature the song is into two different tables, so that people who disagree about a song's time signature can each make their case, and when I try to extend the page to include not just the song but the opinions, I get stuck.  After much googling and Stack Overflow, I'm pretty sure that the data I need has been passed along from the database to snake through a series of Django convolutions not entirely unlike the workings of a digestive system, but now my data is stuck in the rectum of the page rendering system.  I can see it up near the top of the Template context:

But.  I don't understand Python or Django well enough to know how to flush that data out the last little bite.  I had a bit of the same experience with OpenACS and TCL, where data structures like

set x [list a [list b] c]

seem to make sense but when you try to use them, you end up making the same mistakes over and over until you really grok them.  Here's a glimpse at the steepness of the learning curve to my Python data enema:

So it's like knitting. There's a point in the process of learning a new pattern where nothing makes sense and you feel stupid.  In knitting, the path forward seems to be to find some kind of mechanical instruction on how to proceed and to do so automatically, without understanding, and then after you've done it, right or wrong, you have a skeleton of facts to go back and hang the flesh of your mental model on.  I think that approach doesn't quite work with programming, but the meta-pattern of getting stuck, feeling stupid, finding a way—any way—to proceed, and then rebuilding your mental model one bit closer to reality, still holds.  At some point the following sentence will not only make perfect sense, but will be confirms your hard-won knowledge. 
Because Django’s URL resolver expects to send the request and associated arguments to a callable function, not a class, class-based views have an as_view() class method which serves as the callable entry point to your class.
But that point won't be day one.

Anyway.  Going back to task breakdown.  Here's what I have broken out for this mini-project:

Here's where this work breakdown fails:

First, I have to manually transcribe hours from Toggl to Redmine, I only do it when I finish a task, so Redmine doesn't know that I've put 9+ hours into Task 55, and therefore 10+ hours into the overall task, not 1.17.

Second, I probably should have broken up task 55, since I tend to work on this project 1-2 hours at a time, and a 9-hour task that's less than half done is too big to helpfully project or plan around.  Here's the task detail I wrote up for it:
Model:                 DONE
  Song:                DONE
   - Song              DONE
   - artist            DONE
   - Album             DONE
   - uniqueness?       DONE

  song_opinion         DONE
   - PK to song        DONE
   - PK to user        DONE
   - origin            DONE
   - time signature    DONE
   - link to song      DONE
   - notes             DONE

 - Model testing       ?
 - View testing        DONE
 - interface testing   ?

- fix object name for admin

 - LCRUD for Song and Song_Opinion
   - LIST
     - basic list                    DONE
     - Song, Artist, signature
     - pagination                    DONE
     - filter
     - sort by column head
    - basic                          DONE
    - add Song_Opinion
   - READ
    - basic                          DONE
    - add Song_Opinion
    - basic
    - add Song_Opinion
    - basic
    - cascade to Opinion
    - delete Song_Opinion only

 - Navigation
   - breadcrumb

- Bring tests current again 
Third, when I came up for air from task 55, I realized I had already done Task #92 and part of task #93.  So should I bother to move a few hours back from 55 to those tasks?  Or just close them out as done with 0 hours each, which would mess up a hypothetical report on average time per task?  More things to ponder for the ultimate task management system.

Sunday, July 6, 2014

Finite State Machine for newborns

Based on observation, here's the principal FSM for newborn babies:

Here's a more advanced theoretical model, which sadly is not supported by the evidence:

Wednesday, July 2, 2014

It's important to always have a few different knitting projects in progress

Or else you might find that you don't have the brainpower to plan something new, and don't have anything suitable to continue, and you might just idly make a legwarmer because it's simple, and then when you get half-way through the second one you might realize that socks would be better, and then you have to dig up a toe-last pattern and sort of wing it, and you end up with one cold foot.

The Ravelry project.