A Novice Refactors

Having read commentary about coding practices, meditated, contemplated, posted a blog entry about my app and begged for constructive criticism, I found my way into a significant refactoring.

I haven't seen much about the step-by-step process of dividing and modularizing code. Here how I am approching it.

The app already uses OO, but suffers from some 260 global variables and about 6k lines of code in the main namespace.

I broke that code into about 30 different modules, testing after creating each new module, with the help of git for source control, and a couple scripts showing which files and in which subs each variable appears

Most modules still occupy the same namespace, however have access to only the minimum necessary subset of global variables. I did this using a structure like this:

[Audio_engine_setup.pm]

 package main;
 our ( $sampling_frequency,.... )
 sub configure_freq { say "configuring soundcard at $sampling_frequency" }

All subroutines are still in the main namespace, so they work unchanged.

The 'our' declaration tells me exactly what global variables the module touches. So I can look at them and think: Do they need to be in the main namespace? Can they be lexicalized? Can they be passed as arguments?

A next step is to provide more separation by introducing a separate namespace.

  package main;
  our ( $sampling_frequency,....)
  package Audio_engine_setup;
  sub report_freq { say "soundcard is running at $sampling_frequency" }

These subroutines (and those in the main namespace they invoke) will have to be called with the full package affiliation, or be imported into the desired namespace via Exporter and 'use', or be converted to use some kind of OO.

Physically reorganizing the code provides an opportunity to partition functions, to define interfaces and to review provisional design decisions made years ago. Of course greater separation of concerns helps the software to be robust and to be readable. And having the code divided up helps anyone who wants to browse/hack.

How much separation is desirable practical is an open question. Most global variables are indices or configuration variables that are set once and read-accessed. Yes, anywhere it's possible to set them by accident. On the other hand, this is a single app, not a toolkit that will be (ab)used by other programs in an adverse environment.

4 Comments

For some (module set of some) applications, I never bother to separate into individual namespaces. Our developers know, for example, that by convention all Foo/Bar/*.pm are using the main namespace. But we still use separate files for organization and reducing startup overhead.

A propos passing by parameters - the advantage of using this style is that it's easier to test stuff. This is the basis of the Dependency Injection idea.

Leave a comment

About Joel Roth

user-pic I blog about Perl.