Re: So much interconnectedness - good or bad?
by graff (Chancellor) on Dec 17, 2004 at 04:48 UTC
|
To me, the term "module" tends to relate to the notion of "being modular", which gives a sense of being an independent piece that can easily be snapped together with any number of other independent pieces in order to make a vast assortment of different things, or used by itself just to do a particular task.
What you're describing seems different. Your A,B,C and D are not independent: if you need to use any one of them, you end up needing all four. It's not clear what sort of functional or objective specialization (if any) is leading you to make A,B,C and D separate, but if they're as interconnected as you say, maybe they shouldn't be separate.
Having a module depend on one or more others makes sense when the dependency is based on inheritance, or if the object defined in one module is supported by a "helper" or subordinate object in another module (like Archive::Tar, an object for a tar set, uses Archive::Tar::File, an object for an individual data file in the tar set). But a common property of such dependency is that it is unidirectional in some sense.
I'm actually a little puzzled about a design where "A uses D" and "D uses A". Why would these be two separate modules?
You haven't given enough detail, but one guess that comes to mind is that you could do a better job of dividing things up so that dependencies aren't going in all directions: the parts of D that are used by A and C might belong in a fifth module "E", which would then be used by A, C and D; and similarly for the parts of A, B and C that are used by D, etc.
Also, since these are modules, I'm assuming you're envisioning a set of apps that will use them. Is there ever a reason that an app would use D rather A (or vice-versa)?
If you haven't looked at Damian Conway's book Object Oriented Perl, it would probably be worthwhile to check that out. | [reply] |
|
| [reply] |
|
Thanks, graff!
I added the words most/a few functions of. Module B isn't entirely dependent on D. It uses one or two exported functions of D. I guess that still makes the design a bad.
Later, I do hope to rewrite the smaller modules to make them OOish. Before that, I really have to get my hand on Damian Conway's book.
| [reply] |
Re: So much interconnectedness - good or bad?
by stvn (Monsignor) on Dec 17, 2004 at 04:01 UTC
|
In general I strive for as much decoupling as absolutely possible. Now this does not mean things are not connected, it only means that they are not hardwired. This is where polymorphism is so great. Now I suspect your description is not of an OO design, but consider it from an OO perspective for a second:
If Module A used a type-of D, and Module B used a type-of A and a type-of C and Module C used a type-of A and a type-of D, etc etc etc.
The big idea here being that you never hardwire D to A, but just make A expect an instance of something which looks like a D, and acts like a D, but does not have to actually be D.
However, very often "what you should do" (decoupling) and "what you need to do" (interconnectiveness) collide. It just takes experience to know when you actually over-engineering something, and when its good design.
Well thats my 2 cents, now its bedtime.
| [reply] |
|
| [reply] |
|
Err, won't help. OO folks often achieve even more tightly coupled code than they set out to avoid -- what I guess I'm saying here is start thinking "heavy" OO (read c2.com and such) and you'll be ok, but to just be OO for the sake of it -- as most do -- you'll hang yourself because you'll have a lot of rope to do it with!
| [reply] |
Re: So much interconnectedness - good or bad?
by sgifford (Prior) on Dec 17, 2004 at 05:08 UTC
|
It's not necessarily bad; it depends on the situation. The purpose of procedural modules is to promote code re-use and stop you from re-implementing the same thing in multiple places. If it's doing that and it's maintainable, it's fine.
On the other hand, if the modules that the various functions are in is haphazard, the modules are difficult to maintain, or if all programs end up including all four modules, it's worth spending some time coming up with a better design.
| [reply] |
|
| [reply] |
Re: So much interconnectedness - good or bad?
by Anonymous Monk on Dec 17, 2004 at 03:42 UTC
|
Is such interconnectedness bad?
Yes.
Is it a particular feature of procedural perl and not OO perl?
No, circular dependencies are not dependent on style.
Or is it just bad design by the programmer?
Yes, it is just bad design by the programmer.
| [reply] |
|
Yes, it is just bad design by the programmer.
Okay, i will agree that from the short desciption of the design it does not sound like it is very good. But interconnectness and circular dependencies are not always bad design, sometimes they are a fact of life. A, B, C, & D are not very descriptive, but take something like Car, Engine, Tires, Brakes & Steering. They are all tightly interconnected, and require intimate knowledge of each other. Good design also means knowing when to break the "rules" too.
| [reply] |
|
take something like Car, Engine, Tires, Brakes & Steering
If your "Tires" module requires something from any of those other modules, you've got the wrong design for "Tires"; likewise for Engine, Brakes and Steering. Obviously, a "Car" object needs instances of the other four objects, but there is a limit to how "intimate" the Car should be regarding the internals of the others. Really good design means knowing how to maintain a modicum of simplicity, both in the individual pieces and in how they are assembled.
| [reply] |
|
Re: So much interconnectedness - good or bad?
by ysth (Canon) on Dec 17, 2004 at 07:00 UTC
|
I can't help but think of Cwd and File::Spec, caught in a nasty loop of interconnectedness that gave birth to PathTools. | [reply] |
Re: So much interconnectedness - good or bad?
by dragonchild (Archbishop) on Dec 17, 2004 at 14:35 UTC
|
connectedness is good - it means you're reusing code. interconnectedness is bad - it means that you have tight coupling.
The problem is that you have circular dependencies. The ideal situation is that when you look at your dependencies in a picture (circles showing the modules, arrows showing the dependencies), you should never be able to start in one place, follow the arrows and end up where you started. If you can, you need to refactor.
Already, you can see that you have cycles between C & D, and A & D. It sounds like you need to revisit which functions live in which modules. It may be that you need to refactor the functions themselves. Maybe a function is doing too many things at once. :-)
Being right, does not endow the right to be rude; politeness costs nothing. Being unknowing, is not the same as being stupid. Expressing a contrary opinion, whether to the individual or the group, is more often a sign of deeper thought than of cantankerous belligerence. Do not mistake your goals as the only goals; your opinion as the only opinion; your confidence as correctness. Saying you know better is not the same as explaining you know better.
| [reply] |
|
Thanks, dragonchild!
Good to know it's not all that bad.
I plunged into the coding without formal planning. As I add more and more lines of code, the complexity of the inter-connections grows.
It's time I do the circles and arrows thing.
| [reply] |
Re: So much interconnectedness - good or bad?
by DentArthurDent (Monk) on Dec 17, 2004 at 14:12 UTC
|
| [reply] |
|
Thanks, DentArthurDent!
I've a more specific question and hope you can help.
Let's say I've two modules X and Y. Module X has a function func_x that it uses. That function is also used by Y.
Should I pull func_x out of X and put it in a separate module? Or is it okay to have it reside in X (and be exported) and let Y use it via "use autouse X => qw(func_x);" ?
| [reply] |
|
| [reply] |
|
|
Or is it okay to have it reside in X (and be exported)
If you start to try and follow some of the OO advice I would stay away from using exporter if you can.
Some of the worst spaghetti i.e overly interconnected code I have seen has used exporter so much everything might as well be in one big file.
| [reply] |
Re: So much interconnectedness - good or bad?
by cfreak (Chaplain) on Dec 17, 2004 at 15:07 UTC
|
I think that it really depends on what you're doing. If you're releasing the modules to CPAN then no. (I think its obvious that you aren't). So I would think the question would be: Are any of the modules useful on their own?
For example I've been working on an e-commerce system, I have a module for the shopping cart, a module for displaying items, a module for searching the items. None of the modules would be particularly useful on their own so they have some degree of interconnectedness.
You could clean up your scenerio by using OO programming. Make Module 'A' a subclass of 'B','C', and 'D'. That way when you create a new 'A' object, all the functions from all the modules will be availiable to it. Then you don't need to worry about exporting either and module A becomes the key to make the other modules work.
| [reply] |
Re: So much interconnectedness - good or bad?
by deltree (Initiate) on Dec 17, 2004 at 18:11 UTC
|
In an ideal world your module dependency graph is a DAG (directed acyclic graph).
Some module dependency DAGs are better than others: John Lakos talks about why in Large-Scale C++ Software Design. The book also presents some patterns for factoring out cycles.
I'm sure this is overkill in your case but you may be interested in some of the "theory" behind all this.
| [reply] |
Re: So much interconnectedness - good or bad?
by KeighleHawk (Scribe) on Dec 20, 2004 at 16:17 UTC
|
On the chance you're still reading this thread (it's a few days old but still on the front page), I'll add my two pennies worth...
My first response is it is time to refactor.
I often see this sort of thing more as a result of growth and usefulness rather than actual design. First came Module A which was spiffy and had many a good use. Then came Module B and it did much that was cool as well, not the least of which was to make use of A. The story goes on and potentially includes a little creative refactoring of A to make use of D thus creating the circular dependancies.
There are other reasons this happens, such as trying to modularize a relational database and choosing a bad criterion for the initial code seperation. eg. seperating code by client (I've seen it) becaues it was thought the code would never be useful to other clients. Another reason is seperating code by what it does rather than what it does it for (the basis of OO). eg. are we going to copy a file, ftp it, sftp it, or are we doing a Document->move? If you break our code up based on the functions, we often find them being so closely similar to other functions we end up coupling them.
Regardless of whether this design came about over time and wild growth or whether it was designed that way up front, my guess is, if you take a look at how they are currently designed and currently being used, you will find it not so difficult to refactor them into something that is not so convoluted, and considerablly cleaner.
Code, for all we might prefer it to not be, is alive, not static. It grows and changes, as does the need and uses for it. Often times one drives the other and vice-versa. If it's starting to feel uncomfortable (and causing you to question it's validity in public), start reworking it. Your code will thank you for the attention and respond with pleasant purrs and playful barks...
| [reply] |
|
Thanks, KeighleHawk!
That was what happened in my situation. The code just got more complicated as more lines were added.
Yes, I've been trying to slowly refactor some of the more obvious parts and trying to reduce the inter-connections.
| [reply] |