[Chicago] Factoring fun with functions in Python

Garrett Smith g at rre.tt
Wed Nov 14 16:09:45 CET 2012


The thinking here is that, if done right, you can look at any single
function and know exactly what it does. You don't need to look
anywhere else, unless you're curious about another function.

If you look around the room, you'll see thousands of things. But you
never get overwhelming (hopefully) because our brains are very good at
filtering out what isn't important, until it becomes important. Then
we focus on that.

The number of functions shouldn't matter. The obviousness of each
function should matter. The more lines of code a function has, the
less obvious it is.

More importantly, lines of code contain logic that can be more clearly
expressed as a function. By asking, "what's going on here" when you
look at a block of code, you'll discover that you've made decisions
without thinking carefully. A function forces you to map that informal
thought into something precise:

- A name
- A set of inputs
- A set of outputs or side effects

If you drive these mystery blocks (these can be as innocuous as an if
statement or a for loop) into functions, I think you'll find that your
code improves dramatically. First, you're thinking harder about the
problem and solution and second, you're leaving behind artifacts that
are obviously correct, at least according to your intent.

I'm not sure I buy that it's a good idea to group functions together
to better understand "the big picture". The big picture of course is
entirely relative, but if you're interested in a higher level
function, you can look at that function. In the tutorial/example that
big picture is this:

def print_db_table_row_counts(db_name):
    cur = db_cursor(connect_db(db_name)
    print_row_counts(row_counts(all_tables(cur), cur)

This may be all I ever need to know. But if I need to know about a
"smaller" component (it's a matter of perspective) then I can look
there, and see that picture clearly. E.g.

def print_row_counts(counts):
    for table, count in counts:
        print "%s %i" % (table, count)

It is tempting to look at all those functions and think, "whoa, that
looks really confusing" but I've found in practice that it's not
confusing at all -- I just choose where to look and where I look is
usually clear and straight forward.

As an aside, we often group functions together as a result of side
effects [1]. We need to group them tightly because they modify a
common set of resources, typically state/memory. Objects e.g. are used
to "hide" state and provide controlled access to it via related
functions. Traditional OO language features allegedly make all this
better for us.

In functional language circles, side effects are something to avoid
wherever possible. Functions are semantically math formulae that don't
modify the external world. In this form, functions are a wonderful
thing because they tell *exactly* what's going on -- no side effects.
When you get side effects, you need to ask, "what's going on *here*,
and also what is going on *who knows where*?"

While it's hard to avoid side effects entirely (e.g. printing to
stdout is a side effect), we can certainly be aware of them and try to
make our functions side effect free as much as possible. If we're
purists, we can use a language like Haskell that handles this problem
explicitly [2].

I would suggest that you at least keep this method in mind when you're
programming. If you have a block of code that's more than a couple
lines -- just for fun -- try to identify "what's going on there" and
put it into a function. As it's an experiment, you don't need to worry
too much about things getting complicated. You might be surprised that
it's actually not so bad, or you might confirm your suspicion. Either
way, it'll be fun :)

[1]  http://en.wikipedia.org/wiki/Side_effect_(computer_science)

[2] http://www.haskell.org/haskellwiki/Monad

On Tue, Nov 13, 2012 at 10:35 PM, Dan Krol <orblivion at gmail.com> wrote:
> One thing I struggle with on this count is that spitting it up to this
> degree makes it confusing all over again, because there's so many functions,
> so many lines of logic to follow. There's no indicating what the "main idea"
> is, you just have to read it all to find out what isn't being called by
> everything else.
>
> The only solutions I've come up with are A) making functions small but not
> that small, and B) defining functions inside other functions, so that it's
> clear what functions are there purely for the benefit of other functions.
>
> Any ideas on that front? Isn't there such a thing as splitting functions up
> *too* much?
>
> On Nov 13, 2012 2:10 PM, "Cezar Jenkins" <emperorcezar at gmail.com> wrote:
>>
>> I like it.
>>
>> At one point, many moons ago I was a youngling and didn't think that
>> readability was paramount.
>> Then I inherited a giant jumbled PHP app. We now use Python.
>>
>> On Nov 13, 2012, at 10:59 AM, Garrett Smith <g at rre.tt> wrote:
>>
>> > As penance for missing the last several Chipys, I've extended "solving
>> > embarrassing obvious problems" to Python:
>> >
>> >
>> > http://www.gar1t.com/blog/2012/11/11/more-embarrassingly-obvious-problems/
>> >
>> > Will be interested to hear feedback from this group :)
>> >
>> > Garrett
>> > _______________________________________________
>> > Chicago mailing list
>> > Chicago at python.org
>> > http://mail.python.org/mailman/listinfo/chicago
>>
>> _______________________________________________
>> Chicago mailing list
>> Chicago at python.org
>> http://mail.python.org/mailman/listinfo/chicago
>
>
> _______________________________________________
> Chicago mailing list
> Chicago at python.org
> http://mail.python.org/mailman/listinfo/chicago
>


More information about the Chicago mailing list