Hacker News new | past | comments | ask | show | jobs | submit login

Slightly unrelated to Parent:

I struggle very hard creating my own interfaces for my own programs. I haven't found any literature online teaching the _right way_ of coming up with your interface.

For example, I very often struggle with function parameters and return types: should my interface functions only take basic type and return basic types? Can my interface function take more concrete types? Should my interface function take interface types?

I'd love to be directed to a guide on how to create a good interface.

As an example, here's a recent interface declaration I wrote:

    type Checker interface {
        Check(context.Context, *object.Commit, bool) (bool, []string, error)
        Name() string
        Describe() string
    }
My program runs through a list of commits and runs "Checks" on them. These checks "pass (true)" or "fail (false)".

I want the user of my package to be in charge of the implementation details of a "Check", so I created the interface above.

Is it OK for the Check() function to take a *object.Commit? Should I instead pass a `SHA string` and let the implementer figure out how to get a *object.Commit from that string?




Looking up *object.Commit from SHA string doesn't seem like something you want to make every Checker implementation do (even if it's mostly boilerplate), so passing a higher-level object makes sense here.

What you might want to do is also define an interface for what Git calls "commit-ish"[0] objects, and use that in place of *object.Commit. Then you could pass e.g. *object.Tag in place of *object.Commit.

Think of the interface as a contract between implementations and users of the data structure. Typically, you use an interface when multiple implementations are capable of fulfilling the same contract. If there's only one implementation, you likely don't need an interface—for instance, you can ignore my suggestion about abstracting commit-ish if you're pretty sure your checker would never be called for a tag.

Interfaces are often useful when testing, because a mock implementation can fulfill that same contract. For instance, you might implement a *object.MockCommit which just uses static values instead of actually operating on a Git repository, and then pass that for your commit-ish in unit tests for various Checkers.

[0] https://git-scm.com/docs/gitglossary#Documentation/gitglossa...




Consider applying for YC's Spring batch! Applications are open till Feb 11.

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

Search: