Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

It means the object created by NewServer is dealing with too much. Probably has too many data types coupled to it and too much behavior.

Simple example is adding a logger. If you add it as a dependency to the constructor, the object starts doing a bit more than initial simple implementation. It's fine to do it, but shame to not figure out how to log without editing the implementation of a simple thing.

Higher order functions (a logger decorator) get there to allow composition, but even they have their drawbacks.

It's still some form of structure that you can deal with, not a mistake.



As you say, having a logger attached is one of those pragmatic and acceptable exceptions to the rule. In a perfect world we'd have the time to go to the trouble of implementing loggable types and data flows and associated higher order functions, in practice taking the compromise means getting the real business valuable work completed while still having the necessary (but usually "low priority") non-functional requirements like logging and metrics implemented.


I agree that too many arguments to the constructor may have the smell of too much coupling.

But if I really feel I can't avoid the need to pass a good amount of external context, I create a dedicated "options" struct and pass that into the constructor as a pointer. The purpose of the pointer (rather than pass by value) is if I want default arguments, I can pass nil.

    type ServerOptions struct {
        logger    *magic.Logger
        secretKey string
    }

    func NewServer(options *ServerOptions) (*Server, error) {
        ...
    }




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: