i don't know the answer to this it is just a problem I'm fighting.
i don't know the answer to this it is just a problem I'm fighting.
The classic is ArchUnit in Java:
@ArchTest
static final ArchRule layer_dependencies_are_respected = layeredArchitecture().consideringAllDependencies()
.layer("Controllers").definedBy("com.tngtech.archunit.example.layers.controller..")
.layer("Services").definedBy("com.tngtech.archunit.example.layers.service..")
.layer("Persistence").definedBy("com.tngtech.archunit.example.layers.persistence..")
.whereLayer("Controllers").mayNotBeAccessedByAnyLayer()
.whereLayer("Services").mayOnlyBeAccessedByLayers("Controllers")
.whereLayer("Persistence").mayOnlyBeAccessedByLayers("Services");
The problem I've had with these tests is that the run time is abysmal, meaning they only really get run as part of CI and devs complain that they fail too late in the processAlso, I'm on mobile so apologies for the badly formatted code - original can be found here: https://github.com/TNG/ArchUnit-Examples/blob/main/example-j...
For instance, Java lets you say "public class" for a class visible outside its package, and just "class" otherwise. And if you're using Java 11 modules (nobody is though :( ), you can choose which packages are exported to consumers of your module.
In a similar vein, Rust has a `pub` access control that can be applied to modules, types, functions, and so on. A `pub` symbol is accessible outside the current crate; non-pub symbols are only accessible within one crate.
Of course, lots of languages don't have anything like this. The biggest offender is probably C++, although once its own version of modules is widely supported, we'll be able to control access somewhat like Java modules and Rust crates, with "partitions" serving the role of a (flattened) internal package hierarchy. Right now, if you do shared libraries, you can tightly control what the linker exports as a global symbol, and therefore control what users of your shared library can depend on -- `-fvisibility=hidden` will be your best friend!
This is not universally true; it's more that pub makes it accessible to the enclosing scope. Wrapping in an extra "mod" so that this works in one file:
mod foo {
mod bar {
pub fn baz() {
}
}
pub fn foo() {
bar::baz();
}
}
fn main() {
// this is okay, because foo can call baz
foo::foo();
// this is not okay, because bar is private, and so even though baz is marked pub, its parent module isn't
foo::bar::baz();
}