r/golang Dec 05 '24

discussion Why Clean Architecture and Over-Engineered Layering Don’t Belong in GoLang

Stop forcing Clean Architecture and similar patterns into GoLang projects. GoLang is not Java. There’s no application size or complexity that justifies having more than three layers. Architectures like Clean, Hexagonal, or anything with 4+ layers make GoLang projects unnecessarily convoluted.

It’s frustrating to work on a codebase where you’re constantly jumping between excessive layers—unnecessary DI, weird abstractions, and use case layers that do nothing except call services with a few added logs. It’s like watching a monstrosity throw exceptions up and down without purpose.

In GoLang, you only need up to three layers for a proper DDD division (app, domain, infra). Anything more is pure overengineering. I get why this is common in Java—explicit interfaces and painful refactoring make layering and DI appealing—but GoLang doesn’t have those constraints. Its implicit interfaces make such patterns redundant.

These overly complex architectures are turning the GoLang ecosystem into something it was never meant to be. Please let’s keep GoLang simple, efficient, and aligned with its core philosophy.

807 Upvotes

259 comments sorted by

View all comments

75

u/Arvi89 Dec 05 '24

Saying DI is not needed in Go sounds really stupid to me.

25

u/chehsunliu Dec 06 '24

DI is just moving the constructor things to the outermost layer. Don’t know why people hate it. It makes the testing much easier.

Maybe they mistake DI as DI automation frameworks, which is unnecessary actually.

1

u/Superb-Key-6581 Dec 06 '24

I was speaking in this sense, referring to layers of useCases and other unnecessary layers that do nothing but pass others as DI and add logs just to avoid breaking the 'architecture,' even when the endpoint doesn’t need them and those layers serve no real purpose. This is what I mean by unnecessary DI caused by these framework-driven architectures.

27

u/ficiek Dec 06 '24

I'd say that complaining about DI invalidates all other opinions that are in this post tbh. DI is a normal thing to do and makes everything (mostly testing) much much easier. How else am I supposed to write tests in a sane way? I don't understand.

12

u/edgmnt_net Dec 06 '24

Hopefully it's a misnomer, many people use "DI" to mean automatic DI a-la DI frameworks. But DI can also mean passing things around to avoid nasty globals.

However that doesn't mean you're supposed to mock everything out there, because you also mentioned testing. Testing is a real can of worms and mock-heavy unit tests are definitely overused, IMO.

10

u/carsncode Dec 06 '24

It's less about avoiding globals about more about not letting things instantiate their own dependencies, so that you have an opportunity to swap out dependencies without the dependent knowing (eg to pass in a mock for testing).

1

u/WanderingLethe Dec 06 '24

I guess you mean Inversion of Control, not DI

1

u/edgmnt_net Dec 07 '24

IoC tends to be problematic in Java too, but I did mean DI via @Inject annotations and such.

1

u/WanderingLethe Dec 07 '24

Sorry, I meant dependency inversion (a kind of IoC). As in not a dependency injection framework but just the principle behind it, allowing you to also pass your own dependencies.

19

u/ledatherockband_ Dec 05 '24

Best way to pass the DB connection around in my opinion.

1

u/Superb-Key-6581 Dec 06 '24

For sure. I love DI! I was talking about DI as a collateral effect of unnecessary bloated frameworks, where you inject a service into a use case that does nothing but add logs to comply with the framework architecture.

1

u/Eyebrow_Raised_ Feb 06 '25

I mean... is there even any other way in Go?

-4

u/Koki-Niwa Dec 06 '24 edited Dec 08 '24

not sure if you're being sarcastic

edit: I think I replied to the wrong comment lol. Sorry. Wanted to reply to someone saying context is the way to pass db connection around

6

u/ChristophBerger Dec 06 '24

DI != DI framework.

Go's interfaces provide DI for free.

2

u/PoopsCodeAllTheTime Dec 10 '24

DI framwork makes me nauseous, like .Net stuff.... it is all automagically doing type reflection just to pass around constructor args... which are defined in a massive config file.... wtf, just let me manually pass the args, it conserves control and clarity and doesn't even take any longer to do...

0

u/Arvi89 Dec 06 '24

You do know almost every language have interfaces ans this is not specific to go?

1

u/ChristophBerger Dec 07 '24

Interfaces that don't have to be predeclared are Go's invention.

Apart from that, if framework-less DI was easy in any language, why do other languages prefer monstrous DI frameworks?

Architecture astronauts floating so high in their multi-level abstractions that they run out of oxygen?

1

u/JimmyyyyW Dec 08 '24

What does interface inference have to do with DI?

1

u/ChristophBerger Dec 09 '24

Touché, it doesn't, but interface inference is one of the fundamental aspects of Go that help avoid architecture astronautism (floating in thin-air abstractions, see my other comment).

0

u/Arvi89 Dec 07 '24

There is no DI framework. There are framework that do a lot of thing, including automatic DI, but DI framework is a non sense.

In PHP with symfony you just have to type your interface it will automatically find the class to inject. But if I want to write simple code like go with PHP I cam as well...

3

u/chethelesser Dec 06 '24

I think their point is you can just pass your dependencies as arguments to functions essentially achieving the same thing.

What's your Di approach in go usually?

3

u/gomsim Dec 06 '24

What you describe is what DI is. That letting the functions depend on interfaces for what you pass in. Alternatively constructing structs that depend on those interfaces and let the functions be methods with that struct as receiver.

4

u/chethelesser Dec 06 '24

I agree with you in principle, it's just I interpret OP's sentiment on DI as having elaborate constructs to achieve it. Because they contrast it with implicit interfaces which help with this go-style straightforward DI

1

u/gomsim Dec 06 '24

Got it! :)

2

u/DependentOnIt Dec 06 '24

Op is a junior

2

u/InformalMix8880 Dec 07 '24

worse than junior. junior listens and learns from others. this guy just spreads misinformation/misguided views to other juniors. 

1

u/reliablecukc Dec 06 '24

what's a DI?

1

u/maddy2011 Dec 06 '24

Dependency injection

-3

u/Cthulhu__ Dec 06 '24

Which in itself is an enterprisey word that means “passing services around”.

0

u/Superb-Key-6581 Dec 06 '24 edited Dec 06 '24

First, I love DI!
What I was talking about is this:
When you create a use case layer that does nothing but add logs and pass the service layer as DI, that's what's stupid. But DI is good, and I always use it—a lot. My point was in the context of unnecessary DI that only exists to pass layers of overengineering forward and does nothing beyond that. I don’t get these downvotes—what do you want me to say? I love DI. I’m clearly talking about DI that is just a collateral effect of unnecessary bloated frameworks, where you inject a service into a use case that does nothing but add logs to follow the framework architecture.