How Fast is Too Fast?

January 13, 2012 | categories: Web | View Comments

Speed Limit What???

I was recently fixing a bug related to a javascript sliding animation incorrectly computing its final position. When testing the fix, QA noticed that the sliding animation exhibited a little jitter that was not reproduceable in production. At first glance, it must be the fault of a new png being too "heavy" for the browser. Let's put the old one back. No change. Crap. There weren't any changes to the easing or the duration of the animation (change focused on DOM restructuring). I was starting to feel stumped.

Just then, QA also pointed out that one of the content regions on the page in test "flashed" its reload much quicker than the production version. In production, the reload didn't happen until ~ 1/2 second after the animation completed. In our new test version, the reload was happening almost immediately during the animation (which had a duration of 200ms).

As it turns out, our test server wasn't under much load, so the AJAX request was happening in ~80ms, as compared to ~800ms in production! So now, the reloading of the content region was consuming browser resources that could be spent on the animation. Wow, What a good problem to have!

This is when I went to a crazy place.

Jakob Nielsen quotes Miller and Card et al about response times by saying::

0.1 second is about the limit for having the user feel that the system is reacting instantaneously, meaning that no special feedback is necessary except to display the result.

1.0 second is about the limit for the user's flow of thought to stay uninterrupted, even though the user will notice the delay. Normally, no special feedback is necessary during delays of more than 0.1 but less than 1.0 second, but the user does lose the feeling of operating directly on the data.

I decided that any AJAX response < 200ms is just about the same as 200ms, especially when the users' eyes are likely distracted by the animation. I thought about waiting for the animation's complete event to fire the AJAX, but that feels like a lot of wasted time that could be processing the request. So I built a throttleAjax method that goes something like this:

/**
 * Execute an AJAX request using the given parameters, but don't let it
 * fire ``success`` sooner than the given minTime.  E.g.
 *
 *     throttleAjax({
 *         url:'/foo/bar',
 *         success:function(data) { alert('Got ' + data); }
 *     }, 200);
 *
 * Requires jQuery>=1.4
 */
function throttleAjax(params, minTime) {
    var start = new Date().getTime();
    var success = params.success || function(){};
    params.success = function() {
        var flight = new Date().getTime() - start;
        var stall = (flight < minTime) ? minTime - flight : 0;
        setTimeout(function(){ return success(arguments); }, stall);
    };
    return $.ajax(params);
}

// // GIANT DISCLAIMER: I haven't tested this version of code, it's more or less // an abstracted version from memory of what I wrote on company time. //

Now, you can fire off an AJAX request, then immediately start your animation. If the AJAX by itself takes > 200ms (or whatever your animation duration is) you get the response as soon as its done. If it ends up only taking 50ms, the browser holds on to it for ~150ms before handing it off.

If you depend on smooth animations to enhance your user experience, some things really can be too fast.

Read and Post Comments

I Want to Hire Scheduled Maintenance Programmers

March 24, 2011 | categories: Agile, Quality | View Comments

Maintenance programmers get a bad wrap. They're seen tucked away in the corner, frustrated, cleaning up others' bugs. Occasionally, they'll hack a new feature into old code, but without being there from the beginning, their code is usually clumsy. There's little chance to get in on a sexy new project building something cool.

South Morocco Town

In comes the scheduled maintenance programmer. The difference is in the problem they are presented. They're given a software product prior to it blowing up and challenged to make sure it's gonna keep running smoothly. Change the spark plugs, flush and fill, calipers and rotors -- whatever it takes.

Garage party with Lambretta Club Stockholm.

The principles of XP/TDD teach us to refactor our own code to ensure the highest quality before ever delivering it, but technical debt inevitably slips through. Often we abstract more than necessary, creating unnecessary complexity. Other times we miss an abstraction, forcing duplicated code. The scheduled maintenance programmer's role is to remove that debt, run/write additional tests (and automate them where not already), refactor to improve maintainability, and keep the ship moving at full steam ahead.

I want to work in a shop where these guys are respected. Where they take a Porsche, tune it up, and make it run like a Ferrari.

Read and Post Comments

Go Fast!

August 10, 2010 | categories: Agile | View Comments

"Going nowhere fast", or my $800 picture

I was reading Kill Zone by Gunnery Sgt. Jack Coughlin, and was struck by the personal mantra of one of the Marine snipers:

Slow is smooth, smooth is fast.

Even though lives aren't on the line when we step into work, it’s still important in the software industry to understand that sometimes we shouldn’t rush around like chickens with our heads cut off. When we sprint during an agile iteration, we must maintain control. During your project’s crunch time, this is most important.

Slow down, take a breather, and think before you slam in a bunch of crap code. All the technical debt you create has to be accounted for by someone.

Be the rabbit, not the hare.

Read and Post Comments

Python Decorators, SRP, and Testability

June 04, 2010 | categories: Python, Testing | View Comments

On the SRP: For those unfamiliar with the Single Responsibility Principle (SRP), it states that there should never be more than one reason for a class to change.

That is to say: do one thing, do it well.

Decorators (not to be confused with the decorator pattern) can add behaviors or side-effects to a method, and this can be dangerous. It seems harmless, because by adding a decorator, you’re likely taking boilerplate code and shuffling it elsewhere. However, they often encourage badness because of how easy it is to add these behaviors.

On Testing Decorated Methods:

Adding an @decorator to a python object unarguably makes the undecorated code difficult to test in isolation. Decorators are applied at compile-time, and cannot be mocked or made to not-execute without some pain.

There are certainly a few common tricks that can help test a decorated method with minimal side-effects, but they require changes to the decorator itself. There’s just plain and simple no way to un-decorate a method for isolated testing.

Let’s Look at a Few Common Examples:

@expose: register a URL for a view function in a web framework

class BlogPostController(object):
    @expose("/blog/{post_id}")
    def index(self, request, post_id=None):
        """ show a blog post """
        post = adapter.get_post(post_id)
        return render("show_entry.html", dict(post=post))

Without the @expose, your show_entry knows how to get a given post and render it in the proper template. With the decorator, it also now knows which URL corresponds to that. You now have multiple reasons for this block of code to change, including pointing to a different URL or using a different template. It’s preferred to have a separate module for managing which urls point to which views.

Harm factor: low. Ick factor: medium – high.

@cache: try to get the result from memcache, otherwise, execute the function and stick it in cache for next time

class PostAdapter(DataAdapter):
    @cache
    def get_post(self, post_id)
        """ grab a blog post from the database """
        return self.query(Post).filter(id=post_id).one() # SQLAlchemy folks need to talk to Demeter...

OK this seems cool right? You only hit the database when you have to, otherwise we get it even quicker by looking it up in the cache.

What happens if you want to disable caching? A separate cache abstraction layer would reduce volatility in your data adapter.

And what does the unit test look like?

class TestGettingAPost(object):
    def setup(self):
        self.query = Mock() #don't hit the production database!
        self.post_adapter = PostAdapter(query=self.query)
    def test_getting_a_post(self):
        assert self.post_adapter.get_post(123)

Damn, there’s no way to mock out the @cache decorator so it doesn’t run. Try to, I dare you. You’re likely going to actually get post 123 from your production memcache. Crappy. The only thing you can do is make the @cache grab the cache implementation from the PostAdapter instance (and mock that out in your test), or find some other sneaky way of disabling caching for test runs. But the @cache decorator isn’t all self-contained and fun anymore.

Harm factor: medium – high.

@validate: Make sure the request matches the specified schema, otherwise hand-off to error handler

class EditPostController(object):
    def _save_error(self, request, errors):
        """ @validate decorator kicked flow here, redisplay edit page with errors """
        ...
    @validate(schema, error_handler=_save_error)
    def save(self, request)
        post = self.schema.to_python(request.params)
        self.post_adapter.save_post(post)
        return redirect("/blog/{0}".format(post_id))

Without this @validate, there would be a lot of boilerplate code inside the save method. With it, any unit test for the save method will be likely linked to your schema. You’d have to make an actual valid request in order to test this method. That’s outside of any tests for your schema directly. That means double-coverage but 2 tests to update when requirements shift.

Harm factor: low-medium

Conclusions (or tl;dr):

As easy as it is to become infatuated with Python decorators, they definitely encourage you to violate the SRP. This can create a myriad of problems:

  • Difficultly in isolating system under test
  • Added complexity to enable testing
  • Redundant redundant unit tests
  • Making a code module more volatile than it ought to

They still have some valid use cases and can lead to cleaner code, however, as Master Yoda wisely said, “when you look at the dark side, careful you must be…”

