Temporary variables are good

Maddingue on 2007-09-12T10:05:29

First step for understanding a complex code with very deep structures: remove useless brackets, add temporary variables.

sub Dumpbbcs
{
	my $css = $_[0];

	print "Content-Type: text/plain\n\n";

	foreach my $owner ( keys ( %{${${$CSSDUMP{CSSS}}{$css}}{OWNERS}} ) )
	{
		foreach my $content ( keys ( %{${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}} ) )
		{
			my $enable = ${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{ENABLE} if ( exists(${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{ENABLE}) );
			foreach my $service ( keys (  %{${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{SERVICES}} ) )
			{
				my $ip = ${${${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{SERVICES}}{$service}}{apSvcIPAddress} if ( exists(${${${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{SERVICES}}{$service}}{apSvcIPAddress}) );
				my $state = ${${${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{SERVICES}}{$service}}{apSvcState} if ( exists(${${${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{SERVICES}}{$service}}{apSvcState}) );
				my $KALType = ${${${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{SERVICES}}{$service}}{apSvcKALType} if ( exists(${${${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{SERVICES}}{$service}}{apSvcKALType}) );
				my $SvcKALUri = ${${${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{SERVICES}}{$service}}{apSvcKALUri} if ( exists(${${${${${${${${$CSSDUMP{CSSS}}{$css}}{OWNERS}}{$owner}}{CONTENTS}}{$content}}{SERVICES}}{$service}}{apSvcKALUri}) );

				if ( defined($enable) && ($enable eq "enable") && defined($ip) && defined($state) && defined($KALType) && defined($SvcKALUri) )
				{
					print "$owner $content $enable $service $ip DNS $state $KALType $SvcKALUri\n";
				}
			}
		}
	}
}
becomes:
sub Dumpbbcs {
    my ($css) = @_;
    my $owners = $CSSDUMP{CSSS}{$css}{OWNERS};

    print "Content-Type: text/plain\n\n";

    foreach my $owner (keys %$owners) {
        foreach my $content (keys %{ $owners->{$owner}{CONTENTS} }) {
            my $cont_fields = $owners->{$owner}{CONTENTS}{$content};
            my $enable      = $cont_fields->{ENABLE} || "";

            foreach my $service (keys %{ $cont_fields->{SERVICES} }) {
                my $serv_fields = $cont_fields->{SERVICES}{$service};

                my $ip          = $serv_fields->{apSvcIPAddress};
                my $state       = $serv_fields->{apSvcState};
                my $KALType     = $serv_fields->{apSvcKALType};
                my $SvcKALUri   = $serv_fields->{apSvcKALUri};

                if ($enable eq "enable" and all {defined} $ip, $state, $KALType, $SvcKALUri) {
                    print "$owner $content $enable $service $ip DNS $state $KALType $SvcKALUri\n";
                }
            }
        }
    }
}

(Ok, I cheated, I'm also using List::MoreUtils's all (this module rocks)).

Both functions should do exactly the same thing, except than the corrected form is actually readable and probably a lot faster given the number of opcodes such long dereference chains take (run perl -MO=Terse on these).

OTOH, these ${..} may be a technique obfuscators can use in the future ;-)


The real win here is DRY

jordan on 2007-09-12T13:55:42

Temporary variables can be good and can be bad. The real win here is that you Don't Repeat Yourself.

Not only is all that embedded stuff hard to read, it's dangerous and difficult to debug if a typo sneaks into one of the many repeated strings that are present.