Project Organization and Style
Dependency Direction
Packages stay easier to test when higher-level layers depend on lower-level interfaces deliberately.
dependency direction
Track which layer owns a dependency so imports do not grow into cycles.
Dependency Direction
dependency_direction.go
Replay: real traced execution (multi-file project)
package main
import "fmt"
func main() {
var layer = "handler"
allowed := map[string][]string{
"handler": {"domain", "log"},
"domain": {"time"},
"storage": {"domain", "database/sql"},
}
dependencies := allowed[layer]
stable := layer != "domain" || len(dependencies) == 1
fmt.Println("layer=", layer)
fmt.Println("dependency_count=", len(dependencies))
for _, dependency := range dependencies {
fmt.Println("depends_on=", dependency)
}
fmt.Println("stable_core=", stable)
}
package main
import "fmt"
func main() {
var layer = "domain"
allowed := map[string][]string{
"handler": {"domain", "log"},
"domain": {"time"},
"storage": {"domain", "database/sql"},
}
dependencies := allowed[layer]
stable := layer != "domain" || len(dependencies) == 1
fmt.Println("layer=", layer)
fmt.Println("dependency_count=", len(dependencies))
for _, dependency := range dependencies {
fmt.Println("depends_on=", dependency)
}
fmt.Println("stable_core=", stable)
}
package main
import "fmt"
func main() {
var layer = "storage"
allowed := map[string][]string{
"handler": {"domain", "log"},
"domain": {"time"},
"storage": {"domain", "database/sql"},
}
dependencies := allowed[layer]
stable := layer != "domain" || len(dependencies) == 1
fmt.Println("layer=", layer)
fmt.Println("dependency_count=", len(dependencies))
for _, dependency := range dependencies {
fmt.Println("depends_on=", dependency)
}
fmt.Println("stable_core=", stable)
}
layer ← "handler", allowed ← map[string][]string{"domain":[]string{"time"}, "handler":[]string{"domain", "log"}, "storage":[]string{"domain", "database/sql"}}
5func main() {6 var layer→ "handler" = "handler" //@layer="domain", "storage"7 allowed→ map[string][]string{"domain":[]string{"time"}, "handler":[]string{"domain", "log"}, "storage":[]string{"domain", "database/sql"}} := map[string][]string{8 "handler": {"domain", "log"},9 "domain": {"time"},10 "storage": {"domain", "database/sql"},11 }1213 dependencies→ []string{"domain", "log"} := allowed[layer][]string{"domain", "log"}14 stable→ true := layer"handler" != "domain" || len(dependencies[]string{"domain", "log"}) == 11516 fmt.Println("layer=", layer"handler")17 fmt.Println("dependency_count=", len(dependencies[]string{"domain", "log"}))18 for _, dependency := range dependencies {outputlayer= handler dependency_count= 2for _, dependency := range dependencies
pass 1 of 217fmt.Println("dependency_count=", len(dependencies))18for _, dependency"domain" := range dependencies[]string{"domain", "log"} {19 fmt.Println("depends_on=", dependency"domain")20}outputdepends_on= domainfor _, dependency := range dependencies
pass 2 of 217fmt.Println("dependency_count=", len(dependencies))18for _, dependency"log" := range dependencies[]string{"domain", "log"} {19 fmt.Println("depends_on=", dependency"log")20}outputdepends_on= logfmt.Println("stable_core=", stable)
20 }21 fmt.Println("stable_core=", stabletrue)22}outputstable_core= true
layer ← "domain", allowed ← map[string][]string{"domain":[]string{"time"}, "handler":[]string{"domain", "log"}, "storage":[]string{"domain", "database/sql"}}
5func main() {6 var layer→ "domain" = "domain"7 allowed→ map[string][]string{"domain":[]string{"time"}, "handler":[]string{"domain", "log"}, "storage":[]string{"domain", "database/sql"}} := map[string][]string{8 "handler": {"domain", "log"},9 "domain": {"time"},10 "storage": {"domain", "database/sql"},11 }1213 dependencies→ []string{"time"} := allowed[layer][]string{"time"}14 stable→ true := layer"domain" != "domain" || len(dependencies[]string{"time"}) == 11516 fmt.Println("layer=", layer"domain")17 fmt.Println("dependency_count=", len(dependencies[]string{"time"}))18 for _, dependency := range dependencies {outputlayer= domain dependency_count= 1for _, dependency := range dependencies
17fmt.Println("dependency_count=", len(dependencies))18for _, dependency"time" := range dependencies[]string{"time"} {19 fmt.Println("depends_on=", dependency"time")20}outputdepends_on= timefmt.Println("stable_core=", stable)
20 }21 fmt.Println("stable_core=", stabletrue)22}outputstable_core= true
layer ← "storage", allowed ← map[string][]string{"domain":[]string{"time"}, "handler":[]string{"domain", "log"}, "storage":[]string{"domain", "database/sql"}}
5func main() {6 var layer→ "storage" = "storage"7 allowed→ map[string][]string{"domain":[]string{"time"}, "handler":[]string{"domain", "log"}, "storage":[]string{"domain", "database/sql"}} := map[string][]string{8 "handler": {"domain", "log"},9 "domain": {"time"},10 "storage": {"domain", "database/sql"},11 }1213 dependencies→ []string{"domain", "database/sql"} := allowed[layer][]string{"domain", "database/sql"}14 stable→ true := layer"storage" != "domain" || len(dependencies[]string{"domain", "database/sql"}) == 11516 fmt.Println("layer=", layer"storage")17 fmt.Println("dependency_count=", len(dependencies[]string{"domain", "database/sql"}))18 for _, dependency := range dependencies {outputlayer= storage dependency_count= 2for _, dependency := range dependencies
pass 1 of 217fmt.Println("dependency_count=", len(dependencies))18for _, dependency"domain" := range dependencies[]string{"domain", "database/sql"} {19 fmt.Println("depends_on=", dependency"domain")20}outputdepends_on= domainfor _, dependency := range dependencies
pass 2 of 217fmt.Println("dependency_count=", len(dependencies))18for _, dependency"database/sql" := range dependencies[]string{"domain", "database/sql"} {19 fmt.Println("depends_on=", dependency"database/sql")20}outputdepends_on= database/sqlfmt.Println("stable_core=", stable)
20 }21 fmt.Println("stable_core=", stabletrue)22}outputstable_core= true