< prev 27 Feb 2015 to 14 Nov 2014 next >

Posts tagged 'debugging'

  • Learning to ask for help

    Years ago, I was having a fight with a girlfriend, and when things had settled a bit, we had a level-headed conversation about what I needed to do.

    One of the notes I wrote myself was to the effect of "Learning to ask for help, and getting it". Meaning, when I had problems, I expect(ed) to be able to deal with them myself, but that's not how being alive works. No one really get anywhere themselves.

    A couple years ago, my boss sent me a curt email saying that I needed to start asking people for help earlier on in the troubleshooting process, because it can save time. There's a balance between being helpless and always asking others to do your work for you, and never asking for any help. This is, basically, knowing the right time to ask for help even though you could solve your problems on your own.

    I was taking some pride in never asking for TA help on solo days, because there was never any problem that took longer than a couple minutes, but there were always more problems.

    I write about the future of schooling, and how teachers and TAs are education multipliers: they help lead students to good avenues of attack, and know when to step back and let them struggle a bit.

    Last night, I asked Jonathan for advice on an issue with the assets pipeline, and over the course of three quick interactions I was able to generate the behavior I wanted. (Why does every problem fix, including home DIY work, seem to require three tries? Is there some truth to fairy tales?)

    There is no intrinsic virtue to being able to do everything on your own, because the guy who doesn't have that hangup will far surpass you, even though you might feel more self-reliant.

  • Futility; Or: Old Habits

    Despite my half-vow last week to try to write more, it doesn't seem to have worked out that way. I only consider myself to have missed a single day (Friday), but that's enough.

    Thursday I left off having torn out my user auth and dropped in devise; I was getting frustrated with it by the late hour I left, whenever that was. I finally got it working today, and even though it's one of those things that's really powerful once it's up and running, there's so much going on with rails and devise metaprogramming that it was hard to pin down where the weird behaviors were coming from.

    Long story short: getting ajax sign-in working is highly non-trivial in devise, because it has a lot of expectations for how you'll be using it. There's no easy way to shove the user's account data down the pipe when logging in via ajax, and it's not clear from the documentation what's breaking.

    It turns out, though, that you can call respond_with with a :location argument, and rails does not respect that unless the :format is html. So when trying to debug what appears to be a straightforward statement, using the suggestions written by the devise authors, you're led to fixate on a couple small lines of code that actually have nothing to do with your problem.

    This is the double-edged sword of using a framework. Once you figure out enough of the gotchas to get things moving, you get a lot of reliability and power for free, but you're forced to either use things how they intend you to (in the given examples and configuration options) or hack up enough of the framework to bend it to your will.

    Oh, well; that's out of the way. I may have to generate a toy project using straight rails and vanilla devise authentication to see how it's supposed to work, because I'm not entirely happy with what I've got now. That seems to be the way of this latest phase of my final project: I've been adding things and discovering the limitations of a lot of the more robust options out there, and it's annoying.

    One of the things I added to my portfolio recently is a set of progress bars representing my knowledge of different tools. I was reluctant to do this, because any progress number seems quite arbitrary, but I'm willing to venture that one thing that represents knowledge level is when you begin to get frustrated with a tool.

    In fact, I'll put this forward: if we're all being honest, able to use something while using the documentation might be 10% knowledge; 20% would, then, be, able to complete simple tasks without reference to the documentation. 30% might be the point where you start saying "oh, this is neat!". At 40% you feel at ease; 50% would be the point where you have the documentation open, but you don't rely on it. By 60% you forget to even open the documentation, but at 70% you've got it open again because you're trying to do something that the tool just doesn't make easy. At 80% you're saying "oh, for god's sake"… at 90% you're patching the tool.

    It's rough, but it's something. With this framework, my resume is a bit of a lie, but it's close to accurate so I suppose I can leave it. And by this measure, I'm at 80% with some things I wrote as 70%, and 40% on some 50%s.

    I'm okay with this, in the end.

  • RACE CONDITIONS!

    Now that we don't have to blog, I can blog whenever I want—which also means blogging in the middle of the day when I've found some solution to a particularly knotty annoyance and am taking a break from whatever.

    I'll try to keep this quick, and I still don't have it how I want it.

    Sign-in is handled through a modal (using a library that is just okay…). When the app first starts, it tries fetching the currentUser model (asynchronously, of course). Meanwhile, it tries to route to whichever route was input, and if the user isn't signed in (which he won't be, because we're still waiting on a server response), it redirects to the sign-in window, which has an initializer that tells it to destroy itself when it receives a 'signIn' event over the Backbone.Radio eventsChannel.

    Meanwhile, the modal animates, and only adds its keybindings once the animation is finished. But the 'signIn' event is received in the middle of the animation, which means that the view is destroy()ed before it has attached its keybindings… which it does after the fact.

    Long story short, when a signed-in user refreshes the page, the sign-in modal installs listeners that get uninstalled before they're installed, and the next time the user hits "enter" the modal executes a "submit" event on empty text fields.

    I got around it by having an onShow callback that checks to see if we're signed in, and ONCE THAT CHECK HAPPENS, install the 'signIn' event listener. If that check fails (we've signed in during the 100ms that the animation has as default) then we uninstall ourselves.

    Gah. JavaScript, why you hurt so much?

  • The ghosts of problems long dead

    Friday, I thought I had sign-in working the way I wanted. Saturday, I spent the day wrestling with the order that actions hit in Javascript.

    I am hesitant to say that I think I've got it, but it makes a lot more sense—no matter what path someone takes to a URL, make sure to bottleneck actions that need to take place in a certain order in order to make sure that everything related to cleanup happens when it should.

    Originally, the sign-in model we were given had login set with async: false, which is deprecated and rightfully so. A good portion of my day was spent looking at a repeated message from JQuery stating as much, and once I figured out what needed to happen—the user, on sign-in, throws a signIn event that other objects subscribe and respond to—I was most of my way to getting the interaction happening the way I want.

    This is a lot of wasted time, but I have to say that I really understand async events much better now, as well as pub-sub. Whenever I think I know what I'm doing, though, I learn more, so I'm reluctant to say that I know everything I need.

    One other thing happened in that was particularly frustrating. I removed my homebrewed utils directory from the manifest, only to change my mind and keep it in to be able to take advantage of a couple that I thought were useful. Well, for two hours I was getting weird behavior that, it turns out, was caused by my own implementation of router callbacks. Whoops, shit. I'll have to keep an eye on that sort of thing in the future.

    I've noticed that it's nice using a common naming scheme when creating files, but it often makes it challenging to figure out which show.js you need to be editing, or is throwing the error you're looking at. It pays to take the three seconds to verify what you think is happening is what's actually going on.

    I had a similar problem with Wordpress—I was making changes that didn't seem to be showing up in the final render, and I went down a lot of paths before I figured out that there are actually three different blog post views: all posts, posts by category, and single post. That's not DRY at all :(

  • Never have I been so happy to get a blank screen before

    Holy crap. I wasn't sure if I could do it, but I've got my app rendering a blank screen.

    Some elaboration is required.

    I set out today to get the basic infrastructure of Marionette working, with a modal login screen, and a router before action that properly redirects after sign-in.

    At 9:30 tonight, I checked in the last code that was necessary to get this to happen.

    I am so happy. I thought, when we were first learning Backbone, that it was pretty opinionated, but it turns out that it's flexible, and requires more configuration than convention. Sure, there are things that backbone-on-rails tries to enforce, but that's not Backbone per se.

    Marionette, on the other hand, has some strong opinions, but the documentation is sparse enough that it can be hard to discern what those opinions are. Nevertheless, it desires certain things, and after a lot of secondary reading, I have figured out a lot of what those things are. For instance, Marionette wants you to modularize everything, but the Marionette.Module object is pretty ghetto and is slated for deprecation.

    In the meantime, then, one can use standard JavaScript modules and so forth to add in modular portions of an app, or (as I have) simply expand on the backbone-on-rails opinions by adding a folder for (e.g.) controllers and inserting it at the correct point in app startup. It works for now, but I may have to refactor later.

    And what a statement that is! Every single line I wrote in Backbone felt like it needed serious refactoring, but everything in Marionette is so DRY. Sure, there's a bit more "needless" code to pass messages, but that is in keeping with the spirit of loose coupling.

    Case in point: I spent a good deal of time learning about JQuery Deferreds, which are a means of handling promises in JQ. They're similar in behavior to Arel queries—they don't do anything until you resolve() them, and until then you can keep modifying them by tacking on further attributes. Pretty cool, if you ask me, although a bit of a trip to wrap your mind around. When reading Essential JavaScript and coming across the section on promises, I didn't quite understand them, only really understanding that they help cut down on callback hell… but I saw the reason for them. Now I think I can consider them a part of my toolbox.

    What did I do today, then?

    • Marionette is starting up
    • I have created regions
    • I can attach subviews to the correct region
    • Calls to routes that require login are properly intercepted
    • Once login succeeds, the original route is triggered
    • Login is actually working :)

    What did I learn?

    • Reading the docs, while essential, can only get you so far
    • At some point (earlier than you [ed: meaning 'I'] think) you need to sit down and just break things
    • Initially, at least, you're not going to have a damned clue what you're doing, so you have to just get the gist and then try things.
    • Act more than plan. (This is personal, and in reference to my current state.)
  • Week 9 Day 4 - Down to the wire

    Spent most of the day today trying to make up for lost time, which doesn't really work but most of the day I had that level of speed. I left the office at 11:00 last night and midnight tonight, and got in a half-hour late this morning because there just isn't enough time.

    A benefit to overthinking everything and going down blind alleys is that my bug-hunting skills are only getting better. After three productive hours prior to lunch doing… I barely remember, but something… I tried doing something a bit too clever (having to do with separation of concerns again), and didn't come up for air until after 6. From 6 to midnight I was plenty productive, but messing up like that still stings.

    In brief: I monkey-patched the Backbone Router prototype to offer callbacks before and after routing, and then tried using those hooks to grab a user who wasn't logged in and redirect them to the login page (while preserving state). Once again, on my way home, I think I understand what I was doing wrong, and can see how to fix it, but I ended up ripping most of that code out and leaving it basically exactly how we were taught in the auth demo.

    I still don't like having a currentUser global, but for my app it's not a terrible idea, since you need to have some purpose coming to a blackboard-like site. It's not like your typical modern website, where there's generally some functionality that's meaningful even without an account, so… whatever.

    Oh, so I remember now—one of the fastest ways to make me hate your website or app is to have data entry be painful. So I spent three hours making syllabus creation absolutely beautiful, modulo a couple tweaks, and ran into a bug that I couldn't figure out even with Tommy's help. Basically, I had the event creation success callback call a JQuery focus() event on the first field in the form, and it kept losing focus after render. So I said to hell with it, and installed a setTimeout call that waits 50ms then focuses back on the first field. Hacky, but resilient.

    No matter what I do, more of these sorts of hacks creep into my codebase. But then I see things like when iOS autocompletes a word, then you press punctuation, it backspaces and writes the punctuation and a space instead of just inserting it at the previous position.

    I can't decide if this says more about the UX rot of iOS or the inevitability of hacky solutions.

    Tomorrow we're presenting again and I think I'm going to bum rush the core features, no matter how they look, rather than polish anything. I have a TODO.md full of broken things, but that's just going to be the nature of the beast.

    Wanna know what kind of day it's been? I just remembered that I didn't eat my breakfast. I packed it in my bag 16 hours ago.

  • Week 6 Day 3 - Measure once...

    Today's partner: Wes

    Thank god for Jonathan's CSS lectures.

    We skipped the W6D2 content, which was supposed to be on CSS, but last week JT held lectures on CSS at the end of the day each day. Today, we took pre-baked JS solutions for the Tic-Tac-Toe game and Towers of Hanoi and made "visual" versions of them in the browser by using CSS selectors enabled by JQuery.

    Holy crap, that paragraph was a mouthful. Basically, instead of using (e.g.) Canvas (which, it turns out, is a difficult term to Google), or a text-only terminal to represent our game state and to select pieces/grid squares, we contrived to capture mouse clicks on a simple webpage, and then to draw game states using document properties of the webpage.

    The most important things we learned were the varied uses of JQuery selectors, and how to do basic styling with CSS. By the end of the day, the most we were struggling with were edge-cases in the implementation of our final project, Snake; JQuery and CSS were well under our belts.

    I've mentioned before that my memory is one of my best character traits. Well, after this week, I'm realizing that (syntax?) debugging is also another skill I have that others don't always. It's not entirely clear to me whether this is because of my deliberate pace when learning (and the consequent, presumably, deeper understanding that I can achieve), or if I just have more practice/skill than others—or if it's just because I only try the right thing after I've tried all the wrong things. No matter the root cause, I've been happy with my ability to read a stack trace or error message and smash the bug in question, most of the time.

    Wes, on the other hand, is much better than I am at identifying a minimum testable product. There were a couple times he had me tie something off and open it in the browser, and while I wasn't immediately certain what he was doing, as soon as we nipped a problem in the bud, I understood. I'd like to add this to my toolbox, too.

    Storytime: So it turns out that I'm not very good at games such as chess. My friend tells me that I have a comet-sized ego, and this was nowhere more visible than how I'd play games, especially when I was younger. At the time, I would play a move that could only be considered good if my opponent had no skill whatsoever… but my opponents were never were so bad as I wanted them to be, and inevitably they'd paint the floor with me.

    Typically, I want to code for a couple hours, and then run my code and have it be perfect. It is, perhaps, a skill to have the humility to know that you're not as good as you want to be, and (especially when testing carries low overhead) to test your assumptions at good breakpoints. "Measure twice, cut once."

    Or, in my case, measure three times, take a break, measure again, and cut once.

  • Week 1 Day 4 - Applied telepathy

    Today's partner: Michael C. (since there are two)

    I think I adapt to things within three days. Today just felt normal, like what I should be doing with my life. I know it's going to get much harder before we finish, and I keep pushing things onto the stack to go into more depth on over the weekend—but there is already plenty to keep me busy. Life's going to be tough enough on its own, and I should probably be getting up early Saturday morning and diving right in. I may have to work remotely to get away from distractions (although this hasn't been as big a problem as I might have thought - Facebook and reddit just aren't very interesting to me now that I have a stack of things to think about).

    I am still not getting enough sleep, and it doesn't seem to actually affect my engagement or 'awareness' during the day. It's an awesome feeling.

    The highlights of the day were working with procs and, again, the big projects toward the end of the day. We were wrestling with understanding how to write our own versions of a couple Enumerable class methods (my_each, my_select, etc) but the breakthrough on this matter came when we tried to express the same things in "normal" ruby code and then translated that work into our functions.

    For instance, normally, to double all elements in an array, you might write

    1
    
    array.map { |i| i * 2 }
    

    When defining your own function to receive that proc, you can start with something done in the standard ruby function calls:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    def my_map(&prc)
      result = []
    
      self.each do |item|
        result << prc.call(item)
      end
    
      result
    end
    

    Simply replace "each" with "my_each" and you've basically re-created standard ruby functionality. I assume that, even if it's not now written this way, at some point the ruby "standard library" looked something like this (albeit with more error handling).

    My partner mentioned at the beginning of the day that he didn't really understand why you'd use procs, and within a half hour we both got it.

    The work on recursion was solid practice. The first example took ten minutes, the second five, and each one after was simply an exercise in analyzing the higher-level problem. Satisfying, and excellent practice/pedagogy, but nothing earth-shattering. :)

    make_change, the recursive method for taking a list of coin values (for instance, in the US, 25, 10, 5, and 1 for quarters, dimes, nickels, and pennies) as well as an amount that you're trying to target and yielding the list of coins you'd return in order to make the target amount with the minimum number of coins, was easy, then absolutely maddening. We managed to describe the core logic within a half hour - about one line every 90 seconds, go figure - and then took another half hour in order to track down a crazy edge-case bug that was killing most of our results.

    Constance looked at our code for a good ten minutes before we nailed down what was actually going wrong. We had a specific test case that broke the method quickly, a bunch of ghetto debug statements (p for the win!) and basically total awareness about the state of the internal variables, and we still struggled to find what was causing this failure.

    It turned out that there was a loop condition that this edge case was falling through, returning nil when our calling function was expecting an array. It was such a specific edge case that I should have seen earlier, but I kept looking in the wrong places for this, and the doubt caused by that sort of weakened my learning. I spent five minutes doubting each level of my knowledge, until finally I was doubting whether < actually means "less than". I'll definitely need more practice overall, and to develop more facility with debugger… and I've gained some specific respect for the challenges software maintainers face every day.

    WordChainer, today's "capstone", was a blast. The spec was thorough, and my partner and I basically spent fifteen minutes reading sections of it to one another and getting code into the editor. What a delight a properly detailed spec is! Too bad I'll probably never see one again in my life, unless I write it myself! ;)

    It took us about two hours to get a very respectable and pretty clean class for this portion, overshooting the end of class by a half hour. Remarkably, by the last hour, I wasn't sure which one of us was actually driving or navigating. Michael and I were basically on a single wavelength, and passing the keyboard back and forth was mostly a formality.

< prev 27 Feb 2015 to 14 Nov 2014 next >