Starting with a monolith is nearly always great advice. However, monoliths tend towards spaghetti because it's too easy essentially to draw new lines on the architecture diagram by importing from anywhere.
To scale a monolith codebase without devolving into spaghetti you need to have a well defined layered structure for modules. The other aspect is being able to hide internal code to prevent it being imported by other modules.
I did a write-up a while ago about how we do this on my current project [1], and published the Maven enforcer rule and ArchUnit test example as an open source project [2].
I wish language designers would spend more time on designing higher abstractions, like modules, rather than only low level stuff like borrow checkers and async.
To scale a monolith codebase without devolving into spaghetti you need to have a well defined layered structure for modules. The other aspect is being able to hide internal code to prevent it being imported by other modules.
I did a write-up a while ago about how we do this on my current project [1], and published the Maven enforcer rule and ArchUnit test example as an open source project [2].
[1] https://bcoughlan.github.io/posts/modulithic-architecture/ [2] https://github.com/bcoughlan/base-package-enforcer-rule/ https://github.com/bcoughlan/base-package-enforcer-rule/blob...