[erlang-questions] Decomposing Modules

zxq9 zxq9@REDACTED
Fri Nov 13 01:09:49 CET 2015


On 2015年11月12日 木曜日 18:48:25 Judson Lester wrote:
> I suspect I'm not alone in having modules that grow to unwieldy sizes. I'm
> starting to understand better general classes of module that make sense to
> address, but I'm wondering if there's advice about particular features
> within a module that suggest how to separate functions into smaller, more
> module chunks.
> 
> My slowly developing intuition is that it has a lot to do with the
> parameters of the functions, and I get the sense that there's a gap in my
> understanding that'll make the decomposition easier. Maybe a refactoring of
> those parameters that'll make the separation more obvious?

I would first ask "why is this a problem?"

Big modules are not inherently bad, but covoluted modules can be very hard
to read and maintain. One thing that sticks out to me is the mixing of
semantics. The business language is mixed with the language of math and the
language of the program's mechanics.

You can't avoid mixing program mechanics in there somewhere; its got to
run and be callable.

But consider this:

-export([statement_for_edge/1, edge_for_statement/1, remove_statement/2]).

The first two are pure functions that probably don't belong here. They seem
to be more general utilities (otherwise why export them?). The last one is
peculiar, as it is exported from this module, not called internally, takes
your #state{} record as an argument, and calls ets:match/2 on a table owned
by...? So that's sort of odd. Maybe that one doesn't belong here, either.
Your gen_server's state should stay with your gen_server.

There is also a remove_statements/3 function that (at first glance) does
not appear to be a plural form of remove_statement/2. Even if it effectively
is a plural form of remove_statement/2, remove_statements operates in a
very different way, wrapping change_graph/4 in nicer semantics.

It appears that you've implemented a graph manipulation utility -- and very
nearly a tiny graph database. It seems likely that the details of graph
manipulation are a *lot* more general than their specific application in
this product module (or rather what appears to be a product information
(task?) management module -- there is no explanation of how this module
fits into the system, so I'm left guessing). The module name is 'ergo_graphs'
I might consider making it actually be *just* a graphing module, and
create a separate 'ergo_product_manager_thingy' module that does all the
product specific stuff that relates to the broader application.

This difference between the general manipulation of graphs and the specific
way in which they happen to be used within your program may be why you are
beginning to get a creeping sense that "refactoring of those parameters will
make the separation more obvious". It seems likely that the graph-bits and
the gen_server bits can be separated in a useful way.

Blah blah. These are details.

My point is that there are signs that:

1. There are a likely few universal utilities mixed into the module.

2. The gen_server is not always being treated as a service.

3. The module is simply *going to be large* as long as it deals both
   with the business/application semantics and the details of how that
   translates to more general graph functions.

If this thing works *right now* then there is no rush -- but whatever
you can factor out of it would very likely become more generally useful
in other ways (maybe in other projects) later.

-Craig



More information about the erlang-questions mailing list