Cleanup the injection of nil for dependencies #170

Closed
opened 2026-04-16 21:44:52 +00:00 by talksik · 1 comment
talksik commented 2026-04-16 21:44:52 +00:00 (Migrated from github.com)

Some services require lots of dependencies and this means that every consumer (worker, api, etc) has to inject that. Many times, we have leaky abstraction by allowing some dependencies to be optional, and it's overall fragile if we continue to do this.

We have several patterns in addition to passing nil, including Noop implementation structs, and more.

  • Create a wrapper over firestore so that we can create a mock for tests
Some services require lots of dependencies and this means that every consumer (worker, api, etc) has to inject that. Many times, we have leaky abstraction by allowing some dependencies to be optional, and it's overall fragile if we continue to do this. We have several patterns in addition to passing nil, including Noop implementation structs, and more. - [x] Create a wrapper over firestore so that we can create a mock for tests
talksik commented 2026-04-27 23:48:20 +00:00 (Migrated from github.com)

Completed with the following idiomatic go patterns:

  • Caller defines a narrow interface, and external package implements it. Caller injected with a struct, and type safety ensures that the struct satisfies the interface.
  • Mocks are co-located by the interface definition. Other packages can utilize the mock for tests.
  • Split packages into multiple external services / interfaces (e.g. NetworkReader vs. NetworkService), because the reader requires minimal dependencies, which is nice for the majority of consumers.
  • Use //go:generate directive in the interface to create mocks.
  • Introduce an abstraction for firestore: livestore. Currently contains MembershipPublisher which is only useful to NetworkService, however can be expanded into more functionality. Allows unit tests to mock the livestore interface because firestore doesn't have interfaces to mock.
Completed with the following idiomatic go patterns: - Caller defines a narrow interface, and external package implements it. Caller injected with a struct, and type safety ensures that the struct satisfies the interface. - Mocks are co-located by the interface definition. Other packages can utilize the mock for tests. - Split packages into multiple external services / interfaces (e.g. NetworkReader vs. NetworkService), because the reader requires minimal dependencies, which is nice for the majority of consumers. - Use //go:generate directive in the interface to create mocks. - Introduce an abstraction for firestore: livestore. Currently contains MembershipPublisher which is only useful to NetworkService, however can be expanded into more functionality. Allows unit tests to mock the livestore interface because firestore doesn't have interfaces to mock.
Sign in to join this conversation.