6 Responses

  1. Aaron Says:

    Yeap. I tend to only use decorators after exhausting all other practical options.

    I despair when people act like they don’t cost anything.

  2. Gary Bernhardt Says:

    Thanks for writing this post so I don’t have to. :)

    TurboGears seems to get this more right than others. It uses decorators extensively, but they only add attributes to the function; they never actually wrap it. The result is that a TurboGears controller’s output is easy to test – you just get the template context dictionary when you call the function. No template rendering is even done.

    TG has other design choices baked in that are testing-hostile (global tg.request object, I’m looking at you!), but the decorators are unusually benign, which was a nice surprise for me!

  3. Matt Wilson Says:

    Nice post! But I don’t like the subtext that closures in general are sucky. Closures are beautiful.

    The problem comes from code that modifies parameters.

    A decorator like this:


    @expose("/blog...")
    def index

    Is really the same as rebinding the original name to something new, like this:


    index = expose(index, "/blog...")

    I find it hard to follow anything that works like that.

    So when I want to decorate a function, generally I’ll do it like this:

    exposed_index = expose(index, “/blog…”)

    Now there’s no need for fanciness in the tests. It should be easy to verify the behavior at each layer.

    When I use proper “@” decorators, I’m usually doing something like what Gary is talking about in TG. But in general, the @ syntax gives me the willies.

    PS: In your first example, based on the text afterward, maybe you meant to name the method show_entry. And Demeter is a chick :)

  4. Mike Says:

    Thanks for the comments everyone.

    @Matt: The beauty of closures is what makes decorators so appealing.

    The “decorate as a copy” would certainly be preferred to the “@” syntax, but I still don’t know that it addresses the root of the issue.

    In your example, you still need to test `exposed_index`, because likely that’s what you’ll want consumers of your class to use. What sort of tests would you write? You still can’t mock your imported `expose` method, so in reality you’ll need to assert all the behaviors of index as well as assert that expose did what it ought to (leading to even more test duplication).

    I think decorators and closures become most dangerous as they find their way into the lower layers of code. Near the top (view, presentation), we generally expect code to be more volatile and can sacrifice that for the elegant solutions they give us

  5. Matt Wilson Says:

    After I was confident that my index function worked right, and I was confident that my expose function worked right, I wouldn’t bother writing tests to make sure that I could compose the two.

    The only bug I can imagine showing up after combining expose and index would be due to some interface mismatch; like index returns None and expose expects index to return a dict.

    If that happened, I could just add a new test for index. No need to test the combination of index with expose.

    exposed_index is just an output of expose. If expose’s unit tests are written to cover the whole domain of valid inputs, what could go wrong, except when somebody feeds invalid inputs (e.g., a function that doesn’t follow the protocol)?

  6. Arun Says:

    Try this link also,

    http://arunnambyar.blogspot.com/2010/05/python-decorators-in-depth.html

    Its highly helpful.
    It is describing a to Z of python decorators..

Read and Post Comments

Rally Pairing

May 10, 2010 | categories: Agile | View Comments

Iwein Fuld posted a great article about different styles of pair programming. It’s a great post, and I encourage you to read it if you’ve tried pairing but haven’t bought in yet. His rally car analogy is spot-on.

My favorite driver is an outspoken dutch guy. He’s quick on the wheel and if he doesn’t get the idea I’m trying to convey to him he’ll just type something to try if that works. When he does get what I’m mumbling it’s on the screen faster than when I would have typed it myself, so it doesn’t give me time to get frustrated over things not being like the would be when I had the keyboard. And that gives me time to look for exits and pittfalls.

He also dismisses anyone that tries to say pairing isn’t as effective as coding solo.

No you’re not faster on your own, you’re just creating more crap for your colleagues to puzzle over and eventually delete. The code you write alone sucks. That guy that is getting on your nerves is trying to tell you (clumsily) that your code sucks, try to listen to him and you’ll turn into a better programmer. Or maybe you can teach him something and he’ll stop getting on your nerves. … If you’re slowing the other guy down, that’s a good thing. That will prevent him from writing code that you cannot maintain. If you don’t feel worthy of your colleagues code, get over it, or get off the team.

My biggest stumbling block to date has been the ratio of time driving to navigating when you’re pairing a senior and junior dev. Trying to balance productivity and mentoring isn’t always easy. I find allowing the Sr. dev to drive 2/3 of the time and Jr. dev to drive 1/3 strikes close to the optimal balance. Any more driving for the Sr and you’ll lose the Jr entirely as he rides along for the tour. Any less and you lose valuable time in guiding-by-doing.

Whether you’re the driver or navigator, take your role seriously. Share in the responsibility and help foster a mutual respect for the other.

Read and Post Comments

Next Page »