tags:

views:

50

answers:

3

Suppose to have a library which is developed in two levels: a core, low-level one, and a high level one. My design is focused at reducing the coupling between the two.

One of the routines of the high level layer accepts an enumeration (say, FOO=0, BAR=1, BAZ=2). This enumeration is used directly by the low level routines for its final purposes.

To design this, I have three choices:

  1. The high level routine accepts an enumeration encapsulated to the high level module, and translates one-to-one the high level enum into the low-level enum values. Advantages: lower coupling. Disadvantages: I sort of repeat myself
  2. The high level routine accepts the enumeration values of the low level module, and pass it "as is". Advantages: less typing, less duplication. Disadvantages: higher coupling.
  3. I create an "enumeration module" which is external and both levels depend on this enumeration module. Advantages: conceptual clarity. Disadvantages: Uber catch-all module with enumerations that are not near to their code.

Do you have any experience on this case? I would go with 1, as it reduces coupling, but I would like to hear your experience as well.

+2  A: 

I guess this depends on whether your levels are layers or tiers.

If the low level module is behind a web service interface then I'd go for #1 which is essentially achieved by the proxy code generated for you (certainly in the case of WCF or amsx services).

If they are different assemblies running in the same process then I'd be more inclined to go for a shared code solution, probably by creating a separate assembly with core enums and interfaces.

Chris Simpson
+2  A: 

I didn't get much the coupling problem here. IMHO, both levels should see the same enumeration (something more like option 3). The names in the enumeration should be high level names (so who reads it, may understand them well, not needing to understand the low level one), and its values should be unimportant for the high level part.

A problem I see with number one is a bigger maintenance cost and greater susceptibility to commiting errors. Like, suppose the value of an enumeration changes, or you should add another element. You must remember to change it in both parts, otherwise, you could have unexpected behavior and inconsistent data on your applications. Also, you will need a translation layer, resulting in more code to maintain

Hope it helps :)

Samuel Carrijo
+1  A: 

Sounds like your high-level layer is accepting a command or parameter from the user, that it passes along to the low-level layer, without actually having to know what it says.

If that is the case, then option #3: "break it out" is the way to go.

If the high-level layer has to do some processing on the command or parameter, AND it has to be passed to the low-level layer, then there's a good chance you've blown something in your choice of demarcation between the layers. The layers should NOT be concerned about each other's internal business.

If you do have to do this, then breaking it out is even more important, since you want BOTH layers dependent on the enumeration, and you WANT a change in the enumeration to force (at the minimum) recompilation of both sides. (make, dependencies, etc...)

Read Dijkstra's classic paper "Structure of the THE Multiprogramming System", and reflect on what it says about layering philosophy. It is on the UT Austin CS Department website, in the Dijkstra archive.