Classify your Hashes

The reason that I think that so many people loved Perl early on was how easy it was to make a deep object using HashRefs of HashRefs and ArrayRefs. Take this object and start passing it around between a bunch of subroutines that end up being hundreds of lines long, making modifications and adding things to the ‘Object’, causing unknown numbers of side-effects in code in other places.

Looking back, that’s one of the things that I love the most about good old C. Yeah, you can still do what is essentially a map in C if you really try, but it’s actually harder to do that than just to carefully define a struct (or in C++ a class) where the methods are clearly named, and define your class very clearly.

“But what if I don’t know the structure of the Object before I start?” – yeah, of course that happens, but in reality how often? When you build a YAML file with configuration data, you know what should be there. When you are returning data from a method, you know what the shape of the data is, so why be lazy? Let’s say you are working with a well established code base (generally this is picked up early in the wild, but in a Company, you’ll see this all the time – people just don’t actually have time to clean it up), and you see some method…

sub whatever_and_whatnot {
    my $retval = {
        status => ...,
        data_class => ...,
        actions => ...,
    };
    ...
    return $retval;
}

Then you should clean that up. Figuring out the shape of the object being returned shouldn’t be the job of Data::Dumper (regardless of the language, Ruby, Python, JavaScript all have this same problem). The nice thing though is that Perl really makes it easy to class this up compared to other languages (but it’s not built in), although Ruby and Python really are close:

package WhatNot::Result;

use Moose;

has ['status', 'data_class', 'actions'] => ( is => 'rw' );

1;

Is a really basic lazy start to your class. Now, if you change the code above to:

sub whatever_and_whatnot {
    my $retval = WhatNot::Result->new(
        status => ...,
        data_class => ...,
        actions => ...,
    );
    ...
    return $retval;
}

You can start extracting actions into your new class, simplifying your code in the long run, making it easier to maintain, and making it far easier to do unit testing. Adding new fields means you need to modify the class definition, doing a kind of ‘Lazy coder documentation’ (Code is not documentation, no matter what you want to believe). It also helps to move things closer to Functional Programming, which is always good (at least IMHO).

For Perl with Moose, Moose::Util::TypeConstraints with coercion also add a ton of really great stuff to your capability to build a deep object out of a deep hashref, which is also very cool.

Either way, rant off.

Advertisements

One comment

  1. […] One issue that I’ve tried to work around a few times has been the auto-classing of deep hash structures.  I don’t like using raw hashes for anything that isn’t unknown data – if you know the structure of the hash, it should be defined as a class.  Keeping it in a raw hash means that other developers need to go around and search for the potential contents of the hash, which can be unknown if you are mutating that hash in other parts of the code.  Also, the actions that are used to modify that hash are not encapsulated anywhere, so it’s impossible to know what can be done.  I covered more of my opinions on this in Classify Your Hashes. […]

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: