Topic on User talk:DKinzler (WMF)/Software Design Practices

CParle (WMF) (talkcontribs)

The first six bullets in "modularization" are all about cyclic dependencies. I think it'd be useful to spell out what a cyclic dependency is, and what the difference between a public and a private cyclic dependency is - before you talk about them, rather than at the end in 'definitions'. If we had this I think maybe some of the bullets could be consolidated.


This bullet

In the namespace hierarchy, it's also acceptable for classes in (transitive) parent namespaces and (transitive) child namespaces to depend on each other internally (but never publicly)

... suggests that that something in a parent namespace might depend on something in a child namespace, which I guess is not what you meant. Maybe something like

In the namespace hierarchy, classes lower in the hierarchy may depend on classes higher up, but not the other way around, and not on classes in other namespaces at the same level. Examples:

  • a class in Namespace/SubNamespaceA can depend on a class in Namespace
  • a class in Namespace should know nothing about classes in Namespace/SubNamespaceA
  • a class in Namespace/SubNamespaceA should know nothing about classes in Namespace/SubNamespaceB

I'm not really sure what you mean by "never publicly" ... do you mean that a class in Namespace/SubNamespaceA shouldn't directly inherit from a class in Namespace, but composition is ok?

DKinzler (WMF) (talkcontribs)

> In the namespace hierarchy, classes lower in the hierarchy may depend on classes higher up, but not the other way around, and not on classes in other namespaces at the same level.

I'm tempted to agree, but I have seen many examples to the contrary. E.g. factory methods in the parent namespace knowing about specialized implementations in nested namespaces. Or a class defined in the parent namespace pulling in utilities from nested namespaces as composites. Or even all the exceptions used in the parent namespace living in a sub namespace.

My idea here was to allow this as an implementation detail, but not publicly. Public dependency would not just be subclassing, but also any mention in a public (or even protected) method signature.

But of course, any cycles is always undesirable. And I'm rather unsure about whether there should be any special rules for the namespace hierarchy, or whether the hierarchy should be ignored entirely, and we just have rules for access between namespaces.

Because, as far as I can see, as long as there is no cycle, any access to any namespace from any other is generally allowed (we can forbid some, but the default is to allow it). At least for your third rule, I don't think it's enforcable - otherwise, nothing in the MyApp namespace (or any of it's child-namespaces) could ever use anything from outside MyApp, forbidding the use of any libraries. That doesn't make sense to me.

So, if MyApp/Foo can access CoolTool/Barf/Frobniz, why should MyApp/Foo not be allowed to access MyApp/Bar or MyApp/Foo/Bla?

The rule I am trying to establish is that "private" cycles between classes are "acceptable" (but still undesirable!) within a namespace. And maybe also "along" the hierarchy? But I'm happy to drop that, if it's not needed.

CParle (WMF) (talkcontribs)

> if MyApp/Foo can access CoolTool/Barf/Frobniz, why should MyApp/Foo not be allowed to access MyApp/Bar or MyApp/Foo/Bla

(scratches head)

Ok ... but if there are no access rules between levels of a hierarchy, what's the point of the hierarchy? Is it just a filing system?

DKinzler (WMF) (talkcontribs)

In my mind, yes, It's primarily a system of grouping. Namespaces form "components" and their dependencies should be acyclic, but that is unrelated to the hierarchy.

I have searched around a bit, and it seems like there are a number of people who agree with your rule of "you can access any other namespace except your descendant namespaces". But the reasoning seems to be based on the assumption that the child namespaces would naturally depend on the parent namespaces, so also depending the other way around would create a cycle.

So, it seems to me like this rule is really a natural consequence of "no cycles", and can be used as a rule of thumb to avoid cycles among closely related namespaces, but it doesn't provide additional value beyond that. As far as I can see, having a dependency on a child namespace is only bad because it's likely to create a cycle.

Now, all this doesn't really say anything about whether it should be acceptable to have "private" cyclic dependencies along lines of the namespace hierarchy. I think I'll just remove that bullet point. It's bound to create confusion, and since we want to get rid of all cycles, why tollerate more?

DKinzler (WMF) (talkcontribs)

I removed the bullet point about cycles being acceptable in the hierarchy.

I introduced a point discouraging dependencies on child namespaces:

  • In the namespace hierarchy, it is discouraged for the code in a namespace to depend on code in any of its child (or more remote descendant) namespaces. This is primarily because it is expected for child namespaces to depend on code in their parent namespace, and having dependencies both ways would create a cycle.
Reply to "Modularization"