I've recently realised the reason why Plantuml's container shapes behave so oddly when referenced in a connection. It is because behind the scenes they use Graphviz's cluster subgraph syntax. But Graphviz's clusters have a massive short-coming - they can't (directly) be the start/end of a connector! To get around this, if Plantuml knows that the cluster will be used as the start/end of a connector, then it chucks in an invisible point shape to use as the endpoint instead. But this has some nasty drawbacks. Because Graphviz doesn't layout the contents of clusters sympathetically to the global diagram, this point often ends up in the wrong physical location for the connection. And also the presence of an invisible shape adds a small amount of asymmetrical padding to the container.
It is not an easy problem to solve; since it is Graphviz's limitation rather than Plantuml's.
But I was thinking. In the very simple case of a container containing a single shape - then surely we would want that single shape to be the anchor point, rather that throw in a disrupting point shape. The same if we had container A containing container B containing Shape C - then we would want shape C to be the anchor for both container A and for container B.
But having a solution for only a trivial case isn't much good, so I was thinking how to expand it.
1)
One idea (suggested by bfxdev in this question) is for Plantuml to have the option to use the first shape it comes across as the anchor shape instead of adding a point shape. So perhaps a new skinparam/style/instruction for "containerAnchor first". When applicable, it would suppress adding the point shape and instead look for the first sub-shape (which might be nested several containers deep) to use instead. This alone would be a big improvement for many diagrams, I suspect.
2)
A more powerful syntax, but less user-friendly/automatic, would be to expand the arrow syntax, eg We could steal the "lhead/ltail" concept directly from Graphviz:
@startuml
component A {
component B
}
component C {
component D
}
B -[lhead=A, ltail=C]-> D
@enduml
This would connect shapes B and D, but truncate the arrows at containers A and C respectively.
3) Or to combine the two ideas above:
@startuml
component A {
component B
}
component C {
component D
}
A -[from=auto, to=D]-> C
@enduml
This would find an appropriate shape in container A (i.e. shape B) and link it to shape D truncating at container edges of A and C. ("from=default" could represent the status quo of adding a point shape for completeness).