Monday, July 6, 2015

Saturday, July 4, 2015

Amateur programming: one error after another

I want to give non-programmers a taste of what programmers are actually doing all day long.  In this post, I'll show what sloppy trial and error programming looks like.  Specifically, I wanted to add a new feature to Whatnext, the nihilistic task management system.  When I start a time, I want to see the project in Toggl. Instead of this:
I want this:
This should be pretty straightforward.  I already had code that did something very similar, so I used it as a model and wrote out all of the code that I thought would be sufficient to do this.  I treated it like the first draft of prose, and didn't go back to test any of it until I had the whole thing expressed.  Altogether, it was about seventy lines of code. Presented here, for your entertainment, are all of the errors. One at a time.  First error:
'Task' object has no attribute 'tag_set'
Why did I write tag_set? Because, according to the documentation:
By default, this Manager is named FOO_set
So why the error? Because
You can override the FOO_set name by setting the related_name parameter in the ForeignKey definition.
Did I in fact set the related_name paramater in the ForeignKey definition, months ago? Yes, to tags.  I fix that and see the second error:
'NameError' object has no attribute 'message'
Long story short, this is actually an error about how the code that is supposed to handle errors is having an error while handling an error.  I'm lazy and make a guess as to what the underlying error is.  I guessed correctly; the third error is
'MissingSchema' object has no attribute 'message'
This is still the superficial error.  This time, I take a moment to fix the error-handling code, so that it will share the real error instead of masking it behind a new error. Now I can see the fourth error:
Failed to create Toggl project. Invalid URL 'x/projects': No schema supplied. Perhaps you meant http://x/projects?
This is happening because the code I wrote assumes that some information is in the database, but I didn't remember to actually put that information in the database.  I add that information to the database, and get the fifth error:
Failed to create Toggl project. 'tuple' object is not callable
This one takes a second; I put a debugger command into the code so that, at the moment of the error, I can poke around and see what's happening.  It turns out that when I was copying some of my own code I ended up with an extra comma.  I remove the comma and reveal the sixth error:
local variable 'toggl_project_id' referenced before assignment
The problem here is that my code makes a (clearly) false assumption about what could go wrong.  I educate it about some more things that could go wrong and get the seventh error:
local variable 'e' referenced before assignment
This is another sloppy self-copy.  I fix it and get the eighth error:
Failed to create Toggl project. 404 page not found
I make a stab in the dark that this has something to do with the double-slashes in https://www.toggl.com/api/v8//projects. I take out the extra slash and get the ninth error:
Failed to create Toggl project. invalid character 'w' looking for beginning of value
This draws my attention to some what-was-I-thinking code, which I fix. Error number ten:
'"project"'
Looking at the code I was copying from, I play a hunch and change something, but I'm wrong and get the eleventh error:
Failed to create Toggl project. invalid character '{' looking for beginning of object key string
Okay, no hunches, time to re-learn exactly what all of these curly brackets are doing. I'm going to skip past five or six more errors that represent trial and error without progress.  I ultimately sort out the bracket situation and get the twelfth error:  
Failed to create Toggl project. Name has already been taken
That reveals a profound conceptual error with my design. If anyone ever has a Toggl account and has set up Projects in their Toggl, and then starts using Whatnext and recreates their Toggl Projects as Whatnext Tags, and sets up Toggl integration, and starts the clock on a task that uses one of those Projects/Tags, they will get an error.  I'm not going to spend an extra hour tonight to deal with that hypothetical, so I make a quick manual update to the database to avoid this problem.  I reload and get the same error, but now for a different reason. Another coding error is causing the code to skip the manual entry I just made. I guess that's error thirteen. I fix that but introduce another error in the process, error fourteen.  
Cannot resolve keyword 'system' into field. Choices are: id, remote_system, remote_system_id, remote_value, tag, tag_id
I fix that and am up to error fifteen: 'QuerySet' object has no attribute 'remote_value'
I fix that, and now my new feature executes without an error.  It does not, however, actually do what it's supposed to, add a Project in Toggl: