> BTW, the term "organizational" usually refers to how you organize your people.

Then what, in your opinion, is a better adjective for "technical debt" that best conveys my point?

>How do you organize it into layers? How do you organize it into files?

Namespacing, files, and "layers" are aesthetic forms of organization that do not produce actual barriers in organization. They are for people to read and do not produce actual structured barriers.

Namespace MathLayer1 {
function mathlayer1combinator()
}

Namespace OtherLayer2 {
function otherlayer2combinator()
}

You will note because both functions are combinators, they can always be moved/called interchangeably into either namespace/file/layer provided that you handle circular dependencies (easily done in C++ by declaring everything in a header file first and making sure you don't have any sort of circular recursion in the definitions).

Thus "organizational" mistakes in namespacing/layers are actually trivial because none of the combinators in the namespace are tied to context. If you find you can't move a function out of a namespace it is always because of the fact that that function is not a combinator and is likely relying on some other state declared within the namespace/class. It is not the namespace itself that is causing this issue.

Another way to think about a namespace or layer is that all it does is put a prefix on your combinator for readability purposes.

Layer3.combinatorG as opposed to just combinatorG

A third perspective is to view the combinator as a concept that transcends namespacing or layers. A combinator is never limited by scope because it carries the scope with it rather then existing as an entity tied to scope.

Machine organization is a problem though. Machines are a physical limitation placed upon our virtual code and people exploiting this limitation as a feature makes code even less modular. A machine barrier is no different from a namespace or object with one difference: Moving or reusing code in a different machine requires data transfer. There is no reason to impose this limitation on our code unless we have no choice.

Thus the limitations of machines should only be utilized to optimize for performance, not as a feature to organize your code. Inevitably in practice this can cause organizational debt if you placed a function in machine A for optimization reasons and suddenly find that you need to use that function in machine B things will be inconvenient.

Hopefully, if that function is a combinator, moving it for use in machine B will be less of a pain. But keep in mind in the idealistic world of programming the machine barrier doesn't exist. Formally moving your combinator out of Machine B into Machine A is the same as if the Machine was called a Namespace. There is no intrinsic difference. It is the physical limitations of the real world that is making things inconvenient so my statement about combinators still holds logically.

That being said the physical barrier of machines can be abstracted away in a single project directory. There are strategies to handle this (imperfectly), docker or RPCs for example.

It's Good to have awareness of the exact formal and logical consequences of certain actions rather then rely on some fuzzy intuition of design. Clarity in the fundamentals of what's going on is key to developing a logical rule set so that optimal structure can be calculated rather then sub-optimally designed from intuition.